0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Windows対応】Claude Codeのステータスラインを設定する方法 — 5つの罠と解決策

0
Posted at

はじめに

Claude Codeを日常的に使っていて、こんな経験はありませんか?

  • 長いセッションで突然「コンテキストが圧縮されました」と表示される
  • 5時間のローリングウィンドウ制限に気づかず作業が中断される
  • セッション終了まで累積コストがわからない

これらの問題を解決するのが、Claude Codeのステータスライン(statusline)機能です。ターミナル下部に常時表示される1行のバーで、コンテキスト使用率・コスト・レート制限を一目で確認できます。

ただし、Windows環境では一筋縄ではいきません。筆者がWindows 11で設定を試みたところ、5つの問題に連続してハマりました。この記事では、その5つの罠と最終的な解決策(Node.jsによる実装)を体系的に解説します。

この記事でわかること:

  • Claude Codeのstatusline機能の仕組みと設定方法
  • Windows環境で遭遇する5つの問題とその原因
  • Node.jsによる最終的な解決策(コピペで使えるコード付き)
  • トラブルシューティングのフロー図

前提条件(2026-02時点):

項目 内容
OS Windows 11
エディタ VSCode 内蔵ターミナル
Claude Code v2.1.42
Node.js インストール済み(Claude Codeの前提条件)

ステータスラインはローカルで実行されるため、APIトークンを消費しません。安心して導入できます。


statusline機能とは?

ステータスラインは、Claude Codeのターミナル下部に表示されるカスタマイズ可能なバーです。設定ファイルでスクリプトを指定すると、Claude Codeがセッション情報をJSON形式でスクリプトに渡し、スクリプトの出力がバーに表示されます。

設定スキーマ

~/.claude/settings.json(ホームディレクトリ直下の.claudeフォルダ)に以下の形式で設定します。

{
  "statusLine": {
    "type": "command",
    "command": "~/.claude/statusline.sh",
    "padding": 0
  }
}
フィールド 必須 説明
type string Yes 常に "command"
command string Yes 実行するコマンドまたはスクリプトパス
padding number No 表示の余白(デフォルト: 0)

この3つ以外のフィールドは公式スキーマに存在しません。 "enabled": true のような非公式フィールドを追加すると、設定全体が無言で無視される可能性があります(後述の問題2参照)。

動作原理

┌──────────────┐    stdin (JSON)    ┌──────────────┐    stdout (text)    ┌──────────────┐
│  Claude Code  │ ────────────────→ │  スクリプト   │ ────────────────→ │  ターミナル   │
│  (本体)       │                    │  (.sh/.js等)  │                    │  (下部バー)   │
└──────────────┘                    └──────────────┘                    └──────────────┘
  1. Claude CodeがJSON(セッション情報)をスクリプトのstdinにパイプする
  2. スクリプトがJSONをパースし、表示テキストをstdoutに出力する
  3. Claude Codeがその出力をターミナル下部に表示する

更新タイミング

トリガー 説明
アシスタント応答後 Claudeが応答するたびに更新
パーミッション変更 ユーザーが権限を許可/拒否した時
Vimモード切り替え Vimモードの有効/無効切り替え時
デバウンス 300ms の遅延(高速な変更をバッチ処理)

stdinで送信されるJSONの主要フィールド

フィールド 説明
model.id / model.display_name モデル識別子と表示名
cwd / workspace.current_dir 現在の作業ディレクトリ
workspace.project_dir プロジェクトルート(起動ディレクトリ)
cost.total_cost_usd セッション累積コスト(USD)
cost.total_duration_ms セッション経過時間(ms)
context_window.used_percentage コンテキストウィンドウ使用率(%、入力トークンベース)
context_window.remaining_percentage 残りコンテキスト(%)
context_window.total_input_tokens 累積入力トークン
context_window.total_output_tokens 累積出力トークン
context_window.context_window_size コンテキストウィンドウ上限(通常200,000)
session_id セッション識別子
transcript_path 会話トランスクリプトのファイルパス
version Claude Codeバージョン

context_window.current_usage は最初のAPI呼び出し前は null になる場合があります。スクリプト内でnullチェックを実装してください。


最終的な完成形

先に結論をお見せします。Node.jsで実装したステータスラインの出力例です。

ブログ記事 | Opus 4.6 | [======              ] 31% 62k/200k | $1.9560 | 0h25m | 27791 tok | 5h: 0.6% | Week: 0.06%

表示項目:

  • 作業ディレクトリ名
  • 使用モデル
  • コンテキストウィンドウ使用率(プログレスバー付き)
  • セッション累積コスト(USD)
  • セッション経過時間
  • 累積トークン数
  • 5時間レートリミット消費率(暫定ロジック)
  • 週間レートリミット消費率(暫定ロジック)

設定はたった2ステップです。

1. スクリプトを配置

# ~/.claude/statusline.js に後述のコードを保存

2. settings.json に設定を追加

{
  "statusLine": {
    "type": "command",
    "command": "node ~/.claude/statusline.js"
  }
}

ここに至るまでに5つの問題を乗り越える必要がありました。順に解説します。


問題1: プロジェクト設定がグローバル設定を上書きする

症状

グローバル設定 ~/.claude/settings.json に statusline を設定したのに、何も表示されない

原因

プロジェクトレベルの .claude/settings.json(プロジェクトルート直下)に、別の statusLine 設定が存在していました。

// プロジェクトの .claude/settings.json に残っていた設定
{
  "statusLine": {
    "type": "command",
    "command": "input=$(cat); cwd=$(echo \"$input\" | jq -r '.workspace.current_dir // .cwd'); ..."
  }
}

このコマンドには jq のパス未指定や Linux固有のオプション(stat -c %Y)が含まれており、Windows環境では動作しませんでした。

重要な発見

プロジェクトレベルの .claude/settings.json は、グローバルの ~/.claude/settings.jsonstatusLine を「マージ」ではなく「完全に置換」する。

つまり、プロジェクト設定に statusLine が存在する限り、グローバル設定は完全に無視されます。

解決策

プロジェクトの .claude/settings.json から statusLine キーを削除し、グローバル設定に一本化しました。

  {
-   "statusLine": {
-     "type": "command",
-     "command": "input=$(cat); ..."
-   },
    "hooks": { ... }
  }

問題2: 公式スキーマにないフィールドが設定を壊す

症状

問題1を修正後もステータスラインが表示されない

原因

グローバル設定に、以前のデバッグ試行で追加された非公式フィールドが残っていました。

{
  "statusLine": {
    "type": "command",
    "command": "bash ~/.claude/statusline.sh",
    "enabled": true
  }
}

"enabled": true公式スキーマに存在しないフィールドです。公式スキーマが受け付けるのは typecommandpadding の3つのみ。

不明なフィールドが存在すると、Claude Code が statusLine 設定全体を無言で拒否する可能性があります。エラーメッセージは一切表示されません。

解決策

enabled フィールドを削除しました。

{
  "statusLine": {
    "type": "command",
    "command": "bash ~/.claude/statusline.sh"
  }
}

問題3: Windowsでbashスクリプトが動かない

症状

設定スキーマの問題を解消してもステータスラインが表示されない

二分探索的デバッグ

テスト1: インラインecho

"command": "echo 'STATUS LINE TEST'"

表示された :white_check_mark:

テスト2: bashスクリプト呼び出し

"command": "bash ~/.claude/statusline.sh"

表示されない :x:

原因

Claude Codeは Windows上で statusLine コマンドを bash ではなく、cmd.exe または別のシェルで実行している。

echocmd.exe の内蔵コマンドとして動作しますが、bash はPATH上に存在しても外部プログラムであり、statusLineの実行環境からは解決できませんでした。

┌─────────────────────────────────────────────────────────────┐
│  Claude Code statusLine 実行環境 (Windows)                  │
│                                                             │
│  ✅ echo, set, dir  → cmd.exe 内蔵コマンド → 動作する       │
│  ❌ bash, sh        → 外部プログラム → 解決できない         │
│  ✅ node, powershell → フルパスまたは特定条件で動作          │
└─────────────────────────────────────────────────────────────┘

公式ドキュメントにも以下のように記載されています(2026-02時点)。

These examples use Bash scripts, which work on macOS and Linux. On Windows, you can run Bash scripts through WSL (Windows Subsystem for Linux) or rewrite them in PowerShell.
Claude Code 公式ドキュメント: Customize your status line

解決策

bashを放棄し、PowerShellに切り替えました。


問題4: PowerShell -File でstdinが空になる

症状

PowerShellに切り替えてテスト。

テスト3: PowerShellインラインコマンド

"command": "powershell -NoProfile -Command Write-Host 'PS TEST' -NoNewline"

表示された :white_check_mark:

テスト4: PowerShellスクリプトファイル

"command": "powershell -NoProfile -ExecutionPolicy Bypass -File ~/.claude/statusline.ps1"

表示されるが、全データが空/ゼロ :warning:

原因

PowerShell の -File フラグと -Command フラグでは、stdinの取り扱いが異なります

フラグ stdinの挙動
-Command stdinをインタラクティブに読み取り可能
-File stdinのパイピング方式が異なり、[Console]::In.ReadToEnd() でデータを正しく受信できない

デバッグ用にファイル出力を追加して確認したところ、受信データはでした。

解決策

-File-Command に切り替え、スクリプトをdot-sourceする方法に変更しました。しかし、ここで次の問題が発覚します。


問題5: CP932/UTF-8 エンコーディング問題(致命的)

症状

-Command モードに切り替えてstdinの読み取りは成功。しかし ConvertFrom-Json でエスケープシーケンスエラーが発生。

原因

日本語 Windows のデフォルトコンソールコードページは CP932(Shift-JIS) です。Claude CodeがUTF-8でJSONを送信すると、WindowsのコンソールサブシステムがこれをCP932として解釈します。

┌──────────────┐    UTF-8 JSON    ┌──────────────┐    CP932 解釈    ┌──────────────┐
│  Claude Code  │ ──────────────→ │  Windows      │ ──────────────→ │  PowerShell   │
│  (UTF-8出力)  │                 │  Console API  │                 │  (CP932入力)  │
└──────────────┘                 └──────────────┘                 └──────────────┘
                                                                        ↓
                                                                  ConvertFrom-Json
                                                                        ↓
                                                                  ❌ パースエラー

文字化けの実例:

デバッグ出力で確認した結果、以下のように日本語パスが破壊されていました。

元データ(UTF-8):
"cwd": "...\\デスクトップ\\Claude Code\\ブログ記事"

PowerShell 経由の受信データ(CP932 解釈):
"cwd": "...\\繝・せ繧ッ繝医ャ繝予\\Claude Code\\繝悶Ο繧ー險倅コ・"

問題は cwd の日本語だけではありません。JSON全体がバイト列として破壊されるため、model.display_name 等の日本語を含まないフィールドも取得不能になります。

試みた回避策(すべて失敗)

  1. [Console]::OutputEncoding = [Text.Encoding]::UTF8 → 効果なし(出力側のみ)
  2. $OutputEncoding = [Text.Encoding]::UTF8 → 効果なし
  3. chcp 65001 をスクリプト冒頭で実行 → statuslineのコンテキストでは効果なし

結論

日本語パスを含むWindows環境では、PowerShellによるstatusline実装は根本的に不可能。

PowerShellを完全に放棄し、Node.jsに移行しました。


Node.jsによる最終実装

Node.jsを選定した理由

理由 説明
Claude Codeの前提条件 Claude Code自体がNode.jsで動作するため、必ずインストール済み
UTF-8ネイティブ 内部的にUTF-8を使用。CP932の影響を受けない
JSON組み込み JSON.parse() が標準搭載。jq のような外部依存なし
Buffer API Buffer.concat(chunks).toString('utf8') で確実にUTF-8デコード
クロスプラットフォーム macOS/Linuxでもそのまま動作

設定(~/.claude/settings.json

{
  "statusLine": {
    "type": "command",
    "command": "node ~/.claude/statusline.js"
  }
}

statusline.js 全文

以下のコードを ~/.claude/statusline.js に保存してください。

レートリミットの計算ロジック(定数値・計算式)は暫定的なものです。Anthropicは正確な制限値や内部の計算方法を公開していないため(2026-02時点)、実際の使用状況に合わせてご自身で調整してください。

// ============================================================
// Rate Limit Settings (Max 5x plan)
// ⚠️ 以下の定数値・計算ロジックは暫定値です
// Anthropicは正確な制限値を公開していないため、
// 実際の使用状況に合わせて調整してください
// ============================================================
const PLAN = 'Max 5x';
const LIMIT_5H_TOKENS = 5_000_000;    // 5時間ローリングウィンドウ (暫定値)
const LIMIT_WEEKLY_TOKENS = 45_000_000; // 週間上限 (暫定値)
// ============================================================

// --- stdin 読み取り ---
// Claude Code が JSON をパイプで送信する
// Buffer で受け取り、最後に UTF-8 でデコードすることで
// Windows の CP932 エンコーディング問題を回避
const chunks = [];
process.stdin.on('data', c => chunks.push(c));
process.stdin.on('end', () => {
  try {
    // Buffer.concat → toString('utf8') で確実に UTF-8 デコード
    const json = JSON.parse(Buffer.concat(chunks).toString('utf8'));

    // --- モデル名 ---
    const model = json.model?.display_name || 'N/A';

    // --- コンテキストウィンドウ使用率 ---
    const used = Math.round(json.context_window?.used_percentage || 0);
    const totalIn = json.context_window?.total_input_tokens || 0;
    const totalOut = json.context_window?.total_output_tokens || 0;
    const tokens = totalIn + totalOut;

    // --- コスト(API提供値を使用) ---
    const cost = json.cost?.total_cost_usd
      ? json.cost.total_cost_usd.toFixed(4)
      : '0.0000';

    // --- コンテキストウィンドウのトークン数(k表記) ---
    const ctxSize = json.context_window?.context_window_size || 200000;
    const ctxUsed = Math.round(ctxSize * used / 100);
    const fmtK = n => n >= 1000 ? Math.round(n / 1000) + 'k' : String(n);

    // --- プログレスバー(20文字幅) ---
    const filled = Math.floor(used * 20 / 100);
    const bar = '[' + '='.repeat(filled) + ' '.repeat(20 - filled) + ']';

    // --- レートリミット推定(5時間ローリングウィンドウ) ---
    // 注意: セッション単位の累積値であり、5時間全体ではない
    const rate5h = (tokens / LIMIT_5H_TOKENS * 100).toFixed(1);

    // --- レートリミット推定(週間) ---
    const rateWeek = (tokens / LIMIT_WEEKLY_TOKENS * 100).toFixed(2);

    // --- ディレクトリ名(末尾のフォルダ名のみ) ---
    const cwd = json.workspace?.current_dir || json.cwd || 'N/A';
    const shortDir = cwd.split(/[/\\]/).pop();

    // --- セッション経過時間 ---
    let duration = 'N/A';
    const durationMs = json.cost?.total_duration_ms;
    if (durationMs) {
      const sec = Math.floor(durationMs / 1000);
      const h = Math.floor(sec / 3600);
      const m = Math.floor((sec % 3600) / 60);
      duration = `${h}h${m}m`;
    }

    // --- 出力 ---
    process.stdout.write(
      `${shortDir} | ${model} | ${bar} ${used}% ${fmtK(ctxUsed)}/${fmtK(ctxSize)} | $${cost} | ${duration} | ${tokens} tok | 5h: ${rate5h}% | Week: ${rateWeek}%`
    );
  } catch (e) {
    process.stdout.write('statusline error: ' + e.message);
  }
});

各セクションの解説

stdin読み取り部分

const chunks = [];
process.stdin.on('data', c => chunks.push(c));
process.stdin.on('end', () => {
  const json = JSON.parse(Buffer.concat(chunks).toString('utf8'));
  // ...
});

Node.jsの process.stdin はBufferオブジェクトとしてデータを受け取ります。Buffer.concat() で全チャンクを結合し、toString('utf8') で明示的にUTF-8デコードすることで、Windowsの CP932エンコーディング問題を完全に回避します。

プログレスバー

const filled = Math.floor(used * 20 / 100);
const bar = '[' + '='.repeat(filled) + ' '.repeat(20 - filled) + ']';

20文字幅のプログレスバーを生成します。使用率31%の場合、[====== ] のように表示されます。

セッション経過時間

const durationMs = json.cost?.total_duration_ms;
if (durationMs) {
  const sec = Math.floor(durationMs / 1000);
  const h = Math.floor(sec / 3600);
  const m = Math.floor((sec % 3600) / 60);
  duration = `${h}h${m}m`;
}

cost.total_duration_ms(セッション開始からの経過ミリ秒)を時間と分に変換します。

レートリミット推定

const rate5h = (tokens / LIMIT_5H_TOKENS * 100).toFixed(1);
const rateWeek = (tokens / LIMIT_WEEKLY_TOKENS * 100).toFixed(2);

レートリミットの計算ロジックは暫定的なものです。Anthropicはプランごとの正確な制限値や計算方法を公開していません(2026-02時点)。定数値(LIMIT_5H_TOKENS等)は推定であり、tokens(input + output)を等価扱いしている点も実際の課金比率(input:output = 1:5)とは異なります。ここでの値はセッション単位の累積値であり、5時間ローリングウィンドウ全体の使用量ではありません。実際の使用状況に合わせて調整してください。


トラブルシューティング

ステータスラインが正しく動作しない場合、以下のフローで原因を特定できます。

ステータスラインが表示されない
│
├─ settings.json を確認
│  ├─ statusLine キーが存在するか?
│  │  └─ No → 追加する
│  │
│  ├─ プロジェクトの .claude/settings.json に
│  │  statusLine が存在するか?
│  │  └─ Yes → グローバル設定が上書きされている → 削除
│  │
│  └─ type, command 以外のフィールドがあるか?
│     └─ Yes → 削除(enabled 等は公式スキーマにない)
│
├─ コマンドが実行されるか確認
│  ├─ "command": "echo 'TEST'" で表示される?
│  │  ├─ No → Claude Code 自体の問題の可能性
│  │  └─ Yes → スクリプト実行の問題 ↓
│  │
│  ├─ Windows で bash を使おうとしていないか?
│  │  └─ Yes → Node.js に切り替え
│  │
│  └─ PowerShell -File を使っていないか?
│     └─ Yes → Node.js に移行を推奨
│
├─ 表示されるが値がすべて 0 / 空
│  ├─ stdin のデータが届いていない
│  │  └─ デバッグファイル出力で確認
│  │
│  └─ 日本語パスによるエンコーディング問題
│     └─ Node.js に移行(Buffer.concat + toString('utf8'))
│
└─ Node.js 実装で解決
   └─ "command": "node ~/.claude/statusline.js"

よくある質問

Q: /statusline コマンドで自動生成できないの?

A: Claude Codeには /statusline コマンドがあり、自然言語でstatuslineの生成を指示できます。ただし、Windows環境では生成されたbashスクリプトがそのまま動作しない場合があります。その場合は本記事のNode.js実装をお使いください。

Q: macOS/Linuxでもこのスクリプトは使える?

A: はい。Node.jsはクロスプラットフォームで動作するため、同じ statusline.js をmacOS/Linuxでもそのまま使用できます。

Q: disableAllHooks を設定するとstatuslineも消える?

A: はい。settings.json"disableAllHooks": true を設定すると、ステータスラインも無効化されます(2026-02時点)。


まとめ

Windows環境でClaude Codeのステータスラインを設定する際に遭遇した5つの問題と、その解決策をまとめます。

# 問題 原因 解決策
1 表示されない プロジェクト設定がグローバルを上書き プロジェクトからstatusLineを削除
2 表示されない 非公式フィールド(enabled等) 公式スキーマの3フィールドのみ使用
3 表示されない Windowsでbashが動作しない Node.jsに切り替え
4 値がすべて0 PowerShell -File でstdinが空 Node.jsに切り替え
5 値がすべて0 CP932/UTF-8エンコーディング不整合 Node.jsのBuffer APIで解決

教訓

  1. WindowsでClaude Codeのカスタムスクリプトを書くならNode.jsが最適解 — Claude Codeの前提条件として必ず存在し、UTF-8をネイティブに扱える
  2. 設定のスコープを理解する — プロジェクトレベル設定はグローバル設定を「マージ」ではなく「置換」する
  3. 公式スキーマに忠実であること — 非公式フィールドはサイレントに設定を無効化するリスクがある
  4. 日本語Windows環境の特殊性 — CP932がデフォルトのコードページであり、外部プロセスとのstdin/stdoutパイピングでエンコーディング問題が発生しやすい

参考リンク


検証日: 2026-02-14 / Claude Code v2.1.42 / Windows 11 Home

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?