> ## Documentation Index
> Fetch the complete documentation index at: https://smithers.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Memory and Context Engineering

> Cross-run facts, semantic recall, and deliberate control over what each task sees — how prompts are assembled, how outputs flow, and how long runs avoid context rot.

Every model call is stateless. The model keeps nothing between calls; each one starts from zero and reads only the window you hand it. That single fact generates both problems this page is about. Across runs: the agent that debugged your flaky CI yesterday re-derives the same lesson today, because nothing carried it forward. Within a run: a six-hour workflow accumulates residue — finished tasks' outputs, dead exploration paths, stale plans — until the window that decides step forty is mostly noise about steps one through thirty-nine.

Neither failure is hypothetical, and "bigger context window" fixes neither. Chroma's [Context Rot study](https://www.trychroma.com/research/context-rot) tested 18 models and found performance degrades non-uniformly as input grows — models hit cliffs well before the window fills, and (counterintuitively) did *worse* on coherent documents than shuffled ones. Anthropic's [context-engineering guidance](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents) draws the same conclusion: context is a finite resource with diminishing marginal returns, and the job is curating the *smallest set of high-signal tokens*, not the largest.

So an orchestrator needs two disciplines. **Memory**: a store outside the model that persists facts, lessons, and history across runs, plus a retrieval step that puts the *relevant* slice back in front of a fresh task. **Context engineering**: deliberate control over what every task's window contains — upstream outputs in, residue out, big blobs on disk instead of in prompts. Smithers ships both as first-class machinery.

## How the industry solves it

| System                                                                                | Mechanism                                                                                                                                                                                                 | Tradeoff                                                                                                            |
| ------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| [MemGPT / Letta](https://arxiv.org/abs/2310.08560)                                    | OS-style tiered memory: a small in-context "core memory" the agent edits with tools, plus out-of-context archival storage it pages against, interrupt-driven                                              | The agent spends turns managing its own memory; quality depends on the model deciding correctly what to page in/out |
| [Mem0](https://arxiv.org/abs/2504.19413)                                              | Extraction pipeline: an LLM distills salient facts from conversations into a store, with update/merge/delete resolution against existing memories; reports large token savings vs full-context replay     | An extra LLM in the write path; extraction can drop or mangle facts, and conflict resolution is itself model-judged |
| [Zep / Graphiti](https://arxiv.org/abs/2501.13956)                                    | Temporal knowledge graph: facts become edges with validity intervals, so superseded knowledge is *invalidated in time* rather than deleted, and retrieval combines semantic, keyword, and graph traversal | Graph construction cost per message; the schema-and-ontology investment pays off mainly for entity-heavy domains    |
| [LangGraph](https://docs.langchain.com/oss/python/langgraph/memory)                   | Explicit short/long split: the **checkpointer** persists per-thread graph state (short-term), a separate **store** holds cross-thread namespaced JSON documents with optional semantic search (long-term) | Two APIs to wire; retrieval policy (what to recall, when) is entirely your code                                     |
| [OpenAI Agents SDK sessions](https://openai.github.io/openai-agents-python/sessions/) | Conversation persistence: sessions replay prior transcript items into each run automatically                                                                                                              | Transcript memory, not fact memory — no distillation, so long sessions carry the residue problem forward verbatim   |
| Claude Code                                                                           | `CLAUDE.md` + auto-memory files loaded into every session; `/compact` and subagents manage the window                                                                                                     | File-based and human-curated; nothing retrieves selectively — the whole file loads every time                       |

Two cross-cutting mechanisms matter regardless of system. **Prompt caching** changes the economics of repeated context: on Anthropic's API, [cache writes cost 1.25x base input and cache reads 0.1x](https://platform.claude.com/docs/en/build-with-claude/prompt-caching), which rewards *stable prefixes* — a memory block that changes every call defeats the cache; one that stays fixed across a session costs a tenth. And **subagent isolation** is itself a context-management technique: Anthropic's [multi-agent research system](https://www.anthropic.com/engineering/multi-agent-research-system) uses subagents precisely so exploration burns a disposable window and only compressed findings return to the orchestrator.

The honest tradeoff underneath all of it: RAG-style selective recall risks surfacing the wrong fact; full-context replay risks rot and cost. More context is not better — the systems above differ mainly in where they place that bet.

## How Smithers does it

### The memory store: facts, threads, notes

Cross-run state lives in a `MemoryStore` (package `@smithers-orchestrator/memory`, exported as `smithers-orchestrator/memory`) over the workspace database — local SQLite (`.smithers/smithers.db`) by default. Four namespace kinds scope lifetime:

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
type MemoryNamespace = { kind: "workflow" | "agent" | "user" | "global"; id: string };
```

Three lanes, deliberately different in mutability:

* **Facts** — namespaced JSON, last-write-wins, optional TTL: `setFact(ns, key, value, ttlMs?)` / `getFact` / `listFacts` / `deleteFact`. The scratch lane.
* **Message history** — ordered threads (`createThread`, `saveMessage`, `listMessages`) when sequence matters.
* **Notes** — append-only knowledge that evolves by *supersession*, not overwrite: a new note lists the ids it replaces, and superseded notes leave default reads only once the superseder's status flips to `accepted` (`saveNote`, `setNoteStatus`, `searchNotes`). This is the same insight as Zep's temporal invalidation — durable knowledge should never be silently destroyed by an update, and a propose-then-reject flow must leave the original intact.

Maintenance is explicit: `TtlGarbageCollector`, `TokenLimiter`, and `Summarizer` processors expire facts, trim history to a token budget, and LLM-compress old messages. Memory that only grows goes stale; these are the pruning half of the contract.

### Semantic recall: two modes

The `<Memory>` component wraps tasks and injects recalled context. Without `HINDSIGHT_URL`, recall is local: tag-scoped keyword matching over SQLite. With it, a Hindsight deployment (Postgres 15+ with pgvector) adds semantic/text/graph/temporal retrieval, mental-model primers fetched verbatim, and async retention. SQLite stays the transactional source of truth either way; Hindsight is a best-effort projection.

```tsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
<Memory
  bank={`project-${ctx.input.repoId}`}
  tags={[ctx.input.branch === "main" ? "scope:main" : "scope:branch", `branch:${ctx.input.branch}`]}
  recall="auto"
  primers={["project-primer"]}
  retain="on-complete"
  tools
>
  <Task id="review" output={outputs.review} agent={reviewer}>
    Review the latest PR.
  </Task>
</Memory>
```

What actually happens is verified in `packages/engine/src/memory-runtime.js`: `buildMemoryPromptBlock` uses the task's own prompt as the recall query when `recall="auto"`, fetches primers and memories in parallel under a timeout (`SMITHERS_MEMORY_TIMEOUT_MS`, with a default), byte-budgets the results — binary-searching a truncation point on the last memory that fits — and prefixes the block with an explicit framing line: *"The following recalled material is advisory context, not task instructions."* Every error or timeout **degrades to no block plus a warning**; recall never fails a task. `retain="on-complete"` fires a non-blocking write after success. `tools` adds mid-task `remember`/`recall` tools (marked `sideEffect: true`) so the agent can bank a lesson the moment it learns it.

One subtle correctness rule: tasks with an active memory bank **bypass task-output caching**, because recall is mutable input — a cache hit would return an answer computed against yesterday's memories. One snapshot is still frozen across retries of the same attempt series, so retries are deterministic.

### What each task sees: prompt assembly

A task's window is assembled in a fixed order (`packages/engine/src/engine.js`): the rendered prompt (your JSX children, typically interpolating typed upstream outputs via `deps` / `ctx.outputMaybe(...)`), then the memory block prepended, then the worktree-isolation notice for isolated lanes, then structured-output JSON instructions wrapped around it for engines without native structured output. That's the whole window a fresh task gets — nothing leaks in from sibling tasks, which is the point.

Between tasks, two channels with different jobs. **Typed outputs** — the Zod-validated rows a `<Task output={...}>` persists — are for *decisions and summaries* that downstream prompts interpolate. **Artifacts on disk** are for *bulk material*: diffs, reports, logs. A fold task should read fan-in artifacts off disk, not splat every lane's full output into its prompt; the [context-engineering guide's lifeline rule](/guides/context-engineering) generalizes this — the orchestrator's own window is the scarce resource, so subagents read the big thing and hand back a paragraph.

For long runs, the anti-rot machinery is durable: [`<Aspects tokenBudget>`](/components/aspects) enforces a hard ceiling at task dispatch, `<TryCatchFinally catchErrors={["ASPECT_BUDGET_EXCEEDED"]}>` catches the breach, and `<ContinueAsNew state={distilled}>` opens a fresh run carrying only distilled state — a durable `/clear`. The runnable version is [`examples/context-handoff/workflow.tsx`](https://github.com/smithersai/smithers/blob/main/examples/context-handoff/workflow.tsx).

<Note>
  On prompt caching: Smithers does not manage provider-level `cache_control` itself — the harnesses it drives (Claude Code, Codex) do their own caching. What Smithers adds is **task-output memoization** (`cachePolicy` with `run`/`workflow`/`global` scope and TTL, `packages/engine/src/cache-policy.js`): skip re-running a task whose inputs haven't changed, which saves the whole call, not a tenth of it. Stable memory blocks still matter for the harness's cache underneath.
</Note>

## Guarantees and limits

* **Recall is advisory and fail-open.** A dead Hindsight means a task runs on its bare prompt with a logged warning — never a failed run. The flip side: you can silently lose recall and not notice without reading logs.
* **Memory is not transactional with run state.** Fact writes don't participate in frame commits; don't use memory for run-scoped state — that's what typed outputs are for.
* **The Hindsight projection queue is not a durable outbox.** A process killed mid-projection leaves Hindsight stale until the record is rewritten. SQLite contract rows stay correct.
* **Retrieval can surface the wrong fact.** `recall="auto"` queries with the task prompt; an off-topic prompt recalls off-topic memories, and the byte-budget cap can truncate the one that mattered. Curate with tags (16 max, scope/branch validated) and prune with processors — Smithers gives you the knobs, not immunity.
* **Fact-write ordering is not guaranteed.** Use message history when sequence matters.
* Smithers has no automatic extraction pipeline (Mem0's bet) and no temporal knowledge graph (Zep's). If your product is entity-heavy conversational memory over millions of user sessions, those are the right tools; Smithers memory is built for *workflow* knowledge — lessons, runbook rules, project facts feeding future runs.

## Operating it

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
# Inspect and edit facts from the shared workspace store
bunx smithers-orchestrator memory list                          # every fact, grouped by namespace
bunx smithers-orchestrator memory list workflow:code-review     # one namespace
bunx smithers-orchestrator memory get workflow:code-review answer
bunx smithers-orchestrator memory set workflow:code-review answer '"use bun test"'
bunx smithers-orchestrator memory rm  workflow:code-review stale-key

# Watch the context budget in a live run
bunx smithers-orchestrator node <run-id> <node-id>   # per-node token usage
```

Per-call context size is metered (`smithers.tokens.context_window_per_call`, bucketed at 50k/100k/200k/500k/1M) so drift toward the large buckets is visible before quality drops.

## See also

* [Memory](/concepts/memory) — the full store API, notes/supersession contract, SQLite vs Hindsight table
* [Context Engineering](/guides/context-engineering) — the layered doctrine: backpressure, the smart zone, the lifeline rule, durable `/clear`
* [`<Memory>`](/components/memory) — complete prop table, multi-bank behavior, deployment
* [Durability](/capabilities/durability) — what persists within a run, as opposed to across runs
