{"id":47794045,"url":"https://github.com/niclaslindstedt/zag","last_synced_at":"2026-05-02T21:05:43.617Z","repository":{"id":348727220,"uuid":"1199552732","full_name":"niclaslindstedt/zag","owner":"niclaslindstedt","description":"Agents change weekly. Your workflows shouldn't. One CLI for Claude, Codex, Gemini, Copilot, and Ollama.","archived":false,"fork":false,"pushed_at":"2026-04-07T19:40:44.000Z","size":1712,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-07T20:02:29.382Z","etag":null,"topics":["agent","ai","claude-code","cli","codex","copilot-cli","gemini","llm","multi-agent","ollama","orchestration-framework","rust","sdk"],"latest_commit_sha":null,"homepage":"https://niclaslindstedt.github.io/zag/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/niclaslindstedt.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-04-02T13:16:00.000Z","updated_at":"2026-04-07T19:40:47.000Z","dependencies_parsed_at":"2026-04-08T21:00:36.537Z","dependency_job_id":null,"html_url":"https://github.com/niclaslindstedt/zag","commit_stats":null,"previous_names":["niclaslindstedt/zag"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/niclaslindstedt/zag","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niclaslindstedt%2Fzag","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niclaslindstedt%2Fzag/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niclaslindstedt%2Fzag/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niclaslindstedt%2Fzag/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/niclaslindstedt","download_url":"https://codeload.github.com/niclaslindstedt/zag/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niclaslindstedt%2Fzag/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31573788,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T14:31:17.711Z","status":"ssl_error","status_checked_at":"2026-04-08T14:31:17.202Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent","ai","claude-code","cli","codex","copilot-cli","gemini","llm","multi-agent","ollama","orchestration-framework","rust","sdk"],"created_at":"2026-04-03T16:02:58.133Z","updated_at":"2026-05-02T21:05:43.609Z","avatar_url":"https://github.com/niclaslindstedt.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# zag\n\n[![ci](https://github.com/niclaslindstedt/zag/actions/workflows/ci.yml/badge.svg)](https://github.com/niclaslindstedt/zag/actions/workflows/ci.yml)\n[![release](https://github.com/niclaslindstedt/zag/actions/workflows/release.yml/badge.svg)](https://github.com/niclaslindstedt/zag/actions/workflows/release.yml)\n[![pages](https://github.com/niclaslindstedt/zag/actions/workflows/pages.yml/badge.svg)](https://github.com/niclaslindstedt/zag/actions/workflows/pages.yml)\n[![crates](https://img.shields.io/crates/v/zag-cli.svg)](https://crates.io/crates/zag-cli)\n[![npm](https://img.shields.io/npm/v/@nlindstedt/zag-agent.svg)](https://www.npmjs.com/package/@nlindstedt/zag-agent)\n[![pypi](https://img.shields.io/pypi/v/zag-agent.svg)](https://pypi.org/project/zag-agent/)\n[![nuget](https://img.shields.io/nuget/v/Zag.svg)](https://www.nuget.org/packages/Zag/)\n[![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n\nOne CLI for all your AI coding agents.\n\n`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.\n\n## Why zag?\n\n- **One CLI, five agents** — Switch between Claude, Codex, Gemini, Copilot, and Ollama without learning five different CLIs\n- **Cross-provider features** — Model size aliases, JSON schema validation, git worktree isolation, and Docker sandboxing work with every provider\n- **Orchestration primitives** — Spawn, wait, collect, pipe, and chain agents in shell scripts for multi-agent workflows\n- **Programmatic API** — Rust library crate plus TypeScript, Python, C#, Swift, Java, and Kotlin SDKs\n\n## Prerequisites\n\n- **Rust 1.85+** (edition 2024) — for building from source\n- **git** — required for `--worktree` isolation\n- **Docker** — required for `--sandbox` isolation (optional)\n- At least one agent CLI installed (see below)\n\n## Install\n\n### From crates.io\n\n```bash\ncargo install zag-cli\n```\n\n### From GitHub Releases\n\nDownload a pre-built binary from [GitHub Releases](https://github.com/niclaslindstedt/zag/releases), extract it, and place it in your `PATH`.\n\n### From source\n\n```bash\ngit clone https://github.com/niclaslindstedt/zag.git\ncd zag\ncargo install --path zag-cli\n```\n\n### As a library\n\n```bash\ncargo add zag\n```\n\n### Agent CLIs\n\nYou need at least one underlying agent CLI installed:\n\n| Provider | Install command | Link |\n|----------|----------------|------|\n| Claude | `curl -fsSL https://claude.ai/install.sh \\| bash` | [docs](https://docs.anthropic.com/en/docs/claude-code) |\n| Codex | `npm install -g @openai/codex` | [repo](https://github.com/openai/codex) |\n| Gemini | `npm install -g @anthropic-ai/gemini-cli` | [repo](https://github.com/google-gemini/gemini-cli) |\n| Copilot | `npm install -g @github/copilot` | [docs](https://docs.github.com/en/copilot/concepts/agents/about-copilot-cli) |\n| Ollama | See [ollama.com/download](https://ollama.com/download) | [site](https://ollama.com) |\n\n`zag` checks for the required binary before running and provides install hints if it's missing.\n\n## Quick start\n\n```bash\n# Interactive session with Claude (the default provider)\nzag run\n\n# Non-interactive — prints the response and exits\nzag exec \"write a hello world program in Rust\"\n\n# Pick a different provider\nzag -p gemini run\nzag -p codex exec \"add error handling to src/main.rs\"\n\n# Use size aliases instead of provider-specific model names\nzag -m small exec \"what does this function do?\"   # fastest/cheapest\nzag -m large run                                   # most capable\n\n# Let an LLM pick the best provider and model for the task\nzag -p auto -m auto exec \"refactor the auth module\"\n\n# Code review (delegates to Codex)\nzag review --uncommitted\n```\n\n## Providers\n\n| Provider | Default model | Size aliases (small / medium / large) |\n|----------|---------------|---------------------------------------|\n| **claude** | default | haiku / sonnet / default |\n| **codex** | gpt-5.4 | gpt-5.4-mini / gpt-5.3-codex / gpt-5.4 |\n| **gemini** | auto | gemini-3.1-flash-lite-preview / gemini-2.5-flash / gemini-3.1-pro-preview |\n| **copilot** | claude-sonnet-4.6 | claude-haiku-4.5 / claude-sonnet-4.6 / claude-opus-4.6 |\n| **ollama** | qwen3.5:9b | 2b / 9b / 35b (parameter sizes, any model from ollama.com) |\n\nSize 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.\n\n### Provider downgrade\n\nWhen 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:\n\n```\n! Downgrading provider: gemini → copilot ('gemini' CLI not found in PATH. ...)\n```\n\nThe default tier order is `claude → codex → gemini → copilot → ollama`. Pin a provider with `-p \u003cname\u003e` to disable the fallback and get a hard error when the binary is missing.\n\n## Commands\n\n```\nzag run [prompt]              Interactive session (optional initial prompt)\nzag exec \u003cprompt\u003e             Non-interactive — print output and exit (supports --resume, --continue)\nzag review                    Code review (--uncommitted, --base, --commit)\nzag plan \u003cgoal\u003e               Generate an implementation plan (writes to file or stdout)\nzag config [key] [value]      View or set configuration\nzag session list|show|import|delete|update  List/inspect/manage sessions\nzag listen \u003cid\u003e               Tail a session's log events in real-time\nzag ps list|show|stop|kill    List, inspect, and manage agent processes\nzag search \u003cquery\u003e            Search through session logs\nzag input [message]           Send a user message to a single session\nzag broadcast [message]       Send a message to all sessions in the project\n\nzag spawn \u003cprompt\u003e            Launch background agent, return session ID\nzag spawn -I [prompt]         Spawn long-lived interactive session (FIFO-based)\nzag wait \u003cid\u003e... [--timeout]  Block until session(s) complete\nzag status \u003cid\u003e               Machine-readable session health check\nzag collect [--tag \u003ctag\u003e]     Gather results from multiple sessions\nzag env [--session \u003cid\u003e]      Export session environment variables\nzag pipe \u003cids\u003e... -- \u003cprompt\u003e Chain session results into a new session\nzag events \u003cid\u003e [--type ...]  Query structured events from session logs\nzag cancel \u003cid\u003e... [--tag]    Gracefully cancel running sessions\nzag summary \u003cid\u003e... [--tag]   Log-based session summary and stats\nzag watch \u003cid\u003e --on \u003cevent\u003e   Execute command on matching log events\nzag subscribe [--tag \u003ctag\u003e]   Multiplexed event stream from all sessions\nzag log \u003cmessage\u003e [--session] Append custom event to a session log\nzag output [\u003cid\u003e] [--latest]  Extract final result text from a session\nzag retry \u003cid\u003e... [--failed]  Re-run failed sessions with same config\nzag gc [--force] [--older-than]  Clean up old session data and logs\n\nzag serve [--port] [--token]   Start HTTPS/WS server for remote access\nzag connect \u003curl\u003e --token     Connect to a remote zag server\nzag disconnect                Disconnect from remote server\nzag user add|remove|list|passwd  Manage user accounts on the server\n\nzag discover                  Discover providers, models, and capabilities\nzag capability                Show provider capability declarations\nzag skills list|show|add|remove|sync|import   Manage provider-agnostic skills\nzag mcp list|show|add|remove|sync|import     Manage MCP servers across providers\nzag whoami                    Show current session identity (for agents)\nzag man [command]             Built-in manual pages\n```\n\n## Flags\n\n| Flag | Short | Description |\n|------|-------|-------------|\n| `--provider \u003cname\u003e` | `-p` | claude, codex, gemini, copilot, ollama, auto |\n| `--model \u003cname\u003e` | `-m` | Model name, size alias (small/medium/large), or auto |\n| `--system-prompt \u003ctext\u003e` | `-s` | Appended to the agent's system prompt |\n| `--root \u003cpath\u003e` | `-r` | Root directory for the agent |\n| `--auto-approve` | `-a` | Skip permission prompts |\n| `--add-dir \u003cpath\u003e` | | Additional directories to include (repeatable) |\n| `--file \u003cpath\u003e` | | Attach a file to the prompt (repeatable) |\n| `--env \u003cKEY=VALUE\u003e` | | Environment variable for the agent subprocess (repeatable) |\n| `--worktree [name]` | `-w` | Run in an isolated git worktree |\n| `--sandbox [name]` | | Run inside a Docker sandbox |\n| `--json` | | Request structured JSON output |\n| `--json-schema \u003cschema\u003e` | | Validate output against a JSON schema |\n| `--session \u003cuuid\u003e` | | Pre-set the session ID |\n| `--name \u003cname\u003e` | | Human-readable session name (for discovery) |\n| `--description \u003ctext\u003e` | | Short description of the session's purpose |\n| `--tag \u003ctag\u003e` | | Session tag (repeatable, for discovery/filtering) |\n| `--max-turns \u003cn\u003e` | | Maximum number of agentic turns |\n| `--timeout \u003cduration\u003e` | | Timeout duration (e.g., 30s, 5m, 1h). Kills the agent if exceeded. |\n| `--mcp-config \u003cconfig\u003e` | | MCP server config: JSON string or file path (Claude only) |\n| `--size \u003csize\u003e` | | Ollama parameter size (e.g., 2b, 9b, 35b) |\n| `--show-usage` | | Show token usage statistics (JSON output mode) |\n| `--exit-on-failure` | | `exec` only — exit with non-zero code if the agent reports failure |\n| `--debug` | `-d` | Debug logging |\n| `--quiet` | `-q` | Suppress all output except the agent's response |\n| `--verbose` | `-v` | Styled output with icons in exec mode |\n| `--help-agent` | | Print an AI-oriented CLI reference and exit |\n| `--no-health-check` | | Skip health check before proxying to a remote server |\n\n## Session management\n\nEvery interactive session gets a session ID. You can name and tag sessions for discovery, resume them, and `zag` tracks provider-native session IDs automatically.\n\n```bash\n# Create sessions with metadata for discovery\nzag exec --name \"backend-agent\" --tag backend \"implement API\"\nzag run --name \"frontend-agent\" --tag frontend --description \"CSS work\"\n\n# Resume a specific session (interactive or non-interactive)\nzag run --resume \u003csession-id\u003e\nzag exec --resume \u003csession-id\u003e \"add tests for the new handler\"\n\n# Resume the most recent session\nzag run --continue\nzag exec --continue \"keep going\"\n\n# List and filter sessions\nzag session list\nzag session list --tag backend     # filter by tag\nzag session list --name frontend   # filter by name\n\n# Send messages by name\nzag input --name backend-agent \"check the auth module\"\n\n# Broadcast to all sessions in the project (or filter by tag)\nzag broadcast \"report status\"\nzag broadcast --tag backend \"report status\"\n\n# Update session metadata\nzag session update \u003cid\u003e --tag new-tag\n\n# Tail a session's logs in real-time (from another terminal)\nzag listen \u003csession-id\u003e\nzag listen --latest --rich-text\nzag listen --ps \u003cpid\u003e             # by OS PID or zag process UUID\n```\n\n## Orchestration\n\n`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.\n\n```bash\n# Spawn parallel agents\nsid1=$(zag spawn --name analyzer --tag batch -p claude \"analyze auth module\")\nsid2=$(zag spawn --name reviewer --tag batch -p gemini \"review test coverage\")\nsid3=$(zag spawn --name scanner --tag batch -p codex \"find security issues\")\n\n# Check health\nzag status $sid1                          # → running | idle | completed | failed | dead\n\n# Block until all finish (exit code reflects success)\nzag wait --tag batch --timeout 10m\n\n# Collect results\nzag collect --tag batch --json \u003e results.json\n\n# Feed a session's result into a new agent\nzag exec --context $sid1 \"summarize the analysis and suggest fixes\"\n\n# Propagate agent failure as a non-zero exit code\nzag exec --exit-on-failure \"fix the bug\" || echo \"Agent reported failure\"\n\n# Export session env for nested invocations\neval $(zag env --shell --session $sid1)\n\n# Query parent-child process trees\nzag ps list --children $PARENT_SESSION_ID\nzag session list --parent $PARENT_SESSION_ID\n\n# Filter listen to specific event types\nzag listen $sid1 --filter session_ended --filter tool_call\n\n# Chain session results into a new agent session (tag/name/worktree/sandbox/timeout supported)\nzag pipe --tag batch -- \"synthesize all findings into a report\"\nzag pipe $sid1 $sid2 --name synth --tag report -w -- \"write a report\"\n\n# Query structured events from a session log\nzag events $sid1 --type tool_call --json\nzag events $sid1 --last 10 --after-seq 42\n\n# Gracefully cancel sessions\nzag cancel $sid1 --reason \"orchestrator timeout\"\nzag cancel --tag batch\n\n# Get session summaries (no LLM call — log-based)\nzag summary --tag batch --json\n\n# Watch for events and react\nzag watch $sid1 --on session_ended -- echo \"done: {session_id}\"\nzag watch --tag batch --on session_ended --filter 'success=false' --once\n\n# Subscribe to a multiplexed event stream from all sessions\nzag subscribe --tag batch --json | jq 'select(.type == \"session_ended\")'\n\n# Long-lived interactive sessions (Claude only)\nsid=$(zag spawn --interactive --name worker -p claude)\nzag input --name worker \"analyze the auth module\"\nzag input --name worker \"now refactor the error handling\"\nzag listen --name worker\n\n# DAG workflows with spawn dependencies\nsid_a=$(zag spawn \"analyze code\")\nsid_b=$(zag spawn --depends-on $sid_a \"fix issues from analysis\")\nsid_c=$(zag spawn --depends-on $sid_a --inject-context \"write tests\")\nsid_d=$(zag spawn --depends-on $sid_b --depends-on $sid_c \"final report\")\n```\n\nFilesystem lifecycle markers are written to `~/.zag/events/` (`.started` and `.ended` files) for external non-Rust orchestrators that prefer `inotifywait` over polling.\n\n## Remote access\n\nRun agents on your home machine and control them from anywhere (mobile, laptop, another server).\n\n```bash\n# On the server machine — start the zag server\nzag serve --generate-token --port 2100\n# Output: Generated token: a1b2c3...\n\n# With TLS (recommended for non-VPN networks)\nzag serve --token a1b2c3... --tls-cert cert.pem --tls-key key.pem\n\n# On the client machine — connect to the server\nzag connect https://home.local:2100 --token a1b2c3...\n\n# Now all commands transparently proxy through the remote server\nzag spawn \"write tests for the auth module\"\nzag listen --latest\nzag session list\nzag status \u003csession-id\u003e\n\n# Spawn an interactive session on the remote machine\nsid=$(zag spawn --interactive --name worker -p claude)\nzag input --name worker \"analyze the auth module\"\nzag listen --name worker\n\n# Disconnect when done\nzag disconnect\n```\n\nWhen 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.\n\nThe server exposes REST and WebSocket endpoints at `/api/v1/`. See `zag man serve` and `zag man connect` for details.\n\n## Worktree and sandbox isolation\n\n```bash\n# Worktree: isolated git worktree per session\nzag -w run                        # auto-named\nzag -w my-feature exec \"...\"      # named\n\n# Sandbox: Docker microVM isolation\nzag --sandbox run                  # auto-named\nzag --sandbox my-sandbox exec \"...\"\n\n# Both track sessions — resume restores the correct workspace\nzag run --resume \u003cid\u003e\n```\n\nAfter interactive sessions, you're prompted to keep or remove the workspace. Exec sessions with changes are kept automatically with a resume command printed.\n\n## JSON output\n\n```bash\n# Request JSON output\nzag exec --json \"list 3 programming languages\"\n\n# Validate against a schema (inline or file path)\nzag exec --json-schema '{\"type\":\"object\",\"required\":[\"languages\"]}' \"list 3 languages\"\n\n# Stream events as NDJSON\nzag exec -o stream-json \"complex task\"\n```\n\nClaude 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.\n\n### Output formats\n\nWith `exec -o \u003cformat\u003e`:\n\n| Format | Description |\n|--------|-------------|\n| *(default)* | Streamed text — beautiful formatting for Claude, plain for others |\n| `text` | Raw agent output, no parsing |\n| `json` | Compact unified JSON (AgentOutput) |\n| `json-pretty` | Pretty-printed unified JSON |\n| `stream-json` | NDJSON event stream (unified format) |\n| `native-json` | Claude's raw JSON format (Claude only) |\n\n## Configuration\n\nPer-project config lives at `~/.zag/projects/\u003csanitized-path\u003e/zag.toml`. Falls back to `~/.zag/zag.toml` outside of git repos.\n\n```bash\nzag config                          # Print current config\nzag config provider gemini          # Set default provider\nzag config model.claude=opus        # Set per-agent model default\nzag config auto_approve true        # Skip permission prompts by default\nzag config max_turns 10             # Set default max agentic turns\nzag config system_prompt \"Be concise\" # Set default system prompt\nzag config unset provider           # Unset a config key (revert to default)\n```\n\n```toml\n[defaults]\nprovider = \"claude\"\nmodel = \"medium\"\nauto_approve = false\n# max_turns = 10\n# system_prompt = \"\"\n\n[models]\nclaude = \"opus\"\ncodex = \"gpt-5.4\"\n\n[auto]\nprovider = \"claude\"\nmodel = \"sonnet\"\n\n[ollama]\nmodel = \"qwen3.5\"\nsize = \"9b\"\n```\n\nSettings priority: CLI flags \u003e config file \u003e agent defaults.\n\n## Skills\n\n`zag` supports provider-agnostic skills using the [Agent Skills](https://agentskills.io) open standard. Skills are stored in `~/.zag/skills/` and automatically synced to each provider's native skill directory via symlinks.\n\n```bash\nzag skills list                     # List all skills\nzag skills add commit               # Create a new skill\nzag skills import --from claude     # Import existing Claude skills\nzag skills sync                     # Sync to all providers\n```\n\n## MCP Servers\n\nManage 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/\u003cpath\u003e/mcp/` (project-scoped), and synced into each provider's native config format with a `zag-` prefix.\n\n```bash\nzag mcp add github --command npx --args -y @modelcontextprotocol/server-github\nzag mcp add sentry --transport http --url https://mcp.sentry.dev/sse\nzag mcp list                        # List all MCP servers\nzag mcp sync                        # Sync to all providers\nzag mcp import --from claude        # Import from provider config\nzag mcp remove github               # Remove + clean provider configs\n```\n\nSupported providers: Claude (`~/.claude.json`), Gemini (`~/.gemini/settings.json`), Copilot (`~/.copilot/mcp-config.json`), Codex (`~/.codex/config.toml`).\n\n## Programmatic API\n\nThe `zag-agent` crate exposes an `AgentBuilder` for driving agents from Rust code:\n\n```rust\nuse zag::builder::AgentBuilder;\n\nlet output = AgentBuilder::new()\n    .provider(\"claude\")\n    .model(\"sonnet\")\n    .auto_approve(true)\n    .name(\"hello-agent\")        // optional — registers with the session store\n    .tag(\"example\")              // so `zag session list`, `zag input --name`, etc. find it\n    .exec(\"write a hello world program\")\n    .await?;\n\nprintln!(\"{}\", output.result.unwrap_or_default());\n```\n\n#### Live event streaming\n\n`AgentBuilder` can opt in to session logging and live event callbacks, so\nprogrammatic consumers see the same structured stream as `zag listen`\nwithout shelling out to the CLI:\n\n```rust\nuse zag::builder::AgentBuilder;\nuse zag::listen::ListenFormat;\n\n// Tail every event to stderr (same formatter as `zag listen`).\nlet output = AgentBuilder::new()\n    .provider(\"claude\")\n    .stream_events_to_stderr(ListenFormat::Text)\n    .stream_show_thinking(false)\n    .exec(\"refactor this module\")\n    .await?;\n\n// Or register your own callback for fine-grained handling.\nlet output = AgentBuilder::new()\n    .provider(\"claude\")\n    .on_log_event(|event| {\n        eprintln!(\"{}: {:?}\", event.session_id, event.kind);\n    })\n    .exec(\"refactor this module\")\n    .await?;\n\n// The written JSONL path is available on the output once logging is on.\nprintln!(\"log: {:?}\", output.log_path);\n```\n\nBoth helpers implicitly enable `SessionLogMode::Auto`; use\n`.session_log(SessionLogMode::Disabled | Auto | External(coord))` for\nexplicit control (e.g. when an outer caller already owns a\n`SessionLogCoordinator`).\n\nUse `.on_spawn(|pid| ...)` to capture the OS pid of the spawned agent\nsubprocess right after spawn. This is how `zag` wires its own process\nstore so `zag ps kill self` SIGTERMs the agent child rather than the\nparent `zag` process; downstream Rust programs can do the same to\nregister the child pid with their own registries.\n\nSee the [`zag-agent` crate](zag-agent/) 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.\n\n### Language bindings\n\nSDK 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.\n\n**TypeScript** (`bindings/typescript/`)\n\n```typescript\nimport { ZagBuilder } from \"@nlindstedt/zag-agent\";\n\nconst output = await new ZagBuilder()\n  .provider(\"claude\")\n  .model(\"sonnet\")\n  .autoApprove()\n  .exec(\"write a hello world program\");\n\nconsole.log(output.result);\n\n// Streaming\nfor await (const event of new ZagBuilder().provider(\"claude\").stream(\"analyze code\")) {\n  console.log(event.type);\n}\n```\n\n**Python** (`bindings/python/`)\n\n```python\nfrom zag import ZagBuilder\n\noutput = await ZagBuilder() \\\n    .provider(\"claude\") \\\n    .model(\"sonnet\") \\\n    .auto_approve() \\\n    .exec(\"write a hello world program\")\n\nprint(output.result)\n\n# Streaming\nasync for event in await ZagBuilder().provider(\"claude\").stream(\"analyze code\"):\n    print(event.type)\n```\n\n**C#** (`bindings/csharp/`)\n\n```csharp\nusing Zag;\n\nvar output = await new ZagBuilder()\n    .Provider(\"claude\")\n    .Model(\"sonnet\")\n    .AutoApprove()\n    .ExecAsync(\"write a hello world program\");\n\nConsole.WriteLine(output.Result);\n\n// Streaming\nawait foreach (var evt in new ZagBuilder().Provider(\"claude\").StreamAsync(\"analyze code\"))\n{\n    Console.WriteLine(evt.Type);\n}\n```\n\n**Swift** (`bindings/swift/`)\n\n```swift\nimport Zag\n\nlet output = try await ZagBuilder()\n    .provider(\"claude\")\n    .model(\"sonnet\")\n    .autoApprove()\n    .exec(\"write a hello world program\")\n\nprint(output.result ?? \"\")\n\n// Streaming\nfor try await event in ZagBuilder().provider(\"claude\").stream(\"analyze code\") {\n    print(event)\n}\n```\n\n**Java** (`bindings/java/`)\n\n```java\nimport io.zag.ZagBuilder;\n\nvar output = new ZagBuilder()\n    .provider(\"claude\")\n    .model(\"sonnet\")\n    .autoApprove()\n    .exec(\"write a hello world program\");\n\nSystem.out.println(output.result());\n\n// Streaming\nfor (var event : new ZagBuilder().provider(\"claude\").stream(\"analyze code\")) {\n    System.out.println(event.type());\n}\n```\n\n**Kotlin** (`bindings/kotlin/`)\n\n```kotlin\nimport zag.ZagBuilder\n\nval output = ZagBuilder()\n    .provider(\"claude\")\n    .model(\"sonnet\")\n    .autoApprove()\n    .exec(\"write a hello world program\")\n\nprintln(output.result)\n\n// Streaming\nZagBuilder().provider(\"claude\").stream(\"analyze code\").collect { event -\u003e\n    println(event.type)\n}\n```\n\n## Examples\n\nThe `examples/` directory contains complete projects demonstrating `zag` usage:\n\n- **[cv-review](examples/cv-review/)** — A Rust program that uses the `zag` library crate to review CVs against job descriptions using parallel agent invocations\n- **[orchestration](examples/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)\n- **[react-claude-interface](examples/react-claude-interface/)** — A React web app that provides a Claude Code-like chat interface powered by `zag exec` and `zag input` with streaming NDJSON events over Server-Sent Events\n- **[ZagChat](examples/ZagChat/)** — A native macOS SwiftUI chat app built on the Swift bindings, demonstrating `StreamingSession`, expandable tool-call details, and sub-agent nesting\n\nSee the [examples directory](examples/) for details on each.\n\n## Troubleshooting\n\n**\"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](#agent-clis) table above.\n\n**\"Invalid model 'X' for Y\"** — You specified a model name that the provider doesn't recognize. Use `zag discover --models -p \u003cprovider\u003e` to see available models, or use size aliases (`small`, `medium`, `large`). Use `zag discover --resolve \u003calias\u003e -p \u003cprovider\u003e` to trace what an alias resolves to.\n\n**`--worktree` fails** — You must be inside a git repository. The worktree is created under `~/.zag/worktrees/`.\n\n**`--sandbox` fails** — Docker must be installed and running. Sandbox mode uses `docker sandbox run` for microVM isolation.\n\n**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.\n\n## Documentation\n\n- [Getting Started](docs/getting-started.md) — Step-by-step tutorial for new users\n- [Providers](docs/providers.md) — Feature comparison, model recommendations\n- [Configuration](docs/configuration.md) — Complete config reference\n- [Events \u0026 Logging](docs/events-and-logging.md) — NDJSON event format reference\n- [Troubleshooting](docs/troubleshooting.md) — Common issues and solutions\n- [Contributing](CONTRIBUTING.md) — Development workflow and guidelines\n- `zag man \u003ccommand\u003e` — Built-in manual pages for every command\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for the development workflow, branch naming conventions, commit style, and pull request process.\n\n## Architecture\n\n```\nzag (binary crate)\n  CLI parsing (clap) → dispatch to zag-agent and zag-orch\n  Session logs, worktree/sandbox lifecycle, JSON mode, auto-selection\n\nzag-agent (library crate)\n  Agent trait, provider implementations, AgentBuilder API\n  Config, output types, session logs, skills, process helpers\n\nzag-orch (orchestration crate)\n  spawn, wait, collect, pipe, cancel, status, events\n  watch, subscribe, summary, retry, gc, and more\n```\n\nEach 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.\n\n## Development\n\n```bash\nmake build          # Dev build\nmake test           # Run tests\nmake clippy         # Lint (zero warnings)\nmake fmt            # Format\nmake release        # Release build\n```\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniclaslindstedt%2Fzag","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fniclaslindstedt%2Fzag","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniclaslindstedt%2Fzag/lists"}