Documentation
¶
Overview ¶
Package control is the transport-agnostic session driver. A Controller owns the agent run loop and session lifecycle, takes commands (Send/Cancel/Approve/ SetPlanMode/Compact/NewSession) and emits everything that happens — reasoning, tool calls, approvals, turn completion — as a typed event stream to a single event.Sink.
The point is one orchestration layer behind every frontend: a terminal TUI, a desktop webview, or an HTTP/SSE server each drive the Controller identically (issue commands, render events) and none of them re-implement turn lifecycle, cancellation, or approval. The Controller depends on no frontend.
See also:
controller_turn.go — turn lifecycle (runGuarded, Send, Submit, runTurn, Compose) controller_approval.go — approval/ask/plan-mode (Approve, Ask, requestApproval) controller_session.go — session persistence (Snapshot, NewSession, Resume) controller_mcp.go — MCP server hot-add/remove controller_memory.go — memory quick-add/save controller_query.go — read-only accessors (History, Balance, Skills, DST, etc.) input.go — Compose, CustomCommand, RunSkill, MCPPrompt slash.go — slash-command completion and management notices refs.go — @-reference resolution
Index ¶
- Constants
- func PlanTodosJSON(plan string) (string, error)
- type ApprovalManager
- func (m *ApprovalManager) Answer(id string, answers []event.AskAnswer)
- func (m *ApprovalManager) Approve(id string, allow, remember bool)
- func (m *ApprovalManager) Ask(ctx context.Context, questions []event.AskQuestion) ([]event.AskAnswer, error)
- func (m *ApprovalManager) Bypass() bool
- func (m *ApprovalManager) GateApprover() permission.Approver
- func (m *ApprovalManager) SetAutoApprove(v bool)
- func (m *ApprovalManager) SetBypass(v bool)
- type ArgData
- type Controller
- func (c *Controller) AddMCPServer(e config.PluginEntry) (int, error)
- func (c *Controller) Answer(id string, answers []event.AskAnswer)
- func (c *Controller) AnswerQuestion(id string, answers []event.AskAnswer)
- func (c *Controller) Approve(id string, allow, session bool)
- func (c *Controller) Ask(ctx context.Context, questions []event.AskQuestion) ([]event.AskAnswer, error)
- func (c *Controller) AuditLog() []core.AuditRecord
- func (c *Controller) AuditLogJSON() (string, error)
- func (c *Controller) Balance(ctx context.Context) (*billing.Balance, error)
- func (c *Controller) Bypass() bool
- func (c *Controller) Cancel()
- func (c *Controller) Close()
- func (c *Controller) Commands() []command.Command
- func (c *Controller) Compact(ctx context.Context) error
- func (c *Controller) Compose(text string) string
- func (c *Controller) ContextSnapshot() (int, int)
- func (c *Controller) CustomCommand(input string) (sent string, found bool)
- func (c *Controller) DSTBrain() *dstsetup.DSTRunner
- func (c *Controller) DSTEnabled() bool
- func (c *Controller) ECPEngine() *evolution.Engine
- func (c *Controller) ECPSharedSecret() string
- func (c *Controller) EnableInteractiveApproval()
- func (c *Controller) HasRefs(line string) bool
- func (c *Controller) History() []provider.Message
- func (c *Controller) HookRunner() *hook.Runner
- func (c *Controller) Host() *plugin.Host
- func (c *Controller) IsDSTAvailable() bool
- func (c *Controller) Jobs() []jobs.View
- func (c *Controller) Label() string
- func (c *Controller) LastUsage() *provider.Usage
- func (c *Controller) MCPPrompt(ctx context.Context, input string) (sent string, found bool, err error)
- func (c *Controller) Memory() *memory.Set
- func (c *Controller) NewSession() error
- func (c *Controller) PlanMode() bool
- func (c *Controller) QuickAdd(scope memory.Scope, note string) (string, error)
- func (c *Controller) RemoveMCPServer(name string) (disconnected bool, err error)
- func (c *Controller) ResolveRefs(ctx context.Context, line string) (block string, errs []string)
- func (c *Controller) Resume(sess *agent.Session, path string)
- func (c *Controller) Run(ctx context.Context, input string) error
- func (c *Controller) RunSkill(input string) (sent string, found bool)
- func (c *Controller) Running() bool
- func (c *Controller) SaveDoc(path, body string) (string, error)
- func (c *Controller) Send(input string)
- func (c *Controller) SessionCache() (hit, miss int)
- func (c *Controller) SessionDir() string
- func (c *Controller) SessionPath() string
- func (c *Controller) SetBaseContext(ctx context.Context)
- func (c *Controller) SetBypass(on bool)
- func (c *Controller) SetDSTEnabled(v bool)
- func (c *Controller) SetPlanMode(v bool)
- func (c *Controller) SetSessionPath(path string)
- func (c *Controller) Skills() []skill.Skill
- func (c *Controller) Snapshot() error
- func (c *Controller) Submit(input string)
- type Options
- type SlashItem
Constants ¶
const PlanApprovalTool = "exit_plan_mode"
PlanApprovalTool is the Tool name the controller uses on the ApprovalRequest it emits to gate a proposed plan. Frontends key their plan-approval UI on it.
const PlanModeMarker = "" /* 448-byte string literal not displayed */
PlanModeMarker is prepended to every user turn while plan mode is on. It rides in the user message (not the system prompt or tools), so the cache-stable prompt prefix is left untouched and the toggle costs nothing in cache hits.
Variables ¶
This section is empty.
Functions ¶
func PlanTodosJSON ¶
PlanTodosJSON parses an approved plan's markdown into todo_write-shaped args JSON ({"todos":[...]}), or ("", nil) when the plan has no list items.
Types ¶
type ApprovalManager ¶
type ApprovalManager struct {
// contains filtered or unexported fields
}
ApprovalManager manages the approval lifecycle for writer tools.
func NewApprovalManager ¶
func NewApprovalManager(sink event.Sink) *ApprovalManager
NewApprovalManager creates an ApprovalManager.
func (*ApprovalManager) Answer ¶
func (m *ApprovalManager) Answer(id string, answers []event.AskAnswer)
Answer resolves an outstanding ask by id with the user's answers.
func (*ApprovalManager) Approve ¶
func (m *ApprovalManager) Approve(id string, allow, remember bool)
Approve resolves an outstanding approval by id. When remember is true, the grant is cached for this session so subsequent calls to the same tool+subject auto-approve without prompting.
func (*ApprovalManager) Ask ¶
func (m *ApprovalManager) Ask(ctx context.Context, questions []event.AskQuestion) ([]event.AskAnswer, error)
Ask implements agent.Asker — emits an Ask event and blocks for the answer.
func (*ApprovalManager) Bypass ¶
func (m *ApprovalManager) Bypass() bool
Bypass reports bypass mode state.
func (*ApprovalManager) GateApprover ¶
func (m *ApprovalManager) GateApprover() permission.Approver
GateApprover returns a permission.Approver that routes through this manager.
func (*ApprovalManager) SetAutoApprove ¶
func (m *ApprovalManager) SetAutoApprove(v bool)
SetAutoApprove sets auto-approve mode (used during plan execution).
func (*ApprovalManager) SetBypass ¶
func (m *ApprovalManager) SetBypass(v bool)
SetBypass enables/disables bypass mode.
type ArgData ¶
type ArgData struct {
Skills []skill.Skill
ServerNames []string
ModelRefs []string
CurrentModel string
}
ArgData supplies the dynamic data SlashArgItems needs, so the completion logic is one shared function both frontends call with their own session data — the chat TUI (controller-free, from its cached lists) and the desktop (from the controller). This keeps the CLI and desktop sub-command hints identical.
type Controller ¶
type Controller struct {
// contains filtered or unexported fields
}
Controller drives one chat session. Construct with New; drive with the command methods; observe through the Sink passed in Options.
Fields are grouped by concern:
[core] runner, executor, sink, policy, label, systemPrompt, cleanup, baseCtx [session] sessionDir, sessionPath [plugins] host, reg, pluginCtx [modules] commands, skills, hooks, mem [dst] dst, workDir, proofChain [billing] balanceURL, balanceKey [jobs] jobs [approval] approval, planMode [turn] turn, pendingMemory, bgWG, mu, cancel, running
func New ¶
func New(opts Options) *Controller
New builds a Controller. A nil Sink is replaced with event.Discard.
func (*Controller) AddMCPServer ¶
func (c *Controller) AddMCPServer(e config.PluginEntry) (int, error)
AddMCPServer connects an MCP server live and persists it to the config file. Its tools are registered immediately and become available on the next turn (the agent reads the registry per turn). Returns the number of tools the server exposed. A save failure after a successful connect is reported but non-fatal.
func (*Controller) Answer ¶
func (c *Controller) Answer(id string, answers []event.AskAnswer)
Answer replies to an outstanding ask prompt.
func (*Controller) AnswerQuestion ¶
func (c *Controller) AnswerQuestion(id string, answers []event.AskAnswer)
AnswerQuestion is an alias for Answer; used by some frontends.
func (*Controller) Approve ¶
func (c *Controller) Approve(id string, allow, session bool)
Approve answers an outstanding approval prompt. id is the Approval.ID from the event; session=true persists the grant for this session. The reply is consumed by the turn that issued the request; unknown ids are silently ignored.
func (*Controller) Ask ¶
func (c *Controller) Ask(ctx context.Context, questions []event.AskQuestion) ([]event.AskAnswer, error)
Ask implements agent.Asker. It emits an Ask event and blocks for the answer.
func (*Controller) AuditLog ¶
func (c *Controller) AuditLog() []core.AuditRecord
AuditLog returns the complete audit trail.
func (*Controller) AuditLogJSON ¶
func (c *Controller) AuditLogJSON() (string, error)
AuditLogJSON returns the audit trail as a JSON string.
func (*Controller) Balance ¶
Balance queries the active provider's wallet balance, or (nil, nil) when the provider declares no balance_url.
func (*Controller) Bypass ¶
func (c *Controller) Bypass() bool
Bypass reports whether YOLO/bypass mode is on, for the status-bar indicator.
func (*Controller) Cancel ¶
func (c *Controller) Cancel()
Cancel ends the current turn (if any) without changing state.
func (*Controller) Close ¶
func (c *Controller) Close()
Close stops plugin subprocesses and releases resources.
func (*Controller) Commands ¶
func (c *Controller) Commands() []command.Command
Commands returns the loaded custom slash commands.
func (*Controller) Compact ¶
func (c *Controller) Compact(ctx context.Context) error
Compact triggers an immediate context compaction on the executor.
func (*Controller) Compose ¶
func (c *Controller) Compose(text string) string
Compose applies the plan-mode marker to a turn's text when plan mode is on, returning the message to actually send to the model. The frontend keeps showing the raw text as the user bubble.
func (*Controller) ContextSnapshot ¶
func (c *Controller) ContextSnapshot() (int, int)
ContextSnapshot returns (promptTokens, contextWindow) from the most recent turn.
func (*Controller) CustomCommand ¶
func (c *Controller) CustomCommand(input string) (sent string, found bool)
CustomCommand resolves a "/name args…" line against the loaded custom slash commands, returning the rendered prompt to send (found=false when no command matches). It does not apply the plan-mode marker — call Compose for that.
func (*Controller) DSTBrain ¶
func (c *Controller) DSTBrain() *dstsetup.DSTRunner
DSTBrain returns the single DST facade (nil when DST is unavailable).
func (*Controller) DSTEnabled ¶
func (c *Controller) DSTEnabled() bool
DSTEnabled reports whether DST per-step verification is active.
func (*Controller) ECPEngine ¶
func (c *Controller) ECPEngine() *evolution.Engine
ECPEngine returns the evolution engine for ECP federation (may be nil).
func (*Controller) ECPSharedSecret ¶
func (c *Controller) ECPSharedSecret() string
ECPSharedSecret returns the HMAC shared secret for ECP peer authentication.
func (*Controller) EnableInteractiveApproval ¶
func (c *Controller) EnableInteractiveApproval()
EnableInteractiveApproval wires the Controller as the Asker (for `ask` tool) and installs an interactive permission gate (for approval prompts). Without this, headless runs resolve "ask" to allow. Deny rules remain active.
func (*Controller) HasRefs ¶
func (c *Controller) HasRefs(line string) bool
HasRefs reports whether a line contains any resolvable @references, so a frontend can decide to resolve off its event loop only when needed.
func (*Controller) History ¶
func (c *Controller) History() []provider.Message
History returns the executor's current message log.
func (*Controller) HookRunner ¶
func (c *Controller) HookRunner() *hook.Runner
HookRunner returns the session's hook runner (nil-safe; may hold zero hooks).
func (*Controller) Host ¶
func (c *Controller) Host() *plugin.Host
Host returns the running MCP host (nil when no plugins), for frontends that list servers / resolve MCP prompts.
func (*Controller) IsDSTAvailable ¶
func (c *Controller) IsDSTAvailable() bool
IsDSTAvailable reports whether the DST brain is initialised and available.
func (*Controller) Jobs ¶
func (c *Controller) Jobs() []jobs.View
Jobs returns the still-running background jobs for the status bar.
func (*Controller) Label ¶
func (c *Controller) Label() string
Label returns the human-readable model label, e.g. "deepseek-flash".
func (*Controller) LastUsage ¶
func (c *Controller) LastUsage() *provider.Usage
LastUsage returns the most recent turn's token telemetry (nil before the first turn).
func (*Controller) MCPPrompt ¶
func (c *Controller) MCPPrompt(ctx context.Context, input string) (sent string, found bool, err error)
MCPPrompt resolves a "/mcp__server__prompt args…" line: it maps the positional args onto the prompt's declared arguments and fetches the rendered prompt from the MCP server (an async prompts/get). found is false when no such prompt exists; err carries a fetch failure. Honors ctx.
func (*Controller) Memory ¶
func (c *Controller) Memory() *memory.Set
Memory returns the loaded memory snapshot (nil when memory is disabled), for frontends that surface a memory panel or the /memory command. The returned *Set is immutable — mutations go through QuickAdd / SaveDoc.
func (*Controller) NewSession ¶
func (c *Controller) NewSession() error
NewSession rotates to a fresh session file, archiving the old one, and creates a new in-memory conversation so the next turn starts from scratch.
func (*Controller) PlanMode ¶
func (c *Controller) PlanMode() bool
PlanMode reports whether plan mode is on.
func (*Controller) QuickAdd ¶
QuickAdd appends a one-line note to the doc-memory file for scope (project OK.md by default) — the write side of "#<note>". Returns the file written. Protected by a cap (256 entries) to prevent unbounded growth when notes are added without a corresponding turn to drain them.
func (*Controller) RemoveMCPServer ¶
func (c *Controller) RemoveMCPServer(name string) (disconnected bool, err error)
RemoveMCPServer disconnects a live MCP server — its tools vanish from the next turn — and removes it from the config file. A server declared in .mcp.json disconnects for this session but returns on the next start.
func (*Controller) ResolveRefs ¶
ResolveRefs resolves the @references in a line into a single tagged context block (file/dir contents, MCP resource bodies), plus per-reference error strings for any that failed. An empty block means no references resolved. Safe to call off a frontend's event loop; honors ctx for the resource reads.
func (*Controller) Resume ¶
func (c *Controller) Resume(sess *agent.Session, path string)
Resume loads a saved session into the executor.
func (*Controller) Run ¶
func (c *Controller) Run(ctx context.Context, input string) error
Run sends input directly to the runner (bypassing Submit's slash dispatch and @-ref expansion). Used by headless/ACP callers that compose their own input.
func (*Controller) RunSkill ¶
func (c *Controller) RunSkill(input string) (sent string, found bool)
RunSkill resolves a "/<name> args…" line against the loaded skills, returning the skill's rendered body to send as a turn (found=false when no skill matches). Invoking a skill by slash always inlines its body — the model reads and follows the playbook in the main loop; a subagent skill's isolation is only engaged when the model calls it via run_skill / the dedicated tool. The caller applies Compose for plan-mode/memory framing.
func (*Controller) Running ¶
func (c *Controller) Running() bool
Running reports whether a turn is in flight.
func (*Controller) SaveDoc ¶
func (c *Controller) SaveDoc(path, body string) (string, error)
SaveDoc overwrites a recognized memory doc with body — the save side of the desktop panel's in-place editor. Returns the file written.
func (*Controller) Send ¶
func (c *Controller) Send(input string)
Send starts a turn with an already-composed message (the caller applied any plan-mode marker and @-ref expansion). Used by the chat TUI.
func (*Controller) SessionCache ¶
func (c *Controller) SessionCache() (hit, miss int)
SessionCache returns cumulative cache hit/miss prompt tokens for the session.
func (*Controller) SessionDir ¶
func (c *Controller) SessionDir() string
SessionDir returns the directory where session files are persisted ("" when persistence is disabled).
func (*Controller) SessionPath ¶
func (c *Controller) SessionPath() string
SessionPath returns the full path to the current session file ("" when persistence is disabled).
func (*Controller) SetBaseContext ¶
func (c *Controller) SetBaseContext(ctx context.Context)
SetBaseContext replaces the parent context used by runGuarded to spawn turn contexts. Set it before the first turn so cancellation propagates from the caller (e.g. server shutdown) into running turns. Safe to call concurrently with running turns — only the next spawned turn picks up the new context.
func (*Controller) SetBypass ¶
func (c *Controller) SetBypass(on bool)
SetBypass turns YOLO/bypass mode on or off for the session: while on, every approval prompt is auto-allowed (writers and bash run without asking). Deny rules still block. Runtime-only — never written to config.
func (*Controller) SetDSTEnabled ¶
func (c *Controller) SetDSTEnabled(v bool)
SetDSTEnabled turns per-step DST verification on or off.
func (*Controller) SetPlanMode ¶
func (c *Controller) SetPlanMode(v bool)
SetPlanMode toggles plan mode on the controller and the underlying executor.
func (*Controller) SetSessionPath ¶
func (c *Controller) SetSessionPath(path string)
SetSessionPath sets the path for this session's auto-save file.
func (*Controller) Skills ¶
func (c *Controller) Skills() []skill.Skill
Skills returns the discoverable skills.
func (*Controller) Snapshot ¶
func (c *Controller) Snapshot() error
Snapshot saves the current session to disk.
func (*Controller) Submit ¶
func (c *Controller) Submit(input string)
Submith is the one-call entry for a simple frontend: it takes raw user input and does everything — slash-command dispatch, @-reference expansion, plan-mode composition — emitting all output as events.
type Options ¶
type Options struct {
Runner agent.Runner
Executor *agent.Agent
Sink event.Sink
Policy permission.Policy
Label string
SystemPrompt string
SessionDir string
SessionPath string
WorkDir string // project root for DST compile/test checks
Host *plugin.Host
Commands []command.Command
Skills []skill.Skill
Hooks *hook.Runner
Memory *memory.Set
Cleanup func()
// BalanceURL/BalanceKey wire the active provider's optional wallet-balance
// endpoint and bearer key; empty when the provider declares no balance_url.
BalanceURL string
BalanceKey string
// MsgBus is the session-scoped message bus for pub-sub communication.
MsgBus *bus.Bus
// Jobs is the session-scoped background-job manager (nil disables background jobs).
Jobs *jobs.Manager
// Registry is the executor's live tool set, and PluginCtx the session-scoped
// context; both are needed for hot-adding MCP servers via AddMCPServer.
Registry *tool.Registry
PluginCtx context.Context
// DSTBrain is the compile/test guard (nil when DST is unavailable).
DSTBrain *dstsetup.DSTRunner
// ProofChain accumulates per-turn verification results (compile/test/file checks)
// and exposes a ProofSummary() for injection into turn context.
ProofChain *core.ProofChain
// AuditChain is the tamper-evident audit log for tool execution.
// nil disables auditing.
AuditChain *core.AuditChain
// OnRemember is called when the user picks "always allow" — persists the rule.
OnRemember func(rule string)
// EnvDiagnosis is a cached environment+boot diagnostic string injected into
// the user message every 5 turns (not into the system prompt) so the
// cache-stable prefix stays warm. Empty disables injection.
EnvDiagnosis string
// Kernel carries civilization primitives (identity, recall, trust, learn).
Kernel *kernel.Kernel
// EvolEngine is the self-evolution engine for ECP federation endpoints (optional).
EvolEngine *evolution.Engine
// EvolSecret is the shared HMAC secret for ECP peer authentication.
EvolSecret string
}
Options carries the already-built pieces setup assembles. Lifecycle metadata lets the controller mint and rotate session files; Host/Commands are surfaced to frontends that resolve MCP prompts and slash commands.
type SlashItem ¶
type SlashItem struct {
Label string `json:"label"`
Insert string `json:"insert"`
Hint string `json:"hint"`
Descend bool `json:"descend"`
}
SlashItem is one slash-completion suggestion. Insert is the token text placed at the current argument position (callers replace from the token's start, see SlashArgItems' returned offset); Descend hints the menu to re-open one level deeper after accepting (e.g. "/mcp " → "/mcp add ").
func SlashArgItems ¶
SlashArgItems completes the arguments of a management slash command (everything after the command word). It returns the suggestions filtered by the token being typed and the byte offset where that token begins, so a caller replaces just that token. Only structured commands participate (/mcp /model /skill /hooks); others yield nil. Single source of truth for CLI + desktop.