Rust TUI/CLI for Zellij-based development β manage projects, git worktrees, Zellij sessions, and workflow automations from one terminal dashboard.
Install Β· Basic start Β· Shortcuts Β· Configuration Β· Autopilot Β· Development
zigzag is for developers who keep many repositories, branches, and terminal sessions open at once. It gives you one workflow around Zellij and git worktrees:
- Project dashboard β browse configured projects, worktrees, running sessions, notifications, and git/PR/CI preview data.
- Worktree-first sessions β
zigzag openrestores the primary checkout or creates/restores a branch worktree throughwt. - Native Zellij integration β generated layouts load the Zigzag WASM plugin for in-session toasts and session switching, plus shortcuts for actions and logs.
- Action menu β run contextual tools such as review, lazygit, PR opening, CI fixes, or custom commands.
- Autopilot workflows β KDL-defined background workflows for CI fixes, review follow-up, merge/deploy flows, and custom automation.
ββ Zigzag βββββββββββββββββββββββββββββββββββββββ
β PROJECTS WORKTREES β
β > myapp main β β
β api feat/login π β
β β
β PREVIEW β
β myapp:feat/login Β· dirty Β· PR #42 Β· CI passing β
β β
β [o]pen [n]ew [r]un [K]ill [d]el [?]help [q]uitβ
ββββββββββββββββββββββββββββββββββββββββββββββββββ
Note
Zigzag is still in early development. For deeper design context, see docs/PRD.md and docs/SPECS.md.
| Tool | Minimum | Used for |
|---|---|---|
| Rust | stable | Build toolchain |
| Zellij | 0.44.0 |
Terminal sessions |
wt |
0.34.0 |
Git worktrees |
| GitHub CLI | 2.0.0 |
PR, CI, issue data |
Zigzag checks these dependencies at startup and reports missing or outdated tools.
# Latest release
curl -fsSL https://raw.githubusercontent.com/arkan/zigzag/main/install.sh | bash
# Specific version
curl -fsSL https://raw.githubusercontent.com/arkan/zigzag/main/install.sh | ZIGZAG_VERSION=v0.7.0 bash
# Custom install directory, default is ~/.local/bin
curl -fsSL https://raw.githubusercontent.com/arkan/zigzag/main/install.sh | ZIGZAG_INSTALL_DIR=/usr/local/bin bash# Install from the flake
nix profile install github:arkan/zigzag
# Or try it without installing
nix run github:arkan/zigzag -- listThe Nix package wraps zigzag with the common runtime tools it shells out to: zellij, wt, git, gh, ssh, and mosh.
Zigzag does not install a z symlink automatically. If you still want the short command, add this to your shell profile:
alias z=zigzagZigzag does not read old z paths. If you used the previous name, move local files manually:
mv "$HOME/.config/z" "$HOME/.config/zigzag"
mv "$HOME/.local/state/z" "$HOME/.local/state/zigzag"# Builds the CLI and the native Zellij WASM plugin.
# The plugin is a prerequisite for generated Zellij layouts: Alt+k loads it
# from Zigzag's user data directory.
make installBy default this installs:
- CLI:
~/.local/bin/zigzag - Zellij WASM plugin:
~/.local/share/zigzag/zigzag_plugin.wasm
If you build manually instead of using make install, install the plugin in the same canonical path:
rustup target add wasm32-wasip1
cargo build --manifest-path zigzag/Cargo.toml -p zigzag-plugin --release --target wasm32-wasip1
mkdir -p ~/.local/share/zigzag
cp zigzag/target/wasm32-wasip1/release/zigzag_plugin.wasm ~/.local/share/zigzag/zigzag_plugin.wasm
cargo install --path zigzag/crates/zigzag-clizigzag expects the native Zellij plugin for switcher and notifications at ~/.local/share/zigzag/zigzag_plugin.wasm. Override it with ZIGZAG_PLUGIN_WASM=/path/to/zigzag_plugin.wasm when testing a local build.
Create ~/.config/zigzag/projects.kdl:
project "myapp" {
path "~/Code/myapp"
}
project "api" {
path "~/Code/api"
}zigzagThen use:
| Key | Action |
|---|---|
β / β |
Move in the current list |
β / β or Tab |
Switch between Projects and Worktrees |
Enter or o |
Open/restore the selected worktree session |
s or Alt+k |
Open the active-session switcher; inside Zellij this is the native WASM plugin |
n |
Create a new worktree + session from a branch, issue, or PR |
/ |
Fuzzy search |
? |
Show in-app help |
q |
Quit the dashboard |
Tip
Arrow keys always work. h/j/k/l navigation is available when keybindings "vim" is enabled in your config.
zigzag open myapp # Open/restore the primary checkout session
zigzag open myapp feat/login # Open/restore a branch worktree + session
zigzag switch # Pick another local Zigzag-managed sessionWhen a branch worktree does not exist yet, zigzag open <project> <branch> creates it with wt, generates a Zellij layout, starts the session, then attaches to it.
Inside a session, press Ctrl+O, then D to detach. The Zellij session keeps running in the background, and you can return with zigzag or zigzag open <project> [branch].
| Key | Action |
|---|---|
o / Enter |
Open/restore selected project or worktree |
s / Alt+k |
Open the active-session switcher; inside Zellij this is the native WASM plugin |
n |
New worktree + session |
r |
Run action menu |
a |
Autopilot workflows |
K |
Kill active session only |
d |
Delete selected worktree |
D |
Run doctor diagnostics |
A / E / X |
Add, edit, or delete a project |
e |
Edit per-repo .config/zigzag.kdl |
/ |
Search |
? |
Help |
Zigzag injects these shortcuts into generated Zellij layouts:
| Shortcut | Action |
|---|---|
Alt+k |
Open/focus the floating native Zigzag session switcher plugin |
Alt+z |
Open the floating action menu |
Alt+l |
Open the floating log viewer |
| Shortcut | Action |
|---|---|
Ctrl+O, then D |
Detach from the session |
Ctrl+Q |
Quit the session |
Ctrl+T, then N |
New tab |
Ctrl+T, then 1-9 |
Switch to tab by number |
| Command | Description |
|---|---|
zigzag |
Launch the dashboard |
zigzag list |
List configured projects and active sessions |
zigzag open <project> [branch] |
Open/restore a checkout or branch session |
zigzag close [session] |
Detach a session without deleting it |
zigzag switch |
Pick and jump to another local Zigzag session |
zigzag actions |
Open the action menu for the current session |
zigzag logs [-n <count>] |
Show Zigzag logs |
zigzag doctor [--fix] |
Diagnose or repair safe project/session issues |
zigzag session kill <project> <branch> |
Kill a Zellij session only |
zigzag worktree delete <project> <branch> [--confirm <branch>] |
Delete a worktree |
zigzag project delete <project> |
Remove a project from projects.kdl |
zigzag notify [session] <message> |
Add a session notification |
zigzag autopilot <subcommand> |
Manage workflow automation |
Zigzag can create/focus named Zellij tabs and run commands in named panes for a Zigzag-managed session:
zigzag tab create --session myapp:main --name tests
zigzag tab focus --session myapp:main --name tests
zigzag pane run --session myapp:main --tab tests --pane unit "cargo test"
zigzag pane focus --session myapp:main --tab tests --pane unit
zigzag pane list --session myapp:main --jsonPane aliases are Zigzag names stored in worktree-metadata.json; raw Zellij pane IDs are internal details. By default these commands refuse sessions that are not known as Zigzag-managed. Pass --allow-unmanaged only when you intentionally want best-effort control of an arbitrary Zellij session; metadata is limited or unavailable in that mode.
Zigzag uses KDL with three main files:
| File | Purpose |
|---|---|
~/.config/zigzag/projects.kdl |
Project registry |
~/.config/zigzag/config.kdl |
Global preferences, layout defaults, actions, notifications |
<repo>/.config/zigzag.kdl |
Per-repository layout, actions, and autopilot settings |
Minimal global config:
keybindings "vim" // or omit for arrow-key navigation
theme "dracula"
notifications {
tui true
zellij true
macos-native false
}notifications.zellij true sends zigzag notify events to the native plugin with zellij action pipe. The plugin is launched automatically as a floating notification pane when a toast arrives; this does not create a terminal pane and should not steal keyboard focus.
Minimal per-repo layout:
layout {
tab "code" {
pane "editor"
pane "shell" size=30
}
tab "agent" {
pane command="claude"
}
}The action menu (r in the dashboard, Alt+z in a generated Zellij session) resolves built-in, global, and per-repo actions against the current project/session context.
Notifications are stored in local worktree metadata and surfaced as dashboard/switcher badges. From inside a Zellij pane, $ZELLIJ_SESSION_NAME lets you notify the current session without naming it:
zigzag notify "CI finished" --level info
zigzag notify myapp:feat-login "Review comments arrived" --level warningWith zellij true, the same command also emits a native in-session toast via the plugin. Toasts render as a four-line card: status icon + notification type, session subtitle, spacer, then message body:
β Error
hub:main
Build failed
The pipe payload is JSON and targets the zigzag-notify pipe; for manual testing:
zellij -s myapp:feat-login action pipe \
--name zigzag-notify \
--plugin file:$HOME/.local/share/zigzag/zigzag_plugin.wasm \
--floating-plugin true \
--plugin-title Zigzag \
--skip-plugin-cache \
-- '{"message":"CI finished","level":"info","session":"myapp:feat-login"}'Autopilot workflows are KDL-defined state machines that can run commands, send notifications, ask for confirmations, and transition on success/failure.
zigzag autopilot list
zigzag autopilot status
zigzag autopilot run <project> <workflow>Built-in workflows cover common PR and deploy loops such as CI fixing, review follow-up, merge-when-ready, Dependabot auto-merge, and deploy monitoring.
This repository is a Rust workspace:
zigzag/crates/
βββ zigzag-core # Domain types, config, actions, traits
βββ zigzag-cli # CLI entry point and process/filesystem adapters
βββ zigzag-tui # Ratatui dashboard, switcher, logs, action picker
βββ zigzag-autopilot # Workflow DSL and runner
βββ zigzag-plugin # Native Zellij WASM plugin: toasts + session switcher
βββ zigzag-web # Future web bridge
Common checks:
npm run typecheck
npm test
cargo fmt --manifest-path zigzag/Cargo.toml --all --check
cargo test --manifest-path zigzag/Cargo.toml --workspace
cargo build --manifest-path zigzag/Cargo.toml -p zigzag-plugin --target wasm32-wasip1Further reading:
codemap.mdβ repository map and entry pointsdocs/PRD.mdβ product requirementsdocs/SPECS.mdβ technical specs