@dmandalik/cctower
v0.0.2
Published
Control tower for Claude Code - pre-flight token checks, attention alerts, and landing reports.
Maintainers
Readme
cctower
A turn auditor for Claude Code with a live status widget. After every
turn, cctower reads the transcript and writes a "done ≠ correct" landing
report: what changed, what was actually tested versus merely claimed, and a
verdict — VERIFIED · UNVERIFIED · FAILED · NO-OP. If Claude says
"tests pass" but never ran them, the card says so.
Local only: no API keys, no accounts, no network calls. cctower attaches through Claude Code's lifecycle hooks and statusline, never intercepts or slows a session, and fails open on any internal error.
What you get
- Landing reports — per-turn markdown cards with files touched, git diff stats, test/build runs and exit codes, new TODO/FIXMEs, claims checked against reality, and a verdict.
- Live widget (
cctower ui) — a compact local panel: per-session status orbs (working · needs input · issue · done), an alert bar + title flash when any chat needs you, the latest landing cards, the last pre-flight readout, and controls (mode, alerts, thresholds, per-project mute). - Stall watcher — Claude Code fires no hook while a permission or question dialog is open, so the gate keeps a tiny detached watcher process alive (auto-spawned per prompt, self-exits after 10 idle minutes). It tells a blocked tool apart from a running one via the process table, so a slow command never reads as "needs input".
- Pre-flight gate — estimates each prompt's token cost, projects context
use, lints weak prompts, and can block (
gatemode,!forceto override). Self-tunes against real usage. - Best-effort extras — desktop notifications and quota readouts, with platform limits stated plainly below.
Install
npm install -g @dmandalik/cctower
cctower init --dry-run
cctower init(The package is scoped; the installed command is still plain cctower.)
init merges cctower's entries into ~/.claude/settings.json idempotently —
running it twice changes nothing, and your own hooks are left untouched. The
previous file is backed up under ~/.cctower/backups/ first. --dry-run
prints the exact diff and touches nothing.
Commands
cctower status # state-dir + install health, estimator accuracy
cctower ui # live widget (sessions, cards, controls)
cctower report # 7-day summary: verdicts, idle time, top lint findings
cctower uninstall # remove only cctower's entries; prints the newest backupModes
Set mode in ~/.cctower/config.json or from the widget:
observe— log only.advise(default) — pre-flight hints on each prompt; silent on trivial prompts. In GUI clients the hint arrives as a desktop notification (hook stdout only reaches the model), plus the widget's pre-flight row.gate— block a prompt when projected context/quota crosses a threshold; resend with!forcein the prompt to override.
Note: in GUI clients (desktop app, IDE) the pre-flight advise line is injected into the model's context but not shown to you — the widget's "last pre-flight" row and the statusline are the user-facing surfaces.
Known platform limits
- macOS may suppress scripted notification banners. cctower posts via
terminal-notifierwhen you've installed it (optional, auto-detected — not a dependency), else viaosascript(shows as "Script Editor"). For banners: System Settings → Notifications → allow the posting app and set its style to Alerts or Banners; check that no Focus mode is active. Even then, recent macOS versions sometimes deliver scripted notifications silently to Notification Center. The widget and its sound ping are the reliable surface. - Quota is best-effort. Claude Code only exposes
rate_limitsto the statusline on some versions. When present, cctower shows official percentages; when absent, it shows token volume aggregated from your local transcripts over rolling 5-hour/7-day windows, tagged "local estimate" (no percentage — plan limits aren't knowable locally). - Claude Code only. cctower attaches via local hooks, so it covers the CLI, desktop app, and IDE sessions — not claude.ai web chats, which run no local hooks.
State
Everything lives under $CCTOWER_HOME (default ~/.cctower/). Set
CCTOWER_HOME to relocate or isolate it — the whole tool is contained there.
License
MIT
