# Multimem

Shared memory for the AI agents that work for you, kept in your own [Any](https://github.com/anyproto/any) space.

Every agent session (Claude Code, Codex, Cursor, Gemini CLI, Hermes, OpenClaw, a bot in a cloud sandbox, a person) reads the project's memory before it starts, gets the matching memory with every prompt, records decisions, learnings and tasks as they appear, and checkpoints its telemetry into the space. You browse the same objects in the Any app; the space syncs to your other devices like any other.

- **Sessions** — one object per agent session: goal, status, harness, model, branch, tokens, tool calls, duration, notes, and an events table.
- **Decisions** — choices later work must respect; changed only by supersession.
- **Learnings** — one non-obvious fact each: traps, patterns, how-tos, facts, tools, preferences; marked stale, never deleted.
- **Tasks** — follow-ups with a done condition.
- **Feed** — the space chat: one human-readable line per notable event.
- **Handbook** — the contract page in the space, with this kit attached to it, so any agent that can read the space can install itself.

The optional **brain pack** adds a personal assistant's kinds on top: an **About me** profile page read first by every agent, **Goals**, **Commitments** (promises in either direction, soonest due first in the digest), an **Idea** inbox and a **Journal**, plus an `about` relation on learnings and a `goal` relation on tasks. The `work` and `life` area presets serve different uses of the space. See [the handbook](handbook.md#the-brain-pack); a coding-memory upgrade does not need the pack or a new preset.

Stdlib-only Python 3.9+. No daemon: the Any desktop app (or `any run`) is the server, and every command resolves the space and its ids on the fly.

## Install

Choose the existing-space or fresh-space path in [INSTALL.md](INSTALL.md) first. For an existing memory space, verify and pin the intended server and space, then run `ensure` **without `--create`**. Do not rely on implicit space selection when upgrading an existing setup.

The following short form is for **a fresh Claude Code installation and an explicitly approved new space**. Other hosts have different kit paths; use their own blocks in INSTALL.md.

```sh
curl -fsSL https://any.org/assets/multimem/get.py | python3 - --host claude-code
python3 ~/.claude/skills/multimem/multimem.py ensure --create                           # once per account
python3 ~/.claude/skills/multimem/multimem.py doctor
```

`get.py` downloads the kit (checksums from `manifest.json`); `--no-install` downloads without registering a host. `install --host …` registers one host idempotently and preserves unrelated hooks or settings. `uninstall --host …` removes exactly what it wrote. `ensure` installs or adopts the schema in the selected space; only `ensure --create` may create a space. If the kit is already downloaded, run `python3 <kit>/multimem.py install --host …` from its folder.

## What the hooks do (Claude Code, Codex)

| moment | hook | effect |
|---|---|---|
| session start | `session-start` | creates the Session object (key = the harness session id) and injects the context digest: open tasks, decisions in force, learnings, recent sessions for this repo |
| each prompt | `prompt` | hybrid search (full text + vector) of the prompt over the space; the best matches arrive as `<multimem-memory>`; the first prompt becomes the session's goal |
| after a file write | `post-tool` | notes the relative path in a local spool (Claude Code; no network) |
| each turn end | `stop` | checkpoint from the transcript: model, tokens, tool calls, duration, the running outcome, one `files.written` event |
| session end | `session-end` | status done, duration, one feed line |

The hooks never block a session: on any error they exit 0 and log to `~/.multimem/hooks.log`. `MULTIMEM_HOOKS_OFF=1` or `touch ~/.multimem/hooks.off` disables them. Hosts without hooks get an MCP server (`mcp_server.py`) or a rules paragraph plus the CLI; see INSTALL.md.

What stays the agent's job: writing decisions, learnings and tasks, because that needs judgment. The `multimem` skill (Claude Code), the AGENTS.md paragraph (Codex and rules hosts) and the MCP tool descriptions carry the rules; the handbook in the space has the full contract.

Credentials never go into the space. A key an agent will need again belongs in the app's built-in credential store (Settings → Agent → Credentials: `connector.key.<service>`, `llm.key.<provider>`, `local.key.<name>`), which syncs end-to-end encrypted to every device; Multimem keeps only the ref name and what it is for, so a later session on any device knows where to recover it.

## CLI

```
multimem.py context [--repo owner/name]          digest to read before working
multimem.py search "…" [--scopes basic,props,chat,events]
multimem.py show <id>                             properties, body and (sessions) events
multimem.py list sessions|decisions|learnings|tasks [--status …] [--area …] [--since 7d] --md

multimem.py session start --session-key K --harness H --goal "…" [--branch B --model M]
multimem.py session note --body "…"
multimem.py session end --status done --outcome "…" [--tokens-in N --tokens-out N --tool-calls N --pr URL]
multimem.py event --kind test --name test.run --text "…" [--value N --unit count]
multimem.py events [--all] [--kind metric] [--since 7d]      multimem.py stats --by day|session

multimem.py decision "Rule as a sentence" --summary "…" --status accepted --area a,b --body-file d.md [--supersedes ID] [--key slug]
multimem.py learning "One fact" --summary "…" --kind trap|pattern|howto|fact|tool|preference --area a --body "…"
multimem.py task "Imperative" --summary "…" --status open --priority p2 --area a [--owner …] [--due YYYY-MM-DD]
multimem.py update decision|learning|task <id|key> [--status …] [--stale 1] [--summary …] [--body …]
multimem.py chat "…" | --read 20

multimem.py ensure [--create] [--pack brain] [--preset work|life] [--push-handbook]   install/adopt the schema (+ packs), reconcile options, attach the kit
multimem.py goal "Outcome" --summary "…" --horizon month --why "…" --measure "…" [--due …]          (brain pack)
multimem.py commitment "What" --summary "…" --from me --to Name --due YYYY-MM-DD [--source URL]       (brain pack)
multimem.py idea "Title" --summary "pitch" [--goal ID|key]     multimem.py journal "Title" --summary "…" --body "…" [--on … --mood …]
multimem.py profile pull | push --body-file f | append --body "…"                                   (brain pack)
multimem.py install|uninstall --host claude-code|codex|mcp|rules [--write FILE]
multimem.py doctor | ids | config [--set key=value] | area list | area add KEY --name … --color …
multimem.py handbook pull|push|files | manifest [--write]
import_transcripts.py sync [--since 14d] | scan … | from-metadata FILE | apply-extracts DIR
```

Every write returns JSON with the object id and its `any://o/<space>/<object>` link. `--area` takes keys from `area list`; an unknown key is an error, `area add` extends the vocabulary (saved in the config, applied to the space, re-applied by `ensure` on other machines).

## Configuration

`~/.multimem/config.json` and environment variables configure the kit; every config key is optional. [config.example.json](config.example.json) is a **brain/life example**, with `packs: ["brain"]` and `areas_preset: "life"`. Do not copy it unchanged for a coding-memory upgrade. Inspect `multimem.py config` before `ensure`, which also applies configured packs and presets.

| what | env | config | default |
|---|---|---|---|
| server | `MULTIMEM_ADDR` | `addr` | probe `127.0.0.1:31330` (desktop app), then `127.0.0.1:7001` (`any run`) |
| space | `MULTIMEM_SPACE_NAME`, `MULTIMEM_SPACE_ID` | `space.name`, `space.id` | `Multimem`; verify and pin an existing destination by name or id before `ensure` |
| repo label | `MULTIMEM_REPO` | `repo` | the git origin's `owner/name`, else the checkout's folder name |
| harness label for CLI writes | `MULTIMEM_HARNESS` | `harness` | `other` |
| session key | `MULTIMEM_SESSION_KEY` | — | the key last started in the working directory |
| state folder | `MULTIMEM_HOME` | — | `~/.multimem` |
| hooks off | `MULTIMEM_HOOKS_OFF=1` | — | — |
| areas | — | `areas` | the preset's defaults at install |
| area preset | — | `areas_preset` (written by `ensure --preset`) | `work`; `life` for a personal space |
| packs | — | `packs` (written by `ensure --pack`) | none; `brain` adds the personal kinds |
| importer exclusions | — | `import.exclude` | `codex-scratch`, `home` |

## The space

`schema.json` holds the five core bundles the kit registers through `POST /v1/spaces/:id/bundles` (adopt-or-install): `mp.session/v1` (a type with a notes body and a shared `events` dataset), `mp.decision/v1`, `mp.learning/v1`, `mp.task/v1` (collections over `page`), `mp.handbook/v1` (the contract page); the `brain` pack adds `mm.profile/v1`, `mm.goal/v1`, `mm.commitment/v1`, `mm.idea/v1`, `mm.journal/v1` and two extension properties on core roots. Property ids derive from `(rootId, xKey)`, so every device lands on the same ids. The ids and keys deliberately keep their `mp.*` / `mp_*` spelling: they are the identity an existing space converges on; renaming them would make a second schema appear next to the first. Schema changes are additive only (new properties, new options, new bundle versions); the handbook's "Schema evolution" section has the rules.

The handbook page in the space carries the whole contract and the kit's files as attachments (`ensure` re-attaches a file only when its bytes changed), so a second harness, machine or account can read the rules and install from the space itself.

## Use an existing memory space

The five core `mp.*` bundle identities are stable, so existing sessions, decisions, learnings and tasks stay in their current space. Follow the [existing-space path](INSTALL.md#use-an-existing-memory-space): inspect the kit and effective config, verify the server and space with `doctor`, pin their address and space id or exact name, register the hosts you use, then run `ensure` without `--create`. Host registration preserves unrelated hooks and settings.

For a coding-memory upgrade, do not add `--pack brain` or `--preset life`. Check the effective config first: omitting flags does not disable a pack already configured or installed. Updating handbook text with `handbook push` is a separate, user-approved operation. Finish with a new trusted-hook session: verify its `<multimem>` digest, MCP tools where available, hook log and `session current` result.

## Publishing

The published kit is served at [any.org/assets/multimem/](https://any.org/assets/multimem/), where `get.py` downloads its files. After a file change, `python3 multimem.py manifest --write` refreshes `manifest.json`; the publication's `SHA256SUMS` file must be regenerated separately. `VERSION` is the kit version (semver).
