DEV Community

Cover image for The scarce resource is not tokens, it is my attention — why I built ccdeck
Bargan Constantin
Bargan Constantin

Posted on

The scarce resource is not tokens, it is my attention — why I built ccdeck

I build ccdeck, a local dashboard for Claude Code and Codex sessions. This is the story behind it.

Four agents running, and the machine has been quiet for twenty minutes.

One of the four had stopped to ask me something — a permission prompt for a shell command — and I had not seen it go by. From the outside every terminal tab looked the same: the one that was working and the one that had been holding a prompt since I went for coffee. I found it by clicking through the tabs, and of course it was the agent that had been closest to finished.

The agent was not slow. I was. And nothing in my setup could tell me that. That situation is the one ccdeck was built for.


A tree, drawn as a scroll

The second problem is wider. An agent session is a tree: a main agent, subagents it spawns, tool calls under each of them. A terminal shows that tree as a scroll. Five subagents working in parallel arrive as one interleaved column of text.

The questions I actually had were:

  • what is running right now?
  • what did that subagent do?
  • which one is stuck?
  • what is this costing?

Those are exactly the questions a scroll answers worst. So the first version of ccdeck did one thing: it drew the tree.


Day one

The first commit is dated 12 June 2026: a live graph of Claude Code agents, fed by Claude Code's own hooks. Versions 0.1 to 0.6 are all commits from that same day — richer nodes, a detail view for tool calls, persistence, token usage.

By the end of September the repository had a little over 3,000 commits and about 390 tagged releases. It grew Codex support, cost and quota, several Claude accounts, a desktop app, a machine panel. But the thing I use most is still the narrowest one.


The wait is the metric

Tokens matter, and ccdeck shows them. But tokens were never what I ran out of. I ran out of attention. The expensive part of that afternoon was not the API bill; it was twenty minutes of an agent waiting for me while I did not know.

So the sharpest job of the deck became one sentence: say which agent is blocked on a human, and for how long. Every session stopped on a permission prompt, a question or a finished turn goes to the top of the list, longest wait first, and the count in the topbar jumps to the oldest one. The question stops being which terminal tab and becomes this one.

Everything else on the canvas is context for that sentence.


What I decided it must never do

There are four rules I keep for it.

1. Measure, do not steer. A hook that runs on every tool call could, in principle, allow, deny or rewrite that call. ccdeck's hook cannot: it posts the event to the deck on 127.0.0.1, prints nothing and always exits 0, and a test checks both the source and the running script for exactly that. A dashboard you install on every tool call should not be able to become a participant. The README's sentence for it is the one I hold myself to: it never steers an agent or edits your code, but it is not read-only either — it manages two tools it relies on and refreshes the Codex token it reads quota with, and says so.

2. Name the blindness. When the deck cannot know something, it says so instead of guessing quietly. Codex records no approval request in its log, so a Codex session is never shown as waiting — and the docs say that, rather than leaving the queue to look complete. The tool name next to a wait is an inference, so it is labelled as one.

3. It must work from a cold npx. No config file, no account, nothing to read first. npx ccdeck and a page opens. The npm package has no runtime dependencies at all; anything the deck fetches for itself, it fetches after it is already up.

4. Local first, and honest about what is not. Your sessions, prompts, files, project names and paths never leave the machine. What does go out is listed in the README: a version check, the tools it installs, quota reads signed with your own credentials, status pages — and usage reports about the deck itself (version, system, IP address, a device fingerprint, errors), on by default, with one switch to turn them off. I would rather you read that list than a slogan.


Things I got wrong

A few, because they taught me more than the things that worked.

The hook was slower than its own timeout. The hook declared a 2-second timeout to Claude Code, and its internal deadline started when its main() ran. Measured against a stalled deck, the whole process took 1.84 s idle and up to 2.19 s on a loaded machine — the shell fork, Node's startup and reading a large payload all happened outside the budget. Now the cap counts from process start, the declared timeout is a 3-second backstop, and a test pins the two numbers against each other.

A second deck nobody asked for. Typing ccdeck beside a deck that was already running used to start a second one: port 4317 was busy, so the new deck took a random port, and neither mentioned the other. Now a plain ccdeck opens the running deck's tab — after the deck on that port proves it is yours with the same token handshake the hook uses.

Temperatures that do not exist. I wanted a temperature row on every machine. On a Windows 11 laptop with an Intel i5-9300H, the firmware declares no thermal zones at all, and the one source that has the sensors refuses anyone but an administrator. There is no standard user-mode API for CPU temperature on Windows. So the deck shows a Thermal section only where the machine actually answers, and no row at all where it does not.


What it is not

ccdeck is an instrument panel and a flight recorder, not an orchestrator. It does not schedule agents, assign work or supervise anything. One canvas, no tabs, no kanban is a constraint I keep on purpose: the moment a feature wants a tab bar, it is asking for the canvas.

It cannot answer a prompt for you either. You still switch to the terminal. It tells you which one.


Where it is now

npx ccdeck
Enter fullscreen mode Exit fullscreen mode

Or the desktop app for macOS, Windows and Linux, with the waiting count in the menu bar. Claude Code and Codex CLI on one canvas, local, AGPL-3.0, and every guide on ccdeck.dev says which version it was checked against.

If you run more than one agent at a time, I would like to know what you lose track of. Issues and discussions are open:

Top comments (0)