Documentation
¶
Overview ¶
Package runtime: this file is the thin seam to the read-only intelligence Engine (internal/agent/introspect). The commands themselves were carved off the Session god-object into their own leaf package; Session supplies the Engine its state plus the few runtime-internal callbacks it needs and otherwise just delegates.
Package runtime is the agent loop: orient via the context compiler, call Claude, execute the tool calls it proposes (under the permission gate), capture every step as an event, and stop when the model is done. v0 is the minimal organism: state → context → LLM → tools → edit/command → diff → test → event.
Index ¶
- Constants
- func CodeQuery(ctx context.Context, root, query, scope string) (string, bool)
- func ForkSession(root, srcID string) (string, error)
- func RenderThemeSample(width int) string
- func ResolveSession(root, ref string) (string, error)
- func ResumableSessions(root string) []string
- type AdminExecutor
- type AgentResult
- type AgentSpec
- type ApprovalDecision
- type ApprovalRequest
- type ApprovalScope
- type AskOption
- type AskRequest
- type AskResponse
- type BusyOwner
- type ChatState
- type ContextItem
- type Decision
- type DecisionKind
- type DrainSink
- type GateInput
- type GitStat
- type Orientation
- type PlanExit
- type PlanOpt
- type PlanVerdict
- type Result
- type RouteAction
- type Scheduler
- func (s *Scheduler) Accept(line string, gate GateInput) Decision
- func (s *Scheduler) Cancel() bool
- func (s *Scheduler) DrainSeparate() (activeText, activeTitle string, items []separateAsk)
- func (s *Scheduler) DrainSteers() []string
- func (s *Scheduler) Finish(result TransactionResult) (promoted bool)
- func (s *Scheduler) FoldQueued(expectActive string, ids []string) []string
- func (s *Scheduler) NoteSeparate(items []separateAsk, activeTitle string)
- func (s *Scheduler) PendingClassification() (activeID, active string, items []*Transaction)
- func (s *Scheduler) Snapshot() []string
- func (s *Scheduler) TakeActive() (*Transaction, context.Context, bool)
- type SchedulerObserver
- type Session
- func (s *Session) AddObjective(ctx context.Context, title string) (string, error)
- func (s *Session) AddRedactSecrets(values ...string)
- func (s *Session) Admin() bool
- func (s *Session) Answer(ctx context.Context, scope, question string) (string, error)
- func (s *Session) ArchDoc() string
- func (s *Session) AskAdvisor(ctx context.Context, question, effort string) (string, bool)
- func (s *Session) BrowserEnabled() bool
- func (s *Session) CacheStats() (read, write int)
- func (s *Session) Chat(ctx context.Context) error
- func (s *Session) Checkpoints() []checkpoint.Manifest
- func (s *Session) ClassifyFollowups(ctx context.Context, active string, items []string) (verdicts map[int]followupVerdict, activeTitle string, ok bool)
- func (s *Session) ClassifyPlanIntent(ctx context.Context, text string) bool
- func (s *Session) ClassifyPlanMessage(ctx context.Context, text, task, draft string) (related bool, title string)
- func (s *Session) ClearCredentials()
- func (s *Session) CloseBrowser()
- func (s *Session) CommitGateChoice(ctx context.Context, commitFirst bool)
- func (s *Session) CommitGateNeeded(ctx context.Context) bool
- func (s *Session) Compact(ctx context.Context, st *ChatState) string
- func (s *Session) Connected() bool
- func (s *Session) ContextTokens() int
- func (s *Session) ContextWindow() int
- func (s *Session) DeferWhilePlanning(text, title string)
- func (s *Session) DelegatedModel() string
- func (s *Session) DisplayModel() string
- func (s *Session) DrainPlanDeferred() []string
- func (s *Session) DrainShellReportBacks() []ShellReportBack
- func (s *Session) EffortOverride() string
- func (s *Session) Emit(ctx context.Context, kind events.Kind, payload map[string]any)
- func (s *Session) EndChat(ctx context.Context)
- func (s *Session) Endpoint() (provider.Endpoint, bool)
- func (s *Session) EnterPlan(ctx context.Context, opts ...PlanOpt)
- func (s *Session) ExitPlan(ctx context.Context, approved bool)
- func (s *Session) ExtraMile() bool
- func (s *Session) GitStat(ctx context.Context) GitStat
- func (s *Session) Intelligence(ctx context.Context, command, arg string) (string, bool)
- func (s *Session) InvalidateModels()
- func (s *Session) JobsRender() string
- func (s *Session) KillAllJobs()
- func (s *Session) KillJobArg(arg string) string
- func (s *Session) Lanes() []provider.LaneInfo
- func (s *Session) LastError() error
- func (s *Session) LastText() string
- func (s *Session) Mode() permissions.Mode
- func (s *Session) Model() string
- func (s *Session) Orientation(ctx context.Context) Orientation
- func (s *Session) Personality() string
- func (s *Session) PersonalityBlurb(ctx context.Context) string
- func (s *Session) PersonalityResolved() string
- func (s *Session) Pin() string
- func (s *Session) PlanGateSnapshot() (task, draft string)
- func (s *Session) PlanPhaseEpoch() (plan.Phase, int)
- func (s *Session) PlanPolicyOverride(target string) map[string]any
- func (s *Session) PlanPresentable() bool
- func (s *Session) PlanYolo() bool
- func (s *Session) Planning() bool
- func (s *Session) Policy() *policy.Resolver
- func (s *Session) PolicySummary() string
- func (s *Session) ReasoningDisplay() string
- func (s *Session) Restricted() bool
- func (s *Session) ReviewPlanWith(ctx context.Context, plan, model string) (string, string)
- func (s *Session) Rewind(seq int) ([]string, error)
- func (s *Session) Room() room.State
- func (s *Session) Root() string
- func (s *Session) Run(ctx context.Context, task string) (Result, error)
- func (s *Session) RunFollowupClassifier(ctx context.Context, sched *Scheduler, kick <-chan struct{})
- func (s *Session) RunPlan(ctx context.Context, task string) (string, error)
- func (s *Session) RunShellLine(ctx context.Context, line string) bool
- func (s *Session) RunTransaction(ctx context.Context, st *ChatState, tx *Transaction)
- func (s *Session) RunningJobs() int
- func (s *Session) RunningShells() []jobs.View
- func (s *Session) ServedBy() string
- func (s *Session) ServedByok() bool
- func (s *Session) ServingModel() string
- func (s *Session) SessionID() string
- func (s *Session) SetAdmin(exec AdminExecutor)
- func (s *Session) SetApprover(fn func(context.Context, ApprovalRequest) ApprovalDecision)
- func (s *Session) SetAsker(fn func(context.Context, AskRequest) AskResponse)
- func (s *Session) SetBrowserEnabled(enabled bool)
- func (s *Session) SetBrowserHeadless(on bool)
- func (s *Session) SetContext(items []ContextItem)
- func (s *Session) SetCredentials(url, token string)
- func (s *Session) SetEffortOverride(level string)
- func (s *Session) SetExtraMCPServers(servers map[string]mcp.ServerConfig)
- func (s *Session) SetExtraMile(on bool)
- func (s *Session) SetMode(m permissions.Mode)
- func (s *Session) SetModel(model string)
- func (s *Session) SetNoApprover(on bool)
- func (s *Session) SetNoContext(v bool)
- func (s *Session) SetObserver(o UIObserver)
- func (s *Session) SetOutput(w io.Writer)
- func (s *Session) SetPersonality(p string)
- func (s *Session) SetPin(label string, window int)
- func (s *Session) SetPolicy(r *policy.Resolver)
- func (s *Session) SetResume(id string)
- func (s *Session) SetSeparateDrain(f func() (activeText string, activeTitle string, items []separateAsk))
- func (s *Session) SetServingDefault(model string)
- func (s *Session) SetSessionID(id string)
- func (s *Session) SetSkillRoots(roots []string)
- func (s *Session) SetSteerDrain(f func() []string)
- func (s *Session) SetTaskAttachments(atts []input.Attachment)
- func (s *Session) SetToolNotify(fn func(label string))
- func (s *Session) SetToolPolicy(allow, deny []string) (unknown []string)
- func (s *Session) SetWidth(w int)
- func (s *Session) Spend() (in, out, cacheRead, cacheWrite int, usd float64)
- func (s *Session) SpendByBackend() []ledger.BackendSpend
- func (s *Session) SpendByPurpose() []ledger.PurposeSpend
- func (s *Session) StartChat(ctx context.Context) *ChatState
- func (s *Session) Submit(ctx context.Context, st *ChatState, line string)
- func (s *Session) Sync(ctx context.Context, targets []config.SyncTarget) (string, error)
- func (s *Session) SyncDetect() []memsync.DetectedTarget
- func (s *Session) TailJobArg(arg string) string
- func (s *Session) ThinkingEffort() string
- func (s *Session) Tokens() (in, out int)
- type ShellReportBack
- type SteerEvent
- type Transaction
- type TransactionResult
- type TxState
- type UIObserver
Constants ¶
const ( KindInstruction = "instruction" KindMemory = "memory" KindReference = "reference" KindHistory = "history" )
Generic context kinds. Callers classify their material into these; the engine orders by them and knows nothing more.
Variables ¶
This section is empty.
Functions ¶
func CodeQuery ¶ added in v0.10.0
CodeQuery is the deterministic "where does X live" oracle over root — a ranked search with no model loop. Shared by the agent tool (Session.codeQuery) and the standalone `memcode mcp serve` memory server, so an external agent gets the same answer. ok=false marks a usage error (no terms, bad scope, timeout); a no-match result is ok=true with a guidance string.
func ForkSession ¶
ForkSession copies srcID's saved transcript (and its checkpoints) to a fresh session id and returns it — the original session is untouched. Fork-from-disk is safe because the transcript persists at every turn boundary and callers refuse to fork mid-turn, so disk equals the live history. The episodic log (events.jsonl/transcript.md) is DELIBERATELY not copied: session search, recall, and the focus reducer scan every session dir, and a duplicated history would double-count what happened — the original keeps the episodic truth, and the fork starts logging its own from here. Checkpoints ride along (best-effort) so /rewind still reaches pre-fork turns in the fork.
func RenderThemeSample ¶
RenderThemeSample renders a tiny fixed diff snippet using the ACTIVE theme — the real diff add/del backgrounds, gutters, and syntax highlighting — so the /theme picker's live preview shows what code review actually looks like, not just chrome. It reads the active theme live (newDiffCtx), so it recolors as the picker previews.
func ResolveSession ¶
ResolveSession maps a user reference to a resumable session id: ""/"latest" → the most recently saved transcript; otherwise an exact id or unique prefix ("sess_" optional). Only sessions WITH a saved transcript qualify — older sessions predating transcript persistence are recall-only.
func ResumableSessions ¶
ResumableSessions lists resumable session ids, newest first (for pickers).
Types ¶
type AdminExecutor ¶ added in v0.18.0
AdminExecutor performs one admin tool operation (cmd-injected; see cmd/admin_tools.go). It is only invoked after the runtime's gate approves a mutation; read-only calls run directly.
type AgentResult ¶
type AgentResult struct {
Text string
ToolCalls int
ServedBy string // which model actually ran it
}
AgentResult is a sub-agent's report-back: its final text plus the telemetry callers surface (the tool-count + served-by on the marker line).
type AgentSpec ¶
type AgentSpec struct {
Task string // the self-contained instruction the sub-agent runs to completion
ReadOnly bool // read-only (no edits/mutating bash) vs a full mutating agent
Scope string // optional subsystem/path tag (telemetry + scout focus)
IterCap int // 0 = mode default
Purpose llm.Purpose // ledger attribution; also picks the run shape (Explore → scout prompt)
Effort wire.Effort // pin the sub-agent's thinking effort ("" = its own per-turn heuristic)
}
AgentSpec is everything that configures a sub-agent. Defaults (zero value) are a mutating, MainLoop-ish agent; callers set what they need.
type ApprovalDecision ¶
type ApprovalDecision struct {
Allow bool // run it
Remember bool // and don't ask again for like commands (persist an approval rule)
RememberScope string // when Allow: the chosen ApprovalScope.Key ("" = none / plain yes)
Command string // when Allow and non-empty: run THIS instead of the original
Reason string // when !Allow: why — fed back to the model so it can adjust
Interrupt bool // STOP the whole turn (Esc / "No, stop") — the model does not get another call
Redirect bool // when !Allow with a typed Reason: deny this action and skip its siblings, but let the turn CONTINUE so the model reads the feedback and responds (does NOT terminate)
}
ApprovalDecision is the user's structured answer. It generalizes yes/no into the four outcomes a real agent needs: allow · allow-with-edited-input · deny-with-reason · interrupt (stop going down this path entirely).
func Denied ¶
func Denied(reason string) ApprovalDecision
Denied is a no, optionally with a reason the model will see.
type ApprovalRequest ¶
type ApprovalRequest struct {
Title string // the thing being approved — the command, or "edit <path>"
Label string // category header, e.g. "Bash command" / "Edit file"
Detail string // optional one-line description under the title
Command string // the command, when this is a command (so it can be edited/remembered)
Cwd string // working directory for a command (for the "don't ask again … in <dir>" scope)
Editable bool // whether "allow with edited command" / "don't ask again" apply (commands)
Risk string // risk class label
// RememberScopes replaces the single default don't-ask-again option with one card
// option per scope (MCP: remember this tool / remember the whole server). When set,
// the card reads Execute / <scopes…> / Cancel and Cancel is a plain deny.
RememberScopes []ApprovalScope
}
ApprovalRequest is a structured description of an action awaiting the user's OK. The metadata (Title/Label/Detail) lets a front-end render a rich prompt; Command + Editable enable "allow, but run this instead". This replaces the old bare prompt string — a boolean approver is too crude for a serious agent.
type ApprovalScope ¶
type ApprovalScope struct {
Key string // returned in ApprovalDecision.RememberScope when chosen
Label string // full option text on the card
}
ApprovalScope is one scoped "and don't ask again" option a request offers.
type AskOption ¶
AskOption is one candidate answer — a concise Label plus an optional muted Description line. Aliased to the tool-input type so there's ONE shape from the model's JSON through to the rendered card.
type AskRequest ¶
type AskRequest struct {
Question string
Options []AskOption // 2-4 choices (label + optional description); the user may also type their own
}
AskRequest is a clarifying question the agent poses to the user (HITL).
type AskResponse ¶
type AskResponse struct{ Answer string }
AskResponse is the user's answer (a chosen option or free text); empty means the user dismissed it (the agent should then proceed on its best judgment).
type BusyOwner ¶
type BusyOwner int
BusyOwner says who owns the frontend's busy state. OwnerTurn is a scheduler transaction (queueing behind it is normal); OwnerAsync is a non-transaction operation (advisor, /compact) that a new turn must not trample.
type ChatState ¶
type ChatState struct {
// contains filtered or unexported fields
}
ChatState holds the evolving state of an interactive session — the system prompt, the running message history, and the queued follow-ups — so any front-end (the line-REPL below or the TUI) can pump input lines via Submit while the runtime owns routing and the agent loop.
type ContextItem ¶ added in v0.13.0
type ContextItem struct {
Kind string `json:"kind"`
Content string `json:"content"`
Source string `json:"source,omitempty"` // provenance label for the injected block header
}
ContextItem is one piece of supplemental context handed to the engine by a caller (the agent runtime, an API, CI). The engine stays ignorant of where it came from: Kind is a GENERIC content class, never an orchestration concept like "agent", "user", "channel", or "conversation". Those live above the engine and are flattened into these generic items before an invocation.
type Decision ¶
type Decision struct {
Kind DecisionKind
Pos int // 1-based queue position (Queued / Coalesced)
Tx *Transaction // the started or queued transaction (nil for Steered)
}
Decision is the outcome of accept — for the UI to acknowledge.
type DecisionKind ¶
type DecisionKind int
DecisionKind is what the scheduler did with an accepted line.
const ( DecisionStarted DecisionKind = iota // started a transaction now (was idle) DecisionQueued // queued behind the active transaction DecisionCoalesced // merged into the previous queued item (rapid paste) DecisionSteered // folded into the active transaction as a steer DecisionAwaitVerdict // planning, unclassified — classify, then Accept again with the verdict (nothing mutated) DecisionPlanDeferred // classified separate — the frontend parks it (nothing mutated) DecisionBusyDeclined // an async op owns busy while idle — declined (nothing mutated, no ghost tx to cancel) )
type DrainSink ¶
type DrainSink int
DrainSink is where drained deferred messages go.
func PlanDrainSink ¶
PlanDrainSink is the ONE policy for replaying parked messages at a plan exit — the three hand-rolled drain loops used to each encode a different slice of it.
type GateInput ¶
type GateInput struct {
Phase plan.Phase // the plan machine's phase at submit/finalize time
PlanEpoch int // epoch the verdict was computed against (0 = n/a)
CurrentEpoch int // the machine's epoch NOW (finalize time)
Verdict PlanVerdict // the relevance verdict, when one exists
Busy BusyOwner // who owns the frontend's busy state
// Internal marks a system-generated accept (the plan task itself, the apply
// instruction, a revise, an already-classified deferred replay): it bypasses the
// plan gate by construction (Phase zero) AND pre-marks a queued tx classified, so
// the background follow-up classifier never judges system text against the active
// task (folding "Begin implementing the approved plan" as a steer broke the apply).
Internal bool
}
GateInput is the non-scheduler context a frontend supplies with each accept. The zero value is exactly today's plain-chat behavior: chatting, no verdict, not busy.
type GitStat ¶
type GitStat struct {
Files, Added, Removed int // unstaged working tree + untracked
StagedFiles, StagedAdded, StagedRemoved int // index (git add'd)
}
GitStat is the working-tree summary surfaced in the footer cockpit: how many files are dirty and the +/- line churn, split into unstaged (working tree, incl. untracked) and staged (index). A clean tree is the zero value.
type Orientation ¶
type Orientation struct {
Repo string
Branch string
Subsystems int
Highlights []string // top subsystem keys by activity (for a concrete prompt)
ClaimsCurrent int
ClaimsStale int
ClaimsConflicted int
Sources int
}
Orientation is the "I know where I am and what I know about this repo" summary the TUI shows on the opening screen, so the first moment proves memcode is repo-aware rather than a blank chatbot.
type PlanExit ¶
type PlanExit int
PlanExit names how a plan session ended, for the deferred-message drain policy.
type PlanOpt ¶
PlanOpt is a functional option for EnterPlan — an alias for plan.Opt so existing callers (WithYolo) compile unchanged.
type PlanVerdict ¶
type PlanVerdict int
PlanVerdict is the plan-relevance classifier's answer as data.
const ( VerdictNone PlanVerdict = iota // not classified (yet) VerdictRelated // continues/steers the plan being drafted VerdictSeparate // a separate ask — park it until the plan is done )
type Result ¶
type Result struct {
SessionID string `json:"session_id"`
Iterations int `json:"iterations"`
ToolCalls int `json:"tool_calls"`
WrongTurns int `json:"wrong_turns"` // failed tool calls
FilesRead int `json:"files_read"`
FilesChanged []string `json:"files_changed"`
DiffLines int `json:"diff_lines"`
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
Verified bool `json:"verified"` // a verification command passed
}
Result reports measurable outcomes of a session (used by the A/B harness).
type RouteAction ¶
type RouteAction int
RouteAction is the single vocabulary for what happens to an incoming message.
const ( ActStartTurn RouteAction = iota // idle → run it now ActSteer // fold into the active transaction ActQueue // run after the active transaction ActCoalesce // merge into the last queued item (rapid burst) ActAwaitVerdict // planning, unclassified → classify first, re-enter with the verdict ActDeferForPlan // classified separate → park until the plan exits ActRejectBusy // an async op owns busy and nothing is active — decline politely )
type Scheduler ¶
type Scheduler struct {
// contains filtered or unexported fields
}
Scheduler is the actor wrapper around schedState: ONE owner goroutine (run) holds the state and serializes every access through a command channel. Neither the TUI intake nor the executor mutates scheduler state directly — they only send commands and read replies — so there is no shared mutable state to race (the design constraint).
Drivers:
- intake (TUI Update goroutine): Accept / Cancel / Snapshot — fast, synchronous round-trips; they never block on execution.
- executor (TUI engine goroutine): on a "run" kick, TakeActive() → RunTransaction → Finish; DrainSteers mid-run at the runLoop safe boundary. TakeActive is NON-BLOCKING so the executor can keep selecting on its other inputs (sentinels).
The actor owns the per-transaction context: TakeActive mints context.WithCancel and stores the cancel, so Cancel() is just a command and the executor never owns cancellation state.
func NewScheduler ¶
NewScheduler starts the actor goroutine; it runs until parent is cancelled. clock is injectable for tests — pass time.Now in production.
func (*Scheduler) Accept ¶
Accept routes one submitted line against the current state (intake; never blocks on execution). gate carries the non-scheduler context (plan phase/epoch, relevance verdict, busy owner) — GateInput{} is plain-chat behavior. Returns what the scheduler did, for the UI to acknowledge; the AwaitVerdict/PlanDeferred/BusyDeclined kinds mutated nothing and expect the frontend to act (classify / park / decline).
func (*Scheduler) Cancel ¶
Cancel aborts the active transaction (Esc/Ctrl-C): marks it cancelling, cancels its context, and DISCARDS the queue — interrupt means STOP, not advance to the next queued item. Reports whether there was an active transaction.
func (*Scheduler) DrainSeparate ¶
DrainSeparate returns and clears the buffered separate-task items, along with the active transaction's raw text and the classifier's synthesized title for it (for seeding a "current task" placeholder todo item the first time this fires — both go through the synthTitle guard, so raw prose never becomes a list title) — called at the runLoop safe boundary.
func (*Scheduler) DrainSteers ¶
DrainSteers returns and clears the active transaction's pending steers — called at the runLoop safe boundary to fold `+input` into the active turn.
func (*Scheduler) Finish ¶
func (s *Scheduler) Finish(result TransactionResult) (promoted bool)
Finish marks the active transaction terminal and promotes the next queued one (FIFO). Returns true when a transaction was promoted — the executor should kick itself to run it.
func (*Scheduler) FoldQueued ¶
FoldQueued promotes the named queued transactions into the active transaction as steers (the classifier's "related" verdict) and returns their folded texts. expectActive is the active-tx id the classifier judged against — the fold is dropped if the active tx changed since (so a refinement of a finished task can't steer an unrelated running turn).
func (*Scheduler) NoteSeparate ¶
NoteSeparate records items the background follow-up classifier judged SEPARATE from the active task (the "not related" verdict) — they stay queued to run as their own turn later, but this buffers them so the runLoop safe boundary can track them on the todo list and give the model a brief FYI note (see DrainSeparate). activeTitle is the SAME classify call's synthesized title for the CURRENT task (empty when synthesis failed).
func (*Scheduler) PendingClassification ¶
func (s *Scheduler) PendingClassification() (activeID, active string, items []*Transaction)
PendingClassification returns the active task's text and the queued transactions the background follow-up classifier hasn't examined yet (marking them examined). The classifier runs the cheap structured-output model OFF the actor goroutine, then calls FoldQueued with the ids it judged related to the active task.
func (*Scheduler) Snapshot ¶
Snapshot returns the queued transactions' texts (for a quiet UI indicator).
func (*Scheduler) TakeActive ¶
func (s *Scheduler) TakeActive() (*Transaction, context.Context, bool)
TakeActive hands the active, not-yet-running transaction to the executor with its cancellable context. NON-BLOCKING: returns (nil, nil, false) when nothing is ready, so the executor stays free to handle its other inputs. The executor calls this on a "run" kick (after Accept reported Started, or after Finish promoted the next).
type SchedulerObserver ¶
SchedulerObserver is notified (best-effort) when the active/queued set changes, so a front-end can render a quiet "(N queued)" indicator. The queue is runtime-managed; there is no user-facing queue-editing command in Phase 1.
type Session ¶
type Session struct {
// contains filtered or unexported fields
}
Session runs one agent task against a project.
func New ¶
func New(st store.Store, runner *llm.Runner, root, model string, mode permissions.Mode, out io.Writer) *Session
New constructs a Session.
func (*Session) AddObjective ¶
AddObjective records a human-authored goal for this project (the `/goal` command). Objectives are never inferred; this is the user asserting one.
func (*Session) AddRedactSecrets ¶
AddRedactSecrets registers additional secret values with the session's redactor (e.g. the token /login just received) so they never reach transcripts, traces, or tool output.
func (*Session) Admin ¶ added in v0.18.0
Admin reports whether this is an admin session (the TUI swaps its slash set).
func (*Session) Answer ¶
Answer runs a read-only investigation to completion and returns the model's final text. It is the unit of a parallel explorer (a "reader" sub-agent): it orients on a scope, reads/searches under the read-only tool set, and never edits or runs MUTATING commands (it may run read-only shell commands like git log via the gated inspect shell) — so any number can run concurrently with no serialized-writer contention. Output is suppressed (the orchestrator owns presentation); every tool call is still recorded as an event.
func (*Session) ArchDoc ¶
ArchDoc renders the repo's architecture diagrams verbatim from its docs (deterministic).
func (*Session) AskAdvisor ¶
AskAdvisor sends a question (plus light session context) to the gateway's second-opinion advisor — a DIFFERENT vendor from the coding lanes; the gateway owns which model serves it — and returns its advice. effort is the reasoning depth (low|medium|high; "" → high). This is a deliberate user action (/advisor, or "Ask an advisor" in plan mode), not part of the coding-inference path. Returns (text, ok).
func (*Session) BrowserEnabled ¶
BrowserEnabled reports whether --chrome is active (browser tools are advertised and a Chrome session may be launched). Used by the TUI's /dispatch to forward the capability to spawned sub-agents.
func (*Session) CacheStats ¶
CacheStats returns cumulative prompt-cache token counts (read ≈ 10% cost; write = tokens written to the cache). Shown under /debug.
func (*Session) Chat ¶
Chat runs the line-REPL interactive session: streamed stdin with time-based coalescing and routing, multimodal attachments, persisted events. The TUI drives the same StartChat/Submit/EndChat seams without owning stdin.
func (*Session) Checkpoints ¶
func (s *Session) Checkpoints() []checkpoint.Manifest
Checkpoints lists this session's rewind points (turns that edited files), oldest first.
func (*Session) ClassifyFollowups ¶
func (s *Session) ClassifyFollowups(ctx context.Context, active string, items []string) (verdicts map[int]followupVerdict, activeTitle string, ok bool)
ClassifyFollowups asks the cheap structured-output classifier which queued follow-ups refine the active task. Returns one verdict per index: Related marks a fold, and Title — present only for a SEPARATE verdict — is the classifier's concise, synthesized todo-list title (never the raw text). It ALSO returns activeTitle: the SAME classifier call's synthesized title for the CURRENT task itself (same call, no extra cost) — used to seed the placeholder todo item for the active task instead of clipping its raw text. ok=false means NO classification happened (error / timeout / missing context): the caller must treat the batch as unjudged — retry or leave it queued — never as a set of "separate" verdicts (an empty map read through Go's zero value is what used to turn every classify hiccup into untitled "separate tasks" pasted verbatim onto the todo list). Safe to call concurrently with the active turn (the metered Runner is concurrency-safe).
func (*Session) ClassifyPlanIntent ¶
ClassifyPlanIntent resolves the AMBIGUOUS middle of plan-request detection — the front-end's deterministic heuristic handles clear yes/no and only escalates here when "plan" is present but the intent is unclear. Lives on Session (not the introspect Engine) so it rides the shared judge plumbing (traced, failure-counted). Best-effort: any error/timeout/parse miss → false, so ambiguity never hijacks an ordinary turn into plan mode.
func (*Session) ClassifyPlanMessage ¶
func (s *Session) ClassifyPlanMessage(ctx context.Context, text, task, draft string) (related bool, title string)
ClassifyPlanMessage asks the cheap structured-output classifier whether text continues the plan anchored at task (with draft — the pinned LastPlan, possibly empty — as context), or is a separate request that should be parked. task/draft are passed in, not read from s.planCtl, so the call is safe off-goroutine: take them from PlanGateSnapshot. Returns related=true (fold-in, the safe default) when there is no task anchor to judge against (e.g. a test that sets planCtl.Active directly without going through EnterPlan), and on ANY classify error/timeout/parse miss — an infra hiccup must never silently swallow a genuine follow-up by mistaking it for something separate. title is populated only for a related=false verdict and is the classifier's synthesized title, never raw text.
func (*Session) ClearCredentials ¶
func (s *Session) ClearCredentials()
ClearCredentials disconnects the provider (the /logout path).
func (*Session) CloseBrowser ¶
func (s *Session) CloseBrowser()
CloseBrowser tears down the Chrome process if one was launched. Safe to call when no browser session exists (nil-safe). Called at session end.
func (*Session) CommitGateChoice ¶
CommitGateChoice is the TUI's entry point when the PLAN SELECTOR carries the commit decision ("Commit first, then execute" / "Execute without committing") instead of a second card: it performs the commit when asked and marks the gate resolved so the apply turn doesn't re-ask.
func (*Session) CommitGateNeeded ¶
CommitGateNeeded reports whether the plan selector should offer the commit choice: interactive, a git repo, a dirty tree, and no remembered preference (a remembered "commit"/"skip" is honored silently by commitGateOK).
func (*Session) Compact ¶
Compact is the manual /compact entry point: force a compaction now and return a one-line result for the front-end to print (success line, or why it was a no-op).
func (*Session) Connected ¶
Connected reports whether the session's provider has a usable backend — hosted gateway credentials OR a configured custom endpoint (the Phase C widening; the seam is provider.Connector). Providers without the Connector capability (test fakes, futures) count as connected — the mandatory-login gate only applies to the real lazy client.
func (*Session) ContextTokens ¶
ContextTokens returns the input size of the latest MAIN conversation call — an estimate of how full the context window currently is (footer "ctx N%"). Read under dispMu (snapshot): the engine writes s.served mid-turn while View reads this every frame.
func (*Session) ContextWindow ¶
ContextWindow returns the input window (tokens) the meter measures against. It prefers the serving backend's REAL window when the gateway reported one (the lane's max_model_len — often far smaller than the model-name default), so the meter warns before a self-hosted overflow instead of reading a comfortable 14%. Falls back to the model's nominal window (Anthropic turns report none).
func (*Session) DeferWhilePlanning ¶
DeferWhilePlanning parks a message the plan-intake classifier judged SEPARATE from the plan: it never reaches the scheduler while planning (so it can't corrupt the draft), and is instead tracked on the todo list — same synthTitle guard noteSeparateRequests uses, so raw prose never lands on the list even when the classifier gave no title — and stays visible instead of silently vanishing until DrainPlanDeferred replays it. Unlike noteSeparateRequests, there is no live turn's *messages to append an FYI note into — this fires OUTSIDE any turn, off the composer's intake path.
func (*Session) DelegatedModel ¶ added in v0.31.0
DelegatedModel reports the model delegated work runs on, resolved through policy. It exists for display (/status, /policy) — decision points resolve the target they care about rather than asking a general question.
func (*Session) DisplayModel ¶
DisplayModel is what the cockpit (footer/banner//status) shows as THE model: the /model pin when one is set — the user picked it, so that's the identity, even before the first pinned turn serves (ServingModel would still show the pre-pin lane) — else the served/default model. The ⇄ line keeps reporting per-turn serving reality (absorbs included).
func (*Session) DrainPlanDeferred ¶
DrainPlanDeferred pops and clears every message parked by DeferWhilePlanning, FIFO — called on ExitPlan (Execute or Cancel) so parked messages run once the plan work that pushed them aside is actually done, exactly as the user asked.
func (*Session) DrainShellReportBacks ¶
func (s *Session) DrainShellReportBacks() []ShellReportBack
DrainShellReportBacks returns the promoted commands that finished since the last call, each once, with their result redacted for hand-back to the model. Polled by the UI.
func (*Session) EffortOverride ¶
func (*Session) Emit ¶
Emit is the public alias of emit — the plan.Controller's Session interface needs a callable emitter, and interface methods must be exported. Same behavior as emit.
func (*Session) EndChat ¶
EndChat records the session-finished event and closes the episodic log. Idempotent enough for one call.
func (*Session) EnterPlan ¶
EnterPlan switches the session into plan mode: research-only tools, the reasoning model, and the planning system prompt. Records plan_started. Delegates to the plan.Controller machine; already planning/applying → no-op.
func (*Session) ExitPlan ¶
ExitPlan leaves plan mode, restoring the prior model. approved distinguishes an /execute handoff (Approve: pins the contract, arms the apply turn) from a /cancel (Cancel: abandon); either way the lifecycle event is recorded.
func (*Session) GitStat ¶
GitStat computes the current working-tree diffstat. It shells out to git, so the TUI must call it OFF the render path (a tea.Cmd), cache the result, and re-run it on a throttle / at turn end — never per frame.
func (*Session) Intelligence ¶
Intelligence runs a read-only memcode command for the TUI's "orient me" shortcuts.
func (*Session) InvalidateModels ¶
func (s *Session) InvalidateModels()
InvalidateModels drops the Runner's control-plane snapshot (roles, byok coverage, credits state) so the next model call refetches — the hook for /login, /apikeys mutations, and anything else that changes selection inputs.
func (*Session) JobsRender ¶
JobsRender lists the running shells (by slot) for /jobs. Finished/failed attempts aren't shown — they live in the session log, not the user's working set.
func (*Session) KillAllJobs ¶
func (s *Session) KillAllJobs()
KillAllJobs reaps every running job (session end — nothing orphans).
func (*Session) KillJobArg ¶
KillJobArg powers /kill (and the agent's jobs-kill). The arg is a SHELL SLOT: empty stops the lone running shell (lists when several); a slot that isn't running shows what IS running instead of a dead-end.
func (*Session) Lanes ¶ added in v0.26.0
Endpoint reports the ACTIVE custom endpoint when the session runs against an arbitrary OpenAI-compat backend instead of the memcode gateway (one-wire Phase C). ok=false on the hosted gateway, signed out, and providers without the Endpointer capability (test fakes). The TUI keys the /model picker, cost display, and login-card copy on this; the runtime keys tool gating on it. Lanes reports the attached family lanes (subscriptions + own keys), empty off the Laner seam (exclusive endpoint mode, test fakes).
func (*Session) LastError ¶
LastError returns the terminal error of the most recent turn (nil on success). Meaningful on the synchronous one-shot path (agent -c / resumed one-shot), where a non-nil result must surface as a non-zero exit code for scripting/CI.
func (*Session) LastText ¶
LastText returns the most recent assistant message — e.g. the just-proposed plan — so the front-end can hand it to the (stateless) advisor for review. The advisor has no session access, so without this the plan would never reach it.
func (*Session) Mode ¶
func (s *Session) Mode() permissions.Mode
Mode returns the active permission mode.
func (*Session) Orientation ¶
func (s *Session) Orientation(ctx context.Context) Orientation
Orientation gathers the deterministic repo summary (no model call).
func (*Session) Personality ¶
Personality returns the chosen voice ("" = default).
func (*Session) PersonalityBlurb ¶
PersonalityBlurb returns a one-line greeting in the currently-set voice (best-effort).
func (*Session) PersonalityResolved ¶
PersonalityResolved returns the concrete voice in effect ("" = default): the session's random roll when personality is "random", else the chosen voice. Display uses this; persistence keeps the literal choice.
func (*Session) PlanGateSnapshot ¶
PlanGateSnapshot returns the plan anchor task + pinned draft atomically — the machine's own lock covers the read (Controller.Snapshot), so it is safe from the TUI's classify goroutine while the turn goroutine pins the contract at synthesis. Callers snapshot first, then pass the copies into ClassifyPlanMessage.
func (*Session) PlanPhaseEpoch ¶
PlanPhaseEpoch returns the plan machine's phase and session epoch atomically — the pair the intake gate stamps on a submission so an async relevance verdict can be staleness-checked when it lands.
func (*Session) PlanPolicyOverride ¶ added in v0.31.0
PlanPolicyOverride reports policy the user attached to the plan currently in flight, nil when none. It lives on the plan controller and dies with the plan.
func (*Session) PlanPresentable ¶
PlanPresentable reports whether the most recent plan turn actually rendered a plan to approve. The TUI gates the "Plan ready" approval selector on this so an interrupted plan turn (Ctrl-C on a clarifying question) never raises a selector with no plan behind it.
func (*Session) PlanYolo ¶
PlanYolo reports whether the current plan was started with /yolo — suppress HITL questions during planning and auto-execute the plan without showing the selector.
func (*Session) Policy ¶ added in v0.31.0
Policy exposes the resolver so callers at a decision point can read it, and so the /policy view and the policy tool can show and mutate the session layer.
func (*Session) PolicySummary ¶ added in v0.31.0
policySummary answers "how have I customized memcode?" — every target, its effective value, and WHERE each value came from. Per-field resolution across four layers is only comprehensible if the source is visible.
func (*Session) ReasoningDisplay ¶
ReasoningDisplay returns the HONEST reasoning-depth tier the SERVING model is actually using this turn ("high"/"max"/"medium"/"low"), or "" when the model exposes no thinking — for the status line. It is lane-aware (reasoningTier): a hybrid open model (GLM etc.) reasons at HIGH on ordinary turns and MAX on hard ones, matching the gateway's reasoning_effort policy; an Anthropic adaptive model shows its effort tier; anything else shows nothing. This replaces the old label that always read "effort: off" — which LIED on the cheap lane (GLM was actually at high/max).
func (*Session) Restricted ¶ added in v0.28.0
Restricted reports whether the session is a restricted management console (admin): a limited slash whitelist, no repo/coding tools.
func (*Session) ReviewPlanWith ¶ added in v0.29.0
ReviewPlanWith runs a ONE-SHOT plan critique on a model the USER named on the approval card ("Review with another model").
This is deliberately its own category: not utility inference (it is not plumbing, and the user chose it), and not routing (nothing selected it on the user's behalf). It is an explicit, user-directed second opinion, scoped to this one operation.
The chosen model runs on an ephemeral fork. The session pin, the workspace store, and the user store are untouched, the footer keeps showing the session model, and any revision the critique prompts runs back on the pinned model. Returns the critique prose and the model that produced it.
func (*Session) Rewind ¶
Rewind restores every file edited from checkpoint seq onward to its state before that turn ran. Returns the restored paths.
func (*Session) RunFollowupClassifier ¶
func (s *Session) RunFollowupClassifier(ctx context.Context, sched *Scheduler, kick <-chan struct{})
RunFollowupClassifier is the background loop (one goroutine per session) that drives the batched classify. kick is signaled by the front-end on each mid-turn queue submit; the loop debounces, then within followupMaxWait classifies the whole pending batch against the active task and folds the related ones into it as steers. Runs until ctx is done. The classify call runs here, OFF the scheduler's actor goroutine, so it never stalls intake.
func (*Session) RunPlan ¶
RunPlan produces a single, detailed plan for task in plan mode — research-only tools, the reasoning model, the planning prompt — and returns the plan text. It makes NO changes; the interactive TUI is where a plan is iterated on and then executed.
func (*Session) RunShellLine ¶
RunShellLine runs a `$`/`>` shell-lane line IMMEDIATELY, outside the turn scheduler — it's a LOCAL capture action (a command the user typed by hand), not an agent turn, so it must never queue behind an active turn. Reports whether the line was actually a shell route (false → the caller routes it normally through the scheduler). Safe to call concurrently with a running turn: the front-end owns its own busy/spinner state (the observer's Busy is a no-op) and command output is marshalled onto the UI thread, so a hand-run `$ git status` interleaves cleanly mid-turn.
func (*Session) RunTransaction ¶
func (s *Session) RunTransaction(ctx context.Context, st *ChatState, tx *Transaction)
RunTransaction executes one scheduled transaction as a turn — the TUI executor's entry point. The scheduler already routed (this is an active, promoted transaction), so this just scores and runs. A `$`-prefixed transaction takes the direct-shell lane. Steers submitted into this transaction while it runs are folded in by runLoop (SetSteerDrain).
func (*Session) RunningJobs ¶
RunningJobs is the count of live shells — the footer's "N shells".
func (*Session) RunningShells ¶
RunningShells snapshots this session's background shells that are still running — the live surface behind the footer "N shells" segment and the idle-row indicator. In-memory and mutex-cheap, so the TUI may call it on the render path (unlike the agent count, which polls the filesystem).
func (*Session) ServedBy ¶
ServedBy returns a compact label for WHO served the last call — the cheap-lane model's short name (e.g. "glm-5p1") when the cheap lane served it, else the model short name ("sonnet"/"haiku"). Used to tag a scout's Explore marker so you can see, per fan-out, whether it hit the cheap lane or fell back to Anthropic. "" if nothing served yet.
func (*Session) ServedByok ¶
ServedByok reports whether the LAST main call served on the user's own provider key — the footer's per-turn byok segment. Strictly last-turn state: recordServed writes it unconditionally, so a non-BYOK turn clears it.
func (*Session) ServingModel ¶
ServingModel returns the model that ACTUALLY served the last main call — which differs from Model() when a turn escalates (e.g. an apply turn runs on Opus while the session default is Sonnet). The footer uses this so it reflects reality, not the static default.
func (*Session) SetAdmin ¶ added in v0.18.0
func (s *Session) SetAdmin(exec AdminExecutor)
SetBrowserEnabled enables the browser tools (--chrome). When enabled, the browser toolset is advertised to the model and a persistent Chrome session is lazily launched on the first browser tool call — headed (a visible window, ephemeral profile) for interactive sessions, headless for gateway children (SetBrowserHeadless). The Chrome process is torn down on CloseBrowser (called at session end). SetAdmin switches this session into admin mode: the settings assistant for the gateway and agents. Admin tools only, no shell, no editor.
func (*Session) SetApprover ¶
func (s *Session) SetApprover(fn func(context.Context, ApprovalRequest) ApprovalDecision)
SetApprover replaces the approval callback. The TUI routes approvals through its own input instead of a separate os.Stdin reader. The callback receives a structured ApprovalRequest and returns a structured ApprovalDecision (allow / allow-with-edited-command / deny-with-reason / interrupt).
func (*Session) SetAsker ¶
func (s *Session) SetAsker(fn func(context.Context, AskRequest) AskResponse)
SetAsker replaces the human-in-the-loop question callback. The TUI routes ask_user questions through its own selector instead of stdin.
func (*Session) SetBrowserEnabled ¶
func (*Session) SetBrowserHeadless ¶ added in v0.24.0
SetBrowserHeadless makes the lazily-launched Chrome run headless — required for gateway/service children with no desktop session.
func (*Session) SetContext ¶ added in v0.13.0
func (s *Session) SetContext(items []ContextItem)
SetContext supplies caller-provided supplemental context for the run (agent runtime, API, CI). Injected every turn after project/user context, in the engine's fixed Kind order. The CLI and Desktop never call this, so their context is unchanged. Supplemental context is input for this run only — it does not write project memory.
func (*Session) SetCredentials ¶
SetCredentials swaps fresh gateway credentials into the provider (the /login success path — no restart). No-op without the Connector capability.
func (*Session) SetEffortOverride ¶
SetEffortOverride forces the per-turn thinking effort from the /effort command: "off", "medium", or "high" pin it every turn; "auto" (or anything else) clears the override and returns to the per-turn heuristic (effortForTurn). EffortOverride reports the current setting.
func (*Session) SetExtraMCPServers ¶ added in v0.28.0
func (s *Session) SetExtraMCPServers(servers map[string]mcp.ServerConfig)
SetExtraMCPServers adds server configs that were NOT discovered from .mcp.json (project/user/local config) — currently used for one thing: handing this run its own chrome-devtools-mcp connection to the user's existing Chrome, after the caller has already acquired a broker lease. The caller is responsible for that lease; this only wires the resulting MCP server into the session like any other.
func (*Session) SetExtraMile ¶
SetExtraMile toggles "extra mile" mode: when on, a fact rides every turn and the gateway injects an above-and-beyond rule (edge cases + feature completeness) for planner/executor modes. ExtraMile reports the current state.
func (*Session) SetMode ¶
func (s *Session) SetMode(m permissions.Mode)
SetMode changes the permission mode mid-session (e.g. via a `/mode` command).
func (*Session) SetNoApprover ¶ added in v0.24.0
SetNoApprover marks this session as having no human to answer approval prompts (a detached job child). Tools whose every use would be denied (e.g. browser_eval at Dangerous outside allow-all) are then not advertised at all — a tool that can never run must not be offered.
func (*Session) SetNoContext ¶
SetNoContext puts the session in cold mode (no ContextPack) — for A/B eval.
func (*Session) SetObserver ¶
func (s *Session) SetObserver(o UIObserver)
SetObserver attaches a UIObserver (see above). Pass nil to detach.
func (*Session) SetOutput ¶
SetOutput redirects the session's streamed output to w. The TUI points this at a writer that forwards bytes to the Bubble Tea program.
func (*Session) SetPersonality ¶
SetPersonality sets the agent's voice (a built-in key or free-text custom voice); empty clears it back to the default. Tone only — the gateway guards it from affecting behavior. "random" rolls a concrete voice ONCE per session, here — so the ready line can name what the roll selected and the session speaks with one voice (a fresh roll each launch keeps the chaos; a per-request re-roll made every reply a different character and nothing displayable). Re-picking random re-rolls.
func (*Session) SetPin ¶
SetPin pins a concrete model for the session (the /model picker's choice): the gateway serves this model for every real request; invisible plumbing (classify/ compact) stays on the utility lanes. label is the gateway's sanitized short name ("sonnet", "glm-5p2"); "" = Automatic. window is the pin's context window from the picker list (0 = unknown → the SDK catalog sizes the meter). A pin change invalidates the learned lane budget/window — the next serve re-teaches them.
A pin change also drops thinking/redacted_thinking blocks from the live chat history (if a ChatState is attached via StartChat): those blocks are provider-specific — Anthropic validates signatures it issued, and a different model (even another Anthropic tier) can't vouch for them. Replaying foreign thinking produces "thinking blocks in the latest assistant message cannot be modified" (a hard 400). Text and tool blocks are provider-neutral and stay.
func (*Session) SetPolicy ¶ added in v0.31.0
SetPolicy installs the resolved policy layers for this session. Called once at the cmd boundary, where the workspace and user files are loaded.
func (*Session) SetResume ¶
SetResume asks the NEXT StartChat to re-enter session id with its saved history instead of minting a fresh session. Set it from the cmd layer (or a slash command) before the front-end starts the chat; StartChat consumes it.
func (*Session) SetSeparateDrain ¶
func (s *Session) SetSeparateDrain(f func() (activeText string, activeTitle string, items []separateAsk))
SetSeparateDrain wires the interactive separate-task source (the transaction scheduler). runLoop calls it between tool iterations to track genuinely disparate follow-ups on the todo list instead of leaving them invisible in the queue.
func (*Session) SetServingDefault ¶
SetServingDefault records the gateway's everyday (cheap-lane) model so the footer/banner show what will actually serve — instead of the CLI's bootstrap identity — before any turn has run. Set once at startup (after asking the gateway /v1/models); read under dispMu.
func (*Session) SetSessionID ¶ added in v0.12.0
setSessionID assigns this Session's id AND ties the metered Runner to it, so every model call carries the session on the wire (the compat `user` field) for serving affinity + telemetry. Use this everywhere instead of writing s.sessionID directly. SetSessionID pins the session id used by the next StartChat, so a caller can control continuity itself: the gateway derives a stable id per conversation and pins it, and StartChat then does resume-or-create under that id instead of minting a fresh one. (Distinct from a leftover sessionID between two chats on one Session, which must still mint a new id.)
func (*Session) SetSkillRoots ¶ added in v0.13.0
SetSkillRoots supplies caller-provided EXTRA skill discovery roots (e.g. a gateway agent's own skills dir). They rank between repo-local and user-global skills, so an agent can carry capabilities without editing the project or the user's global skill set. Empty for the CLI and Desktop.
func (*Session) SetSteerDrain ¶
SetSteerDrain wires the interactive steer source (the transaction scheduler). runLoop calls it between tool iterations to fold mid-turn `+steer` input into the active turn.
func (*Session) SetTaskAttachments ¶ added in v0.15.0
func (s *Session) SetTaskAttachments(atts []input.Attachment)
SetTaskAttachments supplies caller-resolved attachments for the NEXT submitted turn (a gateway job carrying channel media — a photo texted to the bot, a PDF emailed to it). They merge into that turn's bundle and ride the normal attachment path (caps, downscaling, wire blocks), then clear.
func (*Session) SetToolNotify ¶ added in v0.27.0
SetToolNotify installs a callback invoked once per tool call with a short human label ("bash(go test ./...)", "read_file(internal/sync.go)"). It is a lightweight activity tap for frontends that surface what a detached agent is doing right now (the job heartbeat); unlike toolLine it fires for quiet tools too. Nil detaches. Set before the session runs; not for mid-turn swaps.
func (*Session) SetToolPolicy ¶ added in v0.23.0
SetToolPolicy restricts the session to the given toolsets/tools (allow; empty = all) minus disabled ones (deny wins) — the gateway applies an agent's configured policy here. Unknown entries are reported, not silently dropped.
func (*Session) SetWidth ¶
SetWidth records the terminal width so rendered diffs can fill the full row with a background. The TUI calls this on resize.
func (*Session) Spend ¶
Spend returns the session's token breakdown and estimated cost in USD (priced per response under each call's model; rates are approximate). Powers /cost.
func (*Session) SpendByBackend ¶
func (s *Session) SpendByBackend() []ledger.BackendSpend
SpendByBackend returns per-backend usage, busiest first. One entry ("anthropic") in a classic session; two once the hybrid router is live.
func (*Session) SpendByPurpose ¶
func (s *Session) SpendByPurpose() []ledger.PurposeSpend
SpendByPurpose returns per-purpose usage, most expensive first — so /cost can show where the money actually went (e.g. explore scouts vs the main loop vs synthesis).
func (*Session) StartChat ¶
StartChat begins an interactive session: assigns a session id, loads remembered approvals, records the start event, and builds the system prompt. Pump input with Submit; finish with EndChat. When SetResume was called, the saved transcript is re-entered instead of minting a fresh session — the episodic log appends to the same session dir, so memory stays one thread.
func (*Session) Submit ¶
Submit routes one raw input line and runs the resulting turn(s) to completion, draining any queued follow-ups. Output streams to the session writer; approvals go through the session approver. Blank lines are ignored.
func (*Session) Sync ¶
Sync regenerates the project overview and writes it to the selected AI-editor context files. It mirrors the `memcode sync` CLI pipeline (cmd/sync.go) but runs against the live session's store/runner/root — so the interactive /sync command needs no separate process. targets is the user's pick from the picker (empty + Everything=false means "nothing configured"); the overview is synthesized deterministically from repo facts, so this works without a model call.
func (*Session) SyncDetect ¶
func (s *Session) SyncDetect() []memsync.DetectedTarget
SyncDetect scans the project root for known AI-editor context files (CLAUDE.md, AGENTS.md, .github/copilot-instructions.md, …) and reports which exist on disk and which are already managed by memcode. The /sync picker calls this to show the grid of toggleable targets before the user picks.
func (*Session) TailJobArg ¶
TailJobArg powers /tail: the arg is a shell slot; empty tails the lone running shell.
func (*Session) ThinkingEffort ¶
ThinkingEffort returns the current turn's thinking-effort label for the status line ("low"/"medium"/"high"/…), or "" when thinking is off (so the spinner shows it only while the model is actually thinking).
type ShellReportBack ¶
ShellReportBack is a promoted foreground command that has finished and owes its result back to the model (redacted, ready to inject as a new turn). Identified by command, not shell slot — a finished job holds no slot.
func (ShellReportBack) ReportPrompt ¶
func (b ShellReportBack) ReportPrompt() string
ReportPrompt renders a finished background shell (started or promoted) as the turn text handed to the model.
type SteerEvent ¶
SteerEvent is a `+input` the user submitted while a transaction was active: recorded immediately, then folded into the SAME transaction at the next safe boundary in runLoop (after tool_results, before the next model call). It cannot affect an in-flight model call — that is what cancel is for.
type Transaction ¶
type Transaction struct {
ID string // "tx_<n>" — unique within a session, deterministic for tests
Text string // the user intent (paste-expanded, routing marker stripped)
State TxState
CreatedAt time.Time
StartedAt time.Time
EndedAt time.Time
Result TransactionResult
// contains filtered or unexported fields
}
Transaction is the unit the scheduler manages. steers is unexported because it is mutated only through schedState (actor-serialized); everything else is read-only once the transaction is created, except the lifecycle fields the scheduler advances.
type TransactionResult ¶
TransactionResult is a transaction's outcome. v1 records only the terminal state and any error; the commented fields are the deliberate seam for Phase-3 undo (revert a completed transaction's edits via git/patch) — shaped now so it attaches cleanly later.
type TxState ¶
type TxState string
TxState is the explicit lifecycle of a Transaction. Transitions are owned by the scheduler state core (schedState) and serialized by the actor; nothing mutates a transaction's state from two goroutines.
const ( TxQueued TxState = "queued" // accepted while another was active; inert (no ChatState yet) TxRunning TxState = "running" // the active transaction; the only writer of ChatState TxCancelling TxState = "cancelling" // Esc/Ctrl-C requested; unwinding TxCompleted TxState = "completed" // finished normally (terminal) TxFailed TxState = "failed" // errored (terminal) TxCancelled TxState = "cancelled" // aborted before completion (terminal) )
type UIObserver ¶
type UIObserver interface {
// Routed reports how a submitted line was classified.
Routed(route input.Route, reason string)
// QueueChanged reports the current queued-task texts (most-recent last).
QueueChanged(items []string)
// Busy reports whether a turn is actively running.
Busy(busy bool)
// Mood reports the running interaction-friction reading (for the TUI gauge).
Mood(r mood.Reading)
// Room reports the assessed room state (mode/intent/policy) for the TUI badge.
Room(s room.State)
// Todos reports the agent's current work-tracker checklist (the live region).
Todos(list todos.List)
// Tokens reports the running output-token count for the current turn (the ↓
// counter): a live estimate between the API's usage events, snapped to the
// authoritative value when it arrives.
Tokens(output int)
// Raw prints a block VERBATIM into scrollback — no markdown/prose processing,
// internal whitespace and blank lines preserved exactly. Used by the `$`
// direct-shell lane so command output is high-fidelity terminal output, not an
// assistant-rendered artifact.
Raw(text string)
}
UIObserver lets a front-end (the TUI) observe the interactive session's routing and lifecycle without scraping stdout. Every method is optional — the runtime nil-checks before calling — so a headless caller can ignore it. This is a tap on the existing event points in Submit, NOT a change to the agent loop itself.
Source Files
¶
- activity.go
- admin.go
- advisor.go
- agent.go
- answer.go
- approval.go
- artifact.go
- ask.go
- attachments.go
- bgjobs.go
- browser.go
- chat.go
- classify.go
- codeexec.go
- codequery.go
- commitgate.go
- compact.go
- context.go
- diagnostics.go
- diff.go
- exec.go
- fetch.go
- followup.go
- gather.go
- github.go
- highlight.go
- hooks.go
- impact.go
- instructions.go
- intake.go
- introspect.go
- judge.go
- knowledge.go
- lessons.go
- lint.go
- loop.go
- mcp.go
- mcpbindings.go
- metricsstate.go
- orientation.go
- outcomes.go
- plan.go
- planfollowup.go
- policytool.go
- preference.go
- prompts.go
- reasoning.go
- repomap.go
- rewind.go
- runtime.go
- schedstate.go
- scheduler.go
- script.go
- scripts_prompt.go
- servedstate.go
- shrinkwrap.go
- skill.go
- skills.go
- sync.go
- test_run.go
- testguard.go
- todo.go
- toolleak.go
- toolmark.go
- trace.go
- transaction.go
- transcript.go
- turnintent.go
- turnstate.go
- ui.go
- wiretrace.go