I Cut 80%+ of Context Overhead in My Coding Agent A developer reports cutting 80%+ of context overhead in AI coding agents by consolidating tools and dynamically activating them, benchmarking that OpenAI's Codex loads 79 tools and consumes 14,534 tokens on a fresh session with a single "hi" message. The approach, implemented in the agent harness Pi, keeps only 4 baseline tools active and places others on standby with TTL cleanup, reducing token waste and improving reasoning. How I Cut 80%+ of Context Overhead in My Coding Agent When you start a session in a modern AI coding agent, a huge chunk of your context window is consumed before you type your first message. Between system instructions, formatting rules, MCP server integrations, and dozens of registered tool schemas, most agent harnesses dump 10,000 to 25,000+ tokens of static overhead into the context window on every turn. On 90% of turns, an agent only needs basic file and shell tools read , bash , edit , write . Specialized tools like browser automation, image generation, web search, or background task runners are needed occasionally, sometimes only once a week. Leaving 25 to 80+ tool definitions active in the LLM function schema 100% of the time wastes tokens, increases latency, and degrades model reasoning by polluting the attention space with irrelevant parameters. I solved this with two design decisions: Action-based tool consolidation. Structuring custom tools from day one to avoid CRUD schema duplication. Dynamic tool activation in Pi. Keeping a baseline of 4 tools active, placing everything else on standby, and letting the model or the user activate tools on demand with zero meta-tool schema overhead and automatic TTL cleanup. Benchmarking turn zero context across agent harnesses To measure the scale of the problem, I tested how different coding agent harnesses handle tool schemas and context on a fresh session by sending a single greeting: "hi" . 1. Codex: 79 tools and 14.5k tokens by default I turned off every external plugin and MCP server in Codex, leaving only two custom skills alongside the default built-in setup. Then, I started a fresh session and sent "hi" . The model answered with a standard one-line greeting "Hi How can I help?" . The thread status showed that the session had already consumed 14,534 tokens 6% of the 258k context window gone on turn zero . Figure 1: Codex context consumption after sending a single "hi". 14,534 tokens consumed before any actual work begins. When I asked the agent which tools were currently active and callable, it returned 79 active tools . Click to view the full list of 79 active tools loaded in Codex apply patch codex app automation update codex app create thread codex app fork thread codex app get handoff status codex app handoff thread codex app list archived threads codex app list projects codex app list threads codex app load workspace dependencies codex app navigate to codex page codex app open in codex codex app read thread codex app read thread terminal codex app send message to thread codex app set thread archived codex app set thread pinned codex app set thread title codex app share thread codex app wait threads create goal exec command get goal image gen imagegen list available plugins to install list mcp resource templates list mcp resources mcp codex apps codex document control execute document command mcp codex apps codex document control get document tool schemas mcp codex apps codex document control list document sessions mcp codex apps plugin management get app permissions mcp codex apps plugin management get plugin dependencies mcp codex apps plugin management uninstall app mcp codex apps plugin management update app permissions mcp codex apps safety settings get family info mcp codex apps safety settings get parental controls mcp codex apps safety settings get trusted contact mcp codex apps safety settings prepare parental control update mcp codex apps safety settings update parental control mcp codex apps sites add custom domain mcp codex apps sites change site slug mcp codex apps sites create site mcp codex apps sites create source repository write credential mcp codex apps sites deploy private site version mcp codex apps sites deploy site version mcp codex apps sites generate siwc bypass token mcp codex apps sites get deployment status mcp codex apps sites get environment variables mcp codex apps sites get site mcp codex apps sites get site version mcp codex apps sites get site worker logs mcp codex apps sites list custom domains mcp codex apps sites list site versions mcp codex apps sites list sites mcp codex apps sites read database overview mcp codex apps sites read database table rows mcp codex apps sites refresh custom domain status mcp codex apps sites remove custom domain mcp codex apps sites save site version mcp codex apps sites update environment variables mcp codex apps sites update site access mcp codex apps sites update site metadata mcp node repl js mcp node repl js add node module dir mcp node repl js reset multi agent v1 close agent multi agent v1 resume agent multi agent v1 send input multi agent v1 spawn agent multi agent v1 wait agent plugin management uninstall plugin read mcp resource request permissions request plugin install update goal update plan view image web run write stdin If you enable just one or two extra plugins, such as security scanners or GPT apps, the active tool list passes 100 callable tools. 2. Gemini and Antigravity: fewer tools, still 19.9k tokens You might assume that keeping the tool list shorter avoids context bloat. The Antigravity CLI agy with Gemini 3.7 Flash shows that tool count alone is not the whole story. I ran the exact same test: I opened a fresh session and sent "hi" . The response was a single line "Hello How can I help you with your project today?" . The telemetry reported that 19.9k tokens were consumed immediately on turn zero, with 13.8k tokens taken up by tool schemas alone. Figure 2: Antigravity CLI context breakdown after sending a single "hi". 13.8k tokens consumed by tool schemas alone. Antigravity had only 17 tools active, not 79. Yet its tool schemas consumed 13.8k tokens by themselves. Click to view the 17 active tools in Antigravity 1. run command 2. manage task 3. schedule 4. define subagent 5. invoke subagent 6. manage subagents 7. send message 8. write to file 9. replace file content 10. view file 11. list dir 12. grep search 13. find by name 14. search web 15. read url content 16. generate image 17. ask question The redundancy problem Why create dedicated LLM tools for list dir , grep search , and find by name when the agent already has run command native bash ? An agent with bash access runs ls , grep , rg , or find directly. Building separate function schemas for basic shell operations duplicates capabilities the model already has, while adding thousands of tokens of JSON schema definitions, parameter documentation, and edge-case instructions to every turn. 3. Claude Code: built-in baseline and the MCP dilemma Anthropic recognized this problem in Claude Code and introduced Deferred Tool Loading . Out of the box without any MCP servers, Claude Code maintains a baseline of around 8 to 10 built-in tools Bash , View / Read , Edit , Replace , Glob , Grep , Agent , WebSearch , NotebookEdit . Combined with system prompts and project instructions, turn zero consumption sits around 3,500 to 5,000+ tokens . When developers connect multiple MCP servers for databases, issue trackers, or browser automation, the tool registry passes 30 to 40+ tools , pushing the tool schema payload alone to over 10,000 to 14,000+ tokens per turn. To handle this, Claude Code splits tools into two tiers when deferrable definitions exceed 10% of the context window: Always Loaded: Core file and search tools plus infrastructure Bash , Read , Edit , Write , Glob , Grep , Agent , ToolSearch , Skill . Deferred Name-only : WebSearch , NotebookEdit , cron automation tools, and all connected MCP extension tools. Always Loaded: Bash, Read, Edit, Write, Glob, Grep, Agent, ToolSearch, Skill Deferred Names only until fetched : WebSearch, TodoWrite, NotebookEdit, CronCreate, MCP servers... While deferred loading reduces turn zero bloat when many MCPs are active, its discovery mechanism relies on an LLM meta-tool ToolSearch : - When the model needs a deferred tool, it must first execute ToolSearch "select:ToolName" . - The backend injects the full schema into the context, and only on the following turn can the model execute the tool. - To prevent the model from forgetting loaded tools during context compaction, the runtime maintains custom boundary metadata and compaction recovery logic. - Even in its minimal state, Claude Code keeps 9 tools permanently loaded including redundant search tools and the ToolSearch meta-tool itself , maintaining a baseline overhead of several thousand tokens. Note on Claude Code numbers: Because I do not use Claude Code personally, these figures are based on technical analyses, telemetry shared by other engineers, and community discussions online. I used the lower-bound estimates reported by active users across standard setups. Why turn zero overhead degrades agent performance This design pattern across modern harnesses creates two problems: Token cost and context exhaustion. Burning 14k to 20k tokens on turn zero means you hit context limits and rate quotas faster. Over a multi-turn session with long reasoning chains, you re-send those 17 to 80+ tool schemas on every single request. Attention dilution and tool confusion. Models perform best when their decision space is focused. When an LLM sees dozens of similar tools multiple thread management endpoints, site deployment tools, multi-agent spawners, duplicate search utilities , it burns reasoning capacity sifting through irrelevant options and is more prone to parameter hallucinations or picking the wrong tool. Principle 1: action consolidation instead of CRUD APIs Cutting context bloat does not start with runtime tricks. It starts with how you design individual tools from day one. In traditional software engineering, REST and CRUD principles encourage creating granular endpoints for every verb: memory read memory write memory update memory delete This makes sense for HTTP APIs because registering an extra endpoint in code has zero runtime payload cost until a client makes a request. For AI agents, that assumption fails completely. Every tool schema is sent across the wire and loaded into the LLM context window on every turn. Four separate CRUD tools mean four JSON headers, four descriptions, four parameter objects, and four entries crowding the model's decision space. Action-based tool consolidation When I design custom tools for agents, I consolidate operations by intent. For memory, I split the interface into at most two tools: memory read : Handles semantic search, keyword lookup, and fetching specific memories. memory write : Handles storing new memories, updating existing entries, and deleting memories by passing an action parameter "create" | "update" | "delete" . { "name": "memory write", "description": "Create, update, or delete entries in agent memory.", "parameters": { "type": "object", "properties": { "action": { "type": "string", "enum": "create", "update", "delete" , "description": "The mutation action to perform." }, "id": { "type": "string", "description": "Memory ID required for update or delete ." }, "content": { "type": "string", "description": "Memory content required for create or update ." } }, "required": "action" } } The schema for memory write is only about 15% to 20% larger than a single memory create schema, but it replaces three separate tool definitions with one. You cut the schema footprint by 50% without losing any functionality. If I want to be even more aggressive with token efficiency, I collapse all memory interactions into a single memory tool with an action enum search , fetch , create , update , delete . Modern LLMs handle action-parameterized tools reliably. I have run tools structured this way for months across diverse tasks, and the models pick the correct action without hesitation. These architectural savings take effect before dynamic tool activation or prompt injection ever touches the system. Principle 2: dynamic tool activation in Pi Lessons from denkr.ai I ran into this exact bottleneck months ago when building my mobile app, denkr.ai https://denkr.ai . On mobile workflows, context bloat directly degrades latency and unit economics. I built an early variation of dynamic tool routing in Denkr, loading tools contextually based on intent. It proved that models have no issue activating tools when they need them, provided the instructions are clear and the interface is frictionless. When I switched to Pi as my daily coding agent, I wanted the same lean setup. Because Pi is open source and gives developers full control over runtime lifecycle hooks, building this was straightforward. How dynamic tool activation works The extension dynamic-tools operates on four core mechanics: - A hard default of 4 active tools read , bash , edit , write . - Standby tool registration with zero-schema prompt injection. - In-process bash interception for activation pi-tool . - Co-activation groups and automatic TTL pruning. +-------------------------------------------------------------+ | User Prompt | +-------------------------------------------------------------+ | v +-------------------------------------------------------------+ | Pi Hook: before agent start | | - Active tools set to: read, bash, edit, write | | - Injects minimal Markdown standby tool list into prompt | +-------------------------------------------------------------+ | v +-------------------------------------------------------------+ | LLM decides to use a standby tool | | Runs bash: pi-tool activate browser use | +-------------------------------------------------------------+ | v +-------------------------------------------------------------+ | Pi Hook: tool call | | - Intercepts bash command in-process | | - Calls pi.setActiveTools ...defaults, ...browserTools | | - Rewrites bash command to safe stdout echo | +-------------------------------------------------------------+ | v +-------------------------------------------------------------+ | Pi Hook: agent settled | | - Decrements run TTL on non-default tools | | - Automatically purges expired tools back to 4 defaults | +-------------------------------------------------------------+ Technical mechanisms under the hood 1. Minimal default baseline 4 core tools At startup, the extension forces Pi's active tool schema to only 4 tools: js const DEFAULT CONFIG = { defaultTools: "read", "bash", "edit", "write" , groups: { web search: "web search", "web fetch" , browser use: "browser open", "browser observe", "browser preview", "browser diagnostics", "browser act", "browser wait", , loops: "loops report", "loops create definition", "loops create job", "loops inspect" , }, autoResetOnSessionStart: true, toolTtlRuns: 2, }; Any extension registered in Pi via plugins, MCP, or local scripts is loaded by Pi internally, but excluded from the active LLM schema using pi.setActiveTools ... . 2. Zero-schema overhead: prompt injection instead of meta-tools A common mistake when building tool managers is creating a dedicated LLM meta-tool like activate tool { name: string } . Adding a meta-tool adds its own JSON schema overhead, parameter documentation, and function-calling indirection. Instead, I use Pi's before agent start hook to append a plain, lightweight Markdown summary to the system prompt: js pi.on "before agent start", async event, ctx = { await loadConfig ; applyActiveTools ; const standby = getStandbyTools ; if standby.length === 0 return; const standbyLines = standby.map name = { const group = findGroupForTool name, config.groups ; return group ? - \ ${name}\ part of group: ${group} : - \ ${name}\ ; } ; const injection = " Dynamic Tool Activation", Default active tools: ${config.defaultTools.map t = \ ${t}\ .join ", " }. , "Standby tools not currently in your active schema :", ...standbyLines, "", "To activate a tool or group, run in bash: pi-tool activate