Agent mode, JSON output and exit codes
This page covers how the uno CLI behaves when a program drives it. It is for developers who write agents and scripts that run uno. After you read it, you can parse every result and react to every exit code. The page is self-contained.
Agent mode
Agent mode makes the CLI print JSON, refuse prompts and require explicit inputs for writes.
The CLI turns agent mode on when any of these is true:
UNO_AGENT=1is set.CLAUDECODEis set and not empty. Claude Code sets it.CODEX_THREAD_IDis set and not empty. OpenAI Codex sets it.- You pass an explicit format flag such as
--jsonor--format json. - Stdout is not a terminal.
CI alone on a terminal does not select JSON output, but account pins and guards still treat it as automation. A pseudo-terminal does not turn agent mode off. UNO_AGENT=0 does not disable the other markers. If your host sets no marker, pass --json or set UNO_AGENT=1.
In agent mode:
- Output is JSON.
kit catreturns text underdata.text. Raw byte output is refused with exit 2. Usekit get --out <file>, orkit cat --base64 --jsonfor base64 underdata.inline_content. - Guarded changes exit 2 unless you pass
--yes. The guard checks the agent markers (UNO_AGENT=1,CLAUDECODE,CODEX_THREAD_ID) and whether stdin and stdout are terminals.--jsonon a terminal does not trigger it. Thectathat adds--yesgrants no permission. Get the user's approval first. - Account work needs an account pin. See Pin the account.
- Kit writes need
--operation. See Operation ids.
Output formats
--json is an alias for --format json. Both print one JSON object on stdout. With --json or --format json, a failure prints the same object, with error set, on stdout and prints nothing on stderr. Some commands, such as account create and account key import, still write a key warning to stderr on success.
Use --filter-output and the --token-* flags to shrink output. They apply only to data. The receipt fields always print.
The JSON envelope
Every JSON result has the same shape. This holds for successes, errors, parse failures, discovery and filtered output.
| Field | Meaning |
|---|---|
schema_version | Always 2 |
account | The acting account: id, username, verified, origin, source, state, evidence, authenticated, expectation_enforced, expected_account_id |
selection | How the CLI chose the account: source, value, account_id, binding_path |
assertion | The pin check: expected_account_id, source, matched |
execution | What this run did: operation_id, request_id, transport_origin, account_used, business_request_sent, outcome |
data | The command result. null when a thrown error ended the command |
error | null on success. Otherwise an object, described below |
exit_code | The process exit code |
Command values appear only under data. Read data.account_id, not a root account_id. Unknown facts are null.
execution.outcome is one of not_started, succeeded, failed, pending or unknown. Treat pending and unknown as "the write may still land". Keep the account, the operation id and the inputs, and recover with the same operation.
account is the actor. A Kit owner or a payment target is a separate value under data. Local evidence proves no authentication. For account work, check that account.evidence is "server", account.authenticated is true and assertion.matched is true.
The error object
| Field | Meaning |
|---|---|
code | The name of the exit code, such as ACCOUNT_PIN_REQUIRED |
message | What failed |
hint | The rest of the text, or null |
cta | The exact command to run next, or null. It is not approval to run it |
retryable | true when the same command can succeed later: exit 7, 8 or 14 |
details | Data about the failure, such as details.reason, or details.payment for exit 15 |
details.request_id is the id of the newest RPC of the run. Report it when you ask for help. It is missing when the run sent no RPC.
Some commands return data with a nonzero exit code and error: null. Partial logout --all is one. Read the shell exit code, exit_code and data. Keep every partial result.
Example: exit 27
This refusal comes from uno notifications list --json with an active account and no pin. The CLI sent no request.
{
"schema_version": 2,
"account": {
"id": "<account-b-uuid>",
"username": null,
"verified": null,
"origin": "https://api.uno.fun",
"source": "active",
"state": "local",
"evidence": "local",
"authenticated": null,
"expectation_enforced": false,
"expected_account_id": null
},
"selection": {
"source": "active",
"value": "<account-b-uuid>",
"account_id": "<account-b-uuid>",
"binding_path": null
},
"assertion": {
"expected_account_id": null,
"source": "none",
"matched": null
},
"execution": {
"operation_id": null,
"request_id": null,
"transport_origin": null,
"account_used": false,
"business_request_sent": false,
"outcome": "not_started"
},
"data": null,
"error": {
"code": "ACCOUNT_PIN_REQUIRED",
"message": "Account work in automation requires --account <uuid> or a matching --expect-account <uuid>.",
"hint": "Inspect with `uno account list`.",
"cta": "uno account list",
"retryable": false,
"details": { "reason": "account_pin_required" }
},
"exit_code": 27
}No other output samples are published on this page. Read the schema of a command for its data fields. See Discover commands.
Pin the account
Account work in agent mode needs an account UUID. Set both variables, or pass both flags on each command:
export UNO_ACCOUNT=<uuid>
export UNO_EXPECT_ACCOUNT="$UNO_ACCOUNT"--account selects an account. --expect-account only refuses: it never selects. A default account or a folder binding alone exits 27. A mismatch exits 25. Never switch accounts to clear an auth or payment error.
Operation ids
An operation id makes a write safe to repeat. Pass --operation <id> on every Kit write in agent mode. A write without it exits 2. The error cta is the same command with a new id.
- Use letters, digits,
.,_and-, up to 128 characters. - Reuse the same id only for a retry with identical inputs.
- Use a new id when the inputs change.
uno account createalso needs--operationin agent mode.kit commitalso needs--expected-head. Use--expected-head=""for a branch that does not exist yet.- Key commands and social commands (
star,follow) take no--operation.
After exit 7 or 14, or after a lost reply, rerun the same command with the same id. You can also run uno kit resume <operation>. Never start a new id while the write may still land.
Worked example: small-file lifecycle
Open an upload session, stage one file, commit it and wait for the job. These are account writes, so in agent mode export UNO_ACCOUNT and UNO_EXPECT_ACCOUNT first (see Pin the account) and add --format json to each command. Replace the placeholders with values from the earlier results. Read <session-id> and <job-id> from data.
uno kit whoami
uno kit upload-session example --bytes 5 --files 1 --operation up-1
uno kit stage <session-id> ./hello.txt --path hello.txt --operation stage-1
uno kit commit <session-id> --message "Add hello" --expected-head="" --operation commit-1
uno kit job <job-id> --waitupload-session sends no bytes. Each job --wait polls for up to 60 seconds, so run it again until the job ends. A commit that returns a failed job exits 21. For files above the inline limit, use uno kit upload instead of kit stage.
Discover commands
Do not guess flags or output fields. Ask the CLI.
uno --llms --format jsonlists the commands.uno --llms-full --format jsonlists all commands with their flags and output fields.uno <command> --schemaprints the schema of one command, for exampleuno kit upload --schema.uno <command> --helpprints its help.uno --helpprints the exit-code table.
Global flags
These flags work on every command.
| Flag | Meaning |
|---|---|
--account <uuid> | Select an existing account by UUID. A username works only at a terminal |
--expect-account <uuid> | Require this account UUID. Never selects |
--anonymous | Read public data without credentials. Conflicts with account constraints |
--telemetry, --no-telemetry | Share usage analytics. On by default |
--api <origin> | API origin. Default https://api.uno.fun |
--kit-api <origin> | Kit API origin. Default https://kit.uno.fun |
--confirm-kit-api-origin <origin> | Allow Kit credentials to go to this origin. It must equal the origin in use |
--kit-target <name> | Kit deployment. Only production is accepted |
--trace | Print each request to stderr, with secrets removed |
--format <fmt> | Output format |
--json | Alias for --format json |
--filter-output | Filter the output. Applies to data only |
--full-output | Output flag from the CLI framework. It applies to structured output such as kit cat. Run uno --help for its text |
--token-count, --token-limit, --token-offset | Count or page the output in LLM tokens. They take integers where a value is needed |
--llms, --llms-full | Print the command manifest |
--schema | Print the schema of a command |
--help | Print help |
Credentials and origins
No command takes a credential as a flag. The CLI refuses to define any flag whose name contains token, secret, password, passphrase, credential, bearer, authorization, cookie, key or signature. The one exception in spelling is --passkey on uno login, a boolean that selects the passkey method.
Kit credentials go only to https://kit.uno.fun. They go to another Kit origin only when you pass --confirm-kit-api-origin with that exact origin. Pass --api, --kit-api and --confirm-kit-api-origin only when the user asks.
Exit codes
The CLI uses one table. Read exit_code in the envelope or the shell status.
| Code | Name | Meaning |
|---|---|---|
| 0 | OK | Success |
| 1 | INTERNAL | Internal error: a bug in uno, or an unexpected server failure |
| 2 | USAGE | Usage: a bad command, flag or value |
| 3 | NOT_SIGNED_IN | Not signed in |
| 4 | NOT_FOUND | Not found, or no access |
| 7 | TRANSIENT | Temporary outage or network failure, after retries |
| 8 | RATE_LIMITED | Rate limited, after waiting |
| 9 | ABORTED | Refused by the current state: a conflict or a failed precondition |
| 10 | ALREADY_EXISTS | Already exists |
| 11 | NEEDS_STEP_UP | Needs step-up |
| 12 | CREDENTIAL_STORE_REFUSED | A credential or key file failed a safety check |
| 13 | UNSUPPORTED | Not supported by this platform or server |
| 14 | WRITE_PENDING | A write is still pending and may land |
| 15 | PAYMENT_REQUIRED | Needs payment. The JSON error names the terms and the command |
| 16 | PERMISSION_DENIED | The server denied this account the action |
| 17 | UNVERIFIED | An unverified account cannot do this |
| 21 | SEND_REJECTED | A kit job, a signature check or an object ID check failed |
| 24 | NOT_AVAILABLE | Not available yet |
| 25 | ACCOUNT_MISMATCH | The selected or authenticated account differs from the expectation |
| 26 | ACCOUNT_AMBIGUOUS | Account selection is ambiguous; use an exact UUID |
| 27 | ACCOUNT_PIN_REQUIRED | Automation needs an immutable account UUID pin |
| 128+n | Stopped by signal n: 130 for Ctrl-C, 143 for SIGTERM |
- Codes 5, 6, 20, 22 and 23 are retired. The CLI never returns them.
- Only 7, 8 and 14 are retryable. Every other code fails the same way until something else changes.
- A signal can stop the process without an envelope. The shell sets the 128+n code, so you get no JSON.
- Exit 15 carries
error.details.payment. See Pay with Tempo and Recover an uncertain payment.
What to do for each code
| Code | Next action |
|---|---|
| 1 | Report the failure and details.request_id. |
| 2 | Correct the flag or value. Check whether --operation or --yes is missing. |
| 3 | Sign in to the intended account. Use key login for an unverified account. |
| 4 | Check the address and your access. The code does not prove the resource is absent. |
| 7 | Retry the identical command. Keep the operation id on writes. |
| 8 | Wait, then retry the identical command. |
| 9 | Read the current state and the hint. Resolve the conflict. |
| 10 | Inspect the existing resource. Pick another name only for a new resource. |
| 11 | Follow the message, hint and details to approve, then rerun the same command. |
| 12 | Report the refusal. Do not edit the credential or key file. |
| 13 | Use a supported path. Never remove an account pin to get past it. |
| 14 | Recover with the same operation id. Never start a new id. |
| 15 | Follow the payment steps. Get approval for the exact terms first. |
| 16 | Report the refusal. Do not switch accounts. |
| 17 | Offer account verification. |
| 21 | Report the job, signature or object failure. Do not retry identical rejected content. |
| 24 | Stop. Do not retry. |
| 25 | Stop. Resolve the intended account. Never change actors on your own. |
| 26 | Select the intended exact UUID. Never pick the first candidate. |
| 27 | Supply a trusted account UUID with --account, or a matching --expect-account, then retry. |
Next: Command reference.