Skip to main content
Starting with the post-#920 release, ChatCLI ships a set of atomic tools modeled on Claude Code’s narrow architecture: each common read-only operation gets its own plugin with a dedicated schema instead of living inside the @coder envelope.
Atomic tools coexist with @coder@coder read/search/tree keeps working. The difference is that the LLM can now pick the narrow tool (more precise) when it wants to execute a single read-only operation.

The four tools

@read — file read

Equivalent to Claude Code’s Read. Flat schema:
{"file": "main.go", "from_line": 10, "to_line": 50}
Aliases accepted: path, filepath. Line range, head/tail, and base64 encoding supported. Output cap: 80 000 chars (versus the 30k global) — large files (~1500 lines) fit whole. Equivalent to Claude Code’s Grep. Flat schema:
{"term": "Login", "dir": "./src", "include": "*.go"}
Aliases: pattern, query, regex. Include glob and configurable result cap. Output cap: 60 000 chars.

@tree — directory tree

Flat schema (all optional — {} lists the cwd):
{"dir": "./src", "depth": 3, "exclude": "node_modules"}
Depth bound [1,20]. Output cap: 50 000 chars.

@todo — task plan management

Parity with Claude Code’s TodoWrite. Three subcommands:
// Replace the entire plan (canonical TodoWrite)
{"cmd":"write","args":{"todos":[
  {"description":"Investigate bug","status":"completed"},
  {"description":"Apply fix","status":"in_progress"},
  {"description":"Add tests","status":"pending"}
]}}

// List the current state
{"cmd":"list"}

// Mark ONE task by 1-indexed id
{"cmd":"mark","args":{"id":2,"status":"completed"}}
Status values: pending | in_progress | completed | failed. The @todo adapter routes into the active AgentMode’s cli/agent/task_tracker.go.

Why narrow tools matter

@coder (fat)@read / @search / @tree (narrow)
LLM accuracySingle schema, model picks wrong subcommandDedicated schema, ~10pp more accurate
ParallelizationNo (mixes read and write)Yes (IsConcurrencySafe=true)
Permission gateFalls through to policy regexAuto-allow via capability
Streaming UXGeneric “@coder read""Reading: main.go”
TruncationGlobal 30kPer-tool 50k/60k/80k

Transactional multipatch

New in @coder:
{"cmd":"multipatch","args":{"edits":[
  {"file":"a.go","search":"old","replace":"new"},
  {"file":"b.go","search":"foo","replace":"bar"}
]}}
Phase 1 validates EVERY edit before any write. Phase 2 commits — any failure restores all touched files. Per-file mutex serializes concurrent transactions on the same file. Use this when a refactor needs to be all-or-nothing.

JSON Schema validation

Every atomic plugin ships a draft-2020-12 JSON Schema. The agent loop validates LLM args before calling Execute. Failures return ToolResult{IsError:true, ErrorCode:"InvalidArgs"} with the offending JSON path named — the model gets clear feedback instead of a panic/empty result. Legacy plugins without JSONSchemaAware bypass validation (purely additive change).

Capability-aware permission gate

The policy_manager now consults the capability resolver before falling through to the default ActionAsk:
  1. Deny rules (strictest)
  2. Safety-immune (always asks)
  3. Explicit allow/ask (longest pattern wins)
  4. Read-only exec heuristic
  5. NEW: capability gate — auto-allow plugins with IsReadOnly=true
  6. Default: Ask
Result: @read, @search, @tree, @websearch, @webfetch (GET), @scheduler query/list run without a security prompt while write/exec stay gated.