Working with an agent
How a coding agent should drive zya: output, JSON, errors and safe habits.
This page is written for coding agents (Claude Code, Codex, Cursor and others)
that build and deploy Zenitya tools with the zya CLI. People can read it too:
it is the shortest path to driving the CLI from scripts.
Read the docs that match the installed CLI with zya docs:
zya docs # list topics
zya docs agents # this page
zya docs quickstart # the end-to-end flow
zya docs cli # every command and optionA link to <topic>.md in these pages is another topic: read it with
zya docs <topic>. The same pages are online at https://zenitya.com/docs,
and each one as markdown at https://zenitya.com/docs/<topic>.md. Prefer
zya docs: it always matches the CLI you are running.
Before you start
- Check the CLI:
zya --version. If it is missing, install it withcurl -fsSL https://zenitya.dev/install.sh | shand use~/.zenitya/bin/zyauntil a new shell picks up the PATH. - Check the login:
zya whoami --json. If it fails witherror[AUTH_INVALID], ask the person to runzya loginthemselves. It opens a browser for Google sign-in, which you cannot complete for them. - Zenitya is in private beta. If sign-in shows a waitlist or a command fails
with
error[ACCESS_NOT_GRANTED], the person needs an invitation; send them to https://zenitya.com/early-access and stop. - Inside a project, commands use the nearest
zenitya.jsonfrom the current directory up. Outside one,zya new <directory>creates a project.
The loop
zya new my-tools && cd my-tools && bun install
# edit src/index.ts
bun run check # type-check
zya exec <tool> --local --data '{"...": "..."}' # run the source
zya deploy --json # build remotely, go live
zya tools list --json # what the credential can call
zya exec <tool> --data '{"...": "..."}' # run the deployed copyAlways run a tool with --local before deploying it. A deploy takes a minute
or two; a local run takes a second.
After the first deploy, a tool is callable only once an owner or admin grants
it to a group in the Zenitya app (Groups, then the group, then the tool).
If zya tools list does not show a tool you deployed, ask the person to grant
it; you cannot do that from the CLI.
Reading output
The CLI is built to be read by programs:
- stdout is data only. Tool output from
exec, listings and--jsonresults. Nothing else is ever written there. - stderr is for messages. Progress, notes, warnings and errors. Tool logs
from
execare JSON lines on stderr. - No decoration when piped. Without a terminal, or with
CIset orTERM=dumb, messages are plain lines and listings are tab-separated rows without a header.NO_COLORturns color off everywhere. - Exit code 1 on any failure.
Use --json whenever you parse a result. These commands support it:
| Command | --json prints |
|---|---|
zya deploy | { project, buildId, state, deploymentId, active, toolCount, skills, idempotencyKey } |
zya tools list | { project, activeDeployment, tools: [{ name, key, title, description, ... }] } |
zya builds list | { builds: [{ id, state, createdAt, deployment, ... }] } |
zya builds view <id> | { build, deployment, steps, diagnostics } |
zya builds logs <id> | One JSON record per line: { seq, phase, stream, capturedAt, text } |
zya secrets list | { secrets: [{ name, updatedAt }] } (never values) |
zya whoami | { identity, organization, organizationId, scopes, apiUrl, credential } |
zya exec always prints the tool's output as JSON, so it needs no flag.
Recipes:
zya deploy --json | jq -r .buildId
zya tools list --json | jq -r '.tools[].key'
zya builds list --json | jq -r '.builds[] | select(.state == "failed") | .id'
zya builds logs <build-id> --json | jq -r 'select(.stream == "stderr") | .text'
zya whoami --json | jq -r .organizationId
zya exec search --data '{"query":"late"}' | jq '.items | length'Errors
Every failure prints one line on stderr:
error[CODE]: what happened
hint: the next step, when there is oneRead the code, follow the hint, and add --verbose for details and a stack
trace. A failed API call ends with (request <id>): quote it when reporting a
problem to the person. Codes you will meet:
| Code | Meaning and what to do |
|---|---|
CONFIG_MISSING | No zenitya.json here or above. cd into the project, or zya new. |
CONFIG_INVALID | zenitya.json breaks a rule; the message names the field. See config.md. |
INPUT_INVALID | Bad arguments or tool input. The hint shows the expected form. |
FLAG_UNKNOWN, COMMAND_UNKNOWN | Typo; the hint suggests the closest match. |
AUTH_INVALID | Not signed in, or the credential lacks a permission. Ask the person to run zya login. |
ACCESS_NOT_GRANTED | The account has no beta access yet. Send the person to https://zenitya.com/early-access. |
TOOL_FAILED | The tool itself failed: error[TOOL_FAILED]: <code>: <message>. invalid_input means the input did not match the schema; execution_error means the code threw. |
DEPLOY_FAILED | The build failed or could not start. Read the build output (below). |
SKILL_INVALID | A SKILL.md breaks the format; the message names the file. |
BUN_NOT_FOUND | --local needs Bun on PATH. Install it from https://bun.sh. |
When a deploy fails
zya builds list --limit 1 --json | jq -r '.builds[0].id'
zya builds view <build-id> # which step failed and why
zya builds logs <build-id> --phase install # dependency installation output
zya builds logs <build-id> --phase bundle # bundling output
zya builds logs <build-id> --phase describe # loading your toolsA failed build changes nothing: the previous deployment keeps serving calls. See Deploying and builds.
Safe habits
- Never put a secret on the command line or in source. Pipe it:
printf %s "$VALUE" | zya secrets set API_TOKEN --stdin. Better, ask the person to run that command themselves so the value never enters your context. - Never print or log secret values, and never commit
.env..envis for--localruns only and is never uploaded. - Ask before deploying if the person has not asked you to, and before
calling a deployed tool that changes data (one without
readOnlyHint). - Write precise descriptions. Other agents choose tools by their
descriptionand their schema's.describe()text; say what the tool does, when to use it and what it returns. See Writing tools. - Keep tools small and deterministic. One tool per workflow step that another agent would otherwise do by hand.
When working in a Zenitya project
Projects created with zya new have an AGENTS.md that says so. If a
repository has a zenitya.json, it is a Zenitya project: read this page and
Writing tools before changing it.
zenitya