Zinc Is Not Cowork
Agent multiplexer for the terminal
Manage AI coding agents as persistent background daemons. Attach, detach, and switch between agent sessions instantly. Think tmux, but purpose-built for AI coding agents.
Requires Linux or macOS. zinc uses Unix PTYs and is not available on Windows.
Why not tmux?
You can run agents in tmux panes. zinc adds three things tmux can't do:
- State awareness — zinc knows whether an agent is working, waiting for input, or blocked on a permission prompt. tmux just shows you a pane with text.
- Session resume — zinc integrates with agent session history, letting you resume previous conversations. tmux doesn't know what's running inside it.
- Structured lifecycle — spawn, kill, and list agents by ID across directories. No manual pane/window management.
If you run one agent at a time, tmux is fine. zinc shines when you're running 3+ agents across worktrees and need to know which ones need you.
Features
- Never lose a session - agents run as background daemons, survive terminal close
- TUI supervisor - full-screen view of all agents, keyboard-driven
- Instant switching - one keystroke to attach/detach from any agent
- State tracking - see at a glance which agents are working, waiting for input, or blocked
- Session picker - resume previous sessions or start fresh, with automatic session discovery
- Composable - works with any worktree/project workflow (designed to pair with yawn)
Quick start
# Set up Claude Code hooks for accurate state detection
# Spawn a Claude agent in your project
# Or spawn with a prompt and attach immediately
# Attach (resolves from current directory)
# Open the TUI to see all agents
TUI
Running zinc with no arguments opens the interactive supervisor:
zinc -3 agents (1 needs input)
STATE AGENT ID DIRECTORY UPTIME
● work claude fix-auth ~/worktrees/myapp--fix-auth 12m
▸ ▲ input claude fix-nav ~/worktrees/myapp--fix-nav 8m
● work claude fix-api ~/worktrees/myapp--fix-api 3m
enter:attach n:new d:kill q:quit
j/kor arrows to navigateenterto attach to the selected agentnto spawn a new agentdto kill the selected agentpto toggle scrollback preview/to filter agents by ID, provider, or directoryqto quit (agents keep running)
When attached, a status bar shows the agent info. ctrl-] detaches back to the list.
CLI commands
zinc spawn
Arguments:
<prompt>- initial prompt text (positional, optional)
Flags:
-a/--agent <name>- provider to use (default: from config, orclaude)-d/--dir <path>- working directory (default: current directory)-i/--id <name>- agent ID (default: derived from directory name)-n/--new- skip session picker, always start a new session-A/--attach- attach to the agent immediately after spawning
zinc attach
When no ID is given, zinc finds the agent running in your current directory. Errors clearly if there are zero or multiple agents.
zinc kill
Same CWD resolution as zinc attach.
zinc init
Sets up agent hooks for accurate state detection. For Claude Code, this writes hook entries to ~/.claude/settings.json so zinc can distinguish between working, input, and blocked states. Without this, zinc falls back to PTY activity heuristics.
State detection
zinc uses layered detection to track what each agent is doing:
| State | Meaning |
|---|---|
working |
Actively producing output |
blocked |
Needs user action (e.g. permission prompt) |
input |
Waiting for new user prompt |
idle |
Running but inactive |
For Claude Code, state is detected via hooks (immediate, distinguishes input from blocked). For other agents, PTY activity heuristics are used as a fallback.
Configuration
~/.config/zinc/config.toml - all fields optional:
[]
= "claude" # default provider (alias: agent)
= "yawn prettify {dir}" # derive agent ID from directory
[]
= 1048576 # scrollback buffer size in bytes (1MB)
[]
= "notify-send 'zinc: {id}' '{state}'" # command to run on state change
= ["input", "blocked"] # which states trigger (default)
Custom TUI commands
[[]]
= "open in editor"
= "o"
= "code {dir}"
Adds a keybinding to the TUI that runs a shell command for the selected agent. Placeholders: {id}, {dir}, {provider}. Reserved keys (q, j, k, n, p, d, /) cannot be used.
Project picker
[]
= "yawn list" # command that outputs project names, one per line
= "yawn resolve {name}" # resolves a name to a directory path
When configured, pressing n in the TUI shows a project picker before spawning. The picker lists items from project_picker output. If project_resolver is set, the selected item is resolved to a directory path; otherwise, items are treated as paths directly.
Notifications
The notify.command field runs a command when an agent transitions to a matching state. Placeholders {id}, {state}, {old_state} are shell-quoted and substituted.
# Linux (libnotify)
= "notify-send 'zinc: {id}' '{state}'"
# macOS
= "osascript -e 'display notification \"{state}\" with title \"zinc: {id}\"'"
Namer
The spawn.namer field runs a command to derive the agent ID from the directory. {dir} is replaced with the shell-quoted path:
= "basename {dir}" # use directory name as-is
= "yawn prettify {dir}" # use yawn for clean names
Fallback chain: --id flag > namer > directory basename.
Composing with other tools
zinc operates on directories, so it composes naturally with any worktree or project manager. See yawn for an example of worktree-based workflows with zinc.
Architecture
zinc uses a daemon-client architecture (like tmux):
zinc daemon- long-running daemon that owns agent PTYs, tracks state, broadcasts eventszinc- short-lived client that connects to the daemon via Unix socket
The daemon starts automatically on first zinc command and shuts down automatically after 30 seconds of inactivity (no agents, no connected clients). It keeps agents alive independently of any terminal.
Install
From source
GitHub Releases
Download binaries from the releases page.
Nix flake
inputs.zinc.url = "github:ComeBertrand/zinc";
# then in your packages:
inputs.zinc.packages.${system}.default
Shell completion & man page
Shell completions are generated at build time:
# Bash
# Zsh (or place it anywhere in your $fpath)
# Fish
A man page is generated at build time:
License
MIT