Documentation
¶
Overview ¶
acp_support.go *
Slash-command surface for the ACP server: the allowlisted subset of the
REPL's commands that works headless (no TUI, no stdin prompt), announced
to ACP clients via available_commands_update and executed through the
regular CommandHandler with stdout captured (scheduler_bridge pattern).
agent_board_sync — deterministic turn-boundary reconciliation between the
squad board and the run registry. *
The orchestrator is instructed to move cards as work progresses, but an
LLM under a long ReAct loop reliably forgets: cards sit in "doing" long
after their linked runs finished. This helper detects exactly that state
mechanically and injects a compact [BOARD SYNC] block at the turn
boundary, so the model is reminded with REAL card IDs (never guessed)
in the same turn it can act on them.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
agent_context_block.go *
Injects the session's `/context attach` entries into the agent/coder system
prompt — the agent-mode counterpart of the chat pipeline's Part 1
(attachedContextParts). Historically these attachments were chat-only,
which broke the "same experience" promise for /agent, /coder and every
headless surface built on the loop (gateway, MCP server): a context the
user attached in chat silently vanished the moment a task ran.
ChatCLI - Early-exit heuristics for the ReAct loop.
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
agent_events_bridge.go *
Bridges the ReAct loop (agent_mode.go) to a structured agentevents.Sink.
Protocol frontends (ACP today) install a sink for the duration of a run via
ChatCLI.agentEventSink; the loop keeps rendering its terminal UI as always
and ADDITIONALLY emits typed events from these helpers. Every helper is a
no-op when no sink is installed, so interactive/gateway/scheduler runs are
byte-identical.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Native tool_call result emission helpers
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
When the assistant message carries NATIVE tool_calls, every provider's
tool API (Anthropic, OpenAI-compatible: Moonshot, MiniMax, ZAI, ...)
requires one tool result per call, adjacent to the assistant message.
These helpers guarantee that shape at every spot where the ReAct loop
can end a turn without a complete result set: mid-batch errors
(fail-fast), @park suspension, context cancellation, stagnation stop,
and the agent_call dispatch path that supersedes the batch.
Park / resume integration for the interactive AgentMode loop. *
This file owns three concerns kept separate from agent_mode.go's huge
Run() body: *
1. handleAgentPark — called from the tool-dispatch loop when a tool
returns the park sentinel. It snapshots the loop state, schedules
the appropriate resume job, prints the park banner, and returns
a sentinel to bubble cleanly out of Run(). *
2. RunResumed — public re-entry point used when the scheduler fires
AgentResume. Restores the snapshot's history and synthesizes the
tool result the @park call would have produced, then drives
processAIResponseAndAct from the same loop position. *
3. enqueueParkResumeJob / enqueueParkPollJob — small wrappers that
build the right scheduler.Job for each ParkRequest mode and
submit it via the scheduler adapter.
Slash command handlers for the park subsystem: *
/parked list all snapshots on disk + their scheduler jobs
/resume <token> force-resume a parked agent immediately
/cancel-park <tok> cancel a parked agent (delete snapshot + job) *
Plus the auto-resume hook drainPendingResumes that the outer Run()
loop in cli.go calls between user prompts.
ChatCLI - Mid-park user directives
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
While an agent is parked the REPL stays in normal chat mode — plain
text keeps its default behavior. Directing the parked agent is an
explicit action: /park-note <msg> persists the text into the park
snapshot as a pending directive, and RunResumed injects it into the
agent's context right after the park result at wake-up. A one-time
hint per park surfaces the command when the user chats while a park
is waiting, covering the "I typed and the agent never saw it" gap
without changing what plain input does.
ChatCLI - In-turn park wait for unattended surfaces.
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
On the REPL, a parked agent ends its run and the outer prompt loop later
drains pendingResumeQueue to re-enter the loop. ACP (IDE), the MCP server
and the gateway have no such loop: a park taken there used to end the turn
with nothing ever consuming the resume — the monitor kept firing forever,
invisible, and the client showed an eternally pending turn. *
This file keeps the park IN-TURN on those surfaces: handleAgentPark
registers a waiter channel before enqueueing the scheduler job, Run()
blocks in runParkedInline instead of returning, the bridge delivers the
wake straight to the waiter, and the resumed loop continues on the same
request with the same event sink. Cancelling the turn (IDE Stop /
session/cancel) cancels the scheduler job and deletes the snapshot so
nothing leaks.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Phase 2 (#2) — Plan-and-Solve / ReWOO trigger for /agent and /coder. *
Lives outside agent_mode.go (already 3800+ lines) so the wiring is
easy to audit. The trigger is invoked from AgentMode.Run after the
user's query is appended to history but before the ReAct loop
starts. When it fires, it adds two synthetic messages to history:
1. an assistant message containing the structured plan (so the
orchestrator sees what was attempted), and
2. a system message containing the deterministic execution
report so the orchestrator can finalize with the gathered
outputs.
ChatCLI - Smart chat↔agent routing heuristics.
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
agent_side_commands — lets the user drive the observation commands
(/agents, /board, /mail, /jobs) WHILE the agent/coder loop runs, instead
of the terminal being fully owned by the run until it finishes. *
The centralized stdin reader classifies these lines at the producer: they
never enter the stdinLines channel, so a security prompt cannot read
"/board" as an answer and the type-ahead drain cannot hand them to the
LLM as instructions. When a live display (turn spinner or the multi-agent
dispatch panel) is active, the command executes immediately — the display
pauses, the command output prints, the display resumes. Otherwise (the
terminal is owned by a security prompt, or the loop is between displays)
the command queues and runs at the next turn boundary, right before the
type-ahead drain. *
The allowlist is deliberately small and MUST NOT include mode-switch
commands (/agent, /coder, /run, /plan, /exit): those unwind the REPL via
panic sentinels and would tear the running loop down from a goroutine
that cannot recover them.
ChatCLI - Structured system prompt assembly for agent/coder modes.
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
agent_typeahead — live preview of the line being typed while the agent
loop owns the terminal. *
With the TTY in cbreak mode (see stdin_cbreak_unix.go) the centralized
reader receives bytes as they are typed; the residual partial line is
published here and the spinner / dispatch panel renders it as a `❯ …▌`
input line, so the user finally SEES what they are typing mid-run
instead of the kernel echo being eaten by the repaint.
/agents — human view over the live agent run registry. *
Shows which agent executions are alive right now (orchestrator, workers,
subagents, MoA members, scheduler headless runs) as a parent/child tree
with per-run turn/action progress, plus the recent finished history.
Mirrors what the @agents tool exposes to the LLM, rendered for people.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
/board — human view over the squad work board. *
Renders the same kanban the orchestrator LLM manages via @board:
cards grouped by column with assignee, linked runs and note counts.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Declaring the rewrites we make on purpose. *
The cache telemetry separates a rebuild ChatCLI asked for from a miss
caused by an unstable prefix, and alerts after three unexplained misses
in a row. It only knows what it is told, and three request fields that
arrived later change the prefix without telling it: the effort router
moves output_config between present and absent turn to turn, activating
a deferred tool changes the tools array that is serialized ahead of the
system block, and a task budget appearing mid-run adds a field that was
not there before. All three are our decisions, and all three used to
read as instability — so the alert fired at the user for something the
user did not do. *
A change is only reported when the shape actually differs from the last
request: announcing a rebuild every turn would tell the telemetry
nothing at all.
ChatCLI - /channel command handler
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Subcommands: *
list default — show recent messages + unread count
<channel-name> filter list to that channel
inject splice last 10 messages into the next turn
as a system message (legacy behavior preserved)
ack clear unread + pending notify banner
clear [--all] drain the inbox: empty the ring + ack all state;
--all also truncates the on-disk audit trail
pause / resume toggle the trigger engine
rules show active rule set; `rules reload` re-reads
~/.chatcli/mcp/triggers.json
confirm <id> [no] accept (or deny) a pending confirm action
run <seq> manually fire the agent on a specific message
ChatCLI - MCP channel trigger plumbing
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Glue between cli.mcp.ChannelManager + cli.mcp.triggers.Engine and
the user-facing CLI loop. Three responsibilities: *
1. Boot the trigger engine, load rules from
~/.chatcli/mcp/triggers.json, and wire OnMessage into it.
2. Consume engine.Actions(), separating them by Mode:
- notify → push onto pendingNotify ring, emit one-line
toast on stderr.
- confirm → push onto pendingConfirm map, emit toast with
/channel confirm <id> hint.
- auto → push onto pendingAuto queue; drained at the
top of the next executor tick by
drainPendingAutoTriggers (analogous to
drainPendingResumes for parked agents).
3. Render the inbox banner at the top of each executor cycle. *
The /channel command file (channel_command.go) reads from the
pending stores to implement list/ack/pause/resume/rules/confirm/run.
ChatCLI - @channels Tool Adapter
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Bridges the @channels builtin (cli/plugins/builtin_channels.go) to the
live MCP channel inbox and the trigger-banner state owned by ChatCLI.
Rendering is model-facing plain text: seq + server/channel + timestamp
per line, content clamped so a chatty server cannot flood the context.
ChatCLI - Chat-mode controlled exception for ask_user.
Copyright (c) 2024 Edilson Freitas. License: Apache-2.0. *
Chat mode is tool-less by design. Sanctioned exceptions only: ask_user
(interactive choice), read-only knowledge retrieval when a knowledge base
is attached (chat_knowledge.go), graphview rendering (chat_graphview.go)
and long-term memory/profile persistence (chat_memory.go). No exec/file/
search tools, ever.
Native providers use a buffered SendPromptWithTools turn; non-native ones
(Claude OAuth) use a buffered XML turn with the formats injected and the
markup suppressed. In both cases the turn is BUFFERED and the text RETURNED
— handleChatTurnResult renders it; printing here (after the alt-screen
overlay) is what made the answer vanish.
ChatCLI - Chat-mode controlled exception for @graphview.
Copyright (c) 2024 Edilson Freitas. License: Apache-2.0. *
Chat mode is tool-less by design; ask_user and read-only knowledge retrieval
are its sanctioned exceptions. Interactive graph rendering is the third: the
user explicitly asks "draw a graph of what we discussed", so for THAT turn
the model may call @graphview once. It only writes a self-contained HTML file
and opens a viewer — it never touches the workspace — so it is a benign,
user-requested visualization rather than an execution/file tool. Gated by
CHATCLI_CHAT_GRAPHVIEW (default ON), flippable at runtime via
/config chat graphview on|off.
ChatCLI - Chat-mode controlled exception for knowledge retrieval.
Copyright (c) 2024 Edilson Freitas. License: Apache-2.0. *
Chat mode is tool-less by design; ask_user is its one interactive
exception. Knowledge retrieval is the second sanctioned exception, and the
same reasoning applies: it executes nothing and touches nothing — it only
READS the knowledge bases the user explicitly attached. With it, "attach a
corpus and talk about it" works in plain chat: when the per-turn
auto-retrieved passages are not enough, the model may pull more (search /
get / toc) for a bounded number of rounds before answering, without the
user having to switch to /agent or /coder.
ChatCLI - Chat-mode controlled exception for long-term memory.
Copyright (c) 2024 Edilson Freitas. License: Apache-2.0. *
Chat mode is tool-less by design; ask_user, knowledge retrieval and
graphview are its sanctioned exceptions. Memory is the fourth, and the same
reasoning applies: it executes nothing and touches no files outside the
memory store the background extractor already writes to. Without it, chat
could only PROMISE profile updates ("vou considerar daqui pra frente") while
the throttled extractor decided later whether anything persisted — the
model looked like a liar and the profile rotted. With it, "atualiza meu
perfil" works in plain chat, deterministically, the moment the user asks.
ChatCLI - Chat-mode request pipeline helpers
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
processLLMRequest used to host the whole chat-mode pipeline inline, which
pushed its cyclomatic complexity well above the project's Quality Gate
budget. The helpers in this file extract each pipeline phase so the main
function can be read top-to-bottom as an orchestrator and so each phase
can be unit-tested independently. *
The split mirrors the conceptual phases the chat turn actually goes
through, in order: *
1. assembleChatSystemPrompt — build the structured system prompt
(workspace, contexts, manual + pinned + auto skills, MCP, K8s),
and the model/effort hints derived from the active skills.
2. buildChatTempHistory — splice the new system message into the
conversation history without mutating cli.history.
3. resolveActiveClient — honor any skill model hint, with a
user-visible notice when the swap is cross-provider.
4. applyChatEffortHint — attach the reasoning-effort hint to
ctx so the provider can opt into extended thinking.
5. executeLLMTurn — send the prompt (streaming if the client
supports it, buffered otherwise).
6. handleChatTurnResult — append history, record cost, render.
Package cli implements the interactive terminal UI, command handlers, and orchestration glue that binds every chatcli subsystem together (LLM clients, workspace, memory, agents, plugins, MCP, hooks, quality pipeline).
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Autocomplete providers for the five seven-pattern quality slashes:
/thinking — cross-provider reasoning override (#7)
/refine — Self-Refine session toggle (#5)
/verify — Chain-of-Verification session toggle (#6)
/plan — Plan-and-Solve / ReWOO trigger (#2)
/reflect — Reflexion manual lesson persistence (#3) *
All descriptions resolve via i18n so pt-BR and en speakers get the
explanation in their locale. Keys live under complete.{thinking,
refine,verify,plan,reflect}.* in i18n/locales/*.json.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - cli_session_autosave.go *
Auto-saves the live conversation when the interactive REPL exits, so a
session is never lost just because the user didn't run /session save.
Combined with ranked session search and @session get, this closes the
recall loop: every conversation becomes retrievable memory by default. *
Autosaves live under a reserved "autosave-" name prefix — they never touch
user-named sessions — and are pruned to a small keep-count so /session list
stays readable and disk stays bounded (the 90-day session TTL applies too).
Gated by CHATCLI_SESSION_AUTOSAVE (default on).
cli_session_binding.go *
Cross-surface session continuity for the interactive REPL. Once a named
session is active (loaded or saved via /session), every completed turn is
written through to the saved-session store, and every turn start checks the
store for writes made by another surface (MCP/ACP server, gateway daemon,
another terminal) since our last sync — reloading when the file is newer. *
Conflict model is last-writer-wins on the whole file: the store's atomic
write (temp+rename) guarantees no torn files, and the refresh-before-turn
keeps surfaces converging as long as they alternate. Two surfaces answering
the SAME turn simultaneously is the conversation hub's job, not this one's. *
Guards, in order:
- CHATCLI_SESSION_WRITETHROUGH=off disables both directions;
- no named session active (currentSessionName empty) → no-op;
- machine-prefixed names (autosave-, mcp-) are rolling mirrors owned by
the autosave paths, never live bindings;
- captured RPC runs (MCP/ACP/gateway/scheduler-bridge) are skipped: the
RPC backend owns per-session persistence there, and currentSessionName
holds a surface session id, not a saved-session name.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Slash command chat→coder auto-route (post-unwind consumer)
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
A command whose resolved mode is coder cannot run as a chat turn: chat is
tool-less by design and the model refuses, pointing the user at /coder.
maybeAutorouteCoderCommand (commands_integration.go) intercepts those
invocations at the REPL dispatch and unwinds out of go-prompt exactly like
a manual /coder; this file owns what happens AFTER the unwind — expand the
template, run the coder ReAct loop one-shot, and hand the prompt back to
chat when the loop reaches its final answer.
ChatCLI - Slash command integration (dispatch, expansion, security gate)
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Wires the cli/commands catalog into every user-input surface. Expansion is
pure prompt rewriting, so a command behaves identically on REPL chat,
coder follow-ups, one-shot -p, the messaging gateway, ACP and MCP —
whatever the provider. *
Security invariants (the reason this file owns the ExecRunner):
- Every "!" pre-execution line goes through the SAME machinery as coder
tool calls: IsSafetyImmune → PolicyManager.Check → interactive
approval (PromptSecurityCheckGuarded). The gate is never bypassed.
- Unattended surfaces (gateway/MCP/ACP/scheduler) have no human to
answer an "ask": policy automode may approve, otherwise DENY
fail-safe. Never auto-approve just because nobody is watching.
- allowed-tools from the frontmatter becomes an ephemeral overlay
consumed by the next agent/coder run: a tool outside the list
escalates allow→ask; it never silently widens permissions.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Session-level compaction controls: the /autocompact threshold override
and the dedicated summarizer model (CHATCLI_COMPACT_MODEL). compactConfig
is the single place every compaction call site builds its config, so the
override, the learned token ratio and the summarizer are applied uniformly
in chat, agent/coder, one-shot, RPC and /compact.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
One seam for everything that surrounds a compaction, whichever loop
runs it (chat, agent/coder, one-shot, /compact, overflow recovery):
the PreCompact/PostCompact hooks with their trigger, the cost record,
the cache-rebuild note. Keeping the call sites to two lines is what
makes the four loops behave the same.
ChatCLI - Adapter binding the @compress / @recall tools to the live
compression layer.
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Implements plugins.CompressionAdapter over the session's compress.Layer:
on-demand content-aware compression (@compress), byte-identical retrieval of
offloaded originals (@recall), and a session savings summary. Wired via
plugins.SetCompressionAdapter at startup.
ChatCLI - /config agent mutator.
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Closes the gap where /config agent was read-only: switching the
timeline UI (full / compact / minimal) required restarting the
process with CHATCLI_CODER_UI exported. Now it flips at runtime
and the next /coder or /agent picks up the new style on the next
NewUIRenderer call (which reads agent.DefaultUIStyleFromEnv each
time the agent loop starts). *
/config agent # read-only dump (legacy)
/config agent ui # show current style + options
/config agent ui full # switch to bordered cards
/config agent ui compact # switch to inline ↻/✓ lines
/config agent ui minimal # switch to truncated cards *
Persistence: the switch lives in process env only. The mutator
prints a hint so users that want a permanent default know to add
`CHATCLI_CODER_UI=<value>` to their .env (or wherever CHATCLI_DOTENV
points). We deliberately do NOT rewrite the .env file ourselves —
that file is user-owned territory; transparently editing it would
destroy comments / ordering and surprise anyone who reads it next.
ChatCLI - /config chat mutator.
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Exposes the chat-mode ask_user exception (CHATCLI_CHAT_ASK) on the
/config surface — not just read-only: it can be toggled at runtime. *
/config chat # status (read-only panorama)
/config chat ask # status
/config chat ask on # enable (chat may use ONLY ask_user)
/config chat ask off # disable (chat stays tool-less)
/config chat ask toggle # flip *
The toggle flips process env only (chatAskEnabled reads os.Getenv each
turn, so it takes effect immediately). A hint points users to .env for a
permanent default; we never rewrite .env ourselves (user-owned territory).
ChatCLI - /config commands section
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Diagnostics for the slash-command catalog, organized for scanning: a
one-line summary, commands grouped by source (native first, then each
interop family) with aligned columns, then the two failure ledgers
(refused shadows, parse-skipped files) and the scanned directories with
existence markers. The only mutation is "reload" (re-fingerprint).
ChatCLI - /config compression mutator.
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Exposes the content-aware compression layer (CCR) on the /config surface,
read-only panorama plus runtime mode switching: *
/config compression # status (mode, thresholds, CCR store, savings)
/config compression off # disable compression
/config compression lossless # only lossless reductions (no row/line dropping)
/config compression lossy # lossy-with-CCR (full reduction, reversible via @recall)
/config compression stats # session savings summary *
The mode switch takes effect immediately on the live layer (atomic) and also
sets CHATCLI_COMPRESSION so any rebuilt layer (e.g. the gateway) inherits it.
A hint points to .env for a permanent default; we never rewrite .env.
ChatCLI - /config image mutator.
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Exposes the @image backend on the /config surface — read-only panorama plus
runtime mutation. The imagegen factory reads os.Getenv on every call, so each
setter takes effect immediately; a hint points to .env for a permanent
default (we never rewrite .env — user territory). *
/config image # status
/config image provider <name> # sdwebui|url|openai|responses|google|xai|zai|minimax|bedrock|auto
/config image api images|responses # OpenAI: Images API vs Responses API
/config image model <id> # CHATCLI_IMAGE_MODEL
/config image url <url> # CHATCLI_IMAGE_URL (self-hosted/SD WebUI)
/config image models # list the image-model catalog
/config image reset # clear the overrides above *
Shorthand: `/model-image [<id>]` mirrors `/config image model` (and lists the
catalog when bare), the @image counterpart to `/model` for text models.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
/config managed — the organization-managed defaults and locked
policies in effect (config/managed.go).
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
/config memory renders the long-term memory configuration: the injection
mode that governs the push/pull tradeoff in agent/coder, plus live store
stats. Read-only, mirroring /config quality — set the mode via the
CHATCLI_MEMORY_MODE env var (full | index | off).
ChatCLI - /config output mutator.
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Output-token reduction on the /config surface — read-only panorama plus
runtime mutation: *
/config output # status (verbosity + effort routing)
/config output full # no steering (model's natural verbosity)
/config output concise # drop ceremony/restatement (default)
/config output minimal # fewest correct tokens
/config output effort on|off # complexity->effort downgrade (opt-in) *
Both knobs are read live from the environment each turn, so changes take
effect immediately. A hint points to .env for a permanent default; we never
rewrite .env.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
/config quality renders the seven-pattern quality pipeline state. The
pipeline lives in cli/agent/quality and is wired into the dispatcher
by initMultiAgent. This file only reads the live snapshot — it does
not parse env vars on its own.
ChatCLI - /config scheduler section. *
Lives in its own file (mirrors config_quality.go) and is dispatched
by config_sections.go's routeConfigCommand. Shows operator-tunable
env vars side-by-side with live runtime state (queue depth, WAL
segments, daemon status).
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
/config subsections. *
Design: each showConfigX() is self-contained and reads directly from the
live CLI state (env vars, managers, handlers). None of them pre-compute or
cache — `/config` is called interactively and performance is irrelevant. *
i18n: every user-facing string goes through i18n.T(). Keys live in
i18n/locales/*.json under cfg.*, ws.cmd.*, complete.config.* namespaces. *
Routing layout:
/config → showConfigPanorama (short overview)
/config all → showConfigAll (every section back-to-back)
/config general → showConfigGeneral
/config providers → showConfigProviders
/config agent → showConfigAgent
/config resilience → showConfigResilience
/config session → showConfigSession
/config integrations → showConfigIntegrations
/config auth → showConfigAuth
/config security → showConfigSecurity
/config server → showConfigServer
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
/config security reseal and verify-audit: key rotation for encryption at
rest and integrity check of the hash-chained audit trail.
ChatCLI - /config security mutator. *
Closes the gap where /config security was read-only: operators had
to edit ~/.chatcli/coder_policy.json by hand to add an Allow or
Deny rule outside the interactive /coder "Allow always" prompt.
Now the same PolicyManager.AddRule / DeleteRule pipeline that
backs the prompt is exposed declaratively: *
/config security # read-only dump (legacy)
/config security rules # live rule table
/config security allow "<pattern>" # AddRule ActionAllow
/config security deny "<pattern>" # AddRule ActionDeny
/config security forget "<pattern>" # DeleteRule
/config security reload # re-read the JSON from disk *
Rule edits persist to ~/.chatcli/coder_policy.json (via
PolicyManager.save). They take effect:
- immediately for new /coder turns (workerPolicyAdapter reloads
per Ask prompt);
- on the very next RunShell for the scheduler bridge (it
reloads from disk on every fire, see scheduler_bridge.go). *
Destructive mutations (deny / forget) prompt for confirmation
unless --yes is passed. allow also prompts when the pattern looks
broad (wildcard-only or fewer than 3 literal chars).
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
/config selfevolve renders the self-evolution engine state: the autonomy
mode plus live observability of what the engine owns (skills it authored) vs
the total skill set. Read-only — set the mode via CHATCLI_SELFEVOLVE_MODE.
Activation analytics for individual skills live in the @skill stats tool.
ChatCLI - /config ui (read-only section).
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
The read-only counterpart to config_ui_mutate.go: the section dump shown by
`/config ui` (with no subcommand) and folded into `/config all`. It reports
the active theme, the env var backing it, the detected terminal color
profile, and the list of available themes — so an operator can see what is
driving the UI's colors without reading source.
ChatCLI - /config ui mutator.
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Runtime control of the color theme that skins every surface — chat,
coder and agent cards, borders, markdown and spinners: *
/config ui # show active theme + color profile
/config ui theme # same as above (explicit)
/config ui theme dark # switch to the dark theme
/config ui theme light # switch to the light theme *
Unlike the timeline UI style (which the renderer re-reads from the env on
each NewUIRenderer), the theme is process-global state held by the theme
package, so a switch applies on the very next render with no restart. *
Persistence mirrors /config agent ui: we set the process env and print a
hint to add CHATCLI_THEME=<name> to the .env for a permanent default. We
never rewrite the user's .env ourselves.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
/config update renders the auto-update state: resolved policy mode,
detected install channel, current vs. latest release (from the on-disk
cache — no network on render) and the env vars that steer the updater.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Secret redaction on the LLM-facing path. *
Everything the model receives that did not come from the user's own
keyboard — tool outputs in agent/coder mode, worker tool outputs, the
conversation segment handed to the memory extractor, and the @file/@git
context assembled in chat — passes through redactSecretsForLLM before it
leaves the process. Two layers compose: *
1. KEY=VALUE lines (env dumps, .env files, docker/compose configs,
CI logs) are judged by NAME through EnvRedactor — AWS_SECRET_ACCESS_KEY,
DATABASE_URL, anything ending in _TOKEN/_PASSWORD/_KEY — plus its
value heuristics (known prefixes, long hex).
2. Free text is scanned by utils.SanitizeSensitiveText for the value
shapes providers hand out (sk-…, ghp_…, AKIA…, JWTs, bearer headers,
credential fields in JSON). *
CHATCLI_ENV_REDACT_MODE selects the policy: "permissive" (default) applies
both layers with the name denylist; "strict" additionally redacts every
KEY=VALUE line whose name is not on the known-safe allowlist; "off"
disables this chokepoint entirely (the pre-existing regex pass on exec
output is untouched by this setting).
ChatCLI - Adapter binding the @context tool to the live context manager.
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Implements plugins.ContextAdapter over the session: create / attach / detach
/ list / status / delete of context (knowledge) bases, so the agent can
build and wire its own documentation autonomously. Wired via
plugins.SetContextAdapter at startup, right after the context manager exists.
ChatCLI - Auto-RAG upgrade for /context attach
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
A plain `/context attach <name>` injects the whole context verbatim into
the system prompt every turn. For large contexts that is the single
biggest per-turn payload in chat mode — while the agent-side @context tool
(context_adapter.go) has attached with semantic retrieval by default since
PR #1058. This file closes the asymmetry for the manual command: large
contexts upgrade to --rag semantics automatically, announced to the user,
with --full as the per-call opt-out and CHATCLI_ATTACH_AUTO_RAG as the
global kill switch.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Provider context edits, mirrored locally. *
With the provider context engine on (Anthropic context editing), the
server clears the oldest tool results from the request it processes.
Until now that stayed invisible here: the local history kept shipping
the cleared results, the footer and the compactor over-estimated, the
calibrator saw chars ≫ tokens and the next request's cache write
counted as a miss. mirrorContextEdits closes the loop.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
One context estimate. *
The footer's ctx%, the compactor's budget and /context status used to
compute the window occupancy with three different formulas, none of
which counted the tool definitions or the output reserve. This is the
single source: {prefix, history, tool definitions, reserve}, the same
categories Claude Code's /context shows.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
/context refresh and /context watch: incremental re-indexing of a
context from its recorded source paths, on demand or driven by the
filesystem watcher. Watcher outcomes are queued as notices the REPL
prints at its next tick (never from the watcher goroutine).
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
/context status — "what is in my context right now, and what does each
part cost". Composes the pieces that already existed in isolation (last
assembled prompt breakdown, live history, learned token ratio, cache
telemetry, compaction budget) into one view with token estimates, the
projected share of the model window, and where auto-compact will fire.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Storage pricing for explicit cache resources. Providers that expose the
cache as a resource (Gemini cachedContents) bill storage per token-hour
on top of the discounted reads, and that charge never appears in a
response's usage block — the only place it can be priced is from the
resource lifecycle events the adapters emit (client.EmitCacheResource).
The observer installed here routes them to whichever cost tracker is
active (the tenant swap may replace it between turns).
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Provider-neutral prompt-cache telemetry: how much of the session's input
was served from cache, how many requests missed it, whether a miss was a
rebuild ChatCLI itself caused (compaction, microcompact, skill aging) and
whether the cached prefix is still warm. Fed by the cost tracker from the
cache fields every provider reports (Anthropic/Bedrock additive counts,
OpenAI/Gemini/Grok/Kimi subset counts), so it works on every provider
that reports cache tokens and stays silent on the ones that do not.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Compaction accounting: how many times the history was compacted this
session, how many landed in Level 3, and what the Level 2 summarizer
cost. The summarizer's request is a real request on the session (or
the configured summarizer) route, so its usage joins the totals like
any turn; the compaction slice is kept apart so /cost can show it.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Daily budget: spend accumulated across every session of the calendar
day under one store directory. The session budget bounds one run; the
daily budget bounds a principal — the store directory is the tenant
root under the gateway, so each tenant has its own ceiling. Spend
increments are folded in whenever the session total grows and
persisted (debounced, atomic) to daily-spend.json; a new day resets.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Embedding cost accounting: every Embed call of the session's provider
(knowledge retrieval, memory vectors, HyDE, warm-ups) is counted and
priced from the provider's list rate. Token counts are chars/4
estimates (embedding APIs rarely report usage), marked as such in the
/cost output; local providers (Ollama) cost nothing.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
Package cli implements the interactive terminal interface for ChatCLI, built on Bubble Tea (Charmbracelet) with a rich TUI experience.
Architecture ¶
The CLI operates in three primary modes:
- Interactive mode: Full TUI with streaming output, syntax highlighting via glamour, and context-aware input with @file, @git, @env, @command.
- Agent mode: ReAct engine (Reason + Act) with 12 specialized agents running in parallel — File, Coder, Shell, Git, Search, Planner, Reviewer, Tester, Refactor, Diagnostics, Formatter, Deps.
- One-shot mode: Non-interactive prompt via -p flag with pipe support.
Security ¶
- Command allowlist with 150+ pre-approved commands (strict/permissive modes)
- Sensitive read path blocking (SSH keys, cloud credentials, kubeconfig)
- Environment variable redaction before LLM submission
- Command output sanitization with prompt injection detection
- Ed25519 plugin signature verification
- Session encryption at rest (AES-256-GCM)
- History file sensitive content redaction
Key Components ¶
ChatCLI: Main struct managing the TUI lifecycle and LLM interaction
AgentMode: ReAct loop with multi-agent orchestration
SessionManager: Persistent session storage with encryption and TTL
HistoryManager: Command history with sensitive content redaction
EnvRedactor: Environment variable sanitization (60+ patterns)
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - export_command.go *
/export path writes the current conversation as a ShareGPT-style JSONL
trajectory (training-data format). Provider-agnostic: it serializes the
unified history regardless of which provider produced the turns. Defaults
to ~/.chatcli/exports/trajectory-<timestamp>.jsonl.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Extension points: external memory providers and context engines. *
The embedded memory (facts, episodes, graph, auto-recall) and the
embedded compactor stay the defaults. An organization that already
runs a memory service or a context engine plugs it in through MCP —
the transport ChatCLI already speaks — with no ChatCLI code: *
CHATCLI_MEMORY_PROVIDER=mcp:<server>
memory_recall(query, hints, budget_chars) → text appended to the
auto-recall block of every turn (chat and agent/coder);
memory_store(messages[{role,content}], session) ← every turn's new
messages, forwarded asynchronously and best-effort. *
CHATCLI_CONTEXT_ENGINE=provider-compact
the provider's own context editing plus its server-side
compaction — it summarizes the older conversation itself instead of
the client spending a turn on a summarizer. Opt-in and never the
default: what ChatCLI's own compaction cuts is archived and can be
recalled, and a server-side summary cannot. *
CHATCLI_CONTEXT_ENGINE=mcp:<server>
context_compact(segment, budget_chars, instruction) → the summary
that replaces the compacted segment (auto-compact and guided
/compact); any failure falls back to the embedded summarizer. *
Every external call is bounded and every failure degrades to the
embedded behavior, so a misconfigured or slow server can never stall
or break a turn.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - gateway_command.go *
/gateway [start|stop|status] runs ChatCLI as a messaging daemon. To keep the
interactive REPL free, `start` re-execs the binary as a detached child
(`chatcli gateway`) — its own process, its own stdout — and tracks it via a
pidfile + log under ~/.chatcli/. The child runs RunGatewayForeground. *
In the daemon, each inbound message runs through the real agent loop fully
unattended (no stdin confirmations; full autonomy — the operator opted in).
Progress streams back as a short, filtered action feed and the run closes
with the model's clean prose answer. Access control is at the edge: Telegram
allow-list, Slack signing secret, webhook secret, plus the agent security
mode (CHATCLI_AGENT_SECURITY_MODE).
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Platform shim for the gateway daemon: Setsid detaches the child from the
terminal's process group; SIGTERM stops it; signal(0) probes liveness.
gateway_events_sink — structured progress for gateway turns. *
Instead of scraping the rendered stdout (ANSI stripping + line
heuristics), the gateway installs this agentevents.Sink for the run and
receives typed events at the points where semantics are known: reasoning
parsed, tool classified, result structured. Each event becomes one clean
chat-friendly progress line, batched by the runner's progressSink. *
The legacy stdout-scraping path remains behind
CHATCLI_GATEWAY_STRUCTURED_PROGRESS=false as a rollback switch.
gateway_runs_watcher — per-agent progress lines for gateway turns. *
The events sink covers the orchestrator's own tool calls, but dispatched
workers/subagents report progress only to the run registry (their tool
calls happen inside their own ReAct loops). This watcher polls the
registry during a gateway turn and emits a line whenever an agent's
state changes — the chat-platform equivalent of the terminal's live
dispatch panel.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - gateway_runtime_model.go *
The gateway daemon is a SEPARATE detached process (see gateway_command.go):
it snapshots provider/model at spawn time and never shared memory with the
interactive REPL. So `/switch --model …` (or `/model …`) in the REPL was
invisible to a running daemon, and starting the daemon after a switch still
booted the .env default — both surfaced as "the gateway ignores my current
model". *
The fix is a tiny shared runtime-state file (~/.chatcli/runtime_model.json)
that the interactive process WRITES whenever the live model changes (switch,
provider switch, and right before spawning the daemon) and the daemon READS
before each inbound message. The file is the single cross-process source of
truth for "the operator's current model"; absence means "no override — keep
the env-derived snapshot", so non-gateway use is entirely unaffected. *
Only the interactive process writes; the daemon is read-only here. That keeps
the daemon from clobbering the operator's choice with its own boot snapshot.
gateway_session_binding.go *
Cross-surface session continuity for the gateway daemon: a hub principal
can be bound to a named saved session, making the durable store — not just
the ephemeral hub — the conversation's home. While bound: *
- the turn's preamble comes from the named session file (which carries
REPL/MCP/ACP turns written through by those surfaces), replacing the
hub-backlog preamble so the two threads are never interleaved;
- every completed turn is appended to the named session file
(load+append+save; the store's atomic write keeps it consistent);
- the hub keeps receiving events as before, so channel fan-out and the
co-running CLI's hub pull are unchanged. *
Bindings persist as hub runtime settings ("gateway_session:<principal>"),
the same live-read mechanism as CHATCLI_HUB_ISOLATE — a restart keeps them,
and a co-running CLI could inspect them via /config hub. *
Channel users control the binding with /session commands in the chat
(attach/detach/status/save/list/new). delete is deliberately NOT exposed to
channels: a gateway conversation may be multi-user, and destroying store
state stays an operator/REPL decision.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
graph_command.go — the /graph visualization: renders the in-core knowledge
graph to an image (the Obsidian "graph view"). It reuses the embedded
go-graphviz engine behind @diagram, so no new rendering dependency is added. *
/graph the whole graph (capped to the top hubs when large)
/graph <subject> the local graph around the node matching <subject>
ChatCLI - Adapter feeding the @graphview tool from live CLI state.
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Implements plugins.GraphSourceProvider so @graphview's "knowledge" and
"conversation" sources render real data:
- KnowledgeGraph: the in-core knowledge graph (the same substrate /graph
draws statically), converted to the renderable node/edge shape.
- ConversationGraph: a graph of the whole session — the turn thread and the
tools it invoked, PLUS everything attached with /context (context bases
with their files, knowledge corpora) — all hanging off a session root. *
Wired via plugins.SetGraphSourceProvider at startup. The "json" source needs
no provider, so @graphview works even before this is bound.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - HyDE wiring (Phase 3 of seven-pattern rollout). *
Builds the per-call HyDE augmenter (3a) and ensures the vector
index (3b) is attached to the memory store. Both are no-ops when
the user hasn't enabled HyDE in /config quality, so the steady
state for non-HyDE users is one extra branch and zero allocation.
ChatCLI - Adapter binding the @knowledge tool to the live context manager.
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Implements plugins.KnowledgeAdapter over the session's attached
knowledge-mode contexts: hybrid passage search (keyless BM25 floor +
embeddings when configured), paged document reads and TOC walks. Wired via
plugins.SetKnowledgeAdapter at startup. Also builds the knowledge block the
agent system prompt injects so the model knows the bases exist.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
knowledge_graph.go — derives the in-core knowledge graph from the existing
memory, skill, session and context stores, and implements the @graph tool's
adapter. *
The graph is a DERIVED index: nodes and edges are computed from data
already on disk. Edges come from the relationships those stores ALREADY
record — topic↔fact links, a fact's source project, an episode's project
and date, shared tags, a skill's triggers — plus [[wikilinks]] parsed from
note text. *
With CHATCLI_MEMORY_GRAPH on (default), the derivation is served through
the persisted cache in cli/workspace/memory/graph_cache.go: consumers call
cli.knowledgeGraph() and get an immutable snapshot that only rebuilds when
a source store changed (dirty taps + fingerprint TTL), with graph.json
carrying it across boots. Off, every call derives from scratch — the
legacy behavior, byte-identical.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Knowledge rerank wiring. CHATCLI_KNOWLEDGE_RERANK picks the optional
stage applied to every hybrid knowledge retrieval: *
off (default) — fused BM25+vector order, unchanged behavior;
mmr — keyless diversity rerank (maximal marginal relevance);
llm — listwise rerank by the compaction model
(CHATCLI_COMPACT_MODEL) or, failing that, the session
client, bounded by a short timeout. *
The stage is attached to the context manager, so it survives embedding
provider rebuilds and applies to tenant store sets alike.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
LLM request audit trail. The gRPC server already audited transport
metadata; nothing recorded what the interactive surfaces sent to which
provider. With CHATCLI_AUDIT_LOG_PATH set, every request on every
surface now leaves a JSON line: when, which provider and model, how
large the payload was, how much history and how many cache markers it
carried, the outcome, the latency, the token usage the provider
reported and the running count of secrets redacted from what the model
received. Never the prompt content. The sink hangs off the observability
chokepoint every adapter passes through, so a new provider is audited
the day it ships.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - lsp_command.go *
/lsp <file> runs the matching language server (gopls, pyright, ...) against
a file and prints its diagnostics — giving the user (and, via the agent,
the model) real compiler/linter feedback without a full build.
ChatCLI - Adapter binding the @lsp tool to the session language-server pool.
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Implements plugins.LSPAdapter over cli/agent/lsp: a lazily created,
session-scoped Pool keeps one initialized server per (project root,
language), and every subcommand formats its answer as bounded,
model-facing text with workspace-relative paths and 1-based positions.
Wired via plugins.SetLSPAdapter at startup; the pool is shut down with
the session.
/mail — human surface over the squad message bus. *
Lets the user audit recent agent↔agent traffic, see pending inboxes and
inject a directive into any agent's inbox (delivered at the recipient's
next ReAct turn — e.g. "/mail send coder prioritize the login fix").
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
mail_hub_bridge — persists the squad message bus through the Conversation
Hub's SQLite store, making mail durable across restarts and shared across
processes (REPL and gateway daemon poll the same hub.db, WAL mode). *
Wire format: one hub event per message on a DEDICATED conversation ID
("squad-mail") so squad traffic never leaks into the user-facing
conversation preamble or LLM history. Role "squad_mail" carries a JSON
payload; role "squad_mail_ack" records delivery (the drain) so other
processes — and this one after a restart — do not redeliver consumed
messages. ClientMsgID = the bus message ID gives idempotent appends. *
Delivery semantics are at-least-once ACROSS processes (two processes that
poll between a drain and its ack may both deliver) and exactly-once
WITHIN a process (Registry.Deliver dedups by globally unique ID). Squad
mail is directive text for LLM agents, so duplicate delivery is benign.
ChatCLI - MCP Dynamic Tool Notice
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Renders the mid-loop notice the agent injects when a server's dynamic
tool list changed (notifications/tools/list_changed → registry refresh
in cli/mcp/dynamic_tools.go). Without this the model keeps reasoning
against the catalog it saw in the system prompt and never discovers the
tools that appeared after a bootstrap call (e.g. HTTP Toolkit's start).
ChatCLI - Adapter binding the @mcp-login tool to the live MCP manager.
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Implements plugins.MCPAuthAdapter over cli.mcpManager: login runs the OAuth
authorization-code flow and reconnects the server; status and logout report
and forget per-server credentials. Wired via plugins.SetMCPAuthAdapter at
startup.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - memory_adapter.go *
Implements plugins.MemoryAdapter so the @memory builtin tool can route
ReAct calls into the live memory store. Supplied to
plugins.SetMemoryAdapter when the memory store is initialized. *
Writes go through the deterministic store methods (RememberFact /
UpdateProfile / ForgetFacts) — no LLM, no throttling — and invalidate the
context builder cache so the next prompt reflects the change.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - memory_autorecall.go *
Proactive recall for the "index" memory mode. The pull model keeps per-turn
cost bounded, but it relies on the model CHOOSING to call @memory recall —
and models routinely skip the call, answering with a 600-char digest while
the relevant gotcha sits unread in the fact index. Auto-recall closes that
gap: each chat/agent/coder turn running in index mode, the hints already
extracted from recent messages rank the fact index, and the top few matches
(tiny, budget-capped) ride into the prompt alongside the digest. *
Cache discipline: the block is hint-driven, so it changes turn to turn. It
is therefore injected into the UNCACHED trailing block (with the wall-clock
dynamic context), never into the stable workspace block — a volatile line
placed early would poison every cached block after it (see the chat
pipeline's stable-prefix/volatile-suffix contract). *
Gated by CHATCLI_MEMORY_AUTORECALL (default on; only meaningful in "index"
mode — "full" already injects the whole retrieval, "off" injects nothing).
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - memory_bootstrap.go *
The persistent-memory bootstrap card: a short, stable block that tells the
model — in every surface's system prompt — that durable cross-session
memory EXISTS on this machine and how to navigate it. *
Why it exists: the memory layers (facts, episodes, saved sessions, board)
and their pull tools were all in place, yet a fresh session still opened
with the model claiming "each session starts fresh — I have no memory of
past interactions". Nothing in the system prompt ever said otherwise: the
Memory Index digest lists facts/topics/projects but never mentions saved
conversations, and the only anti-amnesia directive in the repo
(GatewayMemoryDirective) was gated to the messaging gateway. The model's
training prior ("assistants have no memory") wins by default — this card
is the explicit counter-evidence, with live counts so it reads as data,
not aspiration. *
Cache discipline: the card is computed ONCE per process (session-start
snapshot) and then reused verbatim, so it can live in the CACHED stable
prefix of the chat and agent/coder system prompts. Counts drifting
mid-session (the memory worker adds facts continuously) must NOT re-render
the card — that would invalidate the prompt-cache prefix every few turns. *
All strings are English model-facing constants, the same rationale as
memoryRecallHint and the recall block headers.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
/memory export|import|recall|why: the memory stores as a portable file,
and the reasons behind what auto-recall injects.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Memory flush before compaction. The memory worker extracts facts from the
live history a couple of turns behind the conversation; compaction
replaces the middle of that history with a summary, so anything the
worker had not reached yet was distilled from a summary at best and lost
at worst. Every compaction site now hands the not-yet-extracted segment
to the worker's durable queue first, so the original messages reach
long-term memory verbatim regardless of what the summary keeps.
ChatCLI - Memory injection mode (push vs pull).
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Controls how long-term memory reaches the model in every mode: *
full — inject the full hint-driven retrieval every turn (the push
model; cost grows with memory size and is paid each turn).
index — inject only a small, stable digest of what memory knows and
let the model pull detail on demand via the memory recall
tool (the pull model; per-turn cost is bounded regardless of
how large memory grows). Default.
off — inject no memory (bootstrap files still apply). *
Agent/coder honor the mode verbatim (@memory tool). Chat honors "index"
through the sanctioned memory tool exception (chat_memory.go); when that
exception is disabled (CHATCLI_CHAT_MEMORY=off) chat has no pull path and
"index" degrades to "full" — see ChatCLI.chatEffectiveMemoryMode.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - memory_notice.go *
Surfaces background memory activity to the user. The memory worker runs
on its own goroutine and must not write to stdout directly (it would
corrupt go-prompt's line redraw). Instead it queues a one-line notice
here; the main loop drains and prints it at the next executor tick.
ChatCLI - Memory extraction resilience: provider fallback + on-disk pending queue.
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Memory extraction is how conversations become durable knowledge. Until now a
failing extraction LLM (provider outage, timeout) meant the segment was only
retried in-process — and lost for good on exit — while the user noticed
nothing for days. This file closes both gaps: extraction walks a fallback
provider chain before giving up, and a segment that still fails is persisted
to ~/.chatcli/memory/pending as a write-ahead queue, drained on later runs —
surviving restarts. Repeated failures surface a one-line notice so silent
memory loss cannot happen again.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Evidence-based reinforcement of recalled facts. *
Auto-recall injects a few long-term facts into every turn. Bumping their
access counters at injection time would reward whatever the ranker
already favors (rich get richer) regardless of whether the model used
the fact. Instead, the facts shown are remembered per turn and only
those the assistant's reply actually drew on — enough of the fact's
own significant terms appear in the answer — are reinforced. Nothing is
demoted: a fact the model ignored simply keeps its score.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - moa_adapter.go *
Implements plugins.MoaAdapter: runs a Mixture-of-Agents query through the
live LLM manager. Each member model answers the same prompt in parallel;
an aggregator model then synthesizes one best answer from all candidates.
Supplied to plugins.SetMoaAdapter at startup.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - moa_command.go *
/moa <prompt> runs Mixture-of-Agents: fan the prompt out to several
reference models in parallel and synthesize their answers with an
aggregator model. Provider-agnostic — any configured provider can be a
reference or the aggregator. *
Every participant is briefed like a regular chat turn (structured system
prompt: attached contexts, workspace memory, skills, retrieval) and holds
the chat-sanctioned read-only tool exceptions (knowledge retrieval, CCR
recall) — see moa_turn.go. *
CHATCLI_MOA_MODELS="openai:gpt-5,claudeai:claude-opus-4-8,googleai:gemini-2.5-pro"
CHATCLI_MOA_AGGREGATOR="claudeai:claude-opus-4-8" (defaults to current model)
ChatCLI - Tool-aware turn executor for Mixture-of-Agents.
Copyright (c) 2024 Edilson Freitas. License: Apache-2.0. *
A MoA run is a panel of experts, and each expert should be as capable as a
regular conversation turn: able to pull from the attached knowledge bases,
to expand "<<ccr:KEY>>" compression markers back into their originals, and
to recall the user's long-term memory (profile, durable facts, notes).
This file builds the moa.Turn executor that grants exactly those three
sanctioned READ-ONLY exceptions to every participant — proposers and
aggregator alike. Memory access is recall-only by construction: the
executor pins the @memory subcommand to "recall", so the mutating forms
(remember, profile, forget) are unreachable from a panel turn. *
Deliberately excluded: ask_user (participants run concurrently and
unattended — N models racing to open interactive overlays is not a panel,
it's a mob) and graphview (a side-effecting artifact writer). No exec, file
or search tools, ever — the same rule chat mode enforces. *
Participants run in parallel goroutines, so everything here is UI-free
(no spinner/prompt coupling) and never mutates ChatCLI state; the only
shared sinks are the mutex-protected cost tracker and the read-only
knowledge/CCR stores.
ChatCLI - Mode transition cleanup.
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Single source of truth for the rule "exactly one ACTIVE MODE marker
may exist in the system slot at any time". When the user moves
between /chat, /agent, and /coder mid-session, the per-mode entry
points used to leave their own system prompt behind in cli.history.
Without cleanup, the next mode's prompt assembler would ship BOTH
prompts to the LLM (the current one in slot 0 and the stale one as
a mid-history system message), and the model would receive
contradictory format rules — "don't emit tool_call" alongside "you
MUST emit tool_call". This file owns the filtering that prevents
that drift.
ChatCLI - @model tool adapter
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Implements plugins.ModelRoutingAdapter over the live session: lists the
configured providers/models enriched with routing metadata (pricing tier,
cost per 1M tokens, context window, capabilities), applies/clears the
agent-loop route override the AI picks via "@model use", and runs
"@model delegate" one-shots on another model without touching the main
loop's history or prompt cache. *
Resolution reuses the same pipeline as skill `model:` frontmatter
(client.ResolveModelRouting), so qualified "PROVIDER:model" handles are
deterministic and bare names fall back to catalog/family heuristics.
Supplied to plugins.SetModelRoutingAdapter at startup.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Output-token reduction wiring: verbosity steering (the universal, cache-safe
lever) plus a conservative, opt-in complexity→effort downgrade. The policy
logic is keyless and lives in cli/outputpolicy; this file only reads config
and bridges to the cli/agent/chat seams.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Context-overflow recovery for the non-agent loops. *
The agent/coder loop has recovered from "context too long" and
proxy-payload rejections for a long time (aggressive budget → level 2 →
emergency truncation, then retry). The chat REPL, RPC chat (MCP, ACP,
gateway), one-shot and MoA participants simply failed the turn. They
now share one bounded helper with the same guarantees a planned
compaction gives: memory flushed first, hooks told, dropped messages
archived to CCR, the cache rebuild accounted for.
park_completer.go — go-prompt suggestions for /parked, /resume, and
/cancel-park. Mirrors the pattern in scheduler_completer.go: a flat
suggestion table for subcommands, plus dynamic token completion that
reads the on-disk snapshot directory.
ChatCLI - Payload Recovery Helpers
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Small helpers for the agent-mode payload/WAF rejection recovery path in
agent_mode.go. Kept in their own file so the dedup contract is unit-
testable without dragging the full agent loop into tests.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Persisted-data redaction. *
Secret redaction always runs on the LLM-bound path. What ChatCLI writes
to disk for itself — sessions, the transcript journal, CCR archives,
hub mirrors — kept the raw text, so a token pasted once lived on in
every store. The strict policy (CHATCLI_ENV_REDACT_MODE=strict, the
existing switch) now also masks what is persisted; the permissive
default keeps stores verbatim so /rewind and exports stay faithful.
ChatCLI - Persona Command Handler
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
/plan — force Plan-First (Plan-and-Solve / ReWOO) for the next agent run. *
Shapes:
/plan → arms the one-shot flag; user then runs /agent <task>
or /coder <task> to consume it
/plan <task...> → arm + run /agent <task> (default, matches doc)
/plan agent <task...> → explicit agent mode
/plan coder <task...> → arm + run /coder <task> (coder with plan-first)
/plan preview <task...> → dry-run: generate and display the plan only
/plan dry <task...> → alias of preview *
The actual planning + execution happens inside AgentMode.Run via
runPlanFirstIfApplicable; this command only flips the trigger and
picks the consuming mode.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
policy_command.go *
/policy — session-scoped security-policy mode. In automode every coder
policy "ask" verdict auto-approves, so the agent runs uninterrupted;
explicit deny rules, the dangerous-command validator and safety-immune
operations keep gating exactly as in interactive mode. The mode is never
persisted: a new session always starts interactive. Exposed on all three
surfaces — terminal REPL, ACP (slash command), MCP (manage_session
policy_mode action).
ChatCLI - Adapter binding the @proc tool to the session process supervisor.
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Implements plugins.ProcAdapter over cli/agent/proc: a lazily created,
session-scoped Supervisor whose command vetting is the SAME
agent.CommandValidator the one-shot exec path uses — @proc is never a side
door around policy. Every process still running dies with the session.
project_env.go *
Per-project environment overlay for surfaces that only learn about the
user's project after boot — today the ACP server, which receives it as
session/new's cwd. *
The overlay is FILL-ONLY (config.ApplyProjectDotenv): a project .env can
add settings the user has not set, and can never take over one that is
already in effect. It also runs at most once per process: the first
project announced wins, so two editor windows can never fight over the
process-wide environment.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Prompt breakdown: what the last assembled system prompt was made of. *
Seven different injectors contribute to a turn's system prompt (mode
banner, attached contexts, knowledge digests, skills, MCP catalog,
workspace memory, recall blocks, dynamic context). Until now nothing
recorded their sizes, so "what is in my context right now" had no
answer. Both assembly paths — chat (assembleChatSystemPrompt) and
agent/coder (buildAgentSystemMessage) — now record a labeled section
list here, and /context status renders it with token estimates.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Global prompt budget for the system prefix. *
The compactor budgets the CONVERSATION against the model window; the
prefix in front of it (mode card, attached contexts, knowledge digests,
skills, tool catalog, recall blocks) was assembled section by section
with local caps only, so a session with several attachments and a few
fat skills could fill the window before the first user message — and
the compactor would then starve the history to make room. This budget
sums the prefix as it is assembled and, when the prefix alone would
cross its share of the window, degrades sections in a declared order: *
1. skills — bodies fold into read-on-demand pointers (the model still
learns which skills apply and where to read them);
2. knowledge digests — index cards shrink to their compact form;
3. attached contexts — whole-content attachments fold into an index
card that names the files and how to pull them (@context,
/context attach --rag). *
Every degradation is recorded on the prompt breakdown so /context
status shows what was folded and why. Nothing is dropped silently, and
a session that fits keeps exactly the prompt it always had.
ChatCLI - go-prompt colors derived from the active theme
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
The REPL input line and its completion dropdown are painted by go-prompt,
which owns its own render loop and never sees an ANSI string we build — so
theme.Recolor (the bridge that re-skins every fmt.Print call site) cannot
reach it. Historically that meant the colors were LITERALS: the text you
type was prompt.White no matter which theme was active, which is fine on a
dark ground and unusable on a light one — white on white. *
This file is the missing bridge. Every go-prompt color is derived from a
semantic palette entry, so the input line, the suggestion list and the
description panel follow a theme switch exactly like the rest of the UI. *
Two constraints shape the mapping: *
- go-prompt speaks only the 16-color enum, so we read each palette
entry's ANSI16 index (the theme's own explicit downgrade) rather than
letting a library guess from the hex.
- A foreground painted ON a filled row must come from the OPPOSITE end of
the palette. Background is the theme's own ground (dark under dark
themes, light under light ones), so it is the correct ink on a
saturated fill, and TextStrong is the correct ink on the neutral Border
fill. Using TextStrong for both would print black on dark gray under
every light theme. *
Under the default dark theme the resulting indices reproduce the previous
literals (Info→10 = prompt.Green, TextStrong→15 = prompt.White, Border→8 =
prompt.DarkGray, Background→0 = prompt.Black), so adopting the bridge is a
visually neutral change there and a legibility fix everywhere else. *
go-prompt freezes these on its renderer at construction, so a theme switch
mid-session only reaches the input line once the prompt is rebuilt — which
is why /config ui theme unwinds the REPL loop (see cli.Start).
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - ratelimit_command.go *
/ratelimit (alias /limits) shows the latest rate-limit state captured from
provider response headers. Data is populated centrally via
auth.ResponseObserver for every HTTP provider, so this works across all
providers without per-provider code.
ChatCLI - Refine convergence wiring (Phase 5 enterprise). *
Builds a convergence.Composite cascade (char → jaccard → embedding)
from the active embedding provider (shared with HyDE so there's no
duplicate provider instance). Wired by AgentMode.initWorkers into
quality.BuildPipelineDeps.ConvergenceChecker. *
Degrades gracefully: when semantic convergence is disabled in
config, returns nil and the RefineHook falls back to the legacy
char-level heuristic. When the embedding scorer is enabled but the
provider is the null one (no CHATCLI_EMBED_PROVIDER configured),
the cascade still runs char + jaccard, and embedding-related
thresholds are never applied.
ChatCLI - /refine and /verify session toggles (Phases 5 & 6). *
The hooks are normally controlled by /config quality. These slashes
give the user a way to flip the next-turn behavior without editing
env vars: /refine on|off|once, /verify on|off|once. Bare /refine or
/verify show the current state.
ChatCLI - Reflexion wiring (Phase 4 of seven-pattern rollout). *
Builds the LLM and memory-persist callbacks the ReflexionHook needs,
plus the durable lesson queue (lessonq.Runner) used in enterprise
mode. Lives in cli/ so the quality package never imports cli.ChatCLI. *
Subcommands of /reflect:
/reflect → show queue + DLQ status
/reflect <text> → persist a user-supplied lesson
/reflect list → list pending + DLQ entries
/reflect failed → list DLQ entries with errors
/reflect retry <id> → move DLQ entry back to active queue
/reflect purge <id> → permanently delete a DLQ entry
/reflect drain → force processing of pending queue
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Unified retention. Every durable store had its own lifecycle rule and
two of them (park snapshots, cost snapshots) only expired when a user
remembered to run a manual sweep or happened to trigger a save. The boot
pass below applies the machine-session TTL to those stores too, and
/config retention shows every policy in one place.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Undo for compaction and persisted /rewind checkpoints. *
Every rewrite of the history (auto-compact, /compact, overflow
recovery, /clear) is preceded by a snapshot of what it replaces;
/rewind compact puts that history back. The snapshot lives in memory
for the running session and, after a resume, is rebuilt from the
transcript journal: rewrite events carry the ordered hashes of the
replaced history and the journal holds every message ever seen.
/rewind checkpoints persist with the session the same way (hash lists
resolved against the journal on load).
rpc_chat.go *
Full-pipeline chat turns for the MCP/ACP servers. The interactive REPL turn
(processLLMRequest) and this headless variant share every enrichment stage —
assembleChatSystemPrompt (workspace memory, /context attach, pinned + auto
skills, MCP catalog, RAG), buildChatTempHistory, skill model routing, effort
hints, token-aware history compaction, hub mirroring and the memory worker
nudge — so an MCP client gets the SAME ChatCLI experience as the terminal,
by construction rather than by reimplementation. *
Concurrency: the pipeline reads and writes shared ChatCLI state
(cli.history, cli.currentSessionName), so turns run under the same
process-wide serialization as the captured agent/coder runs (rpcStdoutSem via
captureRPCStdout). The backend owns the per-session histories; this method
swaps one in for the duration of the turn and always restores the previous
state, even on error.
rpc_support.go *
Exposes ChatCLI capabilities to the MCP/ACP servers (cmd/rpcserve.go) so an
MCP client can drive the real agent/coder loops and the built-in tools — not
just a chat passthrough. *
The agent and coder render to stdout; these helpers redirect os.Stdout to a
buffer for the duration of the run and return the captured transcript. The
JSON-RPC server holds its own copy of the original stdout (captured at
construction), so the protocol channel is unaffected by the redirect.
rpc_support_full.go *
The full capability surface behind the MCP/ACP servers: every built-in and
external plugin (not just the old curated five), the agent/coder loops with
per-call provider/model routing and quality-harness toggles, the skill
catalog (served as MCP prompts), and provider discovery. *
Beyond plugins, the server re-exports every tool discovered from the MCP
servers ChatCLI itself is connected to (mcp_servers.json), under the same
mcp_<tool> names the agent loop uses — ChatCLI as an MCP hub: one endpoint
aggregating many servers. Proxied tools keep their origin JSON Schema and
receive the caller's arguments verbatim. *
Exposure policy (CHATCLI_MCP_TOOLS):
all (default) every tool, including write/exec — the operator opted in
by starting the server.
safe only tools whose capability metadata reports read-only
for a bare invocation. For proxied MCP tools this trusts
the origin server's annotations.readOnlyHint — the same
trust the operator extended by configuring the server.
<csv> explicit allowlist of tool names (with or without '@');
proxied MCP tools are named with their mcp_ prefix
(e.g. "read,search,mcp_list_regions"). *
Interactive tools that require a live TTY/user (ask, voice, park) are
excluded unconditionally: over stdio RPC they would hang the turn waiting
for input that can never arrive.
rpc_support_resources.go *
Read-only export of ChatCLI's local state to MCP clients as resources under
the chatcli:// scheme: the user's long-term memory, profile and projects,
the /context store (including knowledge bases with paged document reads),
the skill catalog and the saved sessions. This is what lets a user who
built their knowledge in ChatCLI browse the SAME state from any MCP client
on the machine. Everything here is read-only by construction; mutations go
through the tools surface (@memory, @context, manage_session, …). *
URIs:
chatcli://memory/index | longterm | profile | projects | stats
chatcli://contexts — catalog (JSON)
chatcli://contexts/{name} — rendered content / index card
chatcli://knowledge/{kb} — TOC
chatcli://knowledge/{kb}/{source}?offset=N — paged document read
chatcli://skills — catalog with triggers (JSON)
chatcli://skills/{name} — skill body (markdown)
chatcli://sessions — saved-session names
chatcli://sessions/{name} — saved session (JSON) *
Gate: CHATCLI_MCP_RESOURCES=off disables the surface entirely.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
run_coordinator.go — the cadence/back-pressure/circuit-breaker primitive that
governs the background self-evolution pass (memory extraction + skill
detection share one run). Extracted from memoryWorker so the scheduling logic
is independently testable with an injectable clock, and reusable by any future
periodic task. *
It guarantees: at most one run at a time (back-pressure); a minimum gap and a
minimum amount of new work between runs (cadence); and, after a streak of
failures, a cooldown window during which runs are skipped entirely (circuit
breaker) instead of hammering a provider that is down — the queue is drained
on the next run once the window passes.
runs_hub_bridge — mirrors the agent run registry through the Conversation
Hub's SQLite store, giving /agents and @agents cross-process sight: a REPL
can watch runs executing inside the gateway daemon (and vice versa), and
request their cancellation. *
Writer side: an OnEvent observer marks runs dirty and a 1s flusher upserts
their JSON snapshots into the agent_runs table (see hub.AgentRunStore for
why runs are upserted, not appended). Every flush also re-upserts the
local active set, so updated_at doubles as a liveness heartbeat. *
Reader side: the bridge publishes a process-wide provider that lists runs
mirrored by OTHER instances, annotated with staleness (heartbeat silence),
and forwards cancel requests by flagging the row — the owning process
observes the flag on its next flush tick and cancels locally, since only
it holds the context.CancelFunc.
ChatCLI - scheduler_adapter.go *
Implements plugins.SchedulerAdapter so the @scheduler builtin plugin
can route ReAct tool calls into the live Scheduler. Supplied to
plugins.SetSchedulerAdapter during initScheduler.
ChatCLI - scheduler_bridge.go *
Implements scheduler.CLIBridge on top of *ChatCLI. Owned by the CLI
package so the scheduler subpackage stays free of the circular
dependency the top-level struct would introduce. *
The bridge is stateless except for a back-pointer to ChatCLI. Every
method routes through existing chatcli code paths so scheduled work
behaves identically to interactive work — hooks fire, quality
pipeline runs, session policy applies, etc.
ChatCLI - scheduler_command.go *
Top-level command handlers for /schedule, /wait, /jobs and the agent
tool adapters. Routes to either the in-process scheduler or the
remote daemon, transparently.
ChatCLI - scheduler_completer.go *
Context-aware autocomplete for /schedule, /wait and /jobs. Follows
the same pattern as getContextSuggestions / getSessionSuggestions: *
- Subcommand suggestions when the user is at position 1.
- Flag suggestions after the subcommand, with short descriptions.
- Value suggestions right after a flag that has a fixed-vocabulary
(like --status, --on-timeout, --owner), plus live lookups of
active job IDs for --depends-on / --triggers / show / cancel /
pause / resume / logs. *
All descriptions go through i18n so a future translation pass is
trivial. Lookups hit the local scheduler, or the remote daemon via
schedulerList when running in thin-client mode.
httpProbeClient — bounded, redirect-aware HTTP client used by the
scheduler's ParkPoll action via CLIBridge.RunHTTPProbe. Centralizing
timeout, redirect, and body-cap policy here keeps the action
executor terse and the security posture auditable in one place.
ChatCLI - scheduler_init.go *
Scheduler lifecycle integration into *ChatCLI. *
Initialization order (called from NewChatCLI, after hooks + bus are ready): *
1. Build scheduler.Config from env.
2. If daemon auto-connect enabled and a daemon is reachable, wrap
it in a thin proxy and skip in-process init.
3. Otherwise build the in-process scheduler, register builtins,
start it. *
Cleanup: DrainAndShutdown is invoked from ChatCLI.cleanup.
Tiny encoding/json wrappers so the command handler can stay import-
light on the json package. Kept in a separate file so the rest of
scheduler_command.go reads cleanly.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
selfevolve.go — the self-evolution engine. *
Root cause it addresses: long-term memory "happens by itself" because a
background worker extracts facts every few turns, but skills only ever got
created when the model remembered to call @skill — so users had to ASK for
them. This engine gives skills the same proactive treatment WITHOUT a second
LLM call: it piggybacks on the memory worker's existing extraction pass. The
worker appends selfEvolveSkillDirective to that prompt, and the same response
that yields facts also yields ## SKILL_CANDIDATES. applySkillCandidates then
authors or evolves them. *
Safety model (mode=auto): every authored skill is engine-OWNED and tracked by
a content hash in a sidecar manifest, mirroring builtin.Seed. The engine only
ever evolves a skill it still owns and the user has not hand-edited; a skill
the user authored or touched is never clobbered. Every authored skill is
reversible via `/skill remove` and surfaced with a one-line notice. mode=
suggest never writes to disk; mode=off disables the directive entirely. *
The only operator-facing knob is CHATCLI_SELFEVOLVE_MODE. Cadence, cost and
resilience are inherited from the memory worker — no new tuning surface.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
selfevolve_manifest.go — edit-safety ledger for engine-authored skills. *
Mirrors pkg/persona/builtin/seed.go's manifest discipline: each skill the
engine writes is recorded with the SHA-256 of the exact bytes it wrote. On a
later pass the engine only evolves a skill whose current on-disk hash still
matches — i.e. one it owns and the user has not hand-edited. A skill the user
authored (never recorded) or has since changed (hash drift) is treated as
user-owned and never overwritten. The ledger lives beside the skills it
tracks so it travels and is cleaned up with them.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
selfevolve_merge.go — the on-demand skill-body merge (the "pull" half). *
Per-turn the engine injects only a tiny skill index card (names + one-line
descriptions). The full body of a skill is never in the prompt. When — and
only when — an evolution is actually detected, this makes ONE targeted LLM
call that loads just that single skill's body and folds the improvement in.
Cost therefore scales with real evolutions, not with skill-count × turns,
mirroring memory's index/recall split.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
selfevolve_parse.go — robust, YAML-free parser for SKILL_CANDIDATES blocks. *
The extraction LLM emits zero or more self-delimited [[skill]]...[[/skill]]
blocks. We scan for those delimiters directly rather than inferring YAML, so a
stray indent or quote can never corrupt a parse. Blocks are recognized
anywhere in the response (they are self-delimiting), which tolerates models
that reorder or relabel the section header.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - send_adapter.go *
Implements plugins.SendAdapter so the @send builtin tool can deliver
proactive outbound messages through the live gateway platform adapters —
the same Telegram/WhatsApp/Discord/Slack/webhook integrations the gateway
daemon uses for replies. Supplied to plugins.SetSendAdapter at startup. *
Target resolution:
"platform" → the platform's configured home channel
(CHATCLI_<PLATFORM>_HOME_CHANNEL)
"platform:chat_id" → an explicit chat id (the rest is passed verbatim,
so "telegram:-100123:42" keeps the thread suffix) *
Adapters are built on demand via gateway.BuildConfigured() — only platforms
with valid credentials are instantiated, so an unconfigured target yields a
clear "not configured" error instead of a silent drop.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - session_adapter.go *
Implements plugins.SessionAdapter so the @session tool can search the saved
conversation store through the live SessionManager. Supplied to
plugins.SetSessionAdapter at startup.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
/context attach state persisted with the session. Attachments lived only
in the process: a restart, a /session load on another surface or the
gateway daemon picking up a bound session all lost every attached
context. Saved sessions now carry the attachment records and loading one
re-attaches them under the session's own key.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - session_autorecall.go *
Proactive recall for SAVED SESSIONS, the sibling of the fact auto-recall
in memory_autorecall.go. Autosave made every conversation retrievable, but
retrieval relied on the model CHOOSING to call @session — and models
routinely answer "I don't have that context" while the relevant autosave
sits unread in the store. Each agent/coder turn, this ranks the recent
sessions against the turn's hints (or against the user's own words when
they explicitly reference a past conversation) and floats the top matches
as a compact pointer block; the model then pulls detail via @session get. *
Cache discipline: hint-driven text changes turn to turn, so the block
rides in the UNCACHED trailing dynamic block, exactly like the fact
auto-recall — never in the stable workspace block. *
Gated by CHATCLI_SESSION_AUTORECALL (default on). Search is scoped to the
most recent sessions (they are what "ontem"/"where we left off" point at)
and served from the corpus cache, so the per-turn cost is bounded.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - session_search_normalize.go *
Text normalization for saved-session search. Recall queries are natural
language ("o que discutimos sobre o spinner?"), while the session-level
AND filter in SearchSessions is a literal substring match — without
normalization, accents ("autenticação" vs "autenticacao") and
recall-framing words ("discutimos", "what did we decide") disqualify
exactly the sessions the user is asking about. *
Accent folding is a hand-rolled Latin table instead of x/text: the store
only sees PT/EN prose, and stdlib-only avoids a new direct dependency.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
The transcript journal as a first-class record: /session export
(Markdown or JSONL of the full journal, not the compacted view),
/session transcript search (BM25 over every journaled message) and
/session transcript show (replay a range). Falls back to the live
history when the journal is off.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Skill auto-activation helpers
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Extracts file-like tokens from user input and composes the system-prompt
block used to inject auto-triggered / path-matched skills. Shared by chat
mode (cli_llm.go) and agent mode (agent_mode.go) so that both code paths
honor the same skill frontmatter contract.
ChatCLI - Skill Registry Command Handler
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Handles /skill commands: search, install, uninstall, list, info, registries, help.
ChatCLI - Manual skill invocation via /<skill-name>
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Implements the "/<skill-name> [args]" routing promised by the skill
frontmatter advanced docs:
- Only skills with `user-invocable: true` are routable.
- Skills with `disable-model-invocation: true` are still allowed via
manual invocation (the flag only blocks *auto* activation).
- The skill's full content is injected into the system prompt for the
single turn via cli.pendingManualSkill.
- The skill's `model:` / `effort:` hints are honored for that turn.
- Any trailing args become the user message passed to the LLM; when
empty, a neutral "apply skill X" instruction is synthesized and the
`argument-hint` (if any) is shown to the user as a usage nudge.
ChatCLI - Skill model/provider resolution (thin wrapper)
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Delegates to llm/client.ResolveModelRouting which holds the pure logic.
This file only wires in ChatCLI state (cachedModels, manager, logger) and
keeps the existing ChatCLI method signature so the rest of the codebase
stays unchanged.
ChatCLI - Mid-loop skill re-activation for agent/coder mode
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Skills auto-activate once at Run() start against the user's query. That
misses everything the ReAct loop produces afterwards: the model's own
<reasoning> text, the file paths its tool calls start touching, and the
follow-up instructions the user types mid-session (type-ahead queue or the
interactive continuation prompt). This file closes that gap: every turn the
loop re-scans that mid-run text against the skill catalog and injects any
NEWLY matched skill as an append-only history message — so a skill whose
trigger only surfaces in the agent's own plan ("I should write a Helm
chart…") still reaches the model in time to shape the very next action. *
Injection is append-only (a user-role message, like the tool-guard and
payload-recovery hints) so the cached system-prompt prefix is never
invalidated mid-run. A per-Run dedup set guarantees each skill is injected
at most once per session, bounding both token cost and cascade risk.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
Live wiring of @taskgraph: resolves the session's worker dispatcher, runs
validation gates through the coder engine (sandboxed, unsafe-command
gated), attributes real per-call cost to graph tasks, and guards the
one-active-run-per-session invariant.
/taskgraph — human view over @taskgraph runs: status, per-task detail,
run listing and cancel. Allowlisted as a mid-run side command so the user
can watch a live graph without touching the orchestrator loop. The
technical state lines reuse the taskgraph renderers on purpose: human and
model read the same ground truth.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
Learning digest: at the end of a @taskgraph run, feed what the graph
discovered back into the session's long-term memory — the same pipeline
that learns from normal turns. A run's verdicts, evidence and retries are
exactly the material the memory extractor (facts + episodes + topics) and
self-evolution (skill candidates) need; without this, everything the
graph learned evaporated with the report. *
Two sinks, both best-effort (nothing here can fail or block a run):
1. a compact digest segment → memWorker.nudgeSegment (facts/episodes/
self-evolve, on the normal cadence via the durable WAL);
2. one Reflexion lesson per FAILED task → the lesson queue.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Wires the OTLP metrics exporter to the session's cost tracker: the
cumulative token, cache, compaction, embedding and cost counters every
surface already keeps become OpenTelemetry sums, labeled by surface and
tenant. Configured purely through the OTEL_* environment.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Per-tenant paths for the stores that resolve their directory
themselves: parked runs and task-graph runs follow the active state
root (the tenant root under the gateway), so principals never see or
resume each other's work. The scheduler daemon, the conversation hub
database and the tokenizer vocabulary cache stay process-wide by
design: the first two are the cross-process bus, the third holds
public data.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Per-principal store sets for the gateway daemon. *
The gateway serves every channel identity through one ChatCLI. With
CHATCLI_HUB_ISOLATE=true the conversation hub already keeps one
conversation per principal, but every durable store — saved sessions,
long-term memory, knowledge contexts, the CCR archive, cost snapshots,
the transcript journal — and the live history were shared: a /session
list from one chat listed everyone's sessions, one user's facts surfaced
in another's turns. A tenant store set is a complete replacement of those
handles rooted at ~/.chatcli/tenants/<principal>; the gateway swaps it in
under its turn mutex before a principal's turn and swaps the base set
back after. Nothing changes for the single-user default: the swap only
happens when isolation is on and the principal is not the shared one.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
/thinking — session-level reasoning override. *
Sits on top of llm/client/skill_hints (which maps SkillEffort to
Anthropic thinking_budget and OpenAI reasoning_effort). The override
is consumed in cli_llm.go (chat path) and agent_mode.go (orchestrator
turn) so the user can force-on, force-off, or pick an explicit tier
without touching env vars.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Persistence and scoping of the token calibrator. *
A learned chars-per-token ratio is worth keeping: it takes several
turns to converge and every new process started at 4.0 again. Ratios
are saved to <state root>/calibration.json (atomic write, debounced)
and loaded on first use. The state root is the tenant root when a
gateway tenant is active, so tenants never share (or leak) ratios; the
global root serves the REPL, the MCP server and one-shot runs.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Learned chars-per-token ratio per provider/model. *
ChatCLI has no tokenizer: every budget (compaction, projected context
use, per-section estimates) was a fixed 4 chars per token, which is off
by 2-3x for CJK text, base64 payloads or minified code. The provider,
however, reports the real prompt token count on every response, and the
request's character count is known — so the ratio can be learned per
provider+model and fed back to every estimate. The calibrator is the one
place that learning lives; the compactor and /context status read it.
ChatCLI - Tool-catalog rendering and deferral policy.
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
The agent system prompt used to carry the FULL definition of every builtin
(~11k tokens across 28 tools, measured) on every turn, even though a
typical session touches a handful. This file implements the same deferral
the MCP section already applies to external servers: a small CORE set keeps
full definitions inline, every other builtin appears as a one-line index
entry, and the model pulls a full definition on demand through the @tools
meta-tool. External (user-installed) plugins stay fully rendered — they are
few and explicitly chosen. *
CHATCLI_AGENT_TOOL_CATALOG=full restores the legacy always-inline behavior.
ChatCLI - Adapter binding the @tools meta-tool to the plugin registry.
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Implements plugins.ToolCatalogAdapter over the live plugin manager AND the
MCP manager: Describe renders one tool's full prompt block through the SAME
renderer the agent system prompt uses (an on-demand definition is
byte-identical to an inline one) — for mcp_* names it renders the tool's
JSON Schema from the connected server instead — and List renders the
one-line index of everything available, builtins and MCP alike.
Wired via plugins.SetToolCatalogAdapter at startup.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Append-only transcript journal. *
Saved sessions persist the in-memory window as it stands — after
compaction the original messages exist only as CCR keys with a 7-day TTL,
and a hard kill mid-turn lost everything since the last turn boundary.
The journal is the durable record: every message is appended once, the
first time it appears at the tail of the live history, and a history
rewrite (compaction, guided /compact, microcompact stubs) is recorded as
an event instead of being lost. Synced at turn boundaries and after each
agent tool batch, each line fsynced, sealed line by line when encryption
at rest is enabled. Journals follow the machine-session TTL.
tty_inject_unix.go — controlling-TTY input injection via TIOCSTI. *
Used by the park subsystem to wake go-prompt out of its blocking
stdin read when a parked agent's resume becomes ready. We inject
the literal string "/resume <token>\n" as if the user typed it; the
executor then runs naturally (drainPendingResumes consumes the queue,
the resume runs in foreground with full terminal control), the same
code path /coder uses to take the terminal back from go-prompt. *
Platform notes *
- Linux: TIOCSTI behavior depends on the kernel build and a
runtime sysctl introduced in 5.16:
/proc/sys/dev/tty/legacy_tiocsti
Default 0 (enabled) on older kernels and many server distros;
default 1 (restricted) on Linux 6.x+ desktop builds and the
Docker Desktop linuxkit kernel. When restricted, TIOCSTI
returns EPERM. Operators who need auto-resume injection can
toggle the flag with `sysctl -w dev.tty.legacy_tiocsti=0`
(root). The fallback path remains the executor-hook drain. *
- macOS: TIOCSTI was deprecated in macOS Ventura and is gated
behind kern.tiocsti_disable=0 on most modern installs. Calls
return EPERM under the default policy. We surface the error so
the bridge can log the limitation; the executor-hook drain in
cli.executor still consumes the queue when the user types any
character + Enter. *
- FreeBSD/NetBSD/OpenBSD: TIOCSTI works for controlling TTYs in
the same session. macOS-style restrictions don't apply.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Per-turn context as a user-turn message. *
Everything that changes from one turn to the next — the date, the
proactive memory and session recall, auto-activated skills, MCP channel
pushes, the watcher snapshot — used to trail the system message. Every
provider caches by prefix, so a system message that differs each turn
made every breakpoint after it miss: each turn re-wrote the whole
conversation into the cache and read nothing back. Those blocks now ride
as one flagged user-role message placed right before the user's turn,
persisted with the conversation so the next request replays identical
bytes; the system message is byte-stable for the session. *
Persisting them is what keeps the prefix cache alive — dropping a
message the previous request sent moves every byte after it — but it
also meant one block per turn accumulating in the window for the whole
session, most of them repeating what the block before them already
said. So the block is not injected at all when it would repeat the last
one still in history: the conversation keeps growing by appends only,
the cache holds, and the model reads the same information once instead
of once per turn.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
/update atualiza o ChatCLI pelo MESMO canal em que foi instalado
(Homebrew, go install ou binário oficial da release — detectados pelo
pacote update). Canais manuais (Docker, build local) recebem instruções
em vez de ação. Este arquivo também abriga o fluxo de boot: refresh do
cache de release + staging silencioso no modo CHATCLI_AUTO_UPDATE=auto.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Aviso de atualização descoberto DEPOIS da welcome screen: o refresh de
release roda em goroutine no boot, então quando ele detecta uma versão
nova a tela de boas-vindas já foi impressa. Em vez de esperar o próximo
boot, o aviso fica pendente e é drenado no próximo tick do executor —
o único ponto onde escrever no stdout não disputa com o redraw do
go-prompt (mesmo padrão de memNotices).
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Renderização do relatório de versão — usada pelo /version, pela slash
tool equivalente e pela flag -v/--version do binário. Substitui a saída
antiga (hardcoded em PT, sem menção ao /update e cega ao canal de
instalação) por um card no tratamento sóbrio do welcome: régua titulada,
grid de indentação 2, canal detectado, convite ao /update e as novidades
da release quando há atualização disponível.
ChatCLI - Adapter binding the @view tool to the session vision pipeline.
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
Implements plugins.ViewAdapter: loads a local image (same loader and size
caps as @file attachments), routes it through gateImagesForModel (native
vision with compression, describe-fallback, or off) and stages the result
on the live agent loop, which attaches it to the conversation at the next
turn boundary — never between a tool_use and its tool_result.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
ChatCLI - Windows console input sanitizer.
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
On Windows, go-prompt reads keys through go-tty, which translates any key
pressed with Alt held — INCLUDING AltGr (right Alt), which Windows reports
as Ctrl+Alt — into an ESC prefix followed by the character. That is correct
for Alt-as-Meta shortcuts, but AltGr is how several layouts type everyday
characters: "/" is AltGr+Q on Brazilian ABNT2, "@"/"{"/"[" need AltGr on
German and Nordic layouts, and so on. go-prompt doesn't recognize
ESC+<printable> sequences, so it inserts the raw ESC byte into the edit
buffer, which the terminal renders as a stray "?"-like glyph before the
character the user actually typed. *
altGrParser wraps the platform ConsoleParser and strips that spurious ESC
when — and only when — the batch is ESC followed by exactly one printable
rune. Real escape sequences (CSI "ESC [", SS3 "ESC O", double-ESC) and the
Alt shortcuts chatcli itself binds (ESC f / ESC b word navigation,
ESC DEL / ESC BS delete-word) pass through untouched. The logic is
platform-neutral (and unit-tested everywhere); the wrapper is only wired
into the prompt on Windows, where the go-tty translation exists.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0
cli-side wiring for the workers' per-task plugin grants (see
cli/agent/workers/plugin_tools.go). The workers package cannot reach the
plugin or MCP managers, so this file provides:
- runWorkerPluginTool: execute one granted call (builtin or mcp_*),
- workerPluginToolDefs: translate grant names into native tool defs. *
Concurrency: @browser (and any plugin declaring IsConcurrencySafe=false)
drives one process-wide stateful session; parallel workers would corrupt
it. We serialize non-concurrency-safe plugins with a per-plugin mutex —
the first such enforcement in the process. This prevents interleaved CDP
ops; it does NOT prevent one worker's snapshot refs being invalidated by
another worker's navigation, so the skill advises granting @browser to a
single task.
Worker task context provider: what a dispatched squad/taskgraph worker
receives in its system prompt beyond its charter. *
Historically this was only the proactive recall block (memory/session).
This file layers the user's own SKILL.md on top, trigger-matched against
the worker's task text — so a worker executing "validate the login page"
gets the same curated knowledge the orchestrator would. Pinned skills are
always included (explicit user intent); trigger matches are capped and
budgeted. Everything is inlined (a worker cannot expand a global skill
pointer — validatePath confines its reads to the workspace). *
100% cli-side: the registered workers.RegisterWorkerContextProvider hook
now points at workerTaskContext, no changes in cli/agent/workers. *
Note: persona.Skill (user SKILL.md) is unrelated to workers.SkillSet
(executable macros) — do not conflate.
ChatCLI - Command Line Interface for LLM interaction
Copyright (c) 2024 Edilson Freitas
License: Apache-2.0 *
The orchestrator's window management, shared with squad, taskgraph and
delegate workers: the session compactor (with the active tenant's CCR)
and the transcript journal. Workers used to have nothing beyond the L0
microcompact — no compaction, no journal, no overflow recovery.
Index ¶
- Constants
- Variables
- func AgentMaxTurns() int
- func DetectPromptInjection(text string) (bool, []string)
- func FormatPayloadSize(bytes int) string
- func FormatVersionReport(rep version.Report) string
- func HasStdin() bool
- func IsEncrypted(data []byte) bool
- func LocalHubPrincipal() string
- func NewSlashToolPlugin(entry *SlashToolEntry) plugins.Plugin
- func ParsePayloadSize(s string) int
- func PreprocessArgs(args []string) []string
- func RegisterSlashTool(entry *SlashToolEntry)
- func ResetManagerHooksForTest()
- func ResetProjectEnvOnceForTest()
- func RunUpdateOneShot(ctx context.Context, logger *zap.Logger, checkOnly bool) error
- func RunUpdateSubcommand(ctx context.Context, logger *zap.Logger, args []string) int
- func SanitizeCommandOutput(cmd, output string) string
- func SweepStaleParks(cutoff time.Time) (int, []error)
- func TurnCacheHitPct(provider, model string, u *models.UsageInfo) (float64, bool)
- func UpdateSubcommandMain(args []string) int
- type ACPCommandInfo
- type AgentMode
- func (a *AgentMode) InjectedSkillNames() []string
- func (a *AgentMode) Run(ctx context.Context, query string, additionalContext string, ...) error
- func (a *AgentMode) RunOnce(ctx context.Context, query string, autoExecute bool) error
- func (a *AgentMode) RunResumed(ctx context.Context, snap *park.Snapshot, outcome, detail string) error
- type AnimationManager
- type AuditChainReport
- type BudgetLevel
- type CacheStats
- type ChatCLI
- func (cli *ChatCLI) ApplyOverrides(ctx context.Context, mgr manager.LLMManager, provider, model string) error
- func (cli *ChatCLI) ApplyProjectEnv(dir string) (manager.LLMManager, config.ProjectDotenvReport)
- func (cli *ChatCLI) CancelOperation()
- func (cli *ChatCLI) CleanExpiredMachineSessionsRPC() int
- func (cli *ChatCLI) DeleteSessionRPC(name string) error
- func (cli *ChatCLI) EnableHubSync(client HubClient)
- func (cli *ChatCLI) ExpandSlashCommandRPC(ctx context.Context, text string) (string, bool)
- func (cli *ChatCLI) FinalizeSpend(ctx context.Context)
- func (cli *ChatCLI) ForkSessionRPC(sourceName, newName string) error
- func (cli *ChatCLI) GetContextCommands() []prompt.Suggest
- func (cli *ChatCLI) GetInternalCommands() []prompt.Suggest
- func (cli *ChatCLI) HandleOneShotOrFatal(ctx context.Context, opts *Options) bool
- func (cli *ChatCLI) IsACPCommandAllowed(token string) bool
- func (cli *ChatCLI) IsExecuting() bool
- func (cli *ChatCLI) ListACPCommands() []ACPCommandInfo
- func (cli *ChatCLI) ListAllRPCTools() []RPCToolInfo
- func (cli *ChatCLI) ListCommandPromptsRPC() [][3]string
- func (cli *ChatCLI) ListMCPProxyTools() []RPCMCPToolInfo
- func (cli *ChatCLI) ListRPCResources() []RPCResourceInfo
- func (cli *ChatCLI) ListSessionsRPC() ([]string, error)
- func (cli *ChatCLI) ListSkillsRPC() []RPCSkillInfo
- func (cli *ChatCLI) LoadSessionRPC(name string) ([]models.Message, error)
- func (cli *ChatCLI) MCPStartupDone() <-chan struct{}
- func (cli *ChatCLI) OnManagerRebuild(fn func(manager.LLMManager))
- func (cli *ChatCLI) PolicyAutoMode() bool
- func (cli *ChatCLI) PolicyModeLabel() string
- func (cli *ChatCLI) PrintWelcomeScreen()
- func (cli *ChatCLI) ProvidersRPC() (string, error)
- func (cli *ChatCLI) PruneSessionsRPC(prefix string, keep int) int
- func (cli *ChatCLI) ReadRPCResource(_ context.Context, uri string) (RPCResourceContent, error)
- func (cli *ChatCLI) RenderCommandPromptRPC(ctx context.Context, name, args string) (string, bool)
- func (cli *ChatCLI) RotateHubThreadRPC(ctx context.Context)
- func (cli *ChatCLI) RunAgentCaptured(ctx context.Context, task string) (string, error)
- func (cli *ChatCLI) RunAgentFullOnce(ctx context.Context, task string) error
- func (cli *ChatCLI) RunAgentOnce(ctx context.Context, input string, autoExecute bool) error
- func (cli *ChatCLI) RunAgentRPC(ctx context.Context, task string, o RPCRunOpts) (string, error)
- func (cli *ChatCLI) RunAgentStreaming(ctx context.Context, task string, emit func(string)) (string, error)
- func (cli *ChatCLI) RunAnyRPCTool(ctx context.Context, name, args string) (string, error)
- func (cli *ChatCLI) RunAnyRPCToolArgv(ctx context.Context, name string, argv []string) (string, error)
- func (cli *ChatCLI) RunChatTurnRPC(ctx context.Context, sessionID, userInput string, history []models.Message, ...) (RPCChatTurn, error)
- func (cli *ChatCLI) RunCoderCaptured(ctx context.Context, task string) (string, error)
- func (cli *ChatCLI) RunCoderOnce(ctx context.Context, input string) error
- func (cli *ChatCLI) RunCoderRPC(ctx context.Context, task string, o RPCRunOpts) (string, error)
- func (cli *ChatCLI) RunGatewayCoderOnce(ctx context.Context, task string) error
- func (cli *ChatCLI) RunGatewayCoderStreaming(ctx context.Context, task string, emit func(string)) (string, error)
- func (cli *ChatCLI) RunGatewayForeground(ctx context.Context) error
- func (cli *ChatCLI) RunGatewayWithBroker(ctx context.Context, broker hub.Broker) error
- func (cli *ChatCLI) RunMCPProxyTool(ctx context.Context, name string, args json.RawMessage) (string, error)
- func (cli *ChatCLI) RunOnce(ctx context.Context, input string, disableAnimation bool, rawOutput bool) error
- func (cli *ChatCLI) RunSlashCommandRPC(ctx context.Context, line string) (string, error)
- func (cli *ChatCLI) SaveSessionRPC(name string, history []models.Message) error
- func (cli *ChatCLI) SearchSessionsRPC(query string) (string, error)
- func (cli *ChatCLI) SessionExistsRPC(name string) bool
- func (cli *ChatCLI) SessionModTimeRPC(name string) (time.Time, error)
- func (cli *ChatCLI) SetAuditSurface(surface string)
- func (cli *ChatCLI) SetMCPToolsObserver(fn func())
- func (cli *ChatCLI) SetPolicyAutoMode(on bool)
- func (cli *ChatCLI) SetRPCDangerPolicy(block bool)
- func (cli *ChatCLI) SetUnattended(v bool)
- func (cli *ChatCLI) SetWatching(active bool, statusFunc func() string)
- func (cli *ChatCLI) SkillContentRPC(name string) (string, error)
- func (cli *ChatCLI) Start(ctx context.Context)
- func (cli *ChatCLI) StartHubResume(ctx context.Context, principal string) func()
- func (cli *ChatCLI) StartWatcher(ctx context.Context, cfg k8s.WatchConfig) error
- func (cli *ChatCLI) StopWatcher()
- type CommandBlock
- type CommandContextInfo
- type CommandHandler
- type CommandOutput
- type CompactConfig
- type CompactReport
- type CompactStage
- type ContextEngine
- type ContextHandler
- type CostTracker
- func (ct *CostTracker) BudgetBlocked() bool
- func (ct *CostTracker) BudgetHardStopEnabled() bool
- func (ct *CostTracker) BudgetMessage() string
- func (ct *CostTracker) CacheStats() CacheStats
- func (ct *CostTracker) CheckBudget() BudgetLevel
- func (ct *CostTracker) CompactionStats() (total, level3 int, costUSD float64)
- func (ct *CostTracker) ContextEditStats() (edits, toolUses int, tokens int64)
- func (ct *CostTracker) CurrentSessionID() string
- func (ct *CostTracker) DailyBudget() (spentUSD, limitUSD float64)
- func (ct *CostTracker) DailySpend() (spent, limit float64)
- func (ct *CostTracker) EmbeddingStats() (calls int, tokens int64, costUSD float64)
- func (ct *CostTracker) EstimateAndRecord(provider, model string, inputChars, outputChars int)
- func (ct *CostTracker) FlushDailySpend()
- func (ct *CostTracker) GetSummary(provider, model string, history int) stringdeprecated
- func (ct *CostTracker) MemoryStats() (calls int, costUSD float64)
- func (ct *CostTracker) NoteExpectedCacheRebuild()
- func (ct *CostTracker) RecordCacheStorage(ev llmclient.CacheResourceEvent)
- func (ct *CostTracker) RecordCompaction(rep CompactReport)
- func (ct *CostTracker) RecordContextEdits(clearedToolUses, clearedInputTokens int)
- func (ct *CostTracker) RecordEmbeddingUsage(provider string, chars int)
- func (ct *CostTracker) RecordFromHistory(provider, model string, history []interface{ ... })
- func (ct *CostTracker) RecordMemoryUsage(provider, model string, usage *models.UsageInfo)
- func (ct *CostTracker) RecordRealUsage(provider, model string, usage *models.UsageInfo)
- func (ct *CostTracker) RecordUsage(provider, model string, promptTokens, completionTokens int)
- func (ct *CostTracker) ReloadBudget()
- func (ct *CostTracker) RemainingTaskBudgetTokens() (int, bool)
- func (ct *CostTracker) RemainingTaskBudgetTokensFor(provider, model string) (int, bool)
- func (ct *CostTracker) Reset()
- func (ct *CostTracker) RestoreSession(sessionID string) error
- func (ct *CostTracker) SaveSession() error
- func (ct *CostTracker) SetSessionName(name string)
- func (ct *CostTracker) Snapshot() SessionCostData
- func (ct *CostTracker) TakeBudgetTransition() (BudgetLevel, string, bool)
- func (ct *CostTracker) TakeCacheMissAlert() bool
- func (ct *CostTracker) TotalCost() float64
- func (ct *CostTracker) TotalTokens() int64
- type EnvRedactMode
- type EnvRedactor
- type ExecutionProfile
- type FileChunk
- type HistoryCompactor
- func (hc *HistoryCompactor) CharBudget(cfg CompactConfig) int
- func (hc *HistoryCompactor) Compact(ctx context.Context, history []models.Message, llmClient client.LLMClient, ...) ([]models.Message, error)
- func (hc *HistoryCompactor) LastReport() CompactReport
- func (hc *HistoryCompactor) NeedsCompaction(history []models.Message, cfg CompactConfig) bool
- func (hc *HistoryCompactor) SetCompressionLayer(l *compress.Layer)
- func (hc *HistoryCompactor) SetStatusCallback(cb StatusCallback)
- type HistoryManager
- type HubClient
- type HubSync
- type InteractionState
- type Logger
- type MessageTrimmer
- type ModelUsageRecord
- type MultilineBuffer
- type Options
- type PersonaHandler
- func (h *PersonaHandler) AttachAgent(name string)
- func (h *PersonaHandler) DetachAgent(name string)
- func (h *PersonaHandler) GetManager() *persona.Manager
- func (h *PersonaHandler) HandleCommand(userInput string)
- func (h *PersonaHandler) ListAgents()
- func (h *PersonaHandler) ListSkills()
- func (h *PersonaHandler) LoadAgent(name string)
- func (h *PersonaHandler) ShowActive(full bool)
- func (h *PersonaHandler) ShowAgentStatus()
- func (h *PersonaHandler) ShowAttachedAgents()
- func (h *PersonaHandler) ShowHelp()
- func (h *PersonaHandler) UnloadAgent()
- func (h *PersonaHandler) UnloadAllAgents()
- type RPCChatOpts
- type RPCChatTurn
- type RPCMCPToolInfo
- type RPCResourceContent
- type RPCResourceInfo
- type RPCRunOpts
- type RPCSkillInfo
- type RPCToolInfo
- type SessionCostData
- type SessionData
- type SessionEncryptor
- type SessionManager
- func (sm *SessionManager) CleanExpiredMachineSessions() int
- func (sm *SessionManager) CleanExpiredSessions() int
- func (sm *SessionManager) DeleteSession(name string) error
- func (sm *SessionManager) ForkCurrentToNew(newName string, sd *SessionData) error
- func (sm *SessionManager) ForkSession(sourceName, newName string) error
- func (sm *SessionManager) GetSessionMessages(name string, offset, limit int) ([]models.Message, int, error)
- func (sm *SessionManager) LatestSessionInfo() (name string, saved time.Time, title string)
- func (sm *SessionManager) ListSessions() ([]string, error)
- func (sm *SessionManager) LoadSession(name string) ([]models.Message, error)
- func (sm *SessionManager) LoadSessionV2(name string) (*SessionData, error)
- func (sm *SessionManager) PruneSessionsByPrefix(prefix string, keep int) int
- func (sm *SessionManager) SaveSession(name string, history []models.Message) error
- func (sm *SessionManager) SaveSessionV2(name string, sd *SessionData) error
- func (sm *SessionManager) SearchSessions(query string, maxSnippetsPerSession int) ([]SessionSearchHit, error)
- func (sm *SessionManager) SessionExists(name string) bool
- func (sm *SessionManager) SessionModTime(name string) (time.Time, error)
- func (sm *SessionManager) SessionTitles() map[string]string
- type SessionSearchHit
- type SkillClientResolution
- type SkillHandler
- func (sh *SkillHandler) GetPinnedSkills() []*persona.Skill
- func (sh *SkillHandler) HandleCommand(ctx context.Context, userInput string)
- func (sh *SkillHandler) Info(ctx context.Context, name string, fromRegistry string)
- func (sh *SkillHandler) Install(ctx context.Context, name string, fromRegistry string)
- func (sh *SkillHandler) IsPinned(name string) bool
- func (sh *SkillHandler) List()
- func (sh *SkillHandler) Pin(name string)
- func (sh *SkillHandler) PinnedNames() []string
- func (sh *SkillHandler) Prefer(args []string)
- func (sh *SkillHandler) Search(ctx context.Context, query string)
- func (sh *SkillHandler) SetRegistryEnabled(name string, enabled bool)
- func (sh *SkillHandler) ShowHelp()
- func (sh *SkillHandler) ShowPinned()
- func (sh *SkillHandler) ShowRegistries()
- func (sh *SkillHandler) Uninstall(name string)
- func (sh *SkillHandler) Unpin(name string)
- type SlashToolEntry
- type SourceType
- type StatusCallback
Constants ¶
const ( SourceTypeUserInput = agent.SourceTypeUserInput SourceTypeFile = agent.SourceTypeFile SourceTypeCommandOutput = agent.SourceTypeCommandOutput )
Constantes re-exportadas
const ( StateNormal InteractionState = iota StateSwitchingProvider StateProcessing StateAgentMode ProfileNormal ExecutionProfile = iota ProfileAgent ProfileCoder )
Interaction states and execution profiles (iota block shared for legacy reasons; the integer values never cross paths in use).
const ( ColorReset = "\033[0m" ColorGreen = "\033[32m" ColorLime = "\033[92m" ColorCyan = "\033[36m" ColorGray = "\033[90m" ColorPurple = "\033[35m" ColorBold = "\033[1m" ColorYellow = "\033[33m" ColorRed = "\033[31m" ColorBlue = "\033[34m" )
ANSI Color Codes
Legacy path: these hue constants are the legacy color path. New and migrated code styles through semantic roles instead — kit.Colorize / kit.Style with a theme.Role — so the theme-swap contract lives in one place. The constants stay (they are load-bearing across many call sites and theme.Recolor keeps them themable) but should not gain new callers.
const ( // MemoryProviderEnv selects the memory provider: builtin (default) // or mcp:<server>. MemoryProviderEnv = "CHATCLI_MEMORY_PROVIDER" // ContextEngineEnv selects the context engine: builtin (default) or // mcp:<server>. ContextEngineEnv = "CHATCLI_CONTEXT_ENGINE" )
const ( ModeChat = "chat" ModeAgent = "/agent" ModeCoder = "/coder" )
Mode names match the canonical `[ACTIVE MODE: <name>]` markers we embed at the top of every system prompt. Anything that doesn't match is treated as a non-mode system message and left alone.
const AgentFormatInstructions = `
[ACTIVE MODE: /agent]
You are operating inside ChatCLI's /agent mode, supervised plan-and-execute on the user's terminal. Each suggested action goes through an interactive menu before running. Stay strictly within the format below.
[FORMAT — /AGENT]
PROCESS:
1. <reasoning> (step-by-step thought).
2. <explanation> (what the commands will do).
3. Actions — either ` + "```execute:<type>```" + ` blocks (types: shell, git, docker, kubectl) or <tool_call name="@tool" args="..." /> for plugins.
RULES:
- Security: NEVER suggest destructive commands (rm -rf, dd, mkfs) without an explicit warning in <explanation>.
- Clarity: prefer easy-to-understand commands; explain the complex ones briefly.
- Efficiency: combine with pipes when it actually reduces turns.
- Parallelism: batch all independent tool_calls/agent_calls in ONE response. Use <agent_call> when there are 3+ independent tasks.
- Interactivity: avoid vim/nano etc. If unavoidable, suffix the command with #interactive.
- Ambiguous request: ask before acting, no execute blocks.
`
AgentFormatInstructions contains format instructions for /agent mode (used when a persona is active - combined with persona + these instructions). Same lean pattern as CoderFormatInstructions above.
const AuditLogPathEnv = "CHATCLI_AUDIT_LOG_PATH"
AuditLogPathEnv is shared with the gRPC audit logger: one file, one format, both surfaces.
const ChatModeSystemHint = `` /* 934-byte string literal not displayed */
ChatModeSystemHint is prepended to the system prompt when the user is in the default conversational (chat) mode — i.e. NOT inside /agent or /coder. It prevents the AI from emitting execute blocks, tool_call tags, or any command-execution syntax that would be silently ignored by the chat handler.
const CoderFormatInstructions = `
[ACTIVE MODE: /coder]
You are operating inside ChatCLI's /coder mode, supervised plan-and-execute. The user can approve, deny, or roll back every action. Stay strictly within the format below.
[FORMAT — /CODER]
RESPONSE: <reasoning> (2-6 lines, numbered task list, [✓] done) → one or more <tool_call name="@coder" args='{"cmd":"SUBCOMMAND","args":{...}}' />.
RULES:
- @coder tools only (no ` + "```" + ` code blocks). JSON args on a SINGLE line; wrap with single quotes. No backslash escapes.
- Multiline content in write/patch → base64 encoding.
- Parallelism: emit ALL independent tool_calls in ONE response. Sequential only when the next call depends on the previous result. Prefer <agent_call> for 3+ independent tasks.
- No narration ("Let me…", "Now I'll…"). Call tools directly. Final text only: 1-3 sentences summarizing WHAT changed.
- If info is missing that only the user can provide, STOP — write one clear question, emit NO tool_calls.
EXAMPLES:
<tool_call name="@coder" args='{"cmd":"read","args":{"file":"main.go"}}' />
<tool_call name="@coder" args='{"cmd":"search","args":{"term":"TODO","dir":"./src","glob":"*.go"}}' />
<tool_call name="@coder" args='{"cmd":"exec","args":{"cmd":"go test ./..."}}' />
<tool_call name="@coder" args='{"cmd":"patch","args":{"file":"f.go","search":"old","replace":"new"}}' />
SUBCOMMANDS: read, write, patch, tree, search, exec, git-status, git-diff, git-log, git-changed, git-branch, test, rollback, clean, delegate.
OTHER TOOLS:
- @webfetch: <tool_call name="@webfetch" args='{"url":"https://..."}' /> (bodies >~10KB auto-save; use filter/from_line for scoping)
- @websearch: <tool_call name="@websearch" args='{"query":"..."}' />
- MCP tools: <tool_call name="mcp_toolname" args='{"param":"value"}' />
`
CoderFormatInstructions contains ONLY the format instructions for /coder mode (used when a persona is active - combined with persona + these instructions). Kept lean because it is re-sent every turn on top of the active persona prompt.
const CoderSystemPrompt = `[ACTIVE MODE: /coder]
You are a senior software engineer operating in ChatCLI's /coder mode — supervised plan-and-execute on the user's terminal. Every action you suggest goes through a security gate before running. Stay strictly within the response format below.
## RESPONSE FORMAT (mandatory)
1. Start with <reasoning> (2-6 lines): analysis + numbered task list; mark done with [✓]. On error, replan.
2. Emit one or more <tool_call name="@coder" args='{"cmd":"SUBCOMMAND","args":{...}}' /> — args MUST be a single line of JSON.
Alternative CLI syntax also works: <tool_call name="@coder" args="read --file main.go --start 1 --end 50" />
## @coder SUBCOMMANDS
read, write, patch, tree, search, exec, git-status, git-diff, git-log, git-changed, git-branch, test, rollback, clean, delegate.
## EXAMPLES (copy the shape, not the values)
<tool_call name="@coder" args='{"cmd":"read","args":{"file":"main.go","start":10,"end":50}}' />
<tool_call name="@coder" args='{"cmd":"search","args":{"term":"Login","dir":".","glob":"*.go"}}' />
<tool_call name="@coder" args='{"cmd":"exec","args":{"cmd":"go test ./...","dir":"."}}' />
<tool_call name="@coder" args='{"cmd":"git-diff","args":{"staged":true}}' />
Writing / patching:
- Multiline content → encode as base64: args='{"cmd":"write","args":{"file":"x.go","content":"BASE64","encoding":"base64"}}'
- Single-line content → plain string is fine.
- patch: provide "search" (must be unique in the file) and "replace". For diffs: {"diff":"BASE64","diff-encoding":"base64"}.
- Always read the file before patching it.
## RULES
1. Tools only: NEVER use ` + "```" + ` code blocks in lieu of <tool_call>. Shell commands go through ` + "`" + `exec` + "`" + `.
2. Args on a SINGLE line. Use single quotes around the JSON: args='{...}'. Never escape with backslashes.
3. Parallelism: emit ALL independent tool_calls in ONE response. Three reads → three <tool_call> tags together, not three turns. When <agent_call> is offered, prefer it for 3+ independent tasks.
4. Sequential only when a call depends on the previous result.
5. Fail-fast: a failing tool stops the batch.
6. Need info only the user can provide (role name, choice, ambiguous path)? STOP — write one clear question, no tool_calls. The system waits for the reply.
## NO NARRATION
No "Let me…", "I will…", "Now I'll…". Call tools directly after <reasoning>. Output text only for the final 1-3 sentence summary ("what changed", not "what I did"). If blocked, state it in one line.
## DELEGATE FOR BIG PAYLOADS
When a tool would dump a huge response (metrics scrape, verbose logs, exhaustive search) and you only need the gist, delegate:
<tool_call name="@coder" args='{"cmd":"delegate","args":{"description":"analyze metrics","prompt":"Return the top 3 memory hotspots with numbers.","tools":["read","search","tree"],"read_only":true}}' />
Keep read_only=true unless the subagent MUST write/exec. Narrow the tools allowlist. Spell out the expected output format.
## OTHER TOOLS (registered plugins)
Use the best tool for the job, not only @coder:
- @webfetch: <tool_call name="@webfetch" args='{"url":"https://..."}' /> — fetch web pages (HTML stripped). Bodies >~10KB auto-save to disk; use filter/from_line for scoping.
- @websearch: <tool_call name="@websearch" args='{"query":"..."}' />
- MCP tools: <tool_call name="mcp_toolname" args='{"param":"value"}' />
`
CoderSystemPrompt is the complete system prompt for /coder mode (used when NO persona is active). Written in English for maximum AI compliance across all model families.
Token budget: this prompt is re-sent on every agent turn (cached via SystemParts + Anthropic cache_control, but still counted by providers without prompt caching). Keep it dense: every rule here must earn its place. Prefer one crisp example over three verbose ones.
const CompactModelEnv = "CHATCLI_COMPACT_MODEL"
CompactModelEnv names the provider:model that serves Level 2 structured summaries. Empty keeps the session client (legacy behavior).
const GatewayLanguageDirective = `` /* 334-byte string literal not displayed */
GatewayLanguageDirective replaces the daemon-locale "respond in X" pin on the gateway path. A messaging gateway serves many users in many languages, so the reply must follow each incoming message rather than a fixed locale. English (instruction to the model), prominent header like the locale directive it replaces, and applied on every gateway path so language is never static.
const GatewayMaxTenantsEnv = "CHATCLI_GATEWAY_MAX_TENANTS"
GatewayMaxTenantsEnv caps how many tenant store sets stay resident; least recently used sets are released (their memory worker stopped) past the cap and rebuilt from disk on the next turn.
const GatewayMemoryDirective = `` /* 833-byte string literal not displayed */
GatewayMemoryDirective is appended to the gateway core prompt (like GatewayLanguageDirective) so the daemon treats the injected Memory Index as real knowledge about the user instead of answering personal questions as a stranger. A separate composable directive rather than an edit to GatewaySystemPrompt: directives evolve independently of the base persona.
const GatewaySystemPrompt = `` /* 2366-byte string literal not displayed */
GatewaySystemPrompt is the system prompt used when the coder engine answers through the messaging gateway (Telegram/WhatsApp/Discord/Slack/webhook). It keeps the full tool-use mechanics of /coder but replaces the terse "senior engineer / no narration / plan-execute" framing with a conversational assistant voice — because here the final prose IS the chat message the user reads, not a commit summary. English for cross-model compliance, like CoderSystemPrompt.
const KnowledgeRerankEnv = "CHATCLI_KNOWLEDGE_RERANK"
KnowledgeRerankEnv selects the knowledge rerank stage (off|mmr|llm).
const (
// TranscriptEnv disables the journal when set to false.
TranscriptEnv = "CHATCLI_SESSION_TRANSCRIPT"
)
Variables ¶
var CommandFlags = map[string]map[string][]prompt.Suggest{
"@file": {
"--mode": {
{Text: "full", Description: "Processa o conteúdo completo (padrão, trunca se necessário)"},
{Text: "summary", Description: "Gera resumo estrutural (árvore de arquivos, tamanhos, sem conteúdo)"},
{Text: "chunked", Description: "Divide grandes projetos em pedaços gerenciáveis (use /nextchunk para prosseguir)"},
{Text: "smart", Description: "Seleciona arquivos relevantes com base no seu prompt (IA decide)"},
},
},
"@command": {
"-i": {},
"--ai": {},
},
"/session": {
"new": {},
"save": {},
"load": {},
"list": {},
"delete": {},
},
"/context": {
"create": {},
"attach": {},
"detach": {},
"list": {},
"delete": {},
"show": {},
"merge": {},
"attached": {},
"export": {},
"import": {},
"metrics": {},
"help": {},
},
"/connect": {
"--token": {},
"--provider": {},
"--model": {},
"--llm-key": {},
"--use-local-auth": {},
"--tls": {},
"--ca-cert": {},
"--client-id": {},
"--client-key": {},
"--realm": {},
"--agent-id": {},
"--ollama-url": {},
},
"/agent": {
"list": {},
"load": {},
"attach": {},
"detach": {},
"skills": {},
"show": {
{Text: "--full", Description: "Mostra detalhes completos do agente"},
},
"status": {},
"off": {},
"help": {},
},
}
CommandFlags declares the completer suggestions for the flag layer of every supported slash / @ command. See cli_completer.go for the top-level suggestion list.
var ErrSessionSchemaNewer = errors.New("session schema newer than this build")
ErrSessionSchemaNewer marks a session file written by a newer ChatCLI.
Functions ¶
func AgentMaxTurns ¶ added in v1.41.1
func AgentMaxTurns() int
func DetectPromptInjection ¶ added in v1.97.0
DetectPromptInjection scans text for common prompt injection patterns. Returns (detected, list of matched patterns).
func FormatPayloadSize ¶ added in v1.104.0
FormatPayloadSize returns a human-readable size for display.
func FormatVersionReport ¶ added in v1.172.0
FormatVersionReport renderiza o card completo de versão. Exportada para o main (flag -v/--version) compartilhar exatamente a mesma saída do /version.
func HasStdin ¶ added in v1.16.1
func HasStdin() bool
Detecta se há dados no stdin (pipe/arquivo ao invés de TTY).
func IsEncrypted ¶ added in v1.97.0
IsEncrypted checks if data starts with the encrypted session magic header.
func LocalHubPrincipal ¶ added in v1.123.0
func LocalHubPrincipal() string
LocalHubPrincipal returns the shared principal from env/default (no db layer). Used where no store is at hand; store-backed resolution uses resolveHubPrincipal.
func NewSlashToolPlugin ¶ added in v1.118.0
func NewSlashToolPlugin(entry *SlashToolEntry) plugins.Plugin
NewSlashToolPlugin wraps the entry. Returns nil for nil input so callers can pass the result of LookupSlashTool unchecked.
func ParsePayloadSize ¶ added in v1.104.0
ParsePayloadSize accepts human-friendly size strings and returns bytes. A bare number is interpreted as MB (the most common unit users think in for proxy caps). Explicit suffixes: B, KB/K, MB/M, GB/G (case insensitive, whitespace tolerated: "5 MB" works). Returns 0 for any non-positive or unparseable input.
func PreprocessArgs ¶ added in v1.16.2
PreprocessArgs normaliza o caso de -p/--prompt sem valor, convertendo para -p= / --prompt= Ex.: echo "msg" | chatcli -p -> trata como prompt vazio + stdin (não quebra o flag parser)
func RegisterSlashTool ¶ added in v1.118.0
func RegisterSlashTool(entry *SlashToolEntry)
RegisterSlashTool adds an entry to the registry. Idempotent: a second registration with the same Name overwrites the first.
func ResetManagerHooksForTest ¶ added in v1.196.1
func ResetManagerHooksForTest()
ResetManagerHooksForTest clears the registered hooks. Test-only.
func ResetProjectEnvOnceForTest ¶ added in v1.196.1
func ResetProjectEnvOnceForTest()
ResetProjectEnvOnceForTest re-arms the one-shot overlay. Test-only.
func RunUpdateOneShot ¶ added in v1.191.0
RunUpdateOneShot é a superfície one-shot do /update (`chatcli update`), para scripts e automação: mesmo fluxo, mesma saída, sem boot do REPL. O erro devolvido vira exit code no main — nil cobre "atualizado" e "já na última versão"; falha de checagem, canal manual com update pendente e falha de aplicação retornam o erro já impresso.
func RunUpdateSubcommand ¶ added in v1.191.0
RunUpdateSubcommand é o corpo do subcomando `chatcli update [check]`: parseia os args e mapeia o desfecho no exit code do processo — 0 atualizado ou já na última versão (check incluso), 1 falha de checagem/aplicação ou canal manual com update pendente, 2 uso inválido. Vive no pacote cli (e não no main) para o contrato ficar sob teste; o main só faz o boot e repassa.
func SanitizeCommandOutput ¶ added in v1.97.0
SanitizeCommandOutput wraps command output with delimiters, enforces size limits, and detects potential prompt injection attempts.
func SweepStaleParks ¶ added in v1.112.0
SweepStaleParks deletes snapshots whose CreatedAt is older than the cutoff. Returns the count removed and any per-file errors. Suitable for a background goroutine; we don't wire one yet but expose the helper so /parked gc can call it on demand.
func TurnCacheHitPct ¶ added in v1.196.0
TurnCacheHitPct is the per-turn figure for the envelope footer. Returns ok=false when the usage carries no cache fields.
func UpdateSubcommandMain ¶ added in v1.191.0
UpdateSubcommandMain é o entrypoint completo do subcomando `chatcli update`: boot mínimo (dotenv+i18n+tema+logger+config — sem LLM manager) seguido do contrato de exit code de RunUpdateSubcommand. Vive no pacote cli para boot e contrato ficarem sob teste — no main resta apenas o os.Exit.
Types ¶
type ACPCommandInfo ¶ added in v1.173.0
type ACPCommandInfo struct {
Name string // without the leading slash (ACP convention)
Description string
InputHint string
}
ACPCommandInfo describes one slash command advertised to ACP clients.
type AgentMode ¶
type AgentMode struct {
// contains filtered or unexported fields
}
AgentMode representa a funcionalidade de agente autônomo no ChatCLI
func NewAgentMode ¶
NewAgentMode cria uma nova instância do modo agente
func (*AgentMode) InjectedSkillNames ¶ added in v1.177.0
InjectedSkillNames returns a sorted snapshot of every skill name the current Run() has delivered to the model. Consumers: the park snapshot and the scheduler adapter (so a job scheduled mid-run inherits the creating run's skills).
func (*AgentMode) Run ¶
func (a *AgentMode) Run(ctx context.Context, query string, additionalContext string, systemPromptOverride string) error
Run inicia o modo agente com uma consulta do usuário, utilizando um loop de Raciocínio-Ação (ReAct). Agora aceita systemPromptOverride para definir personas específicas (ex: Coder).
func (*AgentMode) RunResumed ¶ added in v1.112.0
func (a *AgentMode) RunResumed(ctx context.Context, snap *park.Snapshot, outcome, detail string) error
RunResumed re-enters the agent loop using a previously-saved snapshot. It is idempotent on token: a Resume that lost the race against a /cancel-park finds a missing snapshot and returns ErrSnapshotNotFound, which the caller renders as a no-op.
outcome and detail come from the AgentResume action payload. They are woven into the synthetic tool-result message so the LLM sees:
[park completed] outcome=matched detail=<probe response>
type AnimationManager ¶
type AnimationManager struct {
// contains filtered or unexported fields
}
func NewAnimationManager ¶
func NewAnimationManager() *AnimationManager
func (*AnimationManager) SetSuppressed ¶ added in v1.65.5
func (am *AnimationManager) SetSuppressed(v bool)
SetSuppressed enables or disables animation suppression. When suppressed, ShowThinkingAnimation stores the message but does not start the spinner goroutine. This prevents the animation from conflicting with go-prompt's rendering.
func (*AnimationManager) ShowThinkingAnimation ¶
func (am *AnimationManager) ShowThinkingAnimation(message string)
ShowThinkingAnimation inicia ou atualiza a animação "pensando"
func (*AnimationManager) StopThinkingAnimation ¶
func (am *AnimationManager) StopThinkingAnimation()
StopThinkingAnimation para a animação de forma segura
func (*AnimationManager) UpdateMessage ¶
func (am *AnimationManager) UpdateMessage(message string)
UpdateMessage atualiza a mensagem sem parar e reiniciar a animação
type AuditChainReport ¶ added in v1.196.0
type AuditChainReport struct {
Entries int
Chained int // entries carrying a hash
Legacy int // entries written before the chain existed
BrokenAt int // 1-based line of the first break (0 = intact)
Err string
// Sealed counts entries stored encrypted; Torn flags an incomplete
// last line (a crash mid-write, not tampering); RotatedFrom names the
// file this trail continues when it starts mid-chain.
Sealed int
Torn bool
RotatedFrom string
}
AuditChainReport is the outcome of VerifyAuditChain.
func VerifyAuditChain ¶ added in v1.196.0
func VerifyAuditChain(path string) (AuditChainReport, error)
VerifyAuditChain re-hashes a trail and reports the first line whose hash or previous-hash link does not match. Version-1 lines (written before the shared chain writer) verify with the struct-order hash.
func (AuditChainReport) Intact ¶ added in v1.196.0
func (r AuditChainReport) Intact() bool
Intact reports whether every chained entry verified.
type BudgetLevel ¶ added in v1.99.0
type BudgetLevel int
BudgetLevel indicates how close the session is to its spending limit.
const ( // BudgetOK indicates spending is within normal limits. BudgetOK BudgetLevel = iota // BudgetWarning indicates spending has reached the warning threshold. BudgetWarning // BudgetExceeded indicates spending has exceeded the configured limit. BudgetExceeded )
type CacheStats ¶ added in v1.196.0
type CacheStats struct {
Requests int
Misses int
Rebuilds int
HitPct float64 // share of input served from cache, 0-100
LastActivity time.Time
TTL string // "5m" or "1h"
Warm bool // last activity within the TTL
}
CacheStats is the read model /cost and the envelope footer render.
func (CacheStats) Reported ¶ added in v1.196.0
func (s CacheStats) Reported() bool
Reported is true when at least one request carried cache fields.
type ChatCLI ¶
type ChatCLI struct {
Client client.LLMClient
Provider string
Model string
UserMaxTokens int
// K8s watcher context injection
WatcherContextFunc func() string // returns K8s context to prepend to LLM prompts
// contains filtered or unexported fields
}
ChatCLI representa a interface de linha de comando do chat
func NewChatCLI ¶
func NewChatCLI(ctx context.Context, manager manager.LLMManager, logger *zap.Logger) (*ChatCLI, error)
NewChatCLI cria uma nova instância de ChatCLI
func (*ChatCLI) ApplyOverrides ¶ added in v1.16.0
func (*ChatCLI) ApplyProjectEnv ¶ added in v1.196.1
func (cli *ChatCLI) ApplyProjectEnv(dir string) (manager.LLMManager, config.ProjectDotenvReport)
ApplyProjectEnv layers <dir>/.env over the process environment and, when that actually contributed variables, rebuilds the LLM manager so providers the project unlocked (a per-repository AWS_PROFILE, a provider key) become available. Returns the rebuilt manager, or nil when nothing changed.
It never runs while an operation is in flight: swapping the manager under a running prompt would race the client it is already using.
func (*ChatCLI) CancelOperation ¶ added in v1.22.0
func (cli *ChatCLI) CancelOperation()
CancelOperation cancela a operação atual se houver uma
func (*ChatCLI) CleanExpiredMachineSessionsRPC ¶ added in v1.165.0
CleanExpiredMachineSessionsRPC applies the machine-session TTL. Called by the MCP/ACP server at boot so long-running daemons get the same bounded lifecycle the REPL applies on start.
func (*ChatCLI) DeleteSessionRPC ¶ added in v1.161.0
DeleteSessionRPC removes a saved session, validating the name first.
func (*ChatCLI) EnableHubSync ¶ added in v1.123.0
EnableHubSync wires a connected CLI to the shared conversation hub. Call it after setting cli.Client to the remote client and before Start.
func (*ChatCLI) ExpandSlashCommandRPC ¶ added in v1.184.0
ExpandSlashCommandRPC is the remote-surface twin of the REPL dispatch: ACP prompts and MCP chat turns call it to resolve a "/name args" input into the expanded prompt. Always non-interactive — the pre-exec gate resolves through policy/automode, never a terminal prompt.
func (*ChatCLI) FinalizeSpend ¶ added in v1.196.0
finalizeSpend persists the session's cost snapshot and daily spend and releases provider cache resources (Gemini explicit caches bill storage per hour). The REPL runs it from cleanup; one-shot, the gateway daemon and the MCP/ACP servers call it on their own exit so no surface leaves spend unsaved or a paid cache lingering. FinalizeSpend is finalizeSpend for the command layer (rpcserve exits).
func (*ChatCLI) ForkSessionRPC ¶ added in v1.163.0
ForkSessionRPC copies a saved session under a new name, validating both names first — this surface is reachable by remote MCP clients.
func (*ChatCLI) GetContextCommands ¶ added in v1.37.0
GetContextCommands retorna a lista de sugestões para comandos com @
func (*ChatCLI) GetInternalCommands ¶ added in v1.37.0
func (*ChatCLI) HandleOneShotOrFatal ¶ added in v1.16.3
HandleOneShotOrFatal executa o modo one-shot se solicitado (flag -p usada ou stdin presente). - Em caso de erro, imprime mensagem em Markdown (stderr) e faz logger.Fatal (sem fallback). - Retorna true se o one-shot foi tratado (com sucesso ou erro fatal). Retorna false se não foi acionado.
func (*ChatCLI) IsACPCommandAllowed ¶ added in v1.173.0
IsACPCommandAllowed reports whether a slash token (with leading slash) is runnable headless over ACP.
func (*ChatCLI) IsExecuting ¶ added in v1.22.0
IsExecuting retorna true se uma operação está em andamento
func (*ChatCLI) ListACPCommands ¶ added in v1.173.0
func (cli *ChatCLI) ListACPCommands() []ACPCommandInfo
ListACPCommands returns the commands advertised to ACP clients: the three mode switches plus the headless allowlist, with the palette registry's localized summaries and each command's real subcommands as its input hint.
func (*ChatCLI) ListAllRPCTools ¶ added in v1.158.0
func (cli *ChatCLI) ListAllRPCTools() []RPCToolInfo
ListAllRPCTools returns every plugin the exposure policy admits.
func (*ChatCLI) ListCommandPromptsRPC ¶ added in v1.184.0
ListCommandPromptsRPC exposes the catalog to the MCP prompts primitive.
func (*ChatCLI) ListMCPProxyTools ¶ added in v1.161.0
func (cli *ChatCLI) ListMCPProxyTools() []RPCMCPToolInfo
ListMCPProxyTools returns every tool discovered from connected MCP servers that the exposure policy admits (visibility masks from EnabledTools/ DisabledTools already honored by VisibleTools). Sorted by name. Waits, bounded, for the initial connect pass so an early listing doesn't miss the aggregated catalog.
func (*ChatCLI) ListRPCResources ¶ added in v1.163.0
func (cli *ChatCLI) ListRPCResources() []RPCResourceInfo
ListRPCResources enumerates the exported resources. Dynamic entries (contexts, knowledge bases, skills, sessions) are listed individually so an MCP client can browse them without knowing names in advance.
func (*ChatCLI) ListSessionsRPC ¶ added in v1.161.0
ListSessionsRPC returns the saved session names.
func (*ChatCLI) ListSkillsRPC ¶ added in v1.158.0
func (cli *ChatCLI) ListSkillsRPC() []RPCSkillInfo
ListSkillsRPC returns the installed skill catalog.
func (*ChatCLI) LoadSessionRPC ¶ added in v1.161.0
LoadSessionRPC returns a saved session's chat history. The name is validated before touching the store — this surface is reachable by remote MCP clients.
func (*ChatCLI) MCPStartupDone ¶ added in v1.161.0
func (cli *ChatCLI) MCPStartupDone() <-chan struct{}
MCPStartupDone returns a channel closed once the initial StartAll pass over the configured MCP servers has finished (regardless of per-server success). When MCP is disabled the channel is already closed, so callers can always select on it.
func (*ChatCLI) OnManagerRebuild ¶ added in v1.196.1
func (cli *ChatCLI) OnManagerRebuild(fn func(manager.LLMManager))
OnManagerRebuild registers a hook fired after every manager rebuild.
func (*ChatCLI) PolicyAutoMode ¶ added in v1.181.0
PolicyAutoMode reports whether the session is in policy automode ("ask" verdicts auto-approve). Safe for concurrent use: toggled from command surfaces while the agent loop reads it.
func (*ChatCLI) PolicyModeLabel ¶ added in v1.181.0
PolicyModeLabel returns the localized label of the current session mode.
func (*ChatCLI) PrintWelcomeScreen ¶ added in v1.18.0
func (cli *ChatCLI) PrintWelcomeScreen()
PrintWelcomeScreen exibe a tela de boas-vindas completa e traduzida no tratamento sóbrio: logo, versão dim, dica sob régua titulada, linha do modelo ativo com o marcador ◆ e rodapé de comandos — tudo no grid de indentação 2, sem molduras.
func (*ChatCLI) ProvidersRPC ¶ added in v1.158.0
ProvidersRPC returns a JSON document describing the configured providers, the active provider/model, and each provider's models — the discovery surface for per-call routing. Models come from the same path the interactive picker uses (ListModelsForProvider: API listing when the provider supports it, merged and deduplicated with the catalog), fetched concurrently with a bounded timeout and a catalog fallback per provider.
func (*ChatCLI) PruneSessionsRPC ¶ added in v1.165.0
PruneSessionsRPC bounds a machine-session set (e.g. the mcp- mirrors) to the newest keep files. No-op when the store is unavailable.
func (*ChatCLI) ReadRPCResource ¶ added in v1.163.0
ReadRPCResource resolves one chatcli:// URI to its content.
func (*ChatCLI) RenderCommandPromptRPC ¶ added in v1.184.0
RenderCommandPromptRPC expands one command for MCP prompts/get. The pre-exec gate runs non-interactive (policy/automode or deny).
func (*ChatCLI) RotateHubThreadRPC ¶ added in v1.179.0
RotateHubThreadRPC rotates the shared cross-channel hub conversation to a fresh thread. The RPC /session handler calls it when a session's identity changes (load/new) so the old thread's backlog is not spliced on top.
func (*ChatCLI) RunAgentCaptured ¶ added in v1.123.0
RunAgentCaptured runs the full agent (ReAct) loop one-shot on task, capturing its transcript. Used by the MCP agent_task tool.
func (*ChatCLI) RunAgentFullOnce ¶ added in v1.163.0
RunAgentFullOnce runs the FULL agent ReAct loop one-shot on a raw task — the same engine, tools, skills and workspace context the interactive /agent command gets — exiting when the loop reaches its final answer. This is the agent-profile mirror of runCoderQuery, and the entry the MCP server's agent_task tool uses; the legacy single-call RunOnce path remains only for the CLI one-shot (-p "/agent …") whose auto-exec contract predates the loop.
func (*ChatCLI) RunAgentOnce ¶ added in v1.19.0
func (*ChatCLI) RunAgentRPC ¶ added in v1.158.0
RunAgentRPC runs the FULL agent (ReAct) loop with per-call options — the same engine, tools, skills and workspace context the interactive /agent command gets.
func (*ChatCLI) RunAgentStreaming ¶ added in v1.123.0
func (cli *ChatCLI) RunAgentStreaming(ctx context.Context, task string, emit func(string)) (string, error)
RunAgentStreaming runs the full agent (ReAct) loop one-shot on task, forwarding the agent's rendered progress to emit line by line as it works, and returning the full transcript. Used by the messaging gateway to narrate task execution back to the chat platform.
func (*ChatCLI) RunAnyRPCTool ¶ added in v1.158.0
RunAnyRPCTool invokes any policy-admitted plugin by name with a raw argument string (JSON envelope or flat args, exactly as the agent passes).
func (*ChatCLI) RunAnyRPCToolArgv ¶ added in v1.180.0
func (cli *ChatCLI) RunAnyRPCToolArgv(ctx context.Context, name string, argv []string) (string, error)
RunAnyRPCToolArgv is the argv-native entry: callers that already hold a real argv (the `chatcli tool` subcommand) pass it verbatim — joining and re-splitting would corrupt values containing whitespace.
func (*ChatCLI) RunChatTurnRPC ¶ added in v1.163.0
func (cli *ChatCLI) RunChatTurnRPC( ctx context.Context, sessionID, userInput string, history []models.Message, o RPCChatOpts, ) (RPCChatTurn, error)
RunChatTurnRPC runs ONE chat turn through the full interactive pipeline, headless. history is the session history owned by the caller; the returned RPCChatTurn.History is the compacted/extended history to store back.
func (*ChatCLI) RunCoderCaptured ¶ added in v1.123.0
RunCoderCaptured runs the coder loop one-shot on task, capturing output.
func (*ChatCLI) RunCoderOnce ¶ added in v1.42.0
RunCoderOnce executa o modo coder de forma não-interativa (one-shot), mas mantendo o loop ReAct do AgentMode (com tool_calls/plugins).
func (*ChatCLI) RunCoderRPC ¶ added in v1.158.0
RunCoderRPC runs the coder loop with per-call options.
func (*ChatCLI) RunGatewayCoderOnce ¶ added in v1.123.0
RunGatewayCoderOnce runs the coder ReAct loop one-shot on a raw task for the messaging gateway: same engine and tools (create/edit files, run commands, iterate) but with the gateway persona layered on the system prompt so the answer is concise, chat-friendly prose. The caller is expected to have set cli.unattended so every confirmation auto-approves — the gateway must never block on a stdin prompt the daemon has no way to answer.
func (*ChatCLI) RunGatewayCoderStreaming ¶ added in v1.123.0
func (cli *ChatCLI) RunGatewayCoderStreaming(ctx context.Context, task string, emit func(string)) (string, error)
RunGatewayCoderStreaming runs the coder ReAct loop one-shot on task with the gateway persona, forwarding the rendered progress to emit line by line and returning the full transcript. Used by the messaging gateway: it keeps the coder engine's full capability (create/edit files, run commands, iterate) while answering as concise chat prose. The clean final answer is captured into cli.lastAgentReply during the run.
func (*ChatCLI) RunGatewayForeground ¶ added in v1.123.0
RunGatewayForeground builds the configured adapters and runs the messaging runner in the foreground until ctx is canceled. It is the body of the detached `chatcli gateway` subcommand; the agent runs fully unattended. It opens its own hub database — durable and cross-channel, but live-tail push to a remote CLI only spans processes via DB-on-connect/resync. For real-time cross-process push, co-locate the gateway in the server via RunGatewayWithBroker (see CHATCLI_GATEWAY_IN_SERVER).
func (*ChatCLI) RunGatewayWithBroker ¶ added in v1.123.0
RunGatewayWithBroker runs the gateway sharing an existing hub broker (the gRPC server's). Because the fan-out Manager is in-memory, sharing one broker in a single process is what makes a Telegram message push live to a connected notebook in real time. The caller owns the broker's lifecycle.
func (*ChatCLI) RunMCPProxyTool ¶ added in v1.161.0
func (cli *ChatCLI) RunMCPProxyTool(ctx context.Context, name string, args json.RawMessage) (string, error)
RunMCPProxyTool executes one proxied MCP tool. name accepts both the prefixed ("mcp_list_regions") and bare ("list_regions") forms; args is the caller's raw MCP arguments object, forwarded verbatim to the origin server. A tool-level error result (isError) is surfaced as a Go error carrying the origin content, so the RPC layer relays it in-band per the MCP convention.
func (*ChatCLI) RunSlashCommandRPC ¶ added in v1.173.0
RunSlashCommandRPC executes one allowlisted slash command headless, capturing its stdout as the result. Mirrors the scheduler bridge's HandleCommand invocation: panic sentinels are flow-control, not crashes. Caller must have validated the command against the allowlist — mode switches (/agent, /coder, /run) never reach here.
func (*ChatCLI) SaveSessionRPC ¶ added in v1.161.0
SaveSessionRPC persists a chat history under name in the saved-session store (the same store the REPL /session command uses). Name validation is the store's own (alphanumeric with dash/underscore/dot).
func (*ChatCLI) SearchSessionsRPC ¶ added in v1.163.0
SearchSessionsRPC runs the full-text search across the saved-session store and renders the hits compactly (session name, match count, snippets) for a model-facing tool result.
func (*ChatCLI) SessionExistsRPC ¶ added in v1.179.0
SessionExistsRPC reports whether a saved session exists in the store.
func (*ChatCLI) SessionModTimeRPC ¶ added in v1.179.0
SessionModTimeRPC returns the store mtime of a saved session — the freshness signal the RPC backend's bound sessions use to adopt writes made by other surfaces (REPL, gateway, another server) before a turn.
func (*ChatCLI) SetAuditSurface ¶ added in v1.196.0
SetAuditSurface names the process role on every audit line from now on.
func (*ChatCLI) SetMCPToolsObserver ¶ added in v1.161.0
func (cli *ChatCLI) SetMCPToolsObserver(fn func())
SetMCPToolsObserver registers fn to run whenever the MCP tool catalog changes (servers connecting, dynamic list_changed refreshes, disconnects). No-op when MCP is disabled. The RPC server uses it to relay notifications/tools/list_changed to its own clients.
func (*ChatCLI) SetPolicyAutoMode ¶ added in v1.181.0
SetPolicyAutoMode switches the session's policy mode. Session-scoped by design — never persisted, so every new process starts interactive.
func (*ChatCLI) SetRPCDangerPolicy ¶ added in v1.163.0
SetRPCDangerPolicy toggles the unattended dangerous-command policy. With block=true, a command classified dangerous by the CommandValidator is declined in-band (the model sees the refusal in the transcript and can replan) instead of auto-approved the way the gateway daemon runs. The MCP server sets this from CHATCLI_MCP_DANGER; the gateway never calls it, so its opt-in auto-approve behavior is unchanged.
func (*ChatCLI) SetUnattended ¶ added in v1.123.0
SetUnattended toggles fully non-interactive agent execution (used by the gateway daemon). When set, the agent never prompts for confirmation and the "thinking" spinner is suppressed — its frames (`model... |/-\`) carry alphanumerics, so they slip past gatewayCleanLine and flood the action feed when stdout is a captured pipe rather than a TTY. Suppressing at the source kills the noise outright instead of trying to filter it downstream.
func (*ChatCLI) SetWatching ¶ added in v1.55.0
SetWatching configures the K8s watcher state for the CLI.
func (*ChatCLI) SkillContentRPC ¶ added in v1.158.0
SkillContentRPC returns a skill's markdown body for prompts/get.
func (*ChatCLI) StartHubResume ¶ added in v1.163.0
StartHubResume joins the shared conversation hub in RESUME mode: it adopts the principal's active conversation (creating it only if none exists) instead of rotating like the interactive Start does. Used by the MCP server so a thread started in the REPL or on a gateway channel continues seamlessly from any MCP client on the machine. principal overrides the hub principal ("" keeps the configured default — the same conversation as the REPL/gateway). Returns the store close function (nil when the hub is unavailable or disabled).
func (*ChatCLI) StartWatcher ¶ added in v1.56.0
StartWatcher creates and starts a K8s watcher in background from interactive mode.
func (*ChatCLI) StopWatcher ¶ added in v1.56.0
func (cli *ChatCLI) StopWatcher()
StopWatcher stops the running K8s watcher if any.
type CommandBlock ¶
type CommandBlock = agent.CommandBlock
CommandBlock and the other aliases below re-export the agent package types so legacy callers can continue to import them from cli without following the refactor chain.
type CommandContextInfo ¶
type CommandContextInfo = agent.CommandContextInfo
CommandBlock and the other aliases below re-export the agent package types so legacy callers can continue to import them from cli without following the refactor chain.
type CommandHandler ¶
type CommandHandler struct {
// contains filtered or unexported fields
}
func NewCommandHandler ¶
func NewCommandHandler(cli *ChatCLI) *CommandHandler
func (*CommandHandler) HandleCommand ¶
func (ch *CommandHandler) HandleCommand(ctx context.Context, userInput string) bool
HandleCommand dispatches a slash command. Returns true to exit the REPL.
type CommandOutput ¶
type CommandOutput = agent.CommandOutput
CommandBlock and the other aliases below re-export the agent package types so legacy callers can continue to import them from cli without following the refactor chain.
type CompactConfig ¶ added in v1.65.2
type CompactConfig struct {
Provider string
Model string
BudgetRatio float64 // fraction of context window to use (default 0.75)
MinKeepRecent int // minimum recent messages to keep verbatim (default 10)
CharsPerToken int // character-to-token ratio estimate (default 4)
// CharsPerTokenPrecise, when > 0, is the learned chars-per-token ratio
// for the provider/model (see tokenCalibrator) and takes precedence
// over the integer default in the budget math.
CharsPerTokenPrecise float64
// ReservedChars is request weight that lives OUTSIDE the history slice
// (native tool definitions, wire overhead) and still counts against the
// model window. Subtracted from the history budget, floored at a quarter
// of it so a huge tool catalog can never starve the conversation.
ReservedChars int
// SummarizerClient, when set, serves the Level 2 structured summary
// instead of the session client — a cheaper/faster model configured via
// CHATCLI_COMPACT_MODEL. Nil keeps the session client.
SummarizerClient client.LLMClient
// SummarizerProvider/SummarizerModel name the summarizer's route so its
// input can be sized against its own window (empty = session model).
SummarizerProvider string
SummarizerModel string
// ExternalSummarizer, when set, is the context engine that produces
// the Level 2 summary (CHATCLI_CONTEXT_ENGINE); an error or empty
// output falls back to the embedded summarizer.
ExternalSummarizer ContextEngine
// MaxPayloadBytes caps the serialized request body size in bytes.
// When > 0, overrides the context-window budget if it would yield
// a larger payload than the corporate proxy / gateway accepts
// (many enterprise proxies cap POST bodies at 1-5 MB). 0 disables
// the cap. Honors env CHATCLI_MAX_PAYLOAD (human-friendly: "5MB",
// "512KB", "5"=5MB when unit is omitted).
MaxPayloadBytes int
}
CompactConfig holds parameters for a compaction operation.
func DefaultCompactConfig ¶ added in v1.65.2
func DefaultCompactConfig(provider, model string) CompactConfig
DefaultCompactConfig returns sensible defaults for chat mode.
type CompactReport ¶ added in v1.196.0
type CompactReport struct {
Level int
SummaryUsage *models.UsageInfo
SummaryProvider string
SummaryModel string
Level2SkippedByBO bool
}
CompactReport describes the last Compact run: the level that produced the result and what the Level 2 summarizer consumed (nil when no summary was produced), so the caller can account for it.
type CompactStage ¶ added in v1.104.0
type CompactStage string
CompactStage identifies which level of the pipeline is running. Used by the UI to render meaningful progress messages instead of a generic "Processando..." while the compactor is working.
const ( CompactStageStart CompactStage = "start" CompactStageTrim CompactStage = "trim" CompactStageSummarize CompactStage = "summarize" CompactStageEmergency CompactStage = "emergency" CompactStageDone CompactStage = "done" )
type ContextEngine ¶ added in v1.196.0
type ContextEngine interface {
Compact(ctx context.Context, segment string, budgetChars int, instruction string) (string, error)
}
ContextEngine is the context-engine seam: given the rendered segment, the character budget and an optional user instruction, return the summary that replaces the segment. An interface (not a func) so the config structs carrying it stay comparable.
type ContextHandler ¶ added in v1.33.0
type ContextHandler struct {
// contains filtered or unexported fields
}
ContextHandler gerencia comandos relacionados a contextos
func NewContextHandler ¶ added in v1.33.0
func NewContextHandler(logger *zap.Logger) (*ContextHandler, error)
NewContextHandler cria um novo handler de contextos
func NewContextHandlerAt ¶ added in v1.196.0
func NewContextHandlerAt(basePath string, logger *zap.Logger) (*ContextHandler, error)
NewContextHandlerAt is NewContextHandler over an explicit contexts directory (per-tenant store sets in the gateway, tests).
func (*ContextHandler) Close ¶ added in v1.196.0
func (h *ContextHandler) Close()
Close stops the watcher (session end / tenant release).
func (*ContextHandler) GetManager ¶ added in v1.33.0
func (h *ContextHandler) GetManager() *ctxmgr.Manager
GetManager returns the underlying context manager.
func (*ContextHandler) HandleContextCommand ¶ added in v1.33.0
func (h *ContextHandler) HandleContextCommand(ctx context.Context, sessionID, input string) error
HandleContextCommand processa comandos /context
func (*ContextHandler) SetRefreshNotifier ¶ added in v1.196.0
func (h *ContextHandler) SetRefreshNotifier(fn func(string))
SetRefreshNotifier installs the sink for watcher-driven refresh notices.
type CostTracker ¶ added in v1.97.0
type CostTracker struct {
// contains filtered or unexported fields
}
CostTracker tracks token usage and estimated cost for the current session, with per-model granularity, real API usage data support, cache token pricing, write-through session persistence, and configurable budget enforcement.
func NewCostTracker ¶ added in v1.97.0
func NewCostTracker() *CostTracker
NewCostTracker creates a new cost tracker with optional budget limit.
func NewCostTrackerAt ¶ added in v1.196.0
func NewCostTrackerAt(dir string) *CostTracker
NewCostTrackerAt is NewCostTracker persisting snapshots under dir (empty = process default).
func (*CostTracker) BudgetBlocked ¶ added in v1.189.0
func (ct *CostTracker) BudgetBlocked() bool
BudgetBlocked reports whether new LLM turns must be refused: a budget is configured, CHATCLI_BUDGET_HARD_STOP is on, and the limit is exhausted.
func (*CostTracker) BudgetHardStopEnabled ¶ added in v1.189.0
func (ct *CostTracker) BudgetHardStopEnabled() bool
BudgetHardStopEnabled reports whether the hard-stop gate is armed.
func (*CostTracker) BudgetMessage ¶ added in v1.99.0
func (ct *CostTracker) BudgetMessage() string
BudgetMessage returns a human-readable budget status message. Returns empty string if no budget is configured or if spending is within limits.
func (*CostTracker) CacheStats ¶ added in v1.196.0
func (ct *CostTracker) CacheStats() CacheStats
CacheStats returns the session's prompt-cache telemetry.
func (*CostTracker) CheckBudget ¶ added in v1.99.0
func (ct *CostTracker) CheckBudget() BudgetLevel
CheckBudget returns the current budget level.
func (*CostTracker) CompactionStats ¶ added in v1.196.0
func (ct *CostTracker) CompactionStats() (total, level3 int, costUSD float64)
CompactionStats returns the session's compaction counters.
func (*CostTracker) ContextEditStats ¶ added in v1.196.0
func (ct *CostTracker) ContextEditStats() (edits, toolUses int, tokens int64)
ContextEditStats returns how many provider context edits were applied this session, the tool results cleared and the input tokens freed.
func (*CostTracker) CurrentSessionID ¶ added in v1.189.0
func (ct *CostTracker) CurrentSessionID() string
CurrentSessionID returns the id under which this session's snapshot is persisted.
func (*CostTracker) DailyBudget ¶ added in v1.196.0
func (ct *CostTracker) DailyBudget() (spentUSD, limitUSD float64)
DailyBudget returns today's spend and the configured daily limit (0 = none).
func (*CostTracker) DailySpend ¶ added in v1.196.0
func (ct *CostTracker) DailySpend() (spent, limit float64)
DailySpend returns today's spend and the configured daily limit (0 when unset).
func (*CostTracker) EmbeddingStats ¶ added in v1.196.0
func (ct *CostTracker) EmbeddingStats() (calls int, tokens int64, costUSD float64)
EmbeddingStats returns the session's embedding counters.
func (*CostTracker) EstimateAndRecord ¶ added in v1.97.0
func (ct *CostTracker) EstimateAndRecord(provider, model string, inputChars, outputChars int)
EstimateAndRecord estimates tokens from text lengths and records usage.
func (*CostTracker) FlushDailySpend ¶ added in v1.196.0
func (ct *CostTracker) FlushDailySpend()
FlushDailySpend writes today's spend now (session end, tenant swap).
func (*CostTracker) GetSummary
deprecated
added in
v1.97.0
func (ct *CostTracker) GetSummary(provider, model string, history int) string
Deprecated: GetSummary has no callers in ChatCLI; /cost renders the localized summary. Kept only because removing an exported method is an API break for embedders. Returns a compact provider/model/turns/cost line.
func (*CostTracker) MemoryStats ¶ added in v1.196.0
func (ct *CostTracker) MemoryStats() (calls int, costUSD float64)
MemoryStats returns the session's background memory-worker counters.
func (*CostTracker) NoteExpectedCacheRebuild ¶ added in v1.196.0
func (ct *CostTracker) NoteExpectedCacheRebuild()
NoteExpectedCacheRebuild tells the telemetry that ChatCLI just rewrote the conversation (compaction, microcompact, skill aging, guided /compact), so the next request's cache write is an expected rebuild rather than a miss caused by an unstable prefix.
func (*CostTracker) RecordCacheStorage ¶ added in v1.196.0
func (ct *CostTracker) RecordCacheStorage(ev llmclient.CacheResourceEvent)
RecordCacheStorage prices one cache resource event: created and refreshed events buy TTL worth of storage for the resource's tokens; released and failed events change nothing (storage already paid for the granted lifetime is not refunded by the provider).
func (*CostTracker) RecordCompaction ¶ added in v1.196.0
func (ct *CostTracker) RecordCompaction(rep CompactReport)
RecordCompaction accounts one Compact run from its report.
func (*CostTracker) RecordContextEdits ¶ added in v1.196.0
func (ct *CostTracker) RecordContextEdits(clearedToolUses, clearedInputTokens int)
RecordRealUsage records actual token usage from an API response. This is the preferred path — provides accurate cost tracking. RecordContextEdits books what the provider context engine cleared server-side (tool results and the input tokens they held).
func (*CostTracker) RecordEmbeddingUsage ¶ added in v1.196.0
func (ct *CostTracker) RecordEmbeddingUsage(provider string, chars int)
RecordEmbeddingUsage accounts one Embed call: chars of input, priced at the provider's rate per million tokens (chars/4).
func (*CostTracker) RecordFromHistory ¶ added in v1.97.0
func (ct *CostTracker) RecordFromHistory(provider, model string, history []interface{ Content() string })
RecordFromHistory is kept for backward compatibility.
func (*CostTracker) RecordMemoryUsage ¶ added in v1.196.0
func (ct *CostTracker) RecordMemoryUsage(provider, model string, usage *models.UsageInfo)
RecordMemoryUsage accounts one background memory-worker call (extraction, rollup, memory compaction): the usage joins the totals like any request and the memory slice is kept apart for /cost.
func (*CostTracker) RecordRealUsage ¶ added in v1.99.0
func (ct *CostTracker) RecordRealUsage(provider, model string, usage *models.UsageInfo)
func (*CostTracker) RecordUsage ¶ added in v1.97.0
func (ct *CostTracker) RecordUsage(provider, model string, promptTokens, completionTokens int)
RecordUsage records tokens used for a single LLM request (legacy path).
func (*CostTracker) ReloadBudget ¶ added in v1.189.0
func (ct *CostTracker) ReloadBudget()
ReloadBudget re-reads the budget environment variables so /reload picks up .env changes without restarting the process.
func (*CostTracker) RemainingTaskBudgetTokens ¶ added in v1.197.0
func (ct *CostTracker) RemainingTaskBudgetTokens() (int, bool)
RemainingTaskBudgetTokens converts the remaining spend into the token ceiling a task budget carries. Reports false when there is no ceiling to express, no measured rate to convert with, or so little room left that the provider's floor would reject it.
func (*CostTracker) RemainingTaskBudgetTokensFor ¶ added in v1.197.0
func (ct *CostTracker) RemainingTaskBudgetTokensFor(provider, model string) (int, bool)
RemainingTaskBudgetTokensFor is RemainingTaskBudgetTokens denominated in the tokens of the pair that actually serves the turn, falling back to the session average while that pair has no rate of its own. Callers that know their route should use this: the ceiling only means something in the currency the next turn will be billed in.
func (*CostTracker) Reset ¶ added in v1.189.0
func (ct *CostTracker) Reset()
Reset closes the current accounting period and starts a fresh one. The closing period is persisted first so /cost last and /cost sessions can still see it — resetting never discards data.
func (*CostTracker) RestoreSession ¶ added in v1.99.0
func (ct *CostTracker) RestoreSession(sessionID string) error
RestoreSession loads a previous session's cost data into the tracker.
func (*CostTracker) SaveSession ¶ added in v1.99.0
func (ct *CostTracker) SaveSession() error
SaveSession persists the current cost data to disk for cross-session tracking (write-through from RecordRealUsage, plus explicit calls on reset/shutdown). Snapshots older than the retention window are pruned.
func (*CostTracker) SetSessionName ¶ added in v1.189.0
func (ct *CostTracker) SetSessionName(name string)
SetSessionName attaches the named-session identity to the persisted snapshot so /cost sessions can show which conversation the spend belongs to.
func (*CostTracker) Snapshot ¶ added in v1.189.0
func (ct *CostTracker) Snapshot() SessionCostData
Snapshot returns a copy of the current session cost data — the same shape that is persisted to disk, safe for the caller to serialize or render.
func (*CostTracker) TakeBudgetTransition ¶ added in v1.189.0
func (ct *CostTracker) TakeBudgetTransition() (BudgetLevel, string, bool)
TakeBudgetTransition returns a one-shot notice when the budget level has escalated since the last check (OK→Warning, Warning→Exceeded, …). The returned message is already localized; ok is false when there is nothing new to announce. De-escalations (after /cost reset or a raised limit) re-arm the notice silently.
func (*CostTracker) TakeCacheMissAlert ¶ added in v1.196.0
func (ct *CostTracker) TakeCacheMissAlert() bool
TakeCacheMissAlert returns true once when a miss streak reached the alert threshold; the caller prints the one-shot notice.
func (*CostTracker) TotalCost ¶ added in v1.99.0
func (ct *CostTracker) TotalCost() float64
TotalCost returns the total estimated cost in USD for the session.
func (*CostTracker) TotalTokens ¶ added in v1.99.0
func (ct *CostTracker) TotalTokens() int64
TotalTokens returns total tokens used across all models.
type EnvRedactMode ¶ added in v1.97.0
type EnvRedactMode string
EnvRedactMode controls how environment variable redaction works.
const ( // EnvRedactStrict uses an allowlist — only explicitly safe vars are shown. EnvRedactStrict EnvRedactMode = "strict" // EnvRedactPermissive redacts known sensitive vars but shows the rest. EnvRedactPermissive EnvRedactMode = "permissive" )
type EnvRedactor ¶ added in v1.97.0
type EnvRedactor struct {
// contains filtered or unexported fields
}
EnvRedactor sanitizes environment variables before sending to LLM.
func NewEnvRedactor ¶ added in v1.97.0
func NewEnvRedactor() *EnvRedactor
NewEnvRedactor creates a redactor configured from environment. CHATCLI_ENV_REDACT_MODE: strict or permissive (default: permissive) CHATCLI_REDACT_PATTERNS: comma-separated additional patterns
func (*EnvRedactor) RedactEnv ¶ added in v1.97.0
func (r *EnvRedactor) RedactEnv(envVars map[string]string) map[string]string
RedactEnv sanitizes a map of environment variables, replacing sensitive values with [REDACTED].
func (*EnvRedactor) RedactEnvSlice ¶ added in v1.97.0
func (r *EnvRedactor) RedactEnvSlice(environ []string) map[string]string
RedactEnvSlice processes os.Environ()-style KEY=VALUE strings.
type ExecutionProfile ¶ added in v1.43.0
type ExecutionProfile int
ExecutionProfile selects which mode-specific defaults apply to the next LLM call (chat vs agent vs coder).
type HistoryCompactor ¶ added in v1.65.2
type HistoryCompactor struct {
// contains filtered or unexported fields
}
HistoryCompactor manages conversation history size through a 3-level pipeline:
Level 1: Near-lossless trimming (strip reasoning, compact XML, dedup) Level 2: Structured summarization (extract facts, not prose) Level 3: Emergency truncation (last resort)
func NewHistoryCompactor ¶ added in v1.65.2
func NewHistoryCompactor(logger *zap.Logger) *HistoryCompactor
NewHistoryCompactor creates a new HistoryCompactor with its embedded trimmer.
func (*HistoryCompactor) CharBudget ¶ added in v1.65.2
func (hc *HistoryCompactor) CharBudget(cfg CompactConfig) int
CharBudget returns the character budget based on the model's context window, additionally capped by MaxPayloadBytes if set (corporate-proxy scenarios). A safety factor leaves headroom for JSON overhead, system prompt and tools.
func (*HistoryCompactor) Compact ¶ added in v1.65.2
func (hc *HistoryCompactor) Compact( ctx context.Context, history []models.Message, llmClient client.LLMClient, cfg CompactConfig, ) ([]models.Message, error)
Compact runs the 3-level compaction pipeline. Each level is progressively more aggressive. Most of the time, Level 1 (trim) suffices.
func (*HistoryCompactor) LastReport ¶ added in v1.196.0
func (hc *HistoryCompactor) LastReport() CompactReport
LastReport returns the report of the most recent Compact call.
func (*HistoryCompactor) NeedsCompaction ¶ added in v1.65.2
func (hc *HistoryCompactor) NeedsCompaction(history []models.Message, cfg CompactConfig) bool
NeedsCompaction returns true if the total character count exceeds the budget.
func (*HistoryCompactor) SetCompressionLayer ¶ added in v1.145.0
func (hc *HistoryCompactor) SetCompressionLayer(l *compress.Layer)
SetCompressionLayer wires the content-aware compression layer into the embedded trimmer so oversized tool feedback and injected context are reduced reversibly (CCR) during compaction instead of being byte-truncated.
func (*HistoryCompactor) SetStatusCallback ¶ added in v1.104.0
func (hc *HistoryCompactor) SetStatusCallback(cb StatusCallback)
SetStatusCallback registers a progress callback for UI feedback. Pass nil to clear. Safe to call concurrently.
type HistoryManager ¶
type HistoryManager struct {
// contains filtered or unexported fields
}
func NewHistoryManager ¶
func NewHistoryManager(logger *zap.Logger) *HistoryManager
func (*HistoryManager) AppendAndRotateHistory ¶ added in v1.19.1
func (hm *HistoryManager) AppendAndRotateHistory(newCommands []string) error
func (*HistoryManager) GetHistoryFilePath ¶ added in v1.47.4
func (hm *HistoryManager) GetHistoryFilePath() string
GetHistoryFilePath retorna o caminho atual do arquivo de histórico
func (*HistoryManager) LoadHistory ¶
func (hm *HistoryManager) LoadHistory() ([]string, error)
LoadHistory carrega o histórico do arquivo
type HubClient ¶ added in v1.123.0
type HubClient interface {
ResolveActiveConversation(ctx context.Context, principal string) (convID, principal2 string, err error)
NewConversation(ctx context.Context, principal string) (string, error)
AppendEvent(ctx context.Context, ev models.ConversationEvent) (models.ConversationEvent, error)
ReadConversation(ctx context.Context, convID string, sinceSeq int64, limit int) ([]models.ConversationEvent, error)
SubscribeConversation(ctx context.Context, convID string, sinceSeq int64) (<-chan models.ConversationEvent, error)
SetBinding(ctx context.Context, platform, userID, principal string) error
ListBindings(ctx context.Context, principal string) ([]models.HubBinding, error)
}
HubClient is the subset of the remote client the CLI needs to share a conversation through the hub. *client/remote.Client satisfies it; defining it here keeps the cli package free of a hard dependency on the remote package.
type HubSync ¶ added in v1.123.0
type HubSync struct {
// contains filtered or unexported fields
}
HubSync keeps a connected CLI in lock-step with the shared cross-channel conversation: it hydrates history on connect, mirrors each local turn, and pulls turns that arrived on other channels (Telegram/Slack/…) into history at the start of the next turn so the model has context — without printing them, which would fight the prompt. /newsession rotates the conversation. All methods are safe to call when the hub is unavailable (no-ops), so the REPL never blocks on the hub.
type InteractionState ¶ added in v1.22.0
type InteractionState int
InteractionState tracks the current phase of the chat loop so the prompt prefix, signal handlers, and spinner can coordinate.
type Logger ¶
type Logger interface {
Info(msg string, fields ...zap.Field)
Error(msg string, fields ...zap.Field)
Warn(msg string, fields ...zap.Field)
Sync() error
}
Logger interface para facilitar a testabilidade
type MessageTrimmer ¶ added in v1.65.2
type MessageTrimmer struct {
// contains filtered or unexported fields
}
MessageTrimmer performs near-lossless trimming of conversation messages to reduce token usage without losing semantic information.
func NewMessageTrimmer ¶ added in v1.65.2
func NewMessageTrimmer(logger *zap.Logger) *MessageTrimmer
NewMessageTrimmer creates a new MessageTrimmer.
func (*MessageTrimmer) SetCompressionLayer ¶ added in v1.145.0
func (t *MessageTrimmer) SetCompressionLayer(l *compress.Layer)
SetCompressionLayer wires the content-aware compression layer (optional).
func (*MessageTrimmer) TrimHistory ¶ added in v1.65.2
func (t *MessageTrimmer) TrimHistory(history []models.Message) []models.Message
TrimHistory performs near-lossless trimming on all messages in the history. It preserves system messages, user-authored messages, and summary messages intact.
type ModelUsageRecord ¶ added in v1.99.0
type ModelUsageRecord struct {
Provider string `json:"provider"`
Model string `json:"model"`
// Core token counts
PromptTokens int64 `json:"prompt_tokens"`
CompletionTokens int64 `json:"completion_tokens"`
TotalTokens int64 `json:"total_tokens"`
// Prompt-cache tokens. Anthropic reports them ALONGSIDE input_tokens
// (additive); OpenAI/Gemini report cache reads as a SUBSET of the
// prompt count — recomputeCost handles both semantics.
CacheCreationTokens int64 `json:"cache_creation_tokens,omitempty"`
CacheReadTokens int64 `json:"cache_read_tokens,omitempty"`
// CacheCreation1hTokens is the share of CacheCreationTokens written with
// the 1-hour TTL (billed at 2x input instead of 1.25x).
CacheCreation1hTokens int64 `json:"cache_creation_1h_tokens,omitempty"`
// Reasoning tokens (o-series / GPT-5 / Gemini thinking). Informational:
// already billed inside CompletionTokens.
ReasoningTokens int64 `json:"reasoning_tokens,omitempty"`
// Tracking
Requests int `json:"requests"`
HasRealData bool `json:"has_real_data"` // true if at least one call returned API usage
// PricingKnown is false when the model matched no pricing table entry —
// the computed cost is then zero NOT because the model is free but
// because ChatCLI does not know its price. /cost surfaces the difference.
PricingKnown bool `json:"pricing_known"`
// ProviderCostUSD accumulates the actually-billed cost reported by the
// provider itself (OpenRouter usage.cost) — authoritative for the calls
// that carried it. The Billed* pools remember WHICH tokens those calls
// covered, so a mixed key (some calls report usage.cost, some do not)
// prices only the uncovered remainder from the tables instead of
// discarding it: TotalCostUSD = table(unbilled tokens) + ProviderCostUSD.
ProviderCostUSD float64 `json:"provider_cost_usd,omitempty"`
BilledPromptTokens int64 `json:"billed_prompt_tokens,omitempty"`
BilledCompletionTokens int64 `json:"billed_completion_tokens,omitempty"`
BilledCacheReadTokens int64 `json:"billed_cache_read_tokens,omitempty"`
BilledCacheCreationTokens int64 `json:"billed_cache_creation_tokens,omitempty"`
// Computed cost (in USD)
InputCostUSD float64 `json:"input_cost_usd"`
OutputCostUSD float64 `json:"output_cost_usd"`
CacheCostUSD float64 `json:"cache_cost_usd"`
TotalCostUSD float64 `json:"total_cost_usd"`
}
ModelUsageRecord tracks cumulative token usage and cost for a single model.
type MultilineBuffer ¶ added in v1.97.0
type MultilineBuffer struct {
// contains filtered or unexported fields
}
MultilineBuffer accumulates lines between --- delimiters, providing consistent multiline input support across chat, agent, and coder modes.
Accepted delimiter (on a line by itself):
- --- (3 or more dashes)
Usage:
buf := &MultilineBuffer{}
complete, text := buf.ProcessLine(line)
if !complete { /* show continuation prompt */ }
else { /* submit text */ }
func (*MultilineBuffer) Active ¶ added in v1.97.0
func (mb *MultilineBuffer) Active() bool
Active returns true when the buffer is accumulating multiline input.
func (*MultilineBuffer) Delimiter ¶ added in v1.97.0
func (mb *MultilineBuffer) Delimiter() string
Delimiter returns the delimiter that opened the current multiline block.
func (*MultilineBuffer) LineCount ¶ added in v1.97.0
func (mb *MultilineBuffer) LineCount() int
LineCount returns the number of lines accumulated so far.
func (*MultilineBuffer) ProcessLine ¶ added in v1.97.0
func (mb *MultilineBuffer) ProcessLine(line string) (complete bool, fullText string)
ProcessLine feeds a new line into the buffer.
Returns:
- complete=false: the buffer is accumulating; show a continuation prompt.
- complete=true: fullText contains the final input to submit.
The opening and closing delimiter lines are NOT included in the output.
func (*MultilineBuffer) Reset ¶ added in v1.97.0
func (mb *MultilineBuffer) Reset()
Reset clears the buffer state (e.g., on Ctrl+C).
type Options ¶ added in v1.16.0
type Options struct {
// Geral
Version bool // --version | -v
Help bool // --help | -h
// Modo one-shot
Prompt string // -p | --prompt
Provider string // --provider
Model string // --model
Timeout time.Duration // --timeout
NoAnim bool // --no-anim
Raw bool // --raw
PromptFlagUsed bool // indica se -p/--prompt foi passado explicitamente
AgentAutoExec bool // --agent-auto-exec
MaxTokens int // --max-tokens
Realm string // --realm
AgentID string // --agent-id
}
Options representa as flags suportadas pelo binário
func NewFlagSet ¶ added in v1.16.0
NewFlagSet cria um FlagSet isolado e as Options para parsing
type PersonaHandler ¶ added in v1.48.0
type PersonaHandler struct {
// contains filtered or unexported fields
}
PersonaHandler handles agent/persona commands
func NewPersonaHandler ¶ added in v1.48.0
func NewPersonaHandler(logger *zap.Logger) *PersonaHandler
NewPersonaHandler creates a new persona handler
func (*PersonaHandler) AttachAgent ¶ added in v1.49.0
func (h *PersonaHandler) AttachAgent(name string)
AttachAgent adds an agent to active pool
func (*PersonaHandler) DetachAgent ¶ added in v1.49.0
func (h *PersonaHandler) DetachAgent(name string)
DetachAgent removes an agent from active pool
func (*PersonaHandler) GetManager ¶ added in v1.48.0
func (h *PersonaHandler) GetManager() *persona.Manager
GetManager returns the underlying persona manager
func (*PersonaHandler) HandleCommand ¶ added in v1.48.0
func (h *PersonaHandler) HandleCommand(userInput string)
HandleCommand processes /persona commands (retrocompatibilidade) Redireciona para os comandos /agent equivalentes
func (*PersonaHandler) ListAgents ¶ added in v1.48.0
func (h *PersonaHandler) ListAgents()
ListAgents shows all available agents
func (*PersonaHandler) ListSkills ¶ added in v1.48.0
func (h *PersonaHandler) ListSkills()
ListSkills shows all available skills
func (*PersonaHandler) LoadAgent ¶ added in v1.48.0
func (h *PersonaHandler) LoadAgent(name string)
LoadAgent loads an agent by name
func (*PersonaHandler) ShowActive ¶ added in v1.48.0
func (h *PersonaHandler) ShowActive(full bool)
ShowActive shows details of the currently active agent
func (*PersonaHandler) ShowAgentStatus ¶ added in v1.48.0
func (h *PersonaHandler) ShowAgentStatus()
ShowAgentStatus shows current agent/persona status (chamado por /agent sem argumentos)
func (*PersonaHandler) ShowAttachedAgents ¶ added in v1.49.0
func (h *PersonaHandler) ShowAttachedAgents()
ShowAttachedAgents shows only the list of attached agents without prompt details
func (*PersonaHandler) ShowHelp ¶ added in v1.48.0
func (h *PersonaHandler) ShowHelp()
ShowHelp shows usage information for /agent subcommands
func (*PersonaHandler) UnloadAgent ¶ added in v1.48.0
func (h *PersonaHandler) UnloadAgent()
UnloadAgent deactivates the current agent
func (*PersonaHandler) UnloadAllAgents ¶ added in v1.49.0
func (h *PersonaHandler) UnloadAllAgents()
UnloadAllAgents deactivates all agents
type RPCChatOpts ¶ added in v1.163.0
RPCChatOpts parametrizes a headless chat turn. Provider/Model are the per-call routing overrides from the MCP tool arguments; when set they win over any skill model hint (explicit beats implicit).
type RPCChatTurn ¶ added in v1.163.0
RPCChatTurn is the result of a headless chat turn: the assistant reply and the updated session history the backend should store.
type RPCMCPToolInfo ¶ added in v1.161.0
type RPCMCPToolInfo struct {
Name string // origin tool name, WITHOUT the mcp_ prefix
Server string // owning MCP server (mcp_servers.json name)
Description string
InputSchema map[string]interface{} // origin JSON Schema, passed through
ReadOnly bool // origin annotations.readOnlyHint
}
RPCMCPToolInfo describes one tool proxied from an MCP server ChatCLI is connected to, re-exported on the MCP/ACP server surface.
type RPCResourceContent ¶ added in v1.163.0
RPCResourceContent mirrors rpcserve.ResourceContent.
type RPCResourceInfo ¶ added in v1.163.0
RPCResourceInfo mirrors rpcserve.ResourceInfo without importing it (the dependency points the other way: cmd adapts between the two).
type RPCRunOpts ¶ added in v1.158.0
type RPCRunOpts struct {
// Provider/Model temporarily reroute the run to another configured
// provider (restored afterwards). Empty keeps the session default.
Provider string
Model string
// Quality maps CHATCLI_QUALITY_* env overrides applied for the run
// only (e.g. "CHATCLI_QUALITY_ENABLED": "true"). The quality pipeline
// re-reads env per run, so this is the canonical toggle surface.
Quality map[string]string
// Emit, when non-nil, receives the rendered transcript line by line
// as the loop works (ACP streaming).
Emit func(string)
// Events, when non-nil, installs a structured event sink for the run
// (ACP structured bridge). It takes precedence over Emit: the rendered
// transcript is captured and discarded, and the client consumes typed
// events plus the returned final answer instead of scraped lines.
Events agentevents.Sink
// Permissions, when non-nil, installs a per-run PermissionRequester so
// policy-gated actions can ask the connected client for approval even
// without an event sink (MCP elicitation bridge). Sinks implementing
// PermissionRequester themselves (ACP) take precedence.
Permissions agentevents.PermissionRequester
// Session scopes the run's /context attachments and knowledge bases
// (ctxmgr session id). Empty keeps the process default.
Session string
// History, together with a non-nil HistoryOut, swaps the caller's
// per-session conversation in for the run — the loop starts from it and
// HistoryOut receives the updated conversation on exit (same contract as
// RunChatTurnRPC). With HistoryOut nil the run keeps the legacy behavior
// of operating on the process-global history.
History []models.Message
HistoryOut *[]models.Message
}
RPCRunOpts parameterizes an agent/coder run driven over RPC.
type RPCSkillInfo ¶ added in v1.158.0
RPCSkillInfo describes one skill served as an MCP prompt.
type RPCToolInfo ¶ added in v1.158.0
type RPCToolInfo struct {
Name string // without the '@' prefix
Description string
Usage string
Schema string // the plugin's self-declared schema (JSON, free-form)
ReadOnly bool // capability metadata for a bare invocation
}
RPCToolInfo describes one plugin tool exposed over MCP/ACP.
type SessionCostData ¶ added in v1.99.0
type SessionCostData struct {
SessionID string `json:"session_id"`
SessionName string `json:"session_name,omitempty"`
StartTime time.Time `json:"start_time"`
LastUpdate time.Time `json:"last_update"`
ModelUsage map[string]*ModelUsageRecord `json:"model_usage"` // key: "provider:model"
TotalCostUSD float64 `json:"total_cost_usd"`
TotalRequests int `json:"total_requests"`
TotalTokens int64 `json:"total_tokens,omitempty"`
// Explicit cache resources (Gemini cachedContents): storage billed per
// token-hour, priced from lifecycle events (cost_cache_resources.go).
CacheResources int `json:"cache_resources,omitempty"`
CacheStorageTokenHours float64 `json:"cache_storage_token_hours,omitempty"`
CacheStorageCostUSD float64 `json:"cache_storage_cost_usd,omitempty"`
EmbeddingCalls int `json:"embedding_calls,omitempty"`
EmbeddingTokens int64 `json:"embedding_tokens,omitempty"`
EmbeddingCostUSD float64 `json:"embedding_cost_usd,omitempty"`
MemoryCalls int `json:"memory_calls,omitempty"`
MemoryCostUSD float64 `json:"memory_cost_usd,omitempty"`
Compactions int `json:"compactions,omitempty"`
CompactionsLevel3 int `json:"compactions_level3,omitempty"`
CompactionCostUSD float64 `json:"compaction_cost_usd,omitempty"`
}
SessionCostData is the serializable snapshot of a cost tracking session.
func ListCostSnapshots ¶ added in v1.189.0
func ListCostSnapshots(limit int) ([]*SessionCostData, error)
ListCostSnapshots returns persisted snapshots, most recent first, capped at limit (0 = no cap). The current process's snapshot is included when it has been written.
func LoadCostSnapshot ¶ added in v1.189.0
func LoadCostSnapshot(sessionID string) (*SessionCostData, error)
LoadCostSnapshot reads one persisted snapshot by session id.
type SessionData ¶ added in v1.65.2
type SessionData = models.SessionData
SessionData is an alias for the shared models.SessionData type. Kept for local convenience within the cli package.
type SessionEncryptor ¶ added in v1.97.0
type SessionEncryptor struct {
// contains filtered or unexported fields
}
SessionEncryptor provides AES-256-GCM encryption for session files. Key is derived from the existing auth key (~/.chatcli/.auth-key) using HKDF.
The format and derivation live in pkg/atrest so the session store, the MCP session mirrors and park snapshots (which cannot import cli) share them; this type remains as the cli-side handle over the same primitive.
func NewSessionEncryptor ¶ added in v1.97.0
func NewSessionEncryptor() (*SessionEncryptor, error)
NewSessionEncryptor creates an encryptor by deriving a key from the auth master key. If CHATCLI_ENCRYPTION_KEY env is set, uses that instead. Falls back to the auth key file at ~/.chatcli/.auth-key.
type SessionManager ¶ added in v1.23.0
type SessionManager struct {
// contains filtered or unexported fields
}
SessionManager gerencia o salvamento e carregamento de sessões de conversa.
func NewSessionManager ¶ added in v1.23.0
func NewSessionManager(logger *zap.Logger) (*SessionManager, error)
NewSessionManager cria uma nova instância do SessionManager.
func NewSessionManagerAt ¶ added in v1.196.0
func NewSessionManagerAt(sessionsDir string, logger *zap.Logger) (*SessionManager, error)
NewSessionManagerAt is NewSessionManager over an explicit store directory (per-tenant store sets in the gateway, tests).
func (*SessionManager) CleanExpiredMachineSessions ¶ added in v1.165.0
func (sm *SessionManager) CleanExpiredMachineSessions() int
CleanExpiredMachineSessions applies the TTL (CHATCLI_SESSION_TTL, default 90 days; "0" disables expiry entirely, honoring the documented contract) to MACHINE-created sessions only — autosaves and MCP session mirrors. User-named sessions are never expired: a checkpoint someone saved on purpose must outlive any retention policy. This is the lifecycle hook the boot paths call; the broader CleanExpiredSessions remains available for operators who explicitly want full expiry.
func (*SessionManager) CleanExpiredSessions ¶ added in v1.97.0
func (sm *SessionManager) CleanExpiredSessions() int
CleanExpiredSessions removes sessions older than the configured TTL (L6). Default TTL: 90 days, configurable via CHATCLI_SESSION_TTL (in days).
func (*SessionManager) DeleteSession ¶ added in v1.23.0
func (sm *SessionManager) DeleteSession(name string) error
DeleteSession apaga um arquivo de sessão.
func (*SessionManager) ForkCurrentToNew ¶ added in v1.97.0
func (sm *SessionManager) ForkCurrentToNew(newName string, sd *SessionData) error
ForkCurrentToNew creates a fork from in-memory session data (for forking unsaved sessions).
func (*SessionManager) ForkSession ¶ added in v1.97.0
func (sm *SessionManager) ForkSession(sourceName, newName string) error
ForkSession creates a copy of an existing session with a new name. The forked session is an independent copy — changes to either session don't affect the other.
func (*SessionManager) GetSessionMessages ¶ added in v1.164.0
func (sm *SessionManager) GetSessionMessages(name string, offset, limit int) ([]models.Message, int, error)
GetSessionMessages returns one page of a saved session's unified message stream plus the total count, so the @session tool can read an old conversation without loading it over the live one. offset is 0-based; limit <= 0 applies a default page size.
func (*SessionManager) LatestSessionInfo ¶ added in v1.167.0
func (sm *SessionManager) LatestSessionInfo() (name string, saved time.Time, title string)
LatestSessionInfo returns the newest saved session's name, save time and title, best-effort — a zero name means the store is empty or unreadable. Only the newest file is parsed, so this is cheap enough for the boot path.
func (*SessionManager) ListSessions ¶ added in v1.23.0
func (sm *SessionManager) ListSessions() ([]string, error)
ListSessions lista todas as sessões salvas.
func (*SessionManager) LoadSession ¶ added in v1.23.0
func (sm *SessionManager) LoadSession(name string) ([]models.Message, error)
LoadSession carrega o histórico de uma conversa de um arquivo JSON. Mantém assinatura original para compatibilidade com remote client. Retorna apenas o chatHistory para uso legado.
func (*SessionManager) LoadSessionV2 ¶ added in v1.65.2
func (sm *SessionManager) LoadSessionV2(name string) (*SessionData, error)
LoadSessionV2 carrega uma sessão completa com suporte a formato v2 e legacy.
func (*SessionManager) PruneSessionsByPrefix ¶ added in v1.165.0
func (sm *SessionManager) PruneSessionsByPrefix(prefix string, keep int) int
PruneSessionsByPrefix deletes the OLDEST sessions matching prefix beyond keep, ordered by file modification time (newest survive). Returns how many were removed. Safe on any cadence; missing dir is not an error.
func (*SessionManager) SaveSession ¶ added in v1.23.0
func (sm *SessionManager) SaveSession(name string, history []models.Message) error
SaveSession salva o histórico da conversa em um arquivo JSON. Mantém assinatura original para compatibilidade com remote client.
func (*SessionManager) SaveSessionV2 ¶ added in v1.65.2
func (sm *SessionManager) SaveSessionV2(name string, sd *SessionData) error
SaveSessionV2 salva uma sessão completa com históricos escopados.
func (*SessionManager) SearchSessions ¶ added in v1.123.0
func (sm *SessionManager) SearchSessions(query string, maxSnippetsPerSession int) ([]SessionSearchHit, error)
SearchSessions performs a ranked full-text search across all persisted sessions, reusing the existing JSON store (no separate index). Semantics, tuned for natural-language recall queries ("o que discutimos sobre X?"):
- Query terms are normalized (lowercase, accent-folded) and reduced to SIGNIFICANT terms — PT/EN stopwords and recall-framing verbs ("discutimos", "decided") carry no signal and used to disqualify every session under the old raw AND filter.
- A session QUALIFIES when every significant term appears somewhere in it — in ANY message, not necessarily the same one. When no session qualifies (or the query was all stopwords), the filter relaxes and BM25 ranks alone rather than returning nothing.
- Qualifying sessions RANK by BM25 over their individual messages (the same keyless scorer the knowledge corpus uses), with a bounded recency boost so yesterday's session outranks a months-old one when match quality is comparable. Snippets come from each session's top-scoring messages.
maxSnippetsPerSession caps how many context snippets each hit carries.
func (*SessionManager) SessionExists ¶ added in v1.179.0
func (sm *SessionManager) SessionExists(name string) bool
SessionModTime returns the store file's last-modified time for a saved session. It is the freshness signal for cross-surface continuity: a bound surface (REPL, MCP/ACP session, gateway principal) compares it against its own last sync stamp to decide whether another surface has written the session since, and reloads before the next turn when it has. SessionExists reports whether a saved session file exists under name. Invalid names report false — callers treat them as "nothing to load" and surface the validation error on the write path instead.
func (*SessionManager) SessionModTime ¶ added in v1.179.0
func (sm *SessionManager) SessionModTime(name string) (time.Time, error)
func (*SessionManager) SessionTitles ¶ added in v1.167.0
func (sm *SessionManager) SessionTitles() map[string]string
SessionTitles returns the stored title per session, best-effort ("" or a missing key means no title). Served from the cached search corpus, so callers can decorate listings without re-reading the store.
type SessionSearchHit ¶ added in v1.123.0
type SessionSearchHit struct {
Session string
Matches int
Score float64
Snippets []string
SavedAt time.Time // session file mtime; zero when unknown
Title string // stored session title; "" when absent
}
SessionSearchHit is one session that matched a search, with the strongest snippets for context.
type SkillClientResolution ¶ added in v1.100.0
type SkillClientResolution = client.ModelRoutingResolution
SkillClientResolution preserves the original type name used by the cli package. It is now just a re-export of the shared resolver struct.
type SkillHandler ¶ added in v1.66.0
type SkillHandler struct {
// contains filtered or unexported fields
}
SkillHandler handles /skill commands.
func NewSkillHandler ¶ added in v1.66.0
func NewSkillHandler(logger *zap.Logger, personaMgr *persona.Manager) *SkillHandler
NewSkillHandler creates a new skill handler with registry manager.
func (*SkillHandler) GetPinnedSkills ¶ added in v1.114.0
func (sh *SkillHandler) GetPinnedSkills() []*persona.Skill
GetPinnedSkills resolves every pinned name against the persona manager and returns the matching skills sorted alphabetically (stable order keeps the system-prompt injection block cache-friendly). Stale pins — skills that were uninstalled or renamed — are pruned silently from the set.
func (*SkillHandler) HandleCommand ¶ added in v1.66.0
func (sh *SkillHandler) HandleCommand(ctx context.Context, userInput string)
HandleCommand routes /skill subcommands.
func (*SkillHandler) Info ¶ added in v1.66.0
func (sh *SkillHandler) Info(ctx context.Context, name string, fromRegistry string)
Info shows metadata about a skill, checking local installed first, then registries. If fromRegistry is non-empty, only that registry is queried for remote metadata. The function is a thin orchestrator — each row of the output (name, description, version, …) is rendered by a focused helper so the function stays under the project's complexity budget and each row can be exercised independently in tests.
func (*SkillHandler) Install ¶ added in v1.66.0
func (sh *SkillHandler) Install(ctx context.Context, name string, fromRegistry string)
Install downloads and installs a skill from a registry. If fromRegistry is non-empty, only that registry is used. If multiple registries have the skill, the user is prompted to choose.
Supported invocations:
/skill install frontend-design → auto-detect or disambiguate /skill install frontend-design --from skills.sh → explicit registry /skill install anthropics/skills/frontend-design → skills.sh slug (unambiguous)
func (*SkillHandler) IsPinned ¶ added in v1.114.0
func (sh *SkillHandler) IsPinned(name string) bool
IsPinned reports whether the named skill is currently pinned. Used by /skill list to render the pin marker.
func (*SkillHandler) List ¶ added in v1.66.0
func (sh *SkillHandler) List()
List shows all installed skills.
func (*SkillHandler) Pin ¶ added in v1.114.0
func (sh *SkillHandler) Pin(name string)
Pin marks a skill to be auto-injected into every turn for the rest of the session, regardless of triggers/paths. Pinning is rejected for skills with `disable-model-invocation: true` (the flag exists precisely to forbid automatic injection; manual invocation via `/<skill-name>` remains the supported path for those).
func (*SkillHandler) PinnedNames ¶ added in v1.114.0
func (sh *SkillHandler) PinnedNames() []string
PinnedNames returns a snapshot of currently pinned skill names sorted alphabetically. Exposed for the completer.
func (*SkillHandler) Prefer ¶ added in v1.101.0
func (sh *SkillHandler) Prefer(args []string)
Prefer manages source preferences for skills with name conflicts. Usage:
/skill prefer → list all preferences /skill prefer frontend-design → show current preference /skill prefer frontend-design skills.sh → prefer the skills.sh version /skill prefer frontend-design local → prefer the local version /skill prefer frontend-design --reset → remove preference (use default order)
func (*SkillHandler) Search ¶ added in v1.66.0
func (sh *SkillHandler) Search(ctx context.Context, query string)
Search performs a fan-out search across all registries.
func (*SkillHandler) SetRegistryEnabled ¶ added in v1.101.0
func (sh *SkillHandler) SetRegistryEnabled(name string, enabled bool)
SetRegistryEnabled enables or disables a registry by name, persists the change, and hot-reloads the registry manager so the change takes effect immediately.
func (*SkillHandler) ShowHelp ¶ added in v1.66.0
func (sh *SkillHandler) ShowHelp()
ShowHelp displays usage information.
func (*SkillHandler) ShowPinned ¶ added in v1.114.0
func (sh *SkillHandler) ShowPinned()
ShowPinned lists all currently pinned skills for the session.
func (*SkillHandler) ShowRegistries ¶ added in v1.66.0
func (sh *SkillHandler) ShowRegistries()
ShowRegistries displays all configured registries.
func (*SkillHandler) Uninstall ¶ added in v1.66.0
func (sh *SkillHandler) Uninstall(name string)
Uninstall removes an installed skill. Supports both exact names ("anthropics-skills--frontend-design") and base names ("frontend-design"). When multiple installs match a base name, lists them and asks the user to specify which one to remove.
func (*SkillHandler) Unpin ¶ added in v1.114.0
func (sh *SkillHandler) Unpin(name string)
Unpin removes a skill from the pinned set. No-op (with a friendly notice) when the skill wasn't pinned to begin with.
type SlashToolEntry ¶ added in v1.118.0
type SlashToolEntry struct {
Name string // canonical slash form, e.g. "/help"
Description string // one-line, i18n-resolved
InputSchema string // JSON schema; can be empty for no-arg commands
Handler func(ctx context.Context, args map[string]any) (string, error)
// ReadOnly tells the orchestrator's partition policy whether this
// command can run in a concurrent batch with other read-only tools.
// /help, /version, /session list, /memory list are read-only.
// /context attach, /skill add are not.
ReadOnly bool
}
SlashToolEntry describes a slash command we expose to the LLM as a tool. The shape mirrors what the model needs to know about any tool: a stable name, a one-line description, a JSON schema for inputs, and the function that produces the output.
The LLM-visible name uses an `@cmd:` prefix (e.g. `@cmd:help`) so it can be discriminated in tool dispatch without colliding with the existing `@coder`/`@websearch` builtins or with MCP `mcp_*` tools. Users still type the unprefixed slash form (`/help`) at the prompt.
Handler receives the parsed input map (already JSON-decoded) and the invocation context, and returns the string to surface back to the LLM. Errors are surfaced via the second return value and mapped to IsError on the plugin side.
func AllSlashTools ¶ added in v1.118.0
func AllSlashTools() []*SlashToolEntry
AllSlashTools returns a deterministic snapshot of every registered entry, sorted by name. Used to seed the plugin manager.
func LookupSlashTool ¶ added in v1.118.0
func LookupSlashTool(name string) *SlashToolEntry
LookupSlashTool returns the entry for a canonical slash name (with or without the leading slash), or nil when not registered.
type SourceType ¶
type SourceType = agent.SourceType
CommandBlock and the other aliases below re-export the agent package types so legacy callers can continue to import them from cli without following the refactor chain.
type StatusCallback ¶ added in v1.104.0
type StatusCallback func(stage CompactStage, msg string)
StatusCallback is invoked by the compactor at the start/end of each level so callers can update spinners, status bars, or animation messages. It must be non-blocking and safe to call from any goroutine.
Source Files
¶
- acp_support.go
- agent_board_sync.go
- agent_coder_validation.go
- agent_command_blocks.go
- agent_context_block.go
- agent_earlyexit.go
- agent_events_bridge.go
- agent_feedback.go
- agent_helpers.go
- agent_mode.go
- agent_native_results.go
- agent_park.go
- agent_park_commands.go
- agent_park_directives.go
- agent_park_inline.go
- agent_plan_first.go
- agent_routing.go
- agent_side_commands.go
- agent_spinner_label.go
- agent_system_prompt.go
- agent_tool_defer.go
- agent_tool_sanitizer.go
- agent_typeahead.go
- agents_adapter.go
- agents_command.go
- agents_completer.go
- animation_manager.go
- board_adapter.go
- board_command.go
- board_completer.go
- cache_prefix_notice.go
- channel_command.go
- channel_triggers.go
- channels_tool_adapter.go
- chat_ask.go
- chat_graphview.go
- chat_knowledge.go
- chat_memory.go
- chat_pipeline.go
- cli.go
- cli_commands.go
- cli_completer.go
- cli_completer_quality.go
- cli_config.go
- cli_file_processing.go
- cli_llm.go
- cli_rendering.go
- cli_session.go
- cli_session_autosave.go
- cli_session_binding.go
- cli_watcher.go
- coder_format_guard.go
- colors.go
- command_handler.go
- command_handler_connect.go
- command_handler_metrics.go
- command_handler_plugins.go
- command_handler_watch.go
- command_output_sanitizer.go
- commands_autoroute.go
- commands_integration.go
- compact_cache_aware.go
- compact_command.go
- compact_config.go
- compaction_hooks.go
- compression_adapter.go
- config_agent_mutate.go
- config_chat_mutate.go
- config_commands_section.go
- config_compression_mutate.go
- config_env_defaults.go
- config_image_mutate.go
- config_managed.go
- config_memory.go
- config_output_mutate.go
- config_quality.go
- config_scheduler.go
- config_sections.go
- config_security_atrest.go
- config_security_jwt.go
- config_security_keychain.go
- config_security_mutate.go
- config_selfevolve.go
- config_ui.go
- config_ui_mutate.go
- config_update.go
- content_redactor.go
- context_adapter.go
- context_autorag.go
- context_display.go
- context_edits.go
- context_estimate.go
- context_handler.go
- context_inspect.go
- context_io.go
- context_refresh.go
- context_status.go
- cost_budget.go
- cost_cache_resources.go
- cost_cache_telemetry.go
- cost_command.go
- cost_compaction.go
- cost_daily.go
- cost_embeddings.go
- cost_task_budget.go
- cost_tracker.go
- doc.go
- env_redactor.go
- export_command.go
- extension_providers.go
- gateway_command.go
- gateway_detach_unix.go
- gateway_events_sink.go
- gateway_runs_watcher.go
- gateway_runtime_model.go
- gateway_session_binding.go
- graph_command.go
- graphview_adapter.go
- history_compactor.go
- history_manager.go
- history_trimmer.go
- hooks_command.go
- hub_command.go
- hub_local.go
- hub_sync.go
- hyde_setup.go
- knowledge_adapter.go
- knowledge_graph.go
- knowledge_rerank.go
- llm_audit.go
- lsp_command.go
- lsp_tool_adapter.go
- mail_adapter.go
- mail_command.go
- mail_completer.go
- mail_hub_bridge.go
- mcp_command.go
- mcp_dynamic_notice.go
- mcplogin_adapter.go
- memory_adapter.go
- memory_autorecall.go
- memory_bootstrap.go
- memory_command.go
- memory_export_command.go
- memory_flush.go
- memory_mode.go
- memory_notice.go
- memory_pending.go
- memory_recall_evidence.go
- memory_redactor_hook.go
- memory_worker.go
- moa_adapter.go
- moa_command.go
- moa_turn.go
- mode_transition.go
- model_tool_adapter.go
- multiline.go
- oneshot_mode.go
- output_policy.go
- overflow_recovery.go
- palette_bridge.go
- park_completer.go
- path_mentions.go
- payload_recovery.go
- persist_redact.go
- persona_handler.go
- plan_command.go
- policy_adapter.go
- policy_command.go
- proc_tool_adapter.go
- project_env.go
- prompt_breakdown.go
- prompt_budget.go
- prompt_theme.go
- prompts.go
- ratelimit_command.go
- refine_setup.go
- refine_verify_commands.go
- reflexion_setup.go
- retention.go
- rewind.go
- rewind_compact.go
- rpc_chat.go
- rpc_support.go
- rpc_support_full.go
- rpc_support_resources.go
- run_coordinator.go
- runs_hub_bridge.go
- scheduler_adapter.go
- scheduler_bridge.go
- scheduler_command.go
- scheduler_completer.go
- scheduler_http_probe.go
- scheduler_init.go
- scheduler_json.go
- selfevolve.go
- selfevolve_manifest.go
- selfevolve_merge.go
- selfevolve_parse.go
- send_adapter.go
- session_adapter.go
- session_attachments.go
- session_autorecall.go
- session_encryption.go
- session_manager.go
- session_search_normalize.go
- session_transcript.go
- signal_unix.go
- skill_activation.go
- skill_handler.go
- skill_invoke.go
- skill_model_resolve.go
- skill_rescan.go
- slash_tool_handlers.go
- slash_tool_registry.go
- stdin_cancel_other.go
- stdin_cbreak_unix.go
- stdin_ready_unix.go
- surface_shutdown.go
- taskgraph_adapter.go
- taskgraph_command.go
- taskgraph_completer.go
- taskgraph_learning.go
- telemetry_wiring.go
- tenant_paths.go
- tenant_scope.go
- thinking_command.go
- todo_adapter.go
- token_calibration_store.go
- token_calibrator.go
- tool_catalog.go
- tools_catalog_adapter.go
- transcript_journal.go
- tty_inject_linux.go
- tty_inject_unix.go
- turn_context.go
- turn_thinking.go
- ui_boxes.go
- update_command.go
- update_notice.go
- version_view.go
- view_tool_adapter.go
- vision_fallback.go
- websearch_command.go
- welcome.go
- wininput.go
- worker_context_tools.go
- worker_plugin_tools.go
- worker_skill_context.go
- worker_window.go
- worktree.go
Directories
¶
| Path | Synopsis |
|---|---|
|
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0
|
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 |
|
ask
* ChatCLI - AskUser request/answer types and parsing.
|
* ChatCLI - AskUser request/answer types and parsing. |
|
lsp
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0
|
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 |
|
mail
* Package mail is the squad's internal message bus: agents (and the user) * send short directed messages to each other, and each recipient drains its * inbox at the next safe turn boundary of its ReAct loop.
|
* Package mail is the squad's internal message bus: agents (and the user) * send short directed messages to each other, and each recipient drains its * inbox at the next safe turn boundary of its ReAct loop. |
|
moa
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0
|
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 |
|
park
* Package park: durable snapshots for the agent ReAct loop.
|
* Package park: durable snapshots for the agent ReAct loop. |
|
proc
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0
|
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 |
|
quality/convergence
* ChatCLI - Convergence: per-scorer circuit breaker.
|
* ChatCLI - Convergence: per-scorer circuit breaker. |
|
quality/lessonq
* ChatCLI - Lesson Queue: idempotency key derivation.
|
* ChatCLI - Lesson Queue: idempotency key derivation. |
|
runs
* Package runs is the process-wide registry of live agent executions.
|
* Package runs is the process-wide registry of live agent executions. |
|
toolguard
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0
|
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 |
|
trajectory
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0
|
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 |
|
workers
* ChatCLI - Builtin agent model/effort metadata * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 * * Shared base struct providing Model() and Effort() for built-in workers.
|
* ChatCLI - Builtin agent model/effort metadata * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 * * Shared base struct providing Model() and Effort() for built-in workers. |
|
* Package agentevents defines the structured event surface the agent/coder * ReAct loop exposes to protocol frontends (ACP today; gateway/MCP later).
|
* Package agentevents defines the structured event surface the agent/coder * ReAct loop exposes to protocol frontends (ACP today; gateway/MCP later). |
|
* Package board is the squad's shared work board: a small kanban of cards * (backlog → doing → review → blocked → done) that the orchestrator LLM * manages autonomously via the @board tool and humans inspect via /board.
|
* Package board is the squad's shared work board: a small kanban of cards * (backlog → doing → review → blocked → done) that the orchestrator LLM * manages autonomously via the @board tool and humans inspect via /board. |
|
* ChatCLI - Denial Tracker * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 * * Tracks consecutive and total denials to prevent infinite permission prompting.
|
* ChatCLI - Denial Tracker * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 * * Tracks consecutive and total denials to prevent infinite permission prompting. |
|
* ChatCLI - Slash command catalog (resolution + fingerprint cache) * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0
|
* ChatCLI - Slash command catalog (resolution + fingerprint cache) * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 |
|
Package compress is ChatCLI's content-aware, reversible context-compression layer.
|
Package compress is ChatCLI's content-aware, reversible context-compression layer. |
|
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0
|
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 |
|
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0
|
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 |
|
Package imgcompress shrinks images before they are sent to vision-capable models, cutting upload bytes, latency and (for oversized images) the actual vision-token cost — keylessly, with the standard library only (no cgo, no golang.org/x/image, no network).
|
Package imgcompress shrinks images before they are sent to vision-capable models, cutting upload bytes, latency and (for oversized images) the actual vision-token cost — keylessly, with the standard library only (no cgo, no golang.org/x/image, no network). |
|
* ChatCLI - MCP Channel Manager * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 * * Production-grade push-message ring for MCP servers: * * - Bounded in-memory ring (Push / GetRecent / GetByChannel / Count) * keeps the working set hot and lock-friendly.
|
* ChatCLI - MCP Channel Manager * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 * * Production-grade push-message ring for MCP servers: * * - Bounded in-memory ring (Push / GetRecent / GetByChannel / Count) * keeps the working set hot and lock-friendly. |
|
triggers
* ChatCLI - MCP channel reactive triggers * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 * * The trigger engine turns inbound MCP channel messages into actionable * events for the CLI.
|
* ChatCLI - MCP channel reactive triggers * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 * * The trigger engine turns inbound MCP channel messages into actionable * events for the CLI. |
|
Go Multi-Agent - Metrics Display
|
Go Multi-Agent - Metrics Display |
|
Package outputpolicy reduces the tokens a model *generates* (the output side of the bill, complementary to the input/context compression in cli/compress).
|
Package outputpolicy reduces the tokens a model *generates* (the output side of the bill, complementary to the input/context compression in cli/compress). |
|
* ChatCLI - AskUser interactive overlay.
|
* ChatCLI - AskUser interactive overlay. |
|
* ChatCLI - Paste Detection * cli/paste/detector.go * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0
|
* ChatCLI - Paste Detection * cli/paste/detector.go * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 |
|
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0
|
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 |
|
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0
|
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 |
|
* ChatCLI - Scheduler: append-only JSONL audit log.
|
* ChatCLI - Scheduler: append-only JSONL audit log. |
|
action
* AgentResume — fires when a parked agent's wait condition is satisfied * and the interactive ReAct loop should re-enter.
|
* AgentResume — fires when a parked agent's wait condition is satisfied * and the interactive ReAct loop should re-enter. |
|
builtins
* Package builtins wires the built-in condition evaluators and action * executors into a Scheduler.
|
* Package builtins wires the built-in condition evaluators and action * executors into a Scheduler. |
|
condition
* Package condition: built-in evaluators registry.
|
* Package condition: built-in evaluators registry. |
|
* The engine is the deterministic orchestrator of one run: it owns every * state transition, schedules tasks the moment their dependencies complete * (ready-set scheduling, not level barriers), runs validation gates itself, * and only promotes a task to done on an independent reviewer's verdict.
|
* The engine is the deterministic orchestrator of one run: it owns every * state transition, schedules tasks the moment their dependencies complete * (ready-set scheduling, not level barriers), runs validation gates itself, * and only promotes a task to done on an independent reviewer's verdict. |
|
dash
* Package dash serves the live task-graph dashboard: a single-file canvas * UI (embedded, zero CDN) over three read-only endpoints that read the * persisted run state from disk on every request.
|
* Package dash serves the live task-graph dashboard: a single-file canvas * UI (embedded, zero CDN) over three read-only endpoints that read the * persisted run state from disk on every request. |
|
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 * * OpenTelemetry metrics export over OTLP/HTTP (JSON encoding), with no * SDK dependency: the exporter renders the standard ExportMetricsService * request by hand and pushes cumulative counters on an interval.
|
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 * * OpenTelemetry metrics export over OTLP/HTTP (JSON encoding), with no * SDK dependency: the exporter renders the standard ExportMetricsService * request by hand and pushes cumulative counters on an interval. |
|
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 * * Instruction-file hierarchy and @imports.
|
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 * * Instruction-file hierarchy and @imports. |
|
memory
* ChatCLI - Change notification for memory sub-stores * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 * * changeNotifier is the one-line "mark derived caches stale" seam each * sub-store embeds.
|
* ChatCLI - Change notification for memory sub-stores * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 * * changeNotifier is the one-line "mark derived caches stale" seam each * sub-store embeds. |
|
memory/eval
* ChatCLI - Long-term memory: retrieval evaluation harness.
|
* ChatCLI - Long-term memory: retrieval evaluation harness. |
|
threatscan
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0
|
* ChatCLI - Command Line Interface for LLM interaction * Copyright (c) 2024 Edilson Freitas * License: Apache-2.0 |