Skip to content
Uno Docs

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=1 is set.
  • CLAUDECODE is set and not empty. Claude Code sets it.
  • CODEX_THREAD_ID is set and not empty. OpenAI Codex sets it.
  • You pass an explicit format flag such as --json or --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 cat returns text under data.text. Raw byte output is refused with exit 2. Use kit get --out <file>, or kit cat --base64 --json for base64 under data.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. --json on a terminal does not trigger it. The cta that adds --yes grants 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.

FieldMeaning
schema_versionAlways 2
accountThe acting account: id, username, verified, origin, source, state, evidence, authenticated, expectation_enforced, expected_account_id
selectionHow the CLI chose the account: source, value, account_id, binding_path
assertionThe pin check: expected_account_id, source, matched
executionWhat this run did: operation_id, request_id, transport_origin, account_used, business_request_sent, outcome
dataThe command result. null when a thrown error ended the command
errornull on success. Otherwise an object, described below
exit_codeThe 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

FieldMeaning
codeThe name of the exit code, such as ACCOUNT_PIN_REQUIRED
messageWhat failed
hintThe rest of the text, or null
ctaThe exact command to run next, or null. It is not approval to run it
retryabletrue when the same command can succeed later: exit 7, 8 or 14
detailsData 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 create also needs --operation in agent mode.
  • kit commit also 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> --wait

upload-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 json lists the commands.
  • uno --llms-full --format json lists all commands with their flags and output fields.
  • uno <command> --schema prints the schema of one command, for example uno kit upload --schema.
  • uno <command> --help prints its help. uno --help prints the exit-code table.

Global flags

These flags work on every command.

FlagMeaning
--account <uuid>Select an existing account by UUID. A username works only at a terminal
--expect-account <uuid>Require this account UUID. Never selects
--anonymousRead public data without credentials. Conflicts with account constraints
--telemetry, --no-telemetryShare 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
--tracePrint each request to stderr, with secrets removed
--format <fmt>Output format
--jsonAlias for --format json
--filter-outputFilter the output. Applies to data only
--full-outputOutput 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-offsetCount or page the output in LLM tokens. They take integers where a value is needed
--llms, --llms-fullPrint the command manifest
--schemaPrint the schema of a command
--helpPrint 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.

CodeNameMeaning
0OKSuccess
1INTERNALInternal error: a bug in uno, or an unexpected server failure
2USAGEUsage: a bad command, flag or value
3NOT_SIGNED_INNot signed in
4NOT_FOUNDNot found, or no access
7TRANSIENTTemporary outage or network failure, after retries
8RATE_LIMITEDRate limited, after waiting
9ABORTEDRefused by the current state: a conflict or a failed precondition
10ALREADY_EXISTSAlready exists
11NEEDS_STEP_UPNeeds step-up
12CREDENTIAL_STORE_REFUSEDA credential or key file failed a safety check
13UNSUPPORTEDNot supported by this platform or server
14WRITE_PENDINGA write is still pending and may land
15PAYMENT_REQUIREDNeeds payment. The JSON error names the terms and the command
16PERMISSION_DENIEDThe server denied this account the action
17UNVERIFIEDAn unverified account cannot do this
21SEND_REJECTEDA kit job, a signature check or an object ID check failed
24NOT_AVAILABLENot available yet
25ACCOUNT_MISMATCHThe selected or authenticated account differs from the expectation
26ACCOUNT_AMBIGUOUSAccount selection is ambiguous; use an exact UUID
27ACCOUNT_PIN_REQUIREDAutomation needs an immutable account UUID pin
128+nStopped 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

CodeNext action
1Report the failure and details.request_id.
2Correct the flag or value. Check whether --operation or --yes is missing.
3Sign in to the intended account. Use key login for an unverified account.
4Check the address and your access. The code does not prove the resource is absent.
7Retry the identical command. Keep the operation id on writes.
8Wait, then retry the identical command.
9Read the current state and the hint. Resolve the conflict.
10Inspect the existing resource. Pick another name only for a new resource.
11Follow the message, hint and details to approve, then rerun the same command.
12Report the refusal. Do not edit the credential or key file.
13Use a supported path. Never remove an account pin to get past it.
14Recover with the same operation id. Never start a new id.
15Follow the payment steps. Get approval for the exact terms first.
16Report the refusal. Do not switch accounts.
17Offer account verification.
21Report the job, signature or object failure. Do not retry identical rejected content.
24Stop. Do not retry.
25Stop. Resolve the intended account. Never change actors on your own.
26Select the intended exact UUID. Never pick the first candidate.
27Supply a trusted account UUID with --account, or a matching --expect-account, then retry.

Next: Command reference.