The rename: zellij → sl0ppij
Status: implemented. See commit sl0p: rename to sl0ppij behind a branding
seam.
Goal: a machine can have stock zellij and sl0ppij installed at the same time, running at the same time, without sharing a single byte of state.
Isolation checklist
All disjoint from upstream as of the rename commit:
| surface | upstream | sl0ppij | done |
|---|---|---|---|
| binary name | zellij |
sl0ppij |
✅ |
| config dir | ~/.config/zellij |
~/.config/sl0ppij |
✅ |
| cache/data dir | ProjectDirs("org","Zellij Contributors","Zellij") |
ProjectDirs("foo","sl0p","sl0ppij") |
✅ |
| system config | /etc/zellij |
/etc/sl0ppij |
✅ |
| system data | /usr/share/zellij |
/usr/share/sl0ppij |
✅ |
| socket/tmp dir | $TMPDIR/zellij-$UID |
$TMPDIR/sl0ppij-$UID |
✅ |
| log dir/file | …/zellij-log/zellij.log |
…/sl0ppij-log/sl0ppij.log |
✅ |
| env vars | ZELLIJ* |
SL0PPIJ* and ZELLIJ* (ours wins) |
✅ |
| plugin URL scheme | zellij:about |
sl0ppij:about (accepts zellij:) |
✅ |
| help / CLI text | "zellij" | "sl0ppij" | ✅ |
| default-plugin text | "zellij" | — | ⬜ needs a wasm rebuild |
| desktop/shell assets | assets/zellij.desktop, zellij.rc |
— | ⬜ packaging-only, unused so far |
Where the work actually is
Encouragingly small and centralised:
zellij-utils/src/consts.rs— the whole path story. Lines to touch:SYSTEM_DEFAULT_CONFIG_DIR(/etc/zellij, and the Windows arm)ZELLIJ_PROJ_DIR—ProjectDirs::from("", "", "Zellij")/("org", "Zellij Contributors", "Zellij")ZELLIJ_TMP_DIR—temp_dir().join(format!("zellij-{}", *UID))ZELLIJ_TMP_LOG_DIR/ZELLIJ_TMP_LOG_FILE—zellij-log,zellij.log- the non-unix arm's
tmp_dir.join("zellij") zellij-utils/src/envs.rs—ZELLIJ_ENV_KEY,SESSION_NAME_ENV_KEY,SOCKET_DIR_ENV_KEY.zellij-utils/src/cli.rs:57— clapname = "zellij"(drives every usage string and--help).zellij-utils/src/input/plugins.rs:77— builtin plugin URL scheme.Cargo.toml— the root packagename = "zellij"decides the binary name. Renaming the package is the loudest possible change against upstream. See "Strategy" below.assets/zellij.desktop,assets/zellij.rc,wix/,.github/packaging bits.- user-visible help strings —
"zellij setup --check","zellij -l compact"etc. insidedefault-plugins/status-bartips andabout.
What was left out, on purpose
default-plugins/*strings (the About screen, status-bar tips) still say "zellij". They live inside prebuilt.wasmblobs inzellij-utils/assets/plugins/, so changing them means rebuilding the plugins and committing new binaries — a separate, chunky commit.assets/zellij.desktop/zellij.rcare only used by distro packaging and the Windows build, neither of which we ship yet.- Crate names (
zellij-utils,zellij-tile, …) — see below.
Strategy: one seam, not a sed
Do not sed -i s/zellij/sl0ppij/g the tree. Every touched upstream line is a
rebase conflict forever, and there are ~3300 upstream commits of future rebases.
Instead:
- Introduce a single branding module (
zellij-utils/src/branding.rs) withpub const APP: &str = "sl0ppij";plus derived consts (config dir name, tmp prefix, log names, env prefix, plugin scheme). - Point the ~15 sites above at it. Each becomes a one-line diff that reads
branding::APPinstead of a literal — small, stable, easy to re-apply. - Keep the crate/package names as
zellij*. The binary name is set with[[bin]] name = "sl0ppij"instead of renaming the package, so all the intra-workspacezellij-utils/zellij-tiledeps, plugin APIs and the0.45.0+sl0p1version trick keep working untouched. Nothing user-facing says "zellij" and nothing internal has to move. ZELLIJ_EXECUTABLE_LOCATION/ self-exec: the client re-execs itself to spawn the server. Verify it resolves viacurrent_exe()and not a hardcoded"zellij"on$PATH, or a sl0ppij client will start a zellij server.
Decided: env vars keep both spellings
Renaming ZELLIJ=0 → SL0PPIJ=0 outright would break every third-party thing
that detects "am I in a multiplexer" (shell prompts, starship, nested-session
guards, and our own pi-ext).
So both are exported, and SL0PPIJ* takes precedence on read:
| variable | ours | upstream's |
|---|---|---|
| marker | SL0PPIJ |
ZELLIJ |
| session | SL0PPIJ_SESSION_NAME |
ZELLIJ_SESSION_NAME |
| pane | SL0PPIJ_PANE_ID |
ZELLIJ_PANE_ID |
| socket dir | SL0PPIJ_SOCKET_DIR |
ZELLIJ_SOCKET_DIR |
| config file/dir, layout dir | SL0PPIJ_CONFIG_*, SL0PPIJ_LAYOUT_DIR |
ZELLIJ_CONFIG_*, ZELLIJ_LAYOUT_DIR |
branding::import_compat_env() runs first thing in main() and folds an
inherited ZELLIJ_* into its SL0PPIJ_* spelling, which is what makes the
clap-derived arguments honour both (clap accepts only one env name per arg).
Note the spelling is SL0PPIJ (zero), matching the binary name.
Because both spellings are exported, a pi running inside sl0ppij still sees
$ZELLIJ, so pi-ext needed no changes.
Verification (all performed)
Unit tests in branding.rs: no shipped default path contains the string
zellij; env precedence is ours-then-upstream; set_env_var writes both
spellings; every pair differs only by prefix.
Suites: zellij-utils 471 passed, zellij-server 1499 passed.
Live, against a box already running stock zellij:
$ sl0ppij --version -> sl0ppij 0.45.0+sl0p1
$ sl0ppij setup --check -> ~/.config/sl0ppij, ~/.cache/sl0ppij,
/usr/share/sl0ppij
$ ls -d /tmp/sl0ppij-1000 /tmp/zellij-1000 -> both exist, disjoint
$ zellij list-sessions -> 3 sessions
$ sl0ppij list-sessions -> "No active sl0ppij sessions found."
Env precedence, end to end:
| set | resulting CONFIG DIR |
|---|---|
ZELLIJ_CONFIG_DIR=/tmp/cfg-upstream |
/tmp/cfg-upstream |
SL0PPIJ_CONFIG_DIR=/tmp/cfg-ours |
/tmp/cfg-ours |
| both | /tmp/cfg-ours |
Config: the rebranded config/config.kdl loads under the renamed binary
([CONFIG FILE]: Well defined.).
