Memory & Knowledge

Aura's native memory system gives every agent a persistent brain and filing cabinet, so it doesn't start each task from a blank slate. Six pieces work together — hybrid recall, layered distillation, CodeGraph, the Wiki, a concept knowledge graph, and team access control — and all of it runs on Aura's own stack: SQLite + FTS5 with optional embeddings, and no external memory service. It works identically in the desktop app and in a deployed daemon container. Everything is configured and browsable under Settings → Memory.

Embeddings are optional and off by default. With them off, recall degrades gracefully to fast keyword-only search — still useful. Turning them on points Aura at any OpenAI-compatible (or legacy-shape) embeddings endpoint you configure under Settings → Memory; no model ships in the app.

How it fits together

Think of it as one persistent memory with several access paths. Facts about you and your projects accumulate in a single store; recall finds the relevant ones and injects them each turn; distillation keeps that store compact; and three specialized indexes — CodeGraph, the Wiki, and the concept graph — give the agent structured ways to look things up. A visibility tag on every row gates all of it.

PieceWhat it doesHow the agent uses it
1. Hybrid recallFinds the relevant stored factsInjected automatically each turn as ## Recalled Facts
2. Layered distillationRolls raw facts up into summaries and a profileHigher layers flow back through recall
3. CodeGraphSymbol + import index of a projectcodegraph_query tool
4. WikiCurated markdown knowledge pageswiki_search / wiki_read / wiki_write tools
5. Team ACLPrivate / team / global visibility on every rowGates recall and every query
6. Concept graphEntity → relation → entity triplesconcept_query tool + interactive graph view

Hybrid recall — the memory that actually finds things

As you work, the agent stores small facts about you and your projects. At the start of each turn it needs the relevant ones, so it searches two ways at once and blends the results:

  • Keyword (lexical) — an FTS5 index over the fact store, ranked with bm25(). Exact words, like Ctrl+F.
  • Meaning (semantic) — vector cosine over stored embeddings, so semantically related facts surface even without shared words. Only active when embeddings are enabled.

The two candidate lists are fused with Reciprocal Rank Fusion (RRF, k = 60) in core/memory_search.rs::hybrid_recall. Results are project-isolated, ACL-filtered, and bounded by a max-item count plus a character budget. Each turn, core/task_agent.rs runs recall against your message and appends a ## Recalled Facts block to the system prompt (gated on memory_enabled). No tool call is needed — it happens implicitly. Settings has a Test recall box to preview exactly what would surface for a given query.

Embeddings shape. core/embeddings.rs handles both the openai and legacy request shapes and stores little-endian f32 blobs. A background backfill (spawn_embedding_backfill) vectorizes existing facts after you enable embeddings, so recall improves without re-entering anything. With embeddings off, recall is keyword-only.

Layered distillation — tidy the pile of sticky notes

Raw facts pile up and repeat. Distillation periodically rolls them up in three layers so memory stays sharp and compact instead of turning into noise:

LayerContentsProduced by
L1Raw atomic factsCaptured as you work
L2Consolidated summaries (1–5 durable summaries per scope)Rolled up from un-distilled L1 facts
L3A single high-level profile (e.g. "builds Rust backends, prefers minimal UIs, deploys via Docker")Synthesized from L2, one per scope

core/memory_distill.rs runs a background loop (its own thread + runtime, gated on memory_distill_enabled), and you can also trigger it on demand with Distill now (the memory_distill_now command). The L1→L2 step consolidates via core/llm_util.rs using your selected provider — it's skipped on CLI-tool models — then marks the sources distilled = 1. The L2→L3 step writes one profile per scope with a deterministic id, so it overwrites in place. Because higher layers write back into the same fact store, they flow through hybrid recall automatically.

CodeGraph — a map of your codebase

Point CodeGraph at a project folder and Scan. It indexes every function, class, and type, plus each file's imports, so the agent (or the Settings search box) can instantly answer "where is login() defined?" — file and line — without reading the whole tree.

core/codegraph.rs::scan_project walks the tree (skipping node_modules, target, .git, dist, and similar, and capping file size and count), extracting symbols and import edges for Rust, TypeScript/JavaScript, Python, and Go via lightweight heuristics — no full parser. Symbols land in code_symbols (with an FTS index) and import edges in code_edges. Re-scanning replaces that project's index. The agent queries it with the codegraph_query tool, which returns kind name — file:line.

The Wiki — a shared notebook

The Wiki is curated markdown — architecture notes, runbooks, conventions — that gives durable project knowledge a permanent home instead of leaving it buried in old chats. Both you (in Settings) and the agent (via tools) can read, write, search, and edit pages.

core/wiki.rs stores pages in wiki_pages (plus an FTS index). Slugs are unique per project scope, and wiki_write upserts by title. Page content is injection-scanned before it ever reaches the agent, so a malicious note can't smuggle instructions into the prompt. The agent reaches it through three tools — wiki_search (full-text), wiki_read (a full page by title or slug), and wiki_write (create or update).

Concept knowledge graph

Where hybrid recall retrieves facts that are similar to your query, the concept graph captures the relationships between things. An LLM pass extracts subject→relation→object triples from your facts, which become nodes (entities) connected by typed, directed edges. This lets the agent answer "what is related to X" or "how does X connect to Y" — not just "what's similar to X".

Build it from Settings → Memory → Knowledge Graph (it needs some facts plus a cloud model). core/concept_graph.rs runs the triple-extraction pass and writes concept_nodes (entities, with a mentions count) and concept_edges (typed, directed, and weighted). Everything is ACL-scoped like the rest of memory.

Then explore the interactive force-directed view rendered by src/components/KnowledgeGraph.tsx — a canvas graph with no external libraries. Drag to pan, scroll to zoom, drag nodes, and hover to highlight a node's connections; nodes are colored by entity type and sized by mention count. During a task the agent traverses the same graph via the concept_query tool, which returns the relationships an entity participates in.

Team ACL — who can see what

Every fact, wiki page, code symbol, and concept carries a visibility tag, and recall plus every query respects it. This keeps things safe when multiple people or teams share one setup.

VisibilityWho sees it
privateJust you (the local operator)
teamOnly when the row's team_id matches your Active team setting
globalEveryone

core/memory_search.rs::AclFilter builds a parameterless SQL predicate: global and private rows are always visible to the local operator, while team rows appear only when their team_id matches active_team_id (team ids are sanitized before inlining). New writes inherit active_team_id and default_memory_visibility, so once you set your team scope, everything you capture is tagged correctly by default.

Agent tools

Five knowledge tools are available to the agent during any task (defined in tools/memory_tools.rs, dispatched in agent/tool_executor.rs, and advertised in the system prompt's tool surface). Hybrid recall is injected implicitly every turn, so it needs no tool call. See Skills & Agent Tools for the full tool catalog.

ToolPurpose
codegraph_queryFind symbols by name; returns kind name — file:line
wiki_searchFull-text search across wiki pages
wiki_readRead a full page by title or slug
wiki_writeCreate or update a page (upserts by title)
concept_queryTraverse the knowledge graph — the relationships an entity participates in

Settings

All of the following live under Settings → Memory (and mirror to the daemon):

SettingDefaultMeaning
memory_enabledtrueMaster switch for recall injection
memory_recall_max_items8Max facts injected per turn
memory_recall_char_budget2000Character cap on injected memory
memory_embeddings_enabledfalseTurn on the vector half of recall
memory_embeddings_url / _model / _api_key / _formatEmbeddings endpoint (openai or legacy shape)
memory_distill_enabledfalseBackground distillation loop
memory_distill_interval_hours12Distillation cadence
memory_distill_min_facts12Min L1 facts per scope before rollup
active_team_id""Team scope for new writes ("" = personal)
default_memory_visibilityprivateprivate / team / global
codegraph_enabledtrueEnable CodeGraph and its tool
wiki_enabledtrueEnable the Wiki and its tools

Data model & API

All memory lives in the single SQLite database (~/Library/Application Support/aura-workshop/aura-workshop.db on macOS, /data/aura-workshop.db in the daemon image; WAL mode). No separate service, no vector database.

TableHoldsKey columns
memory_factsAtomic facts + distilled summaries/profilescontent, category, confidence, embedding (LE f32 blob), layer (1/2/3), distilled, project_path, team_id, visibility
memory_facts_ftsFTS5 index over factstrigger-maintained; bm25() ranking
code_symbols / code_symbols_ftsCodeGraph symbolsname, kind, file, line, lang, team_id, visibility
code_edgesImport edgesfrom_file, to_target, kind
wiki_pages / wiki_pages_ftsWiki pagestitle, slug, content, tags, team_id, visibility
concept_nodesKnowledge-graph entitiesname, node_type, mentions, team_id, visibility
concept_edgesKnowledge-graph relationshipsfrom_name, to_name, relation, weight, team_id, visibility
pending_memory_reviewsFacts awaiting review before commitsource task + proposed fact

Commands & REST (daemon parity)

Every capability is a Tauri command with a matching REST route, so the desktop app and a headless daemon behave identically. Tauri commands include memory_search, memory_stats, memory_layer_stats, memory_distill_now, codegraph_scan, codegraph_query, codegraph_stats, wiki_list, wiki_get, wiki_upsert, wiki_search, wiki_delete, wiki_stats, plus the concept-graph commands. Each mirrors to REST under /api/memories/*, /api/codegraph/*, /api/wiki/*, and /api/concept-graph/* — see the API Reference.

Where it runs

Startup wiring lives in both the desktop entry point and the headless daemon: apply the embedding config, start the embedding backfill, start the distillation loop, and create the CodeGraph, Wiki, and concept-graph tables. Memory therefore works the same way whether you run the desktop app or a deployed daemon container — see Deployment & Security.

All in one store. There is no external memory service, no separate vector DB, and no cloud dependency for memory itself. The only optional external call is to your configured embeddings endpoint, and only when you turn embeddings on.