Zellij per-project auto-layouts on cd (flakes-u0yw)
Spec
When cd’ing to a project directory inside Zellij, automatically open a new tab with a layout matching the project’s configuration.
Preset Layout Files
Location: modules/home/programs/zellij/layouts/ → deployed to ~/.config/zellij/layouts/
claude_terminal.kdl — claude on left (50%), terminal on right (50%)
claude_beans-terminal.kdl — claude on left (50%), right side split: beans-serve --cors-origin "*" on top, stacked terminals below
Presets have no cwd — the fish hook passes --cwd at open time, keeping presets project-agnostic.
Layout Resolution Order
.zellij-layout.kdlfile in project root (inline layout, highest priority)ZELLIJ_LAYOUT_{USERNAME}env var (e.g.,ZELLIJ_LAYOUT_yj=claude_beans-terminal) — only if$USERmatchesZELLIJ_LAYOUTenv var — generic fallback- Neither → do nothing
Env vars are set via .envrc (direnv), e.g.:
export ZELLIJ_LAYOUT=claude_terminal
export ZELLIJ_LAYOUT_yj=claude_beans-terminal
export ZELLIJ_LAYOUT_yjpark=claude_terminal
Fish Hook Logic
Extend existing PWD hook in modules/home/programs/fish/init/zellij.fish:
- Not in Zellij? → skip
- Resolve project root (existing git root detection)
- Determine layout (resolution order above)
- Guard: check
__zellij_opened_layoutsfish global var — if project root already in list → skip zellij action new-tab --layout {layout_file} --cwd {project_root}- Add project root to
__zellij_opened_layouts
State resets when fish session ends. Re-opening after terminal restart is acceptable.
Relationship to existing bean
Related to flakes-kxju (predefined layout files) — this is the broader feature that subsumes it.
Tasks
- Create
claude_terminal.kdlpreset layout - Create
claude_beans-terminal.kdlpreset layout - Extend
zellij.fishPWD hook with layout resolution and auto-open logic - Test: cd to project with
ZELLIJ_LAYOUTset →zzapplies layout to current tab - Test: stacked layout, tab/status bars, clear buffer all working
- Test:
ZELLIJ_LAYOUT_yjoverridesZELLIJ_LAYOUTfor useryj - Test:
.zellij-layout.kdlin project root takes priority (not yet tested)