Skip to main content

Status Line

The status line is a bar at the bottom of Claude Code that shows the output of a script you write. The script gets session data as JSON on stdin, such as the model and the cost. It prints what to show on stdout. It does not use API tokens. Set it with the statusLine key of a user, project, local, or managed settings file. The key names the script. To remove it, delete statusLine, or run /statusline delete.

Example​

~/.claude/statusline.sh
#!/bin/sh
input=$(cat)
model=$(echo "$input" | jq -r '.model.display_name')
used=$(echo "$input" | jq -r '.context_window.used_percentage // 0')
echo "$model | context ${used}%"
~/.claude/settings.json
{
"$schema": "https://clawdipedia.cc/schemas/claude-code-settings.json",
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.sh",
"padding": 1,
"refreshInterval": 30
}
}

The bar shows the model name and how full the context window is. The script also re-runs every 30 seconds.

Settings​

Official page: Customize Your Status Line.

ItemStatusWhat it doesHow it worksWhere to set it
statusLine.type
Documented: An official docs page names this item.
Kind of status lineMust be "command". RequiredUser, project, local, managed
statusLine.command
Documented: An official docs page names this item.
Script path or inline shell commandRuns in a shell. A change to it runs the new command at once, without the debounceSame
statusLine.padding
Documented: An official docs page names this item.
Extra horizontal space in charactersThe default is 0. It adds to the built-in spacingSame
statusLine.refreshInterval
Documented: An official docs page names this item.
Re-runs the command every N secondsThe minimum is 1. The bundle uses Math.max(1, n) * 1000 ms. It suits clocks and idle sessionsSame
statusLine.hideVimModeIndicator
Documented: An official docs page names this item.
Hides the built-in -- INSERT -- textUse it when the script prints vim.mode itselfSame
subagentStatusLine
Documented: An official docs page names this item.
Custom row for each subagent in the agent panelIt has the fields type ("command") and command. See the next sectionSame
/statusline
Documented: An official docs page names this item.
Writes a script in ~/.claude/ and the settingIt takes natural language. /statusline delete removes itInteractive
Workspace trust
Documented: An official docs page names this item.
The command waits for trust--debug logs Status line command skipped: workspace trust not acceptedProject files
CLAUDE_CODE_SAFE_MODE
Documented: An official docs page names this item.
Status line commands do not loadManaged policy still appliesEnv

Two hook settings also act on the status line. disableAllHooks set outside managed settings leaves only a managed statusLine. With no managed statusLine, the status line is off. allowManagedHooksOnly shows only a managed statusLine. A custom one then disappears without a warning. Their rows are on Hooks, Plugins, and Skills Settings.

When the Script Runs​

ItemStatusWhat it doesHow it worksWhere to set it
Session start and resume
Documented: An official docs page names this item.
First runRuns onceEach session
New assistant message, /compact done, permission mode change, vim mode toggle
Documented: An official docs page names this item.
Re-runs the commandClaude Code debounces it at 300ms. A new trigger cancels a running scriptEach session
Rate-limit resets_at and cache expires_at
Documented: An official docs page names this item.
Re-runs at the earliest timeThe time comes from the data the script last receivedEach session
Model, fast mode, effort, thinking, and PR status change
Differs: The official docs and the program disagree. The row says how.
Also re-run the commandThe bundle watches mainLoopModel, fastMode, effortValue, thinkingEnabled, prStatus. The list in the docs does not name themEach session

Output Rules​

  • Each printed line is a row. ANSI colors and OSC 8 links work.
  • The output shows only after exit code 0. A non-zero exit or empty output blanks the line.
  • Claude Code sets COLUMNS and LINES before it runs the statusLine script. tput cols does not work. The subagentStatusLine command does not get them (checked in the interactive screen). It gets columns in its JSON.
  • Claude Code sets the variables CLAUDECODE and CLAUDE_CODE_CHILD_SESSION in the script process. See Environment Variables.
  • claude --debug logs stderr of each run and the exit code of the first run.
  • The line hides during the help menu and permission prompts. The command does not run while a permission or MCP input dialog is open (checked). Outside fullscreen, notifications share the row.
  • On Windows, use forward slashes in command. CLAUDE_CODE_POWERSHELL_RESPECT_EXECUTION_POLICY changes the PowerShell policy flag.

Source for this list: the official Customize Your Status Line and Environment Variables pages.

Subagent Status Line​

subagentStatusLine customizes each subagent row in the agent panel. Its command runs once per refresh tick (a fixed 5 seconds, checked in the interactive screen). It gets all visible rows as one JSON object. It prints one JSON line for each row it wants to override: {"id": "<task id>", "content": "<row body>"}. A row without id keeps the default. An empty content hides the row. The same trust, disableAllHooks, and allowManagedHooksOnly gates apply. A plugin can ship a default subagentStatusLine in its settings.json. The input fields are in the Subagent Task Fields table below.

JSON Fields​

These fields arrive on stdin. A field marked "may be absent" is missing from the JSON when it has no value. Always read optional fields with a default, for example jq -r '.vim.mode // empty'.

Session and Model Fields​

FieldStatusWhat it holdsNotesWhere
session_id
Documented: An official docs page names this item.
Session idStringStatus line
session_name
Documented: An official docs page names this item.
Custom name or AI titleMay be absent. The default display name does not fill itStatus line
prompt_id
Documented: An official docs page names this item.
UUID of the prompt in workMay be absent before the first inputStatus line
transcript_path
Documented: An official docs page names this item.
Transcript file pathStringStatus line
cwd
Documented: An official docs page names this item.
Working directorySame value as workspace.current_dirStatus line
version
Documented: An official docs page names this item.
Claude Code version2.1.312 hereStatus line
model.id, model.display_name
Documented: An official docs page names this item.
Model id and nameStringsStatus line
output_style.name
Documented: An official docs page names this item.
Active style namedefault when none. See Output StylesStatus line
fast_mode
Documented: An official docs page names this item.
Fast mode onBooleanStatus line
effort.level
Documented: An official docs page names this item.
low, medium, high, xhigh, maxMay be absent when the model has no effortStatus line
thinking.enabled
Documented: An official docs page names this item.
Extended thinking onBooleanStatus line
vim.mode
Documented: An official docs page names this item.
NORMAL, INSERT, VISUAL, VISUAL LINEMay be absent. Present when vim mode is onStatus line
agent.name
Documented: An official docs page names this item.
Agent namePresent with --agent or agent settingsStatus line
agent_type
Undocumented: Only the program shows this item. It can change without notice.
Agent type of the main threadPresent with --agent or agent settings. The same value hooks get as agent_type. The built-in statusline-setup agent's prompt calls it agent.type. Read it at the top level as agent_typeStatus line, subagentStatusLine
scratchpad_dir
Gated: Works only behind a flag or a server gate. tengu_scratch, or the artifact tools
The session scratchpad folderPresent when the server flag tengu_scratch is on, or when the session may use the artifact toolsStatus line, subagentStatusLine
remote.session_id
Undocumented: Only the program shows this item. It can change without notice.
Id of a remote sessionPresent when the session is remote. The docs do not list remoteStatus line

Workspace Fields​

FieldStatusWhat it holdsNotesWhere
workspace.current_dir
Documented: An official docs page names this item.
Current directoryPreferred over cwdStatus line
workspace.project_dir
Documented: An official docs page names this item.
Launch directoryThe bundle fills it from the original cwdStatus line
workspace.added_dirs
Documented: An official docs page names this item.
Directories from /add-dir or --add-dirIt is an empty array if there are noneStatus line
workspace.git_worktree
Documented: An official docs page names this item.
Linked worktree nameIt is absent in the main treeStatus line
workspace.repo.host, .owner, .name
Documented: An official docs page names this item.
Repository identity from originMay be absent. GitLab subgroups give a slash path in ownerStatus line
worktree.name, .path, .branch, .original_cwd, .original_branch
Documented: An official docs page names this item.
Worktree session dataOnly in a worktree session. branch and original_branch may be absent for hook-based worktreesStatus line
pr.number, pr.url
Documented: An official docs page names this item.
Open PR or GitLab merge requestClaude Code removes it once the PR merges or closesStatus line
pr.review_state
Documented: An official docs page names this item.
approved, pending, changes_requested, draftMay be absent aloneStatus line
pr.kind
Documented: An official docs page names this item.
mr for a GitLab merge requestAbsent for GitHubStatus line

Cost, Context, and Limit Fields​

FieldStatusWhat it holdsNotesWhere
cost.total_cost_usd
Documented: An official docs page names this item.
Estimated costIt is a client-side list price. It resets at /clearStatus line
cost.total_duration_ms, cost.total_api_duration_ms
Documented: An official docs page names this item.
Wall time and API wait timeMillisecondsStatus line
cost.total_lines_added, cost.total_lines_removed
Documented: An official docs page names this item.
Lines changedNumbersStatus line
context_window.total_input_tokens, .total_output_tokens
Documented: An official docs page names this item.
Tokens in the windowIt comes from the last response. It is 0 before thatStatus line
context_window.context_window_size
Documented: An official docs page names this item.
Window size200000 or 1000000Status line
context_window.used_percentage, .remaining_percentage
Documented: An official docs page names this item.
Percent used and leftIt counts input tokens only. It may be null earlyStatus line
context_window.current_usage
Documented: An official docs page names this item.
Per-category tokensKeys input_tokens, output_tokens, cache_creation_input_tokens, cache_read_input_tokens. null before the first call and after /compactStatus line
exceeds_200k_tokens
Documented: An official docs page names this item.
Last response is over 200k tokensIt is a fixed thresholdStatus line
rate_limits.five_hour, .seven_day
Documented: An official docs page names this item.
used_percentage and resets_atClaude.ai Pro and Max only. A window drops after its reset timeStatus line
rate_limits.spend_limit.used_percentage, .resets_at
Documented: An official docs page names this item.
Gateway spend limitNeeds 2.1.251Status line
rate_limits.spend_limit.used_usd, .limit_usd, .period
Documented: An official docs page names this item.
Spend in dollars and period daily, weekly, monthlyNeeds 2.1.284. Off with CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFICStatus line

Prompt Cache Fields​

The object prompt_cache appears after the first main-conversation response (needs 2.1.251). Subagent requests are not counted.

FieldStatusWhat it holdsNotesWhere
prompt_cache.warm
Documented: An official docs page names this item.
Cache is within its TTLBooleanStatus line
prompt_cache.caching_observed
Documented: An official docs page names this item.
Any response reported cache tokensfalse means caching is off or not reportedStatus line
prompt_cache.ttl
Documented: An official docs page names this item.
Cache lifetime"5m" or "1h"Status line
prompt_cache.expires_at
Documented: An official docs page names this item.
When the cache goes coldEpoch seconds. null if no cache tokensStatus line
prompt_cache.requests, .misses, .expected_rebuilds
Documented: An official docs page names this item.
Request and miss countsA miss is over 5% and at least 2,000 tokens re-processedStatus line
prompt_cache.hit_ratio
Documented: An official docs page names this item.
Cache reads over all input tokensThe value is 0 to 1. It is null when counts are zeroStatus line
prompt_cache.cache_write_tokens, .miss_recache_tokens
Documented: An official docs page names this item.
Tokens writtenTotals for the session and for missesStatus line
prompt_cache.last_miss_at
Documented: An official docs page names this item.
Time of the last missEpoch seconds. null if noneStatus line
prompt_cache.last_miss_cause
Documented: An official docs page names this item.
Likely causecauses array (such as tools_changed, system_prompt_changed, ttl_expired_5m, likely_server_side), plus tools_added, tools_removed, system_char_delta. Needs 2.1.260Status line
prompt_cache.miss_causes
Documented: An official docs page names this item.
Count per causeMapStatus line
prompt_cache.recache_tokens_if_cold
Documented: An official docs page names this item.
Tokens a cold cache re-cachesnull after a compaction until the next requestStatus line

Subagent Task Fields​

The subagentStatusLine command gets session_id, transcript_path, cwd, prompt_id, agent_type and scratchpad_dir when they are set, columns, and a tasks array.

FieldStatusWhat it holdsNotesWhere
columns
Documented: An official docs page names this item.
Usable row widthNumbersubagentStatusLine
tasks[].id
Documented: An official docs page names this item.
Task idEcho it back as idsubagentStatusLine
tasks[].name
Documented: An official docs page names this item.
Address nameOptionalsubagentStatusLine
tasks[].type
Documented: An official docs page names this item.
Kind of tasklocal_agentsubagentStatusLine
tasks[].agentType
Documented: An official docs page names this item.
Subagent typeSame value as hook agent_type. Needs 2.1.293subagentStatusLine
tasks[].status
Documented: An official docs page names this item.
Staterunning, completed, failed, killedsubagentStatusLine
tasks[].description, tasks[].label
Documented: An official docs page names this item.
Short textlabel is a progress summary. Otherwise it is descriptionsubagentStatusLine
tasks[].startTime
Documented: An official docs page names this item.
Start timeEpoch millisecondssubagentStatusLine
tasks[].model, tasks[].contextWindowSize
Documented: An official docs page names this item.
Resolved model and its windowOptionalsubagentStatusLine
tasks[].effort
Documented: An official docs page names this item.
Configured effortString or number. Needs 2.1.213subagentStatusLine
tasks[].tokenCount, tasks[].tokenSamples
Documented: An official docs page names this item.
Running tokens and up to 16 samplesOldest firstsubagentStatusLine
tasks[].cwd
Documented: An official docs page names this item.
Subagent working directoryThis is the worktree of the subagent, if it has onesubagentStatusLine

How It Works​

Interactive Probe Findings

Checked in the interactive screen (2.1.305, local stub, fake key, clean environment). See Interactive Probes.

  • subagentStatusLine runs on a fixed 5-second tick while the agent panel has tasks. The tick is 4.99 to 5.02 seconds over 5 intervals, after a first interval of 4.69 seconds. It also runs for tasks that are completed. It is not debounced like statusLine. No setting changes the 5 seconds. The first run came when the agent started.
  • Its command does not get COLUMNS and LINES. Use the columns field (194 on a 200-column screen). Claude Code sets CLAUDECODE and CLAUDE_CODE_CHILD_SESSION.
  • Its input holds only session_id, transcript_path, cwd, prompt_id, columns, and tasks, not the full statusLine object. The agent panel drew a row override {"id": ..., "content": "..."}.
  • For statusLine, transcript_path is present from the first run, before any message. prompt_id is absent until the first prompt. Then it is the same UUID as prompt_id in hook input. After the first reply, the input also gains prompt_cache. current_usage is no longer null.
  • statusLine runs once at start and once after the first reply (not at prompt submit). Three mode changes gave one run, 0.33 seconds after the last one. This held both when sent 100 ms apart and when sent in one write. This fits the 300 ms debounce. refreshInterval: 3 ran every 3.0 seconds (3.0 to 3.1 seconds over 14 intervals in a run with no other trigger).
  • Runs paused while a permission or MCP input dialog was on screen. A Bash permission dialog was on screen for 17.4 seconds. The gap between runs was 19.3 seconds.
  • padding: 1 gave a one-space indent, and two printed lines showed as two rows under the prompt.
  • With no subagents, subagentStatusLine did not run. In a session left idle for 29.6 seconds its command had not run once. The first run came when a background agent started.
  • A test agent finished at once. The command kept its 5-second tick for 29.7 seconds after the agent started (7 runs, all with the tasks completed). Then it did not run again for the next 29 seconds. The input listed three tasks, because the stub answers every request that has no tool result yet with the same Agent call.

Exact Fields​

The exact fields are in https://clawdipedia.cc/schemas/claude-code-status-line.json. The program builds this payload in code, not with a validator, so the schema comes from that code. A field marked x-unverified has a type the code does not show. x-observed marks a field that a probe saw. It lists every field of this release. Build on the fields it names. Look each one up there before you rely on it.