🎨

Claude Codeのstatuslineをカスタマイズする

に公開

Claude Codeでは、カスタムスクリプトを使ってstatusline(ステータスライン)をカスタマイズできます。この記事では、Git情報やコンテキスト使用量を表示するカスタムstatuslineの設定方法を紹介します。

完成イメージ

設定後のstatuslineはこのように表示されます。

左から順に以下の情報が表示されています:

表示内容 説明
Claude 4 Opus 使用中のモデル名(Opus以外の場合は黄色でハイライト)
14.9K(7%) コンテキスト使用量(トークン数と使用率)
~/S/zenn-contents 現在の作業ディレクトリ(Fish shell風に短縮表示)
main 現在のGitブランチ
+1 -0 未ステージの変更行数(追加/削除)

設定方法

1. statusline.jsを作成

~/.claude/statusline.js にスクリプトを作成します。

~/.claude/statusline.js
#!/usr/bin/env node

const { execSync } = require("child_process");
const os = require("os");

// ANSI color codes
const c = {
  reset: "\x1b[0m",
  dim: "\x1b[2m",
  bold: "\x1b[1m",
  green: "\x1b[32m",
  red: "\x1b[31m",
  yellow: "\x1b[33m",
  cyan: "\x1b[36m",
  magenta: "\x1b[35m",
  blue: "\x1b[34m",
};

// Fish-style path: /Users/username/Sandbox/my-project/node_modules → ~/S/m/node_modules
const fishPath = (fullPath) => {
  const home = os.homedir();
  let p = fullPath;

  if (p.startsWith(home)) {
    p = "~" + p.slice(home.length);
  }

  const parts = p.split("/");
  const lastPart = parts.pop();

  const abbreviated = parts.map((part) => {
    if (part === "~" || part === "") return part;
    return part[0];
  });

  abbreviated.push(lastPart);
  return abbreviated.join("/");
};

// Get git branch
const getGitBranch = (cwd) => {
  try {
    return execSync("git branch --show-current 2>/dev/null", {
      cwd,
      encoding: "utf8",
      stdio: ["pipe", "pipe", "pipe"],
    }).trim() || null;
  } catch {
    return null;
  }
};

// Get git diff stats (unstaged changes)
const getGitDiffStats = (cwd) => {
  try {
    const stats = execSync("git diff --shortstat 2>/dev/null", {
      cwd,
      encoding: "utf8",
      stdio: ["pipe", "pipe", "pipe"],
    }).trim();

    if (!stats) return { added: 0, removed: 0 };

    const addedMatch = stats.match(/(\d+) insertion/);
    const removedMatch = stats.match(/(\d+) deletion/);

    return {
      added: addedMatch ? parseInt(addedMatch[1], 10) : 0,
      removed: removedMatch ? parseInt(removedMatch[1], 10) : 0,
    };
  } catch {
    return { added: 0, removed: 0 };
  }
};

// Format token count
const formatTokens = (tokens) =>
  tokens >= 1000000
    ? `${(tokens / 1000000).toFixed(1)}M`
    : tokens >= 1000
      ? `${(tokens / 1000).toFixed(1)}K`
      : tokens.toString();

// Format context usage with color
const formatContext = (contextWindow) => {
  if (!contextWindow?.context_window_size) {
    return `${c.dim}ctx:--${c.reset}`;
  }

  const size = contextWindow.context_window_size;
  const usage = contextWindow.current_usage;

  let usedTokens = 0;
  if (usage) {
    usedTokens =
      (usage.input_tokens || 0) +
      (usage.cache_creation_input_tokens || 0) +
      (usage.cache_read_input_tokens || 0);
  }

  const percent = Math.round((usedTokens / size) * 100);
  const tokenStr = formatTokens(usedTokens);

  // Color based on usage level
  let color = c.green;
  if (percent >= 80) color = c.red;
  else if (percent >= 60) color = c.yellow;
  else if (percent >= 40) color = c.cyan;

  return `${color}${tokenStr}(${percent}%)${c.reset}`;
};

// Format model name - highlight if NOT opus
const formatModel = (model) => {
  if (!model) return "";

  const name = model.display_name || model.id || "unknown";
  const lowerName = name.toLowerCase();

  // Dim if opus (expected), bold yellow if changed
  if (lowerName.includes("opus")) {
    return `${c.dim}${name}${c.reset}`;
  }
  return `${c.yellow}${c.bold}${name}${c.reset}`;
};

// Build status line
const buildStatusLine = (input) => {
  try {
    const data = JSON.parse(input);

    const cwd = data.workspace?.current_dir || data.cwd || process.cwd();
    const model = data.model;
    const contextWindow = data.context_window;

    // Git info
    const branch = getGitBranch(cwd);
    const gitStats = getGitDiffStats(cwd);

    // Build parts
    const parts = [];

    // Model
    const modelStr = formatModel(model);
    if (modelStr) parts.push(modelStr);

    // Context usage
    parts.push(formatContext(contextWindow));

    // Fish-style directory
    parts.push(`${c.blue}${fishPath(cwd)}${c.reset}`);

    // Git branch and stats
    if (branch) {
      let gitPart = `${c.magenta}${branch}${c.reset}`;

      if (gitStats.added > 0 || gitStats.removed > 0) {
        const statsArr = [];
        if (gitStats.added > 0) {
          statsArr.push(`${c.green}+${gitStats.added}${c.reset}`);
        }
        if (gitStats.removed > 0) {
          statsArr.push(`${c.red}-${gitStats.removed}${c.reset}`);
        }
        gitPart += ` ${statsArr.join(" ")}`;
      }

      parts.push(gitPart);
    }

    return parts.join(" │ ");
  } catch {
    return `${c.dim}statusline error${c.reset}`;
  }
};

// Main
const chunks = [];
process.stdin.on("data", (chunk) => chunks.push(chunk));
process.stdin.on("end", () => console.log(buildStatusLine(chunks.join(""))));

2. 実行権限を付与

chmod +x ~/.claude/statusline.js

3. settings.jsonを設定

~/.claude/settings.json にstatusLineの設定を追加します。

~/.claude/settings.json
{
  "statusLine": {
    "type": "command",
    "command": "~/.claude/statusline.js",
    "padding": 0
  }
}

各機能の解説

コンテキスト使用量の色分け

使用率に応じて色が変わります:

使用率
0-39%
40-59% シアン
60-79%
80%以上

コンテキストが圧迫されてきたら一目でわかるので、/clear/compact のタイミングを判断しやすくなります。

モデル名のハイライト

通常使用するモデル(Opus)はグレーで目立たなく表示し、異なるモデルに切り替わった場合は黄色で強調表示されます。これにより、意図しないモデル変更に気づきやすくなります。

Fish shell風パス短縮

長いパスも短縮して表示されます:

  • /Users/username/Sandbox/my-project~/S/my-project
  • /Users/username/Projects/my-app/src/components~/P/m/s/components

最後のディレクトリ名だけフルで表示し、それ以外は頭文字1文字に短縮されます。

Git情報

  • ブランチ名: マゼンタで表示
  • 追加行数: 緑の +N で表示
  • 削除行数: 赤の -N で表示

未ステージの変更がある場合のみ差分統計が表示されます。

入力データの形式

Claude Codeはstatuslineスクリプトに以下のようなJSONデータを標準入力で渡します:

{
  "workspace": {
    "current_dir": "/Users/username/Projects/my-project"
  },
  "model": {
    "display_name": "Claude 4 Opus",
    "id": "claude-opus-4-5-20251101"
  },
  "context_window": {
    "context_window_size": 200000,
    "current_usage": {
      "input_tokens": 14900,
      "cache_creation_input_tokens": 0,
      "cache_read_input_tokens": 0
    }
  }
}

このデータを解析して、好みの形式でstatuslineを出力できます。

カスタマイズのヒント

  • 区切り文字の を他の文字(|, /, > など)に変更可能
  • 色はANSIカラーコードで自由に変更可能
  • 日時やシステム情報など、任意の情報を追加可能
  • Node.js以外の言語(Python, Bash, Rustなど)でも実装可能

ぜひ自分好みのstatuslineをカスタマイズしてみてください。

Discussion