DEV Community

Cover image for Your AI coding agent writes everything to disk. I built a local cockpit to actually read it.
Young Gao
Young Gao

Posted on

Your AI coding agent writes everything to disk. I built a local cockpit to actually read it.

If you use Claude Code or OpenAI's Codex CLI every day, there's a pile of data in your home directory you've probably never opened: every session, every tool call, every token count, written as plain JSONL under ~/.claude/projects and ~/.codex/sessions.

The CLIs treat these files as internal state. I spent a few weeks treating them as a dataset instead, and built cocopit, a local-first web console on top of them.

The itch

Three things kept bugging me.

I couldn't see cost. A subscription hides per-session cost, but the transcripts contain exact token counts for every call. Multiply by model pricing and you know precisely what each session would have cost on the API. That's the number I want when deciding whether letting an agent grind on a refactor for two hours was worth it.

History was write-only. Hundreds of sessions, none of them readable. One 3.4k-line session I sampled had 14 actual user messages. Fourteen. The rest was tool calls, hook output and other machinery. Nobody reads that in raw JSONL.

Sessions were stuck in one terminal. A long agent run lives in whatever terminal started it. I wanted to check on it, or keep it going, from another machine or my phone.

What it does

Analytics. An incremental indexer tails the JSONL files into SQLite (FTS5 for search). Every usage event gets priced per model, including the cache-read vs cache-write distinction that dominates real costs. The dashboard shows spend over time, model mix, cache hit rates, and live quota windows per account.

Making transcripts readable. The main lesson from this part: a record with role: "user" is usually not the user speaking. Hook output, IDE context injections, slash-command plumbing and tool results all arrive wearing the user role. If you render records one per row, the transcript is unreadable and half of it gets attributed to a human who never typed it. So cocopit classifies everything first. Tool calls fold into one-line summaries, injected context collapses into small metadata chips, subagent transcripts open in place, and what's left actually reads like a conversation.

A real terminal in the browser. Sessions run inside tmux on the host, so the web terminal can attach, detach and survive reconnects. Any indexed session can be resumed from its detail page, including from a phone. There's a touch key bar for Esc/Tab/arrows because mobile keyboards don't have them.

Multi-account. Isolated config dirs per account (CLAUDE_CONFIG_DIR / CODEX_HOME), so work and personal accounts run side by side, each with its own quota display.

What I didn't expect: Codex's data

Supporting Codex properly meant discovering that one machine's session files mix seven different origins: the CLI, the Desktop app, VS Code, the SDK, codex exec, a Chrome extension, and sessions driven remotely from ChatGPT. My own archive had all seven.

The transcripts also contain things I had to reverse-engineer one by one: flattened imports of other agents' tool activity (4,500+ call/result marker pairs in my local files, with no call IDs — arrival order is the only way to pair them), memory-system citation blocks meant for machine parsing, and plugin @-mentions stored as plugin:// markdown links. Rendered verbatim, each of these looks like garbage. Parsed, each one turns out to be genuinely useful.

Design constraints

  • Local-first, zero telemetry. The index lives in ~/.cocopit/index.db and nothing leaves the machine. Binding to a non-localhost address requires an access token, on purpose.
  • Read-only by default. The few write paths that exist (plugin toggles, config profiles) are surgical line edits with automatic backups.
  • Not a wrapper. It never sits between you and the CLI. If cocopit dies mid-session, nothing about your workflow changes.

Try it

bunx cocopit        # needs Bun ≥ 1.2
# → http://localhost:7433
Enter fullscreen mode Exit fullscreen mode

Repo: https://github.com/gps949/cocopit (MIT). All README screenshots are generated demo data — there's a scripts/demo.ts that writes fake sessions to /tmp, because putting real transcripts in marketing material felt wrong.

If you've got an unusual setup (multiple accounts, heavy subagent usage, Codex driven from ChatGPT), I'd especially like to hear what breaks.

Top comments (0)