Back to prompt library
Featured prompt

Claude Code Status Line Setup

A machine-setup prompt that fully replaces any existing Claude Code status line with a jq-powered script: model + window size from the payload, colored remaining bar, mood emoji, and dimmed worktree folder name when inside a linked git worktree.

Model: Claude CodeUse case: AutomationOutput: Shell scriptAdded: Jun 16, 2026

Copies the full prompt text, including setup steps and variables.

Tags

claude-codeStatusLineautomationdeveloper-tools

Preview

Claude Code terminal status line showing Opus 1M context remaining with the linked worktree tree indicator
Claude Code status line preview with linked worktree tree indicator

Prompt

Set up my Claude Code status line to be an exact copy of a specific design.

Use the `/statusline` command to do this — it pulls Claude Code's built-in **statusline-setup** skill that configures the status line setting. But transcribe the script below **verbatim**; do NOT improvise, redesign, or invent your own version.

**IMPORTANT — this must fully replace whatever is already there.** Three cases, all handled the same way:

1. **Nothing configured yet** → install fresh.
2. **A different custom status line configured** in `~/.claude/settings.json` (or anywhere else) → remove/overwrite it.
3. **An older version of _this_ status line already installed** — recognizable by the 20-char `█░` bar and mood emoji, but with either no worktree section at all, or a bare ` 🌳` with no worktree name after it → **overwrite the entire script file; do NOT patch or hand-edit the old copy.** Older revisions drift in small ways, so the only acceptable end state is that `~/.claude/statusline-command.sh` matches the script below exactly.

When you're done there must be exactly one `statusLine` config in `~/.claude/settings.json`, exactly one status line script, and it must be this one.

Steps:

1. Make sure `jq` is installed (it's required — without it the bar silently won't render). Check with `command -v jq`. If missing, install it (macOS: `brew install jq`; Debian/Ubuntu: `sudo apt-get install -y jq`).

2. Write this EXACT content to `~/.claude/statusline-command.sh` (create the `~/.claude` dir if needed), then `chmod +x` it. If the file already exists, **truncate and rewrite it wholesale** — do not merge, append, or surgically edit the worktree block of an older copy:

```bash
#!/usr/bin/env bash
input=$(cat)

# ── Model detection ──────────────────────────────────────────
# Claude Code sends the model as an OBJECT (.model.id). Hand-made or older
# payloads may send a plain string, so handle both without erroring out.
model_id="${CLAUDE_MODEL_ID:-}"
if [ -z "$model_id" ]; then
  model_id=$(echo "$input" | jq -r 'if (.model|type)=="object" then (.model.id // empty) else (.model // empty) end')
fi
model_lower=$(echo "$model_id" | tr '[:upper:]' '[:lower:]')

# Context size is read from the payload, never hardcoded per model — the same
# model ships in different window sizes (e.g. Sonnet 200K vs Sonnet 1M), so
# guessing from the name gets both the label and the "free" count wrong.
total_tokens=$(echo "$input" | jq -r '.context_window.context_window_size // empty')
case "$total_tokens" in ''|null|*[!0-9]*) total_tokens=200000 ;; esac

if [ "$total_tokens" -ge 1000000 ]; then
  ctx_label="$(( total_tokens / 1000000 ))M"
elif [ "$total_tokens" -ge 1000 ]; then
  ctx_label="$(( total_tokens / 1000 ))K"
else
  ctx_label="${total_tokens}"
fi

if echo "$model_lower" | grep -q "opus"; then
  model_label="Opus ${ctx_label}"
elif echo "$model_lower" | grep -q "sonnet"; then
  model_label="Sonnet ${ctx_label}"
elif echo "$model_lower" | grep -q "haiku"; then
  model_label="Haiku ${ctx_label}"
elif echo "$model_lower" | grep -q "fable"; then
  model_label="Fable ${ctx_label}"
else
  model_label="Claude ${ctx_label}"
fi

# ── Context window ───────────────────────────────────────────
remaining=$(echo "$input" | jq -r '.context_window.remaining_percentage // empty')

bar=""
face=""
if [ -n "$remaining" ]; then
  pct=$(printf "%.0f" "$remaining")

  # Free tokens (human-readable)
  free_tokens=$(( total_tokens * pct / 100 ))
  if [ "$free_tokens" -ge 1000000 ]; then
    free_label="$(( free_tokens / 1000 ))K"
  elif [ "$free_tokens" -ge 1000 ]; then
    free_label="$(( free_tokens / 1000 ))K"
  else
    free_label="${free_tokens}"
  fi

  # Color zone based on remaining %
  #   Green  > 20%  — safe
  #   Amber  10-20% — approaching compaction
  #   Red    < 10%  — compaction imminent
  if [ "$pct" -gt 20 ]; then
    color="\033[32m"   # green
  elif [ "$pct" -ge 10 ]; then
    color="\033[33m"   # yellow / amber
  else
    color="\033[31m"   # red
  fi
  reset="\033[0m"
  dim="\033[90m"

  # 20-char wide bar
  width=20
  filled=$(( pct * width / 100 ))
  [ "$filled" -gt "$width" ] && filled=$width
  empty_count=$(( width - filled ))

  filled_str=""
  empty_str=""
  for ((i=0; i<filled; i++)); do filled_str+="█"; done
  for ((i=0; i<empty_count; i++)); do empty_str+="░"; done

  bar="${color}${filled_str}${reset}${dim}${empty_str}${reset} ${pct}% ${free_label} free"

  # ── Smiley face (mood based on remaining context) ──────────
  if [ "$pct" -ge 75 ]; then
    face="😄"
  elif [ "$pct" -ge 55 ]; then
    face="😊"
  elif [ "$pct" -ge 40 ]; then
    face="😐"
  elif [ "$pct" -ge 30 ]; then
    face="😟"
  elif [ "$pct" -ge 20 ]; then
    face="😰"
  elif [ "$pct" -ge 10 ]; then
    face="😱"
  elif [ "$pct" -ge 3 ]; then
    face="🤮"
  else
    face="💀"
  fi
fi

# ── Worktree indicator ───────────────────────────────────────
# Show 🌳 followed by the worktree's folder name on the far right when the
# current directory is a linked git worktree. A linked worktree has a
# per-worktree git dir that differs from the repo's common git dir.
# (reset/dim are re-declared here so the dimmed name still renders even when
# the context-window block above didn't run.)
reset="\033[0m"
dim="\033[90m"

dir=$(echo "$input" | jq -r '.workspace.current_dir // .cwd // empty')
worktree_out=""
if [ -n "$dir" ]; then
  git_dir=$(git -C "$dir" rev-parse --git-dir 2>/dev/null)
  git_common_dir=$(git -C "$dir" rev-parse --git-common-dir 2>/dev/null)
  if [ -n "$git_dir" ] && [ -n "$git_common_dir" ] && [ "$git_dir" != "$git_common_dir" ]; then
    worktree_out=" 🌳"
    # Name the worktree by its root folder (the worktree's directory name)
    worktree_name=$(basename "$(git -C "$dir" rev-parse --show-toplevel 2>/dev/null)")
    [ -n "$worktree_name" ] && worktree_out="${worktree_out} ${dim}${worktree_name}${reset}"
  fi
fi

# ── Assemble output ──────────────────────────────────────────
output="${model_label}"
[ -n "$bar" ]          && output="${output} ${bar}"
[ -n "$face" ]         && output="${output} ${face}"
[ -n "$worktree_out" ] && output="${output}${worktree_out}"

printf "%b" "$output"
```

3. Wire it into `~/.claude/settings.json`. PRESERVE all my other existing settings — only add or replace the top-level `statusLine` key (replacing any status line I already had). Use my real absolute home path (run `echo $HOME` to get it; do not hardcode someone else's username):

```json
"statusLine": {
  "type": "command",
  "command": "bash <MY_HOME>/.claude/statusline-command.sh"
}
```

If `settings.json` doesn't exist, create it as valid JSON containing just that key. If it exists, merge carefully so the rest of the file is untouched and any previous `statusLine` is overwritten.

4. Confirm it works. Run every check below and show me the output of each.

**Base line** — pipe a sample payload through the script, using the real shape Claude Code sends (`.model` is an object, and the window size comes from `.context_window.context_window_size`):

```bash
echo '{"model":{"id":"claude-opus-5[1m]"},"context_window":{"remaining_percentage":82,"context_window_size":1000000}}' | bash ~/.claude/statusline-command.sh
```

It should print:  `Opus 1M ████████████████░░░░ 82% 820K free 😄`

**Sizing check** — the context size must come from the payload, not the model name. Same model, smaller window, and a different model at 1M:

```bash
echo '{"model":{"id":"claude-opus-5"},"context_window":{"remaining_percentage":82,"context_window_size":200000}}' | bash ~/.claude/statusline-command.sh
echo '{"model":{"id":"claude-sonnet-5"},"context_window":{"remaining_percentage":82,"context_window_size":1000000}}' | bash ~/.claude/statusline-command.sh
```

These must print `Opus 200K … 164K free` and `Sonnet 1M … 820K free` respectively. If either shows the wrong size, the script is guessing from the model name instead of reading the payload — go back and fix it.

**Worktree branch** — the 🌳 and the name only appear when the current directory is an actual linked git worktree, so the payload above won't show them. To verify that branch, run it from inside a worktree (or feed a worktree path in), e.g.:

```bash
echo '{"model":{"id":"claude-opus-5[1m]"},"context_window":{"remaining_percentage":82,"context_window_size":1000000},"workspace":{"current_dir":"'"$(pwd)"'"}}' | bash ~/.claude/statusline-command.sh
```

When `current_dir` is a linked worktree it should append ` 🌳 <worktree-folder-name>` to the end of the line, with the name dimmed — e.g. `Opus 1M ████████████████░░░░ 82% 820K free 😄 🌳 feature-auth`.

If I don't have a worktree handy, make a throwaway one to prove the branch fires, then clean it up:

```bash
git worktree add /tmp/wt-check -b wt-check 2>/dev/null
echo '{"model":{"id":"claude-opus-5[1m]"},"context_window":{"remaining_percentage":82,"context_window_size":1000000},"workspace":{"current_dir":"/tmp/wt-check"}}' | bash ~/.claude/statusline-command.sh
git worktree remove /tmp/wt-check --force && git branch -D wt-check
```

**Negative check** — confirm it stays quiet where it should. Against a normal (non-worktree) directory it must print NO 🌳 and no folder name:

```bash
echo '{"model":{"id":"claude-opus-5[1m]"},"context_window":{"remaining_percentage":82,"context_window_size":1000000},"workspace":{"current_dir":"'"$HOME"'"}}' | bash ~/.claude/statusline-command.sh
```

The expected status line format is:

```
<model label> <colored 20-char bar> <pct>% <free tokens> free <mood emoji> [🌳 <worktree name>]
```

The worktree segment is conditional — it appears **only** inside a linked git worktree. In a repo's main working tree, or in a non-git directory, nothing is appended. There is deliberately no always-on "current project" indicator.

Variables

MY_HOMEAbsolute home path used in the settings.json command.
remaining_percentageSample context-window percentage used for verification.