Short answer: Topics are named categories with descriptions, scopes, and bounds that steer what Engram extracts without a new ontology.
Changing topic sets or descriptions changes what the system remembers. Bounded topics keep one memory per scope; unbounded ones accumulate. Topics live inside groups and pipelines: extract by description, transform with bounds, commit tagged memories. Wrong scopes leak tenants; wrong descriptions blur categories. Version topics with the product.
Adaptability needs a dial you can turn without rewriting the agent. In Weaviate Engram, that dial is topics. A topic is a named category inside a group that tells the extraction pipeline what kinds of facts to pull from input and how those facts must be scoped. Change the topic set—or the natural-language descriptions on those topics—and you change what the system remembers, without inventing a new cognitive ontology or a new microservice.
This chapter explains topics as configuration rather than as hard-coded product types, covers bounded versus unbounded topics and scoped search, shows how descriptions steer extraction, and walks a letterpress lockup bench through a small topic set you can evolve. Groups then become the next packaging layer: bundling topics and pipelines by use case.
What problem do topics solve that generic “remember everything” cannot?
After you decide memory must stay configurable, the next failure mode is extraction without intent. If the pipeline treats every utterance as equally memorable, Engram fills with noise: jokes, half-plans, and one-off tool chatter that later hybrid searches resurface at the wrong time. Topics fix that by declaring categories up front. Each topic has a name, a description used in LLM extraction prompts, scoping rules (user_scoped and optional scope_properties), and an is_bounded flag.
Those fields are the configuration layer. They are not a claim that human memory has exactly N faculties. A letterpress assistant might need ink_preferences, stock_constraints, and a bounded job_summary. A coding assistant might need UserKnowledge and tech_stack. Same Engram mechanisms; different topic configs. That is how you avoid prescriptive models while still telling the pipeline what “worth remembering” means for this product.
Topics also sharpen retrieval. Searching with topics: ["ink_preferences"] returns only that category. Omitting topics searches across all topics in the group. Configuration therefore controls both write-side extraction and read-side focus. That dual use is why topics beat prompt-only instructions that the store itself never sees.
How do descriptions and bounds turn config into behavior?
The description is the load-bearing string. Engram’s pipeline uses it to decide how to categorize extracted information. Two topics with vague descriptions collapse into each other. Two topics with precise descriptions—“How this printer prefers ink density and make-ready notes” versus “Paper stocks and sheet sizes this printer refuses or requires”—split a mixed utterance cleanly. When a user says they love dense blacks on cotton stock, the pipeline can route density taste to one topic and stock constraint to another.
Bounded topics (is_bounded: true) hold at most one memory per unique scope. The pipeline derives the memory id deterministically from topic name and scope, so later writes update in place. That shape fits running conversation summaries scoped by user_id plus conversation_id, or a single user profile per user_id. Unbounded topics (the default) mint a new id per memory so preferences and events can accumulate. Choosing bound versus unbound is a configuration decision about cardinality, not a philosophical stance about semantic versus episodic labels. Cardinality mistakes show up as duplicate summaries or as preferences that cannot accumulate.
Scoping is configured per topic. A preference topic can require user_id. A job summary can require user_id and properties.job_id. Getting scope wrong is how tenants leak; getting description wrong is how categories blur. Both belong in the topic definition you version with the product.
Where do topics sit relative to groups and pipelines?
Topics never float alone. They live inside a group, and the group also references the pipeline that extracts, transforms, and commits memories. Most projects start with the default group; templates may seed starter topics such as UserKnowledge. Custom topics are defined in group configuration when you need extraction to match a use case. The conceptual flow is stable: send string, conversation, or pre-extracted content with the scopes the topics require; the group’s pipeline extracts using topic descriptions; transform steps deduplicate and honor bounds; commit stores vector-embedded memories tagged by topic.
That is why topics are the right adaptability lever. You can refine descriptions when support tickets show misfires. You can add a topic when a new question class appears. You can mark a summary topic bounded when duplicates start competing in search. You do not need to redefine “memory” for the whole company. Configuration absorbs the change; Engram’s add/search/get contracts stay intact.
Keep organizational SOPs out of topic greed. Topics configure experiential extraction inside Engram. Certified procedures still belong in a governed Weaviate collection plane with its own write path. Topic greed that tries to absorb policy text turns experiential memory into a shadow handbook.
What does a topic set look like at a letterpress lockup bench?
A shop assistant helps printers at a furniture lockup bench. Early config only tracks ink taste. Later, the same group adds stock constraints and a bounded per-job summary. Scenario id: letterpress-furniture-lockup-bench-6.
from weaviate.engram import EngramClient
from weaviate.engram.retrieval import HybridRetrieval
engram = EngramClient()
user_id = "printer-hada"
group = "default"
scenario = "letterpress-furniture-lockup-bench-6"
# Conceptual topic config (defined on the group at project setup):
# ink_preferences: user_scoped, unbounded
# description: "Ink density, color, and make-ready preferences for this printer"
# stock_constraints: user_scoped, unbounded
# description: "Paper stocks, sheet sizes, and materials this printer requires or refuses"
# job_summary: user_scoped + scope_properties=[job_id], is_bounded=True
# description: "Running summary of the active letterpress job lockup and decisions"
conversation = [
{"role": "user", "content": "Keep the dense black on the cotton 250gsm; skip the slick cover stock for this invite."},
{"role": "assistant", "content": "Understood—I'll note ink density and the stock constraint for job invite-044."},
]
# Store through the group pipeline; topics steer extraction via descriptions
run = engram.memories.add(
content=conversation,
group=group,
scopes={
"user_id": user_id,
"properties": {"job_id": "invite-044", "scenario": scenario},
},
)
# Read-side config: restrict to the category this turn needs
ink_hits = engram.memories.search(
query="make-ready ink density preferences",
group=group,
topics=["ink_preferences"],
retrieval=HybridRetrieval(alpha=0.5, limit=5),
scopes={"user_id": user_id},
)
stock_hits = engram.memories.search(
query="paper stock constraints cotton cover",
group=group,
topics=["stock_constraints"],
retrieval=HybridRetrieval(alpha=0.5, limit=5),
scopes={"user_id": user_id},
)
One utterance produced two configured categories instead of one muddy “user fact.” The bounded job_summary for invite-044 updates in place as the lockup evolves, rather than spawning competing summaries. When the shop later needs a press_speed_notes topic, you extend group configuration and keep the same client calls. That is topics as a configuration layer: extraction policy you can edit, backed by Engram’s real topic, scope, and search controls.
Topics turn “what should we remember” into versioned Engram configuration—names, descriptions, scopes, and bounds—so extraction and retrieval stay adaptable without a prescriptive memory religion. Our next chapter, What are Engram groups for memory use cases?, shows how to package topics and pipelines into groups when one default bundle is no longer enough.