/agent and /coder sessions. This page explains what runs out of the box and which knobs are available when the default behaviour doesnβt fit your workflow.
Every optimization on this page works across all supported providers (Anthropic direct, Bedrock, OpenAI, xAI, ZAI, MiniMax, Moonshot (Kimi), Google AI, Ollama, Copilot, GitHub Models, OpenRouter, OpenAI Responses, StackSpot). Providers with explicit prompt caching (Anthropic, Bedrock Anthropic) or automatic prefix caching (OpenAI, xAI) benefit most.
The real problem
A poorly calibrated ReAct loop can turn a trivial question into huge token bills. Without the optimizations below, a query like βwho won the last Flamengo gameβ can easily burn 20k+ tokens because:- The full system prompt is re-sent on every turn (uncached).
- Tool definitions (15+ JSON schemas) are also re-sent per turn.
- Nothing breaks the loop when the model repeats the same
tool_callwithout converging. - Large
@webfetchbodies land in the context raw.
1. Structured prompt caching
Anthropic caching (and OpenAI/xAI prefix auto-caching) works by prefix: a breakpoint only hits when every byte before it is identical to a prior request. The golden rule is simple β stable blocks first, volatile blocks last. The system prompt is assembled exactly that way: Stable prefix (cached,cache_control: ephemeral):
Volatile suffix (no cache marker β changes every turn):
Each stable block carries
cache_control: ephemeral for Anthropic-family providers (respecting the 4-breakpoint cap, with automatic coalescing). For providers with prefix auto-caching (OpenAI, xAI), the stable ordering ensures cache hits naturally. Chat follows the same ordering; being tool-less, it does not pull memory on demand (see section 7).
Cache on tool definitions
The last tool definition sent to Anthropic also carriescache_control: ephemeral, turning the whole tools array into a cacheable prefix. In a /coder session with 15 coder tools + 2 web tools, this is ~19KB of JSON that stops being re-tokenized every turn.
Cache visibility
OpenAI cached tokens require no opt-in β prompt caching is automatic on
gpt-4o and newer (including o-series and GPT-5), triggered when the prompt prefix is β₯1,024 tokens, with hits served in 128-token increments. For streaming Chat Completions, ChatCLI sets stream_options: {include_usage: true} so the terminal usage chunk arrives before [DONE]; for the Responses API, usage rides on the response.completed SSE event and needs no extra flag./cost β cache hits appear as a separate line. The chat envelope also shows Nβ Mβ on the right border for every provider that surfaces usage, including all OpenAI APIs.
2. Stagnation early-exit
When the model enters a reflection loop β emitting exactly the same batch oftool_calls turn after turn without new information β ChatCLI detects it and breaks the loop.
How it works
Each turn, thetool_calls fingerprint (name + normalized args, order-independent, truncated SHA-256) is computed. Three consecutive turns with the same fingerprint β the loop is stopped with a clear message.
Parameters
3. Smart chat β agent routing
Not every query deserves a full ReAct loop. Conversational / factual questions (βwhat is a mutex?β, βdifference between slice and arrayβ) are answered by a single chat-mode turn. The classifier identifies trivial queries from lexical signals:- Question leaders (
what,why,how does,explain, β¦) - Absence of task verbs (
create,build,run,fix, β¦) - No workspace references (
@file,@git, paths, code extensions) - Short length + a question mark
Modes
Example
4. Smart auto-save in WebFetch
@webfetch is tuned to never dump giant pages into the context. See WebFetch & WebSearch for complete documentation.
Escape hatch
Auto-save always persists the full pre-filter body to
$CHATCLI_AGENT_TMPDIR, and the return carries:
read_file against that path with the right start/end, paying only for the lines that matter.
5. Slimmer system prompts
Mode-specific prompts were condensed without semantic loss β every original rule remains, only redundancy and repeated examples were removed:
Because these prompts live in the core cache block, cache-enabled providers (Anthropic/Bedrock/OpenAI) see the reduction only on the first turn of a session. Providers without caching save those tokens on every turn.
6. Proactive tool result compaction
Old tool results (file reads, search, git-diff, etc.) are progressively compressed in the history to keep the payload lean. See Tool Result Management for the full pipeline. Defaults are conservative to protect multi-turn workflows with cross-references (large refactors, review sessions). Users who want to squeeze harder can tune:7. Pull-first memory (index + recall)
Pushing the whole memory into the system prompt every turn doesnβt scale: the cost grows with the store size and is re-sent each turn. ChatCLI now defaults to a pull model: it injects only a stable digest and lets the agent pull detail on demand via the@memory recall tool.
Controlled by CHATCLI_MEMORY_MODE:
The
index is stable (turn-independent, no timestamp), so it lives in the cached prefix (section 1) and is size-capped regardless of store size. @memory recall uses the full retrieval stack (HyDE + vector cosine search + keyword extraction), so pulled detail matches the quality of the old push.
Proactive auto-recall (CHATCLI_MEMORY_AUTORECALL, on by default) adds a tiny hint-driven top-3-facts block per turn β but it rides in the uncached trailing region next to the wall-clock context, never in the stable digest, so the cached prefix stays byte-identical and none of the savings above are given back. See Bootstrap and Memory for details.
Measured impact
Measured against a real store of 500 facts (MEMORY.md ~32KB, fact index ~270KB):
β87.7% on the per-turn memory block β and unlike
full (capped by CHATCLI_MEMORY_RETRIEVAL_BUDGET), the index does not grow as memory grows.
Chat is tool-less by design and cannot pull on demand: there
index automatically degrades to full, and only off suppresses memory. The active mode is shown in /config memory.Measuring impact
Run your session normally and check/cost at the end:
Cache read> 0 and growing per turn β structured caching is hitting the prefix.- Few/no FORMAT ERROR in logs β reminders are holding format on smaller models.
- Turns with
tool_calls = 0followed by quick completion β early-exit detected convergence. [auto-saved: response was N bytes]markers in@webfetchresults β inline budget is protecting context.
Variable summary
Every variable on this page in one place:Related
- Native Tool Use β how
cache_control:ephemeralpropagates to Anthropic/Bedrock. - Tool Result Management β the compaction pipeline in detail.
- Cost Tracking β how
/costand the catalog compute real per-turn cost. - WebFetch & WebSearch β filters, save_to_file, and backend fallback.