Short answer: Each memory type needs different storage rules: lifetime, cardinality, structure, isolation, and retrieval path.
Conceptual types only help when they become config: what is temporary versus durable, one record versus many, fact versus narrative, private versus shared. Those choices drive collections, scopes, indexes, and pipelines in a real memory system.
Every distinction covered in this Part, working versus long-term, episodic versus semantic, bounded versus unbounded, shared versus private, and the rest, has been discussed at the conceptual level, describing what kind of information something is and how it behaves. None of that conceptual clarity does any good until it gets translated into actual configuration decisions a storage system can act on. This closing chapter of the Part is about making that translation explicit, mapping each conceptual distinction onto the concrete settings that implement it.
Why Does a Conceptual Memory Type Need to Be Translated Into a Storage Decision at All?
A memory type by itself is just a description, useful for reasoning about what content is and how it should behave, but it doesn’t automatically configure anything. Storage systems need concrete instructions: how many entries per scope, which identifiers isolate one piece of content from another, how a search should rank what it returns. Two people who agree completely on what “episodic memory” means could still configure a storage system two very different ways if they haven’t separately worked out what that conceptual agreement actually implies for the settings involved.
This is the gap this chapter closes. Everything covered earlier in this Part answered “what is this kind of memory,” and this chapter answers “so what do I actually set.”
How Does the Bounded-Versus-Unbounded Distinction Map Onto a Concrete Setting?
This one maps almost directly: a bounded topic is the storage-level implementation of anything that should behave like a semantic fact, a profile, or a running summary, holding exactly one current entry per scope, while an unbounded topic implements anything episodic, a stream of individual occurrences that should accumulate rather than collapse into one. Deciding a piece of content is “semantic in character” and deciding a topic should be marked bounded are, practically speaking, the same decision expressed at two different levels of abstraction.
How Does the Shared-Versus-Private Distinction Map Onto a Concrete Setting?
This one maps onto scope configuration specifically: whether a topic requires a `user_id` at all. Content that should be shared across everyone using an agent belongs on a topic with no user scoping, project-wide by default. Content that should stay private to one individual belongs on a topic that requires `user_id`, with that requirement enforced structurally rather than left to application code to remember. A property-scoped identifier, like a `conversation_id`, adds a further layer of isolation beneath the user level when content needs to be separated even more narrowly than by person alone.
How Does the Choice Between Atomic Facts and a Running Summary Map Onto Retrieval Configuration?
This one is less about how content gets written and more about how it gets read back. Atomic, unbounded facts are best paired with a ranked retrieval type, vector, keyword, or hybrid search, that returns whichever subset is actually relevant to a specific query. A bounded running summary is best paired with a direct fetch by scope, retrieving the one canonical entry outright rather than ranking it against a query, since there’s only ever one thing to retrieve in the first place. Choosing the wrong retrieval type for a given shape produces confusing behavior: ranking a bounded fetch wastes effort scoring something there was only ever one version of, while trying to fetch an unbounded topic without a proper search misses the fact that many valid entries could exist simultaneously.
Does Every Piece of Content Map Cleanly Onto Exactly One Combination of These Settings?
Most content does map cleanly once its conceptual category is correctly identified, which is precisely why getting the earlier conceptual analysis right matters so much. Content that seems ambiguous under this mapping is usually a sign that it hasn’t actually been placed in the right conceptual category yet, not evidence that the mapping itself breaks down. Going back to ask which category a piece of content genuinely belongs to, rather than trying to force a mapping onto an unclear starting point, almost always resolves the apparent ambiguity.
How Does Weaviate Engram Turn This Mapping Into Actual Working Configuration?
Weaviate Engram’s topic definitions are exactly this mapping made concrete: a name, a description guiding extraction, a scoping requirement, and a bounded flag, together fully specifying how a conceptual memory type becomes a working piece of storage. Consider a veterinary clinic’s patient-care assistant, where the conceptual categories already covered map onto three cleanly distinct topic configurations:
from engram import EngramClient
client = EngramClient(api_key=os.environ["ENGRAM_API_KEY"])
client.memories.add(
"Patient is allergic to amoxicillin and becomes highly anxious during nail trims; sedation is preferred for that procedure.",
user_id="patient-2214",
topics=["PatientProfile"],
)
client.memories.add(
"Visit on this date: routine checkup, weight stable, updated rabies vaccination administered.",
user_id="patient-2214",
topics=["VisitHistory"],
)
The patient profile topic is configured as bounded and user-scoped, matching its semantic, always-current character, fetched directly rather than ranked whenever a vet needs the full current picture before an appointment. The visit history topic is configured as unbounded, matching its episodic character, retrieved through ranked search whenever a specific kind of past visit needs to be found among many:
profile = client.memories.search(
query="patient profile",
user_id="patient-2214",
topics=["PatientProfile"],
retrieval_config=FetchRetrieval(limit=1),
)
past_visits = client.memories.search(
query="Has this patient had any vaccination issues in past visits?",
user_id="patient-2214",
topics=["VisitHistory"],
retrieval_config=HybridRetrieval(limit=10),
)
Each configuration choice, bounded or unbounded, user-scoped or project-wide, fetched or ranked, traces directly back to a conceptual decision made earlier: is this a current state or a distinct occurrence, does it belong to one patient or the whole practice, does retrieval need one canonical answer or a filtered set of relevant ones. Nothing about the configuration is arbitrary once the underlying conceptual category has been correctly identified, which is exactly the payoff of having worked through that taxonomy carefully in the first place.
This Part has built a complete vocabulary for describing what memory is and how it should be configured to match. Knowing what to store is only half the problem an agent actually faces. The other half is deciding, moment to moment, what deserves an actual seat in the model’s limited context window right now, as opposed to staying in storage until it’s specifically needed. Our next chapter, What is context engineering?, opens the next Part by taking up exactly that discipline.