pitwall

command module
v0.13.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 1, 2026 License: MIT Imports: 27 Imported by: 0

README

pitwall

The instrument panel for a fleet of coding agents.

When you run four or five Claude Code agents at once, the hard part stops being the code. It becomes: which one is blocked on me, what is this costing, what did they leave behind, and which of my habits is burning the budget.

pitwall answers all four from data already on your disk. One binary, no dependencies, nothing leaves the machine.

Two things it shows that other tools do not:

  • How full each agent's context window is. This is the resource that runs out first and least visibly. Money is recoverable and quota resets on a schedule; a conversation forced into a compaction loses what it knew, and nothing warns you before it happens.
  • What your subagents cost. They live in a subagents/ directory that usage trackers skip, and on the machine this was built on they are 23% of the spend across nearly as many messages as the main conversation.
$ pitwall

pitwall  Mon 12:05

  agents  1 WAITING · 2 DONE · 1 WORKING
          ▲ WAITING mds-0e     asks: Drop the legacy index before backfill?
          ✔ DONE    fleety-c8  Shipped to prod. 63 drivers imported, tests…
  spend   $254.74 today   $254.74 in the last 5h   burn $50.95/h
  git     44 worktrees   30 removable (2.5 GB)   1 holding unsaved work

pitwall fleet · burn · tree · coach

The part that is actually new

Everything above is telemetry. pitwall coach is the opinion:

$ pitwall coach

pitwall coach  $17,015.77 across 3373 prompts · 2026-07-30 – 2026-08-31

  what a prompt bought  prompts  spend      share
  execute               889      $8,763.63  52%   wrote or changed code
  investigate           1883     $8,094.75  48%   read, searched or ran things — changed nothing
  talk                  601      $157.39     1%   no tool calls at all

1. "max" carries your spend but "xhigh" delivers more per dollar
   $3,125.98 · 18% of spend · association, not a controlled test
     max      $14111   2320 prompts  $2.42 per code change
     high      $2603    598 prompts  $3.07 per code change
     xhigh      $301     83 prompts  $1.13 per code change
     full gap would be $7532; scaled to $3126 because "xhigh" has only 83 prompts behind it
     → run a week at xhigh and compare — pitwall records the answer either way

2. Sessions restart from zero in repositories with no primer
   $3,121.83 · 18% of spend · association, not a controlled test
     the first 3 prompts of a session are 23% of all spend
     without a primer: $7.84 per opening prompt, 53 tool calls each
     with one:        $1.55 per opening prompt, 18 tool calls each
     → pitwall primer fleety   — drafts a CLAUDE.md from what past sessions discovered

3. Answers that end in a question, followed by a one-line reply
   $2,365.85 · 14% of spend
     171 round trips; each one pays for a full turn to ask and another to resume
     → state the decision up front: which files, what done looks like, what not to touch

Findings are ranked by what they cost, and anything that is a correlation rather than a controlled measurement says so on its own line.

Requirements

Claude Code Any recent version. pitwall reads what it writes to ~/.claude, so there must be some history there to read.
OS macOS, Linux or Windows. The menu bar app is macOS only.
git Only for pitwall tree. Everything else works without it.
Go 1.23+ Only if you build from source.
Xcode command line tools Only for the menu bar app.

Nothing else. The binary is statically linked and carries no dependencies.

Install

Homebrew (macOS and Linux)
brew install sur1cat/tap/pitwall

sur1cat/tap is this project's own tap rather than homebrew-core, so the prefix is part of the command. One brew tap sur1cat/tap up front lets you drop it afterwards.

Go
go install github.com/sur1cat/pitwall@latest

Installs into $(go env GOPATH)/bin, which is ~/go/bin by default. Add it to your PATH if it is not there already.

Script
curl -fsSL https://raw.githubusercontent.com/sur1cat/pitwall/main/install.sh | sh

Downloads the release build for your platform into ~/.local/bin and tells you if that is not on your PATH. Set PREFIX to put it elsewhere:

curl -fsSL .../install.sh | PREFIX=/usr/local/bin sh
By hand

Take the archive for your platform from releases, unpack it, and move pitwall onto your PATH. This is the route for Windows, where the archive is a .zip.

From source
git clone https://github.com/sur1cat/pitwall
cd pitwall
make build            # ./bin/pitwall
make install          # into $GOBIN, or ~/go/bin
Check it worked
pitwall version
pitwall doctor         # what pitwall can and cannot read here

doctor walks the whole chain pitwall depends on — the config directory, the transcripts, the prompt history, the settings files, its own cache, git, the plan credential — and names the first link that is broken. An empty screen and a broken one look identical, and this is how to tell them apart.

First run

In this order:

pitwall                # what is happening right now
pitwall burn           # what it has been costing, by model and effort level
pitwall perms          # which of your permission rules can never match
pitwall tree           # what your agents left behind on disk
pitwall coach          # which of your habits costs the most

coach reads every transcript on the first run, which takes a few seconds on a large corpus; after that it is served from a cache and is instant. Everything above only reads. The two commands that change anything — pitwall perms fix and pitwall tree gc — say so, are a dry run by default, and back up whatever they touch.

Wire it into Claude Code

Three optional pieces, each independent of the others.

A status line, so every session shows what it is spending:

pitwall install          # --print to see the change first, --remove to undo

This adds a statusLine entry to ~/.claude/settings.json and backs up the previous file next to it.

The plugin, which adds a /pitwall command and a hook that offers a primer when you open an unprimed repository:

claude plugin marketplace add sur1cat/pitwall
claude plugin install pitwall

The menu bar app, so none of this needs a terminal open:

brew install sur1cat/tap/pitwall-bar
pitwall-bar

or from a checkout:

make bar && open bar/build/PitwallBar.app

The app is compiled on the machine that installs it rather than shipped as a notarised bundle. That is deliberate: an app downloaded from the internet carries a quarantine attribute that an ad-hoc signature will not clear, while one built locally starts without argument. The cost is that Xcode's command line tools are needed.

To have it come back after a reboot, add PitwallBar.app to System Settings → General → Login Items.

In the menu bar

Six tabs behind the click — Status (who needs you, today's spend, plan left, worktrees, with a button that cleans them up), Coach (the findings, rendered natively), Rules (the permission rules that can never match, and a button that removes them), Projects (per-project primer and effort level), Prompts, and Setup (what the menu bar shows, notifications, language). Clicking an agent brings its terminal tab to the front. Notifications fire once when an agent asks a question or finishes, and never while it is working. Details in bar/README.md.

Update and uninstall

brew upgrade pitwall                     # Homebrew
go install github.com/sur1cat/pitwall@latest   # Go

brew uninstall pitwall pitwall-bar
rm ~/.local/bin/pitwall                  # if installed by the script
pitwall install --remove                 # take the status line back out
rm -rf ~/.claude/pitwall                 # pitwall's cache and quota readings

pitwall keeps nothing else. Removing ~/.claude/pitwall costs you the scan cache and the quota history behind the pace measurement; nothing else changes.

If something looks wrong

An empty screen, or an analysis that finds nothing — run pitwall doctor. It reports every file pitwall needs and which of them is missing. The usual answer is that Claude Code has written nothing to ~/.claude/projects yet, or that CLAUDE_CONFIG_DIR points somewhere else.

Numbers cover less time than you expect — Claude Code deletes transcripts after cleanupPeriodDays, 30 by default. pitwall burn says so once the archive has reached that boundary. Raise it in ~/.claude/settings.json.

pitwall quota says it cannot read your plan — it needs the OAuth token Claude Code stored. On macOS that is in the Keychain and the system asks for permission once. CLAUDE_CODE_OAUTH_TOKEN also works.

The menu bar app will not open — if it was downloaded rather than built locally, macOS quarantines it. Build it from source, which is what the formula does.

A worktree command finds nothing — pitwall tree needs git on the PATH.

Surfaces

Command What it answers
pitwall Everything at a glance, in under two seconds
pitwall fleet Which agent is waiting, working, or done — and wait blocks until one needs you
pitwall burn What usage costs, by model, effort level, project, session and day
pitwall perms Which permission rules can never match, and perms fix removes them
pitwall burn top --by branch What a feature cost, which no other tool answers
pitwall recall Bring back what a compaction threw away
pitwall tune Settings worth changing, from what your usage measures
pitwall drift Which server-side switches moved under you, and when
pitwall doctor What pitwall can and cannot read here, and why a screen is empty

The context reading is derived from each session's newest message — input plus both kinds of cache, which is what occupies the window — against the model's published size. A model whose window pitwall does not know gets no reading rather than a guessed one: a bar that is wrong is worse than one that is absent, because a wrong one gets acted on. In a status line the figure comes from Claude Code itself, which hands it over already computed. | pitwall tree | Which git worktrees your agents left behind, and which hold unsaved work | | pitwall quota | How much of your plan is left, from Anthropic, with a projection | | pitwall coach | Where your spend actually goes and what would change it | | pitwall primer | A draft CLAUDE.md built from what past sessions learned about a repo | | pitwall focus | Brings an agent's terminal tab to the front | | pitwall lint | Checks a prompt against the shapes that needed fewest follow-ups | | pitwall tree prep | Copies the local config a fresh worktree is missing |

Each has --help. Everything takes --json.

fleet — who needs you

WAITING is derived rather than reported: a tool call with no result while the agent is not running means it is parked on a human — a question, or a permission prompt. pitwall fleet wait turns that into a shell primitive:

pitwall fleet wait && say "an agent needs you"
pitwall fleet watch --exec 'terminal-notifier -message "$PITWALL_NAME: $PITWALL_STATE"'
doctor — what pitwall can read, and what Claude Code is keeping

Alongside the chain of files pitwall depends on, doctor accounts for what Claude Code keeps in its own directory. That is 2.3 GB here and nothing else reports it: the worktree scan covers what agents leave in repositories and says nothing about this, though the two are the same size. Shell snapshots older than a week are named separately — each records one session's shell environment, so once that session is gone it reproduces nothing.

drift — what changed under you

Part of how Claude Code behaves is decided by switches the server turns on per account. When one moves, it is felt as the model getting better or worse for no visible reason: the April 2026 postmortem found effort had silently moved from high to medium for a month before anyone could prove it. The prevailing view is that this cannot be checked locally.

It can. The switches are cached in ~/.claude.json — here, 190 of 459 are on — so recording them turns a feeling into a diff:

$ pitwall drift
190 of 459 server-side switches are on for your account

since your last reading 43h ago
  off  claude_code_skills_dashboard_enabled_cli
  new  tengu_amber_flint

What a switch does is not knowable from here; most are codenames. This says that one moved and when, which is the part you cannot otherwise get. A reading is recorded only when something moved or a day has passed, so the history stays readable.

tune — the knobs, and what turning them costs

Claude Code has settings for the two things people complain about most, and they sit in a reference nobody reads with numbers nobody has. pitwall tune supplies the numbers.

  • autoCompactWindow decides when a conversation is summarised. The automatic trigger fires at the very edge of the window — here, at a median of 1,000,333 tokens with 1.7% spread — and the usual complaint is that it lands when a task is nearly done. Lowering it means compaction happens sooner, more often, loses less each time, and at a point you chose.
  • disableBundledSkills, autoMemoryEnabled, includeGitInstructions cut what a session loads before you type. That is 34.1K tokens here, every time.
  • cleanupPeriodDays stops your transcripts being deleted.

Every suggestion says what it trades away, because a setting that only saved money would already have been found. --write applies the ones you have not already set, after copying the file.

quota — how much is actually left

The most common complaint about Claude Code is hitting a limit with no warning. Claude Code itself knows the answer: it calls a usage endpoint that returns the utilisation of both windows. pitwall calls the same one, with the credential Claude Code already stored.

$ pitwall quota

  window   used               resets in  at this pace
  5 hours  ▮▮▮▯▯▯▯▯▯▯▯▯  33%  1h03m      lasts the window
  rolling  ▮▮▮▮▮▮▮▯▯▯▯▯  65%  70h23m     runs out in 52m  (pace of the last 1h37m)

The projection extrapolates the pace used so far inside the window, and says what it extrapolated from — a burst right after a reset produces a short projection, and you should be able to see that rather than be alarmed by it. It stays silent when the window would reset before the pace ran it out.

The rolling window is labelled weekly by Anthropic but is observed to reset every 72 hours. That is not documented, so pitwall says so instead of implying otherwise.

pitwall effort --guard uses this number: when either window passes a threshold, it lowers the effort level new sessions start at, and restores it when the pressure drops.

quota — how much is actually left

A plan stacks several limits and only one of them is on the dashboard. pitwall shows every window the API reports: the rolling five-hour one, the weekly one, and the per-model weekly windows where a plan has them — those run out on their own schedule, and hitting one is indistinguishable from hitting the overall limit unless both are on screen. Pay-as-you-go usage beyond the plan is shown too when it is switched on.

burn — what it costs, priced properly

Cache writes are not input tokens: a 5-minute-TTL write costs 1.25× the input rate, a 1-hour write 2×, a cache read 0.1×. Claude Code records the TTL split per request, and pitwall uses it — which matters when 98% of your tokens are cache reads. Messages replayed by session forks are counted once. Models with promotional launch pricing are billed at the rate that applied on the day.

Three numbers appear here that nothing else reports. What a session cost before anyone typed — the system prompt, tool definitions, skills, plugins, MCP servers and CLAUDE.md all arrive in the first request and are paid for, and the counter you see starts afterwards; the median here is 34.1K tokens, which matches an independent community measurement of ~34,433. What a compaction cost in tokens dropped and time waited. And what a branch cost, via burn top --by branch, which is the closest thing on disk to "what did this feature cost".

Subagents are counted and shown separately. Their transcripts live in a subagents/ directory, they carry isSidechain, and on this machine they are 23% of the spend across nearly as many messages as the main conversation — a fan-out cost that most trackers skip entirely and that nobody notices until it has its own line.

On a subscription these numbers are the value you consumed, not an invoice, and every screen says so.

Spans are written the way people write them: --since 30d, --since 2w, --since 12h, or a bare --since 30 meaning days.

perms — the rules that can never match

Claude Code's "Yes, and don't ask again" writes a rule into .claude/settings.local.json. Over a year that accumulates, and a large share of what accumulates cannot do anything. pitwall perms reads every settings file that carries permission rules and sorts them by why they fail, following Claude Code's documented matching behaviour rather than guesswork:

  • secret — a credential is written into the rule text. Reported as a count and a file, never echoed: printing it would copy the secret into a terminal, a scrollback buffer and very likely another transcript.
  • fragment — a comment line, or a piece of a multi-line block saved with its newlines encoded. Not a command, so it never matches one.
  • unmatchable — the rule text contains a shell separator. Claude Code matches each subcommand independently, so such a rule can never match.
  • ignored — Claude Code skips it at load: an mcp__ rule with parentheses, a rule on a tool's primary content field such as Bash(command:rm *), or an allow glob not anchored to a literal server.
  • never-consulted — a path rule on Write, NotebookEdit, Glob or MultiEdit. File access is only checked against Read and Edit rules.
  • wildcard-inside — a * before the end. In Bash(git * main) the * stands in for the subcommand, which includes -c, and git -c runs a program you name.
  • shadowed and duplicate — a broader or identical rule already covers it.
  • one-off — no wildcard at all, so it matches that one command forever.

It also shows which single prefix rule would replace how many one-offs, and stops there: widening a permission is a decision for the person who owns the repository, so pitwall prints the arithmetic rather than acting on it.

pitwall perms fix cleans up what cannot work. It is a dry run until you add --write, it copies every file into ~/.claude/pitwall/perms-backups before changing it, and it never touches managed settings. Two limits are deliberate:

  • It never widens a permission. Repairing Write(src/**) to Edit(src/**) would grant access that the broken rule does not grant today, so an allow rule is reported and a deny or ask rule is corrected. The same holds for Bash(command:rm *) and every other ignored form.
  • Working rules stay. A literal rule such as Bash(npm run build) is clutter, not a fault; removing it means Claude Code asks again. --drop-one-offs removes them if that is what you want.

Everything else in the file survives byte for byte, in its original key order, so the diff you review is the change and nothing else.

recall — what the compaction threw away

When Claude Code summarises a conversation to fit, the detail is gone from the model and there is no way to ask what it was. This is the most-repeated complaint about the tool, and the usual phrasing is "hours of context, no warning, no way to get it back".

The second half of that is not true. The boundary record lists exactly which message UUIDs survived, so everything written before it that is not on that list is recoverable by subtraction, not inference — it never left the disk, only the model's context.

$ pitwall recall
37 compactions dropped 41.5M and waited 1h26m

  when          project   dropped  waited  session
  Aug 31 09:04  starts    983.2K   3m03s   8e0d2771
  Aug 18 05:19  fleety    3.0M     2m59s   bcb957a6

$ pitwall recall worktree
141 discarded messages mention "worktree"

$ pitwall recall --session 8e0d2771 --out recovered.md
wrote 342 messages, recovered.md
  pull it back into a session with @recovered.md

--mine narrows it to the prompts you typed, and that flag exists because of a measurement. Across 37 compactions here, 302 records were preserved verbatim and three of them were prose a human had written. Everything else kept was the agent's own output and tool results. What a compaction reliably discards is precisely what you asked for, which is why it feels like the agent forgot the task rather than the details.

The file is the point. Injecting context through a hook would be cleverer and would fail silently when it went wrong; a markdown file you pull back with @ works in any session, needs nothing installed, and you can read it first.

Two things worth knowing before reaching for a cleverer fix. A PreCompact hook can stop a compaction by exiting 2 — and that is cancellation, not postponement: it never resumes, so you trade a summarised conversation for a hard context wall. And the automatic trigger is not a mystery: across the automatic compactions measured here it fired at a median of 1,000,333 tokens with 1.7% spread, essentially exactly at the window. That is why a warning at 85% gives real notice rather than a guess.

tree — the worktrees left behind

Six states, and gc only removes what it can prove is safe. Anything holding uncommitted work is salvaged first — committed to its own branch, pinned behind refs/pitwall/salvage/*, and archived as a patch — before the worktree is removed. If the rescue fails, the worktree stays.

primer — a starting point for repos that have none

Start with the list, which ranks every unprimed repository by what its cold starts cost above the rate your primed ones manage:

$ pitwall primer --all

  project      sessions  $/opening prompt  at stake
  tenderai     26        $18.48            $1,261.71
  fleety       87        $5.00               $886.27
  mds          30        $8.79               $607.25

  $3,104.29 across 10 repositories

Then draft one, or all of them with --all --write:

pitwall primer ~/src/fleety

reads every past session in that repository and drafts a CLAUDE.md from what agents actually did: the commands that get run (go test, golangci-lint run, npx vitest, psql), the directories that get touched, the files that keep being opened. It is observed behaviour, not documentation — the draft leaves blanks for the intent no transcript can tell you.

The plugin does this automatically: when a session opens in a git repository with no CLAUDE.md, a SessionStart hook injects a compact version of the same summary. It stays quiet when a CLAUDE.md exists or the repository has too little history to be worth the tokens.

What pitwall deliberately does not do

It does not switch your effort level for you. Claude Code hooks receive the current effort as read-only input; there is no field in any hook's output that can change the model or the reasoning level, and PreModelSwitch can only observe a switch you already asked for. Anything claiming to auto-tune effort is either editing your settings behind your back or not doing it at all.

What pitwall does instead is make those 264 manual /effort decisions informed: it shows what each level has actually cost you per unit of work, so the choice is one keystroke made on evidence rather than on feel.

It also never touches a running session, never proxies your traffic, and never sends anything anywhere.

Where the data comes from

~/.claude/sessions/*.json      live sessions: pid, cwd, busy/idle, name
~/.claude/projects/**/*.jsonl  transcripts: usage, effort, tools, prompts, worktree records
git worktree / status / rev-list

Everything is read-only apart from pitwall's own caches, the salvage archives tree gc writes, the local configuration tree prep copies into a worktree, and the files install, primer --write and effort --apply create.

One command uses the network. pitwall quota calls https://api.anthropic.com/api/oauth/usage — the endpoint Claude Code calls for the same purpose — with the OAuth credential Claude Code already stored (macOS keychain, or ~/.claude/.credentials.json, or CLAUDE_CODE_OAUTH_TOKEN). macOS asks once for permission to read it. Nothing is sent anywhere else, and no other command touches the network. Readings are cached for 180 seconds because that endpoint rate limits hard, with exponential backoff when it does.

There is one record that outlives them. Claude Code keeps its own rolling summary in stats-cache.json — lifetime token totals per model, a daily series, and the date of your first session — and it is not pruned on the transcript schedule. On the machine this was built against it holds 52.1B tokens against the 33.4B still readable from transcripts, and burn reports an all-time figure from it, labelled as coming from there. The file is undocumented, so it is read defensively: an unfamiliar version or shape produces no reading rather than a wrong one.

Transcripts are pruned by Claude Code after about a month, so burn and coach describe the retained window, not all time. Both print the range they measured, and both warn once the archive has actually reached the boundary and is being trimmed — the default is cleanupPeriodDays: 30, and raising it in ~/.claude/settings.json is the only way to keep a longer history. Prompts in ~/.claude/history.jsonl are not pruned on the same schedule, so questions outlive the answers they produced.

Scans are cached per file on size and modification time: a first pass over a couple of gigabytes takes a few seconds, and every pass after that is instant.

Other agent tools

pitwall reads Claude Code's format. The internals are split so that a second adapter (Cursor, Codex, Aider, Gemini CLI) would only need to produce the same Session, Record and Exchange types — but no such adapter exists yet, and one will not be written speculatively. If you want your tool supported, open an issue with a sample of what it writes to disk.

License

MIT

Documentation

Overview

Command pitwall is the instrument panel for a fleet of coding agents: what they are doing, what they cost, what they left behind, and which of your habits is spending the most.

Directories

Path Synopsis
internal
burn
Package pricing converts token counts into dollars using Anthropic's published first-party rates.
Package pricing converts token counts into dollars using Anthropic's published first-party rates.
claude
Package claude reads local Claude Code state: the live session registry and the tail of each session's transcript.
Package claude reads local Claude Code state: the live session registry and the tail of each session's transcript.
coach
Package coach measures how a person actually spends their agent budget: what each prompt bought, where the round trips are, and which habits cost the most.
Package coach measures how a person actually spends their agent budget: what each prompt bought, where the round trips are, and which habits cost the most.
fleet
Package fleet turns Claude Code's session registry into one question: which of your agents is waiting for you right now?
Package fleet turns Claude Code's session registry into one question: which of your agents is waiting for you right now?
lint
Package lint judges a prompt by the only standard that matters: how often prompts shaped like it forced another round trip before any work happened.
Package lint judges a prompt by the only standard that matters: how often prompts shaped like it forced another round trip before any work happened.
primer
Package primer drafts a project starting point from what past Claude Code sessions already discovered about a repository — the commands that get run, the files that get opened first, where the code actually lives.
Package primer drafts a project starting point from what past Claude Code sessions already discovered about a repository — the commands that get run, the files that get opened first, where the code actually lives.
quota
Package quota reads Anthropic's own view of how much of your plan you have used.
Package quota reads Anthropic's own view of how much of your plan you have used.
ui
Package ui renders terminal output: colors when a TTY is attached, plain text when piped, and never any escape codes when NO_COLOR is set.
Package ui renders terminal output: colors when a TTY is attached, plain text when piped, and never any escape codes when NO_COLOR is set.
worktree
Package scan discovers every git worktree reachable from the repositories you work in, joins each one to the Claude Code session that created it, and classifies what it is safe to do with it.
Package scan discovers every git worktree reachable from the repositories you work in, joins each one to the Claude Code session that created it, and classifies what it is safe to do with it.
Package perms reads Claude Code permission rules, reports the ones that cannot do what their author intended, and answers whether a given command is covered by them.
Package perms reads Claude Code permission rules, reports the ones that cannot do what their author intended, and answers whether a given command is covered by them.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL