Tools
Formative Memory
Memory plugin for OpenClaw. Agent's memories strengthen through use, fade when unused, and consolidate overnight.
Install
npm install #
Configuration Example
{
"plugins": {
"entries": {
"formative-memory": {
"enabled": true,
"config": {
"autoRecall": true,
"autoCapture": true,
"requireEmbedding": true,
"embedding": {
"provider": "auto"
},
"consolidation": {
"notification": "summary"
},
"temporal": {
"notification": "summary"
}
}
}
}
}
}
README
# Formative Memory
**Associative memory for [OpenClaw](https://openclaw.ai) agents.**
Formative Memory is an OpenClaw plugin that gives your agent long-term memory modeled after how biological memory works. Before every response, it recalls relevant memories into context. After every response, it evaluates which memories actually contributed — strengthening useful ones and letting unused ones fade. Every night, the agent sleeps: a consolidation process decays, prunes, merges, and connects memories to keep recalled context high-quality.
Over time, raw facts combine into richer structures: merged summaries, connected associations, and deeper understanding.
[](https://www.npmjs.com/package/formative-memory)
[](LICENSE)


---
## How It Works
### Recall
Before every response, the plugin searches for memories relevant to
the current conversation using hybrid search (embedding similarity +
BM25 full-text), ranked by memory strength. Matching memories are
injected into the agent's context automatically. Each retrieval
strengthens the memories that were surfaced.
```
User: "Do you remember that restaurant? The one by the beach
last summer. I'm trying to book for our anniversary."
Injected memories:
[a3f2|fact|strength=0.82] "Dinner at Maininki, Hanko, April 2026"
[b7d1|event|2026-07-04] "Wedding anniversary — 12 years"
[c9f3|preference|str=0.74] "Sanna loves peonies"
[d2e6|fact|2026-07-02] "Sanna: private doctor's appointment"
Agent: "Of course! It was Maininki, in Hanko. Shall I book a table?
Your 12th anniversary is coming up on July 4th."
```
The agent sees recalled memories as context, not instructions — this
reduces prompt injection risk from stored content.
### Evaluate
After each response, the plugin tracks which memories were surfaced
and whether they actually influenced the reply. This happens at two
levels:
- **Automatic attribution** — the plugin logs which memories were
injected and which the model referenced, building a retrieval
history without any agent effort
- **Explicit feedback** — the agent can call `memory_feedback` to
rate a memory's usefulness (1–5), signaling quality directly
Both signals feed into consolidation: frequently used, highly rated
memories are reinforced, while memories that are surfaced but never
referenced gradually lose strength. This creates a feedback loop where
the memory system learns what is actually useful, not just what matches
a query.
```
After the agent's response about Maininki:
Automatic attribution (logged by the plugin):
✓ [a3f2] "Dinner at Maininki, Hanko" — referenced in reply
✓ [b7d1] "Wedding anniversary — 12 years" — referenced in reply
· [c9f3] "Sanna loves peonies" — injected, not used
· [d2e6] "Sanna: doctor's appointment" — injected, not used
→ a3f2 and b7d1 are reinforced at next consolidation
→ c9f3 and d2e6 were surfaced but ignored — no reinforcement
Explicit feedback (agent calls memory_feedback):
→ memory_feedback(memory_id: "a3f2", rating: 5)
→ "Directly answered the user's question"
```
### Capture
Memories are collected in two ways. The agent can store a memory
explicitly with `memory_store`, and auto-capture extracts durable
facts from conversations automatically after each turn.
```
After the turn above, auto-capture extracts:
→ store("Booking anniversary dinner at Maininki", type: event,
temporal_anchor: 2026-07-04, temporal_state: future)
A later turn — user asks for Sanna's favorite foods:
Agent explicitly stores:
→ memory_store("Sanna's favorites: salmon soup (her mother's recipe,
no cream), pistachio ice cream, meat pies from Market Hall
on Saturdays", type: preference)
→ id: e8b2a1f4, strength: 1.0
```
Each memory is content-addressed (SHA-256) — same content always
produces the same ID, so duplicates are prevented by design.
### Consolidate
Every night, the agent sleeps. A consolidation process runs through
the accumulated memories:
| Step | What happens |
|------|-------------|
| **Reinforce** | Memories that influenced responses gain strength |
| **Decay** | All strengths decrease — recent memories fade faster than established ones |
| **Associate** | Memories retrieved together form links; connections grow stronger with co-occurrence |
| **Temporal shift** | Future memories transition to present or past based on anchor dates |
| **Prune** | Weak memories and associations are removed |
| **Merge** | Similar memories are combined into coherent summaries |
```
Before consolidation:
[a3f2|strength=0.82] "Dinner at Maininki, Hanko, April 2026"
[f1c4|strength=0.65] "Maininki — beachfront restaurant, good wine list"
[a9b3|strength=0.41] "Tried booking Maininki in June, fully booked"
After consolidation:
[g7e2|strength=1.00] "Maininki, Hanko: beachfront restaurant with good
wine list. Visited April 2026. Book early — fills up in summer."
Associations formed:
"Maininki" ←0.7→ "Wedding anniversary"
"Maininki" ←0.4→ "Sanna loves peonies"
```
All mutation happens during consolidation — live chat stays fast and
predictable. Over time, simple facts combine into richer structures:
merged summaries, connected associations, and deeper understanding.
## Quick Start
Install the plugin:
```bash
openclaw plugins install formative-memory
```
This installs from npm, enables the plugin, and assigns it the memory
slot automatically. Restart the gateway to load the plugin.
That's it. The plugin works out of the box:
- **Auto-capture** records conversations for consolidation
- **Auto-recall** surfaces relevant memories before every response
- **Consolidation** runs automatically to maintain memory quality
- **Startup tasks** (migrating existing memory files, scrubbing legacy
memory instructions from `AGENTS.md`/`SOUL.md`, backfilling embeddings)
run automatically at gateway boot
No configuration needed — sensible defaults are built in.
> **Multi-agent setups:** automatic startup tasks at boot resolve API
> keys from `<stateDir>/agents/main/agent/auth-profiles.json` because
> OpenClaw's plugin service context does not yet expose the active
> `agentDir`. This is correct for the default single-agent `main`
> setup. If you run multiple agents and the primary profile lives
> elsewhere, the first tool call in a session (which carries the
> correct `agentDir`) will pick up the right profile, so migration
> and cleanup still complete — they just defer until that first call.
## Memory Tools
The plugin registers five tools the agent can use during conversation:
| Tool | What it does |
|------|-------------|
| `memory_store` | Store a new memory with type and optional temporal anchor |
| `memory_search` | Search by meaning and keywords, ranked by relevance x strength |
| `memory_get` | Retrieve a specific memory by ID |
| `memory_feedback` | Rate a memory's usefulness (1-5) — feeds into reinforcement |
| `memory_browse` | Browse all memories sorted by importance, with type diversity |
Memory types: `fact`, `preference`, `decision`, `plan`, `observation`.
## Configuration
All settings are optional — defaults are designed to work out of the box.
Configuration goes in `openclaw.json` under the plugin entry:
```json
{
"plugins": {
"entries": {
"formative-memory": {
"enabled": true,
"config": {
"autoRecall": true,
"autoCapture": true,
"requireEmbedding": true,
"embedding": {
"provider": "auto"
},
"consolidation": {
"notification": "summary"
},
"temporal": {
"notification": "summary"
}
}
}
}
}
}
```
| Key | Default | Description |
|-----|---------|-------------|
| `autoRecall` | `true` | Inject relevant memories into context before every response |
| `autoCapture` | `true` | Automatically capture conversations for consolidation |
| `requireEmbedding` | `true` | Require a working embedding provider. Set `false` to allow BM25-only fallback |
| `embedding.provider` | `"auto"` | Embedding provider: `auto`, `openai`, `gemini`. Additional providers (`voyage`, `mistral`, `ollama`, `local`) are also accepted when memory-core embedding adapters are installed as a fallback registry |
| `embedding.model` | — | Override the provider's default embedding model. Only takes effect with an explicit `embedding.provider` — ignored in `"auto"` mode to avoid passing a provider-specific model name to the wrong provider |
| `dbPath` | `~/.openclaw/memory/associative` | SQLite database location |
| `verbose` | `false` | Enable debug logging |
| `consolidation.notification` | `"summary"` | Notification after nightly consolidation: `"off"`, `"summary"` (LLM-generated, persona-aware), or `"detailed"` (raw technical report) |
| `temporal.notification` | `"summary"` | Notification after temporal transitions (15:00 daily): `"off"`, `"summary"`, or `"detailed"` |
| `logQueries` | `false` | Include raw query text in debug logs (disabled by default for privacy) |
The `"auto"` provider selects the best available embedding provider from
your configured API keys. When `requireEmbedding` is `true` (the
default), the plugin will not start without a working embedding provider.
Set it to `false` to allow graceful degradation to keyword-only search.
### API Keys
API keys are read from OpenClaw's `auth-profiles.json`. Environment
variables are **not** used. Configure a profile under the standard
OpenClaw setup:
```json
{
"version": 1,
"profiles": {
"openai:default": { "type": "api_key", "key": "sk-..." },
"google:default": { "type": "api_key", "key": "AIza..." }
}
}
```
The `openai:default` and `google:default` profile nam
... (truncated)
tools
Comments
Sign in to leave a comment