{"slug": "why-your-coding-agents-burn-tokens-in-the-dark", "title": "Why Your Coding Agents Burn Tokens in the Dark", "summary": "A developer built Thermal, a local monitoring tool, after discovering that autonomous coding agents such as Devin and OpenCode consume tokens in ways that make per-dollar cost attribution impossible. The developer's example shows a single agent session burning roughly 215,000 tokens for a two-line test fix, driven by context accumulation, repeated state inspection, subagent spawning and hidden reasoning tokens in models like o3-mini and DeepSeek-R1. The developer rejected piping private codebases and session transcripts into cloud-hosted SaaS monitoring platforms, citing developer privacy and craftsmanship concerns.", "body_md": "A few months ago, around two in the morning, I was sitting in front of my terminal watching three separate tmux panes hum with activity. In one window, Devin was refactoring an AST parser. In another, OpenCode was executing a test-driven loop against a flaky API endpoint. In a third, an experimental agent was indexing symbol references across a dozen repositories.\n\nFrom the outside, it looked like the ultimate dream of modern software development. The screen was a cascading waterfall of syntax highlights, bash commands, unified diff blocks, and passing test assertions. The manual friction of writing boilerplate had vanished into thin air.\n\nThen the monthly API invoices arrived.\n\nThe numbers were not ruinous, but they were deeply unsettling. Not\nbecause of the absolute dollar figure, but because I had no honest way\nof answering the most fundamental engineering question: *what did each\nof those dollars actually purchase?*\n\nWhen you work alongside human engineers, you have an intuitive grasp\nof where time and energy go. You know whether an architectural refactor\ntook three hours or three days. But with autonomous coding agents,\ntoken consumption happens entirely in the dark. As I learned firsthand\nwhen [evaluating coding agents on real tasks](https://jadmadi.net/posts/power-of-jules/),\nfluency is not the same as discipline. An agent gets trapped in an\ninternal linting dispute, consumes six hundred thousand tokens quietly\nre-reading the entire project schema on every single turn, and reports\nback with a single-line patch. You pay for forty-seven model\ninvocations, and you have no idea which prompt triggered the\navalanche.\n\nWe had traded developer ergonomics for financial blindness. And the prescribed solutions (piping private codebases and session transcripts into yet another closed, cloud-hosted SaaS monitoring platform) felt like an insult to developer privacy and software craftsmanship.\n\nSo I decided to build [Thermal](https://jadmadi.net/project/thermal/).\n\n## The Compounding Geometry of Agent Spend\n\nMost developers still calculate AI costs using a simple calculator mental model: you send a prompt of five hundred tokens, get back a thousand tokens, and pay pennies.\n\nThat model dies the moment you deploy autonomous agents.\n\nIn an agentic loop, token expenditure does not scale linearly with\noutput code. It scales exponentially with *execution uncertainty*.\nAs I explored when breaking down Princeton’s research on\n[how agent skills stabilize execution](https://jadmadi.net/posts/demystifying-agent-skills/),\nan agent does not merely answer questions; it observes, reflects,\nprobes tool outputs, and adjusts its internal plan.\n\n```\nflowchart TD\n    subgraph StepLoop[\"Compounding Token Footprint\"]\n        A[\"User Task: 'Fix flaky test'\"] --> B[\"Step 1: Read Workspace Tree (45k tokens)\"]\n        B --> C[\"Step 2: Run Test Runner (12k tokens output)\"]\n        C --> D[\"Step 3: Reread File + Test Traces (65k tokens)\"]\n        D --> E[\"Step 4: Attempt Speculative Edit (15k tokens)\"]\n        E --> F[\"Step 5: Rerun Tests & Self-Correct (78k tokens)\"]\n    end\n    F --> G[\"Total Billed: ~215,000 Tokens for a 2-Line Fix\"]\n```\n\nConsider what happens inside a single agent session:\n\n1. **Context Accumulation:** On step one, the system prompt, tool\nschemas, and repository summary consume thirty thousand tokens.\n2. **Execution Traces:** By step five, the agent has executed three\nfailing shell commands. The terminal stdout and stderr now live\ninside the message history.\n3. **Repeated State Inspection:** To decide what to do on step six,\nthe model must re-read the entire accumulated dialogue from\nscratch.\n4. **Subagent Spawning:** When the primary agent spawns a subagent, a\nfresh context window opens, often inheriting another slice of the\ncodebase.\n5. **Hidden Reasoning Tokens:** Frontier reasoning models (such as\no3-mini or DeepSeek-R1) generate thousands of hidden thinking\ntokens per turn to deliberate before emitting a single line of\nactionable code.\n\nA two-line patch in a test runner can easily burn three hundred thousand tokens across eight round-trips. If that agent runs on a frontier model, an afternoon of aggressive tinkering can quietly cost twenty or thirty dollars.\n\nMultiply that across five tmux windows, seven days a week, and three different agent CLIs, and you are no longer doing software development. You are running an unmonitored compute furnace.\n\n## Why SaaS Dashboards Miss the Point\n\nThe standard Silicon Valley answer to this problem is predictable:\nsign up for a monitoring service, install their npm package, configure\nan HTTP reverse proxy (`HTTP_PROXY`), and stream every prompt, file\npath, and agent transcript to their cloud.\n\nI refuse to do that.\n\nMy local code is my own. The architecture decisions, private client\nkeys, internal database schemas, and scratch notes that pass through\nmy agent sessions have no business living on a third-party server.\nFurthermore, when you work far from central US data centers, adding an\nexternal telemetry proxy injects a punishing latency tax into every\nsingle turn, a reality I wrote about in [Latency Is Political When You\nLive Far from the Center](https://jadmadi.net/posts/latency-is-political-when-you-live-far-from-the-center/).\nIt violates the offline-first resilience of Unix tools, breaks when\ntools enforce custom certificate verification, and creates yet another\nrecurring subscription.\n\nWhen I started digging into how agent harnesses work on disk, I\nnoticed something fascinating: *the telemetry was already there.*\n\nEvery modern coding agent leaves a rich local trail on your filesystem:\n\n- **Claude Code** streams JSONL event logs under`~/.claude/projects/` .\n- **Codex** maintains`state_5.sqlite` alongside rollout JSONL logs.\n- **OpenCode / MiMoCode** records session graphs in`~/.opencode/` SQLite databases.\n- **Grok** logs completed turns in`updates.jsonl` .\n- **Devin, Gemini CLI / Antigravity, Nous Hermes, and DeepSeek** all\nmaintain local SQLite databases or structured JSON files.\n\nThe agents were not hiding their costs. They were diligently saving them to disk. We were simply ignoring the files.\n\nWe did not need another cloud service. We needed a fast, local-first lens.\n\n## Building Thermal: Architecture of a Zero-Telemetry FinOps Engine\n\nWhen I sat down to design Thermal, I set three non-negotiable principles for myself:\n\n1. **Zero Cloud Telemetry & Zero Daemons:** Thermal is 100% offline.\nIt never makes an outbound phone-home ping, requires no cloud\naccounts, and installs no persistent background processes eating\nbattery and RAM.\n2. **Sub-10ms Cached Invocations:** In order to fit naturally into\ninteractive developer workflows (even rendering inside a shell\nprompt like Starship or`.zshrc` ), invoking`thermal` must return in\nsingle-digit milliseconds.\n3. **Strictly Non-Invasive & Read-Only:** Thermal never injects\nwrappers or modifies user databases. It reads what exists without\ninterfering with active tools.\n\nTo achieve this, I wrote Thermal in **Go** as a zero-CGO, statically\nlinked binary.\n\n```\nflowchart LR\n    subgraph Harnesses[\"14 Local Agent Harnesses\"]\n        H1[\"Claude Code (~/.claude)\"]\n        H2[\"OpenCode / MiMoCode\"]\n        H3[\"Codex (state_5.sqlite)\"]\n        H4[\"Devin, Grok, Agy, Hermes...\"]\n    end\n\n    subgraph ThermalCore[\"Thermal Go Core\"]\n        D[\"Parallel Harness Scanner\"] --> M[\"Read-Only SQLite mmap & JSONL Engine\"]\n        M --> C[\"Delta Cache (~/.cache/thermal/)\"]\n        C --> P[\"Disjoint Token Normalization & Pricing\"]\n        P --> S[\"Unified FinOps Aggregator\"]\n    end\n\n    subgraph Presentation[\"Terminal Output\"]\n        S --> TUI[\"Interactive Bubble Tea TUI\"]\n        S --> CLI[\"Terminal Heatmap & Scriptable JSON\"]\n    end\n\n    Harnesses --> D\n```\n\n### 1. Pure-Go SQLite and Memory-Mapped Zero-Copy I/O\n\nMany agent harnesses run on SQLite. If an agent is actively coding\nwhile Thermal executes, opening the database with a standard\nread-write connection causes immediate lock contention (`database is locked`).\n\nThermal opens all SQLite databases in pure read-only URI mode and\nimmediately activates memory mapping via `PRAGMA mmap_size`:\n\n```\n// Pure-Go SQLite (modernc.org/sqlite): CGO-free, read-only, zero lock contention\ndb, err := sql.Open(\"sqlite\", \"file:\"+dbPath+\"?mode=ro\")\nif err != nil {\n    return err\n}\ndefer db.Close()\n\n// Memory-map 256MB of page cache for instant scanning without heap allocation\nif _, err := db.Exec(\"PRAGMA mmap_size=268435456\"); err != nil {\n    return err\n}\n```\n\nBecause Thermal uses [`modernc.org/sqlite`](https://pkg.go.dev/modernc.org/sqlite)\ncompiled with `CGO_ENABLED=0`, the binary remains fully statically\nlinked. It compiles across Linux, macOS, and Windows without requiring\nGCC toolchains or dynamic C libraries.\n\n### 2. The Sub-10ms Delta Snapshot Cache\n\nScanning gigabytes of raw transcripts on every shell invocation is an\nanti-pattern. To guarantee sub-10ms response times, Thermal employs an\nincremental disk-backed delta snapshot cache in `~/.cache/thermal/<tool>/`.\n\nOn startup, Thermal verifies the target file’s modification timestamp\n(`mod_time`), byte size (` size`), or maximum transaction ID. If the file\nhas not changed, Thermal serves the normalized daily aggregation\ninstantly from cache. If new turns have occurred, it reads only the\nunseen byte delta, appends the new rows, and updates the snapshot. Cold\nscans of thousands of sessions take hundreds of milliseconds; warm\ninvocations take **4 to 7 milliseconds**.\n\n### 3. The 32 MiB JSONL Line Ceiling\n\nGo’s standard library `bufio.Scanner` defaults to a maximum token\nbuffer of 64KB. When reading real agent transcripts from Claude Code or\nCodex rollout logs, single lines containing whole-file reads or huge git\ndiffs easily reach 2MB to 10MB. A naive scanner crashes immediately\nwith `bufio.Scanner: token too long`.\n\nThermal implements a specialized streaming scanner constructor\n(`newJSONLScanner`) that configures an explicit **32 MiB buffer\nceiling** with bounded worker pools capped at the machine’s CPU\ncores, guaranteeing that large agent payloads never abort scans\nmid-stream.\n\n### 4. Disjoint Token Arithmetic: Defeating Double-Counting\n\nA major pitfall in building multi-agent telemetry is that AI providers disagree on token categorization:\n\n- **Codex** and**Grok** nest`Reasoning` tokens inside`Output` , and`CacheRead` tokens inside`Input` .\n- **ZCode** nests`CacheRead` inside`Input` .\n- **OpenCode** and**Claude** separate them.\n\nIf you write a naive `jq` or Python script, you end up double-counting\nreasoning and cache reads, producing wildly inflated token numbers.\nThermal enforces **Disjoint Token Arithmetic** directly inside its\nloaders: nested tokens are subtracted at ingestion so that:\n\n$$\\text{Total Tokens} = \\text{Input} + \\text{Output} + \\text{Reasoning} + \\text{CacheRead} + \\text{CacheWrite}$$\n\nRenderers, financial aggregators, and pricing engines never have to perform defensive arithmetic adjustments.\n\n### 5. Repository Attribution via Symlink-Aware Git Walking\n\nDevelopers rarely run agents from repository roots. You run an agent\nfrom `src/components/`, `pkg/api/`, or a symlinked workspace. If a tool\ntracks paths naively, your project list fragments into dozens of\nisolated subfolders.\n\nThermal routes every working directory through `ProjectKey`: it\nresolves filesystem symlinks first (preventing macOS `/var` vs\n`/private/var` duplication), then walks upwards through parent\ndirectories until it finds a `.git` root. All deep subdirectories fold\ncleanly into their canonical repository name without inventing\nsynthetic hashes.\n\n### 6. FinOps Pricing via the models.dev Catalog\n\nTokens are an engineering metric; dollars are an operational reality. Some tools (like OpenCode or Grok) record their exact expenditure directly to disk. Others (like Claude Code or Devin) record raw token counts without dollar figures.\n\nThermal bridges this gap by prioritizing recorded costs when present,\nand falling back to an offline-cached pricing catalog from\n[`models.dev`](https://models.dev) (`~/.cache/thermal/models-dev-catalog.json`).\nIt calculates granular rates across input, output, cache-read, and\ncache-write tokens, stripping runtime variant suffixes (`-high`,\n`-mini`) to match base tiers while strictly avoiding fuzzy regex\nmatching. Crucially, when tokens cannot be attributed to a recognized\nmodel, Thermal prices them at `$0.00` and discloses them honestly in the\nfooter as unattributed tokens, rather than assuming unpriced compute is\nfree.\n\n## The Terminal TUI Experience\n\nI spend my workday in `tmux` and `alacritty`. I did not want to leave\nthe terminal to inspect a browser tab or log into a billing portal.\n\nUsing Charm’s **Bubble Tea** and **Lip Gloss**, Thermal categorizes\nagents into two distinct archetypes: **Token Warriors** (harnesses that\nreport full token telemetry) and **Activity Hunters** (harnesses that\nmeasure turns, prompts, and tool steps).\n\n```\n  THERMAL: Don't break the streak.\n\n  ╭─ Token Warriors ────────────────────────────────── tokens & spend ─╮\n  │  #    Tool           Strk    Best    Days     Tokens      Cost     │\n  │ ─────────────────────────────────────────────────────────────────  │\n  │  1. Devin              2d     33d     45d   19.2B tok   ~$20134.07 │\n  │  2. Codex              2d      7d     48d    1.0B tok   ~$527.11   │\n  │  3. OpenCode           1d     11d     30d   10.6B tok     $62.91   │\n  │  4. MiMoCode           1d      7d     16d    1.2B tok     $56.14   │\n  │  5. Claude             1d      1d      3d    55.5K tok    ~$0.16   │\n  ╰────────────────────────────────────────────────────────────────────╯\n\n  ╭─ Activity Hunters ─────────────────── messages & steps ─╮\n  │  #    Tool           Strk    Best    Days     Activity  │\n  │ ─────────────────────────────────────────────────────── │\n  │  1. Agy               46d     46d     56d   153.5K step │\n  │  2. command-code       3d      9d     48d    10.9K msg  │\n  ╰─────────────────────────────────────────────────────────╯\n\n  >> Agy is on fire with a 46-day streak!\n```\n\nRunning `thermal <tool>` renders a full 52-week ANSI contribution\nheatmap of daily activity, prompt cache hit ratios, and streak\nmomentum. Subcommands provide immediate period rollups (`daily`,\n`weekly`, `monthly`), git-level attribution (` projects`), and model\ndistribution audits (`models`).\n\n## What 14 Agent Harnesses Taught Me\n\nSupporting 14 different tools (Devin, OpenCode, MiMoCode, Codex, Claude Code, Antigravity, command-code, codewhale, Droid, DeepSeek, Grok CLI, Muse, Nous Hermes, and ZCode) uncovered three inescapable truths about modern AI engineering:\n\n### 1. Nobody Uses Just One Tool\n\nDevelopers pick Claude Code for architectural refactoring, OpenCode for deterministic multi-step pipelines, and fast CLI harnesses for quick script generation. When your tools are fragmented, your mental model of expenditure is nonexistent. You assume you spent five dollars, but across four tools, you quietly spent fifty.\n\n### 2. Prompt Cache Hit Rates Are the Ultimate FinOps Lever\n\nWhen an agent harness properly structures its context to take advantage of prompt caching, input token costs drop by up to 90%. Watching your effective cache read rate climb from 25% to 85% in Thermal makes the economic difference tangible: it is the difference between a $0.03 turn and a $0.30 turn on the same model.\n\n### 3. Visibility Directly Restores Intentionality\n\nThe moment you can see your daily token burn rate rendered as an honest terminal heatmap, your habits immediately improve. You stop letting agents loop aimlessly on ambiguous instructions. You write tighter specifications, provide targeted test constraints, and develop an instinct for when to delegate and when to intervene.\n\n## Software Sovereignty in the Age of Agents\n\nThere is a broader philosophical principle at stake here.\n\nIn the 1990s and 2000s, Unix taught us that you own your machine. You\ninspect the running processes with `ps`, monitor memory with `top`, read\nthe system logs in `/var/log`, and maintain total sovereignty over what\nexecutes.\n\nThe early AI era attempted to erode that discipline. As I argued in\n[the open-source AI rebellion](https://jadmadi.net/posts/open-source-ai-rebellion/),\nwe are encouraged to treat foundational models as opaque cloud magic,\nto stream our intellectual property into proprietary vendor proxies,\nand to accept whatever invoice arrives at the end of the month without\nquestion.\n\nI built Thermal because I believe we can embrace the extraordinary power of autonomous coding agents without surrendering our autonomy as engineers.\n\nI keep thinking back to that night at two in the morning, watching the terminal panes scroll in the quiet of my apartment. There is something exhilarating about watching code emerge from an agent’s reasoning loop. But engineering has never been about surrendering judgment to the machine; it is about understanding the cost, the structure, and the consequences of what we put into the world.\n\nWhen you can see the numbers clearly, the spell breaks, and the agency returns to your hands. And in an era where software wants to think for you, keeping your eyes wide open might be the most rebellious thing you can do.\n\nHow do you keep track of what your autonomous agents are actually doing? Are you measuring your token burn locally, or are you still waiting for the monthly invoice to surprise you?\n\n*Thermal is open source and available as a standalone Go binary. If you\nwant to inspect the architecture, run it against your own local agent\nhistory, or read the source, you can find it at\n[jadmadi.net/project/thermal/](https://jadmadi.net/project/thermal/).*\n\nRecommended\n\n## Continue reading\n\nSelected from shared topics, related tags, and the recent archive.", "url": "https://wpnews.pro/news/why-your-coding-agents-burn-tokens-in-the-dark", "canonical_source": "https://jadmadi.net/posts/why-your-coding-agents-burn-tokens-in-the-dark/", "published_at": "2026-11-09 10:20:32.356884+00:00", "updated_at": "2026-11-09 10:20:34.794732+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "large-language-models"], "entities": ["Thermal", "Devin", "OpenCode", "o3-mini", "DeepSeek-R1", "Princeton"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/why-your-coding-agents-burn-tokens-in-the-dark", "markdown": "https://wpnews.pro/news/why-your-coding-agents-burn-tokens-in-the-dark.md", "text": "https://wpnews.pro/news/why-your-coding-agents-burn-tokens-in-the-dark.txt", "jsonld": "https://wpnews.pro/news/why-your-coding-agents-burn-tokens-in-the-dark.jsonld"}}