ekosistem plugin Zellij: siklus hidup WASM render/event/action dan Zellij Message Protocol, menulis plugin Rust, memuat plugin dari web, mengelola via plugin manager, plus menggabungkan plugin dengan pipes.

Di episode 14, kalian memakai filepicker dan strider — dan kalian mungkin tidak menyadari bahwa kalian sudah berinteraksi dengan sistem plugin Zellij sejak lama. Tab-bar di atas, status-bar di bawah, strider di samping: semuanya adalah plugin. Ini bukan detail teknis semata — ini adalah alasan mengapa Zellij bisa bertahan dan berkembang di ekosistem yang penuh alat terminal lain yang kaku dan sulit dimodifikasi.
Episode 15 masuk ke jantung arsitektur Zellij. Kita akan membedah sistem plugin: bagaimana modul WASM dimuat dan berjalan di dalam server Zellij, siklus hidupnya (render, event, action), dan Zellij Message Protocol yang menghubungkan plugin dengan host. Setelah itu kita belajar menulis dan memuat plugin — dari file lokal hingga URL web — lalu mengelolanya dengan Plugin Manager yang diperkenalkan di versi 0.41, dan menggabungkan plugin dengan pipes untuk automasi dua arah.
Setelah episode ini, kalian tidak akan lagi melihat Zellij sebagai kumpulan fitur tetap yang sudah jadi, melainkan sebagai kerangka kerja yang bisa kalian isi sesuka hati. Kalian akan tahu persis ke mana harus melihat ketika sebuah plugin bermasalah, kapan sebuah plugin bisa diganti, dan mengapa fitur seperti pipes (episode 13) dan filepicker (episode 14) sebenarnya satu sistem yang sama.
Mengapa ini penting? Karena memahami sistem plugin berarti memahami batas kemampuan Zellij — dan batas itu ternyata sangat jauh. Kalian bisa mengganti tab-bar dan status-bar bawaan dengan buatan sendiri, menulis widget khusus untuk workflow kalian, atau memuat plugin komunitas dari web tanpa mengubah kode Zellij sama sekali. Di episode 16 kita akan membangun plugin nyata; episode ini adalah peta konsepnya. Mari mulai dari arsitektur.
Setiap elemen UI Zellij yang kalian lihat — baris tab, baris status, kompiler hint, file explorer, session manager — adalah modul WebAssembly (WASM) yang dimuat ke dalam server Zellij. Ini keputusan desain yang berani: alih-alih meng-hardcode UI di dalam binary, Zellij mengeksekusi plugin sebagai sandbox terisolasi yang berkomunikasi dengan host lewat pesan.
Konsekuensi paling menarik dari keputusan ini adalah bahasa tidak lagi penting. Selama bahasa itu bisa dikompilasi ke target wasm32-wasi, bahasa tersebut bisa menjadi plugin Zellij. Rust adalah warga kelas satu karena ekosistemnya paling matang, tetapi Go, Zig, C, dan bahasa lain juga bisa — inilah makna cross-language UI components yang dibawa sejak versi 0.39. Plugin bukan "aplikasi Rust yang menempel", melainkan komponen UI yang berbicara protokol yang sama, apa pun bahasa asalnya.
Semua plugin bawaan Zellij terdaftar sebagai alias di blok plugins pada config.kdl:
| Alias | Plugin | Fungsi |
|---|---|---|
zellij:tab-bar | tab-bar | Menampilkan tab, indikator pane aktif |
zellij:status-bar | status-bar | Menampilkan mode, hint keybinding, nama session |
zellij:strider | strider | File explorer / filepicker |
zellij:compact-bar | compact-bar | Status bar minimal satu baris |
zellij:session-manager | session-manager | Kelola dan buat session |
zellij:plugin-manager | plugin-manager | Kelola plugin yang berjalan |
Karena semuanya plugin, kalian bisa menukar implementasinya. Kalian bisa mengganti alias status-bar dengan plugin status buatan komunitas, atau mengganti filepicker dengan implementasi file picker kustom — selama mengikuti kontrak yang sama, Zellij tidak peduli siapa yang menggambar UI-nya. Ini tingkat kebebasan yang tidak dimiliki tmux.
Keamanan menjadi pertimbangan yang tidak bisa diabaikan. Setiap plugin berjalan dalam sandbox WASM yang memisahkan memori plugin dari memori host, dan permission yang diminta plugin menentukan kemampuan apa yang bisa ia gunakan — misalnya membaca keadaan aplikasi, menulis ke stdin, atau mengontrol pane. Ini bukan soal kepercayaan buta; ini soal memberi plugin hanya apa yang ia butuhkan, tidak lebih. Model permission ini mirip dengan permission di browser, dan menjadi alasan mengapa memuat plugin pihak ketiga jauh lebih aman daripada menjalankan skrip sebarang di terminal.
Note
Plugin berjalan di server Zellij, bukan di client. Artinya plugin tetap hidup selama session berjalan, bahkan ketika tidak ada yang attach. Konsekuensinya: resource yang dipakai plugin (memori, CPU untuk render) dibebankan ke server — jadi jangan memuat plugin yang tidak kalian butuhkan.
Bagaimana plugin dan host berbicara? Melalui Zellij Message Protocol — serangkaian pesan yang dipertukarkan antara host dan modul WASM. Host memanggil fungsi yang diekspor plugin untuk memberi tahu keadaan; plugin membalas dengan aksi dan teks render. Tidak ada memori bersama, tidak ada pointer — hanya pesan yang lewat batas WASM.
Siklus hidup sebuah plugin terdiri dari beberapa fase:
| Fase | Kapan | Tugas Plugin |
|---|---|---|
load | Sekali, saat dimuat | Mendaftarkan event yang disubscribe, meminta permission |
update (event) | Setiap ada event | Memperbarui state internal, memutuskan apakah perlu render ulang |
render | Setiap kali layar digambar | Menggambar UI lewat teks yang dikirim ke stdout |
pipe | Setiap ada pesan pipe | Menerima data dari luar (CLI, keybinding, plugin lain) |
Alurnya satu arah yang jelas: keadaan dunia Zellij datang sebagai event (perubahan mode, tab, pane, keypress, mouse, timer), plugin merespons dalam update dengan memperbarui state, lalu render menggambar hasilnya. Ketika plugin ingin mengubah dunia — misalnya berpindah mode, membuka pane, atau menulis ke stdin — ia mengirim action kembali ke host.
Kerangka plugin minimal terlihat seperti ini (akan kita bedah penuh di episode 16):
use std::collections::BTreeMap;
use zellij_tile::prelude::*;
#[derive(Default)]
struct MonitorTile {
mode: String,
}
register_tile!(MonitorTile);
impl ZellijTile for MonitorTile {
fn load(&mut self, _config: BTreeMap<String, String>) {
request_permission(&[PermissionType::ReadApplicationState]);
subscribe(&[EventType::ModeUpdate]);
}
}Dua panggilan di dalam load adalah kunci: subscribe menentukan event mana yang akan dikirim host ke plugin, dan request_permission menentukan kemampuan yang boleh dipakai plugin. Tanpa keduanya, plugin hanya akan menerima event dasar dan tidak bisa mengakses keadaan aplikasi.
Alur render layak untuk didalami karena sering disalahpahami. Ketika render dipanggil, plugin menggambar lewat teks yang dikirim ke stdout — setiap baris yang dicetak menjadi baris di layar pane plugin. Host yang mengelola buffer layar, warna, dan scroll; plugin cukup menulis apa yang harus tampil. Inilah mengapa plugin bisa ditulis dalam bahasa apa pun: selama bahasa itu bisa menulis teks ke stdout dan menerima event dari stdin, bahasa tersebut bisa menjadi UI Zellij. Semua ini berjalan di atas antarmuka WASM yang sama, itulah mengapa Zellij menyebut ekosistem ini sebagai UI components lintas bahasa.
Important
subscribe dan request_permission hanya sah dipanggil di dalam load. Permintaan permission yang dilontarkan setelah plugin berjalan akan ditolak host. Tentukan kebutuhan plugin di awal, jangan di tengah jalan.
Menulis plugin dimulai dengan crate Rust yang menggunakan dependency zellij-tile — pustaka yang menyediakan semua fungsi helper: request_permission, subscribe, pengiriman action, dan trait ZellijTile yang tadi kita lihat. Hasil kompilasinya adalah satu file .wasm, dan file itulah yang dimuat Zellij. Memuatnya bisa dari file lokal maupun dari URL web — dua sumber yang dipertukarkan lewat satu mekanisme yang sama:
zellij plugin load -f ./target/wasm32-wasi/release/monitor.wasmSetelah dimuat, plugin muncul sebagai pane baru di session aktif. Saat kalian memperbarui kode dan mengkompilasi ulang, jalankan kembali perintah yang sama untuk memuat versi terbaru — alur build → load → lihat hasilnya inilah yang akan kita pakai sebagai siklus pengembangan di episode 16.
Sejak versi 0.39, Zellij juga bisa memuat plugin langsung dari web — cukup beri URL file .wasm, seperti tab kedua di atas. Fitur ini membuka pintu ke ekosistem: plugin bisa dibagikan sebagai tautan, dimuat tanpa instalasi manual, dan diperbarui cukup dengan memuat URL yang sama lagi. Di layout KDL, plugin dari URL web maupun file lokal dimuat lewat blok plugin dengan properti location:
layout {
pane split_direction="vertical" {
pane
pane size="15%" borderless=true {
plugin location="file:/home/devnull/.config/zellij/plugins/monitor.wasm"
}
}
}Menempatkan plugin di dalam layout berarti plugin otomatis dimuat setiap kali layout dijalankan — pola yang tepat untuk widget yang harus selalu ada, seperti status bar kustom.
Warning
Memuat plugin dari URL web berarti mengeksekusi kode pihak ketiga di dalam session kalian. Meskipun sandbox WASM membatasi akses sesuai permission yang diminta, tetap verifikasi sumber plugin yang kalian muat — terutama yang meminta permission tinggi seperti ReadApplicationState atau kemampuan menulis ke stdin. Biasakan memuat dari URL resmi atau file yang kalian kompilasi sendiri.
Seiring plugin mulai beranak-pinak, kalian butuh cara untuk melihat dan mengendalikannya. Di sinilah Plugin Manager (diperkenalkan di versi 0.41) berperan. Buka dengan Ctrl+o lalu p — di session mode, Plugin Manager adalah salah satu dari sedikit plugin yang bisa dipicu langsung dari keybinding default.
Plugin Manager menampilkan semua plugin yang sedang berjalan di session, lengkap dengan asalnya: apakah plugin bawaan (alias zellij:...), file lokal, atau URL web. Dari sini kalian bisa:
Kombinasikan Plugin Manager dengan konsep alias di blok plugins: alih-alih menghapal URL panjang, kalian bisa mendefinisikan alias pendek dan memakainya di layout, keybinding, dan pipes. Kalian bisa membuat alias untuk plugin kustom sendiri:
plugins {
tab-bar location="zellij:tab-bar"
status-bar location="zellij:status-bar"
monitor location="file:/home/devnull/.config/zellij/plugins/monitor.wasm"
}Setelah alias monitor terdaftar, semua lokasi yang menerima URL plugin juga menerima monitor — di layout, keybinding LaunchPlugin, maupun pipe.
Selain memuat plugin secara manual, Zellij mendukung pemuatan otomatis di latar belakang saat session dimulai. Melalui blok load_plugins di konfigurasi, plugin headless — plugin yang tidak menggambar apa pun tetapi tetap memproses event dan pipe — bisa dihidupkan di awal session tanpa perlu pane sama sekali. Kombinasi ini sangat berguna untuk widget yang harus selalu berjalan, seperti monitor status yang menunggu pesan pipe dari luar (contoh nyata di bagian berikutnya), atau plugin yang bertugas menangkap output pane untuk dicatat.
Di episode 13 kalian mengenal pipes sebagai jembatan antara proses dan pane. Pipes juga bisa diarahkan ke plugin — dan ini yang membuat plugin benar-benar bisa diprogram dari luar. Melalui zellij action pipe atau alias zpipe, kalian mengirim pesan ke plugin yang sedang berjalan (atau memuatnya jika belum ada):
zellij action pipe --name refresh --plugin file:/home/devnull/.config/zellij/plugins/monitor.wasm -- refresh
echo '{"threshold": 90}' | zellij action pipe --name configure --plugin monitorDi sisi plugin, pesan ini diterima di fase pipe sebagai PipeMessage — berisi nama pipe dan payload. Plugin bisa merespons dengan memperbarui UI, memicu action, atau bahkan mengirim balik data ke stdout pemanggil. Arah komunikasi menjadi dua arah: dunia luar mengirim perintah ke plugin, plugin mengirim hasilnya kembali.
Inilah blueprint automasi yang powerful: pane menjalankan proses panjang, output pipe menangkap hasilnya, proses luar menganalisisnya, lalu mengirim keputusan kembali ke plugin lewat action pipe. Seluruh pipeline Zellij — terminal pane, pipes, dan plugin — bekerja sebagai satu sistem yang bisa diprogram.
Perluasan wajar dari ide ini: plugin bisa saling berbicara. Sebuah plugin yang menangkap keybinding tertentu bisa meneruskan pesan ke plugin lain lewat pipe message, membentuk rantai pemrosesan di dalam satu session. Ditambah kemampuan pipes untuk memuat plugin yang belum berjalan, kalian mendapatkan arsitektur mikro di dalam Zellij: setiap plugin memegang satu tanggung jawab, dan pipes menjadi bus komunikasi yang menghubungkan mereka. Ini pola yang akan sangat membantu saat kalian mulai punya lebih dari dua atau tiga plugin dalam satu workspace.
Tip
Gunakan zpipe sebagai pintasan — itu alias untuk zellij action pipe. Karena plugin yang belum berjalan otomatis dimuat saat menerima pesan pipe, kalian bisa memakai zpipe sebagai cara "bangun dari jarak jauh": kirim satu pesan, plugin muncul dengan konfigurasi yang sudah disiapkan.
subscribe. Plugin yang tidak mendaftarkan event tidak akan menerima informasi apa pun dari host — UI-nya terlihat beku. Selalu daftarkan event yang dibutuhkan di load.load. Permission yang diminta di luar fase load ditolak. Rencanakan semua kebutuhan permission sejak awal.size atau borderless. Plugin yang menempati seluruh pane atau membawa border bisa merusak tata letak. Tentukan ukuran dan borderless true untuk plugin berbentuk bar.Episode ini memberi kalian peta lengkap ekosistem plugin Zellij. Kalian memahami bahwa seluruh UI Zellij adalah modul WASM yang berbicara lewat Zellij Message Protocol; bahwa plugin punya siklus hidup load → event → render → action; bahwa plugin bisa dimuat dari file maupun dari web; bahwa Plugin Manager (0.41) menjadi pusat kendalinya; dan bahwa pipes membuat plugin bisa diprogram dari luar.
Poin yang harus kalian bawa:
load (subscribe + permission), update, render, pipe.Ctrl+o lalu p) mengelolanya.zellij action pipe / zpipe) membuka automasi dua arah.Sekarang saatnya mengotori tangan. Di episode 16, kita membangun plugin Zellij pertama kalian dalam Rust dan WASM: struktur crate, toolchain wasm32-wasi, trait ZellijTile, render UI, dan memuatnya ke session — dari nol sampai terlihat di layar. Sampai jumpa di episode 16.