Scripting and AI Agents
Use zev from scripts, CI, servers and AI agents: tokens, JSON output and the MCP server.
Search for a command to run…
Use zev from scripts, CI, servers and AI agents: tokens, JSON output and the MCP server.
Every collaboration command in zev can be driven by a script, a CI job, or an AI agent just as well as by a person at a keyboard. The rules below are the contract such tools can rely on.
--json output goes to stdout, as a single JSON document. Everything meant for humans — progress, prompts, warnings, errors — goes to stderr. Capturing stdout therefore captures only data.0 means success, 1 means failure. On failure, the explanation is on stderr and stdout is empty, so a failed command never produces output that could be mistaken for a result.NO_COLOR environment variable is set.if result=$(zev pr list --json 2>/dev/null); then echo "$result"else echo "zev failed" >&2fiThere is one deliberate exception to "stdout is empty on failure": asking to merge a pull request that is already merged exits with 1 and prints a machine-readable error, so a tool can tell this case apart from a real failure:
{"error":"pull request is already merged","status":"merged"}An agent should never have an account of its own, and never your key. Let it sign in through you instead:
zev login zaryn.xyz --device --client "Claude Code"It prints a link and a code. You open the link, check the code, untick anything it doesn't need, and approve. The agent then holds its own token: named after it, limited to the scopes you approved, valid for 90 days, listed in Settings where you can revoke it, and recorded in the audit log under its own name.
To give the agent Zaryn as tools, add the MCP server that ships with zev:
claude mcp add zaryn -- zev mcp # Claude Codecodex mcp add zaryn -- zev mcp # Codexzev mcp offers zaryn_* tools for repositories, files, history, search, issues, pull requests, CI and advisories. It can open issues and comment (with repo:write); merging, deleting and changing settings are left to people. Agents can also start an account for a person (zev login … --register <name> --email <address>), but only the person can finish it, with the code from their inbox. See Zaryn for AI agents.
A command only prompts for information you did not supply, so passing everything as flags makes it fully non-interactive:
zev issue --title <t> --desc <d> creates an issue without prompting.zev issue comment <n> --body <text> comments without prompting.zev pr --yes opens a pull request using the drafted title and description, targeting main; add --target <branch> for a different target.zev issue close <n> --yes and zev pr merge <n> --yes skip the confirmation. With --json, confirmations are skipped as well, since a prompt would hang a non-interactive session.export ZEV_SERVER=zaryn.xyzexport ZEV_TOKEN=zev_pat_...zev issue list --repo alice/project --jsonZEV_SERVER and ZEV_TOKEN take precedence over a saved login, and --server / --token take precedence over both. Combined with --repo owner/name, this lets a tool operate on any repository from any directory, with no local checkout at all.
Reads on public repositories succeed anonymously, so an invalid token is only detected when a command needs to write — creating, commenting, closing, or merging returns HTTP 401 and exit code 1.
{"issues":[{"number":1,"title":"Login button misaligned","status":"open","author":"alice","created_at":"2026-09-22 23:38:51+03:30"}]}zev issue view <n> --json combines the issue and its comment thread:
{"issue":{"number":1,"title":"...","description":"...","status":"open","author":"alice","created_at":"..."}, "comments":{"comments":[{"id":7,"author":"alice","body":"...","created_at":"..."}]}}zev add .zev commit "Automated change"zev pushnumber=$(zev pr --yes --json 2>/dev/null | python3 -c "import json,sys; print(json.load(sys.stdin)['number'])")echo "Opened pull request #$number"zev issue list --json 2>/dev/null \ | python3 -c "import json,sys; [print(i['number']) for i in json.load(sys.stdin)['issues'] if i['status']=='open']" \ | while read n; do zev issue comment "$n" --body "Triaged automatically." --json > /dev/null donedirty=$(zev status --json | python3 -c "import json,sys; d=json.load(sys.stdin); print(len(d['staged'])+len(d['modified'])+len(d['deleted']))")if [ "$dirty" != "0" ]; then echo "Uncommitted changes present; not switching branches." >&2 exit 1fizev checkout releasezev checkout performs this same safety check on its own and exits with 1 rather than overwriting anything, so the explicit check above is only needed when a tool wants to decide what to do before trying.