如何在 VPS 設定 Claude Code 狀態列
statusLine 會執行 script,並將 stdout 顯示在提示字元下方。本文示範顯示主機名稱、目錄、git 分支與模型,避免操作錯誤伺服器。
Claude Code 狀態列顯示的內容
Claude Code 狀態列位於提示字元下方,會顯示您撰寫之指令碼的輸出。您可以在 settings.json 中加入 statusLine 區塊,並指定要執行的命令。Claude Code 會執行該命令,將工作階段狀態以 JSON 格式透過標準輸入傳送給命令,然後將命令寫入標準輸出的內容顯示出來。
這就是完整的介面約定。您的指令碼從標準輸入讀取 JSON,並將文字輸出至標準輸出。指令碼會在您的電腦上執行,且其輸出內容不會傳送給模型,因此不會消耗 token。
在只有一個專案的筆記型電腦上,這只是裝飾。在 3 台伺服器上,這是安全防護。每個 Claude Code 工作階段在每個終端機中看起來都一樣,因此 4 個沒有標籤的 SSH 視窗,很容易讓遷移操作執行到錯誤的主機。以主機名稱開頭的狀態列,可以避免這類錯誤。
settings.json 中 statusLine 設定的位置
將設定放在 ~/.claude/settings.json 的使用者設定中,該設定會套用到這台機器上的所有專案。儲存庫內 .claude/settings.json 的專案設定也可以使用,而且會優先套用到該目錄。
{
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.sh"
}
}type 一律為 "command"。command 值會透過 shell 執行,因此可以是指令碼路徑或一般命令。撰寫任何指令碼前,先確認設定連線正常:
{
"statusLine": {
"type": "command",
"command": "hostname -s"
}
}啟動 Claude Code 並傳送一則訊息。提示文字下方的狀態列現在會顯示伺服器的簡短主機名稱。如果仍然空白,問題出在設定或信任對話方塊,而不是你的指令碼。請參閱下方的「為什麼 statusline 會保持空白」。
截至 August 2026,共有 3 個選用鍵。padding 會增加以字元數計算的水平間距,預設值為 0。refreshInterval 會在一般觸發條件之外,每 N 秒重新執行一次命令,最小值為 1。只有當狀態列顯示時鐘,或顯示工作階段閒置時仍會變動的內容時,才需要使用此設定。hideVimModeIndicator 會隱藏內建的 -- INSERT -- 文字;如果你的自訂指令碼已經顯示 vim 模式,便可使用此設定。
statusline script 會接收哪些資料?
不要相信你在任何地方讀到的欄位清單,包括本頁內容。請擷取你的版本實際傳送的物件。撰寫一個用完即丟的 script,將 stdin 儲存至檔案:
cat > ~/.claude/statusline-capture.sh <<'EOF'
#!/bin/bash
cat > /tmp/statusline-input.json
echo "captured"
EOF
chmod +x ~/.claude/statusline-capture.sh讓 statusLine.command 指向該檔案,啟動工作階段,然後傳送一則訊息。狀態列會讀取 captured。現在查看實際收到的內容:
jq . /tmp/statusline-input.json這樣即可取得目前 build 的確切結構。日後更新導致結構變更時,也能隨時重新執行。
截至 2026 年 8 月,文件記載的穩定部分是巢狀物件,而不是扁平鍵值。model 包含 id 和 display_name。workspace 包含 current_dir 和 project_dir:current_dir 是目前的工作階段位置,project_dir 是啟動工作階段的位置;工作目錄在工作階段期間變更後,兩者就會不同。最上層的 cwd 會帶有與 workspace.current_dir 相同的值。context_window 包含 token 計數,以及預先計算的 used_percentage。cost 包含 total_cost_usd 和持續時間計數器。session_id 在整個工作階段期間保持不變,且跨工作階段具有唯一性,因此之後進行快取時相當重要。
以下 3 項規則可讓 script 在 schema 變更後持續正常運作。
部分鍵值不存在,而不是 null。 vim、agent、pr、worktree 和 effort 只會在相應功能啟用時出現。vim mode 關閉時,使用 jq -r 讀取 .vim.mode 會輸出字面字串 null,狀態列則會向讀者顯示 null。請將 // empty 附加至每個 selector,讓缺少的鍵值完全不輸出任何內容。
部分值在早期會是 null。 第一次 API 回應前,context_window.used_percentage 和 context_window.current_usage 會是 null;/compact 之後、下一次呼叫重新填入資料前,current_usage 也會恢復為 null。因此,狀態列上的 context 百分比需要使用 // 0,否則每個工作階段的前幾秒都會讀取 null。在將該數字放到狀態列前,了解context window 實際如何逐步填滿會很有幫助。
git 分支不在 JSON 中。 沒有任何欄位會回報分支。狀態列上的任何分支資訊,都是由你的 script 自行執行 git 取得。
狀態列指令碼:即使資料缺失也能正常運作
這是可直接複製貼上的版本。它會顯示主機名稱、目前工作目錄、git 分支和模型名稱。每個欄位都有預設值,因此即使輸入空的 JSON 物件,仍會產生可用的狀態列。
#!/bin/bash
# ~/.claude/statusline.sh
input=$(cat)
# Read one field. Prints nothing when the key is missing or null.
field() { printf '%s' "$input" | jq -r "$1 // empty" 2>/dev/null; }
HOST=$(hostname -s 2>/dev/null)
[ -z "$HOST" ] && HOST="host"
DIR=$(field '.workspace.current_dir')
[ -z "$DIR" ] && DIR=$(field '.cwd')
[ -z "$DIR" ] && DIR="$PWD"
MODEL=$(field '.model.display_name')
[ -z "$MODEL" ] && MODEL="claude"
SHORT="$DIR"
if [ -n "$HOME" ]; then
case "$DIR" in
"$HOME") SHORT="~" ;;
"$HOME"/*) SHORT="~/${DIR#"$HOME"/}" ;;
esac
fi
BRANCH=""
if git -C "$DIR" rev-parse --git-dir >/dev/null 2>&1; then
BRANCH=$(git -C "$DIR" branch --show-current 2>/dev/null)
[ -z "$BRANCH" ] && BRANCH="detached"
fi
CYAN=$'\033[36m'
YELLOW=$'\033[33m'
DIM=$'\033[2m'
RESET=$'\033[0m'
LINE="${CYAN}${HOST}${RESET} ${SHORT}"
[ -n "$BRANCH" ] && LINE="${LINE} ${YELLOW}${BRANCH}${RESET}"
LINE="${LINE} ${DIM}${MODEL}${RESET}"
printf '%s\n' "$LINE"所有讀取都會經過 field,而 field 會附加 // empty。因此,重新命名或移除的索引鍵會產生空字串,下一行便會提供預設值。目錄會依序從 workspace.current_dir、cwd 回退到 $PWD。分支取自 git -C "$DIR",而不是直接使用 git,因此分支一定會對應狀態列目前顯示的目錄。
儲存後,將它設為可執行:
chmod +x ~/.claude/statusline.sh執行權限不是選用項目。Claude Code 會透過 shell 執行此指令,因此沒有 +x 的指令碼會因 Permission denied 而失敗,不會產生 stdout,狀態列也會保持空白,且不會顯示任何錯誤。
jq 會在命令列解析 JSON,而全新的 Ubuntu server 並未預先安裝它:
sudo apt update && sudo apt install -y jq接著將設定指向此指令碼,使用上方第一個 settings.json 區塊。
先測試指令碼,再信任它
手動執行兩次。第一次使用正常的工作階段物件:
echo '{"model":{"display_name":"Opus"},"workspace":{"current_dir":"/srv/api"},"session_id":"t1"}' | ~/.claude/statusline.sh您會依序取得主機名稱、/srv/api,以及 Opus。不會顯示分支名稱,因為您電腦上的 /srv/api 可能不是 Git 儲存庫。
第二次進行降級測試,這正是許多人會跳過的測試:
echo '{}' | ~/.claude/statusline.sh空物件是結構描述變更可能交給您的最糟情況。該行仍會輸出主機名稱、$PWD 提供的目前目錄,以及模型名稱所在位置的 claude。不會發生當機,也不會輸出 null。通過這項測試的指令碼,即使欄位重新命名也能正常運作,因為對指令碼而言,欄位重新命名與欄位遺失是相同事件。
你應看到的結果
statusline 會在內建 footer 徽章上方獨立顯示一列,不會取代這些徽章。正常運作時,該列包含 4 個部分:以青色顯示的短主機名稱、將家目錄縮寫為 ~ 的工作目錄、工作目錄是 git repository 時以黃色顯示的分支名稱,以及以暗色顯示的模型名稱。整體會接近 web-01 ~/api main Opus,且這 4 個部分各自套用色彩。
工作階段啟動時(包括 resume)、收到新的 assistant 訊息後、/compact 完成後、權限模式變更時、vim mode 切換時,以及設定 refreshInterval tick 後,該列會重新執行你的 script。更新會延遲 300 ms 進行去抖動,因此一連串變更只會執行一次 script。使用 autocomplete、help menu 或 permission prompt 時,該列會隱藏,之後恢復顯示。
主機名稱應放在最前面
當你在多台伺服器上執行 agent 時,終端機是唯一能告訴你目前位置的資訊來源,但終端機顯示的資訊可能不可靠。從 tmux pane 內再建立第二個 ssh 連線時,視窗標題通常仍會保留舊名稱,因為設定標題的 shell 並不知道工作位置已經變更。若將 Claude Code 執行於 VPS 上分離的 tmux 工作階段,隔天重新連接時,畫面上沒有任何資訊能區分建置伺服器與 production 主機。
statusline 則不同,因為它是由 Claude Code 依每個工作階段個別呈現,使用該工作階段持有的資料。它不會從錯誤的 pane 繼承,也不會因未重新整理的 shell 提示字元而保留過時資訊。它顯示的是 agent 寫入檔案所在的主機。
為每台伺服器指定不同顏色,讓你在閱讀內容前就能辨識主機。將以下兩行加入 LINE= 指派之前:
CODE=$(printf '%s' "$HOST" | cksum | cut -d' ' -f1)
HOST_COLOR=$(printf '\033[%dm' "$((31 + CODE % 6))")接著使用 ${HOST_COLOR} 取代 ${CYAN}。cksum 會輸出主機名稱的 checksum,因此相同名稱永遠會對應到 31 到 36 範圍內的同一種顏色,也就是從紅色到青色。將相同的 script 複製到每台主機,系統就會自行標示所在主機。
目錄也基於相同原因值得顯示。/srv/api 與 /srv/api-staging 在 ssh 指令中只差一個按鍵,但實際影響可能造成完全不同的事件。Model 與 branch 是另外兩項值得佔用 statusline 寬度的資訊:model 會告訴你恢復的是哪個工作階段,branch 則會告訴你 agent 是否即將提交至 main。
在小型螢幕上,這些資訊更為重要,因為沒有視窗標題可供參考。若你的環境屬於這種情況,請參閱透過手機操作 Claude Code。
讓腳本保持快速
腳本會在每則 assistant 訊息送出時執行,而 Claude Code 會在收到新更新時取消正在執行的程序。因此,腳本執行過慢時,可能顯示過時的文字,或完全沒有輸出。
每次 jq 呼叫只需幾毫秒。速度變慢的部分是 git:在快取尚未建立的大型 repository 中,git status 需要數百毫秒。上述腳本刻意避免使用 git status,而改用 git branch --show-current;它會讀取 .git/HEAD 並立即返回。
如果加入較耗時的處理,請將結果快取到檔案,並每隔幾秒更新一次。請以工作階段作為檔案的識別依據:
CACHE="/tmp/statusline-$(field '.session_id')"請使用 session_id,不要使用 $$。$$ 是腳本的 process ID,每次執行都不同,因此以它作為快取鍵時永遠無法命中,每次都必須承擔完整成本。session_id 在整個工作階段期間保持穩定,且不同工作階段之間各不相同。因此,兩個分別位於不同 repository 的 Claude Code 工作階段,不會讀取彼此快取的分支名稱。
另外還有一項限制值得注意:tput cols 無法在 statusline 腳本內運作。Claude Code 會擷取輸出,而不是將腳本附加至 terminal,因此沒有可供測量的寬度。Claude Code 會在執行命令前設定 COLUMNS 與 LINES 環境變數;v2.1.153 及後續版本皆支援此行為。因此,需要決定輸出內容長度時,請讀取 $COLUMNS。
statusline 維持空白的原因
完全沒有顯示任何內容。 使用 ls -l ~/.claude/statusline.sh 檢查 execute bit,然後以上方的 mock input 手動執行該 script。如果它在 shell 中能印出一行,但在 Claude Code 中沒有,請先查看 claude --debug。該命令會記錄工作階段第一次執行 statusline 時的 exit code 與 stderr。
debug log 顯示 Status line command skipped: workspace trust not accepted。 statusline 會執行 shell command,因此和 hooks 一樣受到 workspace trust gate 控制。在你接受該目錄的 trust dialog 前,這個 command 不會執行。這在 VPS 上很常見,因為每個新 clone 都是 Claude Code 尚未看過的目錄。請在該目錄中重新啟動 Claude Code,並接受對話框。
所有內容都是空白,而且已設定 disableAllHooks。 settings.json 中的 "disableAllHooks": true 也會停用 statusline,因為兩者使用相同的 shell-execution gate。請移除它,或將其設為 false。
該列輸出 null。 jq selector 取用了不存在或值為 null 的 key,而 jq -r 會將 null 輸出為 4 個字元的 null。文字請加入 // empty,數字請加入 // 0。
編輯 script 後,該列立即變成空白。 任何以 non-zero 結束或沒有輸出的 command,都會使該列變成空白。常見原因是最後一行類似 [ -n "$BRANCH" ] && LINE="...";當 branch 為空時,它會以 1 結束,並使整個 script 使用相同的 exit code。請讓 printf 保持在最後,或加入 exit 0。
Escape code 顯示為列上的純文字,例如 \e]8;;。請使用 printf '%b',不要使用 echo -e。可點選的 OSC 8 連結也需要終端機支援;tmux 或 SSH 可能會移除這些序列,因此在遠端主機上使用純色通常更安全。
該列右側的內容被截斷。 系統通知與 verbose-mode token counter 會從右側共用該列,終端機過窄時就會互相重疊。請縮短輸出。若要取得實際的使用量統計,而不是列上的數字,請參閱 Claude Code 如何計算 token。
FAQ
Claude Code 的 statusline 設定位於何處?
設定位於 settings.json 中,使用 statusLine 區塊,並將 type 設為 "command",以及將 command 設為腳本路徑或 shell 命令。使用者設定位於 ~/.claude/settings.json,會套用到該電腦上的所有專案。專案設定位於儲存庫內的 .claude/settings.json,並優先套用於該目錄。設定會自動重新載入,但變更必須等到下一次更新觸發時才會顯示,例如下一則訊息送出時。
為什麼我的 Claude Code statusline 是空白的?
幾乎所有情況都可歸納為 4 個原因。腳本沒有執行權限,因此 shell 回傳 Permission denied,沒有內容寫入 stdout。尚未接受 workspace trust 對話框,而 claude --debug 記錄了 Status line command skipped: workspace trust not accepted。disableAllHooks 是 true,因此在相同的條件檢查下停用 statusline。或者腳本以非零狀態結束,導致該列變成空白。請先手動測試:echo '{}' | ~/.claude/statusline.sh 必須輸出內容。
statusline 的 JSON 是否包含 git 分支?
不包含。JSON 會攜帶工作階段狀態,例如模型、workspace 目錄、context window 數字及成本。其中沒有任何 git 資訊。statusline 上顯示的分支,來自你自己的腳本呼叫 git branch --show-current。請使用 git -C "$DIR" 從 JSON 傳入目錄,讓分支永遠對應 statusline 目前顯示的目錄。
statusline 會消耗 token 或拖慢工作階段嗎?
不會消耗 token,因為腳本在本機執行,輸出也不會傳送給模型。執行速度則由你負責。該命令會在每則 assistant 訊息後執行,並套用 300 ms debounce;如果新的更新抵達,Claude Code 會取消正在執行的程序。因此,若腳本需要完整的 1 秒,statusline 會顯示過時內容。請避免在大型儲存庫中使用 git status,並將耗時操作的結果快取到以 session_id 為鍵值的檔案中。
如何在每台伺服器上顯示不同的 statusline?
保留一個腳本,讓它讀取機器資訊。上方的腳本會以 hostname -s 作為備援,輸出 $HOSTNAME;因此將同一個檔案複製到每台伺服器後,每台都能正確標示自身,checksum 顏色技巧也會為每個 hostname 指定不同顏色。如果某台伺服器需要不同的版面配置,請在該伺服器上所使用之儲存庫的專案設定中加入 statusLine 區塊,因為對該目錄而言,專案設定會優先於使用者設定。