Skip to main content
Last updated: 2026-09-06
Every orca command decides how to print based on two things: whether --json was passed, and whether stdout is a terminal. The rules never vary by command, so a script that works with one command works with all of them.

Output modes

Plain mode follows the gh convention: one record per line, fields separated by a tab, in a fixed column order documented on each command’s reference page. Nothing needs stripping before cut, awk, or grep sees it.
Hints, warnings, progress, prompts, and errors always go to stderr, in every mode. Redirect 2>/dev/null if you want a silent pipeline; stdout stays parseable either way.

JSON

--json works on every command that reports something, including login, doctor, and update. The two exceptions are auth logout and context use, which print a short text confirmation regardless.
  • Lists print a JSON array of records (the page you asked for, or every record with --all).
  • Single-resource commands print one object.
  • Mutations print the updated record where the API returns one, or a small confirmation object such as { "name": "researcher", "deleted": true }.
  • Interactive pickers and confirmation prompts are never shown in JSON mode; a missing argument is a usage error instead.

Streams (NDJSON)

Commands that follow a live run print newline-delimited JSON under --json: one event object per line, flushed as it arrives, until the stream reaches a terminal state.
Streaming commands: orca run (unless --detach), orca runs tail, orca workflows tail, and orca chat. The device-code login also emits one NDJSON event under --json before its final result, see Authentication.

Exit codes

Errors print as orca: <message> on stderr, followed by indented detail lines where there is a fix to suggest:

Pagination

List commands share one set of paging flags: When more records exist than the page shows, terminal and plain modes print Showing X of Y on stderr. --all walks the collection in windows of 200 (the server’s per-request cap) and stops at 10,000 records with a warning; narrow the query if you hit that. Commands with their own paging: orca agents changes caps client-side with --limit (unlimited by default), orca storage ls defaults to 100 and orca storage browse to 1000 (both max 1000), orca memory list has its own --limit and --offset, and orca keys list does not page.

Interactive versus scripted

The CLI decides it is interactive when both stdin and stdout are terminals. That switches three behaviors:
  • Optional positionals such as orca agents get [name] or orca runs tail [id] open a picker when omitted in a terminal. In a script they are required, and omitting one exits 2.
  • Destructive commands (delete, remove, rm, unpublish, keys revoke, workflows cancel, billing cap set) confirm in a terminal. In a script, pass --yes or the command refuses with exit 2. The exceptions are runs cancel and agents keys revoke, which never prompt, and auth logout --revoke, which proceeds without --yes in a script.
  • Prompts that read values, such as orca secrets set without --value, read from stdin when it is a pipe and show a hidden prompt when it is a terminal.
orca login follows the same rule: no terminal means the device-code flow.

Patterns

Start a run, do other work, then collect the result.
With --json, --detach prints the full create response instead, including runId and sessionId. Fail a CI job when the agent fails. orca run and orca runs tail exit 1 when the run ends in any status other than ok, so no parsing is needed:
Capture a minted key without exposing it. Key-minting commands print only the token to a piped stdout:
Create an agent from a template.
Run the same script locally and in CI. Keep ORCA_API_KEY in CI secrets and rely on orca login locally. Flags beat environment variables, which beat the config file, so nothing in the script needs to change between the two. Feed a coding agent. The MCP server built into the CLI gives Claude Code, Cursor, and Codex the same control plane as typed tools, without shelling out. For agents that do shell out, the --json contract above is the whole interface; see CLI for agents.