How to give a capsule memory
By default every task a capsule runs starts from nothing: the model sees only the current task and whatever tools it calls during that task. This guide covers two independent ways to change that — seeding a task with the relevant part of an earlier conversation, and giving a capsule a durable place to write its own notes.
The relevant manifest options are:
| Option | Controls |
|---|---|
| context.record | Whether the runtime keeps a durable conversation record for this capsule |
| context.record_store | Directory under ~/.murmur/conversations/ the record lives in |
| context.seed_budget | Fraction of context.max_tokens an on-task-start hook's seed may occupy |
| context.seed_overflow_margin | Slack above the seed budget before the runtime trims or summarizes instead of seeding it whole |
| capabilities.conversation.read | Grants a hook read access to the conversation record |
| capabilities.state | Durable store an artifact's own file tools cannot reach |
Step 1 — create murmur.yaml with the memory hook
Every task on inference.transport: http already appends the messages it sends to a durable conversation record — this is on by default and needs no configuration. What is not automatic is putting any of that record back in front of the model. murmur-hook-memory is the artifact that does it: bound to on-task-start, it reads the record, selects a budget-bounded chronological slice, and seeds it at the head of the new task's context.
Create a murmur.yaml file:
name: my-agent
version: "0.1.0"
context:
max_tokens: 1000000
artifacts:
- name: murmur-driver-anthropic
version: "1.0.0"
runtime: driver
- name: murmur-hook-memory
version: "1.0.0"
runtime: hook
capabilities:
conversation:
read: true
inference:
transport: http
endpoint: https://api.anthropic.com
model: claude-sonnet-5
api_key: ${ANTHROPIC_API_KEY}
driver:
artifact: murmur-driver-anthropic
name: my-agent
version: "0.1.0"
context:
max_tokens: 200000
artifacts:
- name: murmur-driver-openai
version: "1.0.0"
runtime: driver
- name: murmur-hook-memory
version: "1.0.0"
runtime: hook
capabilities:
conversation:
read: true
inference:
transport: http
endpoint: https://api.openai.com
model: o3-mini-high
api_key: ${OPENAI_API_KEY}
driver:
artifact: murmur-driver-openai
name: my-agent
version: "0.1.0"
context:
max_tokens: 1000000
artifacts:
- name: murmur-driver-deepseek
version: "1.0.0"
runtime: driver
- name: murmur-hook-memory
version: "1.0.0"
runtime: hook
capabilities:
conversation:
read: true
inference:
transport: http
endpoint: https://api.deepseek.com
model: deepseek-r1
api_key: ${DEEPSEEK_API_KEY}
driver:
artifact: murmur-driver-deepseek
capabilities.conversation.read: true on the hook's own entry is required, not inferred — a murmur-hook-memory declared without it fails every read and seeds nothing. context.max_tokens is required too: it is what context.seed_budget is a fraction of, and without it a seed the hook returns is refused.
Step 2 — install dependencies
mur install
Different ways to install artifacts
mur install needs to know where to fetch artifacts from. You have two options:
Option A — configure a registry source in ~/.murmur/config.yaml:
registry:
default: official
sources:
- name: official
type: github
repo: <owner>/<repo>
token: "${GITHUB_TOKEN}"
Then install by artifact name and version:
mur install <artifact-name@version>
Option B — pass a full GitHub reference and skip configuration entirely:
mur install github:<username>/<repo>@<tag>
See Installing artifacts to learn more.
Step 3 — bound what the hook may seed
context.seed_budget and context.seed_overflow_margin both default to 0.10 — a seed may use up to 10% of context.max_tokens, with another 10% of that as slack before the runtime intervenes. Raise the budget for a capsule that leans on its history more than on the current task:
context:
max_tokens: 1000000
seed_budget: 0.15
seed_overflow_margin: 0.10
A proposed seed that fits the budget is seeded whole. One that overflows by no more than the margin has its oldest messages dropped until it fits. One that overflows by more is handed to a bound on-compaction hook to summarize, if the capsule declares one — otherwise its oldest messages are dropped the same way. None of this can fail the task: a seed the runtime cannot commit is skipped, and the task runs without it. See Context seeding for the full decision order.
Step 4 — continue a conversation across separate runs
Two mur run launches with no session directory in common still continue one conversation if you give them the same context id. Create a task.md file:
Our nightly build started failing on ARM runners after upgrading the Docker base image to 3.20. Note that down before you look at anything else.
Run it under a named context:
mur run --task task.md --context nightly-build-investigation
Later, replace task.md with a follow-up:
What did we learn last time about the nightly build failures?
Run it under the same context id:
mur run --task task.md --context nightly-build-investigation
The second run's murmur-hook-memory reads the record the first run wrote under that context id and seeds the relevant slice — the model answers from what the first run actually recorded, not from a fresh start. Omit --context and each run gets its own fresh id, so nothing carries over.
Step 5 — verify the hook seeded something
mur trace show
Different ways to identify a session
mur trace show with no argument reads the most recent session:
mur trace show
To name another one, pass an ordinal counting back from the newest (@2), the last 4 or more
characters of its ID (3e4b), the full ID, or a path to its trace.jsonl:
mur trace show @2
mur trace show 3e4b
mur trace show ses_6801f81dd28b4a9daf434e8324c4793e
mur trace show path/to/trace.jsonl
Use --workdir <path> if your session directories are not under ./workdir. Every command
that names a session takes the same addresses — see
Session addresses.
Other trace exploration commands
mur trace has four subcommands for exploring session output:
mur trace show — print the full trace for a session to the terminal.
mur trace steps — show a turn-by-turn summary of what the agent did in a session. Pass --verbose to include a truncated summary of each tool's input.
mur trace diff — compare the traces of two sessions side by side, or with no arguments the two most recent. Useful for spotting behavioural regressions between runs.
mur trace report — generate a structured summary report from a session's trace. Covers token usage, tool calls, latency, and other session-level metrics.
A run whose memory hook committed a seed shows a Context section:
── Context ──────────────────────────────────────
memory-hook committed 842 tokens (budget 1,600)
seeded from: msg_01a04900754b7183b66c11e744612e2d, msg_01a04900754b7183b66c11e744612e3e
No Context section at all means no on-task-start hook returned a seed — check that capabilities.conversation.read is on the hook's own entry, not the capsule-wide capabilities block, where it is silently inert.
Step 6 — turn the record off, or keep it separate per capsule
context.record: off stops the runtime from writing anything under ~/.murmur/conversations/ at all — useful for a capsule that should never retain what it saw, agent-to-agent handoffs included. murmur-hook-memory gracefully reads an empty page in that case rather than failing.
context:
max_tokens: 1000000
record: off
Two capsules that share a directory get separate records by default, keyed by capsule name. Give context.record_store an explicit name to point two different capsules at the same record, or to keep multiple variants of the same capsule (a staging build and a production build, say) from reading each other's history:
context:
max_tokens: 1000000
record_store: my-agent-staging
Step 7 — give the capsule a place to write its own notes
The conversation record and the memory hook cover what the model said. For structured notes the agent writes on purpose — findings, decisions, anything worth keeping past the task that produced it — declare a durable state store instead. murmur-tool-corpus is the shipped implementation: an append-only, schema-validated record store the capsule's own murmur-tool-editor or shell grant cannot reach, because it lives outside the workdir entirely.
artifacts:
- name: murmur-tool-corpus
version: "1.0.0"
runtime: tool
capabilities:
state: {}
config:
config_version: 1
types:
finding:
schema_version: 1
schema:
type: object
required: [text]
properties:
text: { type: string }
additionalProperties: false
See murmur-tool-corpus for its five operations, and Durable state store for where the grant actually points and how it differs from the conversation record. Confirm the grant resolved before relying on it:
mur run --explain-scope
state stores:
- murmur-tool-corpus: my-agent -> /home/dev/.murmur/state/my-agent
Summary
| Manifest setting | Effect |
|---|---|
context.record: on (default) |
Every task appends its messages to a durable conversation record |
context.record: off |
Nothing is written; a hook granted capabilities.conversation.read reads an empty page |
context.record_store: <name> |
Names the record's directory explicitly; default is the capsule name |
murmur-hook-memory with capabilities.conversation.read: true on its own entry |
Seeds each task with the relevant slice of prior conversation; the capsule-wide capabilities block cannot grant this |
context.seed_budget (default 0.10) |
Fraction of context.max_tokens a seed may occupy |
context.seed_overflow_margin (default 0.10) |
Slack before an over-budget seed is trimmed or summarized instead of seeded whole |
mur run --context <id> |
Two runs with the same id share one conversation record |
capabilities.state: {} on an artifact entry |
Grants that artifact a durable directory outside the workdir, keyed by capsule |
murmur-tool-corpus |
Ships as the append-only, schema-validated store for an agent's own notes |