How to Optimize Coding Agent Costs: Research Notes from Prompt Cache to Context Engineering

71 min

This post was written in May 2026. Everything here is research findings that have not yet been put into practice in our projects. This space moves extremely fast — please keep timeliness in mind as you read.

This is a long read — roughly 20,000 words, about 30–40 minutes.

TL;DR

  • The bulk of coding agent costs come from input tokens (93–99% of total tokens), because every API call resends the full context
  • The most effective cost lever is Prompt Cache (cached input is 10x cheaper). Setting up cache discipline (fixing prefix order, cleaning up unused MCP tools) is a one-time config change with lasting benefits
  • Context Engineering breaks down into four directions: Select (get the right code in), Compress (shrink existing context), Isolate (split tasks, swap models), Write (persist information to the filesystem)
  • Model tiering (Haiku for exploration, Sonnet for implementation, Opus for architecture) can cut costs several-fold without changing total token volume
  • External memory written to files (SPEC.md, planning-with-files, session handoff) lets work persist across sessions, but maintenance is an open problem (code changes, docs don’t follow)
  • Using my real session token counts (Input 1.62M, Output 128.1K, Opus 4.6) for a rough estimate: from $11.30 with no optimization to roughly $4–5 assuming all measures are in place. This is an estimate based on reasonable assumptions (70% cache hit rate, etc.), not a measured result

The Trigger

Our team has been using GitHub Copilot as a development tool. Recently, GitHub Copilot announced it would transition to usage-based billing starting in June. I roughly estimated our team’s usage and figured costs would likely triple. That prompted me to conduct a round of research into open-source cost optimization solutions for coding agents currently available on the market, which I am publishing here in hopes it may serve as a useful reference. I have been using Claude Code personally, while my team is on OpenCode, so the discussion below focuses primarily on these two.


Pricing Tables

To save money, you first need to understand how you are being charged. The following numbers come from the official pricing pages of Anthropic, OpenAI, and GitHub as of May 2026.

Claude vs. GPT Pricing Comparison

ModelInput ($/MTok)Output ($/MTok)Cached InputCache Write (5min)
Claude Opus 4.6 (1M)$5.00$25.00$0.50$6.25
Claude Sonnet 4.6$3.00$15.00$0.30$3.75
Claude Haiku 4.5$1.00$5.00$0.10$1.25
GPT-5.5$5.00$30.00$0.50— (automatic)
GPT-5.4$2.50$15.00$0.25—
GPT-5.4 mini$0.75$4.50$0.075—

GitHub Copilot AI Credits

The new billing model uses AI Credits, where 1 AI Credit = $0.01 USD. Consumption is based on each request’s input tokens, output tokens, cached tokens, and the model’s unit price.

PlanMonthly FeeIncluded AI Credits
Pro$10$10 (1,000 credits)
Pro+$39$39 (3,900 credits)
Business$19/user$19/user
Enterprise$39/user$39/user

The table makes a few things immediately clear. Cached Input costs one-tenth of regular Input. Opus 4.6’s input is $5/MTok, but a cache hit brings it down to $0.50/MTok — at an 80% hit rate, input costs effectively drop to 20%. Output is five times more expensive than input: Opus 4.6 is $25 vs. $5, and GPT-5.5 is even more extreme at $30 vs. $5. Reasoning/Thinking tokens are also billed at the output rate, so the more the model “thinks,” the more you pay.

The optimization priority is clear: first, get input to hit the cache (a 10x cost difference); then reduce unnecessary input; and finally, control output.

So the first question I investigated was: what exactly is Prompt Cache? Why can it make input ten times cheaper? To answer that, I needed to first understand the basic workflow of how a large language model processes a request.


The Complete Workflow of a Single LLM Request

flowchart TD
    A["📝 Input Text"] --> B["① Tokenization\nSplit text into tokens (subword units)"]
    B --> C["② Embedding\nMap each token to a high-dimensional vector"]

    subgraph prefill["Prefill Phase (processes all input at once — the expensive part)"]
        C --> D["③ Transformer Layers × N\nEach layer: Self-Attention + Feed-Forward Network\nComputational cost O(n²)"]
    end

    subgraph decode["Decode Phase (generates output token by token, reuses KV Cache)"]
        D --> E["④ Predict probability distribution of next token"]
        E --> F["⑤ Sample and output one token"]
        F --> G{Done generating?}
        G -->|"No"| H["Add new token to sequence\nReuse existing KV Cache\nOnly compute attention for the new token"]
        H --> E
    end

    G -->|"Yes"| I["🏁 Complete Response"]

    style prefill fill:#fff0f0,stroke:#cc0000
    style decode fill:#f0f7ff,stroke:#0066cc
    style D fill:#ff6b6b,color:#fff,stroke:#cc0000

Prompt Cache skips the red Prefill phase. If the input prefix of the current request matches the previous one, it directly reuses the previous computation results, saving the O(n²) overhead.

The diagram above is an overview. Let me break down each step to see where the money actually goes.

Tokenization

Models do not understand “text.” Every piece of code and every sentence sent to the API is first split into tokens (subword units).

tokens = tokenizer("帮我修一下 billing 里的 bug")
# → [帮, 我, 修一下, billing, 里的, bug]
# → [24891, 1588, 78432, 53012, 9876, 31205]

The splitting algorithm is typically BPE (Byte Pair Encoding). The principle: start with individual bytes, count which byte pairs appear most frequently together in the training corpus, merge them into a new token, and repeat — ultimately building a vocabulary of tens of thousands to hundreds of thousands of entries. High-frequency words (“the”) become a single token, while low-frequency words get split into multiple subwords.

flowchart LR
    A["'帮我修一下 billing 里的 bug'"] --> B["Tokenizer\n(BPE Algorithm)"]
    B --> C["[24891, 1588, 78432, 53012, 9876, 31205]"]
    C --> D["6 tokens"]

    style B fill:#4ecdc4,color:#fff,stroke:#2ba89e

Here is roughly what the splitting looks like:

Input TextResulting TokensToken Count
帮我修一下 billing 里的 bug帮 + 我 + 修一下 + billing + 里的 + bug6
你好世界你好 + 世界2
calculateUsagecalculate + Usage2
const x = 42;const + x + = + 42 + ;5
不可变数据结构不可 + 变 + 数据 + 结构4

The “per million tokens” in the pricing table refers to these tokens. OpenAI’s Tokenizer tool and Anthropic’s token counting API both let you see how many tokens your code actually produces.

There is one detail here that directly affects cost. Different models use different tokenizers, so the same text may produce noticeably different token counts across models. Opus 4.7 adopted a new tokenizer; Anthropic’s official statement was that it “improved how the model processes text, at the cost of the same input potentially mapping to more tokens — roughly 1.0-1.35x.” Simon Willison ran actual tests: the same system prompt produced 7,335 tokens on Opus 4.7 versus only 5,039 on 4.6 — a 46% increase. The per-token price did not change, but the same text now requires more tokens, resulting in a 12-27% increase in the actual bill. This kind of “hidden price increase” is easy to overlook when comparing costs across models.

Embedding

At this point, a token is just an ID number — say, entry #53,012 in the vocabulary. A single integer carries no semantic information, and the model cannot directly compute with it.

What Embedding does is assign a high-dimensional vector to each token. Concretely, it looks up a large table (a matrix of vocabulary size × vector dimension), uses the token ID as the row index, and retrieves the corresponding row of floating-point numbers.

flowchart LR
    A["token #53012\n'billing'"] --> B["Look up Embedding Table\n(vocab size × 4096)"]
    B --> C["[0.12, -0.85, 0.33, ..., 0.07]\n4096-dimensional vector"]

    D["token #31205\n'bug'"] --> B

    style B fill:#9b59b6,color:#fff,stroke:#7d3c98

Think of it as assigning each word a coordinate in a 4096-dimensional space. Semantically similar words end up with nearby coordinates: “dog” and “puppy” have close vectors, while “dog” and “spreadsheet” are far apart. This step is computationally lightweight — just a table lookup, very fast.

However, embeddings have one limitation: the vector assigned to each word is fixed and does not consider context. “bank” in “river bank” and “bank account” gets the same vector — it cannot distinguish between “riverbank” and “financial institution.”

That problem is resolved in the next step.

Transformer and Self-Attention

The Transformer is a model architecture proposed by Google in the 2017 paper “Attention Is All You Need.” Today, virtually all large language models (GPT, Claude, Gemini, LLaMA) are built on it.

Before the Transformer, sequence data was primarily handled by RNNs (Recurrent Neural Networks). RNNs had two problems: first, they had to process words sequentially one by one, making long sequences very slow and unable to leverage GPU parallelism; second, information from earlier in the sequence would gradually decay — by the end of a 2,000-word text, the content from the beginning had already become blurry. The Transformer replaced sequential processing with the Self-Attention mechanism, allowing every token to simultaneously attend to all other tokens in the sequence — enabling both parallelism and long-range information preservation.

Returning to the “bank” example. Embedding gives “bank” a fixed vector that cannot distinguish between the two meanings. Self-Attention addresses this by letting “bank” look at other words in the same sentence: if “river” is nearby, its representation shifts toward the “riverbank” meaning; if “deposit” is nearby, it shifts toward the “financial institution” meaning.

Self-Attention Figure: Self-Attention matrix computation — Query × Key produces attention scores, which are then multiplied with Value (Source: Jay Alammar, The Illustrated Transformer)

Let me illustrate the mechanism with a simplified numerical example. Suppose the sequence has only 3 tokens: I, went, bank, and each token’s embedding is a 2-dimensional vector (in practice it would be 4096 dimensions — simplified here).

Each token’s vector passes through three weight matrices W_Q, W_K, W_V, generating three new vectors:

  • Query (Q): “What information am I looking for?”
  • Key (K): “What information can I provide?”
  • Value (V): “My actual content.”
           Q          K          V
I     [1.2, 0.3]  [0.5, 1.1]  [0.8, 0.2]
went  [0.7, 0.9]  [1.0, 0.4]  [0.3, 0.7]
bank  [1.1, 0.6]  [0.8, 0.9]  [0.6, 0.5]

For “bank,” we compute dot products between its Q and every token’s K to get attention scores:

bank_Q · I_K    = 1.1×0.5 + 0.6×1.1 = 1.21
bank_Q · went_K = 1.1×1.0 + 0.6×0.4 = 1.34
bank_Q · bank_K = 1.1×0.8 + 0.6×0.9 = 1.42

After softmax normalization, these become a probability distribution (summing to 1), which is then used to compute a weighted sum of V, producing bank’s new representation in this sentence.

flowchart TD
    subgraph attn["Attention Weight Example: 'I went to the bank to deposit money'"]
        direction LR
        B["bank"] -->|"0.35"| D["deposit"]
        B -->|"0.28"| M["money"]
        B -->|"0.15"| W["went"]
        B -->|"0.12"| T["to"]
        B -->|"0.10"| I["I"]
    end
    style B fill:#ff6b6b,color:#fff
    style D fill:#ffd93d,color:#333
    style M fill:#ffd93d,color:#333

In the full sentence, “bank” pays the highest attention to “deposit” and “money,” so its representation shifts toward the “financial institution” meaning. If the sentence were “I sat on the bank by the river,” the weight distribution would be completely different.

This is the fundamental reason why longer contexts cost more. With n tokens of context, every token must compute its relationship with every other token — that is n × n dot product operations. A 100,000-token context means 10 billion attention computations per layer. This is not linear growth; it is quadratic growth, O(n^2).

flowchart TD
    subgraph layer["Single Transformer Layer (repeated N times)"]
        direction TB
        T["Input: vector representation of each token"] --> Q["Generate Query vectors\n'What am I looking for?'"]
        T --> K["Generate Key vectors\n'What can I provide?'"]
        T --> V["Generate Value vectors\n'My actual content'"]
        Q --> S["Query × all Keys\n→ Attention score matrix\n(n × n — this is where O(n²) comes from)"]
        K --> S
        S --> W["Scores × Values weighted sum\n→ New representation for each token"]
        V --> W
        W --> F["Feed-Forward Network\nNon-linear transformation (fixed compute cost)"]
        F --> O["Output: updated token vectors"]
    end

    style S fill:#ff6b6b,color:#fff,stroke:#cc0000
    style layer fill:#f9f9f9,stroke:#ccc

The red portion is the core of the cost: pairwise relationship computation among n tokens. The longer the context, the larger this matrix.

Modern large language models have tens to over a hundred such Transformer layers, each performing two operations: Self-Attention plus a Feed-Forward Network (a non-linear transformation of the attention results, with fixed computational cost that does not scale with context length).

For a more intuitive understanding of this process, Georgia Tech’s interactive Transformer Explainer lets you visualize every step of the computation in real time.

Prefill: Processing All Input at Once

From Tokenization to Embedding to N layers of Transformer Self-Attention — this entire pipeline runs on all the input tokens you send, processed in one parallel pass. This phase is called Prefill.

Prefill is the most computationally intensive part of the entire inference process. If you send a 60k-token context, every Transformer layer must compute a 60k × 60k attention matrix. The input token fees on the pricing table are primarily paying for this.

Prefill also produces an important byproduct: during Self-Attention computation, the Key and Value vectors for every input token have already been calculated. These K/V vectors are stored in GPU memory, forming the initial KV Cache. During the subsequent Decode phase, when generating new tokens, the model does not need to recompute K/V for older tokens — it simply retrieves them from the cache.

In other words, the KV Cache is built during the Prefill phase and used and grown during the Decode phase.

There is an interesting idea here: since Prefill performs the same general operations (Tokenization → Embedding → Transformer layers) for all models based on the same architecture, could Prefill computation results be shared across different models? For example, could you Prefill the same system prompt once and share the K/V Cache across multiple models?

Academia is already exploring this direction. A paper from early 2026, PrefillShare, proposed a cross-model Prefill sharing scheme: split the model into Prefill and Decode components, freeze the Prefill module, and only fine-tune the Decode module, allowing multiple task-specific models to share a single Prefill KV Cache. Empirical results showed p95 latency reduced by 4.5x and throughput improved by 3.9x under multi-model agent workloads. Industry is moving in the same direction — vLLM, SGLang, and NVIDIA Dynamo are all building Prefill-Decode disaggregated architectures, splitting Prefill and Decode into independently deployable and scalable services. These are still fairly cutting-edge infrastructure-level efforts that regular API users cannot access yet, but they demonstrate that the space for Prefill computation reuse is larger than one might expect.

Now let us move to the generation phase.

Decode

After Prefill completes, the final layer outputs a probability distribution: “What is the most likely next token?” A token is selected according to the sampling strategy, added to the sequence, and the entire stack of layers is run again to generate the next token. This loop continues until the model outputs a stop token.

This token-by-token generation process is called Decode. Each time a new token is generated, it theoretically needs to attend to all preceding tokens — that is, recompute Key and Value vectors for all tokens. But the K/V for previous tokens were already computed in the prior step and have not changed, so recomputing everything would be wasteful.

This is precisely why, as mentioned in the previous section, we store those computation results in GPU memory — caching each token’s computed Key and Value vectors so that when generating the next token, we can directly reuse them and only need to compute a new set of Q/K/V for the new token. Let me illustrate using the matrix example from earlier:

Prefill phase — all 3 input tokens processed at once, K/V matrices built:

K cache:              V cache:
[I_K   ]  [0.5, 1.1]    [I_V   ]  [0.8, 0.2]
[went_K]  [1.0, 0.4]    [went_V]  [0.3, 0.7]
[bank_K]  [0.8, 0.9]    [bank_V]  [0.6, 0.5]

Decode step 1 — model generates "account":
Only compute account's own Q/K/V, then append K/V to cache:

K cache:              V cache:
[I_K      ]              [I_V      ]
[went_K   ]              [went_V   ]
[bank_K   ]              [bank_V   ]
[account_K]  ← new       [account_V]  ← new

account's Q dot-producted with all 4 cached K's → attention scores → weighted sum of V

Decode step 2 — model generates "balance":
Same process: compute only balance's K/V, append one row, Q dot-producted with 5 K's.

Each step adds only one row, without recomputing the old ones. This is an intra-request acceleration mechanism, handled automatically by the inference engine.

KV Cache Figure: KV Cache accumulates incrementally with each generated token — Token 1 creates [K1,V1], Token 2 appends [K2,V2], and subsequent tokens only need to compute their own K/V and append (Source: Hugging Face KV Caching Explained)

Prefill vs. Decode: Where the Money Goes

PhaseWhat It DoesComputational CostCorresponding Fee
PrefillProcesses all input tokens at onceO(n^2), n = input lengthInput token fee (Opus 4.6: $5/MTok)
DecodeGenerates output tokens one by oneO(n) per new tokenOutput token fee (Opus 4.6: $25/MTok)

Prefill is expensive because it must process the entire prompt at once. A 60k-token context means every layer has to compute a 60k × 60k attention matrix. Output has a higher unit price ($25 vs. $5) because GPU utilization is low during the Decode phase — only one token is generated at a time, without the massive parallelism of Prefill. Providers set output prices higher to cover this hardware idle cost.

This raises a natural question: if the first half of this request’s input is identical to the previous request (the system prompt, tool definitions, and project rules have not changed), can we skip the Prefill computation for that portion?

Yes. That is Prompt Cache.


Distinguishing the Different Types of Cache

As developers, we deal with various caches every day, but “cache” in the LLM context is not quite the same as what we normally mean. It was only after understanding the LLM processing workflow that I was able to sort them out clearly.

Caches Developers Know Well

CacheWhereWhat It Caches
Browser cacheClientCSS/JS/images; controlled by Cache-Control headers
CDN cacheEdge nodesHTTP responses
Redis / MemcachedApp serverDatabase query results, computed results
Database Buffer PoolInside the databaseHot data pages

These caches share a common trait: they cache “results.” Same input, return the previous result, skip the computation.

Caches in the LLM World

There are two types of cache in LLM inference that matter to us, and they cache intermediate computation states, not final answers.

KV Cache is an intra-request acceleration. When generating the 101st token, the K/V for the first 100 tokens have already been computed and are directly reused. Think of it as “short-term memory” while writing a document — you do not re-read everything from the beginning. You have no control over this; the inference engine handles it automatically.

Prompt Cache (also called Prefix Cache) is cross-request reuse of Prefill computation. If the first half of your current request’s input matches the previous request, it skips Prefill for that prefix and directly reuses the previously computed K/V. It is like reading the first 50 pages of an operations manual yesterday — today you only need to start from page 51. This is why Cached Input can be ten times cheaper: it skips the most expensive Prefill computation.

There is also Semantic Cache, an application-layer middleware: if a new question is “semantically similar enough” to a previous one, it returns the old answer directly without even calling the API. This is more like Redis — caching final results. It is useful for FAQs and customer support, but not for Coding Agents, because code is constantly changing, and “semantically similar questions” can have completely different answers under different code versions.

CacheWhat It CachesCross-Request?Can You Control It?Impact on Your Bill
KV CacheK/V computed in current requestNoNoTransparent (inference acceleration)
Prompt CachePrefill K/V for identical prefixYesPartiallyDirectly determines cached input pricing
Semantic CacheOld answers for semantically similar questionsYesFullySkips the entire API call

The Core Rule of Prompt Cache: The Prefix Must Be Exactly Identical

Comparison happens token by token starting from the first token. The moment any position differs, everything from that position onward is a cache miss.

Request A: [system prompt][tools][rules][history A][user message A]
Request B: [system prompt][tools][rules][history B][user message B]
              ↑ identical → cache hit    ↑ differs from here → miss

Providers differ in their mechanisms: Anthropic lets you explicitly set cache_control breakpoints and TTL (5 minutes / 1 hour); the first cache write costs 1.25x-2x more than regular input, but subsequent reads cost only 0.1x. OpenAI automatically detects identical prefixes, with cached input at 0.1x and no additional cache write fee. GitHub Copilot uses the underlying model’s cache mechanism, and users simply see cheaper cached input in their AI Credits.

What Affects Cache

Since the prefix must be exactly identical, anything that changes the earlier content will affect cache hits. Based on community findings:

Cache KillerWhyHow to Fix
Timestamp in system promptChanges every secondMove timestamp to end of messages
Random MCP tool registration orderTool list differs each timeFix registration order
Random few-shot examplesExample ordering variesFix example set and order
Session ID embedded in prefixDifferent for each sessionMove to suffix
Frequent compact/summarizeSummary differs each time → new prefixDelay compact as long as possible
Unused MCP tools not cleaned upWasting prefix spaceClean up periodically

A concrete example: my Claude Code environment has 40+ MCP tools registered, with tool schemas alone taking up approximately 8-10k tokens. If those schemas appear in a different order each time, the following 50k tokens can be as similar as they like and they will still miss. Conversely, if the order is fixed, those 8-10k tokens become a stable cache-hitting prefix, costing only 0.1x each time.

This realization shifted my optimization thinking. Reducing the system prompt is nice, but making it stable — so it consistently hits the cache — is far more effective.

The community has a tool specifically addressing cache alignment: claude-code-cache-fix (~1,800 stars, MIT). It discovered that Claude Code’s --resume session causes cache regression (micro-compression embeds a timestamp that changes each time, altering the prefix bytes). The tool normalizes sentinels to a fixed format via a local proxy, improving the cache hit rate from 82.3% to 95.5%.

If you are connecting Claude Code to a third-party local model, there is an even more direct cache killer. Claude Code adds an attribution header at the beginning of each request, and this header changes every time. For Anthropic’s own API this is not an issue, but for local inference servers, a changed prefix means the entire KV Cache is invalidated and Prefill must restart from scratch. Empirical data shows: Qwen2.5-Coder 14B on a consumer GPU saw first-token latency jump from 1.8 seconds to 24 seconds with a 6k-token context, cache hit rate dropping to zero, and throughput falling by roughly 90%. The fix is to add "CLAUDE_CODE_ATTRIBUTION_HEADER": "0" to the env section in ~/.claude/settings.json (note that shell export does not work — it must be in the settings file).


From Cache to Context Engineering

From the preceding discussion, it becomes apparent that there is a limited amount we can do at the Prompt Cache layer: fix prefix ordering, clean up excess MCP tools, disable the attribution header. Once you have done these things, the cache hit rate is already quite high. The vast majority of open-source tools in the community are not working at the cache layer either — they focus on a different level: how to reduce the total volume of content entering the context, and how to get the model to produce enough code while saying less.

In mid-2025, the term Context Engineering began appearing frequently. Anthropic published an engineering blog post “Effective context engineering for AI agents” providing a systematic treatment, with the core argument that the context window should be managed as a scarce resource — load on demand, do not preload. LangChain’s Lance Martin organized the concrete operations into four categories: Select (bring in relevant information), Compress (reduce tokens), Isolate (split into independent windows), and Write (store outside the window). I will follow this framework going forward.


Select: Getting the Right Information In

This is the most critical and most complex step in Context Engineering. A codebase may have hundreds of thousands of lines, but the agent in this round may only need to see 500 lines. How do you find those 500 lines?

There are two major approaches on the market: the first is Indexing, as exemplified by Cursor; the second is Grep, as exemplified by Claude Code.

Codebase Indexing

The Indexing approach is to build a queryable index of the codebase in advance, letting the agent find what it needs in a single step. I surveyed the current solutions on the market and categorized them by underlying principle.

Embedding Vector Index

Split code into chunks, generate semantic vectors, store them in a vector database, and retrieve relevant code segments via semantic similarity at query time.

ToolStarsLicenseFeatures
Claude Context (Zilliz)11.3kMITAST chunking + Milvus vector DB + hybrid BM25+vector search; supports OpenAI/VoyageAI/Ollama embedding
CocoIndex Code1.7kApache-2.0Lightweight; AST-aware chunks + local SentenceTransformers; incremental indexing
SeaGOAT1.3kMITFully local; ChromaDB + ripgrep hybrid search; no cloud API calls
claude-context-local229GPL-3.0Fully local version of Claude Context; EmbeddingGemma + FAISS; zero API cost

If your project is sensitive about data security and you do not want to send code to the cloud, SeaGOAT or claude-context-local are safer choices. For multi-repo, multi-language support, Claude Context is the most feature-complete.

Cursor and Augment’s Index features work on the same principle. But since they use Embedding for indexing, all the inherent problems of Embedding apply — for example:

  • Synonym / internal terminology issues: You search for “billing,” but the code might use “subscription,” “metering,” or “invoice.” Embedding models trained on general corpora may not understand your company’s internal vocabulary. Searching “login” might fail to find a function called SessionCreation.
  • Probabilistic results: Semantic search returns the “most similar” results, not the “most correct” ones. A high-confidence wrong answer is more dangerous than no answer at all, because the agent will continue working based on what it found.

AST / Knowledge Graph

These tools use Tree-sitter to parse the code’s AST (Abstract Syntax Tree), extracting functions, classes, call relationships, and inheritance hierarchies to build a graph.

ToolStarsLicenseFeatures
Graphify48.6kMITTree-sitter (20 langs) + LLM semantic extraction → multimodal knowledge graph; NetworkX + Leiden clustering
GitNexus37.9kMITTree-sitter → KuzuDB graph database; fully WebAssembly client-side; Graph RAG Agent
code-review-graph15.6kMITIncremental change detection → blast radius analysis; claims 6.8x fewer tokens on reviews, 49x on daily coding
CodeGraph2.2kMITTree-sitter → SQLite + FTS5; Claude Code MCP; filesystem watch for incremental sync
Aider Repo Map41.6kApache-2.0Tree-sitter symbol extraction → directed graph → PageRank ranking; binary search for the most important definitions within a token budget

If you are already using Claude Code, CodeGraph integrates directly via MCP and is the quickest to get started with. For large-scale cross-language code comprehension, Graphify covers the most languages. Aider’s approach is best suited for those who want to run entirely locally without depending on external services.

Aider’s approach is worth elaborating on. It does not use a vector database or embeddings; it uses PageRank to rank code symbols by importance. Files mentioned in the current chat get 50x weight, and active identifiers get 10x weight. It then uses binary search within a token budget (default 1024 tokens) to select the highest-ranked definitions and renders them as a concise tree structure for the model. Fully local, recomputed per message, deterministic results.

Grep: Why Claude Code Does Not Use Indexing

Having covered Indexing and AST graphs, a natural question is: why does Claude Code not do codebase indexing?

The answer is that it tried and abandoned it. Earlier versions of Claude Code used RAG + a local vector database, but the team found that agentic search (grep + glob + read) consistently outperformed RAG. Boris Cherny (a founding engineer of Claude Code) has explained the reasoning on multiple occasions. A 2026 Amazon Science paper also provided corroborating evidence: keyword search via agentic tool use can achieve over 90% of RAG’s effectiveness without requiring a vector database.

Grep’s advantages lie in several areas:

  • Zero configuration: No index needed, no embedding model, no vector database. Clone and search immediately.
  • Ultimate freshness: Code the agent just wrote is searchable by grep the very next second. Indexes have a 5-10 minute delay, and a stale index can lead the agent in the wrong direction.
  • Universal format coverage: YAML, Dockerfile, .env, Markdown, config files — grep can search them all. Indexes and LSP typically only cover code files.
  • Graceful failure mode: Grep’s worst case is returning too many results (noise), which the agent can filter. If an index or LSP is misconfigured or missing dependencies, it may return empty results (the agent thinks there is no relevant code). This kind of false negative is far more dangerous than false positives.

Grep’s costs are also clear:

  • High token consumption: Searching “billing” returns 200 lines, most of which are noise, all entering the context. After a few rounds, the context is stuffed with irrelevant code.
  • No synonym handling: Searching “billing” will not find code called “subscription.” This is a problem it shares with embedding, just with a different failure mode.
  • Slow on large repos: Cursor’s engineering team reported that ripgrep calls exceeded 15 seconds on large monorepos.

At this point, a clear hierarchy emerges: Embedding Index does “find potentially relevant code,” AST graph does “understand structural relationships between code,” and grep does “search by keyword on the spot.” Each has its strengths and weaknesses, but all share a common precision problem: grep returns 200 text matches where only 3 are actual function call sites — the rest are comments, strings, or coincidental name matches in tests. Embedding returns “semantically most similar” results that may be wrong. AST graphs understand structure but cannot cover dynamic language reflection and runtime behavior.

Is there a way to directly use the compiler’s understanding to answer “where is this function called?” Yes — that is LSP.

LSP: Giving the Agent the Compiler’s Eyes

LSP (Language Server Protocol) is a protocol Microsoft designed for VS Code in 2016. Before it, every IDE had to implement smart features (completion, jump-to-definition, refactoring) for every language on its own — an enormous effort. LSP’s approach is to extract “language intelligence” into independent background services (Language Servers), with IDEs communicating through a standardized protocol. TypeScript has tsserver, Rust has rust-analyzer, Python has pyright, and Go has gopls. Any editor supporting the LSP protocol gains these capabilities.

For AI agents, LSP provides compiler-level precision navigation. Grepping “calculateUsage” performs pure text matching — it does not know whether a string is a function name, variable name, comment, or string literal. LSP’s find-references uses the type system and syntactic analysis to return only semantically real call sites. go-to-definition jumps straight to the function definition without sifting through 200 grep results. hover directly provides the type signature without reading the entire file.

The community ran a reproducible benchmark across 5 codebases, 13 tasks, and 3 languages. The result: LSP saves 5-34x tokens compared to grep. The savings scale with codebase size: 5x for a 15k-line project, 34x for a 319k-line project. The reason is intuitive: grep results grow linearly with codebase size, while LSP references only depend on actual call sites, regardless of codebase size.

MethodProcessToken Consumption
grepgrep calculateUsage → 200+ results → read each → found after 5 rounds~12,000
LSP find-referencesOne step returns 3 precise call sites~500

AI coding tools vary widely in their LSP support. OpenCode treats LSP as core architecture, with 30+ preconfigured language servers that auto-download when you open a relevant file type. The agent gets direct access to diagnostics, hover, go-to-definition, find-references, and call hierarchy. Claude Code also has built-in LSP support (11 languages, requires setting ENABLE_LSP_TOOL=1), but the actual trigger rate is low — community members have reported “I haven’t come across a case where it has used the LSP yet.” To force LSP usage in Claude Code, you can install cclsp (637 stars, MIT) as an MCP bridge and pair it with enforcement-kit (294 stars, MIT), which uses hooks to intercept grep calls.

LSP’s problems are also clear:

  • High resource consumption: Language servers reside in memory. A TypeScript project’s tsserver can consume 2-4GB of memory, and a large project’s rust-analyzer can take 30-60 seconds to initialize. Running dozens of language servers simultaneously in OpenCode makes the machine noticeably sluggish. This is one reason why OpenCode tends to feel slow.
  • Poor precision with dynamic languages: Python’s getattr, Ruby’s method_missing, and JavaScript’s dynamic imports are invisible to LSP. LSP relies on static analysis and cannot see runtime behavior.
  • No coverage for non-code files: YAML, Dockerfile, Markdown, config files — LSP cannot help. Grep is actually more useful in these scenarios.
  • Designed for editors, not agents: LSP’s interaction model is cursor-position-based, one operation at a time. Agents need batch cross-file queries. There is no good solution for this mismatch yet.
  • Agents do not use it proactively: Without enforcement, agents will skip LSP and go straight to grep because grep calls are simpler. Tools like enforcement-kit exist specifically to solve this problem.

My preliminary assessment: for statically typed languages (TypeScript, Rust, Go, Java), LSP should be enabled — the ROI is clear, especially in environments like OpenCode where it works out of the box. For dynamic language projects or small projects, a well-written CLAUDE.md plus grep may be more pragmatic.

The Business Code Map: The Most Reliable Context

More reliable than any index is writing human knowledge directly into documents the agent can read.

CLAUDE.md / AGENTS.md / .cursorrules all serve the same purpose — telling the agent “where the project entry points are, what the business concepts are called, where the common pitfalls lie, and where to find more details.” Anthropic calls this “always-loaded context” in their blog.

A good CLAUDE.md is a signpost, not an encyclopedia. It should answer “what does the agent most need to know first when it receives a task,” rather than cramming in documentation for every module.

## Architecture
- Entry point: src/api/routes.ts
- Business logic: src/services/
- Billing-related: src/billing/ (NOT src/payments/)

## Domain Glossary
- plan = user-facing plan, subscription = accounting-side subscription
- metering = usage collection (≠ billing)
- usage_event ≠ usage_summary (raw events vs. aggregates)

## Common Pitfalls
- Do not modify files under src/generated/
- billing unit tests require a mock clock
- Use npm run test:unit, not npm test (the latter runs the full e2e suite)

Why is this more stable than an index? Because it is deterministic. When the agent reads “billing is in src/billing/,” it does not need to grep the entire repository. The savings are not just a few tokens — it is 3-5 rounds of fruitless exploration. And it will not go stale (as long as someone maintains it), does not require embeddings, and does not need external services.

The community has formed some consensus in this direction. The most influential is Karpathy’s CLAUDE.md specification (142k+ stars). Karpathy observed that AI agents writing code have four recurring problems: silently making incorrect assumptions without verification, over-abstracting simple problems, modifying code they should not touch, and starting to code without defining validation criteria. These four rules reduced agent error rates from 41% to 11%.

The community subsequently iterated on this. Mnilax tested on 30 codebases over six weeks and added 8 more rules covering agent fights, hook cascades, skill loading conflicts, multi-step workflow drift, and other issues the original did not address, further reducing the error rate to 3%. One of his key insights: prompt instructions are suggestions; hooks are enforcement. Rules that can be enforced through code should not rely on prompts. Expecting 80% prompt compliance + 20% hooks as a safety net is a realistic way of working.

Regarding how to write CLAUDE.md, there is one important cost constraint: Anthropic recommends keeping it under 200 lines. 200 lines is roughly 1,500-2,000 tokens, injected into the prefix of every single request. If it balloons to 500 lines, that is a 5,000-token tax per round. Many teams write things the agent already knows (“please write code in TypeScript”), spending tokens without changing anything. Only write information the agent cannot infer from the code itself: architecture decisions, business terminology, team conventions, and known pitfalls.

If you do not want to write one from scratch, there are auto-generation options. Caliber can scan project structure, dependencies, and code patterns to automatically generate a CLAUDE.md (it also generates .cursorrules and MCP server configurations). Claude Code also has a built-in /init command that generates an initial CLAUDE.md from the codebase. However, auto-generated results typically need manual trimming, as generators tend to include everything they discover — easily exceeding the 200-line budget.

Skill/MCP Triage

The Index, Grep, and LSP approaches discussed above address “how to find the right code.” But a Coding Agent’s context contains more than just code — it also holds a large volume of MCP tool definitions and Skill instructions. I counted my own Claude Code environment: 40 registered MCP tools, with schemas alone taking up approximately 8-10k tokens, and I am paying for them on every request.

There are two problems to solve here: one is how to apply progressive disclosure to MCP the way Skills do (or replace MCP with CLI entirely, eliminating the schema-eating-context problem altogether); the other is that as Skills themselves proliferate, they also need a round of progressive disclosure.

MCP Tool Triage

Claude Code has a built-in ToolSearch mechanism that activates automatically without manual configuration. Claude Code calculates the total token count for all deferrable tool definitions, and if it exceeds 10% of the context window, deferred loading automatically kicks in. Without it, 147 tool definitions inject approximately 90k tokens into every request. With it enabled, only ~25 core built-in tools plus one ToolSearch tool remain — approximately 15k tokens, a 95% reduction. When the agent needs a deferred tool, it first calls ToolSearch (BM25 or regex search over tool names and descriptions), retrieves 3-5 candidates, automatically expands them into full definitions, and then invokes them.

The cost of ToolSearch is an extra round of calls (search first, then use), and search quality depends on how well the tool’s name and description are written. Community members have reported cases where built-in tools were incorrectly deferred, causing functionality degradation.

OpenCode is working on something similar at the MCP layer. PR #12520 implements mcp_search for on-demand discovery, aiming to reduce the 67k-token startup cost of 7+ MCP servers down to ~350 tokens. As of writing, it has not yet been merged.

The community has developed several MCP triage approaches, which can be categorized by principle. Schema compression shortens the tool descriptions themselves; lazy loading uses 2-3 meta-tools to replace all tools with on-demand full schema retrieval; Code Mode is more radical, exposing only one or two execution tools, with the agent writing code to call the backend.

ToolStarsLicensePrincipleFeatures
IBM ContextForge3,747Apache-2.0Gateway + compressionMCP/A2A/REST unified gateway; TOON format for tool output compression
Headroom1,924Apache-2.0Output compressionCompresses tool return values (60-95%), not the schemas themselves; reversible
1MCP440Apache-2.0Lazy loadinginstructions → inspect → run three-step progressive discovery
One MCP392MITProxy aggregationMultiple MCP servers merged into a single endpoint; Service Groups exported as Skills
mcp-server-code-execution-mode333GPL-3.0Code ModeExposes only run_python (~200 tokens); agent writes Python to call backend tools
MCPProxy227MITLazy loadingretrieve_tools semantic search; ~99% token reduction; built-in security isolation
mcp-funnel153MITFiltering + lazy loadinghideTools whitelist/blacklist (glob); optional discover_* meta-tools
Forgemax149CustomCode ModeCompresses N servers × M tools into 2 tools (search + execute, constant ~1,100 tokens); V8 sandbox execution

Skill Triage

Skills (.md instruction files) also suffer from token bloat. Anthropic’s official Agent Skills spec defines three levels of progressive disclosure: Level 1 puts only name + description in the system prompt (~50-100 tokens/skill), Level 2 loads the full text on demand via the Skill tool, and Level 3 loads resources on demand. Major coding agents have already built in this mechanism — skill full text is not preloaded. At this point, the problem appears solved.

In practice, installing many skills reveals that it is not.

The problem is in the metadata itself. Although skill full text is not preloaded, each skill’s name and description is still injected into the system prompt. Someone in the community dug into this “discovery ceiling”: Claude Code allocates a token budget for available_skills with an upper limit (based on reverse engineering, approximately 1% of context, minimum 8,000 characters), with each skill description truncated to a maximum of 250 characters. 8,000 / 250 = roughly 32 skills that can be effectively matched. Beyond that number, descriptions are too short for the agent to match and are simply ignored. One person installed 63 skills, but only 42 appeared in the session — the rest were cut by the budget. Google Workspace CLI with 95 installed skills consumed 2,007 tokens per round on metadata alone.

Moreover, installing too many skills does not just waste tokens — it actually makes the agent perform worse. Vercel’s evaluation found that agents ignored relevant installed skills 56% of the time, and installing skills actually performed worse than the baseline (58% test pass rate vs. 63%). Unused skills introduced noise in the context. Perplexity, in their skill design guide, reached a similar conclusion: “Every Skill you add has the potential to make every other Skill worse.” They did not provide experimental data but explained the mechanism: each new skill’s description competes for model attention during routing, potentially causing incorrect activation. They also found that the internal organization of a single skill matters greatly: stuffing all 1,945 sections of U.S. tax law into one folder (one skill) made the model perform worse than having no skill at all — it had to be organized in logical tiers (multi-level directories + quick reference guide + custom search tool) before the model could use it effectively.

The community currently has three approaches to this ceiling:

Control the quantity. Keep skills to ~30 or fewer; beyond that, discovery rates decline. If you have installed many skills and are not sure which ones are actually being used, Token Optimizer (1,051 stars, PolyForm NC) can audit actual usage and clean up skills and hooks that have never been triggered. Someone achieved a 44% overhead reduction through auditing + cleanup.

Bypass native indexing and use external search instead. The author of the discovery ceiling blog post built a local daemon called PreBrief: it uses a small model to embed all skills into vectors, performs semantic search on user input, injects only the matched skills into the prompt, and moves the original skills to a disabled directory to bypass native indexing. On the OpenCode side, opencode-triage (MIT) uses hooks to hide all skills and exposes a single triage({ query }) that does keyword matching with IDF weighting and spell correction — 19 skills reduced from 1,226 tokens to 59 tokens (95%).

Do not preinstall at all — discover when needed. A Google Cloud engineer built a Dynamic Skills Agent that installs zero skills upfront. When the agent needs a capability, it searches for and installs from trusted GitHub repositories on demand via searchAgentSkills. Metadata overhead is zero, at the cost of an extra search-and-install round on first use.

All three directions are still experimental. The most pragmatic approach today remains controlling skill count + periodic audit cleanup.

CLI Instead of MCP: A Trend in Progress

There is an even more radical idea: skip MCP entirely and use CLI commands instead. This eliminates the schema tax problem at the root.

Scalekit ran a benchmark: the same GitHub operations required 1,365 tokens with gh CLI versus 44,026 tokens with the GitHub MCP server. A 32x difference. The reason is that the GitHub MCP server exposes 43 tools, and the full schema for all 43 is in the context every request, even if you only used 1. CLI has no schema tax — the agent already knows how to use gh commands from its training data, and gets it done in one shot. At 10,000 requests/month, CLI costs approximately $3.20, while MCP costs approximately $55.20.

Google’s approach best illustrates the trend. In March 2026 they released Google Workspace CLI (gws), covering Drive, Gmail, Calendar, Sheets, and Docs — the full Workspace API surface. At the same time, they had written 1,151 lines of MCP server code, deleted all of it two days later, and published a CLI instead.

MCP’s value lies in governance capabilities: per-user OAuth, tool-level permission boundaries, structured audit logs. But in day-to-day development, command-line permissions come from the developer’s own credentials. As long as you do not accidentally rm -rf everything, finer-grained permission controls amount to over-engineering.

I also lean toward using CLI whenever possible over MCP. GitHub, Jira, Azure DevOps, Supabase, AWS, and Google Workspace all have official or third-party CLI tools. If there truly is no CLI available, you can try getting the official API docs onto your local machine and specifying in your Claude/Agents.md to send curl commands when the tool is needed. Only as a last resort should you consider MCP.


Compress: Reducing Token Count in Existing Context

What do you do when the context has already bloated? Compress. But there is a fundamental tension here: compression and caching are adversarial. Compression modifies history to shorten it; caching requires history to remain unchanged to get hits. Beyond that, based on my personal experience and feedback from teammates, the agent already starts hallucinating when context usage reaches 80%. So the best approach is clearly not to wait until the context is completely full before compressing. Strategically, prevention matters far more than compression.

Prevention Tools (Do Not Break Cache)

These tools compress content before it enters the context, without touching existing history.

ToolStarsLicenseWhat It CompressesPrincipleCompression Rate
RTK49.2kApache-2.0CLI command outputRust binary intercepts Bash, semantically rewrites output80% (session total)
Context Mode~15kELv2Tool execution resultsSandbox execution, raw data never enters context, SQLite + FTS5 storage98% (claimed)
lean-ctx1.7kApache-2.0CLI output + file reads + MCPShell hook + MCP server + Tree-sitter AST60-95% (cached re-read ~13 tokens)
Headroom1.8kApache-2.0Everything entering contextlibrary/proxy/MCP, CacheAligner for prefix alignment, reversible compression87% (10,144→1,260 tokens)

Their coverage differs, and this is the key to choosing: RTK only handles Bash output and cannot touch Read/Grep/Glob or MCP return values; Context Mode handles tool execution results but cannot intercept MCP’s JSON-RPC responses; lean-ctx covers the broadest range (Shell + Read + MCP across three channels); Headroom is the only one that actively considers cache alignment.

RTK: CLI Output Compression

RTK (Rust Token Killer) (GitHub, 49.2k stars, Apache-2.0) is the most widely used tool in this space. It is a Rust CLI proxy that intercepts shell command output and semantically rewrites it before it enters the context — not generic gzip-style compression, but intelligent reduction based on understanding command semantics. Fifty identical ESLint errors become a single line: “ESLint: 50 errors in src/components/ (no-unused-vars).” Test output retains only failures and the summary.

Installation is straightforward: rtk init -g — one command, and all Bash calls transparently pass through RTK.

RTK’s README provides a benchmark from a 30-minute session, broken down by command type:

Command TypeCompression Rate
Directory listing (ls/find)80%
File reading (cat/head)70%
Search (grep/rg)80%
Git (status/log/diff)92%
Tests (npm test/pytest)90%
Session total80% (~118k → ~24k tokens)

Git and test outputs have the highest compression rates because their output is the most repetitive — 100 lines of diff might contain only 5 lines of changes you care about, and 200 lines of test output might boil down to “3 failed, 47 passed.”

However, RTK has clear limitations: it only compresses the current round’s command output and cannot touch existing history. In a 50-round / 150k-token session, the actual savings are approximately 1.6%. It also cannot compress output from Claude Code’s built-in Read/Grep/Glob (which do not go through the Bash hook).

Context Mode: Sandbox Execution

Context Mode (GitHub, ~15k stars, ELv2) takes a fundamentally different approach. Its core idea is: raw data never enters the context window.

It provides 6 MCP sandbox tools to replace the tools the agent would normally use directly (ctx_execute, ctx_batch_execute, ctx_execute_file, ctx_index, ctx_search, ctx_fetch_and_index). The data flow:

  • Tools execute in an isolated subprocess
  • Raw output is written in full to local SQLite (with FTS5 full-text index)
  • Only 1-2 lines of summary are returned to the LLM (command status, output line count, key information)
  • When details are needed, the agent calls ctx_search for on-demand BM25 retrieval

Concrete results: a Playwright page snapshot goes from 56KB to 5.4KB; a 700KB file read goes to 3.6KB.

There is also a PreCompact Hook: before /compact triggers, it automatically saves key state (active files, execution results, work progress) into SQLite as a recovery snapshot. When a new session starts, this is automatically injected so the agent can resume from where it left off.

Limitations:

  • ELv2 license (allows internal use, prohibits hosted services, does not meet the OSI open-source definition)
  • Cannot intercept MCP tool responses (JSON-RPC goes directly to the model; Context Mode has no interception layer)
  • 136 releases in 3 months — some community members question stability
  • 570 points on the HN front page — high visibility but not much production feedback yet

lean-ctx: Full-Channel Compression

lean-ctx (GitHub, 1.7k stars, Apache-2.0) differs from RTK most critically in coverage. RTK only handles Bash output; lean-ctx covers three channels simultaneously:

  • Shell hook for compressing command output (similar to RTK)
  • MCP server for compressing file reads and code analysis (RTK cannot touch these)
  • Tree-sitter AST (21 languages) for understanding code structure and performing semantic-level compression

For file reading, lean-ctx provides 10 read modes:

  • full: complete content
  • map: returns only a file structure overview
  • signatures: extracts only function/class signatures
  • diff: shows only changed portions
  • and more

First-time reads are compressed 60-95%. Cached re-reads are an interesting design: when the agent reads the same file again within a session, lean-ctx detects that the file has not changed and returns a ~13-token short message (“you read this before, nothing changed”), avoiding re-injecting thousands of tokens.

Overall it provides 59 tools and 95+ compression modes. There is also a Property Graph feature: it builds a code graph on top of AST (tracking imports/calls/exports/type_ref), with mixed search at query time (BM25 + embeddings + graph proximity).

Headroom: Cache-Aware Compression

Headroom (GitHub, 1.8k stars, Apache-2.0) specifically focuses on coordination between compression and Prompt Cache.

Core features:

  • CacheAligner: After compression, it actively adjusts the structure and arrangement of results so that compressed content aligns as closely as possible with the previous request’s prefix, improving cache hit rate
  • CCR (Reversible Compression): Compressed content can be retrieved in its original form if the model later needs to see the raw data, via headroom_retrieve. Compression is undoable
  • Kompress-base: Uses a compression model from Hugging Face for text compression. Benchmark: 10,144 tokens → 1,260 tokens (87%), with no measurable quality degradation

Installation Complexity Comparison

The four tools have very different setup costs:

ToolInstallationComplexity
RTKrtk init -g — one command, auto-registers hookSimplest
Context ModeOne-click install from Claude Code marketplace, or npm install -g context-modeSimple, but you need to understand the 6 sandbox tools
lean-ctxbrew install lean-ctx or cargo install lean-ctx, then lean-ctx setup auto-detects AI tools and configuresMedium; setup auto-configures but initial learning of read modes is needed
Headroompip install headroom-ai[all], then configure per deployment mode (library mode is simplest; proxy/MCP requires additional configuration)Most complex; Python environment + many config options; better suited for teams willing to tinker

RTK and Context Mode are the “install and forget” type. lean-ctx requires some time understanding its read modes to maximize effectiveness. Headroom’s CacheAligner and reversible compression features are powerful, but configuration and debugging costs are highest — better suited for teams with ops capabilities or those who need to integrate compression into their own pipeline.

Selection guidance: if the team primarily runs CLI commands (build, test, lint), RTK delivers immediate results. If the agent does heavy file reading and MCP calls, lean-ctx offers broader coverage. Headroom is best for those with extreme cache hit rate requirements or those who need to integrate compression into their own pipeline.

Compression Tools (Will Break Cache)

No matter how good the prevention, context will still grow over long sessions. In my experience, the model starts losing focus when context hits 70-80% — well before the 95% threshold where /compact auto-triggers. The community’s main direction currently is Dynamic Compression: not a blunt summarize-and-restart, but selectively reducing existing content while the session is still running.

ToolStarsLicenseCompression GranularityPrinciple
DCP2.8kAGPL-3.0Selective pruning of completed tool callsAuto-dedup + LLM semantic compression; modifies API payload, original session untouched
Cozempic300MITTiered progressive cleanup (3 levels)Directly modifies session JSONL files, deletes redundant data
Magic Context636MITBackground async compressionHistorian model compresses in background; Compartments + Facts for persistence

The key difference among these tools is “where compression happens” and “how fine-grained it is.” DCP intercepts the API payload and replaces old tool calls before sending the request, leaving the original session file intact for tracing. /compact is the bluntest approach — it compresses the entire context into a summary and starts fresh, completely zeroing out the cache. Cozempic directly modifies the session file itself, physically removing accumulated junk data. Magic Context runs asynchronously in the background without interrupting the main agent, and even calculates whether the cache savings are enough to offset the cold start cost. If you want fine-grained control mid-session, choose DCP; if the session has bloated beyond repair, /compact or Cozempic does a clean reset; if you do not want to think about it, Magic Context handles things automatically in the background.

DCP: Selective Pruning

DCP (GitHub, 2.8k stars, AGPL-3.0) is an OpenCode plugin that selectively reduces completed tool calls during a session, rather than doing a full summary. claude-dcp (MIT) is its Claude Code port.

  • Does two things: automatic deduplication (zero LLM cost) and semantic compression (LLM-driven)
  • Automatic deduplication: if the agent reads the same file 3 times in a session, DCP keeps only the last output and replaces the previous two with placeholders. Same for repeated git status, URL fetches, etc.
  • Semantic compression: DCP exposes a compress tool. The agent itself decides when a segment of conversation is complete (e.g., a bug has been fixed and the 20 rounds of debugging tool calls are no longer needed), calls compress, and replaces that segment with a technical summary
  • Original session files are untouched; replacements happen only in the API payload, so full logs are preserved for tracing
  • Configuration: maxContextLimit defaults to 100k tokens (triggers compression reminders when exceeded), minContextLimit defaults to 50k tokens; these can be changed to percentages like “80%.” In my view, this configuration is quite sensible — for most 200k-context models, 100k is a reasonable sweet spot at the halfway mark
  • Shadow copy mechanism keeps the cache hit rate at approximately 85% (compared to 90% without DCP)
  • Limitations: AGPL-3.0 license requires attention for commercial use; semantic compression needs additional LLM calls — cheaper than re-Prefilling but not free; compression quality depends on the agent’s judgment of whether “this segment of conversation is complete” — compressing incorrectly will lose information

Cozempic: Physical Session File Cleanup

Cozempic (GitHub, 300 stars, MIT) directly operates on Claude Code’s session JSONL files, deleting accumulated junk data.

  • The difference from DCP: DCP modifies the API payload (runtime interception), Cozempic modifies the file itself (persistent cleanup)
  • Typical scenario: a file was modified 50 times, with each tool result recording the full diff, accumulating 2MB. But the agent does not actually need old diffs (it can re-read the file). Cozempic keeps only the most recent diffs and compresses old ones into a one-line summary or deletes them
  • 18 cleanup strategies across three levels:
    • Gentle: delete messages already summarized by /compact but with originals still present, deduplicate file reads, strip metadata
    • Standard: truncate excessively long tool outputs, clean up expired old results, deduplicate system reminders
    • Aggressive: delete old base64 images (keep only the most recent 20%), collapse repeated error-retry loops, truncate blocks exceeding 32KB
  • Savings of approximately 23-45%
  • Default dry-run mode (report only, no modifications), add --execute to actually modify, with automatic backup before changes

Magic Context: Background Async Compression

Magic Context (GitHub, 636 stars, MIT) is an OpenCode plugin — there is no Claude Code plugin. It compresses in the background asynchronously, so the main agent never has to wait.

  • A separate historian model runs in the background, processing old conversations asynchronously. The main agent does not need to wait for compression to finish and is never interrupted
  • Compression results are stored as Compartments (summaries organized by timeline), injected into context for the next round of requests
  • Facts (decisions, constraints, preferences) are extracted from conversations and persisted separately. Facts are not lost during compression, partially solving /compact’s error ossification problem
  • Cache-aware scheduling: calculates the money saved by cache versus cold start cost, only triggering when the compression benefit is positive
  • Facts persist across sessions, automatically injected when a new session starts

Installation Complexity Comparison

ToolInstallation CommandNotes
DCPnpm i @tarquinen/opencode-dcpOpenCode plugin, works out of the box
claude-dcpgit clone + configure three hooksClaude Code port, requires manual configuration of PreCompact, PreToolUse, UserPromptSubmit
Cozempicpip install cozempic && cozempic initRequires Python environment, default dry-run safe mode
Magic ContextAdd "plugin": ["@cortexkit/opencode-magic-context"] in opencode.jsonOpenCode only; requires disabling built-in compaction and configuring the historian model

Supplement: API-Level Context Editing

If you are using the API to build your own agent, Anthropic’s context editing provides server-side context management capabilities. The clear_tool_uses strategy can automatically clean up old tool results by time, with configurable trigger thresholds, retention of the most recent N calls, and exclusion of specific tools. OpenAI has a similar compact endpoint. These are transparent to Claude Code / ChatGPT users, but if you are building your own agent, you can exercise finer-grained control directly at the API layer.


Isolate: Splitting Tasks, Switching Models

The Select and Compress strategies above are matters of installing tools — change the configuration and start saving. Isolate and the upcoming Write are different; they are changes in usage habits.

The core idea of Isolate is to break a large task into subtasks, execute them in independent context windows, and return only the conclusions to the main agent. There are two cost levers: model tiering (cheap models for simple work) and context isolation (sub-agents do not carry unneeded history). Total token count may stay the same or even increase, but cost goes down.

Model Tiering and Context Isolation

Let us look back at the pricing table. Haiku $1/$5, Sonnet $3/$15, Opus $15/$75 (per MTok input/output). Having Haiku do the same job as Opus costs 15x less. The question is which jobs Haiku can handle.

Claude Code’s approach is that its built-in Explore agent defaults to running on Haiku, read-only, specifically designed for searching the codebase. Additionally, Explore and Plan agents skip CLAUDE.md and the parent session’s git status, further reducing context overhead. According to statistics from the Claude Code user community, 36.5% of API calls run on Haiku, but this portion accounts for only 2.3% of total cost ($8/$354). The cheap model absorbs over a third of call volume while spending almost negligible money.

Beyond model tiering, sub-agents also reduce total spending through context isolation. Anthropic’s official documentation provides an example: an Explore agent read 6,100 tokens of files in its own context (session.ts 2,200 + timeouts.ts 800 + config/*.ts 3,100), but when returning to the main agent, it delivered only 420 tokens of conclusions. 93% of intermediate work was discarded, keeping the main agent’s context lean. Beyond that, for specific tasks you can also customize sub-agent agents.md to inject only relevant context — for example, when doing SQL and database tuning, you only need to input relevant business constraints and technical knowledge, and may not need to know how the entire backend codebase is written. In such cases, a dedicated optimization agent can handle the job.

The community has built more systematic approaches in this direction. The three most active currently are: oh-my-claudecode (Claude Code plugin), oh-my-openagent (formerly oh-my-opencode, OpenCode plugin), and oh-my-opencode-slim (a slim version of oh-my-openagent, OpenCode plugin). All three are from different authors and are independently developed.

oh-my-claudecodeoh-my-openagentoh-my-opencode-slim
Stars (at time of research)~34.6k~59k~4.6k
LicenseMITSustainable Use License v1.0 (non-OSI, prohibits commercial redistribution)MIT
Target PlatformClaude CodeOpenCode (+ Codex/Pi adapters in progress)OpenCode
Agent Count19 + tier variants7 core agents + team specialists7-8
Model RoutingHaiku→simple, Opus→complex; supports cross-CLI routing (Codex, Gemini)Auto-routes by task category (quick/deep/visual/ultrabrain)Each agent explicitly specifies model + variant in JSON config

The license differences are worth noting. oh-my-claudecode and slim are both MIT — use freely. oh-my-openagent uses a custom Sustainable Use License v1.0, which allows personal and internal company use but prohibits building commercial products or SaaS on top of it. For personal or team-internal use there is no issue; for commercial product development, slim’s MIT license is safer.

The three tools differ in configuration, but their tiering logic is highly consistent. From the actual configurations of all three tools, I can identify three model tiers and the task types corresponding to each.

Tier 1: Cheap/fast models for legwork

Typical models: Haiku ($1/$5), GPT-5.4-mini ($0.75/$4.50), Gemini Flash, DeepSeek Flash.

Tasks at this tier share a common characteristic: results are deterministic or the cost of error is low. Specifically:

  • File search and code navigation. Finding a function definition in the codebase, grepping a variable name, listing a directory’s file structure. Claude Code’s built-in Explore agent uses Haiku by default for this. oh-my-opencode-slim calls it Explorer (default GPT-5.4-mini), oh-my-openagent calls it Librarian (default Gemini Flash). These tasks are essentially pattern matching and do not require reasoning ability — the model just needs to correctly invoke grep/glob/read tools.
  • Small single-file modifications. Formatting, import sorting, batch-renaming a variable, adding a missing return statement. Small scope, small context — if the cheap model makes a mistake, reverting is trivial. oh-my-opencode-slim specifically has a Fixer agent (default GPT-5.4-mini) for this.
  • Documentation retrieval. Reading external documentation, looking up API usage, searching Stack Overflow. oh-my-opencode-slim’s Librarian (GPT-5.4-mini) and oh-my-openagent’s Librarian both serve this purpose.

This tier’s model spending is virtually negligible. As mentioned earlier: 36.5% of API calls run on Haiku, accounting for only 2.3% of total cost.

Tier 2: Mid-range models for implementation

Typical models: Sonnet ($3/$15), GPT-5.4 ($2.50/$15), Kimi K2.6.

Tasks at this tier require understanding code semantics but do not involve cross-module architectural decisions:

  • Writing tests. Writing unit tests for a function requires understanding the function signature, inputs/outputs, and edge cases, but does not require understanding the entire system design.
  • Fixing simple bugs. Bugs with clear error messages and well-defined locations. A null pointer, an off-by-one, a missing error handler. The fix is typically confined to one or two files.
  • Standard implementation. Writing a new CRUD endpoint following existing patterns, adding a new form field, implementing a feature with a clearly defined interface. No design decisions needed — just follow the existing code’s style.

oh-my-claudecode calls this Tier 2, and oh-my-openagent’s quick category routes here. Augment Code also recommends Sonnet for the implementation layer (citing SWE-bench Verified 79.6%).

Tier 3: Strong models for decisions

Typical models: Opus ($15/$75), GPT-5.5 ($5/$30), Claude Opus 4.7 max variant.

Tasks at this tier carry high costs if done wrong:

  • Architecture design. Choosing the tech stack for a new service, designing cross-module data flows, deciding between a message queue and REST for service-to-service communication. These decisions affect months of development; getting them wrong costs far more in rework than the model fee.
  • Cross-module refactoring. Changing the billing logic in a billing module requires understanding how upstream metering collects data, how downstream invoicing generates bills, and how the subscription state machine transitions. Context spans multiple services, and the reasoning chain cannot break.
  • Security review. Checking authentication flows for vulnerabilities, verifying access controls, looking for SQL injection or XSS. These tasks have extremely high precision requirements — a false negative (an undetected vulnerability) is far more dangerous than a false positive (a false alarm).

Augment Code’s Model Routing Guide corroborates the same tiering logic from a different angle: Opus for coordination, Sonnet for implementation (SWE-bench Verified 79.6%), Haiku for file navigation, GPT-5.2 for code review. Their data shows model routing can cut costs by 40-60%. A 120-person team with $52,000/month in model spending typically sees a 20-35% reduction within 4-6 weeks, without changing developer behavior. Augment later released Prism to automate this process.

When Not to Split

Splitting agents is not free. Done incorrectly, it not only fails to save money but also degrades quality.

As discussed earlier, context is isolated between sub-agents and the main agent. This isolation is the prerequisite for cost savings, but it also comes with a cost: if multiple sub-agents need to share business context, there is currently no good mechanism for it. Although Google has released the A2A (Agent-to-Agent) protocol, in actual coding agent scenarios, I have yet to see an agent team that can do what a human development team does — where one agent directly asks another “what is the business context on your end?” and receives a precise answer.

Current implementations are rather crude. Whenever a sub-agent needs to understand business context, it re-explores the codebase from scratch. Agent A reads 3,000 lines of billing module code to understand the billing logic; if agent B also needs this information, it will not ask agent A but instead read the same 3,000 lines again. Three agents means 3x the exploration cost. A UIUC paper tested across 7 datasets and 6 models and found that multi-agent systems consume 4-220x more tokens than single-agent systems, and even after optimization still require 2-12x more.

My personal criteria for deciding whether to split are roughly as follows:

Good to SplitNot Good to Split
Exploring code in an independent directory (conclusions can be summarized in a few hundred tokens)Cross-service causal reasoning (splitting loses the reasoning chain)
Running tests, lint, formatting (results are pass/fail)Design decisions requiring back-and-forth negotiation (coordination overhead > savings)
Parallel processing of independent filesTightly context-coupled refactoring (every agent has to re-understand the full picture)

A rule of thumb: if you can give the sub-agent instructions in one sentence and its results can be summarized in one paragraph, then it is a good candidate for splitting. If you find yourself writing lengthy background explanations for the sub-agent, that task is not suitable for isolation.


Write: Moving Information Outside the Context

The previous four directions (Select, Compress, Isolate) all operate within the context window. Write takes a different approach: move information that does not need to be constantly present to the filesystem, and have the agent read it back when needed.

Andrej Karpathy mentioned an analogy in his Y Combinator AI School talk: model weights are the CPU (a fixed computation substrate), and the context window is RAM (short-term, volatile, limited-capacity working memory). The MemGPT paper (October 2023, Charles Packer et al.) formalized this analogy into a three-tier architecture:

TierAnalogyFunction
Core MemoryRAMInside the context window, agent reads and writes directly
Recall MemoryDisk cacheSearchable conversation history, stored outside context
Archival MemoryCold storageLong-term storage, agent queries via tool calls

This directly borrows the virtual memory paging concept from operating systems: when data exceeds main memory capacity, pages are swapped between main memory and disk. This later commercialized as the Letta platform.

How Agent Memory Works Today

In terms of implementation, most agents today keep things fairly simple, mostly based on markdown files. This is true not only for coding agents (Claude Code’s MEMORY.md, OpenCode’s AGENTS.md, Codex’s AGENTS.md) but also for general-purpose agents — for example, Hermes and OpenClaw both use markdown files to record memory. One step up, there are SQLite + full-text search approaches (e.g., agentmemory, Engram). Beyond that are vector databases (pgvector is trending — if you already have Postgres, you do not need a separate vector store), as well as dedicated memory platforms (e.g., Mem0 with its three-stage Extraction → Consolidation → Retrieval pipeline). There is also a recent trend of putting everything back into Postgres.

But for the everyday coding agent use case, most of these heavy-weight solutions are over-engineering. Coding agent memory needs differ from general-purpose agents: there is no need to manage personalized state for millions of users or perform temporal reasoning about “what the user said three months ago.” What is needed is cross-session retention of project context and work progress. Markdown files + sensible directory structure + /clear discipline are usually sufficient.

Let me look at specific Write approaches for the coding agent scenario.

Built-in Lazy Loading Mechanisms

Claude Code already has built-in “store externally, load on demand” mechanisms. Auto Memory’s MEMORY.md only loads the first 200 lines into context, with topic files loaded on demand (official docs). AutoDream consolidates memory during idle time — deduplicating, removing stale entries, and merging contradictions. Path-scoped rules (.claude/rules/) only load when operating on matching files. /btw questions and answers do not enter the conversation history. Skills and MCP schema progressive loading were already covered in the Select section. All of these are lazy loading — information enters the context only when needed.

Community Write Patterns

Beyond built-in mechanisms, the community has developed several explicit Write patterns, categorized by use case.

External Spec

In my view, the Spec Driven Development approach that is now essentially standard practice is itself a form of external memory. From a token cost perspective, 50 rounds of discussion accumulating 80k tokens of conversation history can be compressed into a 2k-token spec file, effectively reducing the tokens a coding agent needs to spend finding context.

Work State Persistence and Session Handoff

If the task is not a one-off (e.g., feature development spanning multiple iterations), you need more than just a spec — you need working state that persists and updates across sessions.

The community’s most active approaches in this direction:

Planning-with-files (Manus pattern). Creates three files: task_plan.md (phase breakdown, progress tracking), findings.md (research notes), progress.md (session log, error history). Enforced via hooks: PreToolUse automatically reads the plan before Write/Edit/Bash to refresh goals, PostToolUse reminds to update progress. Manus AI’s own statement: “Markdown is my ‘working memory’ on disk.”

Alive. 5 files + 12 hooks: key.md (project basics), now.md (current state), log.md (immutable decision history), tasks.md (work queue), insights.md (static knowledge). Hooks block deletion of log entries and enforce reading/writing at session boundaries. Alive differs from planning-with-files in that it focuses on project-level persistent knowledge rather than single-task execution tracking.

Agent Kernel. More minimal, 3 files: AGENTS.md (general instructions), IDENTITY.md (agent identity), KNOWLEDGE.md (knowledge directory index). Works across Claude Code, Codex, Cursor, and OpenCode.

These approaches share one thing in common: hooks are the key. Markdown files alone are not enough — as context grows, the agent will skip or misread files. The community’s experience is to use hooks at session boundaries (SessionStart, PreCompact, Stop) to enforce reading and writing, ensuring the agent actually uses these files. The difference from TodoWrite (now called Tasks API): TodoWrite is in-context, present every round, and gone when the session ends. Planning-with-files and similar approaches use real files that survive across /clear and across sessions.

When a session is ending (approaching context limit, or the task entering its next phase), handoff comes into play — how to pass the current state to the next session.

The intuitive approach is to dump the context to a file and have the next session read it. But this treats the symptom, not the cause: 200k tokens of context from the current session, dumped to a file for the next session, is still 200k tokens and will overflow just the same. Good handoff is not “pass the context to the next session” but “compress to 5-10% first, then pass.”

HumanLayer’s ACE-FCA is currently the most concrete implementation. They split work into Research → Plan → Implement phases, with a complete context reset between each phase, passing only a ~200-line (~1,500-token) structured document:

Phase OutputTarget SizeContent
research_doc.md~200 linesProblem summary, relevant files and their purposes, information flow, key findings, recommended approach
implementation_plan.md~200 linesNumbered steps, files to modify, testing approach, dependencies
progress.md~100 linesGoal, completed steps (checked off), current step, remaining work

The key rule: raw file content or search results are not allowed in handoff documents. A sub-agent searches 3,000 lines of code and returns only a 50-line compressed summary. The token budget target is keeping context at 40-60% during active work. They report using this method on a 300k-line Rust codebase.

Matt Pocock (author of grill-me) built a /handoff skill with a similar approach: compress the current session into structured markdown, reference files rather than copy content, store to a temp directory, and start the new session from this file. The difference from /compact: /compact continues within the same session, /handoff switches to an entirely new session. This is also what I am currently experimenting with — compared to other approaches, it is more lightweight and easier to manage.

The community also has a context-save/context-restore skill. /context-save snapshots the current working state to .claude/context.md (what you are doing, key decisions, unresolved issues + git state), and a new session uses /context-restore to recover. The difference from /rewind: /rewind restores code state, context-save restores the understanding of “what you were doing and why.”

Automated Persistent Memory

If manual file management feels too tedious, the community has automated solutions. claude-mem (~74.8k stars) uses 5 lifecycle hooks to automatically capture session data, AI-compresses it into semantic summaries at session end (5,000 tokens → ~500 tokens), and auto-injects in the next session. agentmemory (~9.4k stars) uses the Ebbinghaus forgetting curve for automatic compression and decay, storing approximately 240 observations in ~1,900 tokens (compared to 22,000+ tokens if everything were crammed into CLAUDE.md — a 92% reduction). These benchmarks are from the tools’ own testing and lack independent verification.

What Is Not Write

Two common misconceptions.

  • An overly long CLAUDE.md. CLAUDE.md is always-loaded context, carried in every single API call. Cramming thousands of lines of documentation into it is not “storing outside the context” — it is “forcing it to load every time.” A 5,000-token CLAUDE.md means a 5,000-token tax on every message. Anthropic recommends keeping it under 200 lines (roughly 1,500-2,000 tokens). A good CLAUDE.md is a signpost (telling the agent where to find details), not an encyclopedia.

  • “Store everything in files.” Oracle’s developer blog warns: “saving everything including full conversation logs, every data point, and all outputs causes memory artifacts that grow unbounded.” The principle is to store only information the agent will use, not information the agent can derive from code or git history.

After Writing, Maintenance: Context Drift

The Write strategy has an inescapable problem: after writing, if the code changes but the documentation does not update, the agent works under false premises. In the harness engineering field, this is called context drift. Birgitta Boeckeler’s article on martinfowler.com (April 2026) explicitly lists “how do we keep a harness coherent as it grows?” as an open question, not a solved problem.

Context drift comes in two forms.

  • Structural drift: A file path changes — CLAUDE.md says “billing is in src/billing/” but someone moved it to src/services/billing/.
  • Semantic drift: Code logic changes but the old path remains — CLAUDE.md says “billing charges monthly” but it has been changed to usage-based billing, with src/billing/ still in its original location.

Structural drift already has tooling. ctxlint parses all file paths in CLAUDE.md/AGENTS.md, checks whether they still exist, looks up renames in git history, and cross-checks build/test commands against package.json. Just add npx @yawlabs/ctxlint --strict to your CI. Caliber’s caliber refresh analyzes git diffs and auto-updates CLAUDE.md — it can run as a pre-commit hook.

Semantic drift has essentially no mature solutions. The two closest design approaches are: first, Addy Osmani’s suggestion to write pointers rather than descriptions — “billing logic: see src/billing/README.md.” If the path breaks, ctxlint can detect it. Descriptive text like “billing charges monthly” rots silently. Second, derive from code in real time (Aider’s repo map regenerates from AST with every message; CodeGraph uses filesystem watchers for incremental sync), ensuring context always comes from the current state of the code rather than human-written documentation.

This was also discussed internally on our team (@Xu kunyu). My personal recommendation is to use a GitHub Agentic Workflow to periodically scan documentation and code for alignment, automatically filing a PR when drift is detected. This idea has not been implemented yet — the concept is to make context drift detection and repair part of the CI/CD pipeline rather than relying on humans remembering to update.


Managing Output

Everything discussed so far has been input-side optimization. Intuitively, since output unit price is 5x that of input (Opus $25 vs. $5), optimizing output should be more cost-effective. But looking at actual token distribution tells a different story.

Let me use my actual data from today as an example: Input 1.62M tokens, Output 128.1K tokens (Opus 4.6).

By token count, input is 92.7% and output is 7.3%. This is consistent with community measurements — Branch8’s Claude Code session was 94.5-98.6%, a week-long Cursor test was 97.9%, and a Stanford/Microsoft paper on 2,000+ SWE-bench trajectories was even more extreme at 153

. The reason is that every API call resends the entire context (system prompt + CLAUDE.md + conversation history + files read), so input grows linearly with each round while output stays relatively stable per round.

But when calculated by cost, the picture changes. Using the same data, all at Opus 4.6 standard pricing (ignoring cache):

  • Input: 1.62M × $5/MTok = $8.10 (71.7%)
  • Output: 0.128M × $25/MTok = $3.20 (28.3%)

Though output tokens are only 7% by volume, the 5x unit price means they account for nearly 30% of spending.

If we factor in cache hits (assuming 70% of input hits cache at $0.50/MTok), the picture gets more interesting:

  • Cached input: 1.134M × $0.50 = $0.57
  • Non-cached input: 0.486M × $5.00 = $2.43
  • Output: 0.128M × $25 = $3.20
  • Total: $6.20, output is 51.6%

The higher the cache hit rate, the more input’s actual cost is compressed, and the larger output’s share becomes. After doing a good job on the preceding caching and context optimization steps, output actually becomes the dominant cost driver. So output optimization is not without value — it just becomes salient only after input optimization is well in hand. However, the only widely discussed approach in the community right now is Caveman.

Caveman

Caveman (61k stars, MIT License) is the highest-profile output optimization skill in the Claude Code ecosystem. It uses prompt instructions to make the model respond in extremely compressed language — dropping articles, filler words, and pleasantries, keeping only technical substance.

However, it is controversial. Some testers found that simply writing "be brief" achieves nearly the same effect (419 vs. 401-449 tokens, quality 0.985 vs. 0.970-0.976). Moreover, Caveman only affects output tokens — in input-dominated sessions, the actual cost savings are approximately 7-13%, not the 65% advertised.

In my view, it is better suited for personal use — fine when you can understand it yourself. Defaulting to Caveman for a team is less appropriate: the model saves 200 tokens, but a person spends an extra 5 minutes parsing the compressed response. That may not be a net gain.

Other Directions

If you are building your own agent, another option is the Batch API. Both Anthropic and OpenAI offer Batch APIs with a 50% price discount for non-real-time batch requests. This is suited for scenarios that do not require immediate responses: bulk document translation, batch code review (accumulate a day’s PRs and run them together), batch test generation (generate tests for all functions in a module at once), and batch documentation generation. The key is that these tasks can be batched up and run later without needing synchronous results each time.


Observability and Implementation

First, See Where the Money Goes

If you do not know where the money is going, optimization is fumbling in the dark.

Personally, I use CC Switch. It is primarily a cross-platform API provider management tool (switching API keys, endpoints, failover), but it comes with a usage dashboard for viewing token consumption and cost trends. It supports Claude Code, Codex, Gemini CLI, OpenCode, and OpenClaw.

Beyond official tools, here are the dedicated cost monitoring tools currently active in the community:

ToolStars (at time of research)Supported PlatformsToken Type BreakdownFeatures
ccusage~14.5kClaude Code, OpenCode, and 15 other agentsinput/output/cache read/cache writebunx ccusage zero-install, reads local JSONL, view by day/week/month/session
tokscale~3.1kClaude Code, OpenCode, Cursor, and 22+ agentsinput/output/cache read/cache write/reasoningRust TUI, supports Cursor (requires API sync), contribution graph
agentsview~1.1kClaude Code, OpenCode, and 14+ agentsinput/output/cache read/cache writeLocal web dashboard, SQLite index, 100x faster than ccusage

Both Claude Code and OpenCode write local JSONL logs; ccusage and tokscale just read these files. Cursor does not write local logs; tokscale pulls data via API sync (tokscale cursor login). OpenCode’s own TUI also has built-in session-level token and cost display (real-time updates), so you can see the numbers without installing additional tools.

For self-built agents going through the API, LiteLLM (~48k stars) can serve as a unified gateway supporting 100+ providers, with built-in per-project/per-user cost tracking. However, it requires routing all agent traffic through it, making it considerably heavier than the tools above.

End-to-End Rough Calculation

Using my actual data from today (Input 1.62M, Output 128.1K, Opus 4.6), let me string together the dimensions discussed above into a single cost estimate.

Do nothing, all at standard pricing: Input 1.62M × $5 + Output 0.128M × $25 = $11.30.

Step 1: Cache discipline. Fix system prompt and MCP schema order, disable attribution header, clean up unused MCP tools. Assuming 70% of input hits cache (cached input at $0.50/MTok): Input cost drops from $8.10 to $3.00 (cached 1.134M × $0.50 + non-cached 0.486M × $5.00). Plus output $3.20, total $6.20. Saved 45%. This step requires a one-time configuration change.

Step 2: Reduce wasteful exploration. Write a good CLAUDE.md signpost (tell the agent where the code lives and what the business terminology means), enable LSP for statically typed projects (one find-references replacing 5 rounds of grep). Assuming total session tokens cut by 30%, from 1.62M to 1.13M. Same 70% cache hit: Input cost approximately $2.10, plus output $3.20, total $5.30.

Step 3: Prevent bloat. Install RTK to compress CLI output (80% compression rate), or use lean-ctx to cover file reads and MCP return values. Assuming the session shrinks another 15%, total approximately $4.70.

Step 4: Isolate. Delegate heavy exploration tasks to Haiku sub-agents ($1/$5 vs. Opus’s $15/$75), /clear between different tasks. The exploration portion costs 15x less. The savings from this step depend on how many tasks are suitable for delegation to cheaper models.

Step 5: Output control. Lower /effort for simple tasks, use structured output + Batch API (50% discount) for automation pipelines. After the preceding steps have compressed input costs, output share is already over half — this step’s value becomes apparent.

From $11.30 to approximately $4-5, roughly saving more than half. The biggest contributions come from cache hits (Step 1) and reducing wasteful tokens (Step 2) — these two alone account for most of the savings with the smallest investment.

It bears emphasizing that these numbers are rough estimates. Actual results depend on session structure, cache hit rate fluctuations, and task types. But the order of magnitude should be directionally correct.

Below is the execution order I recommend based on ROI. A necessary disclaimer: this is only my personal recommendation, and our team has not fully completed this entire process ourselves. Some steps (like automated context drift detection) are still at the discussion stage. This post is a set of research notes, not a field report.

Step 0: Observe
  Install ccusage or tokscale, see where the money is going.
  Optimizing without looking at data is fumbling in the dark.

Step 1: Cache discipline (configure once, benefit permanently)
  Fix the order of system prompt and MCP schemas.
  Clean up unused MCP tools.
  Disable the attribution header for local models.
  Install claude-code-cache-fix to fix cache regression in resumed sessions.

Step 2: Reduce wasteful exploration (half a day's work, long-term benefit)
  Write a good CLAUDE.md — a signpost, not an encyclopedia. Keep it under 200 lines.
  Enable LSP for statically typed projects (TypeScript, Rust, Go, Java).
  For large projects, install CodeGraph or a similar AST index.

Step 3: Prevent context bloat (install tools)
  Install RTK to compress CLI output.
  If the agent does heavy file reading and MCP calls, consider lean-ctx.
  Periodically clean up unused Skills.

Step 4: Isolate (change usage habits)
  Delegate heavy exploration tasks to sub-agents on cheap models.
  /clear between different tasks.
  Use worktrees for parallel agents to avoid file conflicts.
  Do not force multi-agent on sequential reasoning tasks.

Step 5: Write (change workflow)
  For complex tasks, generate SPEC.md first, then /clear and execute in a new session.
  For long tasks, use planning-with-files or similar for persistent work state.
  Separate research and implementation — store research conclusions in files, read on demand during coding.
  Periodically check for context drift with ctxlint or Caliber.

Step 6: Output control (icing on the cake)
  Lower /effort for simple tasks.
  Use structured output for automation pipelines.
  Use Batch API for 50% discount on batchable tasks (translation, bulk review).

Do not look at tokens alone. Track at least three categories simultaneously:

CategoryKey Metrics
CostTotal cost, cached input share, output cost share
EfficiencyTool call count, first-attempt success rate, total elapsed time
QualityWhether context is missed, whether incorrect edits are made, whether human correction is needed

If the agent starts missing context, going down wrong paths, or producing lower-quality output, you have cut too much. Good optimization is cost reduction without quality loss.


References

Context Engineering Framework

Harness Engineering

Pricing and Billing

LLM Fundamentals

Token Consumption Research

Multi-Agent Research

Agent Memory

Select Tools

Compress Tools

Isolate Tools and Documentation

Write Tools and Patterns

Context Drift and Maintenance

  • ctxlint — CLAUDE.md/AGENTS.md path validation and auto-repair
  • Caliber — Auto-update CLAUDE.md from git diff
  • claude-code-cache-fix — Fix cache regression in resumed sessions

Output Control and Cost Monitoring