GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • ChatCLI home page
  • Cookbook
  • Releases
  • diillson/chatcli
  • Install
  • Quickstart
  • Docker & Kubernetes
  • Auto-Update
  • Config Migration
  • Basic Usage
  • Context Commands
  • Agent Mode (/agent)
  • Coder Mode (/coder)
  • One-Shot Mode

This view

  • Original page
  • New address

GeezerVison is showing chatcli.edilsonfreitas.com — Coder Mode (/coder) - ChatCLI

The /coder mode is specialized for software engineering tasks with a read, modify, and feedback cycle. It provides more rigor than /agent, because the assistant follows an output contract so that ChatCLI can execute actions safely (with rollback semantics).

​
When to Use

Use /coder for...

Real changes to the repository, running tests/lint/build automatically, applying patches with rollback, iterating until a verifiable result.

Use /agent for...

High-level conversations, writing text, ideas, plans — without executing code directly.

​
Handoff from chat

You do not have to know in advance that a request needs the workspace. In chat mode the assistant recognizes it (changing code, running or debugging the project, multi-step work in the repository), answers briefly with its understanding, and proposes the switch itself:
  🛠  The assistant proposes switching to coder mode for this task:
     Fix the failing parser tests in cli/parser_test.go
     Press Enter (or y) to enter coder mode, n to stay in chat; anything else continues the chat.
Your next input is the answer: Enter (or y, yes, s, sim, ok) enters coder mode with that task, exactly as if you had typed /coder <task>; n / no stays in chat; any other text is a normal chat turn and the proposal is dropped. Plain text never changes mode on its own — you always confirm. The proposal is only made on an attended interactive session; the gateway, MCP/ACP and one-shot (-p) surfaces never receive it. Set CHATCLI_CHAT_CODER_HANDOFF=false to turn it off (see environment variables).

​
Engineering Flow


​
Multi-Agent Orchestration

/coder includes multi-agent orchestration enabled by default. The orchestrator LLM dispatches specialized agents in parallel:
AgentRole
FileAgentCode reading and analysis (read-only)
CoderAgentCode writing and modification
ShellAgentCommand execution and testing
GitAgentVersion control operations
SearchAgentCodebase search (read-only)
PlannerAgentReasoning and task decomposition (no tools)
ReviewerAgentCode review and quality (read-only)
TesterAgentTest generation and coverage
RefactorAgentStructural transformations (rename, extract, move)
DiagnosticsAgentTroubleshooting and error investigation
FormatterAgentCode formatting and style
DepsAgentDependency management and auditing
Custom AgentsPersonas from ~/.chatcli/agents/ registered automatically
Each agent has its own skills and executes in its own isolated mini ReAct loop. Multiple agents run simultaneously via goroutines with a configurable semaphore (CHATCLI_AGENT_MAX_WORKERS).
Disable with CHATCLI_AGENT_PARALLEL_MODE=false if needed. See the full documentation.

​
Output Contract

The assistant’s response format in /coder is mandatory:
1

Reasoning

Before any action, the assistant writes a short reasoning block (2 to 6 lines).
2

Tool Call

If it needs to act, it emits a tool_call name="@coder" args="..." with JSON in the args.
3

No direct commands

It never uses code blocks or direct shell commands — everything goes through @coder.

​
Contract Validation and Enforcement

When the AI violates the output contract, ChatCLI automatically detects it and injects a format correction feedback message. The turn is reprocessed until the format is correct. The enforcement rules are:
Detected ViolationInjected Feedback
tool_call uses a tool other than @coderFormat error — only @coder is allowed in /coder mode
tool_call missing but code blocks present”Code blocks are not allowed, use @coder”
<plan> missing before tool_call”A plan block is required before any tool_call”
Loose shell commands detected (e.g., $ go test)“Use @coder exec, not direct commands”
If the AI persists in violating the contract after multiple attempts, ChatCLI aborts the turn and displays a warning to the user. This rarely happens with modern models.
Internally, validation occurs in agent_coder_validation.go — a dedicated module that inspects each AI response before executing any tool_call. The sequence is:
  1. Parse the response — extract <plan>, <tool_call>, code blocks, and loose text
  2. Plan check — if <tool_call> exists but <plan> does not, reject
  3. Tool name check — if the tool_call name is not @coder, reject
  4. Code block check — if code blocks (```) are present in the response, reject
  5. Shell pattern check — detect patterns like $ cmd, > cmd, run: cmd
  6. If any check fails, inject feedback and retry the turn (up to 3 attempts)

​
Internal Difference Between /coder and /agent

Both modes use the same ReAct loop (processAIResponseAndAct). The difference is in configuration, not architecture:
Aspect/coder/agent
System PromptCoderSystemPrompt (full) or CoderFormatInstructions (when persona active)AgentFormatInstructions
Output formatStrict: <plan> + <tool_call name="@coder"> onlyFlexible: any tool, execute blocks, free text
ValidationActive (isCoderMode=true) — rejects violationsDisabled — accepts any valid format
Tool contextCompact: required flags only, 1-2 examples per subcommandFull: all flags, multiple examples
HistoryShared (unified history)Shared (unified history)
Multi-agentSupports <agent_call>Supports <agent_call>
Format anchorReminds about <plan> + @coder each turnReminds about tool_call and execute each turn
In practice, /coder is /agent with additional guardrails. If you switch from /agent to /coder mid-conversation, the history is preserved — only the validation rules and system prompt change.
The isCoderMode flag is what activates all the differences. When true:
  • The contract validator runs on every response
  • The tool context is reduced to save tokens
  • The format anchor is specific to @coder
  • The system prompt describes content as JSON text, with base64 optional

​
Task Tracker and Progress

When the AI includes a <plan> block with numbered tasks (e.g., “1. Read files\n2. Apply patch\n3. Run tests”), the TaskTracker automatically parses this and creates a TaskPlan:

​
How it works

  1. Parse: Each numbered line becomes a Task with initial status Pending
  2. Tracking: As tool_calls are executed, the current task’s status is updated
  3. Rendering: Progress appears below the reasoning as compact status lines

​
Task status

StatusMeaning
PendingWaiting for execution
InProgressBeing executed in the current turn
CompletedTool_call executed successfully
FailedTool_call returned an error

​
Automatic replanning

If 3 or more tasks fail consecutively, the TaskTracker signals NeedsReplan = true. ChatCLI then injects a system message asking the AI to reformulate its plan before continuing. The TaskTracker also computes a signature (hash) of the plan. If the AI changes its plan between turns (e.g., adds or removes tasks), the tracker detects the change and restarts tracking with the new plan.
The TaskTracker is purely informational for the user — it does not block execution. Even if the progress shows “Failed”, the AI may decide to ignore the error and continue.

​
TodoWrite parity — @todo plugin

Beyond the TaskTracker (which automatically extracts tasks from the <plan> block), agent mode also exposes an atomic plugin @todo with parity to Claude Code’s TodoWrite. The AI can explicitly emit:
<tool_call name="@todo" args='{"action":"write","tasks":["read main.go","apply patch","run tests"]}' />
<tool_call name="@todo" args='{"action":"mark","index":1,"status":"done"}' />
<tool_call name="@todo" args='{"action":"list"}' />
The list is shared with the TaskTracker via liveTodoAdapter, so the checkbox UI renders the same plan that appears in <plan>. Details in Atomic Tools.

​
Content encoding: JSON text by default, base64 optional

For write and patch, content travels as an ordinary JSON string inside the single-line args: newlines as \n, quotes as \", backslashes as \\, tabs as \t. The tool-call parser hands the JSON escapes to the JSON decoder untouched, keeps backtick spans inside args intact (a Go raw string, a Markdown snippet being written) and tolerates apostrophes, so plain text reaches the disk byte for byte. Base64 is no longer mandated: it costs about a third more tokens and models corrupt long payloads.

​
When base64 still helps

  • Binary files (images, archives).
  • Content dense with quotes and backslashes that the model would rather not escape.
In both cases add "encoding":"base64"; the payload is validated and never repaired silently.

​
Encoding rules

OperationRule
write --contentJSON text by default; --encoding base64 optional
patch --search / --replaceJSON text by default; --encoding base64 optional
patch --diffUnified diff as text; --diff-encoding base64 optional
read, search, treeNot applicable (output is always text)

​
The --encoding flag

The --encoding flag controls content interpretation:
  • text (default): content is interpreted as literal text
  • base64: content is decoded from base64 before being written
# Example: writing plain text (newlines escaped inside the JSON string)
<tool_call name="@coder" args='{"cmd":"write","args":{"file":"main.go","content":"package main\n\nfunc main() {}\n"}}' />

# Example: a binary file with base64
@coder write --file logo.png --content "iVBORw0KGgo..." --encoding base64

​
System Prompt Composition in /coder

The system prompt is assembled in layers, in the following order:
1

Layer 1: Persona or CoderSystemPrompt

If a custom persona is active (e.g., --persona senior-go), the persona prompt is used as the base. Otherwise, the default CoderSystemPrompt is used.
2

Layer 2: CoderFormatInstructions

When a persona is active, CoderFormatInstructions are appended to the persona prompt. This ensures the persona respects the /coder output contract. When no persona is active, the instructions are already embedded in the CoderSystemPrompt.
3

Layer 3: Workspace Context

Project context files are injected via contextBuilder:
  • SOUL.md — personality and global guidelines
  • USER.md — user preferences
  • RULES.md — project-specific rules
4

Layer 4: Tool Context

The compact @coder schema is included: list of subcommands, required flags, and 1-2 examples per subcommand. In /coder mode, this context is reduced compared to /agent to save tokens.
5

Layer 5: Multi-Agent Orchestrator Prompt

If parallel mode is active (CHATCLI_AGENT_PARALLEL_MODE=true), the multi-agent orchestrator prompt is appended with the list of available agents and dispatch instructions.

​
Format Anchor (Per-Turn Reminder)

At each turn of the ReAct loop, a short format reminder is appended to the message history. This prevents the AI from “forgetting” the format rules in long conversations.

​
In /coder mode

The anchor reminds about:
  • Mandatory format: <plan> followed by <tool_call name="@coder">
  • Prohibition of code blocks and direct commands
  • Base64 encoding requirement for file writes

​
In /agent mode

The anchor reminds about:
  • tool_call and execute block format
  • Tools available in the current turn
The anchor is a prompt engineering technique to maintain format adherence. Without it, models tend to “drift” into free text after 10-15 turns of conversation. The anchor is short (3-5 lines) to avoid consuming excessive tokens.

​
Tools and Dependency

The /coder mode uses the @coder plugin, which comes built into ChatCLI — no additional installation required.
Check with /plugin list — @coder appears with the [builtin] tag.

​
Supported Subcommands

SubcommandDescription
tree --dir .List directory tree
search --term "x" --dir .Search the codebase
read --file xRead file
write --file x --content "..."Write file (--encoding base64 optional)
patch --file x --search "..." --replace "..."Apply patch
patch --diff "..."Apply unified diff (--diff-encoding base64 optional)
exec --cmd "command"Execute command
git-status --dir .Git status
git-diff --dir .Git diff
git-log --dir .Git log
git-changed --dir .Changed files
git-branch --dir .Current branch
test --dir .Run tests
rollback --file xRevert change
clean --dir .Clean backups
delegate --prompt "..." --tools [...]Delegate sub-task to a subagent with isolated context — see Subagent Delegation
/coder mode also receives the CHATCLI_AGENT_TMPDIR variable pointing to the session scratch dir. It is the recommended path for creating temporary scripts and intermediate files without polluting the project.

​
Example Flow

1

List the tree

tree --dir .
2

Search for occurrences

search --term "FAIL" --dir .
3

Read relevant files

read --file cli/agent_mode.go
4

Apply patch

patch --file cli/agent_mode.go --search "..." --replace "..."
5

Run tests

exec --cmd "go test ./..."

​
Operation Parallelization

/coder maximizes parallelism by emitting multiple tool_calls in a single response when operations are independent. For example, when needing to read 3 files, the AI emits 3 tool_call tags at once instead of one per turn. A failure inside such a batch does not throw the rest away: the failed action reports its error, the read-only siblings still run, and only a mutating sibling (write, exec, patch…) is skipped — with a note saying it was skipped because an earlier action failed — so nothing builds on a broken step. A read-only tool that hits a transient failure (timeout, connection reset, DNS hiccup, 429/5xx) is retried once before the failure reaches the model; mutating tools are never retried, since the first attempt may have landed. For complex tasks with 3+ independent operations, the AI uses <agent_call> to dispatch specialized agents in parallel via goroutines.
If you notice the AI performing sequential operations that could be parallel, remind it: “emit all independent tool_calls in a single response”.

​
User Interaction (Ask When Needed)

The AI doesn’t always have all the information needed to execute a task. When it needs data that only the user can provide (database choice, framework, credentials, options), the AI asks directly instead of guessing.

​
How It Works

When the AI responds without emitting any tool_call (just text with a question), ChatCLI detects this and:
  1. Displays the AI’s question normally
  2. Shows a Waiting for your response... prompt instead of ending the session
  3. Waits for the user to type a response
  4. Adds the response to the history and continues the ReAct cycle
+-- RESPONSE
|  I need information before proceeding:
|  1. Which database? (PostgreSQL, MySQL, SQLite)
|  2. Which library? (pgx, GORM, sqlx)
|  3. Database host and port?
+--------------------------------------------------

  Waiting for your response (--- for multiline, 'exit' to finish): PostgreSQL, pgx, localhost:5432
The AI receives the response and continues with <plan> + <tool_call> as usual.

​
Multiline Responses

For complex responses, use multiline mode with --- (``` is also accepted as a fence opener):
  Waiting for your response: ---
  Multiline mode — type --- on a new line to finish
  ... [1] PostgreSQL on port 5432
  ... [2] Host: db.internal
  ... [3] Use pgx as driver
  ... [4] Schema: public
  ... [5] ---

​
Coder-mode prompt UX (parity with chat)

The input that appears while /coder is waiting for your reply uses the same readline engine as chat mode (go-prompt + BracketedPasteParser). That means:
FeatureBehavior
WidthGrows to the real terminal width — no 80-column cap
Bracketed pastePasted multiline content is preserved (does not submit on the first newline)
EditingArrows, Home/End, Ctrl+A/E, word navigation (Alt/Ctrl+arrows)
Paste detectionLarge pastes are captured via placeholder (same mechanism as chat) and expanded before going to the AI
Non-TTY stdin (pipes, CI)Automatic fallback to bufio.Reader — the agent still reads one line per iteration
This input used to be a stripped-down golang.org/x/term reader that capped at 80 columns and treated each pasted \n as Enter. If you still see that behavior, update ChatCLI — the chat-parity holds on any modern terminal.

​
Exiting the Session

To end the session when the AI is waiting, type:
  • exit, quit, or sair
  • Or press Ctrl+C
This feature is enabled by the “ASK WHEN NEEDED” rule in the /coder system prompt. The AI is instructed not to emit tool_calls when it needs user-provided information, but instead ask the question directly. This ensures ChatCLI detects the question and waits for the response.

​
FAQ

Can I use JSON in args?

Yes, it is the recommended format:tool_call name="@coder" args='{"cmd":"read","args":{"file":"main.go"}}'

When should I use patch --diff?

When the change involves multiple sections or requires more precision. It accepts unified diff in text or base64.

Do I need to install @coder separately?

No. @coder is a builtin plugin — it comes embedded in the binary. If you install a custom version in ~/.chatcli/plugins/, it will take precedence over the builtin.

Is exec safe?

@coder exec blocks dangerous patterns by default. For sensitive commands, prefer using the Git subcommands and test.

Is there a read limit?

Yes. Use read --max-bytes, --head, or --tail to control the output size.

How does /coder handle AI format errors?

ChatCLI validates every response from the AI against the output contract. If a violation is detected (e.g., direct code block, wrong tool, missing reasoning), a format correction feedback message is injected into the history and the turn is reprocessed. The AI gets up to 3 attempts to correct the format. In practice, modern models get it right on the first or second turn.

Can I use /coder with a custom persona?

Yes. When a persona is active (e.g., --persona senior-go), the persona prompt is used as the base and CoderFormatInstructions are automatically appended. This ensures the persona respects the /coder output contract without losing its custom personality.

What is the Task Tracker?

It is a module that parses numbered tasks from the AI’s <plan> block (e.g., “1. Read files\n2. Apply patch”). Each task receives a status (Pending, InProgress, Completed, Failed) that is updated as tool_calls are executed. Progress is displayed in the interface. If 3+ tasks fail, ChatCLI asks the AI to reformulate its plan.

Is base64 required for write?

No. Content is a normal JSON string (newlines as \n, quotes as \") and reaches the disk byte for byte: the parser keeps JSON escapes and backtick spans inside args intact. Use "encoding":"base64" only for binary files or content so dense with quotes and backslashes that escaping it is error-prone.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.