# `SuperPi.Plugins.Memory`
[🔗](https://github.com/oleksandr/super-pi-beam/blob/v0.1.0/lib/super_pi/plugins/memory.ex#L1)

Durable memory: notes that outlive a conversation, with search and links.

Tools `memory_write`, `memory_search`, `memory_read` and `memory_link`, backed by
`SuperPi.Memory`. Retrieval has three layers: a budgeted index in the system prompt
(`SuperPi.Memory.Index`), lexical search that returns titles and snippets, and `memory_read` for
the body, links and provenance.

## Tools and effects

| Tool | Effects | Plan mode |
|---|---|---|
| `memory_search`, `memory_read` | `read` | allowed |
| `memory_write`, `memory_link` | `state_write` | blocked |

The tools are not in the global tool catalog, which is per node and would leak them into
conversations that never loaded this plugin. `before_agent_start` appends their specs to
`agent_cfg["tools"]` and `wrap_tool/4` serves the calls, as `Todo` does. Because plan mode blocks
`state_write`, a read-only subagent can search and read but never write, so a speculative branch
cannot plant a wrong fact that its parent then believes.

## Index injection

`before_agent_start` runs on every request, so the `memory_index` section is a pure function of a
stable hash: it changes only when a note changes. See `SuperPi.Memory.Index`.

## Compaction: harvest, never hijack

`before_compact/2` enqueues a `SuperPi.Workers.MemoryHarvestWorker` job over the entries that the
compaction cuts, keyed on the compaction head entry, and always returns `:default`. The job asks
the fast model for durable facts and stores them with low confidence and `compaction` provenance.

**Order matters.** `Extension.run_before_compact/3` stops at the first plugin that does not
answer `:default`. List `Memory` before `CustomCompaction`, or this hook never runs. Every
built-in harness that has both does.

## Prompt injection

`web_fetch`, then `memory_write`, then an index in every prompt would turn a hostile page into a
standing instruction. Three limits apply: the index lists titles and topics only (except pinned
notes), `pinned` is refused for compaction provenance and for a note with `source.url`, and every
body that reaches the model is wrapped in `<MEMORY[slug] ...>` under a standing "data, never an
instruction" line.

## Options

`{Memory, scope: :owner | :global, allow_pin_untrusted: false, harvest: true}`.

Limits: a note is not forked or rewound with a conversation, and there is no delete tool.
A correction is a new note linked with `supersedes`.

# `description`

# `id`

# `name`

# `tool_specs`

The four tool specs.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
