スパイダープラス Tech Blog

建設SaaS「スパイダープラス」のエンジニアとデザイナーのブログ

[Claude Code]status line つかってる???つかってないあなたも今日からstatus lineデビュー!

こんにちは!ピヨコです。
Claude Codeのシェア拡大がめざましく、ブログ記事なども多く発信されるようになりました。
ここ半年でClaude Codeは急速な進化を遂げているなと感じています。

それでは、みなさんにClaude Codeについて質問です。

status line つかってますか?」

私は使ってます。ズブズブに浸かってるといっても過言ではないです。

※いずれも2026/04/23時点の情報です。記事内のスクリプトは自己責任での利用をお願いします。

status line とは

status line とは、Claude Code CLIの下部に情報を表示できる便利な機能です。
Claude Code v.2.1.6で登場しました。

以下の画像のplan modeより上の3行がstatus lineです。
ちょこっと見るだけで、良さそうな機能に見えませんか…?

具体的に表示できるものとしては、コンテキストウィンドウの使用状況やレートリミットの使用状況、gitの情報などClaude Code利用中に確認できると助かる情報を表示可能です。
特にレート制限の使用状況に関しては、ccusageなどサードパーティ製のツールに頼らねばならない状態にあったので嬉しい機能です。

また、status lineの中にリンクも配置することができます。私はGitHub issueのリンクを配置しています。
他にもBash、Python、Node.jsで表現できるものなら表示できるため、工夫次第でClaudeの枠を超えた多彩な情報を表示することが可能です。

導入方法

導入はとても簡単で、Claude Code CLIから/statusline {表示したい情報などの要望}を実行するだけです。

もし気になるstatus line用のスクリプトを手に入れているのであれば、~/.claude/にスクリプトを配置し、Claude Codeに設定をお願いすると簡単です。 実態としては、Claudeのプロジェクト設定のファイル~/.claude/setting.jsonに以下の設定を記載することによってstatus lineを表示していますので、手動でスクリプトを設定することもできます。

{
  "statusLine": {
    "type": "command",
    "command": "~/.claude/{スクリプトのファイル名}",
    "padding": 2
  }
}

status lineの実例を紹介!

status line使ってみたくなったそこのあなた、今日はスパイダープラス開発から4つのstatus lineを紹介です!!
設定用のBashスクリプトも掲載するので、ぜひご自身の環境に合わせて修正して試してみてください!

(1)worktreeの作業でオススメの構成!

エントリーナンバー1〜! まずは私、ピヨコの利用しているstatus line です!

構成はこちらです。

  • 1行目:ワークスペース、Claude Code CLIのバージョン、モデル、remote-controlのON/OFF、通知音のON/OFF
  • 2行目:ブランチ名、変更ステップ数、GitHub issueのリンク、GitHub issueのタイトル
  • 3行目:コンテキストウィンドウの使用状況、5時間のレートリミットの使用状況・リセットまでの時間、7日間のレートリミットの使用状況・リセットまでの時間

こだわりポイントは、現在のディレクトリとブランチ名、変更ステップ数、作業issueが一目で分かるところです。
Claude Codeのworktreeで複数並列で作業している人に特におすすめです!

statusline-command.sh

{owner}, {repo}, {default_branch}はご自身の環境のものに置き換えて利用してください。

#!/bin/sh
input=$(cat)
cwd=$(echo "$input" | jq -r '.workspace.current_dir // .cwd // empty')

# ── Path ──────────────────────────────────────────────────────────────
home="$HOME"
short_cwd=""
if [ -n "$cwd" ]; then
  short_cwd=$(echo "$cwd" | sed "s|^$home|~|")
  short_cwd=$(echo "$short_cwd" | awk -F'/' '{if(NF>2) print "…/"$(NF-1)"/"$NF; else print $0}')
fi

# ── Git ───────────────────────────────────────────────────────────────
branch=""
dirty=""
diff_str=""
if [ -n "$cwd" ] && git -C "$cwd" --no-optional-locks rev-parse --is-inside-work-tree >/dev/null 2>&1; then
  branch=$(git -C "$cwd" --no-optional-locks branch --show-current 2>/dev/null)
  if [ -n "$(git -C "$cwd" --no-optional-locks status --porcelain 2>/dev/null)" ]; then
    dirty="*"
  fi
  # Diff with origin/{default_branch} (+ins / -del)
  if [ -n "$branch" ] && [ "$branch" != "{default_branch}" ]; then
    shortstat=$(git -C "$cwd" diff --shortstat origin/{default_branch}...HEAD 2>/dev/null)
    ins=$(echo "$shortstat" | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+')
    del=$(echo "$shortstat" | grep -oE '[0-9]+ deletion'  | grep -oE '[0-9]+')
    if [ -n "$ins" ] || [ -n "$del" ]; then
      green=$(printf '\033[32m')
      red=$(printf '\033[31m')
      reset=$(printf '\033[0m')
      diff_str="${green}+${ins:-0}${reset}/${red}-${del:-0}${reset}"
    fi
  fi
fi

# ── Issue link ────────────────────────────────────────────────────────
issue_link=""
issue_num=""
if [ -n "$branch" ]; then
  issue_num=$(echo "$branch" | grep -oE '[0-9]+' | head -1)
  if [ -n "$issue_num" ]; then
    issue_url="https://github.com/{owner}/{repo}/issues/${issue_num}"
    issue_link=$(printf '\033]8;;%s\033\\#%s\033]8;;\033\\' "$issue_url" "$issue_num")
  fi
fi

# ── Issue title (cached by issue number) ─────────────────────────────
issue_title=""
if [ -n "$issue_num" ]; then
  cache_file="/tmp/claude-issue-cache-${issue_num}"
  use_cache=0
  if [ -f "$cache_file" ]; then
    cache_age=$(( $(date +%s) - $(stat -f %m "$cache_file" 2>/dev/null || echo 0) ))
    [ "$cache_age" -lt 3600 ] && use_cache=1
  fi
  if [ "$use_cache" -eq 1 ]; then
    issue_title=$(cat "$cache_file" 2>/dev/null)
  else
    # Fetch in background to avoid blocking the statusline
    (gh issue view "$issue_num" --repo {owner}/{repo} \
      --json title --jq '.title' 2>/dev/null | grep . > "$cache_file") &
    issue_title=""
  fi
  # Truncate to 15 chars
  if [ ${#issue_title} -gt 15 ]; then
    issue_title="$(echo "$issue_title" | cut -c1-15)…"
  fi
fi

# ── Context window ────────────────────────────────────────────────────
ctx_str=""
used_pct=$(echo "$input" | jq -r '.context_window.used_percentage // empty')
if [ -n "$used_pct" ]; then
  used_int=$(printf '%.0f' "$used_pct")
  if [ "$used_int" -ge 90 ]; then ctx_level="!!"
  elif [ "$used_int" -ge 75 ]; then ctx_level="!"
  else ctx_level=""
  fi
  ctx_str="${used_int}%${ctx_level}"
fi

# ── Remote-control / Sound ────────────────────────────────────────────
claude_json="$HOME/.claude.json"
settings_file="$HOME/.claude/settings.json"
remote_str=""
sound_str=""
rc="false"
if [ -f "$claude_json" ]; then
  rc=$(jq -r '.remoteControlAtStartup // "false"' "$claude_json" 2>/dev/null)
fi
[ "$rc" = "true" ] && remote_str="rc:ON" || remote_str="rc:off"
if [ -f "$settings_file" ]; then
  voice=$(jq -r '.voiceEnabled // "false"' "$settings_file" 2>/dev/null)
  [ "$voice" = "true" ] && sound_str="snd:ON" || sound_str="snd:off"
fi

# ── Version / Model ───────────────────────────────────────────────────
version_str=$(echo "$input" | jq -r '.version // empty')
model_str=$(echo "$input"   | jq -r '.model.display_name // empty')

# ── Rate limits ───────────────────────────────────────────────────────
rl_str=""
five_pct=$(echo "$input"    | jq -r '.rate_limits.five_hour.used_percentage // empty')
five_reset=$(echo "$input"  | jq -r '.rate_limits.five_hour.resets_at // empty')
seven_pct=$(echo "$input"   | jq -r '.rate_limits.seven_day.used_percentage // empty')
seven_reset=$(echo "$input" | jq -r '.rate_limits.seven_day.resets_at // empty')
if [ -n "$five_pct" ] || [ -n "$seven_pct" ]; then
  now=$(date +%s)
  fmt_remain() {
    secs=$(( $1 - now ))
    [ "$secs" -le 0 ] && echo "now" && return
    h=$(( secs / 3600 ))
    m=$(( (secs % 3600) / 60 ))
    if [ "$h" -ge 24 ]; then
      echo "${h}h"
    elif [ "$h" -gt 0 ]; then
      echo "${h}h${m}m"
    else
      echo "${m}m"
    fi
  }
  bar_color() {
    pct=$1
    if [ "$pct" -ge 76 ]; then printf '\033[31m'
    elif [ "$pct" -ge 51 ]; then printf '\033[33m'
    else printf '\033[32m'
    fi
  }
  reset=$(printf '\033[0m')
  make_bar() {
    pct=$1
    filled=$(( pct / 10 ))
    [ "$filled" -gt 10 ] && filled=10
    color=$(bar_color "$pct")
    bar=""
    i=0
    while [ "$i" -lt "$filled" ]; do bar="${bar}▰"; i=$(( i + 1 )); done
    while [ "$i" -lt 10 ];        do bar="${bar}▱"; i=$(( i + 1 )); done
    printf '%s%s%s' "$color" "$bar" "$reset"
  }
  five_int=$(printf '%.0f' "${five_pct:-0}")
  seven_int=$(printf '%.0f' "${seven_pct:-0}")
  five_remain=$(fmt_remain "$five_reset")
  seven_remain=$(fmt_remain "$seven_reset")
  five_bar=$(make_bar "$five_int")
  seven_bar=$(make_bar "$seven_int")
  # Context bar (built here to reuse make_bar)
  ctx_bar=""
  if [ -n "$ctx_str" ]; then
    ctx_bar=$(make_bar "${used_int:-0}")
  fi
  ctx_part="${ctx_bar:+ctx ${ctx_bar} ${ctx_str}}"
  rl_str="${ctx_part:+${ctx_part}  |  }5h ${five_bar} ${five_int}% ↺${five_remain}  |  7d ${seven_bar} ${seven_int}% ↺${seven_remain}"
fi

# ══ Line 1: directory  version  model  rc  snd ═══════════════════════
green=$(printf '\033[32m')
reset=$(printf '\033[0m')
line1=""
[ -n "$short_cwd" ] && line1="📂 ${short_cwd}"
if [ -n "$version_str" ] || [ -n "$model_str" ]; then
  line1="${line1} | 💥 v${version_str} / ${model_str}"
fi
if [ -n "$remote_str" ] || [ -n "$sound_str" ]; then
  rc_val="${remote_str#rc:}"
  snd_val="${sound_str#snd:}"
  [ "$rc_val"  = "ON" ] && rc_disp="${green}${rc_val}${reset}"   || rc_disp="${rc_val}"
  [ "$snd_val" = "ON" ] && snd_disp="${green}${snd_val}${reset}" || snd_disp="${snd_val}"
  line1="${line1} | 📲 ${rc_disp} / 🔔 ${snd_disp}"
fi

# ══ Line 2: branch  diff  issue  issue_title ═════════════════════════
line2=""
if [ -n "$branch" ]; then
  line2="🌿 ${branch}${dirty}"
  [ -n "$diff_str" ] && line2="${line2}  ${diff_str}"
  if [ -n "$issue_link" ]; then
    line2="${line2}  🎫 ${issue_link}"
    [ -n "$issue_title" ] && line2="${line2}  ${issue_title}"
  fi
fi

# ══ Line 3: rate limits ══════════════════════════════════════════════
line3="${rl_str}"

if [ -n "$line3" ]; then
  printf '%s\n%s\n%s' "$line1" "$line2" "$line3"
else
  printf '%s\n%s' "$line1" "$line2"
fi

(2)シンプル is ベスト so 省エネ

エントリーナンバー2〜!
開発本部CREチームのstatus line です!
お客様と技術的な向き合いを続けているCREチームですが、Claude Code もフル活用して日々問い合わせの調査など行っています!!

構成はこちらです。

  • 1行目:モデル、コンテキストウィンドウ使用状況、5時間のレートリミット使用状況・リセットの時間、7日間のレートリミット使用状況

こだわりポイントは、仕様調査や課題起票を主軸に使っているため、コード変更に関する情報ゼロの省エネ仕様とのこと。
チーム管理のリポジトリ内でスクリプトを共有して設定の手間も省力化しています!

シンプル is ベスト!! まずは簡単に始めてみたい、ごちゃごちゃ画面に表示したくないって人にもオススメなstatus line ですね!!!

statusline-command.sh

#!/bin/bash
input=$(cat)
MODEL=$(echo "$input" | jq -r '.model.display_name // "unknown"')
CTX=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)
FIVE_H=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // 0')
FIVE_H_RESETS=$(echo "$input" | jq -r '.rate_limits.five_hour.resets_at // 0')
FIVE_H_TIME=$(date -r "$FIVE_H_RESETS" "+%H:%M" 2>/dev/null || date -d "@${FIVE_H_RESETS}" "+%H:%M" 2>/dev/null || echo "??:??")
SEVEN_D=$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // 0')
echo "[$MODEL] ctx: ${CTX}%  5h: ${FIVE_H}% (reset ${FIVE_H_TIME})  7d: ${SEVEN_D}%"

(3)おしゃれに演出!アゲてく↑↑status line

エントリーナンバー3〜!
三好さんのstatus line です!!
入社間もない三好さんですが、早速ClaudeなどのAIをフル活用すべく部署内のメンバーと試行錯誤しながら推進を行っているお一人です!

構成はこちらです。

  • 1行目:Ombra Animo、モデル、ワークスペース、コンテキストウィンドウ使用状況

こだわりポイントは、「Ombra Animo」を文字単位でグラデーション(truecolor 24bit)+イタリックで名前そのものを"見せる"演出をしているとのこと! また、[1M] コンテキストモデルを名前で自動検出して、コンテキストウィンドウの使用状況のゲージ最大値を 200K / 1M で自動切替されています。

お、おしゃれ〜!!「Ombra Animo」が何か気になってご本人に聞いたのですが、自分をアゲる↑造語(要約)だと教えてもらいました!! シンプルな中でも自己表現がめっちゃエモいstatus line!こんな表現があったとは…完敗です。私も推しの名前を刻もう。

statusline-command.sh

#!/usr/bin/env bash
# Claude Code statusline: Ombra Animo
#   ☽ Ombra Animo ≪<model>≫ ✦ <workspace>(<branch>) ✦ ❤ [███░░░░░░░]
# HP gauge = context tokens used / context window max (approx by chars/4).
# Reads JSON from stdin, emits a single-line status.

set -u

# ANSI (truecolor) — per-character gradient (light→dark→light)
# Ombra=Bold, Animo=Bold+Italic
CSI=$'\033['
RESET="${CSI}0m"

# Ombra: O(明)→m→b→r→a(暗)
O_O="${CSI}1;38;2;179;229;252m"  # #B3E5FC
O_m="${CSI}1;38;2;130;177;255m"  # #82B1FF
O_b="${CSI}1;38;2;68;138;255m"   # #448AFF
O_r="${CSI}1;38;2;41;121;255m"   # #2979FF
O_a="${CSI}1;38;2;26;35;126m"    # #1A237E

# Animo: A(暗)→n→i→m→o(明)  (italic)
A_A="${CSI}1;3;38;2;26;35;126m"
A_n="${CSI}1;3;38;2;41;121;255m"
A_i="${CSI}1;3;38;2;68;138;255m"
A_m="${CSI}1;3;38;2;130;177;255m"
A_o="${CSI}1;3;38;2;179;229;252m"

input=$(cat)

model=$(printf '%s' "$input" | jq -r '.model.display_name // "?"')
cwd=$(printf '%s' "$input" | jq -r '.workspace.current_dir // ""')
transcript=$(printf '%s' "$input" | jq -r '.transcript_path // ""')

# workspace = basename of cwd (worktree-aware)
ws=$(basename "${cwd:-?}")

# git branch detection + truncation (24 chars + ...)
if [ -n "$cwd" ] && git -C "$cwd" rev-parse --git-dir >/dev/null 2>&1; then
  branch=$(git -C "$cwd" rev-parse --abbrev-ref HEAD 2>/dev/null || echo "—")
else
  branch="—"
fi
if [ "${#branch}" -gt 24 ]; then
  branch="${branch:0:24}..."
fi

# context window max: detect [1M] in model display name, else 200K
if printf '%s' "$model" | grep -q '1M'; then
  ctx_max=1000000
else
  ctx_max=200000
fi

# approximate tokens used = transcript byte size / 4
if [ -n "$transcript" ] && [ -f "$transcript" ]; then
  chars=$(wc -c <&quot;$transcript&quot; 2>/dev/null | tr -d ' ')
  tokens=$(( ${chars:-0} / 4 ))
else
  tokens=0
fi

# 10-block HP gauge
fill=$(( tokens * 10 / ctx_max ))
[ "$fill" -lt 0 ] && fill=0
[ "$fill" -gt 10 ] && fill=10
empty=$(( 10 - fill ))

bar=""
i=0
while [ $i -lt $fill ]; do bar="${bar}█"; i=$((i+1)); done
i=0
while [ $i -lt $empty ]; do bar="${bar}░"; i=$((i+1)); done

printf '☽ %sO%sm%sb%sr%sa%s %sA%sn%si%sm%so%s ≪%s≫ ✦ %s(%s) ✦ ❤ [%s]' \
  "$O_O" "$O_m" "$O_b" "$O_r" "$O_a" "$RESET" \
  "$A_A" "$A_n" "$A_i" "$A_m" "$A_o" "$RESET" \
  "$model" "$ws" "$branch" "$bar"

(4)美しさと利便性を兼ね備えたstatus line

エントリーナンバー4〜!
本田さんのstatus line です!
本田さんといえば、開発環境カスタマイズのプロ!!この記事も見てください。最高です。

techblog.spiderplus.co.jp

構成はこちらです。

  • 1行目:モデル、Claude Code CLIバージョン
  • 2行目:リポジトリ名、ブランチ名
  • 3行目:コンテキストウィンドウの使用状況、5時間のレートリミットの使用状況・リセットまでの時間、7日間のレートリミットの使用状況・リセットまでの時間

こだわりポイントは、リポジトリ名、ブランチ名、Issue名などをクリックでブラウザでページを開ける部分とのことです。 これを実現するために、GitHubのissue名はブランチ名から推測できた場合に表示する。推測できない場合はブランチ名をフォールバックして表示という仕組みも入っています。

ターミナルの背景も相まって美しい〜!!
もはや絵画のキャンバスの上で仕事をしているかのような気持ちになれそうです。
そして何を隠そう、私のstatus line は本田さんリスペクトで作らせてもらっているのですが、本家本元は流石と言わざるを得ないです。

statusline-command.sh

#!/usr/bin/env bash

input=$(cat)

# ─── Powerline separator ───
PL=$(printf '\xee\x82\xb0')  # U+E0B0

# ─── Color helpers ───
h2r() { local h="${1#\#}"; echo "$((16#${h:0:2}));$((16#${h:2:2}));$((16#${h:4:2}))"; }

# ─── OSC 8 hyperlink helper ───
_link() { echo "\033]8;;${1}\007${2}\033]8;;\007"; }

# ─── Segment palette ───
BG_REPO="#1A6E6E"
BG_BRANCH="#5B4A8A"
BG_STATUS="#3E3E3E"
BG_MODEL="#2B4570"
BG_VER="#4A4A4A"
BG_RATE="#2A2A2A"
BG_TOK_GREEN="#2E7D32"
BG_TOK_YELLOW="#F57F17"
BG_TOK_RED="#C62828"

# ─── Segment builder ───
# Tracks previous segment bg to render Powerline separator transitions
_prev=""
_out=""

_sep() {
  local next_bg=$1
  if [ -n "$_prev" ]; then
    _out+="\033[38;2;$(h2r "$_prev")m\033[48;2;$(h2r "$next_bg")m${PL}"
  fi
}

_seg() {  # $1=bg $2=fg $3=text
  _sep "$1"
  _out+="\033[48;2;$(h2r "$1")m\033[38;2;$(h2r "$2")m ${3} "
  _prev="$1"
}

_seg_raw() {  # $1=bg $2=content (may contain ANSI fg codes)
  _sep "$1"
  _out+="\033[48;2;$(h2r "$1")m ${2}\033[48;2;$(h2r "$1")m "
  _prev="$1"
}

_end() {
  if [ -n "$_prev" ]; then
    _out+="\033[0m\033[38;2;$(h2r "$_prev")m${PL}\033[0m"
  fi
  _prev=""
}

# ─── Extract data from JSON ───
MODEL=$(echo "$input" | jq -r '.model.display_name')
PROJECT_DIR=$(echo "$input" | jq -r '.workspace.project_dir')
VER=$(echo "$input" | jq -r '.version')

# Repo: owner/repo from git remote, fallback to dirname
DIR=""
if remote_url=$(git remote get-url origin 2>/dev/null); then
  remote_url="${remote_url%.git}"
  repo="${remote_url##*/}"; owner="${remote_url%/*}"; owner="${owner##*[:/]}"
  [ -n "$owner" ] && [ -n "$repo" ] && DIR="${owner}/${repo}"
fi
[ -z "$DIR" ] && DIR="${PROJECT_DIR##*/}"

# GitHub HTTPS base URL (for OSC 8 hyperlinks)
GH_BASE_URL=""
if [ -n "$owner" ] && [ -n "$repo" ]; then
  case "$remote_url" in
    *github.com*) GH_BASE_URL="https://github.com/${owner}/${repo}" ;;
  esac
fi

# Git branch
BRANCH=""
if git rev-parse --git-dir >/dev/null 2>&1; then
  BRANCH=$(git branch --show-current 2>/dev/null)
fi

# Extract issue number from branch name
# Patterns: feature/123-desc, fix/GH-123, issue-123, 123-desc
ISSUE_NUM=""
if [ -n "$BRANCH" ]; then
  if [[ "$BRANCH" =~ (^|[/-])(GH-)?([0-9]+)([/-]|$) ]]; then
    ISSUE_NUM="${BASH_REMATCH[3]}"
  fi
fi

# Fetch issue title with background caching
ISSUE_TITLE=""
ISSUE_URL=""
if [ -n "$ISSUE_NUM" ] && [ -n "$GH_BASE_URL" ]; then
  ISSUE_URL="${GH_BASE_URL}/issues/${ISSUE_NUM}"
  CACHE_DIR="${TMPDIR:-/tmp}/claude-statusline-cache"
  CACHE_FILE="${CACHE_DIR}/${owner}__${repo}__${ISSUE_NUM}"
  LOCK_FILE="${CACHE_FILE}.lock"
  CACHE_TTL=300

  mkdir -p "$CACHE_DIR" 2>/dev/null

  if [ -f "$CACHE_FILE" ]; then
    ISSUE_TITLE=$(cat "$CACHE_FILE" 2>/dev/null)
    cache_age=$(( $(date +%s) - $(stat -f %m "$CACHE_FILE" 2>/dev/null || echo 0) ))
    if [ "$cache_age" -gt "$CACHE_TTL" ] && [ ! -f "$LOCK_FILE" ]; then
      touch "$LOCK_FILE" 2>/dev/null
      ( gh issue view "$ISSUE_NUM" --repo "${owner}/${repo}" --json title -q '.title' \
          > "$CACHE_FILE" 2>/dev/null; rm -f "$LOCK_FILE" ) &
    fi
  else
    if [ ! -f "$LOCK_FILE" ]; then
      touch "$LOCK_FILE" 2>/dev/null
      ( gh issue view "$ISSUE_NUM" --repo "${owner}/${repo}" --json title -q '.title' \
          > "$CACHE_FILE" 2>/dev/null; rm -f "$LOCK_FILE" ) &
    fi
  fi
fi

# Git status (fg-colored text with bg maintained for segment)
git_stat() {
  local bg_e="\033[48;2;$(h2r "$BG_STATUS")m"
  local a=0 d=0 u=0
  eval "$(git diff HEAD --numstat 2>/dev/null | awk '{ a+=$1; d+=$2 } END { printf "a=%d d=%d",a+0,d+0 }')"
  u=$(git status --short 2>/dev/null | grep -c '^\?\?')
  local r=""
  [ "$a" -gt 0 ] && r+="\033[38;2;0;212;0m${bg_e}+${a}"
  [ "$d" -gt 0 ] && { [ -n "$r" ] && r+=" "; r+="\033[38;2;255;96;96m${bg_e}-${d}"; }
  [ "$u" -gt 0 ] && { [ -n "$r" ] && r+=" "; r+="\033[38;2;212;212;0m${bg_e}?${u}"; }
  echo "$r"
}
GSTAT=$(git_stat)

# Context token usage
CTX_SIZE=$(echo "$input" | jq -r '.context_window.context_window_size')
CTX_USAGE=$(echo "$input" | jq '.context_window.current_usage')
TOK_TEXT="-"
TOK_BG="$BG_TOK_GREEN"

if [ "$CTX_USAGE" != "null" ] && [ "$CTX_SIZE" != "null" ] && [ "$CTX_SIZE" != "0" ]; then
  CUR_TOK=$(echo "$CTX_USAGE" | jq '(.input_tokens // 0) + (.cache_creation_input_tokens // 0) + (.cache_read_input_tokens // 0)')
  pct=$((CUR_TOK * 100 / CTX_SIZE))
  TOK_TEXT=$(printf "%'d" "$CUR_TOK")
  if [ "$pct" -ge 90 ]; then
    TOK_BG="$BG_TOK_RED"
  elif [ "$pct" -ge 70 ]; then
    TOK_BG="$BG_TOK_YELLOW"
  fi
fi

# ═══════════════════════════════════════
#  Line 1: Claude info
# ═══════════════════════════════════════
_seg "$BG_MODEL" "#FFFFFF" "🤖 ${MODEL}"
_seg "$BG_VER" "#B0B0B0" "💥${VER}"
_end
LINE1="$_out"

# ═══════════════════════════════════════
#  Line 2: Git / GitHub info
# ═══════════════════════════════════════
_prev=""
_out=""

if [ -n "$GH_BASE_URL" ]; then
  _seg "$BG_REPO" "#FFFFFF" "🚀 $(_link "$GH_BASE_URL" "$DIR")"
else
  _seg "$BG_REPO" "#FFFFFF" "🚀 ${DIR}"
fi

if [ -n "$ISSUE_TITLE" ] && [ -n "$ISSUE_URL" ]; then
  # Issue detected: show issue title instead of branch name
  _disp="$ISSUE_TITLE"
  [ ${#_disp} -gt 40 ] && _disp="${_disp:0:39}…"
  _seg "$BG_BRANCH" "#FFFFFF" "🎫 $(_link "$ISSUE_URL" "#${ISSUE_NUM}: ${_disp}")"
elif [ -n "$BRANCH" ]; then
  if [ -n "$GH_BASE_URL" ]; then
    _seg "$BG_BRANCH" "#FFFFFF" "⚡$(_link "${GH_BASE_URL}/tree/${BRANCH}" "$BRANCH")"
  else
    _seg "$BG_BRANCH" "#FFFFFF" "⚡${BRANCH}"
  fi
fi

[ -n "$GSTAT" ] && _seg_raw "$BG_STATUS" "$GSTAT"
_end
LINE2="$_out"

# ═══════════════════════════════════════
#  Line 3: Token gauge + Rate limits
# ═══════════════════════════════════════
_prev=""
_out=""

gauge() {
  local pct=$1 width=${2:-10}
  local pct_int=${pct%.*}
  local fx2=$(( pct_int * width * 2 / 100 ))
  local full=$(( fx2 / 2 ))
  local half=$(( fx2 % 2 ))
  local empty=$(( width - full - half ))
  local bar="" i
  for (( i=0; i<full; i++ )); do bar+="█"; done
  [ "$half" -eq 1 ] && bar+="▌"
  for (( i=0; i<empty; i++ )); do bar+="░"; done
  printf "%s" "$bar"
}

remaining_time() {
  local now diff hours mins
  now=$(date +%s); diff=$(($1 - now))
  if [ "$diff" -le 0 ]; then printf "reset soon"; return; fi
  hours=$((diff / 3600)); mins=$(( (diff % 3600) / 60 ))
  [ "$hours" -gt 0 ] && printf "%dh%02dm" "$hours" "$mins" || printf "%dm" "$mins"
}

rate_fg() {
  local p=${1%.*}
  if [ "$p" -ge 90 ]; then printf "\033[38;2;255;82;82m"
  elif [ "$p" -ge 70 ]; then printf "\033[38;2;255;183;77m"
  else printf "\033[38;2;102;187;106m"; fi
}

FIVE_H=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty')
SEVEN_D=$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty')

# Token segment first
_seg "$TOK_BG" "#FFFFFF" "🧠 ${TOK_TEXT}"

# Then rate limits in the same line
if [ -n "$FIVE_H" ] || [ -n "$SEVEN_D" ]; then
  bg_e="\033[48;2;$(h2r "$BG_RATE")m"
  fg_dim="\033[38;2;120;120;120m"
  fg_lbl="\033[38;2;200;200;200m"

  parts=""
  if [ -n "$FIVE_H" ]; then
    p=$(printf '%.0f' "$FIVE_H")
    fc=$(rate_fg "$p")
    g=$(gauge "$p" 10)
    rst_at=$(echo "$input" | jq -r '.rate_limits.five_hour.resets_at // empty')
    rem=""
    [ -n "$rst_at" ] && rem=" ${fg_dim}${bg_e}$(remaining_time "$rst_at")"
    parts+="${fg_lbl}${bg_e}5h ${fc}${bg_e}${g} ${p}%${rem}"
  fi

  if [ -n "$SEVEN_D" ]; then
    p=$(printf '%.0f' "$SEVEN_D")
    fc=$(rate_fg "$p")
    g=$(gauge "$p" 10)
    rst_at=$(echo "$input" | jq -r '.rate_limits.seven_day.resets_at // empty')
    rem=""
    [ -n "$rst_at" ] && rem=" ${fg_dim}${bg_e}$(remaining_time "$rst_at")"
    [ -n "$parts" ] && parts+=" ${fg_dim}${bg_e}│ "
    parts+="${fg_lbl}${bg_e}7d ${fc}${bg_e}${g} ${p}%${rem}"
  fi

  _seg_raw "$BG_RATE" "⏳ ${parts}${bg_e}"
else
  bg_e="\033[48;2;$(h2r "$BG_RATE")m"
  fg_dim="\033[38;2;100;100;100m"
  fg_lbl="\033[38;2;200;200;200m"
  empty_g="░░░░░░░░░░"
  _seg_raw "$BG_RATE" "⏳ ${fg_lbl}${bg_e}5h ${fg_dim}${bg_e}${empty_g} --% ${fg_dim}${bg_e}│ ${fg_lbl}${bg_e}7d ${fg_dim}${bg_e}${empty_g} --%"
fi
_end
LINE3="$_out"

# ─── Output ───
echo -en "\033[0m"
echo -e "$LINE1"
echo -e "$LINE2"
echo -e "$LINE3"

まとめ

さて、今回はClaude Code CLIのstatus lineについて紹介しましたが、いかがでしたか?
Claude Codeは日々アップデートされているので、今後よりstatus lineの機能がパワーアップしていくのではないかと期待してます。

これを機にstatus lineを使ってみようと思った方、ぜひstatus lineに浸かりましょう。
すでに使ってる方、コメントであなたのステキなstatus lineも教えてください。

スパイダープラスでは仲間を募集中です。 スパイダープラスにちょっと興味が出てきたなという方がいらっしゃったらお気軽にご連絡ください。

https://hrmos.co/pages/spiderplus/jobs/0000067/apply