> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anonalabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Scripting & automation

> JSON output, exit codes, retries and timeouts, waiting on background jobs, batch files and shell completion for the anona CLI.

Everything a script needs to use `anona` without parsing prose: one JSON
document on stdout, a stable exit code, and errors on stderr.

## JSON output

Every data command takes `--json`, and then prints **one JSON document on
stdout and nothing else there**. Each command page shows its document; the
short form is also printed by [`anona guide`](https://docs.anonalabs.com/cli/agents#anona-guide).

* On success, stdout is the document, usually the API's response as it came.
  Where the API answers with no body (a delete, a settings reset), the CLI
  writes a small document of its own, such as
  `{"deleted": true, "memory_id": ..., "space_id": ...}`.
* An empty result is still a document with exit `0`: `{"results": []}`,
  `{"items": [], ...}`.
* On failure, stdout is **empty** and a one-line error is on stderr, so
  `anona retrieve ... --json | jq` never receives half a document.
* The one exception is `record` that stored nothing: exit `3`, and its
  document (with `status: "nothing_extracted"`) is still on stdout.
* Non-ASCII and control characters are escaped (`é`, `\u001b`), so the
  output is safe to print to a terminal and decodes to exactly what was stored.

Progress and retry notices go to stderr, so they never mix into the document.
`--quiet` turns them off.

```bash theme={null}
anona record "Deploys run Tuesdays at 10:00 UTC." --tags ops,schedule --space ops --json
anona retrieve "deploy schedule" --space ops --json --limit 3 | jq -r '.results[].content'
anona reason "how does this team ship?" --space ops --json | jq -r .insights
```

## Exit codes

A script branches on the exit code rather than on the message. Each code means
the same thing on every command.

| Code | Name | Means |
| - | - | - |
| `0` | `ok` | It did what it was asked. A search that matched nothing is `0` |
| `1` | `failed` | The server refused the request for a reason no code below names (a `409` or `422`, say), or a job `--wait` was watching failed or was cancelled |
| `2` | `usage` | The command line was wrong. **Nothing was sent, and nothing was billed** |
| `3` | `nothing_stored` | `record` only: accepted, but no memory was extracted. Not an error to retry blindly: re-record with more context |
| `4` | `auth` | No usable credential, a credential that may not go to that server, or a `401` / `403` |
| `5` | `not_found` | `404`: the space, memory, job or setting does not exist |
| `6` | `rate_limited` | `429` after the retries ran out, or out of credits |
| `7` | `unavailable` | A `5xx`, a timeout, or the server could not be reached. **A write may still have been stored** |
| `8` | `still_running` | `--wait` gave up while the job was still running |

> [!NOTE]
>
> **Codes `5` to `8` are new.** pip `anona` 0.24.0 and the npm CLI report every
> refused or failed request as `1`, and a `403` as `1` rather than `4`. The table
> above is the next pip release; the npm CLI follows when its port lands. A script
> that must run on both can treat `1` and `5`-`7` alike.

The account commands (`start`, `login`, `logout`, `status`) use only `0` and
`1`, plus `2` for a wrong command line.

```bash theme={null}
anona record "$FACT" --space notes --json > out.json
case $? in
  0) echo "stored" ;;
  3) echo "nothing extracted; add context" ;;
  7) echo "unknown: check before retrying" ;;
  *) echo "failed" ;;
esac
```

## Errors

Errors go to stderr, one line, in the API's own terms:

```text theme={null}
anona: validation_error: Request validation failed -- content: String should have at least 1 character (request_id req_…)
anona: could not reach api.anonalabs.com: Connection refused
```

The first word after `anona:` is the [error code](https://docs.anonalabs.com/api-reference/errors.md), which
is the stable thing to match on. A failure to reach the server is reported as
exactly that, never as an HTTP status, because no server answered. Quote the
`request_id` when you contact support.

## Retries and timeouts

`--timeout`, `--retries`: pip 0.25.0; npm 0.19.0

| Option | Default | |
| - | - | - |
| `--timeout SECONDS` | 120 | Give up on one HTTP request after this long |
| `--retries N` | 2 | Retry a `429`, or a `5xx` on a request that is safe to repeat, up to N times, honouring `Retry-After` |
| `--quiet`, `-q` | off | No progress or retry notices on stderr; results and errors still print |

**A write is never re-sent after a `5xx` or a timeout.** The server may already
have stored it, and a second send would store it twice. So after exit `7` from
`record`, `documents upload` or any other write, check before you run it again:
`anona retrieve` or `anona memories list --q` for a record, `anona documents
list` for an upload. Reads are retried, and so is a `429` on anything, because a
rate-limited request was not processed.

Each retry says so on stderr while it waits
(`anona: rate limited, retrying in 3 s (1/2)`), so a slow command can be told
from a hung one. An expired `anona login` is renewed and the request sent once
more; that is separate from `--retries`.

## Waiting on background work

pip 0.25.0; npm 0.19.0

`record --async`, `record --batch` and `documents upload` queue work and return
job ids. Add `--wait` to poll until the jobs finish, and the exit code reports
the outcome instead of the submission:

| Exit | After `--wait` |
| - | - |
| `0` | every job completed |
| `3` | `record` only: completed, but no memory was stored |
| `1` | a job failed or was cancelled |
| `5` | the server no longer knows a job |
| `8` | still running when `--wait-timeout` ran out (default 300 s); check later with `anona jobs get JOB_ID` |

Polling is free and backs off from 1 s to 5 s. `--wait-timeout 0` is a single
status check. With `--json` the document is
`{"submitted": <what the submit returned>, "jobs": [<one jobs get document per job>]}`.

```bash theme={null}
anona record --batch history.jsonl --space notes --wait --wait-timeout 600 --json \
  | jq '.jobs[] | {job_id, status, memory_count}'
```

## Batch files

`record --batch FILE` takes [JSON Lines](https://jsonlines.org), at most 100
items, one per line: a JSON string, or an object with `content` and any of
`context`, `timestamp`, `metadata`, `tags`, `user_id`, `agent_id`,
`session_id`. The file is validated in full before anything is sent; a bad line
exits `2` and names the line number. Details and examples:
[Batch ingest](https://docs.anonalabs.com/cli/memory.md#batch-ingest).

```bash theme={null}
split -l 100 big.jsonl part-
for f in part-*; do anona record --batch "$f" --space notes --wait || break; done
```

## Global options

These go before or after the command.

| Option | |
| - | - |
| `--base-url URL` | The Anona server. See [Where a key may be sent](https://docs.anonalabs.com/cli/sign-in.md#where-a-key-may-be-sent) |
| `--profile NAME` | A [named profile](https://docs.anonalabs.com/cli/sign-in.md#named-profiles) (or `ANONA_PROFILE`) |
| `--timeout SECONDS`, `--retries N`, `--quiet` | As above |
| `--no-browser` | `login` only: print the URL instead of opening it |
| `--version` | Print the installed version |

Environment: `ANONA_API_KEY`, `ANONA_SPACE_ID`, `ANONA_BASE_URL`,
`ANONA_PROFILE`.

## In CI

Use an API key from your CI's secret store, never `anona login`, which needs a
person at a browser:

```bash theme={null}
pip install -U anona
export ANONA_API_KEY="$ANONA_KEY_FROM_SECRETS"
export ANONA_SPACE_ID=release-notes
git log -1 --format=%B | anona record - --tags ci --metadata "{\"sha\": \"$GITHUB_SHA\"}" --json
```

`anona doctor --json` is a cheap first step that fails the job early, with exit
`4` or `7`, when the key or the network is wrong.

## Shell completion

pip 0.25.0; npm 0.19.0

```bash theme={null}
anona completion bash > ~/.local/share/bash-completion/completions/anona
anona completion zsh  > "${fpath[1]}/_anona"
anona completion fish > ~/.config/fish/completions/anona.fish
```

The script completes every command, subcommand and flag, generated from the
installed CLI, so regenerate it after an upgrade.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.