Skip to main content

Status Line

Claude Code only

The status line is not available with Codex CLI. It uses a Claude Code-specific stdin API that Codex does not support.

Compact session dashboard rendered below every Claude Code response. Idle sessions use two lines; an active Pilot Spec or Buildout adds its progress line between them.

Idle session:

Opus 5 [high] [1M] | █████░▓ 60% | 5h: 42% ⇡ 2h | 7d: 18% ⇣ 4d | +120 -38 | main ~5
Pilot 8.4.0 (Solo) · CC 2.1.80 (Max) · Console: localhost:41777

Active Pilot workflow:

Opus 5 [high] [1M] | █████░▓ 60% | 5h: 42% ⇡ 2h | 7d: 18% ⇣ 4d | +120 -38 | main ~5
Spec: my-feature feature [implement] ████░░░░ 3/6
Pilot 8.4.0 (Solo) · CC 2.1.80 (Max) · Console: localhost:41777

Line 1 — Session Metrics​

WidgetWhat it shows
ModelActive model with reasoning effort immediately after its name (Opus 5 [high] [1M], Fable 5.1 [xhigh])
ContextRuntime context usage bar + percentage. Green < 75%, Yellow 75–90%, Red 90%+
5h / 7d usageRate-limit percentage with pacing arrow and reset countdown. Shown on Pro/Max subscriptions. ⇡ = over pace (red), ⇣ = under pace (green)
Lines+added -removed for the session.
DirectoryWorking directory, shown only when the branch alone can't place you — see below.
GitBranch with staged/unstaged file counts, resolved from the same directory shown beside it.
CostSession cost in USD. Shown on API/Enterprise only — suppressed on subscription plans.

The effort label uses Claude Code's live effort.level value, including mid-session /effort changes. When Claude Code omits that field, no effort label is shown.

When the directory appears​

The directory would be noise for the common case — one checkout, sitting at its root — so it earns its columns only when the branch alone leaves you guessing:

Where you areDirectory shown?
Inside a git worktreeYes
In a subdirectory of a checkoutYes
Outside a git repo entirelyYes — no branch renders either
At the root of an ordinary checkoutNo

This is what makes a worktree readable at a glance. claude -w and similar tools name the directory independently of the branch you later switch to, so the two drift apart:

Opus 5 [high] [1M] | █████░▓ 60% | +120 -38 | ~/…/angry-purple-tiger | feat/pr-prep

Now you can see the branch you're preparing a PR for and the directory to cd into, without running !pwd.

The path is shortened from the left, keeping the trailing components (~/…/angry-purple-tiger), because the last part is what identifies the checkout. A Pilot-managed /spec worktree adds its own wt marker after the branch:

Opus 5 [high] [1M] | █████░▓ 60% | +120 -38 | ~/…/.worktrees/my-feature | spec/my-feature wt

Active workflow line — when present​

Specification: Spec: my-feature feature [implement] ████░░░░ 3/6 iter:2

Shows plan name, type (feature/bugfix), phase (plan/implement/verify), task progress bar, and iteration count.

Buildout: Build: running-brand build ███░░░░░ 3/8 r:2

A /build Buildout renders the same way, counting the same tasks, with rounds (r:) instead of iterations and the phases goal (goal, tasks, and criteria being drafted) -> build (working the task list) -> judge (acceptance criteria being ruled). The type tag is magenta. Its acceptance criteria are a separate list from its tasks and are not counted here.

During the plan phase (before tasks exist) the detail slot reads models: auto / manual / off, reflecting the Model Switching mode selected in your Console settings.

In auto mode it turns red and reads models: auto ⚠ not-opus (just ⚠ on a narrow line) when runtime evidence shows planning on something other than Opus. The warning identifies the observed mismatch, not its cause. Check /model and /usage, or select Manual to manage the model yourself. Pilot does not assume a universal 200K planning limit or force compaction to restore Opus.

Final line — Version Info​

Pilot <version> (<tier>) · CC <version> (<subscription>) · Console: <host:port>

This line carries the Console address — open it to reach sessions, memories, plans, Buildouts, changes, and settings.

Configuration​

Configured automatically during installation in ~/.claude/settings.json — no manual setup required.

Composing with your own status line​

Pilot's status line isn't all-or-nothing. If you already had one — a shell-prompt prefix, a project label, anything — you can keep it and render Pilot's lines underneath. Point statusLine.command at a wrapper script instead of at Pilot directly.

The one thing to get right: Claude Code sends the session JSON on stdin, and stdin can only be read once. Capture it, then replay it into Pilot — otherwise Pilot receives nothing and its lines come out empty.

~/.claude/pilot-statusline-wrapper.sh
#!/usr/bin/env bash
input=$(cat)

# Your own line(s) first — anything you like.
printf '%s\n' "$(whoami)@$(hostname -s):$(basename "$PWD")"

# Then Pilot's two or three lines, fed the JSON you captured.
printf '%s' "$input" | ~/.pilot/bin/pilot statusline

Make it executable and point ~/.claude/settings.json at it:

"statusLine": {
"type": "command",
"command": "~/.claude/pilot-statusline-wrapper.sh",
"padding": 0
}

Reading the session JSON in your wrapper​

The input variable holds everything Claude Code knows about the session, so your own lines can use it too. A small helper keeps this readable:

field() {
printf '%s' "$input" | python3 -c "import json,sys; print(json.load(sys.stdin)$1)"
}

model=$(field '["model"]["display_name"]')
dir=$(field '["workspace"]["current_dir"]')

Fields Pilot itself reads, and therefore the ones you can rely on: workspace.current_dir, model.display_name, model.id, effort.level when reported, session_id, version, cost.* (total_cost_usd, total_lines_added, total_lines_removed), context_window.* (used_percentage, context_window_size, total_input_tokens), and rate_limits.* on Pro/Max plans.

Does a wrapper survive pilot update?​

Yes, in the normal case. Pilot merges ~/.claude/settings.json three ways — baseline, your current file, and the incoming defaults — and a statusLine.command you changed away from the baseline is kept rather than overwritten.

The exception worth knowing: if ~/.claude/.pilot-settings-baseline.json is missing (a first install, or the file was deleted), there is nothing to compare against and the incoming default wins — your wrapper would be replaced. Keep a copy of the script itself somewhere safe; re-pointing statusLine.command at it takes a second.