Replicate the Claude Code Status Line¶
This guide explains how to reproduce the custom two-line Claude Code status display on a new macOS or Debian/Ubuntu machine.
The coloured rows above the Claude Code prompt are provided by ccstatusline, a third-party npm CLI. Claude Code sends status information to ccstatusline as JSON on standard input, and displays the text that ccstatusline returns.
What belongs to Claude Code?
The first two coloured rows are rendered by ccstatusline.
The row resembling:
▶▶ auto mode on (shift+tab to cycle) · ← 6 agents
is Claude Code's native footer and does not require additional installation.
Components¶
Only two configuration files and the ccstatusline executable are required:
| Component | Purpose |
|---|---|
~/.claude/settings.json |
Tells Claude Code to execute ccstatusline |
~/.config/ccstatusline/settings.json |
Defines what ccstatusline renders |
ccstatusline |
npm CLI that renders the status rows |
The source machine used the following versions:
| Component | Version |
|---|---|
| ccstatusline | 2.2.22 |
| Node.js | v26.3.1 |
| npm | 11.16.0 |
Tip
Pinning ccstatusline to version 2.2.22 helps keep rendering consistent with the source machine.
1. Install Node.js and npm¶
ccstatusline targets Node.js 14 compatibility, so any modern Node.js version such as Node 18 or newer is suitable.
Install Node.js with Homebrew:
Homebrew's global npm packages normally live under:
Executable symlinks are placed in:
This setup normally does not require sudo.
Install Node.js using NodeSource:
Configure a user-owned npm global package directory:
mkdir -p ~/.npm-global
npm config set prefix ~/.npm-global
echo 'export PATH="$HOME/.npm-global/bin:$PATH"' >> ~/.bashrc
exec $SHELL -l
If you use Zsh, write the PATH entry to ~/.zshrc instead.
Tip
nvm can also be used and does not require npm prefix configuration.
2. Install ccstatusline¶
Install the exact version used on the source machine:
Verify that the executable resolves through your PATH:
Typical paths are:
Do not install ccstatusline with Homebrew
There is no Homebrew formula for ccstatusline.
The following will fail:
ccstatusline is installed through npm. On a Homebrew-based Node.js installation, it may only appear to be associated with Homebrew because Node owns the global npm prefix.
3. Configure ccstatusline¶
Create the configuration directory:
Create ~/.config/ccstatusline/settings.json:
cat > ~/.config/ccstatusline/settings.json <<'EOF'
{
"version": 3,
"lines": [
[
{ "id": "1", "type": "model", "color": "cyan" },
{ "id": "2", "type": "separator" },
{ "id": "3", "type": "context-length", "color": "brightBlack" },
{ "id": "4", "type": "separator" },
{ "id": "5", "type": "git-branch", "color": "brightRed" },
{ "id": "6", "type": "separator" },
{ "id": "7", "type": "git-changes", "color": "yellow" },
{ "id": "5f3c3050-18af-4359-99c8-aa949e929444", "type": "separator" }
],
[
{ "id": "df6fa480-31af-4ffc-b2ab-9735a474a5ec", "type": "tokens-input", "color": "brightMagenta" },
{ "id": "1e4dddf4-b7cd-4613-836e-c520ce730f50", "type": "separator" },
{ "id": "6497c9dd-15c5-4431-9582-a0a4e7d78700", "type": "tokens-output", "color": "brightBlue" },
{ "id": "301b1f5e-53ce-4418-9c34-9490fc6d808d", "type": "separator" },
{ "id": "c9e42aa8-8400-4167-9f95-2ad31f195eab", "type": "tokens-total", "color": "brightGreen" },
{ "id": "63d39087-9188-4bca-a410-66aa5afc0884", "type": "separator" },
{ "id": "8cc384e8-c9e5-4212-9418-465f9d2dd612", "type": "session-cost", "color": "white" },
{ "id": "0d2408ee-a222-43dc-b94f-a217a1dd42d9", "type": "separator" },
{ "id": "aea35e35-9e1a-47e2-acdd-c0dd0aee57fc", "type": "session-usage" }
],
[]
],
"flexMode": "full-minus-40",
"compactThreshold": 60,
"colorLevel": 2,
"inheritSeparatorColors": false,
"globalBold": false,
"gitCacheTtlSeconds": 5,
"minimalistMode": false,
"powerline": {
"enabled": false,
"separators": [""],
"separatorInvertBackground": [false],
"startCaps": [],
"endCaps": [],
"autoAlign": false,
"continueThemeAcrossLines": false
},
"installation": {
"method": "pinned",
"installedVersion": "2.2.22"
}
}
EOF
The widget id values are simply unique keys. They can technically be changed, but copying the working values is the simplest approach.
The configuration path is XDG-based and is identical on macOS and Debian:
Status line layout¶
Line 1¶
A typical first row resembles:
| Widget | Colour | Purpose |
|---|---|---|
model |
Cyan | Active model |
context-length |
Bright black | Tokens currently in context |
git-branch |
Bright red | Current Git branch or no git |
git-changes |
Yellow | Dirty-file count |
Line 2¶
A typical second row resembles:
| Widget | Colour | Purpose |
|---|---|---|
tokens-input |
Bright magenta | Input token count |
tokens-output |
Bright blue | Output token count |
tokens-total |
Bright green | Total token count |
session-cost |
White | Session cost |
session-usage |
Default | Percentage of the rolling usage window consumed |
Line 3¶
The third configured line is intentionally empty:
Keep the empty third line
Do not remove the empty array from lines.
It preserves the three-line layout. The auto-mode and agents row shown underneath is provided by Claude Code itself.
4. Understand the global options¶
flexMode: "full-minus-40"-
Allows widgets to flex according to the terminal width minus 40 columns.
compactThreshold: 60-
Switches to compact rendering when the terminal becomes narrower than 60 columns.
colorLevel: 2-
Enables 256-colour output.
gitCacheTtlSeconds: 5-
Caches Git status for five seconds to avoid repeatedly querying the repository.
powerline.enabled: false-
Uses plain separators. A Nerd Font is therefore not required.
installation.method: "pinned"-
Prevents the configured installation from being silently treated as an automatically updated version.
Terminal colours
colorLevel: 2 expects a terminal that supports 256 colours, such as:
xterm-256colorscreen-256color
On a bare Debian TTY, the source configuration recommends:
For tmux:
Keep the pinned version in sync
If you install a version other than 2.2.22, update:
so the value matches the installed version.
5. Configure Claude Code¶
Claude Code must be told to invoke ccstatusline for its status line.
Add the following statusLine object to:
Do not overwrite existing settings
If ~/.claude/settings.json already contains other configuration, merge the statusLine object into the existing JSON rather than replacing the entire file.
Merge into an existing configuration¶
tmp=$(mktemp)
jq '.statusLine = {type:"command", command:"ccstatusline", padding:0, refreshInterval:10}' \
~/.claude/settings.json > "$tmp" && mv "$tmp" ~/.claude/settings.json
Create a new configuration¶
If ~/.claude/settings.json does not exist:
mkdir -p ~/.claude
cat > ~/.claude/settings.json <<'EOF'
{
"statusLine": {
"type": "command",
"command": "ccstatusline",
"padding": 0,
"refreshInterval": 10
}
}
EOF
Debian PATH issues¶
The command value is resolved through the login shell's PATH.
If the status line remains blank on Debian, use the absolute path to ccstatusline.
For example:
Use the actual path returned by:
6. Test ccstatusline without Claude Code¶
ccstatusline reads a JSON payload from standard input.
You can test the configuration by sending it a sample payload:
echo '{"model":{"display_name":"Opus 5"},"workspace":{"current_dir":"'"$PWD"'"},"cost":{"total_cost_usd":0,"total_lines_added":0,"total_lines_removed":0}}' \
| ccstatusline
You should see the configured coloured status rows.
No input received
Running ccstatusline without piping data into it in a non-TTY context can produce:
This means no JSON payload was received on standard input and is expected in that situation.
After the test succeeds, launch Claude Code. The configured status display should appear above the prompt.
7. Edit the status line interactively¶
Run ccstatusline directly from a real terminal:
This opens the interactive configurator.
It can be used to:
- Add or remove widgets
- Reorder widgets
- Change colours
- Toggle Powerline rendering
- Preview the status line
Changes are written back to:
The file can also be edited manually.
Files and paths¶
| Path | macOS | Debian |
|---|---|---|
| Binary symlink | /opt/homebrew/bin/ccstatusline |
~/.npm-global/bin/ccstatusline |
| Package | /opt/homebrew/lib/node_modules/ccstatusline |
~/.npm-global/lib/node_modules/ccstatusline |
| ccstatusline config | ~/.config/ccstatusline/settings.json |
~/.config/ccstatusline/settings.json |
| ccstatusline cache | ~/.cache/ccstatusline |
~/.cache/ccstatusline |
| Claude Code settings | ~/.claude/settings.json |
~/.claude/settings.json |
Tip
The ~/.cache/ccstatusline directory is safe to delete.
Common problems¶
brew install ccstatusline fails¶
There is no Homebrew formula for ccstatusline.
Install it with npm:
npm global packages become root-owned¶
Avoid using:
on Debian when using a user-owned npm prefix.
Configure the prefix under your home directory instead.
Layout changes after editing the configuration¶
Make sure the empty third line remains in the lines array:
Colours look incorrect¶
The configuration uses:
which expects a 256-colour terminal.
Powerline symbols are missing¶
The supplied configuration has Powerline disabled:
No Nerd Font is required in this configuration.
If Powerline separators are enabled later, a patched font such as MesloLGS NF will be required.
Session cost or usage shows zero¶
Session and cost data comes from the JSON payload supplied by Claude Code, not from ccstatusline itself.
A value of zero can therefore simply mean the session has not accumulated that usage yet.
Status line is blank on Debian¶
Check the executable path:
If required, replace:
with its absolute path.
One-shot installation¶
The following block installs the pinned version of ccstatusline, creates its configuration, and adds the Claude Code statusLine configuration.
Warning
This assumes Node.js and npm are already installed.
set -e
npm install -g ccstatusline@2.2.22
mkdir -p ~/.config/ccstatusline ~/.claude
cat > ~/.config/ccstatusline/settings.json <<'EOF'
{
"version": 3,
"lines": [
[
{ "id": "1", "type": "model", "color": "cyan" },
{ "id": "2", "type": "separator" },
{ "id": "3", "type": "context-length", "color": "brightBlack" },
{ "id": "4", "type": "separator" },
{ "id": "5", "type": "git-branch", "color": "brightRed" },
{ "id": "6", "type": "separator" },
{ "id": "7", "type": "git-changes", "color": "yellow" },
{ "id": "8", "type": "separator" }
],
[
{ "id": "9", "type": "tokens-input", "color": "brightMagenta" },
{ "id": "10", "type": "separator" },
{ "id": "11", "type": "tokens-output", "color": "brightBlue" },
{ "id": "12", "type": "separator" },
{ "id": "13", "type": "tokens-total", "color": "brightGreen" },
{ "id": "14", "type": "separator" },
{ "id": "15", "type": "session-cost", "color": "white" },
{ "id": "16", "type": "separator" },
{ "id": "17", "type": "session-usage" }
],
[]
],
"flexMode": "full-minus-40",
"compactThreshold": 60,
"colorLevel": 2,
"inheritSeparatorColors": false,
"globalBold": false,
"gitCacheTtlSeconds": 5,
"minimalistMode": false,
"powerline": {
"enabled": false,
"separators": [""],
"separatorInvertBackground": [false],
"startCaps": [],
"endCaps": [],
"autoAlign": false,
"continueThemeAcrossLines": false
},
"installation": {
"method": "pinned",
"installedVersion": "2.2.22"
}
}
EOF
if [ -f ~/.claude/settings.json ]; then
tmp=$(mktemp)
jq '.statusLine = {type:"command", command:"ccstatusline", padding:0, refreshInterval:10}' \
~/.claude/settings.json > "$tmp" && mv "$tmp" ~/.claude/settings.json
else
printf '%s\n' '{"statusLine":{"type":"command","command":"ccstatusline","padding":0,"refreshInterval":10}}' \
> ~/.claude/settings.json
fi
echo "done — restart Claude Code"
Final checklist¶
- Node.js and npm are installed
-
ccstatusline@2.2.22is installed globally -
which ccstatuslinereturns a valid executable -
~/.config/ccstatusline/settings.jsonexists - The empty third line remains in the
linesarray -
~/.claude/settings.jsoncontains thestatusLineconfiguration - The test JSON renders the two status rows
- Claude Code has been restarted