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

# Agent Skills

> Install Anona into Claude Code, Codex, Hermes, OpenClaw and other agents so they remember, without being told to.

An MCP server gives an agent the *ability* to remember. It does not give it the
*habit*. You still end up typing "remember that" and "what did we decide about
the deploy" every session.

Agent Skills close that gap. A skill is a Markdown file the agent loads when its
description matches what you are doing, so recall at the start of a task and
recording at the end become part of how the agent works.

## Install

```bash Installer theme={null}
curl -fsSL https://raw.githubusercontent.com/anonalabs/Anona-Memory-SDK/main/skills/install.sh | bash
```

```bash npx skills theme={null}
npx skills add anonalabs/Anona-Memory-SDK
```

```bash Claude Code plugin theme={null}
/plugin marketplace add anonalabs/Anona-Memory-SDK
/plugin install anona-memory@anona
```

The installer detects the agents already on your machine, copies the skills in,
stores your key at `~/.anona/config.env` with mode 600, and registers the MCP
server with Claude Code when the `claude` CLI is on your PATH. It edits no shell
profile and writes nothing outside the directories it prints.

> [!NOTE]
>
> Skills load at session start. Restart your agent once after installing, or the
> skill is on disk and invisible.

## The three skills

> **anona-memory**
>
> The agent's own memory. Recalls what is already known before a task, records
> what the task settled after it.

> **anona-memory-sdk**
>
> Building on Anona. The SDK and API surface, scoping rules, error codes and
> framework adapters, so generated code compiles the first time.

> **[anona-cli](#the-anona-cli-skill)**
>
> Driving the `anona` command line from a shell, a script or CI: uploads,
> batch ingest, jobs, settings, and what every exit code means.

Install only some of them with `--skill`, repeated:

```bash theme={null}
install.sh --skill anona-memory
```

## Options

```bash theme={null}
install.sh --app claude --api-key anona_live_... --space my-project
install.sh --project          # into ./.claude/skills rather than ~/.claude/skills
install.sh --dir /path/to/skills
install.sh --zip                # build uploadable .zip files, see below
install.sh --no-mcp
install.sh --uninstall
install.sh --help
```

| Option | Effect |
| - | - |
| `--app <name\|all>` | `claude`, `codex`, `opencode`, `cursor`, `hermes`, `openclaw`, or `all`. Defaults to every one already present. |
| `--skill <name>` | `anona-memory`, `anona-memory-sdk` or `anona-cli`. Repeatable. Defaults to all three. |
| `--project` | Installs into `./.claude/skills`, so the skill ships with the repository. |
| `--dir <path>` | Installs into one directory and nowhere else. Use this for a harness the installer does not know. |
| `--api-key <key>` | Verified against the API before it is written. Prompted for if omitted and a terminal is attached. |
| `--space <id>` | The default space the skill records into. |
| `--zip [dir]` | Builds one `.zip` per skill instead of installing, for upload to Claude Desktop or claude.ai. Defaults to the current directory. |
| `--no-mcp` | Skips MCP registration and prints the config snippets instead. |
| `--uninstall` | Removes the skills. Leaves `~/.anona/config.env` alone. |

An existing install is moved under `~/.anona/backups/` rather than deleted, and
deliberately not left beside the skill: an agent reads every directory under
`skills/`, so a backup parked there would load as a second skill claiming the
same name.

## How the skill reaches your memory

Four ways, tried in order. You only need one.

**1. MCP tools**

If the host exposes `record`, `retrieve`, `reason` and `list_spaces`, the
skill uses them and there is nothing to configure.

```bash theme={null}
claude mcp add --transport http anona https://memory.anonalabs.com/mcp \
  --header "Authorization: Bearer $ANONA_API_KEY"
```

See [MCP](https://docs.memory.anonalabs.com/mcp-integration.md) for OAuth, the local stdio server, Hermes and OpenClaw.

**2. The anona CLI**

Otherwise, if the [`anona` CLI](https://docs.memory.anonalabs.com/cli/overview) is installed (pip `anona`
0.24.0 or later), the skill runs `anona status` once, then
`anona retrieve`, `anona record` and `anona reason` with `--json`, and
branches on the exit code. The CLI finds its own credential: an API key
(`--api-key`, `ANONA_API_KEY`, or `~/.anona/config.env`), the command-line
login from `anona login`, or a temporary profile from `anona start`. It
never uses the MCP login, so a machine signed in for MCP only exits 4 here
and the skill moves on. Before a command it has not used, it reads
`anona guide --json` rather than guessing a flag.

**3. REST with curl**

Otherwise the skill reads `ANONA_API_KEY` from the environment or from
`~/.anona/config.env` and calls `https://api.anonalabs.com` directly. This
is what makes the skill work in a harness with no MCP support and no
Python.

**4. Neither**

If `anona` or `uvx` is available, the skill may run `anona start` for a
temporary profile and tell you so in one line; you keep it with
`anona login`. Otherwise it says once that memory is not configured and
does the task without it. A memory layer that blocks the work is worse
than no memory layer.

> [!NOTE]
>
> MCP OAuth sign-in needs no API key. An organization that has never created one
> works from its first tool call. If you see
> [`403 no_api_key`](https://docs.memory.anonalabs.com/api-reference/errors#status-and-error-codes), that is a fault
> on our side, not a missing step on yours; the one case where it is intended is an
> organization that revoked all of its keys.

## The anona-cli skill

`anona-memory` uses the CLI only for the memory loop: recall, record, reason.
`anona-cli` teaches an agent the rest of the [`anona` CLI](https://docs.memory.anonalabs.com/cli/overview), and
fires when there are no MCP tools, in a script or CI job, for a file upload or
a batch ingest, for managing spaces, jobs or settings, or on any `anona` exit
code. It teaches four habits:

* **Look before guessing.** Run `anona guide --json` (or `anona <command> --help`)
  before composing an unfamiliar command. It is generated from the installed
  CLI, so it never lists a flag that copy lacks. See
  [For AI agents](https://docs.memory.anonalabs.com/cli/agents.md#anona-guide).
* **Always `--json`, branch on the exit code.** `3` is an accepted write that
  stored nothing, not a failure to retry; `8` is a job still running, to poll
  with `anona jobs get`.
* **Never re-send a write after exit `7`** without checking: it may have been
  stored. The CLI itself never re-sends one.
* **`--yes` is the user's decision.** Destructive commands refuse without it,
  and the agent confirms with the user before adding it.

It also carries the credential order, how to set one up without running
`anona login` on a person's behalf, and scoping with `--user-id`. The details
live in three reference files the agent opens only when needed: commands by
task, JSON shapes and exit codes, and credentials.

```bash theme={null}
install.sh --skill anona-cli
```

## Which space

The skill picks one per session, in this order:

1. `ANONA_SPACE_ID`, set by `--space` or in your environment.
2. The git repository name, lowercased, when working in a repo.
3. `default`.

With more than one space and no `ANONA_SPACE_ID`, the skill lets Anona choose:
it sends [`route: "auto"`](https://docs.memory.anonalabs.com/api-reference/retrieve#let-anona-choose-the-space)
in place of a space, with the space picked above as `fallback_space_id`, and
reads `searched` / `routed_to` to see where the call went. A pinned
`ANONA_SPACE_ID` always wins. Routing works over MCP and REST; the `anona` CLI
has no route flag, so on the CLI the skill keeps naming the space.

A write creates the space. A read does not, so
[`404 space_not_found`](https://docs.memory.anonalabs.com/api-reference/errors#status-and-error-codes) on a space
nothing has been written to yet means empty, not broken.

> [!NOTE]
>
> Serving several people through one space? The skill passes `user_id` when you
> give it one, and the match is strict in both directions: a scoped read never
> returns an unscoped memory. See [Scoping](https://docs.memory.anonalabs.com/guides/scoping-multi-tenant.md).

## What gets recorded

Preferences, decisions and their reasons, fixes that cost time, constraints the
code does not state, and outcomes. One fact per memory.

Not recorded: secrets, anything already in the repository, narration of the
session, or anything still a hypothesis. The skill carries the judgment call and
worked examples of both sides.

## Saving a session

Ask the agent to save, remember or export the session ("save this to Anona",
"save the deploy decisions") and it makes a full record pass: every durable
fact the conversation settled that is not in Anona yet, one memory each, then
one line saying how many it wrote and to which space. It never stores the
transcript or a summary as a single memory, because a blob retrieves badly and
is mostly narration.

In Claude Code, the plugin adds a command for the same thing:

```text theme={null}
/anona-memory:save
/anona-memory:save the deploy decisions
```

Claude Code names a plugin's commands after the plugin, which is why it is
`anona-memory:` and not `anona:`.

**An exported conversation** (a Claude Code `/export` file, or a conversation
from a claude.ai data export) works the same way: hand it to the agent and ask
it to save what is in it. For many conversations, a pass each is slow and
costly; the skill suggests writing the facts to a JSON Lines file and loading
it with [`anona record --batch`](https://docs.memory.anonalabs.com/cli/overview) instead.

No hook is involved. Claude Code fires none on `/export`, and the
[hooks](#hooks) already keep a redacted excerpt at every compaction and a work
log at every session end, so the command is for the moments you want saved
now.

## Compaction

Compacting a conversation swaps it for a summary, and whatever the summary
drops is gone. The skill treats that as a deadline: what the session settled
goes to Anona before it can be lost.

* **Before.** Tell the agent you are about to compact and it records what the
  session settled first, then says how many memories it wrote.
* **After.** When a conversation resumes from a summary, the agent records the
  durable facts in it before going back to the task.

It sends facts, one per memory and into the session's usual space, never the
transcript or the summary itself. Over REST each one carries
`"trigger": "compaction"` in `metadata`; the MCP `record` tool has no metadata
field, so there it goes without the marker. The same rules apply:
no secrets, nothing already in the repository, nothing still a hypothesis.

## Hooks

Skill instructions only run when the agent has a turn, and some of the moments
that matter most happen without one: Claude Code compacts without asking, and a
session can end mid-thought. A Claude Code
[hook](https://docs.claude.com/en/docs/claude-code/hooks) is a command the
client runs on a lifecycle event, so it covers exactly those moments.

| Event | Direction | What it does |
| - | - | - |
| `SessionStart` (startup, resume, clear, compact) | Pull | Retrieves what the space knows about the repository, branch and recent commits, and adds it to the agent's context inside an `<anona-memories-…>` fence (a fresh random name each time, so stored text cannot close it), marked as untrusted data rather than instructions. |
| `PreCompact` | Push | Sends an excerpt of the conversation about to be summarised away as one async `record`, with `"trigger": "pre-compact"` in `metadata`. Anona's extraction keeps the durable parts. |
| `SessionStart` (compact) | Prompt | Tells the agent to record the facts the summary kept, as described under [Compaction](#compaction). Prints only. |
| `SessionEnd` | Push | Records a short work log (the task, branch, files changed and commits made) with `"trigger": "session-end"`, so the next session and every other agent on the space know what was being worked on. Skipped when nothing changed. |

**What leaves your machine.** The pre-compact excerpt holds the user's prompts
and the agent's prose. It never holds tool output, which is where file contents
and command output live; pasted blocks and system text are dropped, the excerpt
is capped at the last 40,000 characters, and key-shaped strings (API keys
from common providers, tokens, bearer headers, webhook URLs, private keys,
passwords, credentials in URLs) are
replaced with `[redacted]` before it is sent. Redaction is pattern matching, not
a guarantee: turn the digest off with `ANONA_HOOK_DIGEST=0` in sessions that
handle secrets in plain prose.

**What it costs.** Each pull is one retrieve. Each push is one async record,
billed like any other write: an excerpt costs more than a one-line fact because
extraction reads all of it.

**Which space.** The same order as the skill: `ANONA_SPACE_ID`, then the
repository name, then `default`. When you can see more than one space and none
is pinned, the pull sends `route: "auto"` with that space as the fallback.

The pushes do not route by default. They carry raw session text the agent never
reviewed, and routing chooses among every space you can see, including one
shared with you by another organization or one a Slack channel or GitHub
repository reads from. Filing a conversation excerpt there would show it to
everyone on that space. So the pushes write only to a space that is your own: the
repository's space once it exists, or `ANONA_SPACE_ID`. They route only when
you set `ANONA_HOOK_ROUTE=auto`, and a routed write that cannot be placed then
goes to that same space. While the repository has no space of your own, the
pushes are skipped rather than sent by bare name, since a bare name resolves to
a space someone shared with you under that name when you have none. The
agent's first `record`, or creating the space in the dashboard, starts them. The agent's own
records, made under the skill, still route. Space ids are case-sensitive,
so the repository name is matched against your spaces ignoring case: a checkout
of `anona-memory` uses an existing `Anona-memory`. The space list is cached for
an hour.

**No API key needed.** The hooks use the first of these that is available:

1. `ANONA_API_KEY`, in the environment or `~/.anona/config.env`: REST calls.
2. The [`anona` CLI](https://docs.memory.anonalabs.com/cli/overview) on `PATH` with a login from `anona login`
   (or a temporary profile from `anona start`): the hooks start `anona mcp`, the
   CLI's stdio bridge, and call its `retrieve` and `record` tools. The bridge
   holds the login and refreshes it, so it keeps working for as long as the
   login does (30 days from the last use). This is the same login the `anona`
   MCP server in Claude Code uses.
3. Neither: every hook is a silent no-op.

Over the bridge, a write carries no `metadata` (the MCP `record` tool has no
such field), so `trigger` is not stored; the excerpt and the work log still say
in their first line where they came from. Force one path with
`ANONA_HOOK_TRANSPORT=rest` or `mcp`.

**Safety.** The hooks never fail or slow a session. The pull is an async hook:
startup does not wait for it, and what it finds arrives with your first prompt.
Pushes are handed to a detached process and the hook returns at once. The
script is standard-library Python 3 and needs no install.

| Install path | Hooks |
| - | - |
| Claude Code plugin | Installed and enabled automatically (plugin `0.3.0` or later; `0.2.0` had the compaction prompt only). |
| Installer, `npx skills` | Not installed. Add them by hand, below. |
| Other agents | Not available. The skill instructions still cover recall, recording and a compaction you announce. |

### Adding them by hand

Sign in once with `anona login` (or set `ANONA_API_KEY`), download the script,
then register it in `~/.claude/settings.json` (every
project) or `.claude/settings.json` (one project):

```bash theme={null}
mkdir -p ~/.anona/hooks
curl -fsSL https://raw.githubusercontent.com/anonalabs/Anona-Memory-SDK/main/hooks/anona_sync.py \
  -o ~/.anona/hooks/anona_sync.py
```

```json theme={null}
{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "startup|resume|clear|compact",
        "hooks": [
          { "type": "command", "command": "python3 ~/.anona/hooks/anona_sync.py session-start", "timeout": 30, "async": true }
        ]
      },
      {
        "matcher": "compact",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'This conversation was just compacted. Follow the anona-memory skill Compaction section: record the durable facts in the summary above before resuming.'"
          }
        ]
      }
    ],
    "PreCompact": [
      { "hooks": [ { "type": "command", "command": "python3 ~/.anona/hooks/anona_sync.py pre-compact", "timeout": 10 } ] }
    ],
    "SessionEnd": [
      { "hooks": [ { "type": "command", "command": "python3 ~/.anona/hooks/anona_sync.py session-end" } ] }
    ]
  }
}
```

If the file already has a `hooks` object, merge these events into it rather
than replacing it. Run `/hooks` in Claude Code to confirm they are registered.

### Settings

Read from the environment, then from `~/.anona/config.env`:

| Variable | Effect |
| - | - |
| `ANONA_HOOKS=off` | Turns every hook off. |
| `ANONA_HOOK_RECALL=0` | No pull at session start. |
| `ANONA_HOOK_DIGEST=0` | No pre-compact excerpt. |
| `ANONA_HOOK_WORKLOG=0` | No session-end work log. |
| `ANONA_HOOK_ROUTE=auto` / `off` | `auto` routes the pushes too (into your own spaces' fallback); `off` routes nothing. Default: the pull routes when you have more than one space, the pushes never do. |
| `ANONA_HOOK_TRANSPORT=rest` / `mcp` | Use only the REST API, or only `anona mcp`. Default: REST with a key, else the bridge. |
| `ANONA_HOOK_DIGEST_MAX_CHARS` | Size of the excerpt's tail. Default `40000`. |

> [!NOTE]
>
> The `anona` CLI reads only `ANONA_API_KEY`, `ANONA_SPACE_ID` and
> `ANONA_BASE_URL` from `config.env`. Put the `ANONA_HOOK*` switches in your shell
> environment, or in the `env` object of Claude Code's `settings.json`, which
> applies them to hooks too.

**Turning them off.** For the plugin, set `ANONA_HOOKS=off`, or disable the
plugin under `/plugin`, which also unloads the skills. If you added them by
hand, delete the entries.

**Checking they work.** Start a session in a repository whose space has
memories: the first turn's context should open with "Anona memory recalled at
session start". Edit a file and end the session; a minute later, a retrieve for
"what was worked on" in that space returns the work log.

## Claude Desktop and claude.ai

Those two do not read a skills directory. They take a **ZIP upload** under
Customize > Skills, so build one:

```bash theme={null}
curl -fsSL https://raw.githubusercontent.com/anonalabs/Anona-Memory-SDK/main/skills/install.sh | bash -s -- --zip
```

That writes `anona-memory.zip`, `anona-memory-sdk.zip` and `anona-cli.zip` into
the current directory, with the skill folder as the archive root, which is what
the upload expects. Every skill stays inside the caps that surface enforces on
`name` and `description`, 64 and 200 characters. `anona-cli` is of no use there,
since that surface has no shell.

Then give them tools. There is no shell there, so the CLI and `curl`
fallbacks cannot run: add Anona as a **custom connector** under Settings > Connectors.

```
https://memory.anonalabs.com/mcp
```

Sign in with OAuth when prompted. See [MCP](https://docs.memory.anonalabs.com/mcp-integration.md) for the same flow
in other clients.

> [!NOTE]
>
> The Claude Code that runs inside Claude Desktop is a different surface, and it
> reads `~/.claude/skills/` normally. The installer at the top of this page
> already covers it. The ZIP is only for the chat surface.

## Supported agents

| Surface | Skills | Tools |
| - | - | - |
| Claude Code, in a terminal or inside Claude Desktop | Installer, `npx skills`, or the plugin marketplace | MCP server, or the `anona` CLI or `curl` fallback |
| Codex, OpenCode, Cursor, Hermes, OpenClaw | Installer or `npx skills` | MCP server, or the `anona` CLI or `curl` fallback |
| Claude Desktop chat, claude.ai | `--zip`, then upload under Customize > Skills | Custom connector only |

The installer knows Claude Code, Codex, OpenCode, Cursor, Hermes and OpenClaw
(into `~/.openclaw/skills`, or `$OPENCLAW_STATE_DIR/skills` if you moved it), and takes
`--dir` for anything else. The community `npx skills` CLI covers 75+ harnesses
from the same repository:

```bash theme={null}
npx skills add anonalabs/Anona-Memory-SDK --agent codex --global
```

## Source

The skills live in [`skills/`](https://github.com/anonalabs/Anona-Memory-SDK/tree/main/skills)
in the SDK repository. Read them before you install them; they are Markdown
files and one shell script.

## Next steps

> **[MCP](https://docs.memory.anonalabs.com/mcp-integration.md)**
>
> The transport the skill prefers, with OAuth and stdio.

> **[Python SDK](https://docs.memory.anonalabs.com/sdk/python.md)**
>
> The programmatic client the second skill documents.


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