zag
One CLI for all your AI coding agents.
zag wraps Claude, Codex, Gemini, Copilot, and Ollama behind a single command so you can switch between them without learning five different CLIs. It adds cross-provider features on top: model size aliases, automatic provider/model selection, git worktree isolation, Docker sandboxing, structured JSON output with schema validation, unified session logs, and a programmatic Rust API.
Why zag?
- One CLI, five agents — Switch between Claude, Codex, Gemini, Copilot, and Ollama without learning five different CLIs
- Cross-provider features — Model size aliases, JSON schema validation, git worktree isolation, and Docker sandboxing work with every provider
- Orchestration primitives — Spawn, wait, collect, pipe, and chain agents in shell scripts for multi-agent workflows
- Programmatic API — Rust library crate plus TypeScript, Python, C#, Swift, Java, and Kotlin SDKs
Prerequisites
- Rust 1.85+ (edition 2024) — for building from source
- git — required for
--worktreeisolation - Docker — required for
--sandboxisolation (optional) - At least one agent CLI installed (see below)
Install
From crates.io
From GitHub Releases
Download a pre-built binary from GitHub Releases, extract it, and place it in your PATH.
From source
As a library
Agent CLIs
You need at least one underlying agent CLI installed:
| Provider | Install command | Link |
|---|---|---|
| Claude | curl -fsSL https://claude.ai/install.sh | bash |
docs |
| Codex | npm install -g @openai/codex |
repo |
| Gemini | npm install -g @anthropic-ai/gemini-cli |
repo |
| Copilot | npm install -g @github/copilot |
docs |
| Ollama | See ollama.com/download | site |
zag checks for the required binary before running and provides install hints if it's missing.
Quick start
# Interactive session with Claude (the default provider)
# Non-interactive — prints the response and exits
# Pick a different provider
# Use size aliases instead of provider-specific model names
# Let an LLM pick the best provider and model for the task
# Code review (delegates to Codex)
Providers
| Provider | Default model | Size aliases (small / medium / large) |
|---|---|---|
| claude | default | haiku / sonnet / default |
| codex | gpt-5.4 | gpt-5.4-mini / gpt-5.3-codex / gpt-5.4 |
| gemini | auto | gemini-3.1-flash-lite-preview / gemini-2.5-flash / gemini-3.1-pro-preview |
| copilot | claude-sonnet-4.6 | claude-haiku-4.5 / claude-sonnet-4.6 / claude-opus-4.6 |
| ollama | qwen3.5:9b | 2b / 9b / 35b (parameter sizes, any model from ollama.com) |
Size aliases let you write zag -m large exec "..." and get the right model regardless of which provider you're using. For Claude, default delegates model selection to the Claude CLI itself.
Provider downgrade
When you don't pin a provider with -p, zag walks a tier list and falls back to the next provider if the configured one isn't usable — the binary is missing from PATH, or its startup probe fails (e.g. gemini without configured auth). Each downgrade is logged so you can see which provider actually ran:
! Downgrading provider: gemini → copilot ('gemini' CLI not found in PATH. ...)
The default tier order is claude → codex → gemini → copilot → ollama. Pin a provider with -p <name> to disable the fallback and get a hard error when the binary is missing.
Commands
zag run [prompt] Interactive session (optional initial prompt)
zag exec <prompt> Non-interactive — print output and exit (supports --resume, --continue)
zag review Code review (--uncommitted, --base, --commit)
zag plan <goal> Generate an implementation plan (writes to file or stdout)
zag config [key] [value] View or set configuration
zag session list|show|import|delete|update List/inspect/manage sessions
zag listen <id> Tail a session's log events in real-time
zag ps list|show|stop|kill List, inspect, and manage agent processes
zag search <query> Search through session logs
zag input [message] Send a user message to a single session
zag broadcast [message] Send a message to all sessions in the project
zag spawn <prompt> Launch background agent, return session ID
zag spawn -I [prompt] Spawn long-lived interactive session (FIFO-based)
zag wait <id>... [--timeout] Block until session(s) complete
zag status <id> Machine-readable session health check
zag collect [--tag <tag>] Gather results from multiple sessions
zag env [--session <id>] Export session environment variables
zag pipe <ids>... -- <prompt> Chain session results into a new session
zag events <id> [--type ...] Query structured events from session logs
zag cancel <id>... [--tag] Gracefully cancel running sessions
zag summary <id>... [--tag] Log-based session summary and stats
zag watch <id> --on <event> Execute command on matching log events
zag subscribe [--tag <tag>] Multiplexed event stream from all sessions
zag log <message> [--session] Append custom event to a session log
zag output [<id>] [--latest] Extract final result text from a session
zag retry <id>... [--failed] Re-run failed sessions with same config
zag gc [--force] [--older-than] Clean up old session data and logs
zag serve [--port] [--token] Start HTTPS/WS server for remote access
zag connect <url> --token Connect to a remote zag server
zag disconnect Disconnect from remote server
zag user add|remove|list|passwd Manage user accounts on the server
zag discover Discover providers, models, and capabilities
zag capability Show provider capability declarations
zag skills list|show|add|remove|sync|import Manage provider-agnostic skills
zag mcp list|show|add|remove|sync|import Manage MCP servers across providers
zag whoami Show current session identity (for agents)
zag man [command] Built-in manual pages
Flags
| Flag | Short | Description |
|---|---|---|
--provider <name> |
-p |
claude, codex, gemini, copilot, ollama, auto |
--model <name> |
-m |
Model name, size alias (small/medium/large), or auto |
--system-prompt <text> |
-s |
Appended to the agent's system prompt |
--root <path> |
-r |
Root directory for the agent |
--auto-approve |
-a |
Skip permission prompts |
--add-dir <path> |
Additional directories to include (repeatable) | |
--file <path> |
Attach a file to the prompt (repeatable) | |
--env <KEY=VALUE> |
Environment variable for the agent subprocess (repeatable) | |
--worktree [name] |
-w |
Run in an isolated git worktree |
--sandbox [name] |
Run inside a Docker sandbox | |
--json |
Request structured JSON output | |
--json-schema <schema> |
Validate output against a JSON schema | |
--session <uuid> |
Pre-set the session ID | |
--name <name> |
Human-readable session name (for discovery) | |
--description <text> |
Short description of the session's purpose | |
--tag <tag> |
Session tag (repeatable, for discovery/filtering) | |
--max-turns <n> |
Maximum number of agentic turns | |
--timeout <duration> |
Timeout duration (e.g., 30s, 5m, 1h). Kills the agent if exceeded. | |
--mcp-config <config> |
MCP server config: JSON string or file path (Claude only) | |
--size <size> |
Ollama parameter size (e.g., 2b, 9b, 35b) | |
--show-usage |
Show token usage statistics (JSON output mode) | |
--exit-on-failure |
exec only — exit with non-zero code if the agent reports failure |
|
--debug |
-d |
Debug logging |
--quiet |
-q |
Suppress all output except the agent's response |
--verbose |
-v |
Styled output with icons in exec mode |
--help-agent |
Print an AI-oriented CLI reference and exit | |
--no-health-check |
Skip health check before proxying to a remote server |
Session management
Every interactive session gets a session ID. You can name and tag sessions for discovery, resume them, and zag tracks provider-native session IDs automatically.
# Create sessions with metadata for discovery
# Resume a specific session (interactive or non-interactive)
# Resume the most recent session
# List and filter sessions
# Send messages by name
# Broadcast to all sessions in the project (or filter by tag)
# Update session metadata
# Tail a session's logs in real-time (from another terminal)
Orchestration
zag provides primitives for launching, synchronizing, and collecting results from multiple agent sessions. These are building blocks — not an orchestration engine — designed for shell scripts and pipelines.
# Spawn parallel agents
sid1=
sid2=
sid3=
# Check health
# Block until all finish (exit code reflects success)
# Collect results
# Feed a session's result into a new agent
# Propagate agent failure as a non-zero exit code
||
# Export session env for nested invocations
# Query parent-child process trees
# Filter listen to specific event types
# Chain session results into a new agent session (tag/name/worktree/sandbox/timeout supported)
# Query structured events from a session log
# Gracefully cancel sessions
# Get session summaries (no LLM call — log-based)
# Watch for events and react
# Subscribe to a multiplexed event stream from all sessions
|
# Long-lived interactive sessions (Claude only)
sid=
# DAG workflows with spawn dependencies
sid_a=
sid_b=
sid_c=
sid_d=
Filesystem lifecycle markers are written to ~/.zag/events/ (.started and .ended files) for external non-Rust orchestrators that prefer inotifywait over polling.
Remote access
Run agents on your home machine and control them from anywhere (mobile, laptop, another server).
# On the server machine — start the zag server
# Output: Generated token: a1b2c3...
# With TLS (recommended for non-VPN networks)
# On the client machine — connect to the server
# Now all commands transparently proxy through the remote server
# Spawn an interactive session on the remote machine
sid=
# Disconnect when done
When the remote server becomes unreachable, zag automatically disconnects and falls back to local execution (with a warning). The health check result is cached for 30 seconds. Use --no-health-check or ZAG_NO_HEALTH_CHECK=1 to disable this behavior.
The server exposes REST and WebSocket endpoints at /api/v1/. See zag man serve and zag man connect for details.
Worktree and sandbox isolation
# Worktree: isolated git worktree per session
# Sandbox: Docker microVM isolation
# Both track sessions — resume restores the correct workspace
After interactive sessions, you're prompted to keep or remove the workspace. Exec sessions with changes are kept automatically with a resume command printed.
JSON output
# Request JSON output
# Validate against a schema (inline or file path)
# Stream events as NDJSON
Claude uses its native --json-schema support. Other providers get JSON instructions injected into the system prompt. On validation failure, zag retries up to 3 times via session resume.
Output formats
With exec -o <format>:
| Format | Description |
|---|---|
| (default) | Streamed text — beautiful formatting for Claude, plain for others |
text |
Raw agent output, no parsing |
json |
Compact unified JSON (AgentOutput) |
json-pretty |
Pretty-printed unified JSON |
stream-json |
NDJSON event stream (unified format) |
native-json |
Claude's raw JSON format (Claude only) |
Configuration
Per-project config lives at ~/.zag/projects/<sanitized-path>/zag.toml. Falls back to ~/.zag/zag.toml outside of git repos.
[]
= "claude"
= "medium"
= false
# max_turns = 10
# system_prompt = ""
[]
= "opus"
= "gpt-5.4"
[]
= "claude"
= "sonnet"
[]
= "qwen3.5"
= "9b"
Settings priority: CLI flags > config file > agent defaults.
Skills
zag supports provider-agnostic skills using the Agent Skills open standard. Skills are stored in ~/.zag/skills/ and automatically synced to each provider's native skill directory via symlinks.
MCP Servers
Manage MCP (Model Context Protocol) servers across all providers from a single place. Each server is stored as an individual TOML file in ~/.zag/mcp/ (global) or ~/.zag/projects/<path>/mcp/ (project-scoped), and synced into each provider's native config format with a zag- prefix.
Supported providers: Claude (~/.claude.json), Gemini (~/.gemini/settings.json), Copilot (~/.copilot/mcp-config.json), Codex (~/.codex/config.toml).
Programmatic API
The zag-agent crate exposes an AgentBuilder for driving agents from Rust code:
use AgentBuilder;
let output = new
.provider
.model
.auto_approve
.name // optional — registers with the session store
.tag // so `zag session list`, `zag input --name`, etc. find it
.exec
.await?;
println!;
See the zag-agent crate for the full API including JSON schema validation, custom progress handlers, and interactive sessions. Library-level primitives for review, plan, discover, manpages, and agent-to-agent messaging are re-exported from zag_agent and zag_orch so downstream programs can drive these flows without shelling out to the CLI.
Language bindings
SDK packages are available for TypeScript, Python, C#, Swift, Java, and Kotlin. Each wraps the zag CLI and exposes a fluent builder API with typed output models.
TypeScript (bindings/typescript/)
import { ZagBuilder } from "@nlindstedt/zag-agent";
const output = await new ZagBuilder()
.provider("claude")
.model("sonnet")
.autoApprove()
.exec("write a hello world program");
console.log(output.result);
// Streaming
for await (const event of new ZagBuilder().provider("claude").stream("analyze code")) {
console.log(event.type);
}
Python (bindings/python/)
= await \
\
\
\
# Streaming
C# (bindings/csharp/)
using Zag;
var output = await new ZagBuilder()
.Provider("claude")
.Model("sonnet")
.AutoApprove()
.ExecAsync("write a hello world program");
Console.WriteLine(output.Result);
// Streaming
await foreach (var evt in new ZagBuilder().Provider("claude").StreamAsync("analyze code"))
{
Console.WriteLine(evt.Type);
}
Swift (bindings/swift/)
import Zag
let output = try await ZagBuilder()
.provider("claude")
.model("sonnet")
.autoApprove()
.exec("write a hello world program")
print(output.result ?? "")
// Streaming
for try await event in ZagBuilder().provider("claude").stream("analyze code") {
print(event)
}
Java (bindings/java/)
;
var output ;
System.out.;
// Streaming
for
Kotlin (bindings/kotlin/)
import zag.ZagBuilder
val output = ZagBuilder()
.provider("claude")
.model("sonnet")
.autoApprove()
.exec("write a hello world program")
println(output.result)
// Streaming
ZagBuilder().provider("claude").stream("analyze code").collect { event ->
println(event.type)
}
Examples
The examples/ directory contains complete projects demonstrating zag usage:
- cv-review — A Rust program that uses the
zaglibrary crate to review CVs against job descriptions using parallel agent invocations - orchestration — Shell scripts demonstrating 8 multi-agent patterns: sequential pipelines, parallel fan-out, generator-critic loops, coordinator dispatch, hierarchical decomposition, event-driven composites, decision arenas, and meta-bootstrap (agents that generate their own orchestration scripts)
- react-claude-interface — A React web app that provides a Claude Code-like chat interface powered by
zag execandzag inputwith streaming NDJSON events over Server-Sent Events - ZagChat — A native macOS SwiftUI chat app built on the Swift bindings, demonstrating
StreamingSession, expandable tool-call details, and sub-agent nesting
See the examples directory for details on each.
Troubleshooting
"CLI not found in PATH" — The agent CLI binary isn't installed or isn't in your PATH. Install it using the commands in the Agent CLIs table above.
"Invalid model 'X' for Y" — You specified a model name that the provider doesn't recognize. Use zag discover --models -p <provider> to see available models, or use size aliases (small, medium, large). Use zag discover --resolve <alias> -p <provider> to trace what an alias resolves to.
--worktree fails — You must be inside a git repository. The worktree is created under ~/.zag/worktrees/.
--sandbox fails — Docker must be installed and running. Sandbox mode uses docker sandbox run for microVM isolation.
Config not taking effect — Check which config file is being used with zag config path. Config is per-project (based on git repo root). CLI flags always override config.
Documentation
- Getting Started — Step-by-step tutorial for new users
- Providers — Feature comparison, model recommendations
- Configuration — Complete config reference
- Events & Logging — NDJSON event format reference
- Troubleshooting — Common issues and solutions
- Contributing — Development workflow and guidelines
zag man <command>— Built-in manual pages for every command
Contributing
See CONTRIBUTING.md for the development workflow, branch naming conventions, commit style, and pull request process.
Architecture
zag (binary crate)
CLI parsing (clap) → dispatch to zag-agent and zag-orch
Session logs, worktree/sandbox lifecycle, JSON mode, auto-selection
zag-agent (library crate)
Agent trait, provider implementations, AgentBuilder API
Config, output types, session logs, skills, process helpers
zag-orch (orchestration crate)
spawn, wait, collect, pipe, cancel, status, events
watch, subscribe, summary, retry, gc, and more
Each provider implementation spawns the respective CLI tool as a subprocess. The Agent trait defines the common interface (run, resume, cleanup, model resolution). AgentOutput normalizes output from all providers into a unified event stream.
Development