cli

package
v1.189.0 Latest Latest
Warning

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

Go to latest
Published: Aug 24, 2026 License: Apache-2.0 Imports: 102 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

  • 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 - /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 - 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 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 - /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 - 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

  • 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

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

  • 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

  • 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 - 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

  • 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.

  • 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 - 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.

  • 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

  • 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

  • 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

  • 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 *

  • /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 - 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.

  • 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 *

  • /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 - 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

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 (
	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 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 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 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.

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.

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

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 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 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) 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) 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) 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) 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)

	// 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 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 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 (*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

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 (*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) CheckBudget added in v1.99.0

func (ct *CostTracker) CheckBudget() BudgetLevel

CheckBudget returns the current budget level.

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) 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) GetSummary added in v1.97.0

func (ct *CostTracker) GetSummary(provider, model string, history int) string

GetSummary returns a formatted cost summary string.

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) RecordRealUsage added in v1.99.0

func (ct *CostTracker) RecordRealUsage(provider, model string, usage *models.UsageInfo)

RecordRealUsage records actual token usage from an API response. This is the preferred path — provides accurate cost tracking.

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) 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) 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) 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"`

	// 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"`
}

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.

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 (*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.
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