Documentation
¶
Index ¶
- Variables
- func CompareTaskIDs(a, b string) int
- func GenerateName() string
- func SortTasksByID(tasks []Task)
- type CacheBreakInfo
- type Compaction
- type ContextSnapshot
- type Entry
- type EntryKind
- type GoalStateEntry
- type Header
- type History
- type HistoryEntry
- type LLMCallEntry
- type Manager
- type ModelChange
- type PlanFile
- type PlanStateEntry
- type PlanStore
- type ReasoningEffortChange
- type Roster
- type RosterMember
- type RosterStore
- type SessionInfo
- type Store
- func (s *Store) AppendCompaction(summary string, keptMessages []json.RawMessage) error
- func (s *Store) AppendGoalState(entry GoalStateEntry) error
- func (s *Store) AppendLLMCall(entry LLMCallEntry) error
- func (s *Store) AppendMessage(msg agentcore.Message) error
- func (s *Store) AppendModelChange(provider, model string) error
- func (s *Store) AppendPlanState(phase, slug, preMode string) error
- func (s *Store) AppendReasoningEffortChange(level string) error
- func (s *Store) BuildSnapshot() (ContextSnapshot, error)
- func (s *Store) Close() error
- func (s *Store) Header() Header
- func (s *Store) Path() string
- func (s *Store) SetName(name string) error
- type Task
- type TaskNotifyFn
- type TaskSnapshot
- type TaskStatus
- type TaskStore
- func (s *TaskStore) Claim(id, owner string) (*Task, error)
- func (s *TaskStore) Create(subject, description, activeForm string, metadata map[string]any) *Task
- func (s *TaskStore) Delete(id string) bool
- func (s *TaskStore) FindClaimable() *Task
- func (s *TaskStore) Get(id string) (*Task, bool)
- func (s *TaskStore) List() []Task
- func (s *TaskStore) Reset() error
- func (s *TaskStore) SetDir(dir string) error
- func (s *TaskStore) SetNotifyFn(fn TaskNotifyFn)
- func (s *TaskStore) Snapshot() TaskSnapshot
- func (s *TaskStore) Update(id string, opts TaskUpdateOpts) (*Task, error)
- type TaskUpdateOpts
- type TranscriptStore
Constants ¶
This section is empty.
Variables ¶
var ( ErrTaskNotFound = errors.New("task not found") ErrAlreadyClaimed = errors.New("task already claimed by another owner") ErrAlreadyResolved = errors.New("task already completed") ErrBlocked = errors.New("task has unresolved blockers") )
Sentinel errors returned by Claim so callers can branch on cause without string-matching.
Functions ¶
func CompareTaskIDs ¶ added in v0.1.1
CompareTaskIDs compares two task ID strings numerically.
func GenerateName ¶
func GenerateName() string
GenerateName returns a random name in adjective-gerund-noun format.
func SortTasksByID ¶ added in v0.1.1
func SortTasksByID(tasks []Task)
SortTasksByID sorts tasks by numeric ID ascending.
Types ¶
type CacheBreakInfo ¶ added in v0.1.1
type CacheBreakInfo struct {
PrevCacheReadTokens int `json:"prev_cache_read_tokens"`
CurrCacheReadTokens int `json:"curr_cache_read_tokens"`
DropAbsolute int `json:"drop_absolute"`
DropFraction float64 `json:"drop_fraction"`
// SystemChanged is true when either the frozen prefix or the dynamic
// tail of the system blocks changed. Kept for backwards compatibility
// with existing JSONL — prefer the finer-grained fields below.
SystemChanged bool `json:"system_changed,omitempty"`
FrozenChanged bool `json:"frozen_system_changed,omitempty"`
DynamicChanged bool `json:"dynamic_system_changed,omitempty"`
ToolsChanged bool `json:"tools_changed,omitempty"`
Note string `json:"note,omitempty"`
}
CacheBreakInfo is attached to an LLMCallEntry when the prompt cache hit rate unexpectedly dropped relative to the previous turn. It captures why the cache likely invalidated so the session can be diagnosed after-the- fact without replaying the full request.
type Compaction ¶
type Compaction struct {
Summary string `json:"summary"`
Messages []json.RawMessage `json:"messages,omitempty"`
}
Compaction stores a compaction summary and optionally kept messages.
type ContextSnapshot ¶
type ContextSnapshot struct {
Messages []agentcore.AgentMessage
Provider string
Model string
ReasoningEffort string
PlanSlug string
PlanPhase string
PlanPreMode string
Goal GoalStateEntry
}
ContextSnapshot is the projected runtime state from a session log.
type Entry ¶
type Entry struct {
Kind EntryKind `json:"kind"`
ID string `json:"id"`
ParentID string `json:"parent_id,omitempty"`
Timestamp time.Time `json:"timestamp"`
Data json.RawMessage `json:"data"`
}
Entry is a single JSONL line in the session file.
type EntryKind ¶
type EntryKind string
EntryKind identifies the type of a JSONL entry.
const ( EntryHeader EntryKind = "header" EntryMessage EntryKind = "message" EntryModelChange EntryKind = "model_change" EntryCompaction EntryKind = "compaction" EntryReasoningEffortChange EntryKind = "reasoning_effort_change" EntrySessionInfo EntryKind = "session_info" EntryPlanState EntryKind = "plan_state" EntryGoalState EntryKind = "goal_state" EntryLLMCall EntryKind = "llm_call" )
type GoalStateEntry ¶ added in v0.2.2
type GoalStateEntry struct {
ID string `json:"id,omitempty"`
Objective string `json:"objective,omitempty"`
Status string `json:"status"`
CreatedAt time.Time `json:"created_at,omitempty"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
CompletedAt time.Time `json:"completed_at,omitempty"`
BlockedAt time.Time `json:"blocked_at,omitempty"`
BudgetLimitedAt time.Time `json:"budget_limited_at,omitempty"`
UsageLimitedAt time.Time `json:"usage_limited_at,omitempty"`
Reason string `json:"reason,omitempty"`
BlockedReason string `json:"blocked_reason,omitempty"`
BlockedCount int `json:"blocked_count,omitempty"`
BlockedAttemptTokenTotal int `json:"blocked_attempt_token_total,omitempty"`
BudgetLimitReported bool `json:"budget_limit_reported,omitempty"`
TokenBudget int `json:"token_budget,omitempty"`
TokensUsed int `json:"tokens_used,omitempty"`
TokenTotalAtLastAccount int `json:"token_total_at_last_account,omitempty"`
}
GoalStateEntry records the explicit /goal state for session resume.
type Header ¶
type Header struct {
Version int `json:"version"`
SessionID string `json:"session_id"`
Name string `json:"name,omitempty"`
Cwd string `json:"cwd"`
Created time.Time `json:"created"`
}
Header is the first line of a session file.
type History ¶
type History struct {
// contains filtered or unexported fields
}
History provides append-only input history with per-project filtering. The backing file (~/.codebot/history.jsonl) is shared across all projects; only entries matching the current project are surfaced.
func NewHistory ¶
NewHistory loads history from path, filtering by project.
func (*History) SetSessionID ¶
SetSessionID updates the session ID for subsequent entries (e.g. after session switch).
type HistoryEntry ¶
type HistoryEntry struct {
Display string `json:"display"`
PastedContents map[string]any `json:"pastedContents"`
Timestamp int64 `json:"timestamp"`
Project string `json:"project"`
SessionID string `json:"sessionId,omitempty"`
}
HistoryEntry is one line in the JSONL history file.
type LLMCallEntry ¶ added in v0.1.1
type LLMCallEntry struct {
Provider string `json:"provider"`
Model string `json:"model"`
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
CacheReadTokens int `json:"cache_read_tokens,omitempty"`
CacheCreationTokens int `json:"cache_creation_tokens,omitempty"`
TotalTokens int `json:"total_tokens,omitempty"`
LatencyMs int64 `json:"latency_ms,omitempty"`
StopReason string `json:"stop_reason,omitempty"`
ReasoningEffort string `json:"reasoning_effort,omitempty"`
CacheBreak *CacheBreakInfo `json:"cache_break,omitempty"`
}
LLMCallEntry is a per-turn observability record for a single LLM response. Emitted once per assistant message_end, independent of the message itself so that downstream can diagnose cache hits, latency, and provider without re-parsing the message payload.
type Manager ¶
type Manager struct {
Dir string
}
Manager manages session files in a directory.
func NewManager ¶
NewManager creates a Manager for the given sessions directory.
func (*Manager) List ¶
func (m *Manager) List() ([]SessionInfo, error)
List returns all sessions sorted by updated time (newest first).
func (*Manager) MostRecent ¶
func (m *Manager) MostRecent() (*SessionInfo, error)
MostRecent returns the most recently updated session.
type ModelChange ¶
ModelChange records a model switch event.
type PlanStateEntry ¶ added in v0.1.0
type PlanStateEntry struct {
Phase string `json:"phase"`
Slug string `json:"slug,omitempty"`
PreMode string `json:"pre_mode,omitempty"`
}
PlanStateEntry records a plan-mode phase transition.
type PlanStore ¶
type PlanStore struct {
// contains filtered or unexported fields
}
PlanStore manages plan markdown files in a single directory.
func NewPlanStore ¶
NewPlanStore creates a PlanStore and ensures the directory exists.
func (*PlanStore) Dir ¶ added in v0.1.3
Dir returns the directory plans are stored in. Used by the TUI to detect whether a write/edit target is a plan file (hidden rendering).
type ReasoningEffortChange ¶ added in v0.3.0
type ReasoningEffortChange struct {
Level string `json:"level"`
}
ReasoningEffortChange records a reasoning effort switch event.
type Roster ¶ added in v0.2.0
type Roster struct {
Team string `json:"team"`
Description string `json:"description,omitempty"`
Members []RosterMember `json:"members,omitempty"`
}
Roster is the persisted team snapshot: the active team's identity plus every live teammate. It mirrors the in-memory team.Registry roster so a restarted session can rebuild the team and re-spawn its members.
type RosterMember ¶ added in v0.2.0
type RosterMember struct {
Name string `json:"name"`
AgentType string `json:"agent_type"`
Color string `json:"color,omitempty"`
InitialPrompt string `json:"initial_prompt,omitempty"`
Description string `json:"description,omitempty"`
Depth int `json:"depth,omitempty"`
Kind string `json:"kind,omitempty"`
}
RosterMember is the minimal, faithful record needed to re-spawn one teammate after a restart. It deliberately stores only spawn-time facts that are NOT recoverable from the agent definition registry:
- Name is the unique routing identifier (post de-duplication), distinct from AgentType when the leader spawned two of the same kind.
- AgentType is the definition key (subagent.Config.Name) the harness rebuilds the full Config from on resume — model, system prompt, tools and context manager all come back via that lookup, so they are not duplicated here.
- Color / InitialPrompt / Description / Depth are per-spawn overrides the definition does not carry.
- Kind tags the agent's spawn mode. Today every team-spawned agent is a teammate; the field exists so restore/UI can branch once background or one-shot agents also land in the roster. Empty ⇒ treat as teammate.
type RosterStore ¶ added in v0.2.0
type RosterStore struct {
// contains filtered or unexported fields
}
RosterStore persists a single team Roster to <dir>/roster.json with atomic writes. Like TaskStore it is safe for in-memory-only use: with no dir set every mutation is kept in memory and nothing touches disk. The directory is created lazily on the first write so sessions that never form a team leave nothing behind.
func NewRosterStore ¶ added in v0.2.0
func NewRosterStore() *RosterStore
NewRosterStore returns an empty in-memory store. Call SetDir to enable persistence (and load any prior roster).
func (*RosterStore) Clear ¶ added in v0.2.0
func (s *RosterStore) Clear()
Clear drops the team and all members, removing roster.json from disk. Used when the leader deletes the team (team_dismiss of the whole team).
func (*RosterStore) RemoveMember ¶ added in v0.2.0
func (s *RosterStore) RemoveMember(name string)
RemoveMember drops the member with the given Name (e.g. on team_dismiss) so a restart does not resurrect a teammate the leader deliberately retired. No-op when the name is absent.
func (*RosterStore) SetDir ¶ added in v0.2.0
func (s *RosterStore) SetDir(dir string) error
SetDir enables file persistence and loads an existing roster.json if present. A missing dir or file is not an error — it just means no prior team.
func (*RosterStore) SetTeam ¶ added in v0.2.0
func (s *RosterStore) SetTeam(name, description string)
SetTeam records the active team's name and description, replacing any prior team. Members are preserved (rename/describe must not drop the roster); use Clear to drop a team entirely.
func (*RosterStore) Snapshot ¶ added in v0.2.0
func (s *RosterStore) Snapshot() Roster
Snapshot returns a deep copy of the current roster for resume. The Members slice is freshly allocated so callers can iterate without holding the lock.
func (*RosterStore) UpsertMember ¶ added in v0.2.0
func (s *RosterStore) UpsertMember(m RosterMember)
UpsertMember adds m, or replaces the existing member with the same Name. Matching by Name (the routing key) means a re-spawn under an existing name updates rather than duplicates.
type SessionInfo ¶
type SessionInfo struct {
ID string
Name string
Path string
Cwd string
Created time.Time
Updated time.Time
MessageCount int
FirstMessage string // first user message, truncated to 80 chars
}
SessionInfo is a summary of a session for listing.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store manages a single session JSONL file.
func (*Store) AppendCompaction ¶
func (s *Store) AppendCompaction(summary string, keptMessages []json.RawMessage) error
AppendCompaction records a compaction event with summary and optional kept messages.
func (*Store) AppendGoalState ¶ added in v0.2.2
func (s *Store) AppendGoalState(entry GoalStateEntry) error
func (*Store) AppendLLMCall ¶ added in v0.1.1
func (s *Store) AppendLLMCall(entry LLMCallEntry) error
AppendLLMCall records a single LLM response's observability metadata. This is written alongside the assistant message itself, so the message payload stays minimal while diagnostics (cache/latency/provider) stay queryable without replaying the whole message.
func (*Store) AppendMessage ¶
AppendMessage serializes and appends an agentcore.Message.
Thinking blocks are truncated to maxStoredThinkingRunes before write to keep session files compact. Truncation is storage-only — the in-memory message retains full thinking for this turn, since agentcore may still need it during the same agent_end lifecycle.
func (*Store) AppendModelChange ¶
AppendModelChange records a model switch.
func (*Store) AppendPlanState ¶ added in v0.1.0
func (*Store) AppendReasoningEffortChange ¶ added in v0.3.0
AppendReasoningEffortChange records a reasoning effort switch.
func (*Store) BuildSnapshot ¶
func (s *Store) BuildSnapshot() (ContextSnapshot, error)
BuildSnapshot reconstructs runtime state by walking the tree from the current leaf.
type Task ¶ added in v0.1.1
type Task struct {
ID string `json:"id"`
Subject string `json:"subject"`
Description string `json:"description,omitempty"`
ActiveForm string `json:"activeForm,omitempty"`
Status TaskStatus `json:"status"`
Owner string `json:"owner,omitempty"`
Blocks []string `json:"blocks"`
BlockedBy []string `json:"blockedBy"`
Metadata map[string]any `json:"metadata,omitempty"`
// CompletedAt is set when the task transitions into TaskCompleted and
// cleared if it ever reverts to a non-completed state. Pointer + omitempty
// keeps older persisted JSON files (without this field) loading cleanly.
// The TUI uses it to keep recently-completed tasks pinned to the top of
// the truncated task tree for ~30s before they sink to the bottom.
CompletedAt *time.Time `json:"completedAt,omitempty"`
}
Task is a single tracked work item.
type TaskNotifyFn ¶ added in v0.1.1
type TaskNotifyFn func(TaskSnapshot)
TaskNotifyFn is called after each store mutation with the latest snapshot.
type TaskSnapshot ¶ added in v0.1.1
TaskSnapshot is a read-only snapshot of all tasks sent to the TUI.
type TaskStatus ¶ added in v0.1.1
type TaskStatus string
TaskStatus represents the lifecycle state of a task.
const ( TaskPending TaskStatus = "pending" TaskInProgress TaskStatus = "in_progress" TaskCompleted TaskStatus = "completed" )
type TaskStore ¶ added in v0.1.1
type TaskStore struct {
// contains filtered or unexported fields
}
TaskStore is a thread-safe task store with optional file persistence.
func NewTaskStore ¶ added in v0.1.1
func NewTaskStore() *TaskStore
NewTaskStore creates an empty store.
func (*TaskStore) Claim ¶ added in v0.2.0
Claim atomically assigns owner to task id, but only when the task is in a claimable state: it exists, has no current owner (or already equals owner — idempotent retry), is not completed, and all of its blockedBy dependencies are completed. Returns the updated task on success or a sentinel error explaining the rejection.
This is the CAS primitive that makes work-stealing safe: when two idle teammates race for the same unowned task, only the first Claim succeeds; the loser sees ErrAlreadyClaimed and falls through to find another task. The in-memory mutex is the only lock — codebot is single-process.
Deliberately NOT implemented: a "busy-check" variant that rejects when the claimant already owns another open task. The pull path is strictly sequential per agent (FindClaimable → Claim → run turn → return → pull again), so one-in-flight-per-agent holds by construction; the only case such a check would catch is a model marking two tasks in_progress inside the same turn — a degenerate prompt-shape problem, not a race.
func (*TaskStore) FindClaimable ¶ added in v0.2.0
FindClaimable returns a copy of the next claimable task by ascending ID, or nil when nothing is available. Claimable = owner empty, status != completed, and every blockedBy reference points to a completed task. Pure read; safe for the dispatcher hot loop.
func (*TaskStore) Reset ¶ added in v0.1.1
Reset clears all tasks from memory and persistence while preserving the monotonic task ID sequence for future task creation.
func (*TaskStore) SetDir ¶ added in v0.1.1
SetDir enables file persistence. The directory is created lazily on the first write (persistLocked / writeHighWaterMarkLocked) — sessions that never create a task leave nothing behind on disk.
func (*TaskStore) SetNotifyFn ¶ added in v0.1.1
func (s *TaskStore) SetNotifyFn(fn TaskNotifyFn)
SetNotifyFn registers a callback invoked after every mutation.
func (*TaskStore) Snapshot ¶ added in v0.1.1
func (s *TaskStore) Snapshot() TaskSnapshot
Snapshot returns the current read-only snapshot.
type TaskUpdateOpts ¶ added in v0.1.1
type TaskUpdateOpts struct {
Status *TaskStatus
Subject *string
Description *string
ActiveForm *string
Owner *string
Metadata map[string]any // merged; nil-valued keys are deleted
AddBlocks []string
AddBlockedBy []string
}
TaskUpdateOpts describes optional fields to update.
type TranscriptStore ¶ added in v0.2.0
type TranscriptStore struct {
// contains filtered or unexported fields
}
TranscriptStore persists each teammate's conversation as an append-only JSONL file at <dir>/<agentName>.jsonl — one marshaled agentcore.Message per line, in conversation order. It is the durable counterpart to the in-memory team.EventHub: the hub is lossy (drop-oldest, for live UI), whereas this captures every turn losslessly so a restarted session can rebuild a teammate's full context.
Append is driven from the teammate's turn executor (the same messages the team runner stitches into its history), so persistence and the live loop see identical bytes. Load + RepairMessageSequence reconstruct a valid sequence even when a crash left a half-written tool call at the tail.
func NewTranscriptStore ¶ added in v0.2.0
func NewTranscriptStore(dir string) *TranscriptStore
NewTranscriptStore returns a store rooted at dir (typically config.TeamDir(sessionID)/transcripts). A "" dir disables persistence — every method becomes a no-op — so callers need not special-case it.
func (*TranscriptStore) Append ¶ added in v0.2.0
func (s *TranscriptStore) Append(agent string, msgs []agentcore.AgentMessage) error
Append writes each message as one JSON line, creating the dir/file on first use. Append-only: prior turns are never rewritten, so a resumed teammate's new turns extend the existing transcript rather than duplicating loaded history. Safe for concurrent calls across different agents (one mutex serialises the rare per-turn writes).
func (*TranscriptStore) Load ¶ added in v0.2.0
func (s *TranscriptStore) Load(agent string) ([]agentcore.AgentMessage, error)
Load reads <agent>.jsonl and returns the repaired message sequence ready to seed a resumed teammate via team.SpawnConfig.History. A missing file yields (nil, nil). An invalid, unterminated final line is ignored as a crash-torn append; malformed complete lines are reported.