record, retrieve, reason and everything else that
reads or writes memory) work with any of three credentials:
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:--api-keyon the command lineANONA_API_KEYin the environmentANONA_API_KEYin~/.anona/config.env(or the active profile’sconfig.env)- the command-line login from
anona login - a temporary profile from
anona start
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
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.
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:~/.anona/config.env:
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 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 ishttps://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:
https://, except localhost and 127.0.0.1.
With anona login
anona login asks for two approvals, one after the other, each in the browser:
- The command line, stored in
~/.anona/cli-credentials.json. The data commands use it. - MCP, stored in
~/.anona/credentials.json.anona mcpuses it.
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:
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
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
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:
- 72 hours, then deletion, memories included.
anona statusprints the deadline whenever you ask. - One space,
default. Omit--space. Creating another is refused withtemp_profile_single_spaceuntil 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_accountotherwise). - One live profile at a time.
anona startrefuses to create a second.
Named profiles
--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.
- 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.