Claude Code Statusline: Setup, Examples and Fixes

Claude Code statusline

A Claude Code statusline is a small command that prints session information beneath the prompt. A useful one shows the current model, project, context usage and available limit information without turning the bottom of the terminal into a dashboard. This tutorial gives you a versioned Node.js example for Windows, macOS and Linux, plus sample JSON inputs you can use to check whether the numbers are correct.

Quick setup: save the statusline.cjs script below in your .claude folder, add a statusLine command to settings.json, then test the script with the fixtures before trusting its live display. It needs Node.js 18 or later, uses no external packages and makes no API calls.

Sonnet | client app | ctx 47% | sess $1.37 | 5h 24% | 7d 31% | cap 63%

The line above is fixture output, not a claim about a live Claude account. The complete sample includes a Windows project path containing spaces and deliberately separates six kinds of information. If a value is unavailable, the script displays -- or leaves the optional segment out rather than inventing a zero.

Read the numbers before deciding what to display

SegmentWhat it readsWhat it does not mean
Sonnetmodel.display_nameNot a promise that every subagent uses the same model.
client appLast folder in workspace.current_dirNot the entire repository path or necessarily the directory where the session began.
ctx 47%context_window.used_percentageNot 47% of a subscription allowance or monthly spend.
sess $1.37cost.total_cost_usdNot necessarily the amount charged to your card.
5h 24%, 7d 31%Available rate_limits windowsNot the size or fullness of the model’s context window.
cap 63%rate_limits.spend_limit.used_percentageNot a universal API billing cap: this field is for applicable Claude apps gateway spend limits.

The context percentage is calculated from input tokens, including cache reads and cache writes. It does not add the latest output tokens to the numerator. Claude Code reports its most recent API response, while /context can estimate extra content added since that response. A brief disagreement between the two displays is therefore possible.

Session cost is an API-equivalent estimate, usually calculated at list prices, and resets when /clear starts a new session. For Pro or Max subscribers, it is not an invoice and should not be treated as money deducted from a subscription balance. Our Claude Code pricing guide explains the practical difference between plan allowances, optional overage and metered API use.



Install one statusline script on Windows, macOS or Linux

First, run node --version in your terminal. The example below uses CommonJS so it runs without an npm installation step, TypeScript build, or jq. It reads a single JSON document from standard input and prints one line to standard output. No Git commands run on each refresh, which avoids unnecessary work in a large repository.

Step 1: Save DIY AI statusline v1.0

Copy the complete script into statusline.cjs. Use ~/.claude/statusline.cjs on macOS and Linux, or the corresponding .claude directory in your Windows user profile. Create the folder if it does not already exist. Keep the .cjs extension so Node treats the file as CommonJS even if your project defaults to ES modules.

// DIY AI statusline v1.0 - Node.js 18+, no packages or API calls.
'use strict';

function clean(value, fallback = '') {
  return typeof value === 'string' && value.trim()
    ? value.replace(/[\x00-\x1f\x7f]/g, ' ').trim()
    : fallback;
}
function short(value, max) {
  const chars = Array.from(value);
  return chars.length <= max ? value
    : chars.slice(0, max <= 3 ? max : max - 3).join('') + (max <= 3 ? '' : '...');
}
function folder(value) {
  return clean(value).replace(/[\\/]+$/, '').split(/[\\/]/).pop() || '';
}
function percent(value) {
  return Number.isFinite(value) ? `${Math.round(value)}%` : '--';
}

let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', chunk => { input += chunk; });
process.stdin.on('end', () => {
  let data;
  try { data = JSON.parse(input); }
  catch { console.error('statusline: invalid JSON on stdin'); process.exitCode = 1; return; }

  const model = short(clean(data?.model?.display_name, 'Claude'), 16);
  const dir = short(folder(data?.workspace?.current_dir ?? data?.cwd), 16);
  const context = 'ctx ' + percent(data?.context_window?.used_percentage);
  const dollars = data?.cost?.total_cost_usd;
  const sessionCost = 'sess ' + (Number.isFinite(dollars) ? '$' + dollars.toFixed(2) : '--');
  const five = data?.rate_limits?.five_hour?.used_percentage;
  const seven = data?.rate_limits?.seven_day?.used_percentage;
  const spend = data?.rate_limits?.spend_limit?.used_percentage;

  let parts = [
    { key: 'model', text: model },
    ...(dir ? [{ key: 'project', text: dir }] : []),
    { key: 'context', text: context },
    { key: 'cost', text: sessionCost },
    ...(Number.isFinite(five) ? [{ key: 'five', text: '5h ' + percent(five) }] : []),
    ...(Number.isFinite(seven) ? [{ key: 'seven', text: '7d ' + percent(seven) }] : []),
    ...(Number.isFinite(spend) ? [{ key: 'spend', text: 'cap ' + percent(spend) }] : [])
  ];

  const columns = Number.parseInt(process.env.COLUMNS || '', 10);
  const budget = Math.max(12, (columns >= 12 ? columns : 80) - 6);
  const width = () => parts.map(x => x.text).join(' | ').length;
  for (const key of ['spend', 'project', 'seven', 'five', 'cost']) {
    if (width() > budget) parts = parts.filter(x => x.key !== key);
  }
  if (width() > budget) {
    const index = parts.findIndex(x => x.key === 'model');
    if (index !== -1) parts[index].text = short(parts[index].text, Math.max(1, budget - context.length - 3));
  }
  process.stdout.write(parts.map(x => x.text).join(' | ') + '\n');
});

The code deliberately keeps the output to one line, avoids emojis and colours, and budgets six characters for interface spacing. It reads COLUMNS when Claude Code supplies the terminal width, then removes lower-priority segments in order: spend cap, folder, seven-day limit, five-hour limit and session cost. Model and context are preserved where possible. The width calculation uses JavaScript string length, so filenames containing double-width characters may still need a larger margin.

Step 2: Configure the command for your operating system

Open your user-level ~/.claude/settings.json. Add the statusLine property to the existing JSON object rather than replacing permissions, hooks or other settings. The padding value of zero avoids adding extra spaces to an already narrow terminal.

Windows (PowerShell or Git Bash): replace Your Name with your actual Windows profile folder name. Keep the forward slashes and the escaped quotation marks inside the JSON string. Claude Code can execute the command through Git Bash if installed, or PowerShell otherwise, and either route needs the script filename to stay one argument.

{
  "statusLine": {
    "type": "command",
    "command": "node \"C:/Users/Your Name/.claude/statusline.cjs\"",
    "padding": 0
  }
}

macOS or Linux: use the shell-expanded home directory. You do not need to mark a .cjs file executable because Node runs it directly.

{
  "statusLine": {
    "type": "command",
    "command": "node \"$HOME/.claude/statusline.cjs\"",
    "padding": 0
  }
}

Save the configuration. Claude Code normally reloads settings automatically; the statusline updates after the next relevant event. If you prefer the built-in generator, /statusline can create a different script from a natural-language description, but use the manual settings above when you want this exact version and testable output.

Test three input states before relying on the display

Create three JSON files in a temporary folder. These fixtures intentionally cover a populated session, an early session where values are null, and an object in which optional fields are missing. The first also establishes why a displayed context percentage must not be calculated by adding output tokens.

Fixture A: A populated session and a Windows folder containing spaces

Save as active.json. Its input tokens total 94,000 against a 200,000-token window, so the supplied 47% is internally consistent; the 1,000 output tokens are not added to that percentage.

{
  "model": { "display_name": "Sonnet" },
  "workspace": { "current_dir": "C:\\Users\\Alex Doe\\Projects\\client app" },
  "context_window": {
    "context_window_size": 200000,
    "used_percentage": 47,
    "current_usage": {
      "input_tokens": 32000,
      "cache_creation_input_tokens": 40000,
      "cache_read_input_tokens": 22000,
      "output_tokens": 1000
    }
  },
  "cost": { "total_cost_usd": 1.37 },
  "rate_limits": {
    "five_hour": { "used_percentage": 24 },
    "seven_day": { "used_percentage": 31 },
    "spend_limit": { "used_percentage": 63 }
  }
}

Fixture B: Context and cost are not available yet

Save as warming.json. A missing value is not the same as measured zero usage. Immediately after /compact, current_usage can also return to null until the next API response.

{
  "model": { "display_name": "Opus" },
  "workspace": { "current_dir": "/home/alex/my project" },
  "context_window": { "used_percentage": null, "current_usage": null },
  "cost": { "total_cost_usd": null },
  "rate_limits": null
}

Fixture C: Optional objects are absent altogether

Save as missing.json. This is the regression input for a common broken implementation.

{ "model": { "display_name": "Opus" } }

From the folder holding your fixtures, test on macOS or Linux:

COLUMNS=80 node "$HOME/.claude/statusline.cjs" < active.json
COLUMNS=36 node "$HOME/.claude/statusline.cjs" < active.json
node "$HOME/.claude/statusline.cjs" < warming.json
node "$HOME/.claude/statusline.cjs" < missing.json

Or in Windows PowerShell, quote the script path exactly as configured:

$env:COLUMNS = '36'
Get-Content -Raw .\active.json | node "C:/Users/Your Name/.claude/statusline.cjs"
Get-Content -Raw .\warming.json | node "C:/Users/Your Name/.claude/statusline.cjs"
Remove-Item Env:COLUMNS -ErrorAction SilentlyContinue

For the supplied fixtures, the expected output is:

# active.json with 80 columns
Sonnet | client app | ctx 47% | sess $1.37 | 5h 24% | 7d 31% | cap 63%

# active.json with 36 columns
Sonnet | ctx 47% | sess $1.37

# warming.json
Opus | my project | ctx -- | sess --

# missing.json
Opus | ctx -- | sess --

These outputs check parsing, escaping and width selection without consuming Claude Code usage. The production line still depends on your installed Claude Code version, account type, and available session data; the fixture verifies only the formatter.

A real failure case: dereferencing a missing context object

A tempting first implementation reads data.context_window.used_percentage directly. It works on a complete example, then fails with a TypeError when context_window is absent. The statusline can disappear even though Claude Code itself is working. You can reproduce the problem with missing.json by running this intentionally broken expression against the parsed fixture:

const pct = Math.round(data.context_window.used_percentage); // TypeError

The correction is to check both the object and the numeric value before formatting it:

const value = data?.context_window?.used_percentage;
const label = Number.isFinite(value) ? `${Math.round(value)}%` : '--';

Using value || 0 instead is weaker. It turns a genuine unknown into 0%, making a new session appear empty rather than not yet measured. The v1.0 script uses the same guarded read for cost and rate-limit fields. Invalid JSON is handled separately: it writes an error to standard error and exits unsuccessfully rather than printing invented session data.

Fix a blank, clipped or misleading Claude Code statusline

SymptomCheck firstFix
Completely blank lineRun the exact node command with active.json.Check Node is on the shell’s PATH, JSON settings are valid, and output goes to stdout. Use claude --debug for script errors.
Works in PowerShell but not inside Claude CodeLook for Windows backslashes or unquoted spaces in statusLine.command.Use a quoted path with forward slashes as in the Windows example. Git Bash treats unquoted backslashes as escapes.
ctx -- after startup or compactionCheck whether an API response has completed.Send the next request and re-check. Do not force the field to zero or guess from transcript size.
Line wraps or interface layout shiftsSet COLUMNS=36 and inspect the formatter’s output.Reduce segments or increase the reserved width margin. Claude Code’s own notifications can occupy part of the row.
No 5h, 7d or capCheck whether your account and gateway supply those objects.Do not derive a quota percentage from session cost. Leave unsupported segments absent.
Statusline works in a trusted project but not anotherInspect workspace trust and managed hook restrictions.Complete the trust flow or ask the administrator whether managed settings disable custom status lines.

Before debugging output colours or adding git status, verify one plain line. Calling Git, checking a network endpoint or parsing an entire transcript on every redraw makes diagnosis harder, and a slow command can be cancelled when a new update arrives. Claude Code’s official statusline documentation describes update events, the JSON fields, Windows command handling and the debug checks.

Your search, your sources
Make DIY AI a preferred source

See more of our reporting in Google Top Stories, AI Overviews and AI Mode.

Add DIY AI on Google

What this statusline cannot tell you

A context window, a session cost estimate, a gateway spend cap, and a subscription rate limit are four different measurements. A model can have plenty of context remaining while your five-hour account allowance is nearly exhausted. Equally, a high context percentage may warrant /compact without suggesting any spend-limit problem.

For subscription accounts, the rate-limit fields may appear only after an API response, and individual windows may be omitted. A gateway spend limit is not automatically available to every API user. Avoid promising a precise reset time, live account balance or hard spending protection from a script that only reads the provided JSON. If you need billing controls, configure them in the billing or gateway system itself.

The best use of a statusline is early warning and orientation. Keep it concise, then use Claude Code best practices for the separate questions of task scoping, verification and controlling long-running agents. If you launch Claude Code from an IDE terminal, the same path and display checks apply; our JetBrains AI coding workflow guide covers the wider integration choice.

Preflight checklist before you keep the statusline

  • node --version works in the environment used by Claude Code.
  • settings.json remains valid and retains existing settings.
  • Windows script paths use quoted forward slashes; folder names with spaces survive.
  • Populated, null and missing-field fixtures all print their expected output.
  • A 36-column fixture produces one line without wrapping.
  • Unknown values remain --, and absent account limits are not fabricated.
  • Live output is checked after a completed response and again after /compact.

Start with v1.0 unchanged. Once it survives those checks, add one feature at a time and keep the three fixtures as a regression test. A smaller statusline whose numbers you can explain is more useful than a colourful one you cannot troubleshoot.

You Might Also Like:

best AI coding tools

Best AI Coding Tools 2026

By: Steven Jones On:
Updated on: August 12, 2026
Claude Code is the best AI coding tool overall in 2026 because it leads the DIY AI dataset for repository…
Claude Code & Claude Pro Pricing 2026

Claude Code Pricing 2026

By: Steven Jones On:
Updated on: October 17, 2026
Claude Code pricing starts at $20 per month with Claude Pro; Max 5x costs $100 per month, and Max 20x…
code review automation

Code Review Automation

By: Steven Jones On:
Updated on: October 15, 2026
Code review automation runs repeatable checks on a pull request and helps determine whether it can be merged. A useful…
Steven Jones

Writer: Steven Jones

AI Tools Reviewer and Technical Analyst

Steven Jones is a technology analyst specialising in artificial intelligence, machine learning workflows, and emerging automation tools.

At DIY AI, he focuses on clear, practical guidance for people comparing AI tools in the real world. His work covers text generation, image generation, video tools, data platforms, developer-focused AI products, and the automation workflows that connect them.

Steven's reviews are built around hands-on testing, practical benchmarks, and transparent scoring rather than vendor claims. He looks closely at where each tool performs well, where it falls short, and what those trade-offs mean for creators, teams, and businesses trying to make sensible AI adoption decisions.

He has a particular interest in safety, reliability, output quality, performance metrics, and dataset quality. When he is not reviewing the latest AI model updates, he experiments with prompt engineering techniques and contributes to DIY AI ongoing work on fair, explainable scoring frameworks for AI tools.

Contact

Leave a Comment On: Claude Code Statusline

Your email address will not be published.