AI Agent Memory: Better Handled via Context Engineering

LLMs are inherently stateless. "Memory" is entirely platform-engineered through strategic context injection — and RDF provides a superior substrate for doing it right.

Sources: ByteByteGo + agent-rdf-memory KG curated by Kingsley Uyi Idehen

Comparative Analysis: Generic Framework vs. Concrete Implementation 🔗

The two source materials operate at different altitudes. ByteByteGo describes the problem space in framework-agnostic terms. agent-rdf-memory is a working implementation that satisfies that framework using RDF Turtle rather than vector embeddings or plain text.

DimensionByteByteGo (Generic Framework)agent-rdf-memory (Concrete Implementation)
Level of abstractionVendor-neutral taxonomy — applies to any agent stackA single, opinionated reference implementation
Memory substrateUnspecified — vector DB, SQL, key-value, or filesRDF Turtle exclusively — typed, named-IRI graph
Retrieval mechanismGeneric "retrieval" — typically semantic/vector similarity searchStructural injection (SessionStart hook) + on-demand rdfs:seeAlso traversal, no embeddings
Injection triggerNot prescribed — left to the implementerHard-coded hook (load_memory.py) fires before every session
Compression strategySummarisation (lossy)Sparse-index pattern — lossless pointer-based deferral to howto/*.ttl
VerifiabilityNot addressed — no audit mechanism describedvalidate-memory-protocol.py post-session transcript audit + schema:text length gate
QueryabilityImplementation-dependentNative — any SPARQL engine can query the memory store directly
Primary failure mode namedLost-in-the-middle effect, retrieval failureSame risks, mitigated structurally rather than algorithmically
Audience / purposeIndustry-wide conceptual referenceProduction behavioral contract for one agent in one repository
Where they agree: both treat retrieval — not storage — as the central engineering problem, and both argue memory must be tiered rather than treated as a single undifferentiated blob.

Where they diverge: ByteByteGo stays substrate-agnostic and leaves retrieval ranking as an implementation detail (commonly solved with vector similarity in practice). agent-rdf-memory rejects vector similarity retrieval entirely in favor of deterministic, structural mechanisms — trading retrieval recall for retrieval reliability.

The Four Memory Tiers 🔗

🔥 Working

Active context window — hot, bounded by token limit, populated by SessionStart hook from RDF files each session.

⚡ Session

Recent activity awaiting archival — current day's session TTL file, written on trigger events.

💾 Long-term

Persistent facts and behavioral rules — core.ttl, preferences.ttl, and the full sessions/ archive.

🗄️ Cold Archive

Full historical session log — all past sessions/*.ttl, queryable via SPARQL even if not injected at startup.

Knowledge Graph Explorer 🔗

Density
Physics

Frequently Asked Questions 🔗

Every LLM API call begins from a completely fresh slate — the model has no access to prior calls even one millisecond earlier. There is no built-in memory; the illusion of continuity is produced entirely by platform engineering that strategically reinserts relevant context (prior messages, facts, rules) into each new call. This means "agent memory" is not a property of the model — it is a property of the infrastructure wrapping it.

Prompt engineering focuses on crafting individual instructions to steer model behavior in a single call. Context engineering is the broader discipline of deciding what information to include, exclude, compress, or retrieve across the entire context window — managing memory tiers, retrieval signals, summarisation fidelity, and injection timing so the model has the right information at each turn. Context engineering is the architectural layer; prompt engineering is one tool within it.

Working memory (active context window — populated by the SessionStart hook); Episodic memory (time-anchored records — sessions/YYYY-MM-DD-{llm-id}-{agent-env}.ttl using OPAL Analytics Ontology); Semantic memory (stable facts — core.ttl with schema:Person and schema:PropertyValue triples); Procedural memory (behavioral rules — preferences.ttl sparse index + 44 companion howto/*.ttl files encoding 103 standing instructions).

The lost-in-the-middle effect is the empirically observed phenomenon where LLMs recall information at the beginning and end of a context window more reliably than in the middle. agent-rdf-memory mitigates this through the sparse-index pattern: preferences.ttl contains only step names and one-sentence rules — keeping it compact so all content falls in the high-attention zone. Full detail is in howto/*.ttl files loaded on demand.

RDF Turtle gives behavioral rules four properties markdown cannot: (1) Queryability — rules are addressable via SPARQL by trigger condition, position, or topic; (2) Semantic typing — each rule is a schema:HowToStep with explicit rdf:type, trigger, and rdfs:seeAlso; (3) Resolvability — entity IRIs are dereferenceable URLs, not opaque strings; (4) Composability — rules cross-reference each other, forming a connected graph rather than a flat list.

The SessionStart hook (load_memory.py) fires before the agent generates any response. It reads core.ttl, preferences.ttl, index.ttl, and the most recent session file, then returns their compiled content as additionalContext to the harness, which injects it into the model's context window. Memory loading is structural — enforced by the runtime, not reliant on the agent remembering to invoke a tool.

The sparse-index pattern splits memory into two tiers: a compact always-loaded index (preferences.ttl) with only step names, one-sentence rules, trigger conditions, and rdfs:seeAlso pointers; and verbose on-demand companion files (howto/*.ttl) with full rationale, code examples, and gates. preferences.ttl is read at every session start — its token cost is unconditional. Verbose content would inflate that cost by its full length every single session.

Four key tradeoffs: (1) Recency vs. relevance — balance between the most recent and most semantically similar information; (2) Summarisation fidelity — compression reduces cost but loses precise detail; (3) Staleness — outdated facts can persist with unwarranted confidence; (4) Security exposure — persistent memory creates long-term attack surfaces for injected malicious content. agent-rdf-memory addresses staleness via dated session files and explicit schema:dateModified tracking.

validate-memory-protocol.py parses Claude Code JSONL session transcripts and checks for five mandatory tool calls in order: (1) ls agent-rdf-memory/, (2) Read core.ttl, (3) Read preferences.ttl, (4) Read index.ttl, (5) at least one additional howto or session file. The --strict mode additionally verifies all reads occurred before the first substantive assistant response — catching "read-after-respond" violations.

RAG retrieves relevant chunks from a vector store at query time. agent-rdf-memory uses structural injection — loading behavioral rules in full at session start, not query time — ensuring they are always present. Retrieval is reserved for querying the local RDF file system during KG question-answering workflows. The two approaches are complementary: RDF context engineering for behavioral rules, RAG for knowledge retrieval.

Session files follow: YYYY-MM-DD-{llm-id}-{agent-env}.ttl. The three-component key (date, model, environment) enables unambiguous cross-session provenance: the same day can produce multiple files for different models or environments, and the model component is always sourced from the system-prompt model identifier — never inferred from conversation context — preventing misrouting of artifacts.

Production memory failures are almost never caused by information not being stored — they are caused by the right information not being surfaced at the right moment. This shifts the design burden from storage capacity to retrieval precision. In agent-rdf-memory, the SessionStart hook pre-loads critical memory unconditionally; howto files are loaded on demand via rdfs:seeAlso; and SPARQL makes any fact retrievable by subject, predicate, trigger condition, or date range.

Glossary 🔗

Context Engineering

The discipline of strategically assembling and injecting relevant information into a stateless LLM's context window — the actual mechanism behind "agent memory."

Working Memory

The live context window for the current agent task — hot, bounded by the model's token limit, populated by the SessionStart hook from persistent RDF files.

Episodic Memory

Time-anchored records of specific past interactions — stored as dated Turtle files in sessions/ using OPAL Analytics Ontology vocabulary.

Semantic Memory

Context-independent stable facts — user identity, output path routing, canonical IRIs — stored in core.ttl and valid across all sessions.

Procedural Memory

Behavioral rules encoded as schema:HowToStep entities in preferences.ttl and companion howto/*.ttl files — 103 standing instructions governing every session.

Lost-in-the-Middle Effect

Empirically observed degradation in LLM recall for information positioned centrally in long context windows — motivating the sparse-index pattern.

Sparse Index Pattern

A two-tier architecture where the always-loaded index holds only compact pointers and one-sentence rules; verbose detail lives in on-demand companion files.

Behavioral Contract

A set of queryable schema:HowToStep RDF entities encoding standing agent instructions, each with a trigger condition and a pointer to a companion howto file.

SessionStart Hook

A harness-level Python script that reads RDF memory files and injects them as additionalContext before the agent's first turn — enforcing context engineering structurally.

RDF-Based Agent Memory

Persistent agent memory stored as Turtle RDF — queryable via SPARQL, semantically typed, dereferenceable, and structured for the sparse-index pattern.

How to Implement Agent Memory via Context Engineering 🔗

1

Classify memory needs across the four functional types

Map each piece of information to working, episodic, semantic, or procedural memory. This classification determines where it is stored, how it is injected, and when it expires.

2

Design the storage tier mapping

Map memory types to tiers: procedural and semantic → long-term storage (always-loaded RDF files); episodic → session tier (dated files loaded on demand); working → context window assembled at each call.

3

Choose RDF Turtle as the persistent storage format

Encode all persistent memory as RDF Turtle with well-typed schema.org and custom ontology terms. Each rule becomes a schema:HowToStep, each session an opal:ChatSession, each fact a schema:PropertyValue triple.

4

Implement structural context injection via a harness hook

Do not rely on the agent to load memory via tool calls — enforce it structurally. Configure a SessionStart hook that reads core memory files and injects their content as additionalContext before the first user turn.

5

Apply the sparse-index pattern to keep the always-loaded contract compact

In the behavioral contract file, each rule should contain: schema:name, one-sentence schema:text, onto:hasTrigger, and rdfs:seeAlso. Run a verification script to catch schema:text values exceeding 300 characters.

6

Add a post-session validation gate to audit protocol compliance

Implement a transcript audit script that verifies all mandatory memory-loading steps were executed before the agent's first response. Let its failures drive iterative improvement of the hook injection.

7

Make memory queryable — enable SPARQL retrieval across the local RDF store

Point a SPARQL engine at the memory directory and build query patterns for: "what are all rules triggered by artifact generation?", "which sessions generated output to this path?", "what was the most recent correction?"

SPARQL Explorer 🔗

Query the knowledge graph via URIBurner SPARQL endpoint. Select a recipe or write your own. Results open in a new tab. Use format=text%2Fx-html%2Btr for HTML table output from SELECT queries.

PREFIX : <https://linkeddata.uriburner.com/DAV/demos/daas/ai-agent-memory-context-engineering-claude_sonnet_4_6-1.ttl#>
PREFIX schema: <http://schema.org/>
SELECT ?memoryType ?description ?storedIn
FROM <https://linkeddata.uriburner.com/DAV/demos/daas/ai-agent-memory-context-engineering-claude_sonnet_4_6-1.ttl>
WHERE {
  ?m a :MemoryType ;
     schema:name ?memoryType ;
     schema:description ?description .
  OPTIONAL { ?m :storesIn ?tier . ?tier schema:name ?storedIn . }
}
ORDER BY ?memoryType
▶ Run on URIBurner
PREFIX : <https://linkeddata.uriburner.com/DAV/demos/daas/ai-agent-memory-context-engineering-claude_sonnet_4_6-1.ttl#>
PREFIX schema: <http://schema.org/>
SELECT ?position ?stepName ?stepText
FROM <https://linkeddata.uriburner.com/DAV/demos/daas/ai-agent-memory-context-engineering-claude_sonnet_4_6-1.ttl>
WHERE {
  :howtoContextEngineering schema:step ?step .
  ?step schema:position ?position ;
        schema:name ?stepName ;
        schema:text ?stepText .
}
ORDER BY xsd:integer(?position)
▶ Run on URIBurner
PREFIX : <https://linkeddata.uriburner.com/DAV/demos/daas/ai-agent-memory-context-engineering-claude_sonnet_4_6-1.ttl#>
PREFIX schema: <http://schema.org/>
SELECT ?name ?description
FROM <https://linkeddata.uriburner.com/DAV/demos/daas/ai-agent-memory-context-engineering-claude_sonnet_4_6-1.ttl>
WHERE {
  ?concept :addressesChallenge :LLMStatelessness ;
           schema:name ?name ;
           schema:description ?description .
}
ORDER BY ?name
▶ Run on URIBurner
PREFIX : <https://linkeddata.uriburner.com/DAV/demos/daas/ai-agent-memory-context-engineering-claude_sonnet_4_6-1.ttl#>
PREFIX schema: <http://schema.org/>
SELECT ?question ?answer
FROM <https://linkeddata.uriburner.com/DAV/demos/daas/ai-agent-memory-context-engineering-claude_sonnet_4_6-1.ttl>
WHERE {
  ?q a schema:Question ;
     schema:name ?question ;
     schema:acceptedAnswer ?ans .
  ?ans schema:text ?answer .
}
ORDER BY ?question
▶ Run on URIBurner
Results open in a new tab via URIBurner