ASK KNOX
beta
LESSON 587

The Memory Taxonomy: Episodic, Semantic, Procedural, Working

Memory type is not decoration — it determines lifecycle policy, confidence floor, and when a memory should die.

7 min read·Agent Knowledge Systems

Why Classify Before You Write

Most early implementations treat the memory store as a flat bag of strings. Everything goes in as the same type, with the same confidence, under the same namespace. This works until the store has a few hundred entries — and then recall degrades, lifecycle policies cannot differentiate, and there is no principled way to decide which memories should expire, which should be verified, and which should win when two memories conflict.

The taxonomy exists to give every memory a lifecycle contract at write time. A working memory scratched out during a debugging task has no value after the task ends. A procedural memory encoding a rule stated explicitly by a human should persist until a human explicitly supersedes it. A semantic memory synthesized by the agent from several observations should carry a moderate confidence and a periodic verification expectation. These are different things. Treating them the same produces a store that ages badly.

The four-type taxonomy maps directly to the memory_type column in the canonical schema, and each type drives different lifecycle behavior.

The Four Types

Episodic memories record what happened: a session retro, an observed failure, a correction received, a milestone completed. The content is time-indexed — observed_at context matters. Episodic memories are the receipts of experience. They are usually high-confidence when written (you directly observed the event) and long-lived (retros and corrections are worth keeping). They answer: "What did the agent learn in that session?" When you retrieve an episodic memory, you are accessing the agent's personal history.

// An episodic memory — what happened
const correction: CreateMemoryInput = {
  memory_id: "mem_" + crypto.randomUUID().slice(0, 8),
  namespace: "project-alpha",
  memory_type: "episodic",
  heading: "Correction received: always soft-delete before insert in supersede path",
  content: "Code review caught the supersede implementation bug on 2026-06-06. The INSERT must happen before the soft-delete, not after. If INSERT fails after DELETE, the old memory is lost with no replacement.",
  confidence: 0.95,
  source_type: "raw",
}

Semantic memories record what is true: facts about the system, architectural decisions, naming conventions, the shape of an API. They are the agent's model of the world. Semantic memories decay as the world changes — an API that was true in January may no longer be true in June. This is why confidence and a verify-before-trust policy matters most for semantic memories. A wrong semantic memory that arrives with high confidence is particularly dangerous because it provides false grounding for downstream reasoning.

Procedural memories record what to do: rules, workflows, checklists, standing protocols. "Always run the tests before committing" is procedural. "When you see this error, check that dependency first" is procedural. Procedural memories are the closest thing to a permanent behavioral prescription — they do not expire on their own, they supersede each other when the process changes, and they have the highest claim on session context at hydration time because they are the rules that govern the current task.

Working memories are this-task scratch. The agent is mid-way through a complex multi-step task and needs to persist state across tool calls: "Current subtask: migration step 3 of 7. Completed: schema update, data copy. Next: index rebuild." That fact has zero value after the task completes. It gets an expires_at — typically the expected task completion time plus a small buffer. If the task completes normally, the memory is superseded by a completion episodic. If the memory expires unused, the hygiene job cleans it. Either way, it does not clutter future recall.

Provenance: Who Wrote the Fact

The source_type column encodes how authoritative the fact's origin is. It is not an audit log — it is a trust signal.

The three rungs are raw, derived, and output. Raw facts come from human ground truth or direct system observation: Knox told the agent X, or the agent queried the live database and got Y back. These are the most trustworthy category. If a raw memory and a derived memory make conflicting claims, the raw memory wins.

Derived facts are agent syntheses: patterns inferred from multiple observations, lessons extracted from retros, conclusions drawn from data. They are the most common type the agent writes. They can be highly accurate — but they can also compound errors. If the underlying observations were skewed or if the synthesis had a logic error, the derived memory propagates that error into future sessions with the authority of learned knowledge. Setting confidence appropriately (lower floor than raw, closer to 0.7 as the default) and periodically verifying key derived claims is the mitigation.

Output facts record that the agent produced something: "Generated component X for feature Y on date Z." These are reliable records of what was done, but the artifact itself may have since changed or been deleted. An output memory accurately records what happened; it does not guarantee the artifact still exists or is still correct.

The interplay between type and source_type is what produces a differentiable memory store. A procedural + raw memory is a human-stated rule — treat it with maximum authority. A semantic + derived memory is a synthesized fact — verify it before acting on it for consequential decisions. A working + derived memory is scratch context — let it expire.

Classification in Practice

The BuildChallenge for this lesson implements a classifier using claude-haiku-4-5 with structured output. The classifier is not decorative — it is what makes the taxonomy systematic at scale. When the agent processes dozens of session events per day, classifying each manually is not viable. An automated classifier that assigns memory_type and source_type from the content makes lifecycle policies operational rather than aspirational.

The classification schema uses additionalProperties: false on every object level, no minItems/maxItems constraints, and returns memory_type, source_type, confidence, and reasoning. The classifier runs claude-haiku-4-5 rather than claude-sonnet-4-6 because classification is a pattern-matching task that does not require synthesis — keep the expensive model for synthesis and judging.

// Classifying a candidate memory before write
const classification = await classifyMemory(
  "Deploy pipeline: always use gh workflow run deploy.yml",
  "Production deploys now use GitHub Actions. The npm run deploy script was removed."
)
// Expected: { memory_type: "procedural", source_type: "derived", confidence: 0.82, reasoning: "..." }

const writeInput: CreateMemoryInput = {
  memory_id: "mem_" + crypto.randomUUID().slice(0, 8),
  namespace: "project-alpha",
  memory_type: classification.memory_type,
  heading: "Deploy pipeline: always use gh workflow run deploy.yml",
  content: "Production deploys now use GitHub Actions. The npm run deploy script was removed.",
  confidence: classification.confidence,
  source_type: classification.source_type,
}

The classifier pays for itself on the first hygiene pass. When every memory has a consistent memory_type, your hygiene job can apply a TTL to all working memories, schedule confidence-decay checks for all semantic + derived memories, and give procedural + raw memories a different verification cadence. Without the taxonomy, lifecycle is a manual decision for each row. With it, lifecycle is a policy applied automatically by type.