Membangun helper tmux sendiri lewat fungsi shell, merancang status widget ringan dengan script eksternal, memecah konfigurasi menjadi modul-modul source-file, serta menyimpan semuanya via versioning.

Di episode 16 sebelumnya kita membangun fondasi plugin dengan TPM — mendeklarasikan plugin, menginstall lewat prefix + I, mengupdate lewat prefix + U, dan memilih plugin wajib untuk clipboard, persistence, dan widget status. Namun ada kalanya plugin terasa seperti membeli perabot jadi: cocok untuk kebutuhan umum, tetapi kurang pas untuk kebutuhan spesifik kalian sendiri.
Pada episode ini kita membalik perspektif. Alih-alih selalu menambah plugin, kita belajar membangun sendiri: fungsi shell untuk mengotomasi tmux, status widget ringan yang ditulis dalam beberapa baris, dan struktur konfigurasi yang dipecah menjadi modul-modul agar mudah dirawat dan di-versioning. Ini adalah keterampilan yang membedakan pemakai tmux biasa dengan engineer yang benar-benar mengendalikan workflow-nya.
Seluruh contoh merujuk tmux 3.7b sebagai versi stabil terbaru. Target akhirnya sederhana: konfigurasi yang tipis, jelas, dan bisa dipindahkan ke mesin mana pun tanpa drama.
Sebelum menulis baris pertama, penting untuk memahami kapan plugin layak dipakai dan kapan script sendiri lebih masuk akal. Keduanya bukan musuh — keduanya adalah alat dengan trade-off berbeda.
| Faktor | Plugin (via TPM) | Script / Fungsi Sendiri |
|---|---|---|
| Maintenance | Ikut ekosistem, update via prefix + U | Dirawat sendiri oleh kalian |
| Biaya | Folder + state per plugin | Satu file kecil |
| Kustomisasi | Sesuai desain penulis plugin | Persis sesuai kebutuhan |
| Portabilitas | Bergantung prasyarat plugin | Bergantung tool yang kalian pilih |
| Kasus Pakai | Masalah umum dengan komunitas besar | Kebutuhan spesifik / internal tim |
Analoginya seperti memilih antara membeli alat jadi dan membuat alat sendiri di bengkel. Untuk masalah yang sudah umum — clipboard, persistence — plugin adalah keputusan tepat karena komunitas sudah menguji jutaan kali. Tetapi ketika kalian membutuhkan perintah yang hanya masuk akal di workflow tim sendiri, misalnya "buat session sesuai nama folder proyek", script 15 baris jauh lebih ringan daripada plugin yang mendukung seratus fitur yang tidak pernah kalian pakai.
Jembatan paling alami antara tmux dan shell adalah fungsi. Fungsi shell bisa dijalankan dari mana saja, membaca environment, dan memanggil perintah tmux secara non-interaktif — persis yang kita pelajari dari sisi CLI di episode 13 dan 14.
Contoh paling berguna adalah fungsi untuk membuat session per proyek. Simpan fungsi berikut di shell config kalian, misalnya ~/.zshrc atau ~/.bashrc:
mkt() {
local name="${1:-$(basename "$PWD")}"
tmux has-session -t "$name" 2>/dev/null || tmux new-session -d -s "$name"
tmux switch-client -t "$name"
}Mari bedah setiap baris:
mkt backend, nama yang dipakai adalah backend; jika tanpa argumen, nama diambil dari basename "$PWD" — jadi di folder /home/devnull/work/api-gateway, session otomatis bernama api-gateway.tmux has-session -t "$name" memeriksa apakah session sudah ada. Jika belum (ditandai dengan ||), session baru dibuat detached dengan tmux new-session -d -s "$name".tmux switch-client -t "$name".Kunci dari pola ini adalah flag -d pada new-session. Tanpa -d, tmux akan mencoba menempelkan client ke session baru secara langsung, dan di dalam tmux yang sudah berjalan itu akan membuat konflik. Membuat session detached lalu memindahkan client secara eksplisit adalah pola yang aman di kedua konteks: dari dalam tmux maupun dari shell biasa.
Tip
Pola has-session || new-session ini adalah idiom terpenting dalam otomasi tmux. Kalian akan melihatnya berulang di script tmuxp, sessionizer, dan berbagai tools lain. Begitu kalian paham idiom ini, hampir semua otomasi session terbuka di hadapan kalian.
Status bar tmux mendukung dua cara menampilkan data dinamis: format variable #{...} yang dievaluasi oleh server, dan komando shell #(...) yang mengeksekusi perintah. Keduanya sering tertukar, padahal perilakunya berbeda.
Format variable dievaluasi cepat karena dihitung internal server. Komando shell #() justru mem-spawn proses baru setiap kali dievaluasi — fleksibel, tetapi ada biayanya. Frekuensi evaluasi diatur oleh option status-interval.
Contoh widget paling sederhana adalah menampilkan cabang git di status bar:
set -g status-interval 5
set -g status-right '#[fg=green]#(git rev-parse --abbrev-ref HEAD 2>/dev/null)#[default] %H:%M'Perhatikan penggunaan 2>/dev/null — ketika kalian berada di direktori yang bukan repo git, git rev-parse mengeluarkan error ke stderr yang bisa merusak status bar. Membuangnya membuat widget diam ketika tidak relevan.
Ketika satu baris #(...) mulai terlalu panjang atau membutuhkan logika, pindahkan ke script eksternal. Konvensi yang sehat adalah menaruh semua widget di satu direktori, misalnya ~/.config/tmux/widgets/.
#!/usr/bin/env bash
if [[ -r /proc/loadavg ]]; then
read -r load _ < /proc/loadavg
else
load="$(uptime | awk -F'load average: ' '{print $2}' | cut -d, -f1)"
fi
echo "#[fg=yellow]load ${load}#[default]"Script ini membaca load average dengan satu trik portabilitas: di Linux, data dibaca langsung dari /proc/loadavg; di platform tanpa file tersebut, nilainya diambil dari output uptime. Hasilnya dicetak dengan format color code yang bisa langsung dipahami status bar.
Agar dapat dieksekusi, beri izin eksekusi, lalu referensikan path-nya di konfigurasi:
chmod +x ~/.config/tmux/widgets/loadavg.sh
set -g status-left-length 40
set -g status-left '#[fg=cyan]#(~/.config/tmux/widgets/loadavg.sh)#[default]'Warning
Setiap kali status-interval habis, tmux menjalankan ulang seluruh widget #(). Logika berat seperti panggilan jaringan atau parsing file besar akan menjadi beban CPU yang tidak perlu. Jaga widget tetap tipis — tampilkan nilai, jangan melakukan kerja berat di dalamnya.
Seiring bertambahnya keybinding, tema, plugin, dan widget, satu file ~/.tmux.conf bisa membengkak hingga ratusan baris. Di sinilah source-file berperan: perintah untuk memuat file konfigurasi lain, mirip include di bahasa pemrograman.
Pola modular memecah konfigurasi berdasarkan kepentingan:
~/.config/tmux/
tmux.conf
keys.conf
plugins.conf
theme.conf
widgets.confPada tmux 3.7b, konfigurasi bisa disimpan di ~/.config/tmux/tmux.conf mengikuti standar XDG — tmux otomatis memakainya selama ~/.tmux.conf tidak ada. File utama kemudian cukup menjadi titik masuk yang memuat modul lain:
set -g base-index 1
set -g mouse on
source-file ~/.config/tmux/keys.conf
source-file ~/.config/tmux/theme.conf
source-file ~/.config/tmux/plugins.conf
source-file ~/.config/tmux/widgets.confKeuntungan pemecahan ini nyata di dunia nyata: ketika satu orang mengubah tema, git diff hanya menyentuh theme.conf; ketika menambah keybinding, hanya keys.conf. Kolaborasi tim jadi lebih rapi dan konflik merge lebih mudah diselesaikan. Ingat untuk memuat ulang dengan prefix + r setiap kali salah satu modul berubah.
Salah satu modul yang paling sering dipisah adalah tema, karena perubahan visual paling sering terjadi. Berikut contoh theme.conf dengan palet Catppuccin Mocha:
set -g status-style 'bg=#1e1e2e,fg=#cdd6f4'
set -g window-status-current-style 'fg=#89b4fa'
set -g pane-border-style 'fg=#45475a'
set -g pane-active-border-style 'fg=#89b4fa'| Warna | Nilai | Peran |
|---|---|---|
#1e1e2e | Mantle | Background status bar |
#cdd6f4 | Text | Warna teks default |
#89b4fa | Blue | Warna aksen / aktif |
#45475a | Surface | Border pane non-aktif |
Karena tema hanya berisi option, memindahkannya ke file terpisah tidak mengubah perilaku sama sekali — hanya menyederhanakan perawatan. Pola yang sama berlaku untuk keys.conf dan widgets.conf.
Di episode 14 kita sudah menyentuh tmuxp sebagai alat deklaratif untuk menyusun session. Sekarang kita pakai lebih dalam untuk melengkapi konfigurasi modular: layout yang disimpan sebagai YAML bisa dijalankan ulang kapan saja dan menghasilkan struktur yang identik.
session_name: web
windows:
- window_name: editor
panes:
- shell_command: nvim
- window_name: server
panes:
- shell_command: npm run devFile YAML ini menggambarkan sebuah session bernama web dengan dua window: editor yang membuka nvim, dan server yang menjalankan dev server. Bandingkan dengan menulis ulang baris-baris tmux new-window dan tmux send-keys secara manual — file deklaratif jauh lebih mudah dibaca, direview, dan di-versioning.
tmuxp load tmuxp.yamlKarena tmuxp hanya memakai command tmux di balik layar, layout yang sama bekerja di mesin mana pun selama tmux terpasang — ideal untuk tim yang ingin menyamakan struktur workspace.
Semua upaya di atas akan sia-sia tanpa versioning. Konfigurasi yang tidak dikelola versi akan mulai berbeda antar mesin, dan perbedaan itulah sumber bug yang paling sulit dilacak.
Pendekatan paling umum adalah menyimpan konfigurasi di repo dotfiles dan menautkannya ke lokasi yang dibaca tmux:
mkdir -p ~/dotfiles/tmux
git init ~/dotfiles
ln -s ~/dotfiles/tmux/tmux.conf ~/.tmux.confDengan symlink, kalian hanya punya satu sumber kebenaran: file di dalam repo. Setiap perubahan langsung bisa di-commit, di-review, dan di-rollback. Untuk setup yang lebih rapi dengan banyak tools sekaligus, tools seperti GNU Stow bisa mengelola symlink secara otomatis — tetapi untuk satu konfigurasi tmux, ln -s sudah cukup.
chmod +x pada script widget. Script yang tidak executable hanya akan menampilkan error atau tidak menghasilkan apa pun di status bar. Selalu verifikasi dengan menjalankan script langsung dari terminal sebelum menautkannya ke konfigurasi.#(). Widget dieksekusi ulang setiap status-interval. Panggilan jaringan, loop besar, atau parsing file raksasa di dalam widget akan membuat status bar lambat dan membebani CPU.source-file. source-file /home/user/.config/tmux/theme.conf akan rusak di mesin orang lain. Gunakan ~ atau $HOME agar konfigurasi portabel.theme.conf, kalian tetap harus menekan prefix + r agar perubahan tampak.~/.tmux.conf dan ~/.config/tmux/tmux.conf sekaligus. Tmux memprioritaskan ~/.tmux.conf; file XDG hanya dipakai ketika file lama tidak ada. Dua file ini akan saling menutupi dan membingungkan. Pilih salah satu.Episode ini melengkapi pola pikir kalian: plugin memang hebat, tetapi kemampuan membangun sendiri adalah aset jangka panjang. Kalian kini bisa menulis fungsi shell seperti mkt() yang membuat session per proyek, merancang widget ringan dengan #() dan script eksternal, memecah konfigurasi menjadi modul source-file yang terorganisir, mendeskripsikan layout dengan tmuxp, dan menjaga semuanya tetap sinkron lewat versioning.
Poin yang harus kalian bawa:
has-session || new-session adalah fondasi otomasi session.#() fleksibel tapi harus tipis; naikkan status-interval untuk mengurangi beban.source-file dan XDG, bukan menumpuk ratusan baris dalam satu file.Dengan fondasi lokal yang sudah kokoh, saatnya membawa tmux ke skenario yang paling menentukan: mesin remote. Di episode 18 selanjutnya kita akan membahas remote development dan SSH workflow — bertahan dari koneksi yang terputus, memakai mosh untuk jaringan lambat, menembus jump host, dan menangani nested tmux ketika server juga menjalankan tmux. Sampai jumpa di episode 18!