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, and an API key is
reported as “not checked here”. An access token’s expiry is not a deadline to
act on: it renews itself, and you need anona login again only after a
revocation or 30 unused days. A temporary profile stored beside an API key is
introduced as what anona mcp uses. anona status with nothing stored prints
Not logged in and exits 1.
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 one approval in the browser, stored in
~/.anona/cli-credentials.json. The data commands use it, and so does
anona mcp, so one
sign-in covers both (pip anona 0.26.1 or later, npm @anona-labs/memory
0.20.1 or later; older versions asked for a second, MCP-only approval). If a
temporary profile is stored, the approval claims it.
anona login --mcp asks instead for a separate MCP-only credential, stored in
~/.anona/credentials.json. It can call only the MCP tools, and anona mcp
uses it only when there is no command-line login for the same server. Each
credential is its own app on the approval screen and under Connected apps,
with its own refresh token, so revoking one never touches the other.
anona login --cli is the same as anona login, except that a server which
does not issue command-line credentials is a failure rather than a fallback to
the MCP-only approval.
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 works with a new or an existing account. A new account takes over the profile’s workspace; an existing one gets the profile’s space copied in as a new space (see What claiming does).
- One live profile at a time.
anona startrefuses to create a second.
anona login on the machine (and
--profile) that holds the temporary profile: approving in the browser claims
it, and anona login --help says so. anona usage --json reads its credit
balance without exposing the token.
The full walkthrough is on Temporary profiles.
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.