Claude Code
Since 0.5.0, τ-mux integrates with Claude Code on three planes, plus a native Claude Code pane (0.7.0). Each piece degrades independently — any subset works, and none of it can break the terminal (the PTY never depends on the integration).
The three planes
Section titled “The three planes”Event plane — hooks
Section titled “Event plane — hooks”Fourteen Claude Code shell hooks (session start/end, prompt/stop, API
failures, subagent start/stop, compaction, cwd changes, task
created/completed, idle/permission notifications) run a small bridge that
forwards one normalized JSON event to the app (ht claude event). A
per-session registry tracks each Claude Code session’s phase —
working / waiting for input / approval needed / compacting / error — and
attributes it to the pane it runs in (HT_SURFACE).
You see it as:
- the
Claudelabel pill — session title while working, yellow Waiting for input, red Approval needed, muted Compacting…, red error text on API failures (rate limit, overload); - a completion notification on every turn end (prompt + duration + cost), an error notification on API failures;
- the plan panel mirroring Claude Code’s native task list — see below.
Data plane — statusline
Section titled “Data plane — statusline”{ "statusLine": { "type": "command", "command": "ht claude statusline" } }Claude Code pipes a JSON snapshot to its statusline command on every
assistant message. ht claude statusline renders a τ-mux-styled status
line back into Claude Code — model, effort, directory, git branch,
permission mode, PR badge, a color-coded context bar, session cost,
±lines, and rate-limit warnings at ≥80% — and tees the data into the
sidebar: the cc ticker becomes Opus · 42% ctx · $0.31.
Cost, context %, rate limits, and the session title are numbers Claude
Code computes itself — they always match /cost and /context.
(Earlier versions parsed transcripts against a hand-maintained pricing
table; that machinery is gone.)
Decision plane — remote approvals (opt-in)
Section titled “Decision plane — remote approvals (opt-in)”With the approvals feature installed, Claude Code permission prompts
are routed to a τ-mux ask-user modal — and to
Telegram when the bridge is configured
— with three answers: Allow, Deny, Answer in terminal. The
modal shows the exact tool + input (ground truth, never a summary).
Fail-safe by construction: if τ-mux isn’t running, the modal times
out, you pick “Answer in terminal”, or anything at all goes wrong, the
bridge prints nothing and Claude Code shows its own prompt exactly as
before. The gate can only ever add an answer path. Kill switch without
uninstalling: HT_CLAUDE_APPROVALS=0.
Accepting terminal prompts
Section titled “Accepting terminal prompts”When Claude Code runs in a terminal pane and asks permission to run a command, τ-mux can press Enter for you (its prompt’s default answer is Yes):
- Manually, always available — command palette → “Approve Claude Code
permission prompt”, or
ht claude approve(answers the longest-waiting session, or--surface). - Automatically — Settings → Auto-approve Claude Code prompts
(off by default), or
ht claude auto-approve on|off|status. Every approval is written to that pane’s sidebar log, so there is a record of what was accepted unattended.
This is deliberately narrow. It only fires when Claude Code is showing its own prompt in that pane’s terminal; it never answers the τ-mux approval modal (there is no terminal prompt to answer in that case) and never types into the Claude Code pane. It re-checks the prompt is still on screen after the configured delay, so it can’t fire a stray Enter into a pane where you already answered. And if more than eight prompts arrive in a minute it pauses itself and notifies you — a prompt storm is not something to rubber-stamp.
Questions addressed to you are never auto-answered
Section titled “Questions addressed to you are never auto-answered”Claude Code raises the same permission-prompt hook for an
AskUserQuestion or ExitPlanMode modal as it does for “may I run
this command”, with the same generic message — on the hook stream alone
the two are indistinguishable. Two hooks scoped to
AskUserQuestion|ExitPlanMode tell τ-mux when a choice modal is open, and
both auto-approve and the manual ht claude approve refuse to act while
one is up: pressing Enter on a choice modal picks its default option,
which is not what “approve” means.
When the modal closes, τ-mux retracts the approval announcement it raised
— so an answered question stops showing a pending-approval pill, and a
later ht claude approve can’t type Enter into a pane with no prompt on
screen. A genuine tool prompt is left untouched.
A notification arriving while a modal is open is attributed to the modal. If that ever misfires the result is a missed auto-approval — you press Enter yourself — never a stray keystroke.
A turn that asks permission more than once has every prompt answered, not just the first — τ-mux counts prompt announcements rather than state transitions, because Claude Code ships no “prompt resolved” hook.
Auto-approve hands a coding agent unattended consent for the commands it asks to run. Turn it on when you are supervising the pane, not as a permanent default.
Task-list mirror
Section titled “Task-list mirror”Claude Code’s native task list (TaskCreate / TaskCompleted) is mirrored into the plan panel automatically, per session — no model cooperation needed. Completed tasks show as done, the first open task as active; the mirror is cleared when the session ends, and it coexists with pi plans (each agent gets its own slot).
The mirror survives an app restart: session state (identity, cwd, title,
task list, spend) is persisted to claude-sessions.json in the config dir
and reloaded at launch. Live state is deliberately not restored — a
restored session comes back idle, with no in-flight turn and no pending
approval, and the next hook event corrects the rest. Without this, a
restart left a still-running session with a permanently empty plan panel,
because hooks only report transitions and nothing would re-announce the
tasks it had already created.
Because the mirrored plan and the turn-end notification feed the existing
auto-continue engine, plan-anchored
continuation works for Claude Code sessions under the same safety gates.
Note that the engine runs on every turn end, so a workspace with no
published plan records a “no plan published” skip — consecutive identical
skips collapse into a single row with a ×N count rather than filling
the audit panel.
Install
Section titled “Install”# one-time: put the bridge + skill in place (from the τ-mux repo)./claude-integration/install.sh
# wire everything into ~/.claude/settings.json (managed, reversible)ht claude install # lifecycle + tasks + statuslineht claude install --features approvals # opt-in: remote approvalsht claude install --dry-run # preview the diffht claude uninstall # remove every managed entryThe installer makes a timestamped backup, merges additively (your
existing hooks are untouched), is idempotent, refuses to rewrite a
settings file it cannot parse, and never clobbers a user-defined
statusline (it reports it as kept). See ht claude.
Diagnostics
Section titled “Diagnostics”ht claude doctor # binary + version, hooks wired/missing, approvals, # statusline, skill, app reachabilityht claude sessions # sessions the app has observed (phase, title, cost)HT_CLAUDE_DEBUG=1 # surface bridge errors on stderrThe tau-mux skill
Section titled “The tau-mux skill”The skill (v2) teaches Claude Code the interactive surfaces — ht ask for decisions, splits for long-running processes, ht browser / ht screenshot for verification, confirm-command gating for destructive
bash. Everything the hooks automate (pills, ticker, notifications, the
plan mirror, approvals) is explicitly not the model’s job — the skill
says so, which keeps it short and reliable.
Agent teams
Section titled “Agent teams”When Claude Code’s experimental agent teams are enabled, τ-mux shows a
passive team sidebar pill (“3 members · 2/6 tasks”) read from the
on-disk team state. Read-only and schema-defensive — the upstream feature
is experimental.
Architecture
Section titled “Architecture”Bridge and skill live in claude-integration/ in the repo; app-side
state lives in a session registry with presenter / mirror / watcher
modules. The full design — including the trust model — is documented in
doc/system-claude-integration.md.