> ## 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.

# Sign in & credentials

> The three credentials the anona CLI uses, the order it picks them in, named profiles, and how to check which one a command will use.

The data commands (`record`, `retrieve`, `reason` and everything else that
reads or writes memory) work with any of three credentials:

| Credential | Get it with | Reaches | Space |
| - | - | - | - |
| **API key** | the dashboard, under **API keys** | your organization | required: `--space` or `ANONA_SPACE_ID` |
| **Command-line login** | `anona login` (or `anona login --cli`) | your account | required: `--space` or `ANONA_SPACE_ID` |
| **Temporary profile** | `anona start` | one throwaway workspace, no account | always `default`; omit `--space` |

A fourth credential, the **MCP login**, is stored by `anona login` too, but
only `anona mcp` uses it. The REST API refuses it, so the data commands never
fall back to it.

## Which credential wins

The first one found is used:

1. `--api-key` on the command line
2. `ANONA_API_KEY` in the environment
3. `ANONA_API_KEY` in `~/.anona/config.env` (or the active
   [profile's](#named-profiles) `config.env`)
4. the command-line login from `anona login`
5. a temporary profile from `anona start`

An API key, wherever it came from, outranks every stored login. With only the
MCP login stored, the data commands exit `4` and tell you to run
`anona login --cli`.

`--api-key` is visible to other users of the machine in the process list, so
prefer the variable or the file.

**A space is required with an API key or the command-line login.** Both reach
an account that can hold many spaces, so the CLI never picks one for you: pass
`--space`, or set `ANONA_SPACE_ID` in the environment or in `config.env` (in
that order). Without one the command exits `2` and sends nothing.
`anona spaces list` shows the spaces you can use.

## Check what a command will use

```bash theme={null}
anona status        # which credentials are stored, where they came from
anona doctor        # which one wins and why, and whether it actually works
```

`anona status` reads only the local files. It names the API key the data
commands would use and where it came from, the command-line login, and the MCP
login, each with the server it is for and when its access token expires, and
for a temporary profile when the profile expires. It shows at most a key's
first characters (`anona_live_abc1…`) and never a token. Because it does not
call the server, a revoked credential still shows as found.

`anona doctor` (pip 0.25.0; npm 0.19.0) goes further.
It reports which Python and which `anona` are running, which profile and
directory are active, which credential a data command would use **and why the
others lost**, which server it talks to, whether that server answers, and
whether the space a data command would use is reachable with that credential,
and how many credits are left (the same balance `anona usage` shows). It never prints a secret, and its health check carries no credential at all.

```bash theme={null}
anona doctor --space notes
anona doctor --json | jq .credential
```

It exits `0` when everything checks out (it prints `All good.`), and otherwise
with the code a data command would fail with: `4` for a credential problem,
`7` for a server it cannot reach, `5` for a space that does not exist, `2` when
no space is named at all, `6` when no credits are left (reads are refused at
zero too). A balance it cannot read is reported as unknown and does not fail
the check. With `--json` it prints one document:
`{"anona_version", "python", "profile", "profile_dir", "credential": {"kind", "display", "source", "why", "base_url", ...}, "health": {"ok", "status"}, "space": {"id", "source", "accessible", "error"}, "credits": {"remaining", "limit", "used", "exhausted", "error"}, "ok"}`.

## With an API key

Create a key in the dashboard under **API keys**, then:

```bash theme={null}
export ANONA_API_KEY=anona_live_YOUR_KEY
export ANONA_SPACE_ID=notes

anona record   "The user prefers pnpm."
anona retrieve "package manager preference"
```

Or keep both in `~/.anona/config.env`:

```bash theme={null}
ANONA_API_KEY=anona_live_YOUR_KEY
ANONA_SPACE_ID=notes
```

The CLI reads `config.env` as data and never runs it, takes only
`ANONA_API_KEY`, `ANONA_SPACE_ID` and `ANONA_BASE_URL` from it, and warns if the
file is readable by anyone but you (`chmod 600 ~/.anona/config.env`). The
[agent skills installer](https://docs.anonalabs.com/integrations/skills.md) writes this file for you.

### Where a key may be sent

A key only goes to Anona's own servers unless you say otherwise in the same
place it came from. The default is `https://api.anonalabs.com`, and a key from
the environment or `config.env` is sent only to `api.anonalabs.com` or
`memory.anonalabs.com`. It may go to another server only when that server is
named beside it: `--base-url` beside `--api-key` on the same command line,
`ANONA_BASE_URL` beside `ANONA_API_KEY` in the environment, or both in
`config.env`. A `--base-url` on its own never redirects a key you set
elsewhere, so a URL an agent was talked into typing cannot carry it off.
Anything else is refused with exit `4` before a request is made:

```text theme={null}
anona: refusing to send the API key from ANONA_API_KEY to https://other-host (named by --base-url). ...
```

The server must be `https://`, except `localhost` and `127.0.0.1`.

## With `anona login`

```bash theme={null}
anona login
```

`anona login` asks for two approvals, one after the other, each in the browser:

1. **The command line**, stored in `~/.anona/cli-credentials.json`. The data
   commands use it.
2. **MCP**, stored in `~/.anona/credentials.json`. `anona mcp` uses it.

Each is its own app on the approval screen and under **Connected apps**, with
its own refresh token, so revoking or renewing one never touches the other.
`anona login --cli` asks for only the first, `anona login --mcp` for only the
second.

If one approval fails, the other still runs, and `anona login` exits `0` as long
as one succeeded; it says which one did not. If a temporary profile is stored,
the first approval claims it.

A browser opens on the approval screen. If you have no account, you create one
there. Read the client name before you approve it: that screen is the whole
security model. Over SSH or in a container the browser cannot open on its own,
so `anona login` prints the URL and you open it yourself; `--no-browser` skips
the attempt. The approval redirects back to a local port on the machine running
`anona login`, so open the URL in a browser on that machine, or forward that
port.

**Renewal is automatic.** The access token lasts an hour and the refresh token
30 days, rolling: each refresh issues a new 30 days, so a credential you use
does not expire. When a data command finds the access token expired it
refreshes first, and if the server refuses the token anyway it refreshes once
and retries once. You are asked to approve again only after 30 days of total
silence, or after you revoke the app under **Connected apps** in the dashboard;
the command then exits `4` and says to run `anona login --cli`.

**A stored login only goes to the server that issued it.** A `--base-url` or
`ANONA_BASE_URL` naming a different one is refused with exit `4`, not followed:

```text theme={null}
anona: the stored credential is for https://memory.anonalabs.com, not https://other-host. Run `anona login --base-url https://other-host` to switch.
```

Switching servers is always an explicit `anona login --base-url`. For a
self-hosted deployment pass `--base-url https://your-host` or set
`ANONA_BASE_URL`; the flag works before or after the command and wins over the
variable.

### Signing out

```bash theme={null}
anona logout          # both logins
anona logout --cli    # only the command line
anona logout --mcp    # only MCP
```

`logout` deletes the local file and then asks the server to revoke the
credential. The file is deleted even when the server cannot be reached, and the
CLI says so; a credential it could not revoke dies after 30 days unused, or
revoke it under **Connected apps**. `logout` refuses to discard a live,
unclaimed temporary profile unless you pass `--force`, because its memories
cannot be recovered. With nothing stored, `logout` says there was nothing to
remove and still exits `0`. Neither `login` nor `logout` touches `config.env`.

## With a temporary profile

```bash theme={null}
anona start
```

`anona start` creates a **temporary profile**: a memory workspace with no
account, no email address and nobody owning it. An agent can use it
immediately, and a person claims it later with `anona login`, which keeps
everything it holds. It prints the deadline:

```text theme={null}
Temporary profile created. It expires 2026-10-06 15:22 UTC (in 71 hours), after which its memories are deleted.
Nothing warns you before then: run `anona status` to check, and
`anona login` to claim it and keep what it holds.
Its space, `default`, is normally created now; if a retrieve reports no space, the first memory you write creates it.
```

* **72 hours, then deletion**, memories included. `anona status` prints the
  deadline whenever you ask.
* **One space, `default`.** Omit `--space`. Creating another is refused with
  `temp_profile_single_space` until the profile is claimed.
* **1,000 credits while unclaimed**, rising to the normal allowance on claim.
* **Claiming needs an email that has never been used for Anona**
  (`claim_needs_new_account` otherwise).
* **One live profile at a time.** `anona start` refuses to create a second.

The full walkthrough is on [Temporary profiles](https://docs.anonalabs.com/agents/temp-profiles.md).

## Named profiles

pip 0.25.0; npm 0.19.0

`--profile NAME` (or `ANONA_PROFILE=NAME`) switches the whole credential set to
`~/.anona/profiles/NAME/`: its own command-line login, its own MCP login and
temporary profile, its own `config.env`, and its own locks. Nothing is shared,
so a refresh in one profile can never rotate a token in another. Unset, or
`default`, is `~/.anona` itself.

```bash theme={null}
anona --profile work login --cli
anona --profile work spaces list
ANONA_PROFILE=personal anona retrieve "reading list" --space books
```

A profile name is letters, digits, `-` and `_`, at most 64 characters; anything
else exits `2`. Use one profile per account or per deployment, for example to
keep a staging server's login apart from production's.

> [!WARNING]
>
> **The `anona login` credentials are for the CLI, not for your code.** The MCP
> one works only on `/mcp`; the command-line one works only for the `anona`
> commands on this machine. The Python and JavaScript SDKs and raw REST calls
> need an API key, minted in the dashboard under **API keys**. A temporary
> profile's `anona_tmp_` token is the exception: it also authenticates the REST
> API until it is claimed or expires.


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