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.

At a Glance​

QuestionAnswer
Can you use it?✅ Yes. Run /statusline and describe what you want, or write a script yourself.
Can you change it?✅ Yes. Edit the statusLine key in a settings file.
Can you turn it on or off?Remove statusLine, or run /statusline delete. disableAllHooks: true turns off custom ones.
Where does it live?The statusLine key of user, project, local, or managed settings, and the script it names.
StatusDocumented Undocumented Differs

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
{
"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.typeDocumentedKind of status lineMust be "command". RequiredUser, project, local, managed
statusLine.commandDocumentedScript path or inline shell commandRuns in a shell. A change to it runs the new command at once, without the debounceSame
statusLine.paddingDocumentedExtra horizontal space in charactersDefault 0. Adds to the built-in spacingSame
statusLine.refreshIntervalDocumentedRe-runs the command every N secondsMinimum 1. The bundle uses Math.max(1, n) * 1000 ms. For clocks and idle sessionsSame
statusLine.hideVimModeIndicatorDocumentedHides the built-in -- INSERT -- textUse when the script prints vim.mode itselfSame
subagentStatusLineDocumentedCustom row for each subagent in the agent panelFields type ("command") and command. See the next sectionSame
/statuslineDocumentedWrites a script in ~/.claude/ and the settingTakes natural language. /statusline delete removes itInteractive
disableAllHooksDocumentedWhen true outside managed settings, only a managed statusLine runsWith no managed statusLine the status line is offSettings
allowManagedHooksOnlyDocumentedOnly a managed statusLine showsA custom one disappears without a warningManaged
Workspace trustDocumentedThe command waits for trust--debug logs Status line command skipped: workspace trust not acceptedProject files
CLAUDE_CODE_SAFE_MODEDocumentedStatus line commands do not loadManaged policy still appliesEnv

When the Script Runs​

ItemStatusWhat it doesHow it worksWhere to set it
Session start and resumeDocumentedFirst runRuns onceEach session
New assistant message, /compact done, permission mode change, vim mode toggleDocumentedRe-runs the commandDebounced at 300ms. A new trigger cancels a running scriptEach session
Rate-limit resets_at and cache expires_atDocumentedRe-runs at the earliest timeTaken from the data the script last receivedEach session
Model, fast mode, effort, thinking, and PR status changeDiffersAlso re-run the commandThe bundle watches mainLoopModel, fastMode, effortValue, thinkingEnabled, prStatus. The docs list do 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 script. tput cols does not work.
  • The variables CLAUDECODE and CLAUDE_CODE_CHILD_SESSION are set 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. 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 and 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_idDocumentedSession idStringStatus line
session_nameDocumentedCustom name or AI titleMay be absent. The default display name does not fill itStatus line
prompt_idDocumentedUUID of the prompt in workMay be absent before the first inputStatus line
transcript_pathDocumentedTranscript file pathStringStatus line
cwdDocumentedWorking directorySame value as workspace.current_dirStatus line
versionDocumentedClaude Code version2.1.304 hereStatus line
model.id, model.display_nameDocumentedModel id and nameStringsStatus line
output_style.nameDocumentedActive style namedefault when none. See Output StylesStatus line
fast_modeDocumentedFast mode onBooleanStatus line
effort.levelDocumentedlow, medium, high, xhigh, maxMay be absent when the model has no effortStatus line
thinking.enabledDocumentedExtended thinking onBooleanStatus line
vim.modeDocumentedNORMAL, INSERT, VISUAL, VISUAL LINEMay be absent. Present when vim mode is onStatus line
agent.nameDocumentedAgent namePresent with --agent or agent settingsStatus line
remote.session_idUndocumentedId of a remote sessionPresent when the session is remote. The docs do not list remoteStatus line

Workspace Fields​

FieldStatusWhat it holdsNotesWhere
workspace.current_dirDocumentedCurrent directoryPreferred over cwdStatus line
workspace.project_dirDocumentedLaunch directoryThe bundle fills it from the original cwdStatus line
workspace.added_dirsDocumentedDirectories from /add-dir or --add-dirEmpty array if noneStatus line
workspace.git_worktreeDocumentedLinked worktree nameAbsent in the main treeStatus line
workspace.repo.host, .owner, .nameDocumentedRepository identity from originMay be absent. GitLab subgroups give a slash path in ownerStatus line
worktree.name, .path, .branch, .original_cwd, .original_branchDocumentedWorktree session dataOnly in a worktree session. branch and original_branch may be absent for hook-based worktreesStatus line
pr.number, pr.urlDocumentedOpen PR or GitLab merge requestRemoved once it merges or closesStatus line
pr.review_stateDocumentedapproved, pending, changes_requested, draftMay be absent aloneStatus line
pr.kindDocumentedmr for a GitLab merge requestAbsent for GitHubStatus line

Cost, Context, and Limit Fields​

FieldStatusWhat it holdsNotesWhere
cost.total_cost_usdDocumentedEstimated costClient-side list price. Resets at /clearStatus line
cost.total_duration_ms, cost.total_api_duration_msDocumentedWall time and API wait timeMillisecondsStatus line
cost.total_lines_added, cost.total_lines_removedDocumentedLines changedNumbersStatus line
context_window.total_input_tokens, .total_output_tokensDocumentedTokens in the windowFrom the last response. 0 before itStatus line
context_window.context_window_sizeDocumentedWindow size200000 or 1000000Status line
context_window.used_percentage, .remaining_percentageDocumentedPercent used and leftInput tokens only. May be null earlyStatus line
context_window.current_usageDocumentedPer-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_tokensDocumentedLast response is over 200k tokensFixed thresholdStatus line
rate_limits.five_hour, .seven_dayDocumentedused_percentage and resets_atClaude.ai Pro and Max only. A window drops after its reset timeStatus line
rate_limits.spend_limit.used_percentage, .resets_atDocumentedGateway spend limitNeeds 2.1.251Status line
rate_limits.spend_limit.used_usd, .limit_usd, .periodDocumentedSpend 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.warmDocumentedCache is within its TTLBooleanStatus line
prompt_cache.caching_observedDocumentedAny response reported cache tokensfalse means caching is off or not reportedStatus line
prompt_cache.ttlDocumentedCache lifetime"5m" or "1h"Status line
prompt_cache.expires_atDocumentedWhen the cache goes coldEpoch seconds. null if no cache tokensStatus line
prompt_cache.requests, .misses, .expected_rebuildsDocumentedRequest and miss countsA miss is over 5% and at least 2,000 tokens re-processedStatus line
prompt_cache.hit_ratioDocumentedCache reads over all input tokens0 to 1. null when counts are zeroStatus line
prompt_cache.cache_write_tokens, .miss_recache_tokensDocumentedTokens writtenTotals for the session and for missesStatus line
prompt_cache.last_miss_atDocumentedTime of the last missEpoch seconds. null if noneStatus line
prompt_cache.last_miss_causeDocumentedLikely 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_causesDocumentedCount per causeMapStatus line
prompt_cache.recache_tokens_if_coldDocumentedTokens a cold cache re-cachesnull after a compaction until the next requestStatus line

Subagent Task Fields​

The subagentStatusLine command gets the base hook fields, columns, and a tasks array.

FieldStatusWhat it holdsNotesWhere
columnsDocumentedUsable row widthNumbersubagentStatusLine
tasks[].idDocumentedTask idEcho it back as idsubagentStatusLine
tasks[].nameDocumentedAddress nameOptionalsubagentStatusLine
tasks[].typeDocumentedKind of tasklocal_agentsubagentStatusLine
tasks[].agentTypeDocumentedSubagent typeSame value as hook agent_type. Needs 2.1.293subagentStatusLine
tasks[].statusDocumentedStaterunning, completed, failed, killedsubagentStatusLine
tasks[].description, tasks[].labelDocumentedShort textlabel is a progress summary, else descriptionsubagentStatusLine
tasks[].startTimeDocumentedStart timeEpoch millisecondssubagentStatusLine
tasks[].model, tasks[].contextWindowSizeDocumentedResolved model and its windowOptionalsubagentStatusLine
tasks[].effortDocumentedConfigured effortString or number. Needs 2.1.213subagentStatusLine
tasks[].tokenCount, tasks[].tokenSamplesDocumentedRunning tokens and up to 16 samplesOldest firstsubagentStatusLine
tasks[].cwdDocumentedSubagent working directoryOwn worktree if anysubagentStatusLine

How It Works​

Not Verified

The exact debounce for subagentStatusLine. The source of transcript_path and prompt_id inside the program (a shared helper adds them).