Paano Mag-set Up ng Claude Code Statusline sa VPS
I-configure ang statusLine para ipakita ang hostname, directory, git branch, at model sa ilalim ng prompt, para tama ang server na nae-edit mo.
Ipinapakita ng Claude Code statusline
Ang Claude Code statusline ay isang hanay ng teksto sa ilalim ng prompt na nagpapakita ng output ng script na iyong isinusulat. Magdagdag ng statusLine block sa settings.json at ituro ito sa isang command. Pinapatakbo ng Claude Code ang command na iyon, ipinapadala rito ang session state bilang JSON sa standard input, at ipinapakita ang anumang isinusulat ng command sa standard output.
Iyan ang buong contract. Binabasa ng script mo ang JSON mula sa stdin at nagpi-print ng text sa stdout. Tumatakbo ito sa machine mo, at walang ipinapadala sa model mula sa mga inilalabas nito, kaya walang nagagamit na tokens.
Sa laptop na may isang project, dekorasyon lamang ito. Sa tatlong server, nagsisilbi itong safety rail. Pare-pareho ang hitsura ng bawat Claude Code session sa bawat terminal, kaya ang apat na SSH window na walang label ay maaaring magdulot ng migration sa maling machine. Kapag hostname ang simula ng statusline, naiiwasan ang ganitong uri ng pagkakamali.
Kung saan nakalagay ang statusLine setting sa settings.json
Ilagay ito sa user settings sa ~/.claude/settings.json, na nalalapat sa bawat project sa machine na iyon. Gumagana rin ang project settings sa .claude/settings.json sa loob ng isang repository, at inuuna ang mga iyon para sa directory na iyon.
{
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.sh"
}
}Ang type ay palaging "command". Tumatakbo ang value ng command sa isang shell, kaya maaari itong script path o simpleng command. Patunayan munang gumagana ang wiring bago gumawa ng script:
{
"statusLine": {
"type": "command",
"command": "hostname -s"
}
}Simulan ang Claude Code at magpadala ng isang message. Ipinapakita na ngayon ng bar sa ilalim ng prompt ang maikling hostname ng server. Kung nananatili itong walang laman, ang problema ay nasa setting o sa trust dialog, hindi sa script mo. Basahin ang “Bakit nananatiling blangko ang statusline” sa ibaba.
May tatlong optional key hanggang Agosto 2026. Ang padding ay nagdaragdag ng horizontal spacing ayon sa bilang ng characters at ang default nito ay 0. Inuulit ng refreshInterval ang command bawat N segundo bukod sa mga normal na trigger, na may minimum na 1. Gamitin lamang ito kapag may clock o ibang value sa line na nagbabago habang idle ang session. Pinipigilan ng hideVimModeIndicator ang built-in na text na -- INSERT -- kapag sarili mong script ang nagre-render ng vim mode.
Anong data ang natatanggap ng statusline script?
Huwag magtiwala sa field list na nabasa mo kahit saan, kabilang na ang page na ito. Kunin ang aktuwal na object na ipinapadala ng iyong version. Gumawa ng pansamantalang script na nagse-save ng stdin sa isang file:
cat > ~/.claude/statusline-capture.sh <<'EOF'
#!/bin/bash
cat > /tmp/statusline-input.json
echo "captured"
EOF
chmod +x ~/.claude/statusline-capture.shIturo ang statusLine.command sa file na iyon, magsimula ng session, at magpadala ng isang message. Binabasa ng bar ang captured. Pagkatapos, tingnan kung ano ang natanggap:
jq . /tmp/statusline-input.jsonNasa iyo na ang eksaktong structure para sa iyong build, at maaari mo itong ulitin anumang oras na may mabago sa update.
Ang mga stable na bahagi, ayon sa dokumentasyon noong August 2026, ay mga nested object sa halip na flat key. Naglalaman ang model ng id at display_name. Naglalaman ang workspace ng current_dir at project_dir: ang current_dir ang kasalukuyang lokasyon ng session, habang ang project_dir ang lokasyon kung saan ito inilunsad. Magkaiba ang dalawang ito kapag nagbago ang working directory habang tumatakbo ang session. Ang top-level na cwd ay naglalaman ng parehong value gaya ng workspace.current_dir. Naglalaman ang context_window ng token count at ng pre-calculated na used_percentage. Naglalaman ang cost ng total_cost_usd at mga duration counter. Stable ang session_id sa buong buhay ng session at unique sa bawat session, na mahalaga para sa caching sa susunod.
Tatlong rule ang makatutulong para manatiling gumagana ang script kapag nagbago ang schema.
May mga key na absent, hindi null. Lumilitaw lamang ang vim, agent, pr, worktree at effort kapag aktibo ang katumbas na feature. Kapag binasa ang .vim.mode gamit ang jq -r habang naka-off ang vim mode, ipi-print nito ang literal na string na null, kaya makikita ng reader sa bar ang null. Idagdag ang // empty sa bawat selector para walang mai-print kapag missing ang key.
May mga value na null sa simula. Null ang context_window.used_percentage at context_window.current_usage bago ang unang API response, at bumabalik sa null ang current_usage pagkatapos ng /compact hanggang sa mapunan itong muli ng susunod na call. Kaya ang context percentage sa bar ay nangangailangan ng // 0; kung hindi, babasahin nito ang null sa unang ilang segundo ng bawat session. Bago mo ilagay ang numerong iyon sa bar, makatutulong na malaman kung paano aktuwal na napupuno ang context window.
Wala sa JSON ang git branch. Walang field na nag-uulat nito. Anumang branch na nasa bar ay nagmumula sa script na mismong nagpapatakbo ng git.
Isang statusline script na nagde-degrade sa halip na mag-crash
Ito ang copy-paste na bersyon. Ipinapakita nito ang hostname, working directory, git branch, at model name. May fallback ang bawat field, kaya kahit walang laman ang JSON object ay makakagawa pa rin ito ng kapaki-pakinabang na linya.
#!/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"Ang bawat pagbasa ay dumadaan sa field, na nagdaragdag ng // empty. Dahil dito, ang pinalitan o inalis na key ay nagiging empty string, at ang susunod na linya ang nagbibigay ng default. Ang directory ay gumagamit ng fallback mula workspace.current_dir, patungo sa cwd, at pagkatapos ay $PWD. Kinukuha ang branch mula sa git -C "$DIR" sa halip na sa simpleng git, kaya palaging tumutugma ang branch sa directory na ipinapakita ng bar.
I-save ito, pagkatapos ay gawin itong executable:
chmod +x ~/.claude/statusline.shHindi optional ang execute bit. Pinapatakbo ni Claude Code ang command sa pamamagitan ng shell, kaya ang script na walang +x ay nagfa-fail na may Permission denied, walang nilalabas na stdout, at nananatiling blanko ang row nang walang nakikitang error.
Ang jq ay nagpa-parse ng JSON sa command line at hindi ito naka-install sa bagong Ubuntu server:
sudo apt update && sudo apt install -y jqIturo ang setting sa script gamit ang unang settings.json block sa itaas.
Subukan ang script bago ito pagkatiwalaan
Patakbuhin ito nang dalawang beses nang mano-mano. Una, gamit ang normal na session object:
echo '{"model":{"display_name":"Opus"},"workspace":{"current_dir":"/srv/api"},"session_id":"t1"}' | ~/.claude/statusline.shMakukuha mo ang hostname, kasunod ang /srv/api, at pagkatapos ang Opus. Walang branch na lalabas dahil malamang na hindi git repository ang /srv/api sa machine mo.
Ikalawa, ang degradation test, na kadalasang nilalaktawan ng mga tao:
echo '{}' | ~/.claude/statusline.shAng empty object ang pinakamasamang sitwasyong maaaring ibigay sa iyo ng pagbabago sa schema. Lalabas pa rin ang linya: ang hostname, ang kasalukuyang directory mula sa $PWD, at ang salitang claude kung saan dapat ilagay ang model name. Walang magka-crash at walang magpi-print ng null. Makakalampas sa test na ito ang script kapag may field na pinalitan ng pangalan, dahil para sa script mo, pareho lang ang renamed field at missing field.
Ang dapat mong makita
Lumilitaw ang statusline sa sarili nitong row sa itaas ng mga built-in footer badge at hindi nito pinapalitan ang mga ito. Sa gumaganang setup, isang row ito: ang pinaikling hostname na cyan, kasunod ang working directory na pinaikli ang home directory bilang ~, pagkatapos ang branch name na yellow kapag nasa loob ng git repository ang directory, at ang pangalan ng model na dimmed. Halos ganito ang itsura: web-01 ~/api main Opus, na may kulay ang apat na bahaging iyon.
Muling pinapatakbo ng row ang script kapag nagsisimula ang session, pati kapag nagre-resume, kapag may bagong assistant message, pagkatapos matapos ang /compact, kapag nagbago ang permission mode, kapag nag-toggle ang vim mode, at sa bawat refreshInterval tick kung nagtakda ka nito. May debounce na 300 ms ang mga update, kaya isang beses lamang pinapatakbo ang script kapag sunod-sunod ang mga pagbabago. Nagtatago ang bar habang ginagamit ang autocomplete, help menu, at permission prompt, at muling lumilitaw pagkatapos.
Bakit dapat mauna ang hostname
Kapag nagpapatakbo ka ng agents sa higit sa isang server, ang terminal lang ang nagsasabi kung nasaan ka, at nagkakamali ang mga terminal. Magbukas ng ikalawang ssh connection mula sa loob ng tmux pane, at madalas ay nananatili ang lumang pangalan sa window title dahil itinakda ito ng shell na hindi nalaman na lumipat ito. Iwan ang Claude Code na tumatakbo sa isang detached tmux session sa isang VPS at mag-reattach makalipas ang isang araw, at walang nasa screen na naghihiwalay sa build server mula sa production box.
Iba ang statusline dahil Claude Code mismo ang nagre-render nito para sa bawat session, gamit ang data na hawak ng session na iyon. Hindi ito maaaring mamana mula sa maling pane o maiwan na luma dahil sa shell prompt na hindi nag-refresh. Ang ipinapakita nito ay ang box kung saan nagsusulat ng files ang agent.
Bigyan ng sariling kulay ang bawat server para makilala mo ito bago mo basahin. Dalawang linya ang ilagay bago ang LINE= assignment:
CODE=$(printf '%s' "$HOST" | cksum | cut -d' ' -f1)
HOST_COLOR=$(printf '\033[%dm' "$((31 + CODE % 6))")Pagkatapos, gamitin ang ${HOST_COLOR} kapalit ng ${CYAN}. Ang cksum ay nagpi-print ng checksum ng hostname, kaya palaging pareho ang kulay na itinatapat sa isang partikular na pangalan sa range na 31 hanggang 36, mula red hanggang cyan. Kopyahin ang parehong script sa bawat box at bawat isa ay maglalabel sa sarili nito.
Mahalaga rin ang directory sa parehong dahilan. Ang /srv/api at /srv/api-staging ay isang keystroke lang ang pagitan sa isang ssh command, pero malaki ang epekto ng pagkakaiba sa panahon ng isang buong incident. Ang model at branch ang dalawa pang sulit isama sa limitadong lapad: sinasabi ng model kung aling session ang ni-resume mo, at sinasabi ng branch kung magko-commit na ang agent sa main.
Mas kapansin-pansin ang lahat ng ito sa maliit na screen dahil wala kang window title na mapagkukunan ng impormasyon. Kung ganoon ang setup mo, tingnan ang pagpapatakbo ng Claude Code mula sa phone.
Panatilihing mabilis ang script
Tumatakbo ang script mo sa bawat mensahe ng assistant, at kino-cancel ng Claude Code ang kasalukuyang tumatakbong proseso kapag may bagong update. Kaya kapag mabagal ang script, lumalabas ang lumang text o walang text.
Ilang millisecond lang ang gastos sa bawat jq call. Ang bahaging nagiging mabagal ay ang git: ang git status sa malaking repository na cold ang cache ay maaaring umabot ng daan-daang millisecond. Sinasadyang iwasan ng script sa itaas ang git status at ginagamit nito ang git branch --show-current, na nagbabasa ng .git/HEAD at agad nagbabalik ng resulta.
Kung magdaragdag ka ng mas mabigat na operasyon, i-cache ito sa isang file at i-refresh bawat ilang segundo. Gamitin ang session bilang key ng file:
CACHE="/tmp/statusline-$(field '.session_id')"Gamitin ang session_id, hindi ang $$. Ang $$ ang process ID ng script mo, at naiiba ito sa bawat invocation. Kaya hindi kailanman nagkakaroon ng cache hit kapag ito ang ginamit na key, at binabayaran mo ang buong gastos sa bawat pagkakataon. Stable ang session_id sa buong session at naiiba ito sa bawat session. Dahil dito, hindi mababasa ng dalawang Claude Code session sa magkaibang repository ang naka-cache na branch name ng isa't isa.
May isa pang limitasyon na dapat malaman: hindi gumagana ang tput cols sa loob ng statusline script. Kinukuha ng Claude Code ang output sa halip na i-attach ang script sa terminal, kaya walang masusukat para matukoy ang lapad. Itinatakda ng Claude Code ang mga environment variable na COLUMNS at LINES bago patakbuhin ang command, sa v2.1.153 at mas bago, kaya basahin ang $COLUMNS kapag kailangan mong magpasya kung gaano karaming text ang ipi-print.
Nananatiling walang laman ang statusline
Walang lumalabas. Suriin ang execute bit gamit ang ls -l ~/.claude/statusline.sh, pagkatapos ay patakbuhin nang mano-mano ang script gamit ang mock input sa itaas. Kung may nailalabas itong linya sa shell pero wala sa Claude Code, magsimula sa claude --debug, na nagla-log ng exit code at stderr ng unang statusline run sa session.
Sinasabi ng debug log na Status line command skipped: workspace trust not accepted. Nagpapatakbo ang statusline ng shell command, kaya saklaw ito ng parehong workspace trust gate na ginagamit ng hooks. Hangga't hindi mo tinatanggap ang trust dialog para sa directory na iyon, hindi tatakbo ang command. Karaniwan ito sa isang VPS, kung saan bawat bagong clone ay directory na hindi pa nakikita ng Claude Code. I-restart ang Claude Code sa directory na iyon at tanggapin ang dialog.
Walang laman ang lahat at naka-set ang disableAllHooks. Hindi rin pinapagana ng "disableAllHooks": true sa settings.json ang statusline, dahil pareho itong shell-execution gate. Alisin ito o itakda sa false.
Nagpi-print ang row ng null. Umabot ang jq selector sa key na nawawala o null, at pini-print ng jq -r ang null bilang apat na character na null. Idagdag ang // empty para sa text at // 0 para sa mga number.
Nagiging walang laman ang row agad pagkatapos mong i-edit ang script. Kapag nag-exit sa non-zero status ang isang command o walang nai-print, nagiging walang laman ang row. Karaniwang sanhi nito ang huling linya na gaya ng [ -n "$BRANCH" ] && LINE="...", na nag-e-exit sa 1 kapag walang laman ang branch at naipapasa ang exit code nito sa buong script. Panatilihing huli ang printf, o idagdag ang exit 0.
Lumilitaw bilang literal na text ang escape codes gaya ng \e]8;; sa bar. Gamitin ang printf '%b' sa halip na echo -e. Kailangan din ng clickable OSC 8 links ng terminal na sumusuporta rito, at maaaring alisin ng tmux o SSH ang mga sequence, kaya mas ligtas ang plain colour sa remote box.
Napapuputol ang kanang bahagi ng row. Magkasalo sa row na iyon ang system notifications at verbose-mode token counter mula sa kanan, kaya nagkakaroon ng overlap sa makitid na terminal. Panatilihing maikli ang output. Para sa aktuwal na accounting ng usage sa halip na numerong ipinapakita sa bar, tingnan ang kung paano nagbibilang ng tokens ang Claude Code.
FAQ
Saan nakalagay ang setting ng Claude Code statusline?
Nasa settings.json ito bilang block na statusLine, na may type na nakatakda sa "command" at command na nakatakda sa script path o shell command. Nasa ~/.claude/settings.json ang user settings at nalalapat ang mga ito sa bawat project sa machine na iyon. Nasa .claude/settings.json sa loob ng repository ang project settings, at inuuna ang mga ito para sa directory na iyon. Awtomatikong nagre-reload ang settings, pero makikita lamang ang pagbabago sa susunod na update trigger, gaya ng susunod mong message.
Bakit blangko ang Claude Code statusline ko?
Apat na sanhi ang sumasaklaw sa halos lahat ng kaso. Walang execute bit ang script, kaya ibinabalik ng shell ang Permission denied at walang napupunta sa stdout. Hindi kailanman tinanggap ang workspace trust dialog, kaya nagla-log ang claude --debug ng Status line command skipped: workspace trust not accepted. Ang disableAllHooks ay true, kaya dini-disable nito ang statusline sa ilalim ng parehong gate. Maaari ring non-zero ang exit ng script, na nagbablanko sa row. Subukan muna ito nang manu-mano: kailangang may i-print ang echo '{}' | ~/.claude/statusline.sh.
Kasama ba sa statusline JSON ang git branch?
Hindi. Naglalaman ang JSON ng session state gaya ng model, workspace directories, context window numbers, at cost. Walang git information sa loob nito. Ang branch na lumalabas sa bar ay galing sa sarili mong script na tumatawag sa git branch --show-current. Ipasa ang directory mula sa JSON gamit ang git -C "$DIR" para laging tumugma ang branch sa directory na ipinapakita ng bar.
Kumokonsumo ba ng tokens ang statusline o nagpapabagal sa session?
Wala itong kinokonsumong tokens dahil lokal na tumatakbo ang script at hindi ipinapadala sa model ang output nito. Ikaw ang responsable sa speed nito. Tumatakbo ang command sa bawat assistant message na may 300 ms debounce, at kinakansela ng Claude Code ang kasalukuyang run kapag may bagong update. Kaya kung umaabot nang isang buong segundo ang script, stale text ang makikita. Iwasan ang git status sa malalaking repository, at i-cache sa file ang anumang mabagal, gamit ang session_id bilang key.
Paano ako magpapakita ng magkakaibang statusline sa bawat server?
Gumamit ng isang script at hayaan itong basahin ang machine. Ipi-print ng script sa itaas ang $HOSTNAME, na may hostname -s bilang fallback. Kaya kapag kinopya ang parehong file sa bawat box, tama nitong malalagyan ng label ang bawat isa, at bibigyan ng checksum colour trick ang bawat hostname ng sarili nitong kulay. Kung kailangan ng ibang layout ng isang server, maglagay ng statusLine block sa project settings ng repository na ginagamit mo sa box na iyon, dahil inuuna ng project settings ang user settings para sa directory na iyon.