Cara Membuat Statusline Claude Code di VPS
Pelajari pengaturan statusLine di settings.json untuk menampilkan hostname, direktori, branch git, dan model dari stdout skrip di bawah prompt Claude Code.
Yang ditampilkan oleh statusline Claude Code
Statusline Claude Code adalah baris di bawah prompt yang menampilkan keluaran dari skrip yang Anda tulis. Tambahkan blok statusLine ke settings.json, lalu arahkan blok tersebut ke sebuah perintah. Claude Code menjalankan perintah itu, mengirimkan status sesi kepadanya dalam format JSON melalui standard input, lalu mencetak apa pun yang ditulis perintah tersebut ke standard output.
Itulah seluruh kontraknya. Skrip Anda membaca JSON dari stdin dan mencetak teks ke stdout. Skrip berjalan di mesin Anda. Tidak ada hasil yang dicetaknya dikirim ke model, sehingga tidak menggunakan token.
Pada laptop dengan satu project, fitur ini hanya bersifat dekoratif. Pada tiga server, fitur ini menjadi pengaman. Setiap sesi Claude Code terlihat sama di setiap terminal. Karena itu, empat jendela SSH tanpa label dapat menyebabkan migrasi diterapkan pada server yang salah. Statusline yang diawali hostname mencegah jenis kesalahan tersebut.
Lokasi pengaturan statusLine di settings.json
Letakkan pengaturan ini di user settings pada ~/.claude/settings.json. Pengaturan tersebut berlaku untuk setiap project pada mesin itu. Project settings pada .claude/settings.json di dalam repository juga dapat digunakan, dan pengaturan tersebut lebih diutamakan untuk direktori itu.
{
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.sh"
}
}type selalu berupa "command". Nilai command dijalankan melalui shell, sehingga dapat berupa path skrip atau perintah biasa. Pastikan konfigurasi ini berfungsi sebelum menulis skrip apa pun:
{
"statusLine": {
"type": "command",
"command": "hostname -s"
}
}Mulai Claude Code dan kirim satu pesan. Baris di bawah prompt sekarang menampilkan hostname singkat server. Jika tetap kosong, masalahnya ada pada pengaturan atau dialog trust, bukan pada skrip Anda. Baca "Mengapa statusline tetap kosong" di bawah.
Tersedia tiga key opsional per August 2026. padding menambahkan spasi horizontal dalam satuan karakter dan nilai default-nya adalah 0. refreshInterval menjalankan ulang perintah setiap N detik selain trigger normal, dengan nilai minimum 1. Gunakan ini hanya jika baris tersebut menampilkan jam atau sesuatu yang berubah saat session dalam keadaan idle. hideVimModeIndicator menyembunyikan teks bawaan -- INSERT -- jika skrip Anda sendiri sudah menampilkan vim mode.
Data apa yang diterima skrip statusline?
Jangan mempercayai daftar field yang Anda baca di mana pun, termasuk halaman ini. Tangkap objek sebenarnya yang dikirim oleh versi Anda. Tulis skrip sementara yang menyimpan stdin ke sebuah file:
cat > ~/.claude/statusline-capture.sh <<'EOF'
#!/bin/bash
cat > /tmp/statusline-input.json
echo "captured"
EOF
chmod +x ~/.claude/statusline-capture.shArahkan statusLine.command ke file tersebut, mulai sesi, lalu kirim satu pesan. Bar membaca captured. Sekarang periksa data yang diterima:
jq . /tmp/statusline-input.jsonAnda kini memiliki struktur yang tepat untuk build Anda. Anda dapat mengulangi langkah ini kapan pun pembaruan mengubah sesuatu.
Bagian yang stabil, sebagaimana didokumentasikan pada August 2026, berupa objek bertingkat, bukan key datar. model memuat id dan display_name. workspace memuat current_dir dan project_dir: current_dir menunjukkan lokasi sesi saat ini, sedangkan project_dir menunjukkan lokasi saat sesi dimulai. Keduanya berbeda setelah direktori kerja berubah di tengah sesi. cwd tingkat teratas membawa nilai yang sama dengan workspace.current_dir. context_window memuat jumlah token serta used_percentage yang telah dihitung sebelumnya. cost memuat total_cost_usd dan penghitung durasi. session_id tetap sama selama sesi berlangsung dan unik untuk setiap sesi. Hal ini penting untuk caching pada tahap berikutnya.
Tiga aturan berikut membuat skrip tetap berfungsi saat skema berubah.
Beberapa key tidak ada, bukan bernilai null. vim, agent, pr, worktree, dan effort hanya muncul ketika fitur yang sesuai aktif. Membaca .vim.mode dengan jq -r saat mode vim nonaktif akan mencetak string literal null, sehingga bar Anda menampilkan null kepada pembaca. Tambahkan // empty ke setiap selector agar key yang tidak ada tidak mencetak apa pun.
Beberapa nilai bernilai null pada tahap awal. context_window.used_percentage dan context_window.current_usage bernilai null sebelum respons API pertama diterima. current_usage kembali bernilai null setelah /compact, sampai panggilan berikutnya mengisinya kembali. Karena itu, persentase konteks pada bar memerlukan // 0. Jika tidak, bar akan membaca null selama beberapa detik pertama setiap sesi. Sebelum menampilkan angka tersebut pada bar, sebaiknya pahami cara pengisian context window sebenarnya.
Branch git tidak ada dalam JSON. Tidak ada field yang melaporkannya. Branch apa pun yang muncul pada bar berasal dari skrip Anda sendiri yang menjalankan git.
Skrip statusline yang menurun secara aman alih-alih gagal
Berikut versi yang dapat langsung disalin dan ditempel. Skrip ini mencetak hostname, direktori kerja, branch git, dan nama model. Setiap bidang memiliki fallback, sehingga objek JSON kosong pun tetap menghasilkan baris yang dapat digunakan.
#!/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"Setiap pembacaan dilakukan melalui field, yang menambahkan // empty. Dengan demikian, key yang diubah namanya atau dihapus menghasilkan string kosong, lalu baris berikutnya menyediakan nilai default. Direktori menggunakan fallback dari workspace.current_dir ke cwd lalu ke $PWD. Branch diperoleh dari git -C "$DIR", bukan dari git tanpa konteks, sehingga branch selalu sesuai dengan direktori yang ditampilkan oleh bar.
Simpan skrip tersebut, lalu jadikan executable:
chmod +x ~/.claude/statusline.shBit execute wajib diatur. Claude Code menjalankan perintah melalui shell, sehingga skrip tanpa +x gagal dengan Permission denied, tidak menghasilkan stdout, dan baris tersebut tetap kosong tanpa error yang terlihat.
jq mengurai JSON pada command line dan tidak terinstal pada server Ubuntu yang baru:
sudo apt update && sudo apt install -y jqKemudian arahkan setting ke skrip tersebut menggunakan blok settings.json pertama di atas.
Uji skrip sebelum mempercayainya
Jalankan secara manual dua kali. Pertama, gunakan objek sesi normal:
echo '{"model":{"display_name":"Opus"},"workspace":{"current_dir":"/srv/api"},"session_id":"t1"}' | ~/.claude/statusline.shAnda mendapatkan hostname, lalu /srv/api, kemudian Opus. Tidak ada cabang yang muncul karena /srv/api pada mesin Anda mungkin bukan repositori git.
Kedua, lakukan uji degradasi. Uji ini sering dilewati:
echo '{}' | ~/.claude/statusline.shObjek kosong adalah kondisi terburuk yang dapat diberikan oleh perubahan skema. Baris tersebut tetap mencetak hostname, direktori saat ini dari $PWD, dan kata claude pada posisi nama model. Tidak ada yang mengalami crash dan tidak ada null yang dicetak. Skrip yang lulus uji ini tetap berfungsi ketika suatu field diganti namanya karena bagi skrip Anda, field yang diganti nama dan field yang tidak ada merupakan peristiwa yang sama.
Yang harus Anda lihat
Baris status ditampilkan pada barisnya sendiri di atas lencana footer bawaan dan tidak menggantikannya. Pada konfigurasi yang berfungsi, baris ini terdiri dari hostname singkat berwarna cyan, lalu direktori kerja dengan direktori home yang disingkat menjadi ~, kemudian nama branch berwarna kuning jika direktori tersebut merupakan repositori git, lalu nama model dengan warna redup. Hasilnya kurang lebih seperti web-01 ~/api main Opus, dengan keempat bagian tersebut diberi warna.
Baris ini menjalankan ulang script Anda saat sesi dimulai, termasuk saat melanjutkan sesi, saat pesan assistant baru tiba, setelah /compact selesai, saat mode permission berubah, saat mode vim diaktifkan atau dinonaktifkan, dan pada interval refreshInterval jika Anda menetapkannya. Pembaruan ditunda selama 300 ms, sehingga serangkaian perubahan hanya menjalankan script satu kali. Baris ini disembunyikan selama autocomplete, menu bantuan, dan prompt permission, lalu ditampilkan kembali.
Hostname harus ditampilkan lebih dahulu
Saat Anda menjalankan agent di lebih dari satu server, terminal adalah satu-satunya penanda lokasi Anda, dan terminal dapat menyesatkan. Buka koneksi ssh kedua dari dalam panel tmux, dan judul jendela sering kali tetap menggunakan nama lama karena judul tersebut diatur oleh shell yang tidak pernah mengetahui bahwa lokasinya telah berpindah. Biarkan Claude Code berjalan dalam sesi tmux terlepas di VPS lalu sambungkan kembali sehari kemudian. Tidak ada elemen pada layar yang membedakan server build dari server production.
Statusline berbeda karena dirender langsung oleh Claude Code untuk setiap sesi, berdasarkan data yang dimiliki sesi tersebut. Statusline tidak dapat diwarisi dari panel yang salah atau tetap kedaluwarsa karena prompt shell tidak pernah diperbarui. Informasi yang ditampilkan adalah server tempat agent menulis file.
Gunakan warna yang berbeda untuk setiap server agar Anda dapat mengenalinya sebelum membaca informasinya. Tambahkan dua baris berikut di atas assignment LINE=:
CODE=$(printf '%s' "$HOST" | cksum | cut -d' ' -f1)
HOST_COLOR=$(printf '\033[%dm' "$((31 + CODE % 6))")Selanjutnya, gunakan ${HOST_COLOR} sebagai pengganti ${CYAN}. cksum mencetak checksum hostname, sehingga nama tertentu selalu dipetakan ke warna yang sama dalam rentang 31 hingga 36, yaitu dari merah hingga cyan. Salin script yang sama ke setiap server, dan setiap server akan menampilkan identitasnya sendiri.
Direktori memiliki alasan yang sama untuk ditampilkan. /srv/api dan /srv/api-staging hanya berjarak satu keystroke dalam perintah ssh, tetapi dampaknya dapat membedakan keseluruhan insiden. Model dan branch adalah dua informasi lain yang layak menggunakan ruang tersebut: model menunjukkan sesi yang Anda lanjutkan, sedangkan branch menunjukkan apakah agent akan melakukan commit ke main.
Layar kecil membuat semua informasi ini semakin penting karena tidak ada judul jendela yang dapat digunakan sebagai cadangan. Jika itu adalah setup Anda, lihat mengendalikan Claude Code dari ponsel.
Percepat skrip
Skrip Anda dijalankan pada setiap pesan assistant. Claude Code membatalkan proses yang sedang berjalan ketika pembaruan baru tersedia. Karena itu, skrip yang lambat dapat menampilkan teks lama atau tidak menampilkan teks sama sekali.
Setiap pemanggilan jq memerlukan waktu beberapa milidetik. git adalah bagian yang menjadi lambat: git status pada repository besar dengan cache yang belum terisi memerlukan waktu ratusan milidetik. Skrip di atas sengaja menghindari git status dan memanggil git branch --show-current, yang membaca .git/HEAD lalu segera mengembalikan hasil.
Jika Anda menambahkan proses yang lebih berat, simpan hasilnya dalam file cache dan perbarui setiap beberapa detik. Gunakan session sebagai kunci file:
CACHE="/tmp/statusline-$(field '.session_id')"Gunakan session_id, bukan $$. $$ adalah ID proses skrip Anda. Nilainya berbeda pada setiap pemanggilan, sehingga cache yang menggunakan nilai ini sebagai kunci tidak pernah terkena cache dan Anda harus membayar seluruh biaya proses setiap kali. session_id tetap sama selama seluruh session dan berbeda antar-session. Dengan demikian, dua session Claude Code pada dua repository tidak dapat membaca nama branch yang tersimpan dalam cache milik session lain. Secara desain, session tetap terisolasi seperti itu. Karena itu, agar satu session menyerahkan pekerjaan kepada session lain diperlukan langkah yang disengaja. Itulah kegunaan mengirim pesan dari satu session Claude Code ke session lain.
Ada satu batasan lain yang perlu diketahui: tput cols tidak berfungsi di dalam skrip statusline. Claude Code menangkap output tersebut, bukan memasang skrip Anda ke terminal. Karena itu, deteksi lebar tidak memiliki apa pun untuk diukur. Claude Code menetapkan variabel lingkungan COLUMNS dan LINES sebelum menjalankan perintah, mulai v2.1.153. Jadi, baca $COLUMNS jika Anda perlu menentukan jumlah teks yang akan dicetak.
Baris status tetap kosong
Tidak ada apa pun yang muncul. Periksa bit eksekusi dengan ls -l ~/.claude/statusline.sh, lalu jalankan skrip secara manual menggunakan input mock di atas. Jika skrip mencetak baris di shell tetapi tidak di Claude Code, mulai dengan claude --debug. Perintah ini mencatat exit code dan stderr dari eksekusi statusline pertama dalam sesi.
Log debug berisi Status line command skipped: workspace trust not accepted. Statusline menjalankan perintah shell, sehingga statusline tunduk pada workspace trust gate yang sama seperti hooks. Sebelum Anda menyetujui dialog trust untuk direktori tersebut, perintah tidak akan dijalankan. Hal ini umum terjadi pada VPS karena setiap clone baru merupakan direktori yang belum pernah dilihat Claude Code. Jalankan ulang Claude Code di direktori tersebut, lalu setujui dialognya.
Semuanya kosong dan disableAllHooks disetel. "disableAllHooks": true di settings.json juga menonaktifkan statusline karena merupakan shell-execution gate yang sama. Hapus pengaturan tersebut atau ubah nilainya menjadi false.
Baris menampilkan null. Selector jq mencapai key yang tidak ada atau bernilai null, dan jq -r mencetak null sebagai empat karakter null. Tambahkan // empty untuk teks dan // 0 untuk angka.
Baris menjadi kosong segera setelah Anda mengedit skrip. Perintah yang keluar dengan status non-zero atau tidak mencetak apa pun akan mengosongkan baris tersebut. Penyebab yang umum adalah baris terakhir seperti [ -n "$BRANCH" ] && LINE="...", yang keluar dengan status 1 ketika branch kosong dan membuat seluruh skrip menggunakan exit code tersebut. Biarkan printf sebagai baris terakhir atau tambahkan exit 0.
Escape code tampil sebagai teks literal, misalnya \e]8;; pada baris tersebut. Gunakan printf '%b', bukan echo -e. Link OSC 8 yang dapat diklik juga memerlukan terminal yang mendukungnya. tmux atau SSH dapat menghapus sequence tersebut, jadi warna biasa merupakan pilihan yang lebih aman pada server remote.
Sisi kanan baris terpotong. Notifikasi sistem dan penghitung token verbose-mode menggunakan baris tersebut dari sisi kanan, sehingga terminal yang sempit menyebabkan keduanya bertumpang tindih. Buat output tetap singkat. Untuk penghitungan penggunaan yang sebenarnya, bukan sekadar angka pada baris, lihat cara Claude Code menghitung token.
FAQ
Di mana pengaturan statusline Claude Code berada?
Di settings.json, sebagai blok statusLine dengan type yang ditetapkan ke "command" dan command yang ditetapkan ke path skrip atau perintah shell. Pengaturan pengguna berada di ~/.claude/settings.json dan berlaku untuk setiap project pada mesin tersebut. Pengaturan project berada di .claude/settings.json di dalam repository dan diutamakan untuk direktori tersebut. Pengaturan dimuat ulang secara otomatis, tetapi perubahan baru terlihat pada pemicu pembaruan berikutnya, seperti pesan Anda berikutnya.
Mengapa statusline Claude Code saya kosong?
Hampir semua kasus disebabkan oleh empat hal. Skrip tidak memiliki bit eksekusi, sehingga shell mengembalikan Permission denied dan tidak ada output yang masuk ke stdout. Dialog kepercayaan workspace belum pernah disetujui, dan claude --debug mencatat Status line command skipped: workspace trust not accepted. disableAllHooks adalah true, yang menonaktifkan statusline dengan pemeriksaan yang sama. Atau skrip keluar dengan kode non-zero, sehingga baris tersebut kosong. Uji skrip secara manual terlebih dahulu: echo '{}' | ~/.claude/statusline.sh harus mencetak sesuatu.
Apakah JSON statusline menyertakan branch git?
Tidak. JSON tersebut memuat status sesi, seperti model, direktori workspace, angka context window, dan biaya. JSON tersebut tidak memuat informasi tentang git. Branch pada bar Anda berasal dari skrip Anda sendiri yang memanggil git branch --show-current. Teruskan direktori dari JSON menggunakan git -C "$DIR" agar branch selalu sesuai dengan direktori yang ditampilkan oleh bar.
Apakah statusline menggunakan token atau memperlambat sesi?
Statusline tidak menggunakan token karena skrip berjalan secara lokal dan outputnya tidak pernah dikirim ke model. Kecepatan menjadi tanggung jawab Anda. Perintah dijalankan pada setiap pesan assistant dengan debounce 300 ms, dan Claude Code membatalkan eksekusi yang sedang berlangsung saat pembaruan baru tiba. Karena itu, skrip yang memerlukan waktu satu detik penuh akan menampilkan teks yang sudah kedaluwarsa. Hindari git status pada repository besar, dan cache apa pun yang lambat ke dalam file dengan kunci session_id.
Bagaimana cara menampilkan statusline yang berbeda pada setiap server?
Gunakan satu skrip dan biarkan skrip tersebut membaca mesin tempatnya berjalan. Skrip di atas mencetak $HOSTNAME dengan hostname -s sebagai fallback. Dengan demikian, file yang sama dapat disalin ke setiap server dan memberi label yang benar pada masing-masing server, sedangkan trik warna checksum memberikan warna tersendiri untuk setiap hostname. Jika salah satu server memerlukan tata letak yang berbeda, letakkan blok statusLine dalam pengaturan project pada repository yang Anda gunakan di server tersebut karena pengaturan project diutamakan daripada pengaturan pengguna untuk direktori itu.