--- frontmattername: zjj
description: "zjj workspace isolation expert v0.4.0. Use when the user says 'zjj', 'isolated workspace', 'spawn workspace', 'workspace isolation', or needs to stand up, manage, sync, merge, or remove isolated jj workspaces with Zellij session integration. Covers 56 commands: init, add, remove, list, status, focus, switch, attach, sync, diff, done, abort, spawn, work, agents, ai, bookmark, template, pane, checkpoint, undo, revert, retry, rollback, recover, integrity, lock, unlock, claim, yield, queue, batch, events, whereami, whoami, context, introspect, query, can-i, contract, examples, validate, whatif, wait, schema, export, import, rename, pause, resume, clone, backup, clean, doctor, dashboard, config, completions."
argument-hint: [subcommand or workflow question]
You are an expert in zjj (v0.4.0), the workspace isolation manager that combines Jujutsu (jj) workspaces with Zellij terminal sessions. When the user asks for an isolated workspace, you use zjj commands — never raw jj workspace commands.
Core Mental Model
- •zjj = jj workspaces + Zellij tabs + session state — one command stands up an isolated working directory with its own terminal session
- •Each session gets: a jj workspace (separate working directory), a Zellij tab (terminal environment), and tracked state (in
.zjj/state.db)
- •Workspaces share the repo — changes are visible across workspaces via
jj log, but working copies are independent
- •
zjj done is the clean exit — squash-merges work back to main, cleans up workspace and session
- •Dependencies: jj (required), zellij (required), beads (optional), claude (optional)
Architecture
project/ # main jj repo
├── .zjj/
│ ├── state.db # SQLite session tracking database
│ ├── config.toml # project-level configuration
│ └── layouts/ # generated Zellij layout files (KDL)
├── .beads/
│ └── issues.jsonl # bead issue tracker (JSONL)
└── ../lewis__workspaces/ # workspace directory (configurable via workspace_dir)
├── feature-auth/ # zjj session workspace
│ ├── .cursorrules # AI agent discovery (Cursor/Windsurf)
│ └── .ai-instructions.md # AI agent discovery (Claude/generic)
├── bugfix-123/ # another session workspace
└── ai-sandbox/ # spawned agent workspace
Each zjj add creates:
- •A jj workspace via
jj workspace add --name <name> <path>
- •A Zellij tab named
zjj:<name> (context-dependent: new tab if inside Zellij, new session if outside)
- •A session record in state.db (SQLite) with status
Creating → Active
Session State Machine
Sessions follow a strict lifecycle with validated transitions:
Creating ──→ Active ──→ Completed
│ │ ↘ ↑
│ │ Paused ─┘
│ ↓
└──→ Failed ←── Syncing → Synced → Active
| State | Allowed Operations | Transitions To |
|---|
Creating | (none — transient) | Active, Failed |
Active | status, diff, focus, remove, sync, done, abort, checkpoint | Syncing, Paused, Completed, Failed |
Syncing | (transient) | Synced, Failed |
Synced | (transient) | Active, Paused, Completed |
Paused | status, focus, remove, resume | Active, Completed |
Completed | remove, undo | (terminal; undo only if not pushed) |
Failed | remove, recover | (terminal; recover auto-diagnoses and fixes) |
Database Schema (state.db)
CREATE TABLE sessions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT UNIQUE NOT NULL,
status TEXT CHECK(status IN ('creating','active','paused','completed','failed')),
workspace_path TEXT NOT NULL,
branch TEXT,
created_at INTEGER, -- unix timestamp
updated_at INTEGER, -- unix timestamp (auto-updated via trigger)
last_synced INTEGER,
metadata TEXT -- JSON blob
);
Internal Command Flows
zjj add — 8-Step Creation
- •Validate name: ASCII alphanumeric/dash/underscore, starts with letter, max 64 chars
- •Check uniqueness: no existing session with same name
- •Resolve workspace path:
{repo_root}/{workspace_dir}/{name} (creates parent dir if needed)
- •Create jj workspace: runs
jj workspace add --name <name> <path>
- •Insert DB record: status =
Creating
- •Execute post_create hooks: sequential, CWD = workspace dir, failure → status =
Failed
- •Update status:
Active
- •Open Zellij: new tab (inside Zellij) or new session (outside Zellij), using layout template
zjj done — 9-Phase Merge
- •Validate location: must be in workspace OR use
-w <name> to target a workspace from main — exit code 2 only if neither applies
- •Build preview (if
--dry-run or via zjj whatif done): uncommitted files, commits to merge, conflicts, bead to close
- •Get uncommitted files:
jj status --no-pager, parse M/A/D/R lines
- •Commit changes:
jj commit -m "<message>" (auto-generated or custom)
- •Check conflicts:
jj log -r @..@ for divergent commits
- •Get commits to merge: parse change_id, commit_id, description, timestamp from
jj log
- •Merge to main:
jj workspace abandon --name <name> — exit code 3 on conflict
- •Update beads: find linked bead in
.beads/issues.jsonl, set status to closed
- •Cleanup: delete workspace directory (unless
--keep-workspace)
Note: done is reversible — zjj undo can roll it back within 24 hours, as long as changes haven't been pushed to remote.
If step 7 returns exit code 3 — exponential backoff with checkpoint safety:
The full safe sequence: checkpoint first (safety snapshot), then sync + retry with backoff, then recover on exhaustion. Use zjj retry (not a manual re-invocation of done) — it retries the exact last failed command.
# 1. Safety checkpoint BEFORE the retry loop
zjj checkpoint create -d "Before merge retry loop"
# 2. Backoff retry loop
WAIT=2
MAX_RETRIES=6
RETRY=0
EXIT_CODE=3
while [ $RETRY -lt $MAX_RETRIES ] && [ $EXIT_CODE -ne 0 ]; do
# Re-sync onto latest main — stale state is the #1 cause of repeated conflicts
zjj sync
SYNC_EXIT=$?
if [ $SYNC_EXIT -ne 0 ]; then
echo "Sync conflict — resolve manually in workspace, then retry."
break
fi
# Use zjj retry — retries the last failed command (the done)
zjj retry
EXIT_CODE=$?
[ $EXIT_CODE -eq 0 ] && break
RETRY=$((RETRY + 1))
echo "Merge attempt $((RETRY + 1))/$((MAX_RETRIES + 1)) — waiting ${WAIT}s..."
sleep $WAIT
WAIT=$((WAIT * 2))
[ $WAIT -gt 60 ] && WAIT=60
done
# 3. On exhaustion: recover, then flag user
if [ $EXIT_CODE -ne 0 ]; then
echo "EXHAUSTED: merge retries failed."
zjj recover --diagnose # diagnose what's broken without auto-fixing
echo "Workspace preserved. File a bead. Flag user for manual resolution."
# DO NOT abort or remove the workspace — it is evidence.
# Rollback to checkpoint if state is corrupt:
# zjj rollback --to <checkpoint-id> <session-name>
fi
zjj spawn — Agent Isolation
- •Validate location: must be on main branch (not in workspace)
- •Validate bead: check
.beads/issues.jsonl, must be open or ready
- •Create workspace:
jj workspace add --name <bead_id> <path>
- •Write agent discovery files:
.cursorrules and .ai-instructions.md in workspace
- •Update bead: status →
in_progress
- •Spawn agent subprocess: CWD = workspace, env vars set (see below)
- •On success (exit 0): merge via
jj workspace abandon, bead → completed, cleanup
- •On failure (exit non-0): bead stays
in_progress, optionally cleanup
Agent Environment Variables:
- •
ZJJ_BEAD_ID — the bead being worked on
- •
ZJJ_WORKSPACE — absolute path to workspace
- •
ZJJ_AGENT_ID — agent identifier for tracking
- •
ZJJ_SESSION — current session name
- •
ZJJ_ACTIVE=1 — signals agent is in zjj context
Exit Codes
| Code | Meaning | Context |
|---|
| 0 | Success | All commands |
| 1 | Validation error | Invalid input, bad name, missing args |
| 2 | Not in workspace | zjj done run from main instead of workspace |
| 3 | Merge conflict | zjj done encountered conflicts during merge |
| 4 | Other error | Command failures, hook failures, DB errors |
Standing Up an Isolated Workspace
Quick Start (Most Common)
zjj init # first time only — initialize zjj in a jj repo
zjj add feature-auth # create isolated workspace + Zellij tab
# You're now in an isolated workspace. Work freely.
zjj done # merge back to main, clean up
Full Workflow
# 1. Initialize (once per repo)
zjj init
# 2. Create isolated workspace
zjj add feature-auth # standard layout (claude + beads + status panes)
zjj add quick-fix -t minimal # minimal layout (just a shell)
zjj add experiment -t full # full layout (all panes)
zjj add headless --no-open # create workspace without opening Zellij tab
zjj add feature-x -b zjj-abc12 # associate with bead zjj-abc12
# 3. Work in isolation
# Your workspace is at ../lewis__workspaces/feature-auth/
# All jj commands work normally within the workspace
# 4. Check status
zjj status feature-auth # detailed session info
zjj list # all active sessions
zjj list --state active # filter by state
# 5. Stay synced with main
zjj sync feature-auth # rebase workspace onto latest main
zjj sync # sync current workspace
zjj sync --all # sync all active sessions
# 6. Review changes
zjj diff feature-auth # full diff against main
zjj diff feature-auth --stat # summary only
# 7. Complete work
zjj done # merge to main + cleanup
zjj done -m "feat: auth system" # custom commit message
zjj done --squash # squash all commits into one
zjj done --dry-run # preview without executing
zjj done --keep-workspace # merge but keep workspace alive
zjj done --detect-conflicts # check for conflicts before merging
Complete CLI Reference (56 Commands)
1. Initialization
| Command | Purpose |
|---|
zjj init | Initialize zjj in a jj repo (creates .zjj/ directory) |
zjj init --json | JSON output for programmatic use |
2. Session Creation (Manual)
| Command | Purpose |
|---|
zjj add <name> | Create workspace + Zellij tab |
zjj add <name> -t <template> | Use layout: minimal, standard, full, split, review |
zjj add <name> --no-open | Create workspace without Zellij tab |
zjj add <name> --no-zellij | Skip Zellij integration (non-TTY) |
zjj add <name> --no-hooks | Skip post_create hooks |
zjj add <name> --idempotent | Succeed if session already exists |
zjj add <name> -b <bead_id> | Associate with bead/issue ID |
zjj add <name> --dry-run | Preview without creating |
3. Session Completion
| Command | Purpose |
|---|
zjj done | Complete work: merge to main + cleanup |
zjj done -w <name> | Complete specific workspace from anywhere |
zjj done -m "msg" | Merge with custom message |
zjj done --squash | Squash all commits into one |
zjj done --dry-run | Preview merge |
zjj done --keep-workspace | Merge but preserve workspace |
zjj done --detect-conflicts | Check for conflicts before merging |
zjj done --no-bead-update | Skip bead status update |
zjj abort | Discard workspace without merging |
zjj abort -w <name> | Discard specific workspace |
zjj abort --keep-workspace | Keep files, just remove from tracking |
4. Session Removal
| Command | Purpose |
|---|
zjj remove <name> | Remove session + workspace (with confirmation) |
zjj remove <name> -f | Force removal without confirmation |
zjj remove <name> --merge | Squash-merge to main before removal |
zjj remove <name> -k | Remove session but keep jj branch |
zjj remove <name> --idempotent | Succeed if session doesn't exist |
5. Session List & Status
| Command | Purpose |
|---|
zjj list | List active sessions |
zjj list --all | Include completed and failed sessions |
zjj list --verbose | Show workspace paths and bead titles |
zjj list --bead <id> | Filter by bead ID |
zjj list --agent <name> | Filter by agent owner |
zjj list --state <state> | Filter by state (created, working, ready, merged, etc.) |
zjj status | Show all session statuses |
zjj status <name> | Detailed status for one session |
zjj status --watch | Continuously update (1s refresh) |
6. Navigation & Focus
| Command | Purpose |
|---|
zjj focus <name> | Switch to session's Zellij tab (inside Zellij) |
zjj focus | Interactive session selection |
zjj attach <name> | Attach to Zellij session from outside (shell → Zellij) |
zjj switch <name> | Navigate between workspaces |
zjj switch --show-context | Switch and show session details |
zjj dashboard | Launch interactive TUI kanban dashboard |
7. Sync & Diff
| Command | Purpose |
|---|
zjj sync <name> | Rebase session workspace onto main |
zjj sync | Sync current workspace |
zjj sync --all | Sync all active sessions |
zjj diff <name> | Diff between session and main |
zjj diff <name> --stat | Summary diffstat only |
8. Version Control (Bookmarks)
| Command | Purpose |
|---|
zjj bookmark list [session] | List bookmarks in session workspace |
zjj bookmark list --all | Show all bookmarks including remote |
zjj bookmark create <name> | Create bookmark at current revision |
zjj bookmark create -p <name> | Create and push to remote |
zjj bookmark delete <name> | Delete a bookmark |
zjj bookmark move --to <rev> <name> | Move bookmark to different revision |
9. Checkpoint & Undo
| Command | Purpose |
|---|
zjj checkpoint create -d "desc" | Create checkpoint with description |
zjj checkpoint list | List all available checkpoints |
zjj checkpoint restore <id> | Restore sessions to checkpoint |
zjj undo | Revert most recent done (24hr window) |
zjj undo -l | List undo history |
zjj undo --dry-run | Preview undo |
zjj revert <name> | Revert specific session merge |
zjj rollback --to <cp> <session> | Rollback session to checkpoint |
zjj retry | Retry the last failed operation |
10. Agent Management
| Command | Purpose |
|---|
zjj agents | List all active agents |
zjj agents --all | Include stale agents |
zjj agents --session <name> | Filter by session |
zjj agents register | Register as an agent |
zjj agents register --id <id> | Register with specific ID |
zjj agents register -s <session> | Associate with session |
zjj agents heartbeat | Send heartbeat to indicate liveness |
zjj agents heartbeat -c <cmd> | Report current command |
zjj agents status | Show current agent status |
zjj agents unregister | Unregister as an agent |
11. Agent Spawning
| Command | Purpose |
|---|
zjj spawn <bead_id> | Spawn workspace + run Claude agent |
zjj spawn <bead_id> -b | Run agent in background |
zjj spawn <bead_id> --agent-command=<cmd> | Use custom agent |
zjj spawn <bead_id> --agent-args <args> | Pass additional arguments |
zjj spawn <bead_id> --timeout <secs> | Set timeout (default: 14400s) |
zjj spawn <bead_id> --no-auto-merge | Don't merge on success |
zjj spawn <bead_id> --no-auto-cleanup | Don't cleanup on failure |
zjj work <name> | Create workspace + register agent |
zjj work <name> -b <bead_id> | Associate with bead |
zjj work <name> --agent-id <id> | Register with specific agent ID |
zjj work <name> --no-zellij | Don't create Zellij tab |
zjj work <name> --no-agent | Don't register as agent |
zjj work <name> --idempotent | Reuse existing session |
zjj broadcast <message> | Send message to all active agents |
zjj broadcast --agent-id <id> <msg> | Send as specific agent |
12. AI Integration
| Command | Purpose |
|---|
zjj ai status | AI-optimized status with guided next action |
zjj ai workflow | Show 7-step parallel agent workflow |
zjj ai quick-start | Show essential commands |
zjj ai next | Get single next action with copy-paste command |
zjj whereami | Returns 'main' or 'workspace:<name>' |
zjj whoami | Returns agent ID or 'unregistered' |
zjj context | Show complete environment context |
zjj context --field <path> | Extract single field |
zjj context --no-beads | Skip beads database query (faster) |
zjj context --no-health | Skip health checks (faster) |
13. Introspection & Query
| Command | Purpose |
|---|
zjj introspect | Discover zjj capabilities |
zjj introspect <command> | Inspect specific command |
zjj introspect --ai | AI-optimized output |
zjj introspect --env-vars | Show environment variables |
zjj introspect --workflows | Show common workflow patterns |
zjj introspect --session-states | Show valid state transitions |
zjj query session-exists <name> | Check if session exists |
zjj query session-count | Count active sessions |
zjj query can-run | Check if zjj can run |
zjj query suggest-name <pattern> | Suggest next available name |
zjj doctor | Run system health checks |
zjj doctor --fix | Auto-fix issues where possible |
zjj doctor --dry-run | Preview what would be fixed |
zjj doctor --verbose | Show detailed progress |
zjj can-i <action> [resource] | Check if action is permitted |
zjj contract [command] | Show command contracts |
zjj examples [command] | Show usage examples |
zjj examples --use-case <case> | Filter by use case |
zjj validate <command> [args]... | Pre-validate inputs |
zjj whatif <command> [args]... | Preview command effects |
14. Template Management
| Command | Purpose |
|---|
zjj template list | List all available templates |
zjj template create <name> | Create a new template |
zjj template create -d "desc" <name> | Create with description |
zjj template create -f <file> <name> | Import from KDL file |
zjj template create -b <base> <name> | Use builtin as base (minimal, standard, full, split, review) |
zjj template show <name> | Show template details |
zjj template delete -f <name> | Delete without confirmation |
15. Integrity & Recovery
| Command | Purpose |
|---|
zjj integrity validate <workspace> | Validate workspace integrity |
zjj integrity repair <workspace> | Repair corrupted workspace |
zjj integrity repair -f <workspace> | Repair without confirmation |
zjj integrity backup list | List available backups |
zjj integrity backup restore <id> | Restore from backup |
zjj integrity backup restore -f <id> | Restore without confirmation |
zjj recover [session] | Recover from inconsistent state |
zjj recover --diagnose | Only diagnose, don't fix |
zjj recover --op <id> | Restore to specific operation ID |
zjj recover --last | Restore to previous operation |
zjj recover --list | List operation log |
16. Locking & Coordination
| Command | Purpose |
|---|
zjj claim <resource> | Acquire exclusive lock on resource |
zjj claim -t <secs> <resource> | Lock with timeout (default: 60s) |
zjj yield <resource> | Release exclusive lock |
zjj lock <session> | Acquire lock on session |
zjj lock --ttl <secs> <session> | Lock with specific TTL |
zjj lock --agent-id <id> <session> | Lock as specific agent |
zjj unlock <session> | Release lock on session |
zjj unlock --agent-id <id> <session> | Unlock as specific agent |
zjj queue --list | List all queue entries |
zjj queue --add <workspace> | Add workspace to queue |
zjj queue --add <ws> --bead <id> | Add with bead association |
zjj queue --add <ws> --agent <id> | Add with agent assignment |
zjj queue --add <ws> --priority <N> | Add with priority (1-10, default: 5) |
zjj queue --next | Get next pending entry |
zjj queue --remove <workspace> | Remove from queue |
zjj queue --status <workspace> | Check workspace status |
zjj queue --stats | Show queue statistics |
17. Batch & Events
| Command | Purpose |
|---|
zjj batch <cmd> <cmd> ... | Execute multiple commands |
zjj batch -f <file> | Execute commands from file |
zjj batch --atomic <cmds> | All or nothing execution |
zjj batch --stop-on-error <cmds> | Stop on first failure |
zjj events | View recent events |
zjj events --follow | Stream events in real-time |
zjj events -l <count> | Limit number of events |
zjj events --session <name> | Filter by session |
zjj events --type <type> | Filter by event type |
18. Pane Management
| Command | Purpose |
|---|
zjj pane focus <session> [pane] | Focus specific pane |
zjj pane focus -d <dir> <session> | Focus pane in direction (up, down, left, right) |
zjj pane list <session> | List panes in session |
zjj pane next <session> | Focus next pane |
19. Import & Export
| Command | Purpose |
|---|
zjj export [session] | Export session state |
zjj export <session> -o <file> | Export to file |
zjj import <file> | Import session state |
zjj import -f <file> | Force overwrite existing |
zjj import --skip-existing <file> | Skip existing sessions |
zjj import --dry-run <file> | Preview import |
20. Wait & Schema
| Command | Purpose |
|---|
zjj wait session-exists <name> | Wait for session to exist |
zjj wait session-unlocked <name> | Wait for session to be unlocked |
zjj wait healthy | Wait for healthy state |
zjj wait session-status <name> | Wait for specific status |
zjj wait -t <secs> <condition> | Set timeout (default: 30s) |
zjj wait -i <secs> <condition> | Set polling interval (default: 1s) |
zjj schema | Show all JSON schemas |
zjj schema <name> | Show specific schema |
zjj schema --list | List available schemas |
21. Session Lifecycle
| Command | Purpose |
|---|
zjj rename <old> <new> | Rename a session |
zjj pause [name] | Pause an active session |
zjj resume [name] | Resume a paused session |
zjj clone <source> <dest> | Clone a session |
zjj clone --no-zellij <src> <dest> | Clone without Zellij |
22. Backup & Maintenance
| Command | Purpose |
|---|
zjj backup --create | Create backups of all databases |
zjj backup --list | List all available backups |
zjj backup --restore <db> | Restore database (state.db, beads.db, queue.db) |
zjj backup --restore <db> -t <ts> | Restore specific timestamp (YYYYMMDD-HHMMSS) |
zjj backup --status | Show backup status and retention |
zjj backup --retention | Apply retention policy |
zjj clean | Remove stale sessions |
zjj clean --dry-run | Preview stale sessions |
zjj clean -f | Force clean |
zjj clean --periodic | Run as periodic daemon (1hr interval) |
zjj clean --age-threshold <secs> | Set age threshold (default: 7200s) |
23. Configuration
| Command | Purpose |
|---|
zjj config | View all configuration |
zjj config <key> | View specific config value |
zjj config <key> <value> | Set config value |
zjj config -g <key> <value> | Set global config |
zjj config --json | Output as JSON |
Full Configuration Schema (TOML, hierarchy: built-in defaults → global ~/.config/zjj/config.toml → project .zjj/config.toml → ZJJ_* env vars → CLI flags):
workspace_dir = "../{repo}__workspaces" # {repo} = repo folder name
main_branch = "" # auto-detected if empty
default_template = "standard" # minimal | standard | full | split | review
state_db = ".zjj/state.db"
[watch]
enabled = true
debounce_ms = 100
paths = [".beads/beads.db"]
[hooks]
post_create = [] # run after zjj add (CWD = workspace)
pre_remove = [] # run before zjj remove
post_merge = [] # run after zjj done merges
[zellij]
session_prefix = "zjj"
use_tabs = true # tabs (inside Zellij) vs sessions (outside)
layout_dir = ".zjj/layouts"
[zellij.panes.main]
command = "claude"
args = []
size = "70%"
[zellij.panes.beads]
command = "bv"
args = []
size = "50%"
[zellij.panes.status]
command = "zjj"
args = ["status", "--watch"]
size = "50%"
[zellij.panes.float]
enabled = true
command = ""
width = "80%"
height = "60%"
[dashboard]
refresh_ms = 1000
theme = "default"
columns = ["name", "status", "branch", "changes", "beads"]
vim_keys = true
[agent]
command = "claude" # default agent for zjj spawn
[agent.env]
# Additional agent environment variables
[session]
auto_commit = false
commit_prefix = "wip:"
[recovery]
policy = "warn" # warn | error | ignore
log_recovered = true
auto_recover_corrupted_wal = true
delete_corrupted_database = false
Key config paths (dot notation for zjj config <key> <value>):
- •
workspace_dir — where workspaces are created
- •
main_branch — main branch name (auto-detected if empty)
- •
default_template — Zellij layout template (minimal, standard, full, split, review)
- •
zellij.use_tabs — tabs vs separate sessions
- •
zellij.session_prefix — prefix for session names
- •
zellij.panes.main.command — main pane command
- •
agent.command — default agent for zjj spawn
- •
session.auto_commit / session.commit_prefix — auto-commit behavior
- •
hooks.post_create / hooks.pre_remove / hooks.post_merge — lifecycle hooks
- •
dashboard.vim_keys — enable hjkl navigation in dashboard
- •
recovery.policy — recovery behavior (warn, error, ignore)
24. Completions
| Command | Purpose |
|---|
zjj completions bash | Generate bash completions |
zjj completions zsh | Generate zsh completions |
zjj completions fish | Generate fish completions |
zjj completions powershell | Generate PowerShell completions |
zjj completions elvish | Generate elvish completions |
25. Help
| Command | Purpose |
|---|
zjj help | Print top-level help |
zjj help <command> | Print help for specific command |
Zellij Layout Templates
minimal
Single pane — lightest weight:
layout {
pane {
command "claude"
cwd "/path/to/workspace"
focus true
}
}
standard (default)
Claude main + beads sidebar + jj log:
┌────────────────────────────┬──────────────┐
│ │ beads (bv) │
│ main pane (claude) 70% │ 50% │
│ ├──────────────┤
│ │ jj log 50% │
│ │ (--limit 20) │
└────────────────────────────┴──────────────┘
layout {
pane split_direction="horizontal" {
pane { command "claude"; cwd "..."; focus true; size "70%" }
pane split_direction="vertical" {
pane { command "bv"; cwd "..."; size "50%" }
pane { command "jj"; args "log" "--limit" "20"; cwd "..."; size "50%" }
}
}
}
full
Standard layout + floating pane (80% width, 60% height)
split (NEW in v0.4.0)
Split pane layout for multi-directional work
review (NEW in v0.4.0)
Review-focused layout for code review workflows
Beads Integration
zjj integrates with the beads issue tracker (.beads/issues.jsonl). Bead lifecycle:
open → (zjj spawn) → in_progress → (zjj done / agent success) → closed
↓
(agent failure) → stays in_progress (retry)
| Bead Status | Meaning |
|---|
open | Ready for work (required for zjj spawn) |
in_progress | Agent/workspace actively working |
blocked | Waiting on dependency |
deferred | Postponed |
closed | Work complete (zjj done sets this) |
Integration points:
- •
zjj spawn <bead-id>: validates bead is open, creates workspace, sets in_progress
- •
zjj add -b <bead-id>: associate session with bead
- •
zjj done: finds linked bead, sets closed (skip with --no-bead-update)
- •
zjj abort: sets bead to abandoned
- •
zjj list --bead <id>: filter sessions by bead
- •
zjj dashboard: watches .beads/beads.db for real-time updates
- •
zjj context: includes beads summary for AI agents
Environment Variables
| Variable | Description | Direction |
|---|
ZJJ_AGENT_ID | Agent identifier for tracking | both |
ZJJ_SESSION | Current session name (set by zjj) | write |
ZJJ_BEAD_ID | Associated bead ID | both |
ZJJ_WORKSPACE | Absolute path to workspace | write |
JSON Output Envelope
All commands support --json. Responses use a consistent envelope:
{
"$schema": "zjj://schema/<type>/<version>",
"_schema_version": "1.0",
"schema_type": "single|array",
"success": true,
"data": { ... }
}
On error:
{
"success": false,
"error": {
"code": "VALIDATION_ERROR|JJ_COMMAND_ERROR|INVALID_ARGUMENT|...",
"message": "Human-readable description",
"exit_code": 1
}
}
Global Options
Available on ALL commands:
- •
--on-success <CMD> - Command to run after successful execution
- •
--on-failure <CMD> - Command to run after failed execution
- •
--json - Output as JSON
Hooks
Configure hooks to run custom commands at lifecycle events:
# Set a post_create hook (runs after zjj add)
zjj config hooks.post_create '["echo workspace ready"]'
# Set a pre_remove hook (runs before zjj remove)
zjj config hooks.pre_remove '["echo cleaning up"]'
# Set a post_merge hook (runs after zjj done)
zjj config hooks.post_merge '["echo merged to main"]'
Skip hooks on demand: zjj add <name> --no-hooks
Typical Workflows
Feature Development
zjj add feature-auth # stand up isolated workspace
# ... develop in isolation ...
zjj sync # stay current with main
zjj diff feature-auth --stat # review what changed
zjj done -m "feat: auth system" # merge back to main
AI Agent Workflow (7-Step)
# 1. Orient
zjj whereami # returns 'main' or 'workspace:<name>'
# 2. Register
zjj agents register --id agent-123 # register as agent
# 3. Isolate
zjj work feature-auth -b zjj-abc12 # create workspace + register agent
# 4. Enter
cd ../lewis__workspaces/feature-auth
# 5. Implement
# ... do work ...
zjj agents heartbeat -c "implementing" # signal liveness
# 6. Heartbeat (periodically)
zjj agents heartbeat
# 7. Complete
zjj done # merge to main + cleanup
zjj agents unregister # unregister agent
Parallel Experiments
zjj add approach-a # first approach
zjj add approach-b # second approach (independent)
zjj diff approach-a --stat # compare approach A
zjj diff approach-b --stat # compare approach B
zjj done # merge winner (from its workspace)
zjj abort -w approach-b # discard loser
Multi-Agent Coordination
# Agent 1 claims session
zjj claim session:feature-x -t 300
# Agent 2 waits for unlock
zjj wait session-unlocked feature-x -t 300
# Agent 1 completes and yields
zjj done
zjj yield session:feature-x
# Agent 2 proceeds
zjj work feature-y
Merge Queue
# Add workspaces to queue for ordered processing
zjj queue --add feature-x --bead zjj-001 --priority 1
zjj queue --add feature-y --bead zjj-002 --priority 2
# Agent processes queue
zjj queue --next # get next pending entry
# ... work ...
zjj done
# Check queue status
zjj queue --stats
Session Cleanup
zjj list --all # see everything including stale
zjj clean --dry-run # preview what would be removed
zjj clean # remove stale sessions
zjj doctor # health check
zjj doctor --fix # auto-fix issues
Anti-Patterns to Avoid
| Anti-Pattern | Problem | zjj Solution |
|---|
Using raw jj workspace add | No session tracking, no Zellij integration | zjj add <name> manages everything |
| Manually creating Zellij tabs | Disconnected from workspace state | zjj add creates both together |
| Forgetting to merge back | Orphaned workspaces accumulate | zjj done merges + cleans up |
| Manual cleanup of workspaces | Easy to leave stale state | zjj clean finds and removes stale sessions |
| Not syncing before merging | Merge conflicts at the end | zjj sync regularly during development |
zjj remove -f to discard work | Loses work silently, bead status not updated | zjj abort — proper discard |
Retrying zjj done in a tight loop | Hammers merge queue, terrible state | zjj sync + zjj retry with backoff |
| Ignoring exit code 3 from done | Silently lost merge attempt | Check exit code, enter backoff loop |
| Not checkpointing before risky ops | Can't recover if merge goes sideways | zjj checkpoint create before done |
| Spawning agents without timeout | Runaway processes | zjj spawn --timeout <secs> |
| Not using agent heartbeats | Agent appears stale | zjj agents heartbeat periodically |
| Not using locks for coordination | Race conditions in multi-agent | zjj claim / zjj yield |
Best Practices
Workspace Discipline
- •One concern per workspace:
zjj add names should describe the task
- •Sync frequently:
zjj sync before starting each work block
- •Use
zjj done not zjj remove: done merges your work
- •Use
zjj abort not zjj remove -f: abort is the proper discard
- •
zjj whatif done before zjj done: Shows steps, prerequisites, reversibility
- •
zjj checkpoint create before zjj done: Safety snapshot
- •Clean up regularly:
zjj clean --dry-run then zjj clean
Session Management
- •Use
zjj focus to switch between sessions
- •Use
zjj status --watch in a side pane for live monitoring
- •Use
zjj dashboard for kanban view
- •Use
zjj list --all to see completed/failed sessions
- •Name sessions descriptively: name becomes workspace directory and tab name
Agent Spawning
- •Use
zjj spawn for AI work: creates isolated workspace, runs agent
- •Use
zjj work for unified workflow: workspace + agent registration
- •Use
-b for background spawning: don't block terminal
- •Set
--no-auto-merge when you want to review output first
- •Set
--timeout for long-running agents
- •Send heartbeats:
zjj agents heartbeat periodically
Multi-Agent Coordination
- •Use
zjj claim / zjj yield: for resource locks
- •Use
zjj queue: for ordered merge processing
- •Use
zjj wait: for condition-based synchronization
- •Use
zjj broadcast: for agent-to-agent messaging
Quality Gates Checklist
Before running zjj done:
After zjj done:
Troubleshooting
"Not in a JJ repository"
zjj init # initializes both jj and zjj
"Session already exists"
zjj list # verify it exists
zjj remove <name> -f # force remove if stale
zjj add <name> # recreate
Stale sessions
zjj clean --dry-run # preview stale sessions
zjj clean # remove them
Workspace out of sync
zjj sync <name> # rebase onto latest main
Dependency issues
zjj doctor # diagnose issues
zjj doctor --fix # auto-fix where possible
zjj introspect # check dependency versions
Zellij tab not opening
zjj focus <name> # try to focus the tab
zjj attach <name> # attach to the session
Merge conflict (exit code 3)
zjj checkpoint create # safety snapshot
zjj sync # re-sync
zjj retry # retry the done
# If still failing after 6 retries:
zjj recover --diagnose # diagnose without fixing
Agent spawn fails
zjj query can-run # check system readiness
zjj introspect # verify agent dependency
zjj spawn <bead> --agent-command=<path> # specify full path
Corrupted state
zjj recover --diagnose # diagnose issues
zjj integrity validate <ws> # validate workspace
zjj integrity repair <ws> # repair workspace
zjj rollback --to <cp> <session> # rollback to checkpoint
Guidelines
- •When the user asks for workspace isolation, always use
zjj add, never raw jj workspace add
- •When the user says "spin up a workspace" or "isolate this work", run
zjj add <name>
- •When the user is done with isolated work, guide them to
zjj done (not zjj remove)
- •Always suggest
zjj sync before zjj done to minimize merge surprises
- •For AI agent workflows, use
zjj spawn or zjj work with appropriate flags
- •Use
--json flag when integrating zjj into scripts or automation
- •Always check
zjj doctor if something seems wrong
- •Remind users that
zjj init is required once per repo
Session Completion (Landing the Plane)
CRITICAL: Before ending any work session using this skill, you MUST complete the Landing the Plane workflow.
When to Land
- •After completing work in an isolated workspace
- •Before going AFK
- •When switching contexts
- •At end of work session
Landing Checklist
# 1. File beads for remaining work (NOT gh issues — beads are the single source of truth)
br create "[process] Follow-up: description" --type task --priority 2 --labels "smell:process"
# 2. Verify workspace state
zjj status # all sessions accounted for
zjj diff <name> --stat # review changes
# 3. Sync and complete — if zjj done fails with exit code 3, use exponential backoff
zjj sync # rebase onto latest main
zjj done -m "description" # merge to main + cleanup
# Or if not ready to merge:
jj describe -m "WIP: description"
jj git push --change @ --allow-new
# 4. Verify — sessions AND directories
zjj list # no orphaned sessions
zjj clean --dry-run # no stale sessions
# Verify workspace directories are actually gone from disk:
WORKSPACE_BASE=$(zjj config workspace_dir 2>/dev/null || echo "../lewis__workspaces")
[ -d "$WORKSPACE_BASE" ] && ls "$WORKSPACE_BASE"/ # should be empty or non-existent
# 5. Hand off
# Provide summary of work completed, sessions created/closed, next steps
For detailed workflow, invoke: /land or use the landing-skill
Skill Version: 2.0.0
Last Updated: February 2026
zjj Version Support: 0.4.0 (verified against installed binary at /home/lewis/.local/bin/zjj)
Status: Production-Ready
Backoff: Exponential backoff on merge conflicts (exit code 3). Uses zjj retry natively. Max 6 retries, 60s cap. Checkpoint before loop. recover on exhaustion. Workspace preserved.