Skip to content

Memory

Give an agent memory that persists across sessions. Useful for preferences, durable facts, learned heuristics — anything you'd want the agent to remember next time.

Memory is opt-in per agent and scoped to that agent. Each deployed agent has its own memory silo.

Enabling memory

Add a memory block to your swarmlord.jsonc:

jsonc
{
    "name": "my-agent",
    "memory": { "enabled": true },
}

That's the whole minimum. All defaults are reasonable.

Full shape:

jsonc
{
    "memory": {
        "enabled": true,
        "maxEntries": 200, // cap on live entries (oldest low-confidence pruned)
        "maxCharsInjected": 2000, // budget for memory injected into the system prompt
        "confidenceThreshold": 0.6, // auto-extracted writes below this are skipped
        "minMessagesToExtract": 4, // skip extraction on trivial sessions
        "dryRun": false, // emit events without writing — safe-rollout mode
    },
}

How the agent uses it

When memory is enabled, the agent gets three new tools:

ToolWhat it does
rememberStore a durable memory (category + content + optional confidence)
recallSearch memories for the current task
forgetDelete a memory that's wrong or outdated

The agent also gets a relevant slice of memory automatically injected at the start of each session — you don't have to prompt for it.

After every successful session, a lightweight model reviews the transcript and proposes memory writes — new facts, updates to existing memories, or deletions. Low-confidence proposals are filtered automatically.

Categories

Memories are tagged with a category so retrieval and inspection stay organized:

  • factUser's stack is Python 3.12
  • preferenceUser prefers concise replies
  • instructionAlways PR against develop
  • relationshipAlice is on the platform team, reports to Bob
  • skill_observationThis approach to X has worked well across three runs

You can use any string; the built-in five are suggestions.

SDK

Memory attaches to client.agent(...):

ts
import { createClient } from "swarmlord";

const client = createClient();
const agent = client.agent({ name: "my-agent" });

await agent.memory.add({ category: "preference", content: "User prefers Python 3.12" });

const hits = await agent.memory.search("python", { limit: 5 });
const all = await agent.memory.list({ category: "preference", limit: 50 });

await agent.memory.forget(hits[0].id);

See the TypeScript SDK reference for the full API.

CLI

sh
swarmlord memory list   --agent my-agent
swarmlord memory add    --agent my-agent --category preference --content "User prefers concise replies"
swarmlord memory search --agent my-agent --query "python"
swarmlord memory forget <id>

Learned memory never overrides instructions

A recurring risk with agent memory is that a learned fact contradicts the agent's original instructions or SOUL.md — and starts winning. We prevent this two ways:

  1. Every recalled memory is wrapped in a <memory-context> block with an explicit note that it's background information, not a new instruction.
  2. Retrieved memory is placed before SOUL.md and your instructions in the system prompt, so your instructions always appear later and win on any conflict.

Writes are also scanned for prompt-injection patterns (role markers, override phrases, jailbreak triggers) and blocked if matched — these trigger a memory.blocked event you can monitor.

Observability

Four events stream over SSE alongside normal session events. You can subscribe to them from session.send() via dedicated callbacks — no need to drop down to session.stream():

ts
await session.send(prompt, {
    onText: d => process.stdout.write(d),
    onMemoryRecalled: e => console.log(`recalled ${e.entryCount} entries (${e.charsInjected} chars)`),
    onMemoryExtracted: e => console.log(`extraction: ${e.opsApplied}/${e.opsProposed} applied`),
    onMemoryWrote: e => console.log(`wrote [${e.category}] id=${e.id}`),
    onMemoryBlocked: e => console.warn(`blocked by sanitizer: ${e.reasons.join(", ")}`),
});
CallbackWhen it fires
onMemoryRecalledAuto-retrieval at the start of a session loop
onMemoryExtractedOnce per session, after end-of-session extraction completes
onMemoryWrotePer successful write — tool, SDK, or extractor
onMemoryBlockedWhen the sanitizer rejects content

If you need every raw event, onEvent: e => ... on the same send() call gives you the firehose.

Rollout tip

Set dryRun: true when you first enable memory. The extractor runs, events fire, but no writes land. Watch the memory-extracted events to see what the model would have stored, tune confidenceThreshold to your comfort level, then flip dryRun off.

When memory is unavailable

Memory requires a deployed agent. Raw sessions without a deployed-agent identity skip memory injection entirely, and the remember / recall / forget tools short-circuit with a clear message.