cli

package
v1.199.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 8, 2026 License: Apache-2.0 Imports: 114 Imported by: 0

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

View Source
const (
	SourceTypeUserInput     = agent.SourceTypeUserInput
	SourceTypeFile          = agent.SourceTypeFile
	SourceTypeCommandOutput = agent.SourceTypeCommandOutput
)

Constantes re-exportadas

View Source
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).

View Source
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.

View Source
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"
)
View Source
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.

View Source
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.

View Source
const AuditLogPathEnv = "CHATCLI_AUDIT_LOG_PATH"

AuditLogPathEnv is shared with the gRPC audit logger: one file, one format, both surfaces.

View Source
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.

View Source
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.

View Source
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.

View Source
const CompactModelEnv = "CHATCLI_COMPACT_MODEL"

CompactModelEnv names the provider:model that serves Level 2 structured summaries. Empty keeps the session client (legacy behavior).

View Source
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.

View Source
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.

View Source
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.

View Source
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.

View Source
const KnowledgeRerankEnv = "CHATCLI_KNOWLEDGE_RERANK"

KnowledgeRerankEnv selects the knowledge rerank stage (off|mmr|llm).

View Source
const (
	// TranscriptEnv disables the journal when set to false.
	TranscriptEnv = "CHATCLI_SESSION_TRANSCRIPT"
)

Variables

View Source
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.

View Source
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

func DetectPromptInjection(text string) (bool, []string)

DetectPromptInjection scans text for common prompt injection patterns. Returns (detected, list of matched patterns).

func FormatPayloadSize added in v1.104.0

func FormatPayloadSize(bytes int) string

FormatPayloadSize returns a human-readable size for display.

func FormatVersionReport added in v1.172.0

func FormatVersionReport(rep version.Report) string

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

func IsEncrypted(data []byte) bool

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

func ParsePayloadSize(s string) int

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

func PreprocessArgs(args []string) []string

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

func RunUpdateOneShot(ctx context.Context, logger *zap.Logger, checkOnly bool) error

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

func RunUpdateSubcommand(ctx context.Context, logger *zap.Logger, args []string) int

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

func SanitizeCommandOutput(cmd, output string) string

SanitizeCommandOutput wraps command output with delimiters, enforces size limits, and detects potential prompt injection attempts.

func SweepStaleParks added in v1.112.0

func SweepStaleParks(cutoff time.Time) (int, []error)

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

func TurnCacheHitPct(provider, model string, u *models.UsageInfo) (float64, bool)

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

func UpdateSubcommandMain(args []string) int

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

func NewAgentMode(cli *ChatCLI, logger *zap.Logger) *AgentMode

NewAgentMode cria uma nova instância do modo agente

func (*AgentMode) InjectedSkillNames added in v1.177.0

func (a *AgentMode) InjectedSkillNames() []string

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) RunOnce added in v1.19.0

func (a *AgentMode) RunOnce(ctx context.Context, query string, autoExecute bool) error

RunOnce executa modo agente one-shot

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 (cli *ChatCLI) ApplyOverrides(ctx context.Context, mgr manager.LLMManager, provider, model string) error

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

func (cli *ChatCLI) CleanExpiredMachineSessionsRPC() int

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

func (cli *ChatCLI) DeleteSessionRPC(name string) error

DeleteSessionRPC removes a saved session, validating the name first.

func (*ChatCLI) EnableHubSync added in v1.123.0

func (cli *ChatCLI) EnableHubSync(client HubClient)

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

func (cli *ChatCLI) ExpandSlashCommandRPC(ctx context.Context, text string) (string, bool)

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

func (cli *ChatCLI) FinalizeSpend(ctx context.Context)

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

func (cli *ChatCLI) ForkSessionRPC(sourceName, newName string) error

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

func (cli *ChatCLI) GetContextCommands() []prompt.Suggest

GetContextCommands retorna a lista de sugestões para comandos com @

func (*ChatCLI) GetInternalCommands added in v1.37.0

func (cli *ChatCLI) GetInternalCommands() []prompt.Suggest

func (*ChatCLI) HandleOneShotOrFatal added in v1.16.3

func (cli *ChatCLI) HandleOneShotOrFatal(ctx context.Context, opts *Options) bool

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

func (cli *ChatCLI) IsACPCommandAllowed(token string) bool

IsACPCommandAllowed reports whether a slash token (with leading slash) is runnable headless over ACP.

func (*ChatCLI) IsExecuting added in v1.22.0

func (cli *ChatCLI) IsExecuting() bool

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

func (cli *ChatCLI) ListCommandPromptsRPC() [][3]string

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

func (cli *ChatCLI) ListSessionsRPC() ([]string, error)

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

func (cli *ChatCLI) LoadSessionRPC(name string) ([]models.Message, error)

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

func (cli *ChatCLI) PolicyAutoMode() bool

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

func (cli *ChatCLI) PolicyModeLabel() string

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

func (cli *ChatCLI) ProvidersRPC() (string, error)

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

func (cli *ChatCLI) PruneSessionsRPC(prefix string, keep int) int

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

func (cli *ChatCLI) ReadRPCResource(_ context.Context, uri string) (RPCResourceContent, error)

ReadRPCResource resolves one chatcli:// URI to its content.

func (*ChatCLI) RenderCommandPromptRPC added in v1.184.0

func (cli *ChatCLI) RenderCommandPromptRPC(ctx context.Context, name, args string) (string, bool)

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

func (cli *ChatCLI) RotateHubThreadRPC(ctx context.Context)

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

func (cli *ChatCLI) RunAgentCaptured(ctx context.Context, task string) (string, error)

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

func (cli *ChatCLI) RunAgentFullOnce(ctx context.Context, task string) error

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 (cli *ChatCLI) RunAgentOnce(ctx context.Context, input string, autoExecute bool) error

func (*ChatCLI) RunAgentRPC added in v1.158.0

func (cli *ChatCLI) RunAgentRPC(ctx context.Context, task string, o RPCRunOpts) (string, error)

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

func (cli *ChatCLI) RunAnyRPCTool(ctx context.Context, name, args string) (string, error)

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

func (cli *ChatCLI) RunCoderCaptured(ctx context.Context, task string) (string, error)

RunCoderCaptured runs the coder loop one-shot on task, capturing output.

func (*ChatCLI) RunCoderOnce added in v1.42.0

func (cli *ChatCLI) RunCoderOnce(ctx context.Context, input string) error

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

func (cli *ChatCLI) RunCoderRPC(ctx context.Context, task string, o RPCRunOpts) (string, error)

RunCoderRPC runs the coder loop with per-call options.

func (*ChatCLI) RunGatewayCoderOnce added in v1.123.0

func (cli *ChatCLI) RunGatewayCoderOnce(ctx context.Context, task string) error

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

func (cli *ChatCLI) RunGatewayForeground(ctx context.Context) error

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

func (cli *ChatCLI) RunGatewayWithBroker(ctx context.Context, broker hub.Broker) error

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) RunOnce added in v1.16.0

func (cli *ChatCLI) RunOnce(ctx context.Context, input string, disableAnimation bool, rawOutput bool) error

func (*ChatCLI) RunSlashCommandRPC added in v1.173.0

func (cli *ChatCLI) RunSlashCommandRPC(ctx context.Context, line string) (string, error)

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

func (cli *ChatCLI) SaveSessionRPC(name string, history []models.Message) error

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

func (cli *ChatCLI) SearchSessionsRPC(query string) (string, error)

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

func (cli *ChatCLI) SessionExistsRPC(name string) bool

SessionExistsRPC reports whether a saved session exists in the store.

func (*ChatCLI) SessionModTimeRPC added in v1.179.0

func (cli *ChatCLI) SessionModTimeRPC(name string) (time.Time, error)

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

func (cli *ChatCLI) SetAuditSurface(surface string)

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

func (cli *ChatCLI) SetPolicyAutoMode(on bool)

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

func (cli *ChatCLI) SetRPCDangerPolicy(block bool)

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

func (cli *ChatCLI) SetUnattended(v bool)

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

func (cli *ChatCLI) SetWatching(active bool, statusFunc func() string)

SetWatching configures the K8s watcher state for the CLI.

func (*ChatCLI) SkillContentRPC added in v1.158.0

func (cli *ChatCLI) SkillContentRPC(name string) (string, error)

SkillContentRPC returns a skill's markdown body for prompts/get.

func (*ChatCLI) Start

func (cli *ChatCLI) Start(ctx context.Context)

func (*ChatCLI) StartHubResume added in v1.163.0

func (cli *ChatCLI) StartHubResume(ctx context.Context, principal string) func()

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

func (cli *ChatCLI) StartWatcher(ctx context.Context, cfg k8s.WatchConfig) error

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 FileChunk

type FileChunk struct {
	Index   int
	Total   int
	Content string
}

FileChunk representa um pedaço do conteúdo de arquivos

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

func NewFlagSet() (*flag.FlagSet, *Options)

NewFlagSet cria um FlagSet isolado e as Options para parsing

func Parse added in v1.16.0

func Parse(args []string) (*Options, error)

Parse analisa os args, valida e retorna Options

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

type RPCChatOpts struct {
	Provider string
	Model    string
}

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

type RPCChatTurn struct {
	Reply   string
	History []models.Message
}

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

type RPCResourceContent struct {
	URI      string
	MimeType string
	Text     string
}

RPCResourceContent mirrors rpcserve.ResourceContent.

type RPCResourceInfo added in v1.163.0

type RPCResourceInfo struct {
	URI         string
	Name        string
	Description string
	MimeType    string
}

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

type RPCSkillInfo struct {
	Name         string
	Description  string
	ArgumentHint string
}

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.

func (*SessionEncryptor) Decrypt added in v1.97.0

func (se *SessionEncryptor) Decrypt(data []byte) ([]byte, error)

Decrypt decrypts data that was encrypted with Encrypt. Returns the plaintext. Validates the magic header.

func (*SessionEncryptor) Encrypt added in v1.97.0

func (se *SessionEncryptor) Encrypt(plaintext []byte) ([]byte, error)

Encrypt encrypts plaintext data and prepends the magic header + nonce. Format: CHATCLI_ENC_v1\n + 12-byte nonce + ciphertext (with GCM tag)

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

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).
mcp
* 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

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL