$ cat ~/writing/2026-09-12-claude-code-statusline-payload.md

Claude Code statusLine 研究:34 個 payload 欄位、更新機制與顯示取捨

DATE2026·09·12
TAGSClaude Code · CLI · Terminal
READING7 min

為了做一個線上的 statusLine 設定頁面 —— 勾欄位、調樣式、即時預覽、匯出一份能交給 coding agent 的規格 —— 有幾件事得先查清楚。

Claude Code 的 statusLine 是一條命令:把 session 狀態序列化成 JSON 從 stdin 餵進來,腳本印什麼就顯示什麼。官方文件列了 34 個欄位組,但接下來的問題沒有答案:哪些欄位真的會動、哪些值得佔用終端那一行、進度條字元在別人的終端顯示得出來嗎、腳本跑一次要多久才不至於拖慢每一則回應。

以下是做到那個頁面能用為止,累積出來的答案。

1. 組裝器

先看成品。statusLine 組裝器 把 45 個欄位、13 種進度條字元、12 套終端配色攤成選項,預覽即時更新 —— 不必改腳本、重開 Claude Code 才看得到結果。本文後面的欄位清單與取捨判準,都可以在上面直接試。四列預覽分別餵不同的用量情境(低用量、常態、偏高、接近上限),用來檢視顏色門檻在實際數值下的表現。本文第 4 節那組進度條對比就是從這裡得到的。

下面是它產生的一種配置,11 個欄位:

StoreOps │ Opus 5 │ ctx ████░ 72% │ 5h 7% │ 7d 67% │ cch 97% │ 1h13m │ 253.4k │ ● 10 │ +1529 -8 │ $9.70

context 的進度條是五格逐格漸層,5h 與 7d 只有數字加門檻換色,其餘用 dim 灰。為什麼這樣分配,是第 4 節的主題。

調完之後按「複製給 Claude」,會得到一份機器可讀的設定規格:欄位順序、每個欄位在 payload 裡的確切路徑、進度條參數、配色的 hex 值,以及四種情境下應該長的樣子。把那段貼回 Claude Code 對話,它就能據此產生對應平台的腳本並寫進設定檔。規格裡逐欄位標明 payload 路徑不是多餘的 —— 第 3 節會說明為什麼消費端不能照單次取樣的結果寫死。

頁面底下另外收錄了 115 個現成的 statusLine 實作,附最後更新時間;不想自己組的話可以直接挑一個,選擇的依據見第 7 節。

2. 更新模型

statusLine 何時重跑,決定了哪些欄位有意義。文件列出的觸發條件:

類別觸發
session 生命週期開始、resume、/compact 結束
狀態變更新的 assistant 訊息、權限模式改變、vim 模式切換、command 設定被改
payload 內的時間點rate-limit 視窗走到 resets_at、熱 cache 走到 expires_at
計時器refreshInterval 到點(選用,單位秒,最小 1)

前兩類是事件驅動,第三類是資料驅動,只有第四類是時間驅動而且預設關閉。更新有 300ms debounce,連續變化會合併成一次;腳本還在跑時有新的觸發進來,in-flight 的那次會被取消。

這個模型有個直接後果:腳本自己算出來的時間值不會自己更新。

時間類欄位沒設 refreshInterval 的行為
rate_limits.*.resets_at視窗真的重置時跳一次
prompt_cache.expires_atcache 過期時跳一次
由上述兩者換算的「還剩多久」不動,停在最後一次事件當下的值

倒數會凍結在最後一則訊息抵達的時刻。文件另外指出主 session 閒置時事件會整個停止,例如等待背景 subagent 期間,這時只有計時器能維持新鮮度。

代價是腳本按固定頻率重跑。設 refreshInterval: 60 而腳本要 600ms,等於每分鐘燒掉 1% 的一個核心 —— 這個數字在第 5 節會有意義。

3. payload 結構與可用性

欄位表看得到有什麼,看不到哪些會出現在你的機器上。這兩件事要分開處理。

取得實際內容

在 command 前面串一個 tee,payload 會在送進腳本的同時落地:

"statusLine": {
  "type": "command",
  "command": "tee /tmp/statusline-last.json | node ~/.claude/statusline.js"
}

下一次觸發後 jq . /tmp/statusline-last.json 就是完整內容。這個做法不必改腳本,取樣完把 tee 段拿掉即可。

也可以寫進腳本內部:

input=$(cat)                                          # 必須在腳本開頭
printf '%s' "$input" > /tmp/statusline-last.json

注意這兩行只在腳本裡有意義。直接貼進互動 shell 的話,cat 會停在那裡等你打字,按 Ctrl+D 結束只會得到一個空檔案。

條件性欄位

文件列 34 個欄位組,但單次 dump 拿不到那麼多。在 Claude Code 2.1.268、WSL2、1M context 模型下的一次取樣只有 17 個 top-level 鍵,缺席的包括 vim.mode(未啟用 vim mode)、agent.name(未帶 --agent)、pr.*(分支無開啟中 PR)、workspace.git_worktree(不在 linked worktree)、rate_limits.spend_limit(未走 gateway)。

欄位可用性分三級:

級別欄位消費端處理
恆存model、cwd、workspace.current_dir、version、session_id、context_window.*、cost.*可直接取用
帳號/方案相關rate_limits.five_hour、seven_day、prompt_cache.*判空後省略整格
情境相關vim.mode、agent.name、pr.*、git_worktree、spend_limit、session_name判空,且不可影響其他欄位排版

取樣結果不能當成規格。任何欄位都要當成可能不存在,包括第一級 —— 那只是這次取樣沒缺而已。

另外,dump 裡有一個 scratchpad_dir,文件的欄位表沒有列。

4. 顯示取捨

單看欄位表看不出取捨。終端寬度是固定的,一行大約 80 到 140 字元,扣掉分隔符後每個欄位的預算是個位數到十幾個字元。決定放什麼,實際上是在四個維度上排序:

維度問題為什麼重要
變動頻率這個值多久變一次不變的欄位是靜態裝飾,佔寬度而不提供資訊
決策價值看到它會不會改變行為statusLine 的功能是讓人在不下指令的情況下做決定
字元成本渲染後佔幾個字元寬度是零和的,長欄位排擠其他欄位
可用性是否條件性存在條件性欄位需要額外的判空邏輯

下面逐類列出欄位與渲染結果,長度以等寬字型計。判斷依上述四個維度,但不逐欄位打分 —— 同一個欄位在不同工作型態下的決策價值差很多,列成固定評分反而誤導。

位置類

欄位渲染長度備註
workspace.current_dir~/work/StoreOps/server 或 server6–40多視窗時的辨識依據
workspace.project_dirStoreOps8多數時候等於 current_dir
workspace.git_worktreefeat-ledger11worktree 之間唯一的區分
workspace.repo.owner/.nameAustinsuyoyo/StoreOps2121 字元換一個幾乎不變的值
workspace.added_dirs+16 dirs8陣列,需自行取長度

cwd 與 workspace.current_dir 值相同,文件建議用後者以配合 project_dir。全路徑在深層目錄下會吃掉半行,取 basename 是常見處理。

模型與 session

欄位渲染長度備註
model.display_nameOpus 56切換模型後容易忘記當前是哪個
session_name重構 ledger不定--name 或 /rename 設定,否則自動生成
effort.levelxhigh3–6low / medium / high / xhigh / max
thinking.enabledthinking8布林,false 時顯示什麼要自行決定
fast_modefast4布林
vim.modeNORMAL6–11唯一高頻變動的狀態欄位;VISUAL LINE 最長
agent.nameexecutor不定--agent 或 agent 設定才存在
version2.1.2687幾乎不變
output_style.namedefault7九成時間是 default
session_idUUID36須截斷才能用
prompt_idUUID36每則訊息都變,但變化不可行動
transcript_path絕對路徑80+長度不適合狀態列

vim.mode 是少數幾個高頻變動又有決策價值的欄位,而且它本身就是 statusLine 的觸發條件之一。prompt_id 相反:每則訊息都變,但變化不帶任何可行動的資訊,是四個維度裡最差的組合。

context window

欄位渲染備註
context_window.used_percentage42%已算好,直接用;對應 /compact 這個明確行動
context_window.remaining_percentage58%與上互補,兩者擇一
context_window.context_window_size1M200000 或 1000000
context_window.total_input_tokens253.4k含 cache 讀取,與百分比資訊重複
context_window.total_output_tokens1.3k
context_window.current_usage.cache_read_input_tokens252.4k最後一次 API 呼叫的量,屬除錯資料
exceeds_200k_tokens200k+見下

exceeds_200k_tokens 的語意是「最近一次回應的 token 總數超過 200k」。在 200k 模型上這是有效的警示;在 1M context 模型上,工作一陣子後它會永遠是 true —— 變動頻率歸零,決策價值歸零。

額度與 cache

欄位渲染備註
rate_limits.five_hour.used_percentage7%0–100
rate_limits.seven_day.used_percentage67%0–100
rate_limits.*.resets_at2h14mepoch 秒;換算成倒數需搭配 refreshInterval,見第 2 節
rate_limits.spend_limit.*21%僅走 gateway 時存在
prompt_cache.hit_ratio97%0–1 浮點數,需乘 100;沒有對應的行動
prompt_cache.warmwarm布林
prompt_cache.ttl1h字串,5m 或 1h
prompt_cache.expires_at42mepoch 秒,同樣需 refreshInterval
prompt_cache.requests/.misses51/0除錯資料

hit_ratio 是 0 到 1 的浮點數,要自行乘 100。prompt_cache 底下另有 cache_write_tokens、recache_tokens_if_cold 等,屬於除錯資料。

成本與版本控制

欄位渲染備註
cost.total_cost_usd$9.70client 端牌價估算,非帳單金額
cost.total_duration_ms73msession 總時長
cost.total_api_duration_ms26m等待 API 的時間;與上者相減是自己花的時間
cost.total_lines_added/_removed+1529 -8
pr.number#42當前分支的開啟中 PR
pr.review_stateapprovedapproved / pending / changes_requested / draft
pr.kindmrGitLab 為 mr,GitHub 缺席

git 的 branch 與工作區狀態不在 payload 裡,要自己呼叫 git。這是唯一會讓腳本 fork 子行程的欄位群,成本見下節。

收斂

把上面的判斷收斂,會落在三組:

高決策價值 + 高變動:used_percentage、five_hour、seven_day、vim.mode。這四個是 statusLine 的核心 —— 它們會讓人在不下指令的情況下改變下一步。

高決策價值 + 低變動:model、session_name、git_worktree、agent.name、pr.review_state。它們幾乎不動,但在多視窗、多 worktree 的情境下是唯一的辨識依據。值得放,但不需要進度條這類強調。

低決策價值:其餘。prompt_id、transcript_path、session_id 連截斷後都不值得;output_style.name、version、context_window_size 是變動頻率近零的靜態值,適合放在別處而不是狀態列。

一個推論:進度條只值得畫在決策門檻明確的欄位上。context 有 /compact 這個明確的行動門檻,額度有「把重活往後排」的門檻。hit_ratio 沒有對應的行動,畫條只是把注意力導向一個看了也不會做什麼的數字。

把 context、5h、7d 都畫成進度條:

StoreOps │ Opus 5 │ ctx ████░ 72% │ 5h ███░░ 64% │ 7d ██░░░ 41% │ cch 88% │ 2h13m │ 253.4k │ +1529 -8 │ $9.70

只留 context 一條,5h 與 7d 用數字加門檻換色:

StoreOps │ Opus 5 │ ctx ████░ 72% │ 5h 64% │ 7d 41% │ cch 88% │ 2h13m │ 253.4k │ +1529 -8 │ $9.70

兩者資料完全相同。三條並排時視覺重量一致,但 ctx 72% 逼近 /compact 門檻、7d 41% 還很寬鬆 —— 眼睛要讀完數字才分得出哪個要緊。只留一條時,進度條本身就成為「這個要注意」的標記,5h 與 7d 退回背景,超過門檻才靠顏色跳出來。

這不是說進度條不好,而是它是強調機制,強調三個等於沒有強調。

5. 渲染成本

statusLine 每次觸發都重跑整支腳本,所以啟動成本是主要開銷,不是腳本邏輯本身。

跨平台的限制先於效能:

  • Claude Code 不提供 node。 安裝文件明載 The installed claude binary does not itself invoke Node,npm 安裝版裝的同樣是原生 binary。「Claude Code 用 Node 寫所以機器上有 node」不成立,node 必須偵測。
  • Git for Windows 不含 jq.exe。 shell + jq 的組合在原生 Windows 無法直接運作。
  • PowerShell 5.1 為 Windows 內建,是唯一無條件存在的 host。

四種 host 的啟動成本,在 WSL2 透過 interop 呼叫 Windows 執行檔測得,含約 20–40ms 的 interop 開銷,各執行 5 次取中位數:

Host啟動完整渲染JSON 解析
PowerShell 5.1(內建)676ms—ConvertFrom-Json
PowerShell 7328ms—ConvertFrom-Json
node84ms110ms內建
Git Bash (MSYS)67ms—無 jq,須自行抓欄位

這組數字不適合當成原生 Windows 的絕對值,但相對順序清楚:PowerShell 5.1 光啟動就是 node 的八倍。同一份 node 腳本在 WSL 上是 28ms,對照 sh + jq 的 26ms,差異在量測誤差內。

另外兩項與成本相關的機制:

  • MSYS 的 fork 約 25ms。 Git Bash 路線下,渲染路徑每個 $(...) 命令替換都是一次 fork。實測一份到處使用命令替換、且分四次呼叫 git 的腳本,在 Linux 上正常而在 Windows/MSYS 上是 1.24 秒;移除渲染路徑的 subshell、git 併成單一 git status --porcelain --branch 後降到 0.22 秒。
  • 路徑展開。 Claude Code 2.1.47 起,command 字串中的 ~ 在 Windows 會被展開,%USERPROFILE% 則不再可靠。因此 "command": "node ~/.claude/statusline.js" 可三平台共用。

終端寬度不能用 tput cols 或語言層的偵測取得 —— Claude Code 捕捉腳本輸出而非連接終端。寬度由環境變數 COLUMNS 和 LINES 傳入。

6. 字元覆蓋率

進度條與分隔符的字元選擇受限於終端字型。直接讀取 Windows 內建字型的 cmap 表:

字型缺少
Consolas▰ ▱ ⣿ ⣀ ▕ ▶ ▷ ✦ ✧ ❯ ⟩ ⟨ ⎇ ⇅ ◐ ◆ ▦ ⟲ ✓
Lucida Console上列再加 ● ━ ╌ ╭ ╮ ╰ ╯ ▸

兩者都沒有全形寬的問題。█ ░ ▓ ■ □ │ ─ 在兩者皆存在,是跨平台最安全的集合。Powerline 的尖角與 capsule 的圓帽屬於 Nerd Font 私有區,與此表無關。

瀏覽器無法用來代測這件事。 想在網頁上預覽終端呈現時,直覺做法是用 canvas measureText 比對字元寬度與豆腐字寬度,但瀏覽器遇到缺字會靜默 fallback 到系統其他字型,canvas 量不到豆腐。document.fonts.check() 同樣不可用 —— 它對未安裝的字型回傳 true,在一台只有 DejaVu Sans Mono 的 Linux 機器上會回報「已安裝 SF Mono、Menlo、Consolas」。字型覆蓋率只能從 cmap 表取得。

7. 生態現況

2026-09-11 查了 115 個 statusLine 專案最後一次更新程式碼的時間:

最後 push專案數
30 天內35
30 天至半年62
半年至一年14
超過一年4

star 數與維護狀態沒有相關性。星數第二高的 CCometixLine(3,458★,Rust)已經六個月沒有更新,而 ccstatusline(12,836★,TypeScript)在查詢前四天還有更新。

這對選型有直接影響:本文列出的欄位裡,rate_limits、prompt_cache、pr.* 都是後期加入 payload 的,停更超過半年的專案多半讀不到。挑現成專案時,「最後一次更新是多久以前」比 star 數更有參考價值。

編譯型(Rust、Go)的優勢是零 runtime 依賴,在沒有 node 的 Windows 上是唯一不需額外安裝的選項;代價是設定必須透過 config schema,欄位組合被鎖定在作者預設的範圍內。腳本型(Node、Python、Shell)反過來,可任意客製但依賴 runtime。前面提到的 CCometixLine 支援 7 個 segment,對照本文的 34 個欄位組,差距就在這裡。

參考資料