zellij
Skill1 starsChanged 51 days agoMITView on GitHub
Session, layout, and pane management for Zellij terminal multiplexer. Use when managing Zellij sessions, layouts, or automating terminal workflows.
2 other projects use a version of this.
Adopted by
Most recently taken up by
- Voronenko/ai-filestheir own version, first seen Nov 1, 2026
- tarrragon/claude-skillstheir own version, first seen Sep 1, 2026
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 2
- tarrragon/claude-skills★ 1same name
- Voronenko/ai-files★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository113 other files it gives its agents.
- AGENTS.mdAGENTS.md
- ac-ideateSkill
- ac-listSkill
- ac-roadmapSkill
- agentbridge-mcpSkill
- almanacSkill
- almquist-shellSkill
- ansible-fleetSkill
- apfsSkill
- apple-siliconSkill
- arena-actorsSkill
- asustor-nasSkill
- a-teamSkill
- atem-miniSkill
- at-tuiSkill
- autoresearchSkill
- babysitSkill
- bonzibuddySkill
- bop-brainstormSkill
- bop-catalogSkill
- bop-onSkill
- bop-teamSkill
- bop-workflowSkill
- bsd-portabilitySkill
- code-refactoringSkill
- codex-personasSkill
- context-graphSkill
- councilSkill
- datadog-backupSkill
- dd-tagsSkill
- delegateSkill
- deming-pdsaSkill
- deterministic-replaySkill
- dispatch-nuSkill
- durable-commitSkill
- elixir-gastown-opsSkill
- ergo-ircSkill
- esp32-tang-bridgeSkill
- fleet-evalSkill
- fleet-ircSkill
- freebsd-build-vmSkill
- freebsd-piSkill
- freebsdSkill
- ganttSkill
- gastown-opsSkill
- gastown-slingSkill
- gh-authSkill
- gitea-releaseSkill
- gitea-runnerSkill
- henshuSkill
- irclaw-cluster-opsSkill
- irclaw-research-teamSkill
- irc-taskSkill
- jail-factorySkill
- jjSkill
- jobcard-systemSkill
- kubernetesSkill
- leptosSkill
- loreSkill
- lower-bound-reviewSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 1 is distinctive, and 4 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈1
Distinctive · estimate
This author's own choices. Worth a look.
4
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 11
Always read it — never write "pmr", "bop", or any literal name.
- Distinctive: line 145
Always use the full path:
- Very specific: line 223
All three projects (bop, efi, zam) use the same zellij_session pattern:
- Very specific: line 280
Hardcoding session names: Never write literal names like "bop" or "efi" — always read $ZELLIJ_SESSION_NAME
- Very specific: line 284
Using Ctrl+O for subshell drop: Use bare ! key instead, as Ctrl+O is intercepted by Zellij
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Zellij — Session, Layout, and Pane Management
Core rule: never hardcode the session name
Zellij injects $ZELLIJ_SESSION_NAME into every process inside a session.
Always read it — never write "pmr", "bop", or any literal name.
# Nushell — canonical zellij_session function used in all dispatch.nu files
def zellij_session [] {
if "ZELLIJ_SESSION_NAME" in $env {
$env.ZELLIJ_SESSION_NAME
} else {
# Running outside Zellij — auto-detect
let sessions = (^zellij list-sessions --no-formatting 2>/dev/null
| lines | where { |l| ($l | str trim) != "" })
if ($sessions | length) == 1 {
$sessions | first | str trim
} else if ($sessions | length) > 1 {
error make { msg: $"Multiple sessions active: ($sessions | str join ', '). Set ZELLIJ_SESSION_NAME." }
} else {
error make { msg: "No Zellij session found. Start one with: zellij --session <name>" }
}
}
}# Bash equivalent
SESSION=${ZELLIJ_SESSION_NAME:-$(zellij list-sessions --no-formatting | head -1 | awk '{print $1}')}Sessions
# Start or resume (canonical pattern — no hardcoded name)
zellij attach --create bop # bop project
zellij attach --create efi # efi/dub project
zellij attach --create zam # zam project
# List active sessions
zellij list-sessions
zellij list-sessions --no-formatting # machine-readable, no ANSI
# Detach without killing
Ctrl+p d
# Kill a session
zellij kill-session <name>Layouts
Each project has a .kdl layout file:
| Project | Layout | Launch |
| bop | layouts/bop.kdl | zellij --session bop --layout layouts/bop.kdl |
| efi | layouts/efi.kdl | zellij --session efi --layout layouts/efi.kdl |
| zam | layouts/zam.kdl | zellij --session zam --layout layouts/zam.kdl |
bop.kdl structure
Two tabs: bop (primary) and dispatch (engine runners).
bop tab (7-pane card lifecycle layout):
┌──────────┬──────────────────┬──────────────────┐
│ BOARD │ SPEC │ QA │
│ watch │ what to build │ did it work? │
│ status ├──────────────────┼──────────────────┤
│ │ STDOUT │ STDERR │
│ │ agent output │ agent errors │
├──────────┴──────────────────┴──────────────────┤
│ INSPECTOR — bop inspect <id> │
├─────────────────────────────────────────────────┤
│ SHELL — bop commands (focus/retry/approve) │
└─────────────────────────────────────────────────┘dispatch tab: dispatcher (75%) | merge-gate (75%) | dispatch-shell (25%)
KDL quick reference
layout {
default_tab_template {
children
pane size=2 borderless=true {
plugin location="zellij:status-bar"
}
}
tab name="main" focus=true {
pane split_direction="horizontal" {
pane name="top" size="70%" { command "nu" }
pane name="bottom" size="30%" { command "nu" }
}
}
tab name="logs" {
pane name="log-tail" {
command "nu"
args "-c" "tail -f /tmp/bop.log"
}
}
}split_direction="horizontal" = children stacked top/bottom.
split_direction="vertical" = children side by side.
Spawning panes from scripts
# Fire-and-forget — pane closes when command exits
zellij --session $ZELLIJ_SESSION_NAME run \
--name my-card \
--close-on-exit \
-- sh -c "nu /path/to/adapter.nu ..."
# Inspectable — pane stays open after command exits (for debugging)
zellij --session $ZELLIJ_SESSION_NAME run \
--name my-card \
-- sh -c "nu /path/to/adapter.nu ..."
# Open a new tab
zellij --session $ZELLIJ_SESSION_NAME action new-tab --name "logs"
# Navigate to an existing tab by name
zellij --session $ZELLIJ_SESSION_NAME action go-to-tab-name "bop"Use --close-on-exit for: dispatch worker panes (adapter runs).
Omit --close-on-exit for: interactive panes, debugging, long-lived agents.
PATH gotcha — critical for dispatch workers
nu (Nushell) is not in PATH inside Zellij panes spawned via zellij run.
Always use the full path:
# WRONG — fails silently in detached pane context
nu dispatch.nu mark-done 022
# CORRECT
/opt/homebrew/bin/nu dispatch.nu mark-done 022Same applies to bop binary: use $ROOT/target/debug/bop or add to PATH explicitly:
export PATH=$HOME/bop/target/debug:$PATHSuspending TUI to drop to shell (! key in bop ui)
Do NOT use Ctrl+O — that is Zellij's built-in Session mode key and will
be intercepted before reaching any app running inside a pane.
bop ui uses ! (normal mode, no modifier) for the subshell drop, inspired
by vim's :! convention. Zellij does not intercept bare printable keys in
normal mode.
// Triggered by KeyCode::Char('!') in the AppEvent::Key handler
// Suspend TUI
crossterm::terminal::disable_raw_mode()?;
crossterm::execute!(stdout(), crossterm::terminal::LeaveAlternateScreen)?;
// Run shell in card's worktree
std::process::Command::new(std::env::var("SHELL").unwrap_or("sh".into()))
.current_dir(&card_worktree)
.status()?;
// Restore TUI
crossterm::execute!(stdout(), crossterm::terminal::EnterAlternateScreen)?;
crossterm::terminal::enable_raw_mode()?;
// trigger full redrawThis does NOT open a new Zellij pane — it suspends and restores within the existing pane. Works correctly inside Zellij because alternate screen is stacked (Zellij has its own alternate screen above it).
Zellij keys already taken — do NOT use in TUI apps
These are intercepted by Zellij before reaching pane content:
| Key | Zellij action |
Ctrl+O | Session mode (session manager) |
Ctrl+P | Pane mode |
Ctrl+T | Tab mode |
Ctrl+N | New pane |
Ctrl+H | Move pane focus left |
Ctrl+B | Scroll up |
Ctrl+F | Scroll down |
Ctrl+G | Unlock (in locked mode) |
Safe to use in TUI apps: bare printable keys (!, e, n, r, etc.),
Alt+<key> (Zellij uses Alt+arrow but not most Alt+letter combos),
function keys F1–F12.
Key bindings (Zellij default — navigation)
| Key | Action |
Alt + arrow | Move focus between panes |
Alt + n | New pane |
Alt + [ / ] | Previous / next tab |
Ctrl+p d | Detach from session (session stays alive) |
Ctrl+p z | Toggle pane fullscreen |
Ctrl+p x | Close focused pane |
Ctrl+p r | Rename focused pane |
Integration with dispatch.nu (all three projects)
All three projects (bop, efi, zam) use the same zellij_session pattern:
dispatch.nu run --wave N --yes
→ zellij_session [] # reads $ZELLIJ_SESSION_NAME
→ zellij --session <name> run --name <spec-id> --close-on-exit -- sh -c <AC cmd>
→ pane runs Auto-Claude agent
→ on exit: mark-done / mark-failed called via /opt/homebrew/bin/nuLock file (dispatch-lock.json) records session: (zellij_session) so rescue
operations can target the correct session.
Nested panes — bop ui card tabs (spec 029 future)
Each running card will optionally get a tab with nested panes:
- Top pane: adapter stdout (live)
- Bottom pane: log tail (
logs/stderr)
Tab naming convention: card-<id> (e.g. card-feat-auth).
Created via zellij action new-tab --name card-<id>, then pane splits via
zellij action new-pane --direction down.
Projects and session names
| Project | Canonical session | Layout |
| bop | bop | layouts/bop.kdl |
| efi (dub) | efi | layouts/efi.kdl |
| zam | zam | layouts/zam.kdl |
These are current names — they WILL change. Always use $ZELLIJ_SESSION_NAME.
Quick reference
# Get current session name (canonical method)
SESSION=${ZELLIJ_SESSION_NAME:-$(zellij list-sessions --no-formatting | head -1 | awk '{print $1}')}
# Start/attach to session
zellij attach --create <session-name>
# List sessions
zellij list-sessions --no-formatting
# Run command in new pane
zellij --session $SESSION run --name pane-name --close-on-exit -- command
# Detach without killing
Ctrl+p d
# Navigate between panes
Alt + arrow keysCommon mistakes
- Hardcoding session names: Never write literal names like "bop" or "efi" — always read
$ZELLIJ_SESSION_NAME - Using Ctrl+O in TUI apps: Zellij intercepts this key for Session mode — use bare printable keys like
!instead - Not using full paths to binaries:
nuand other tools are not in PATH inside spawned panes — use full paths like/opt/homebrew/bin/nu - Forgetting --close-on-exit: Worker panes should close when done to avoid resource leaks
- Using Ctrl+O for subshell drop: Use bare
!key instead, as Ctrl+O is intercepted by Zellij
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

