KnowledgeManager,
and a background consolidation pass in
MemoryManager
that distills recent traffic into durable state.

KnowledgeManager
Three steerable operations
The contract (base.py) exposes exactly three natural-language operations, each returning aSteerableToolHandle:
ask— read-only interrogation. “This call must never create, modify or delete knowledge or schema.”update— mutations described as desired end-state: “Do not request how the change should be implemented; describe the desired end-state in natural language.”refactor— schema restructuring across knowledge tables.
start_async_tool_loop) with a
prompt from
prompt_builders.py
(build_ask_prompt / build_update_prompt / build_refactor_prompt) and
a registered tool group: the ask loop gets _tables_overview, _filter,
_search, _reduce (plus join variants for multi-table stores); the
update loop adds _add_rows and the full schema suite (_create_table,
_transform_column, _vectorize_column, _delete_rows, …).
Storage is dynamic tables, not documents
Knowledge is not a fixed title/content/tags store. It’s a dynamic multi-table layout under theKnowledge/ context root — personal at
{base}/Knowledge/{table}, team-shared at Teams/{team_id}/Knowledge/{table}
(the destination parameter, validated by ContextRegistry.write_root).
Tables have typed snake_case columns (ColumnType in
types.py)
and an auto-increment unique key; _add_rows auto-creates missing columns
with inferred types.
Under the hood, KnowledgeManager is a thin domain layer over
DataManager
— every filter, search, join, and reduction delegates to it (see
storage.py,
search.py,
and ops.py).
Semantic search runs through the same
federated machinery
as the skill libraries, with multi-reference queries ranked by summed
cosine distance and embedding columns created on demand
(_vectorize_column → ensure_vector_column). The ask prompt is emphatic
about routing: “For ANY semantic question over free-form text, ALWAYS use
search” — never substring filters.
How it’s reached at answer time
There’s no ConversationManager fast-path for knowledge. A question like “what’s our refund policy?” routes CM →act → the actor calling
execute_function on primitives.knowledge.ask (wired through the
primitives registry).
Document ingestion follows the same actor-orchestrated pattern: parse with
primitives.files.parse, persist extracted facts with
primitives.knowledge.update.
MemoryManager
The 50-event window
MemoryManager
is the offline consolidator — per its contract, “invoked every 50
messages (by default)” (_CHUNK_SIZE = 50). It subscribes to the
EventBus (Message events plus ConversationManager ManagerMethod
events), buffers them in an in-memory window (_recent_messages), and on
overflow runs process_chunk over the rendered transcript under a chunk
lock. It doesn’t query the transcript store — it rides the same event
stream the TranscriptManager publishes while persisting.
Extraction categories
process_chunk runs one unified pass (build_unified_prompt in
prompt_builders.py),
with each category gated by a MemoryConfig flag (env-configurable via
UNITY_MEMORY_* in
settings.py):
| Category | Default | Lands in |
|---|---|---|
| Contact CRUD | off | ContactManager rows |
| Bios | on | Contact.bio |
| Rolling summaries | on | Contact.rolling_summary |
| Response policies | on | Contact.response_policy |
| Domain knowledge | off | KnowledgeManager.update |
| Task commitments | off | TaskScheduler.update |
manager_method event showing the operation happened,
treat it as handled. There is no persistent watermark; idempotency is
in-process (buffer reset + chunk lock) plus prompt-level.
Extension points
- New extraction category — add a
MemoryConfigflag, gate a prompt section inbuild_unified_prompt, expose the env var, and wire it in the CM’s manager setup. The standalone methods (update_contacts,update_knowledge,update_tasks) show the per-category pattern. - Custom knowledge schemas — the update/refactor loops already create
tables and columns on demand;
case_specific_instructionsonask/updateinjects per-call system guidance without forking prompts. - Simulated twins —
SimulatedKnowledgeManagerandSimulatedMemoryManagermirror the contracts for tests, with sandboxes undersandboxes/knowledge_manager/andsandboxes/memory_manager/.
Where the boundaries sit
A routing summary that keeps the four stores straight in code, mirroring the user-facing distinction:| Content | Store | Write path |
|---|---|---|
| Procedural how-to | Guidance | GuidanceManager_add_guidance (actor/storage loops) |
| Executable workflow | Functions/Compositional | FunctionManager_add_functions |
| Facts, reference data | Knowledge/* tables | primitives.knowledge.update |
| People & preferences | Contacts | ContactManager (largely via MemoryManager) |