AgentDockDownload for Mac

Guide

Add a Claude Code status line

How to set a Claude Code status line: statusLine in settings.json, the JSON on stdin, and a script that prints the model, git branch, and directory.

A Claude Code status line is a row at the bottom of that session. Claude Code runs a shell command you configure, passes JSON about the session on stdin, and prints whatever the command writes to stdout. The row sits above the built-in footer badges. It is how you keep the model, the directory, and the git branch visible in the terminal you are looking at. The setup below follows Claude Code's status line docs.

Set it with /statusline

In a Claude Code session, /statusline plus a description writes a script under ~/.claude/ and updates your settings. Approve the file edits if Claude asks.

/statusline show the model, the folder name, and the git branch

Run /statusline with no arguments and it auto-configures from your shell prompt, as the command list describes. To turn the row off, run /statusline delete, /statusline clear, or /statusline remove it. Deleting the statusLine field from the settings file does the same.

The statusLine setting

The setting is statusLine in ~/.claude/settings.json (every project) or in the project's .claude/settings.json. type is "command". command is a script path or an inline shell command. Add the field beside the settings you already have. This one-liner uses jq to print the model, the last segment of the directory, and the context percentage. used_percentage can be null early in a session, so // 0 keeps the line from printing the word null:

{
  "statusLine": {
    "type": "command",
    "command": "jq -r '\"[\\(.model.display_name)] \\(.workspace.current_dir | split(\"/\") | last) | \\(.context_window.used_percentage // 0)%\"'"
  }
}

Claude Code reloads settings on save and runs the command. The line stays blank until the command exits 0 and prints something. Install jq first (on a Mac with Homebrew, brew install jq); a missing jq makes this command fail, and a failing command leaves the row empty.

Three optional fields sit on the same object. padding is extra horizontal space in characters, default 0, on top of the interface's own spacing. refreshInterval is a number of seconds, minimum 1, and re-runs the command on that timer as well as on events. Leave it unset to run only on events. Set it for a clock, or when background subagents change git state while the main session is idle. hideVimModeIndicator set to true hides the built-in -- INSERT -- text when your script prints vim.mode itself. The same page documents all three.

JSON Claude Code passes on stdin

The command's standard input is one JSON object for this session. These are the fields the examples on this page use. Names and meaning are from the status line docs; that page has the full list, including rate limits, the prompt cache, and pull requests.

A field the docs mark as absent is left out of the JSON. A field that is present and null is separate: jq -r prints the word null unless you give a fallback (// 0 or // empty). The script runs on your machine and does not spend API tokens.

Model, git branch, and directory

The one-liner can only print fields that are in the JSON. The branch comes from git, in the directory the JSON names. Save this as ~/.claude/statusline.sh. git -C runs in workspace.current_dir, which is the path the docs say is the session directory. git branch --show-current prints nothing when that directory is not a checkout, and nothing on a detached HEAD.

#!/bin/bash
# Claude Code writes session JSON to stdin.
# https://code.claude.com/docs/en/statusline
set -o pipefail
input=$(cat)

if ! command -v jq >/dev/null 2>&1; then
  echo "status line: install jq"
  exit 0
fi

model=$(printf "%s" "$input" | jq -r ".model.display_name // empty") || {
  echo "status line: jq could not parse stdin"
  exit 0
}
dir=$(printf "%s" "$input" | jq -r ".workspace.current_dir // .cwd // empty") || {
  echo "status line: jq could not parse stdin"
  exit 0
}
if [ -z "$model" ]; then
  model="?"
fi

folder=""
branch=""
if [ -n "$dir" ]; then
  folder=$(basename "$dir")
  # The branch is not a stdin field. Ask git in the session directory.
  branch=$(git -C "$dir" branch --show-current 2>/dev/null || true)
fi

if [ -n "$folder" ] && [ -n "$branch" ]; then
  printf "[%s] %s (%s)\n" "$model" "$folder" "$branch"
elif [ -n "$folder" ]; then
  printf "[%s] %s\n" "$model" "$folder"
else
  printf "[%s]\n" "$model"
fi

Mark it executable, then point command at it. A script that is not executable fails, and the row stays blank.

chmod +x ~/.claude/statusline.sh
{
  "statusLine": {
    "type": "command",
    "command": "~/.claude/statusline.sh"
  }
}

Try it before trusting the setting. This feeds a small JSON document on stdin. The branch appears when $PWD is inside a git checkout:

echo "{\"model\":{\"display_name\":\"Opus\"},\"workspace\":{\"current_dir\":\"$PWD\"}}" | ~/.claude/statusline.sh

A checkout at ~/code/shop-web on branch feature-auth prints [Opus] shop-web (feature-auth). The docs' own walkthrough prints the model, the folder, and the context percentage, and their git example is the pattern this script follows. Bash covers macOS and Linux. On Windows, the docs' Windows section shows PowerShell and Git Bash, and paths in command use forward slashes.

When the line updates

The command runs once when the session starts, including when you resume one. After that it runs when a new assistant message arrives, when /compact finishes, when the permission mode changes, when vim mode toggles, when you change the command in settings, when a refreshInterval elapses, when a rate-limit window in the last JSON reaches its resets_at, and when a warm prompt cache in that JSON reaches its expires_at. Updates are debounced by 300ms, except a change to command itself, which runs immediately. If a new update arrives while the script is still running, Claude Code cancels the in-flight script. Editing the script shows up the next time a trigger runs it. The row hides while the help menu or a permission prompt is open.

With a custom status line configured, Claude Code stops showing most of the footer's keyboard hints, including esc to interrupt, ? for shortcuts, and hold space to speak. The footer badges stay. The status line does not replace them.

When the line stays blank

Claude Code shows the command's stdout only after it exits 0. Anything else leaves the row blank. claude --debug logs the script's stderr on every run, and the exit code on the first run of a session.

Several sessions at once

Each claude process has its own status line, and the JSON is that process's session. The model, folder, and branch on the row tell you which checkout this terminal is. Set a name with /rename or start with --name when you want session_name in the JSON too. The default short name does not populate that field.

The row is inside the session on screen. A question in another window is not part of this stdin. Give each task its own checkout and its own tmux window or iTerm tab, and name the window for the branch. Run Claude Code in parallel with git worktrees is that layout: claude --worktree, one window per task, and what still collides. tmux's status line is the window list along the edge. Claude Code's status line is the row inside the pane.

AgentDock is the view across those sessions. It reads Claude Code sessions you already started, from ~/.claude and, where it can, from the terminal. Your statusLine script keeps running inside Claude Code. Each session is a dot on the screen edge: blue while the turn runs, amber when it is waiting on you, green when the turn finished, gray when idle. With the Claude Code hook on (Settings › Agents › Claude Code › Know when Claude Code needs you), amber means a permission prompt or a question, for a session in a window you are not looking at as well as the one in front. The hook applies to sessions started after you turn it on. The Inbox (⌃⌥I) collects the questions. The hover card shows the git branch, and a linked worktree is labeled with the repository name.

That works in tmux, iTerm, and cmux, which can also take a typed answer. Ghostty, Warp, Alacritty, and Terminal show the same dots; typing into those terminals goes through tmux. After the trial, the dots and the hover card keep working. The Inbox and ⌥⌥ need a license.

Questions

How do I add a Claude Code status line?

Run /statusline and describe what to show, or add a statusLine object to ~/.claude/settings.json or the project's .claude/settings.json. Set type to command and command to a script or an inline shell command. The command reads JSON on stdin and prints the row. Make a script executable with chmod +x. The fields and the setup are documented at https://code.claude.com/docs/en/statusline.

What does the /statusline command do?

It configures Claude Code's status line. With a description, Claude Code writes a script under ~/.claude/ and updates settings. With no arguments, it auto-configures from your shell prompt. /statusline delete, /statusline clear, or /statusline remove it turns the row off. Deleting the statusLine field from settings.json does the same.

What JSON does the Claude Code status line receive?

One object on stdin. It includes model.id and model.display_name, cwd and workspace.current_dir (the same path), workspace.project_dir, session_id, context_window.used_percentage, and cost.total_cost_usd. session_name appears after --name, /rename, or an AI-generated title. Read the git branch with git. worktree.branch is present only during a worktree session. The full list is at https://code.claude.com/docs/en/statusline.

Can the Claude Code status line show the git branch?

Yes, by asking git. The directory is workspace.current_dir. Run git branch --show-current in that directory. A worktree session can also include worktree.branch, and a linked worktree can include workspace.git_worktree. Neither replaces git branch --show-current for an ordinary checkout.

Why is my Claude Code status line blank?

The command must exit 0 and print to stdout. A script that is not executable, a missing jq, a parse error, or empty output leaves the row blank. It also stays blank until you accept the workspace trust dialog. disableAllHooks outside managed settings, and allowManagedHooksOnly, leave only a managed status line. claude --debug logs the script's stderr. Use a jq fallback such as // 0 when a field is null before the first API response.

Does the status line show every Claude Code session?

Each claude process runs its own command and passes that session's JSON. The model and the question in another terminal are not in this stdin. Put the folder and the git branch on the row, and give each task its own window. AgentDock shows every Claude Code session as a dot, including ones waiting in a window you are not looking at.

Does a Claude Code status line use API tokens?

The script runs on your machine and does not spend API tokens. cost.total_cost_usd is an estimate computed on your machine at list price, unless a modelPricing table is in effect, and it can differ from the bill. It resets to 0 when /clear starts a new session.