# Exomem assistant guide
This guide is for agents using Exomem after the MCP server or connector is
available. It keeps the contract simple:
- Keep temporary working context in the current conversation. Custom instructions
can guide one client; native memory is an explicit fallback when Exomem cannot capture.
- Use Exomem as long-term governed memory: eligible durable preferences, personal baselines, project context, decisions, sourced
conclusions, failures, experiments, proof-bearing records, and anything that
should be searchable, citeable, reviewable, or supersedable across clients.
- Do not make the user choose internal folders or page types unless the choice
changes the outcome.
## Start here
If the Exomem skill has already been loaded, follow it. Otherwise call:
```text
read_instructions(profile="compact")
```
Do this once at the start of a session for generic MCP clients, hosted chat
clients, Cursor, Codex, ChatGPT, scripts, and future clients that only see tool
schemas. Use `read_instructions(profile="full")` when the client needs examples. Use
`read_instructions(profile="diagnostics")` only for speed, ranking, cache, CPU/GPU,
rerank, or packed-context questions.
## The rule
Search Exomem before answering when the turn touches the user's prior projects,
notes, decisions, sources, failures, experiments, entities, or domains. Stay
quiet for unrelated chat, short control prompts, and follow-ups where the current
conversation already contains fresh KB evidence.
An empty search means "not found with that query and scope." It is not proof that
the knowledge does not exist. Try synonyms, adjacent terms, singular/plural
forms, `widen_outside_kb=true`, or `scope="vault"` before saying there is no
relevant material.
`scope="kb"` (the default) searches the knowledge base and nothing else.
`widen_outside_kb` is off by default: set it to true to also reserve up to
`limit - 1` slots for curated vault pages outside the knowledge base, which is
what surfaces a terse tracker or handbook whose title is the query. Reserved
hits carry `outside_kb: true`. Earlier releases widened on every `scope="kb"`
recall; the reserve is now something the caller asks for, so the default costs
nothing for the callers that never read it.
Use page recall for conclusions, unit recall for exact observations, and mixed
recall when both are useful. An empty query with structured filters is a
filter-only lookup. Set `explain=true` only to inspect ranking: BM25, cosine,
RRF contributions, reranker values, and final rank are different labelled
metrics, never confidence. See [first-class semantic language](semantic-language.md).
Save durable conclusions when the conversation lands on one: a decision, solved
problem, diagnosed failure, reusable pattern, stable project fact, or conclusion
that future agents should find. Save a concise compiled note, not a transcript.
Capture raw material separately when provenance matters.
Capture a stable preference, recurring routine, historical baseline, or durable
affiliation only when both stability or recurrence and reusable comparison,
interpretation, or decision value are clear. Put a facet or affiliation on a
uniquely resolved Entity; otherwise write one concise compiled observation. Use
Records only for an observed measurement accepted by a compatible existing
collection. Fleeting preferences, one-off activity, incidental associations, trivial
metrics, and tentative claims stay quiet; this never authorizes creating an Entity,
collection, or schema. A concise observation or narrow Entity facet follows
`proactive_capture`; a new Entity or your own affiliation edge follows `proactive_capture`;
accepting a queued relation requires `link_acceptance`; merge or substantial curation requires
confirmed `restructure_execution`.
## Simple actions for agents
Use the simple product actions as the first mental model. Product commands are
what agents should call; canonical leaves stay underneath as implementation
routes.
| Simple action | User intent | Product command |
| --- | --- | --- |
| `ask` | "What do I know?", "find what I concluded", "show the context" | `search_memory(detail="compact", rerank=false)`, then `read_page`; use `search_memory(deep=true)` for synthesis |
| `create_note` | "remember this conclusion", "save this decision", "write this up" | `create_note`; use `supersede_note` when it supersedes an old conclusion |
| `capture` | "save this source", "preserve this receipt", "keep this proof" | `save_source` for raw sources; `save_evidence` or `upload_files` for Evidence |
| `review` | "what needs review?", "show stale/disconnected knowledge", "what is unprocessed?" | `list_review_items`; `decide_review_item` for explicit dismiss/snooze/reopen |
| `connect` | "what should this link to?", "suggest relations", "show related ideas" | `inspect_memory` with the `connections` operations; entity writes stay explicit through `manage_memory` |
| `adopt` | "import/adopt this existing vault safely" | `adopt_vault(mode="scan-only")`; explicit modes for manifest/copy/compile planning |
| `maintain` | "check/fix vault health" | Remote tools may audit or dry-run; actual `fix`/`reconcile` writes require the host operator CLI |
Do not make the user choose `Sources`, `Evidence`, `Notes`, `Entities`, pack
metadata, graph sidecars, or schema terms unless the distinction changes the
outcome. With the user, say "ask", "remember", "capture", "review", "connect",
"adopt", or "maintain"; use canonical leaf names only when debugging internals.
## Typed relation loop
For a request to connect two memories, first call
`connect_memory(operation="resolve-relation")`. Reuse a specific truthful
registered relation when one fits. `relates_to` and no edge remain valid outcomes;
candidate ordering is not a semantic decision. When a reviewed distinction is
missing, call `schema_memory(subject="relations", operation="propose-relation")`.
Only a separate `save-relations` call with `expected_hash` and `why` changes the
registry; never treat a proposal, recurrence count, or queue item as approval.
`schema_memory(subject="relations", operation="infer")` is read-only. Its
aggregate `census` is privacy-safe evidence: `relation_counts`, `page_counts`,
and `denominators` contain counts only. Optional `project`, `page_type`,
`date_from`, and `date_to` scope it. Origin dates use `created`, then `captured`;
undated pages remain explicit and `updated` is not used as a cohort date.
For CLI use, these actions are also available as friendly aliases:
```bash
exomem ask "what did I conclude about onboarding?" --json
exomem ask "warranty dispute context" --deep --graph-enrich --json
exomem ask "battery policy" --category config --result-level mixed --explain --json
exomem create_note "# Decision\n\n## Claim\n\nUse simple actions first." --title "Use simple actions first" --json
exomem capture "raw article excerpt" --title "Article title" --source-type article --url "https://example.com" --json
exomem capture "receipt text" --as evidence --scope warranty --category receipts --filename receipt.txt --json
exomem review --json
exomem review --category relation_debt
exomem review snooze exomem://review/0123456789abcdef01234567 --until 2026-08-01
exomem connect --path "Notes/Insights/example" --json
exomem maintain --json
```
## Examples
### Remember this
User:
```text
Remember this: for the onboarding docs, lead with simple actions, not schema
folders.
```
Agent behavior:
1. Recognize a durable project conclusion.
2. Save a concise compiled note.
3. Report the path.
```text
Saved -> Knowledge Base/Notes/Research/Exomem/
.md
```
### Find what I concluded
User:
```text
What did I conclude about Exomem vs built-in memory?
```
Agent behavior:
1. Run `search_memory(query="Exomem built-in memory boundary", detail="compact")`.
2. Cite relevant hits.
3. If results are thin, retry with adjacent terms such as `native memory`,
`assistant memory`, `custom instructions`, or `durable governed knowledge`.
### Preserve source
User:
```text
Save this article as a source and keep the URL.
```
Agent behavior:
1. Use `save_source` for the raw article or excerpt.
2. Keep the URL and capture rationale.
3. Classify on two independent open axes: `source_kind` is what the artifact
**is** (`research-report`, `invoice-receipt`, `field-notebook`), `domain` is
what it is **about** (`travel`, `marine-biology`). Neither is a closed list —
an unfamiliar but meaningful label is accepted and registers itself, so name
the label you actually mean instead of falling back. Add `projects` for the
work it serves; a source can serve several, and projects never affect where
it is stored.
4. Always name a kind. If no known kind fits, name a new one; there is no
catch-all, and `other` is retired.
5. Offer to compile a note only if there is a durable conclusion to extract.
For one observation or rich unit, use `edit_note` rather than page-wide
string editing. For reviewed creation, validate first and commit the unchanged
`draft_id`, `draft_hash`, and `draft_token`. When required, echo the returned
`relation_review_hash` with `relation_disposition="reviewed_none"` and an
explicit `relation_review_reason`; never infer reviewed-none from a missing
relation.
### Preserve proof
User:
```text
Keep this receipt for the warranty case.
```
Agent behavior:
1. Treat it as a proof-bearing record, not a research source.
2. Preserve the original file or text with `save_evidence` or `upload_files`.
3. Report the stored path and any metadata the server returns.
### Adopt a generated artifact
Keep every generated file you hand the user. At hand-over, preserve that
file's exact bytes once. Under balanced or maximal prominence this uses
`proactive_capture`; do not wait for the user to say they chose it. Drafts,
previews and variants you never hand over stay ephemeral. The rule covers files
you generate and give the user: downloads, attachments and sandbox outputs. It
does not cover files you write or edit in the user's own workspace or
repository, which already persist there. An explicit save request remains an
ordinary requested action.
Choose Source or Evidence from purpose before transport: reasoning material is
a Source, while a deliverable or proof-bearing final is Evidence. MIME never
chooses. Pass the closed `adoption` envelope to `save_source` or
`save_evidence`. Use one `key` per hand-over, such as the file name plus a
version, and name the handed-over handle in `selected_file_id`. A revision you
hand over later is kept beside the first, and identical bytes return
`already_stored`. When no usable handle exists, report a non-committing
`handoff_required` or `handoff_prepared` state. Do not substitute base64, a
textual reconstruction, or a claim that the bytes were saved.
A later send or publication is a separate delivery fact. Append it through
`record_memory(..., delivery={...})` only after a committed local Evidence
receipt and only into one existing compatible Records collection. The delivery
envelope maps the caller-authored link, reported-reference, and verification
fields; it creates no schema and sets no item values. Reported remote identity
is unverified unless matching platform proof establishes remote byte equality.
Missing schema may yield a `structural_suggestions` proposal, but creation or
change remains confirmed `restructure_execution`; an independently authored edge follows the served promotion class; a queued acceptance remains `link_acceptance`.
### Compile evidence
User:
```text
Compile the notes from these two sources into what we learned.
```
Agent behavior:
1. Search or read the named sources.
2. Draft a compiled conclusion that links back to the sources.
3. Use `create_note(suggestions=true, response_detail="full")` so the new note
connects to prior work. Link suggestions are off by default — they cost a
whole retrieval pass on the write path — so the call has to ask for them,
and the default compact response would not carry them even once computed.
### Review stale knowledge
User:
```text
Show me conclusions that may be stale.
```
Agent behavior:
1. Run `list_review_items` with the appropriate review mode.
2. Present candidates as review items only.
3. Ask whether to keep, connect, edit, supersede, archive, dismiss, or snooze.
Use `decide_review_item` only for an explicit review decision. Do not auto-decay
old knowledge or auto-accept suggested relations.
### Supersede old conclusion
User:
```text
The old setup recommendation is wrong now; this new one replaces it.
```
Agent behavior:
1. Find and confirm the old compiled page.
2. Use `supersede_note` to write the new conclusion and mark the old page superseded.
3. Surface downstream pages that may need review; do not silently rewrite them.
## Mutation responses and compatibility
Successful product mutations now return a compact decisive terminal by default:
`ok`, `status="committed"`, `mutated`, `path` or `paths`, `request_id`,
`receipt_id`, and `warnings_count`. When the write actually warned, the texts
come back as `warnings` — at most 8 entries of at most 300 characters each.
`warnings_count` stays authoritative, so fewer entries than the count means the
rest were trimmed. Two cases return a count with no `warnings`: an upload
receipt, whose warnings are already per-file rows under `files`, and a mutation
recovered from a portable receipt, which deliberately retains no leaf content.
A compiled-note write may also return `structure_suggestion` of kind
`note_cohesion` while the written page has reached a size step that nobody has
answered. It carries `units`, `step_units`, `next_step_units`, the review item's
`ref` and `fingerprint`, and one `question`: does this page answer more than one
independent question? Every value comes from the page named in the same response,
so it discloses nothing about any other page. It never changes `status`,
`mutated`, `warnings_count`, mutation identity, or replay, and a failure to
compute it omits the field rather than affecting the write. The runtime counts
size and asks; it never judges the page or reorganises the vault. To keep the page
whole, dismiss the item through `decide_review_item` with a reason that starts
`intentional:`; it stays quiet until the next size step. To split it, propose a
plan through the curation lane and ask the user to confirm the exact plan. A hub
by design carries a breadth tag. The same items sit in due-state as a backlog.
Use `response_detail="full"` when an agent
needs the previous leaf diagnostics nested under `diagnostics`.
`response_detail="legacy"` returns the old raw result for temporary
compatibility. Detail is presentation-only and does not change replay identity.
Busy, acknowledgement-pending, and committed-acknowledgement-uncertain results
remain errors. Follow their remediation with the same mutation identity and
unchanged payload; never turn an uncertain acknowledgement into a new write.
`edit_note` remains one tool. New clients must send `path`, `why`, and a nested
`operation` whose `kind` is one of `replace_body`, `replace_tags`,
`replace_string`, `batch_replace`, `edit_section`, `patch_frontmatter`, or
`fill_row`. The old flat arguments remain runtime-only for at least one release,
are deprecated, and must not be generated by new clients.
Bootstrap guidance is filtered to the active adapter. Use
`active_capabilities.available_product_tools` and its active capability digest
for what that MCP/REST/CLI surface can actually call. The canonical MCP tool-
surface digest identifies packaged full MCP discovery instead; it is a separate
identity.
Audit defaults to the read-only `detail="actionable"` view: current blockers,
malformed or unregistered relation work, ordinary findings, then a grouped
grandfathered backlog with exact counts and bounded samples. Request
`detail="full"` for raw enumeration. `legacy_sample_limit` accepts 0 through 50
and changes presentation only.
Budgeted audits return findings only from completed categories. Check
`metadata.coverage` (also `meta.coverage`) for `corpus_complete`,
`completed_categories`, `requested_categories`, and `complete`.
For example, `complete=false` with an empty summary means unknown coverage;
it does not prove that the vault has no findings. The `budget` block names
checks that stopped or did not start. Full detail keeps the same deadline.
Every audit report passes fresh authorization before release. If that pass
cannot finish, `AUDIT_BUDGET_EXHAUSTED` replaces the entire report. Retry with
fewer categories, such as `categories=["broken_wikilink"]`. The error contains
no findings, paths, or counts. Unbudgeted local audits keep their existing scope.
Compatibility window: compact success is the default; `response_detail="legacy"`
and the legacy flat edit shim remain for at least one release. Because these
changes alter MCP discovery schemas, deployed connectors must be refreshed and
content-read smoke-tested before their new digest is marked verified.
## Client setup
| Client | Connection | Behavioral layer |
| --- | --- | --- |
| Claude Code | Local MCP via setup or manual config | Exomem skill, optional hooks |
| Codex CLI | `codex mcp add ...` | `AGENTS.md`, optional hooks, `read_instructions()` fallback |
| ChatGPT or hosted chat clients | Remote MCP/connector when supported | Custom instructions plus `read_instructions()` |
| claude.ai web/mobile | Remote connector | Custom instructions plus `read_instructions()` |
| Cursor, Windsurf, Gemini, generic MCP clients | Stdio or remote MCP config | `read_instructions()` at session start |
| Scripts and custom chatbots | MCP, REST, or CLI | Cache `read_instructions()` (REST and CLI: `bootstrap`) per process/session |
## Copyable instruction block
Use this block when a client has no loaded Exomem skill. Claude Chat and ChatGPT
can load the skills from a plugin. Claude Code and Codex load them through
`exomem setup`.
Trim the tone line to your preference.
```text
Use Exomem for eligible durable preferences, personal baselines, governed knowledge, sources, evidence, decisions, and reusable conclusions. Keep temporary working context in the current conversation.
Without a loaded skill, call read_instructions(profile="compact") once per session and follow it.
Search for prior projects, decisions, sources, failures, experiments, or domains; skip unrelated chit-chat/control and answered follow-ups. Cite hits. Empty is a scoped miss; retry terms or scope="vault" when absence matters.
Save durable conclusions on your own: decisions, solved problems, diagnosed failures, reusable patterns/context, or a method actually carried out with a reported reusable result. A stable preference, recurring routine, historical baseline, or durable affiliation qualifies only with stability or recurrence plus reusable comparison, interpretation, or decision value. Use a uniquely resolved Entity's narrow facet; else one concise compiled observation; Records only for a compatible existing measurement. Fleeting preferences, one-off activity, incidental associations, trivial metrics, and tentative claims stay quiet. Concise observation, narrow Entity facet, new Entity or own edge: `proactive_capture`; accepting a queued relation: `link_acceptance`; merge or structural change: confirmed `restructure_execution`. Save compiled notes, not transcripts; keep raw sources/evidence separate. Use `edit_note` for small corrections, `supersede_note` for supersession.
```
## Codex CLI
`exomem setup` now wires Codex the same way it wires Claude Code — MCP
registration, all ten skills, and hooks — so the usual answer is simply:
```bash
exomem setup
```
It detects Codex from `codex` on PATH or a `~/.codex` directory, registers the
server via `codex mcp add` (falling back to a backed-up, diffed merge into
`~/.codex/config.toml`), and installs the skills into `~/.codex/skills/`.
Codex **does** load Agent Skills from disk, so the instruction block above is no
longer required there — it remains the fallback for clients that have neither
skills nor hooks. To do the steps individually:
```bash
exomem install-skill --client codex
exomem install-hook --client codex
codex mcp add exomem --env EXOMEM_VAULT_PATH="/path/to/vault" -- exomem --transport stdio
```
`--transport stdio` is not optional: the server defaults to HTTP, so a config
that omits it starts a web server on port 8765 instead of speaking MCP.
Check deployed Claude Code and Codex hooks:
```bash
exomem install-hook --check
```
The continuation portion uses one client-neutral, stdlib-only core with thin
Claude/Codex envelope and output adapters:
| Lifecycle event | Claude Code | Codex CLI 0.144.3 |
| --- | --- | --- |
| `PreCompact(manual|auto)` | structural checkpoint | structural checkpoint |
| `SessionEnd` | structural checkpoint | unsupported; no Exomem registration |
| `SessionStart(compact|resume)` | validated reinjection | validated reinjection |
It runs locally without MCP, REST, a model, Exomem CLI, a vault path, or an MCP
credential. A checkpoint contains only bounded structural recovery evidence:
repository/worktree state, bounded paths, content-free artifact hashes and
checkbox profiles, and path-bound transcript byte-slice hashes. It never parses
or stores transcript records, conversation/tool/system output, compaction
summaries, secrets, or artifact/task text. Reinjection is advisory and never
turns checkpoint data into an automatic Exomem write.
State is per client and collision-resistant under
`~/.claude/.cache/exomem-continuation/` or
`~/.codex/.cache/exomem-continuation/`. `CLAUDE_CONFIG_DIR` and `CODEX_HOME`
relocate the respective client roots; `EXOMEM_HOOK_HOME` overrides either root
for isolated installs. Current state is accepted only for the exact
client/session/root and transcript provenance, and only for 30 days. A validated
previous generation may be reinjected as an explicit `rollback`; corrupt,
foreign, stale, truncated, or oversized state stays silent. Metadata-only logs
contain no environment values or absolute paths.
Set `EXOMEM_CONTINUATION_DISABLE=1` in the environment that launches the client
to bypass checkpoint writes and reinjection without deleting state. Reload or
restart the target client after installation and accept any local-hook trust
prompt. `install-hook --check` validates exact supported registrations and
matchers, deployed hashes, legacy entries, runtime permissions/age/status, and
logs; before the first write event, absent runtime state is a warning, not a
failure.
Re-running installation performs a narrow migration: only exact legacy
`kb_continuation_checkpoint.py` and `kb-continuation-checkpoint.sh` basenames are
retired, unrelated hook order is preserved, user-owned Codex `SessionEnd`
handlers stay untouched, and changed valid config is backed up and replaced
atomically. Malformed config fails closed. `install-hook --uninstall` rolls the
whole thing back: it removes only the entries this installed and then the
scripts it deployed, `--keep-scripts` unwires the config alone, and where the
config is deployed by yadm alternates it prunes the `##os.*` sources as well —
without that, the next alternate selection regenerates the deployed file and the
hooks return. The local state is inert afterward and can be deleted
independently.
Codex reads repository instructions from `AGENTS.md`. Put the instruction block
there, or keep an equivalent policy. Restart Codex sessions after changing MCP
or hook config.
## Generic stdio MCP clients
Use the standard stdio config shape:
```json
{
"mcpServers": {
"exomem": {
"command": "exomem",
"args": ["--transport", "stdio"],
"env": {
"EXOMEM_VAULT_PATH": "/path/to/vault"
}
}
}
}
```
After connecting, ask the agent to call:
```text
read_instructions(profile="compact")
```
## Hosted chat clients
Hosted clients usually cannot use local filesystem hooks or load the repo's
Claude Code skill. To set one up:
1. Connect Exomem through the remote MCP or connector support the client offers.
2. Paste the learning instruction below into the account-level or project-level custom instructions.
3. If the client has no loaded Exomem skill, add the instruction block above after it.
```text
Use Exomem as the memory for my work. Before you start a task, recall what Exomem holds about the systems, projects or topics it touches. As you work, save each reusable fact you establish (how something is structured, a pitfall, a method that worked) as one concise observation, and update an existing note when one covers it, so a later session does not have to find it again.
```
The agent then recalls what Exomem holds before a task and saves what it learns.
The learning instruction is your own request, so it goes where the client reads
your instructions. With the instruction block it is longer than a 1,500-character
field, so where the client caps a field, give each text its own field. `exomem
setup` offers the same text for Claude Code (`CLAUDE.md`) and Codex
(`AGENTS.md`). Leave it out at the `light` and `off` prominence levels: they save
only when you ask.
For ChatGPT Personal Plugins, follow the exact OAuth-only settings and
tool-surface refresh gate in [remote-quickstart.md](remote-quickstart.md#chatgpt-personal-plugin-oauth-only).
If the hosted client cannot reliably call `read_instructions()` on its own, start a new
chat with:
```text
Call Exomem read_instructions(profile="compact") once, then use that contract for this
chat. Do not search the KB unless this turn touches my prior projects, notes,
decisions, sources, failures, experiments, or domains.
```
## Performance guidance
| Use case | Tool shape | Meaning |
| --- | --- | --- |
| Normal lookup | `search_memory(detail="compact", rerank=false)` | Cheap routing recall |
| Reasoning | `search_memory(deep=true)` | Bounded context assembly for synthesis |
| Diagnostics | `search_memory(detail="compact", include_timings=true, rerank=true)` | Explain latency and ranking behavior |
When reranking is active, optional `rerank_max_candidates` bounds the fused
prefix sent to the scorer. It must be between the effective normalized result
limit and 300. The retrieval profile reports `candidate_limit_requested`,
`candidate_limit_effective`, `scorer_input_count`, and `unscored_tail_count`;
the tail keeps fused order. This is a work bound, not a hard latency budget.
Resource mode is separate from search knobs:
| Mode | Meaning |
| --- | --- |
| `quiet` | Low-resource CPU mode; avoid warm-up and release models when idle |
| `normal` | CPU-first default; keyword/BM25 recall is ready first |
| `performance` | Explicit opt-in for GPU-capable steady-state work; models preload at startup and stay resident, so no request pays a model load |
Do not interpret a slow diagnostic search with rerank enabled as "Exomem is
slow" without checking timings, resource mode, cache state, and whether a model
was cold.
## Verification
After setup:
```bash
exomem doctor
exomem install-hook --check
```
Then ask the client to call `read_instructions(profile="compact")`. A good response
includes a `contract_version`, server compute policy, tool defaults, and the
search/save workflow. Ask one known vault question next and confirm it uses
`search_memory` before answering.
For remote connectors, use [remote-quickstart.md](remote-quickstart.md). For the
memory boundary, see [vs-built-in-memory.md](vs-built-in-memory.md).
After a durable-auth upgrade, keep the existing connector URL and complete its
one final GitHub login. New conversations should reuse the stored Exomem bearer;
a repeated login prompt is a failed client-compatibility gate, while a `503`
means the session authority is unavailable and should not trigger reauthorization.