Mneme is a local-first graph memory layer for AI agents.
It turns Markdown notes into an inspectable SQLite memory graph: notes become nodes, links/tasks/bullets become evidence-backed edges and observations, and agents can use the graph to generate thought paths, audit why relationships exist, or build prompt-time context packs.
Mneme (Μνήμη) means memory.
Mneme is an alpha public package. The public repository contains the sanitized, reusable core:
- Markdown vault ingestion
- SQLite graph storage
- relationship ontology seeding
- edge evidence + debug/audit logs
- retrieval-backed context and thought surfacing
- thought-path generation and rendered cards
- SVG/PNG thought-card rendering
- privacy-first rebuild defaults and scans
- World-model layer: durable state assertions, deterministic predictions, and an auditable action ledger on top of the graph
- Non-mutating contradiction radar for newly sensed evidence that disagrees with current durable state
- CLI commands for ingestion, retrieval, thought surfacing, scoped graph memory, research resolution writeback, edge explanation, world-model state/prediction/action management, and agent preflight
The private dogfood runtime is also exploring active synapse validation, graph workbench UX, and prompt-time retrieval. Those patterns are documented below as design direction, but only shipped public CLI commands are listed in the CLI section.
The shared public/private graph semantics are documented in GRAPH_CONTRACT.md, including edge/synapse status mapping and promotion rules.
The repo also includes a Hermes-compatible skill bundle at
skills/mneme-agent-brain/. Install or point Hermes at that
directory when an agent should operate Mneme as a working brain. The skill
contains the SKILL.md entrypoint, a detailed operator runbook, and a smoke
helper that delegates to scripts/hermes_brain_ready.sh. Hermes install and
update steps live in
skills/mneme-agent-brain/references/install-update.md
and are summarised in the Hermes install section below.
Hosts that wire Mneme as a pre-LLM hook should use the repo-managed hook at
scripts/mneme_senses_context_hook.py
and install/check it with:
python scripts/sync_hermes_hook.py
python scripts/sync_hermes_hook.py --checkThe hook follows the compact injection pattern documented at
skills/mneme/references/hook-directive-order.md:
do not inject large MNEME RETRIEVAL PATH / MNEME BOTH PATH protocol blocks
or long PRIMARY DIRECTIVE banners into every prompt. Use a short reminder that
points agents to preflight/world state/watch, and strip leaked hook markers before
classifying user text. The public test suite (tests/test_hook_directive_order.py)
covers the invariant and executes the real repo-managed hook.
- Ingests Markdown notes from a vault/folder.
- Extracts notes, wikilinks, headings, tasks, dates, email-like strings, and high-signal observations.
- Stores nodes, edges, observations, generated thoughts, relationship types, and edge debug logs in SQLite.
- Distinguishes reference/structural edges from semantic claims through a seeded relationship ontology.
- Records why an edge exists: source path, evidence text, confidence, extraction rule, and later validation/audit events.
- Performs biased graph walks over unresolved, risky, recent, or connected items.
- Renders compact thought cards as SVG, with optional PNG conversion via ImageMagick.
- Provides a CLI suitable for cron jobs, local agent runtimes, and private graph workbenches.
Mneme treats memory as an auditable graph:
Markdown notes
-> nodes / observations / evidence-backed edges
-> SQLite graph + audit log
-> graph walks, explanations, workbench APIs, or prompt context
A line between two nodes is not automatically a fact. Mneme separates:
- Reference edges — e.g.
links_to, created from explicit Markdown wikilinks. Useful for navigation, but not proof of a real-world relationship. - Extraction edges — e.g.
mentions_date,mentions_email, created from text patterns. - Observation edges — e.g.
has_fact,has_risk,has_blocked, created from scored bullets/tasks. - Semantic relationships — e.g.
belongs_to,located_in,part_of,father_of. These are marked as requiring validation before an agent treats them as real-world claims.
This keeps the graph useful without letting weak co-occurrence or casual links become hallucinated truth.
The new world model is a small durable layer above the rebuildable graph. The graph remains Mneme's perception/index: it can be rebuilt from Markdown and senses. The world model stores state that should survive graph churn:
- State:
world_state_assertionsrecords current, source-backed beliefs such as “Person X belongs to Organisation Y”. Assertions reuse the same validation contract as active research edges, so low-confidence observations do not become durable facts. - Prediction:
world_predictionsrecords future expectations in structured JSON. Checks are deterministic against storedsense_eventsand observations — no LLM judgement. - Action:
world_actionsis a ledger table for external side effects. The public helper enforces that side-effectful records carry a provider handle (external_refortool_call_id) before they can be stored.
The point is not to replace the graph. It is to let agents ask: “What do I currently believe?”, “What did I expect to happen?”, and “Did new evidence confirm or miss that expectation?” See docs/world-model-v1.md for the design notes.
The contradiction radar enforces a related principle: suppression applies to
recall, not perception. Current state remains authoritative until new evidence
passes the assertion gate, but disagreeing active or candidate graph evidence is
returned in preflight/world-tick contradiction and attention reports. Historical
edges already represented by superseded, contradicted, or killed assertions are
excluded so old state changes do not become permanent alert noise.
Edge comparison is opt-in for single-valued assertions via
metadata.conflict_policy: "exclusive" (or metadata.cardinality: "one"), so
multi-valued predicates such as purchases or memberships do not create false alarms.
When Mneme surfaces a thought, the CLI renders a self-contained SVG/PNG
card so the human can see at a glance what was found, why, and what to
do next. The example below is a fictional demo (the [Persona] token
and the mneme://thoughts/demo-open-loop URI make this unmistakable).
A real card would carry your actual node names and source paths.
A card carries:
- Header — wordmark, classification badge (
Open loop/Deadline/Surface match/Reasoned walk), score chip. - Path — the multi-hop graph walk that surfaced, with the relation
(e.g.
blocks,mentions,raises,references) shown as a chip between each pair of nodes. Paths longer than 12 nodes get a+N moreoverflow chip. - Evidence — the thought's source-backed snippets and observations,
deduped, capped at 5 lines with a
+N more in JSON outputmarker when truncated. Hidden entirely when no observations exist. - Reasoning — the insight, with a distinct purple/violet tint so it reads as a third colored band.
- Next — a concrete next step in an amber tint.
- Footer —
Why now:explanation,src:URI,matched:terms, and the generated timestamp.
Theme can be dark (default) or light, selectable via the
MNEME_CARD_THEME env var or the theme= kwarg on render_card.
Mneme is local-first:
- No network calls in the public core
- No telemetry
- No required LLM dependency
- No cloud database
- SQLite stays wherever you put it
Important: generated SQLite databases, JSON output, SVG/PNG cards, and logs can contain snippets from your notes. Do not commit generated databases, private cards, logs, or real vault content to public repositories.
Privacy-focused defaults:
ingestandrun-oncerebuild graph tables by default, so stale private nodes/edges are removed when a DB is reused.- Symlinked Markdown files are skipped by default to avoid reading files outside the vault.
- Generated cards named
thought_*.svg/thought_*.pngand SQLite files are blocked by the included privacy scan. - Public examples are intentionally small and fictional.
Mneme stores meaningful memory state in SQLite, so backup is part of the workflow, not an afterthought.
Public Mneme remains local-first and does not make cloud calls by default. For any private deployment that runs scheduled thought cards, validation, migrations, or rebuilds:
- Take a SQLite-consistent snapshot before risky work. Use SQLite's backup API or
.backup; do not rely on copying a live SQLite file as the only backup. - Include a manifest with integrity data: creation time, source DB path, checksums, and counts such as edges/synapses by status.
- Compress and encrypt the backup before it leaves the machine.
- Verify decryptability and
PRAGMA integrity_checkbefore considering the backup valid. - Keep local encrypted backups and a restore script that makes a safety copy before replacing the live DB.
- If the user wants Google Drive backup, use Google Workspace/Drive tooling such as
gws drive +uploadfirst. Use rclone or other remotes only as fallback. - Never print, commit, or send the backup passphrase. If the encrypted backup is stored off-box, the passphrase must be stored separately somewhere safe or cloud restore will be impossible after machine loss.
A private deployment can schedule this as: snapshot -> manifest/checksum -> encrypt -> verify -> upload to Drive -> periodically test restore verification.
One-command install/update on Linux/macOS:
curl -fsSL https://raw.githubusercontent.com/georgeantonopoulos/mneme/main/scripts/install.sh | bashManual install from a checkout:
git clone <this-repository-url>
cd mneme
python -m pip install -e .Requirements:
- Python 3.10+
- Optional: ImageMagick (
convertormagick) for PNG output. Without it, Mneme writes SVG cards.
The installer creates/updates the mneme CLI. After installation, check the Markdown editor commands with:
mneme note --helpThe package includes the graph memory engine and a small path-safe Markdown editor; there is no separate editor plugin to install.
Hermes needs two things from Mneme:
- The
mnemeCLI onPATH(installed by the standard install above). - The
skills/mneme-agent-brain/skill directory reachable from the active Hermes profile (for example~/.hermes/skills/mneme-agent-brain/).
The fast path:
# 1. Install or update the CLI
curl -fsSL https://raw.githubusercontent.com/georgeantonopoulos/mneme/main/scripts/install.sh | bash
# 2. Wire the skill into the active Hermes profile
mkdir -p ~/.hermes/skills
ln -sfn ~/.local/share/mneme/skills/mneme-agent-brain ~/.hermes/skills/mneme-agent-brain
# 3. Smoke-test the wiring. The helper runs the full brain harness,
# including contract check, world tick dry-run, retrieval, surface,
# and agent preflight.
MNEME_BRAIN_DEPTH=smoke ~/.local/share/mneme/scripts/hermes_brain_ready.sh /tmp/mneme_smoke.sqliteIf your Hermes profile lives somewhere other than ~/.hermes, set
HERMES_HOME to that directory before step 2 and substitute the
profile's skills/ path in the symlink.
Manual checkout (for hermes profiles that need the repo on disk):
git clone https://github.com/georgeantonopoulos/mneme.git ~/.local/share/mneme
python -m pip install -e ~/.local/share/mneme
ln -sfn ~/.local/share/mneme/skills/mneme-agent-brain ~/.hermes/skills/mneme-agent-brainThe full operator runbook (env-var overrides, profile isolation, brain
harness depths) lives at
skills/mneme-agent-brain/references/install-update.md.
The Mneme skill is intentionally vault-agnostic: it never assumes a particular
folder layout, private database path, or user's notes. Hermes operators provide
$DB, $VAULT, and $PROMPT; the skill describes the portable state/action/
prediction loop that any Mneme-backed agent can run.
Before Hermes uses Mneme context in an answer or action, run preflight:
mneme agent preflight --db "$DB" --prompt "$PROMPT"
# Reproduce validity decisions at a specific instant:
mneme agent preflight --db "$DB" --prompt "$PROMPT" --as-of 2026-07-03T09:00:00ZFor tasks that depend on current state or expected future evidence, inspect the world model first:
mneme state list --db "$DB" --status current
mneme state conflicts --db "$DB"
mneme state explain ASSERTION_ID --db "$DB"
NOW=$(python3 -c 'from datetime import datetime, timezone; print(datetime.now(timezone.utc).isoformat())')
mneme predict due --db "$DB" --before "$NOW"
mneme world watch --db "$DB" --lead 1d
mneme world tick --db "$DB" --before "$NOW" --dry-runUse world watch as a read-only radar for open predictions that are due soon
but have no matching evidence yet. Use world tick --dry-run during interactive
operation so the agent can see lapsed open loops, due predictions, pre-failure
watch items, contract status, and attention items without changing prediction
state. Run mutating world tick from explicit maintenance jobs when you want
open predictions to become confirmed, missed, or unverifiable.
Retrieval and preflight evaluate valid_until at read time. A stored current
assertion whose validity has elapsed is returned as lapsed_state_assertion
and loses current-state ranking authority without mutating its durable row.
Use --as-of on retrieve or agent preflight for deterministic replay.
Predictions may include a structured match_json.gate when success must occur
before a sensed event rather than only before a fixed timestamp:
{
"sense_type": "gws",
"observation_terms_all": ["boarding", "confirmation"],
"gate": {
"sense_type": "gws",
"event_type": "calendar_event",
"title_terms_all": ["paris", "flight"],
"time_field": "metadata.gws.start"
}
}The earliest matching gate becomes the effective deadline. Evidence after it
cannot confirm the prediction, watches stop when it passes, and an unresolved
gate becomes unverifiable at the configured expiry. Gate resolution uses only
stored sense evidence and supports observed_at or a nested metadata.* field.
When a source-backed resolution creates a future expectation, write it into the
same payload with predictions[]; for standalone expectations use
mneme predict add --file prediction.json. When an integration records a real
side effect, it should call the action-recording helper with an external
provider reference or tool-call ID so world_actions becomes an auditable action
ledger rather than chat history archaeology. Add an optional verify block with
an explicit sense_type when that side effect should spawn a deterministic
verification prediction.
mneme action record --db "$DB" --file action.jsonSide-effectful actions must include external_ref or tool_call_id; otherwise
the contract rejects the record.
Canonicalize fragmented subject names with aliases. alias add affects future
writes; alias merge also rewrites existing world-state assertions and
recomputes current/superseded pointers.
mneme alias add "the landlord" "St James" --db "$DB"
mneme alias merge "the landlord" "St James" --db "$DB" --dry-run
mneme alias ls --db "$DB"Use the scored retrieval eval whenever retrieval/world-model scoring changes:
mneme eval retrieval --demo --min-score 0.9If the Hermes deployment uses a pre-LLM hook that injects a Mneme
path (retrieval, correction, or both) into the agent's system
prompt, install the repo-managed hook and check drift:
python scripts/sync_hermes_hook.py
python scripts/sync_hermes_hook.py --checkThe hook MUST keep compact reminders ahead of any Mneme operational detail and
strip leaked hook markers before classifying user text. Hermes hosts that inject
large manuals or omit the compact ordering have been observed to lose the user's
request to a Mneme writeback loop and stop responding. The public test
tests/test_hook_directive_order.py pins the invariant and executes the real
repo-managed hook; run it after any hook changes:
python -m pytest tests/test_hook_directive_order.py -vConfigure Mneme once, validate it, then use short commands:
mneme init --vault ./examples/vault --db /tmp/mneme.sqlite --out /tmp/mneme_out
mneme doctor
mneme update
mneme candidates
mneme promote-candidates --dry-run
mneme retrieve --prompt "what should the agent remember here?"
mneme surface --prompt "what should surface now?"
mneme thoughtResearch results can be written back as evidence packs plus weighted graph edges:
mneme resolve --file research-resolution.jsonWorld-model predictions can be added and checked deterministically:
mneme state list --db /tmp/mneme.sqlite --subject "school"
mneme state explain ASSERTION_ID --db /tmp/mneme.sqlite
mneme predict add --db /tmp/mneme.sqlite --file prediction.json
mneme predict due --db /tmp/mneme.sqlite --before 2026-07-02T12:00:00+00:00
mneme world tick --db /tmp/mneme.sqlite --before 2026-07-02T12:00:00+00:00 --dry-runYou can keep multiple configs if needed:
mneme --config /tmp/project-mneme.json init --vault ./examples/vault --db /tmp/project.sqlite --out /tmp/project_out
mneme --config /tmp/project-mneme.json run-onceOr run one-off commands with explicit paths:
mneme run-once --vault ./examples/vault --db /tmp/mneme.sqlite --out /tmp/mneme_outThe command prints JSON with the generated title, thought path, and image path. Agent runtimes can use that image as a proactive visual memory nudge.
mneme init --vault ./examples/vault --db /tmp/mneme.sqlite --out /tmp/mneme_out
mneme doctorDefault config path is ~/.config/mneme/config.json. Pass --config /path/to/config.json before the subcommand to use another config. Once configured, ingest, update, retrieve, surface, thought, run-once, and write can read missing --vault, --db, or --out values from config when that command needs them.
mneme ingest --vault ./examples/vault --db /tmp/mneme.sqliteBy default this rebuilds graph tables to avoid stale data and keeps deterministic navigation/extraction edges as candidate rather than making every parsed link active. Source-contained observation edges can be active; durable validated active edges and killed tombstones are preserved across rebuilds.
If you want to refresh the graph while preserving generated thought history, use update:
mneme update --vault ./examples/vault --db /tmp/mneme.sqliteIf you explicitly want append-only behaviour:
mneme ingest --vault ./examples/vault --db /tmp/mneme.sqlite --appendMneme is selective by default: parsed links/headings/dates/emails remain candidates until review or validation. To inspect candidate paths:
mneme candidates --db /tmp/mneme.sqliteTo opt into bulk activation, run a dry run first. The default mode only promotes validated research candidates; --mode all is intentionally explicit because it can make the graph noisy.
mneme promote-candidates --db /tmp/mneme.sqlite --dry-run
mneme promote-candidates --db /tmp/mneme.sqlite --mode validated-only
# explicit noisy option:
mneme promote-candidates --db /tmp/mneme.sqlite --mode allMneme ships with a small path-safe Markdown editor for agents and scripts. It is part of the installed mneme CLI, returns JSON, uses vault-relative .md paths only, writes atomically, creates backups for changed existing notes, and supports dry-run diffs.
mneme note read Projects/new-note.md --vault ./examples/vault
mneme note write Projects/new-note.md --vault ./examples/vault --mode create --content '# New note
'
mneme note replace Projects/new-note.md --vault ./examples/vault --find 'New note' --replace 'Updated note' --dry-run
mneme note upsert-section Projects/new-note.md --vault ./examples/vault --heading Status --content 'Ready for review'
mneme note add-bullet Projects/new-note.md --vault ./examples/vault --heading Tasks --bullet 'Follow up'Use mneme note upsert-section for section-level updates instead of fragile multiline find/replace. Use mneme note add-bullet for deduped bullets under a heading. These commands are intentionally small: exact replace, section upsert, bullet insertion, read, and write — not a full Markdown platform.
The older top-level mneme write command remains as a simple compatibility shortcut:
mneme write --vault ./examples/vault --path Projects/new-note.md --mode create --content '# New note
'
printf -- '- Follow up\n' | mneme write --vault ./examples/vault --path Projects/new-note.md --mode appendmneme note and mneme write only accept relative .md paths that resolve inside the vault. Modes are create, append, and overwrite.
For development:
python -m pip install -e '.[dev]'
python -m pytest -qWhen an agent finishes source-backed research, pass a JSON resolution payload to mneme resolve. Mneme writes a durable Markdown evidence pack under Sources/ and creates weighted graph edges.
mneme resolve --vault ./examples/vault --db /tmp/mneme.sqlite --file research-resolution.jsonMinimal payload:
{
"slug": "school-clubs",
"title": "School clubs resolved",
"date": "2026-04-26",
"sources_checked": ["email", "payment", "calendar", "vault"],
"claims": [
{
"subject": "Example Child",
"subject_type": "person",
"predicate": "attends_activity",
"object": "Handwriting Club",
"object_type": "activity",
"confidence": 0.94,
"strength": 0.93,
"certainty": "confirmed",
"source_type": "payment",
"evidence": "Payment receipt and school brochure confirm the club timing."
}
],
"unresolved": ["Morning club paid but child assignment is unclear."]
}Safety rule: only sourced, confirmed/certain claims at or above --active-threshold (0.90 by default) become active edges. Pending, unsupported, or lower-confidence claims become candidate edges. Candidate edges are stored for audit and follow-up, but graph walks/thoughts ignore them so unresolved claims do not become proactive “truth.”
The command accepts JSON via --file or stdin, which keeps the interface simple for future Node/npm wrappers.
The world-model commands are opt-in and local. They create/use three tables in the same SQLite database:
| Table | Purpose | v1 producer |
|---|---|---|
world_state_assertions |
Durable current beliefs that survive graph rebuilds | mneme resolve / remember_graph assertions when claim validation passes |
world_predictions |
Machine-checkable expectations about future sensed evidence | mneme predict add |
world_actions |
External-action ledger with side-effect handle enforcement | record_action() helper; higher-level producers can call it later |
A minimal prediction file looks like this:
{
"id": "example-school-confirmation",
"title": "School confirmation should arrive",
"prediction_type": "confirmation_expected",
"match_json": {
"sense_type": "md",
"observation_terms_all": ["school", "confirmation"]
},
"check_after": "2026-07-01T00:00:00+00:00",
"expires_at": "2026-07-03T00:00:00+00:00",
"confidence": 0.8
}Commands:
# current durable beliefs
mneme state list --db /tmp/mneme.sqlite --status current
mneme state explain ASSERTION_ID --db /tmp/mneme.sqlite
mneme state backfill --db /tmp/mneme.sqlite --dry-run
# deterministic expectations
mneme predict add --db /tmp/mneme.sqlite --file prediction.json
mneme predict due --db /tmp/mneme.sqlite --before 2026-07-02T12:00:00+00:00
mneme predict check --db /tmp/mneme.sqlite --id example-school-confirmation --dry-run
mneme world watch --db /tmp/mneme.sqlite --lead 1d
mneme world tick --db /tmp/mneme.sqlite --before 2026-07-02T12:00:00+00:00 --dry-run
# canonical world-state subjects
mneme alias add "the landlord" "St James" --db /tmp/mneme.sqlite
mneme alias merge "the landlord" "St James" --db /tmp/mneme.sqlite --dry-run
mneme alias ls --db /tmp/mneme.sqlite
# retrieval scoring regression guard
mneme eval retrieval --demo --min-score 0.9mneme world tick runs the normal graph tick first, checks due predictions, reports lapsed open-loop assertions, runs the DB contract checks, and returns an attention list. Use --dry-run to evaluate prediction transitions without committing them:
{
"ok": true,
"graph": {"candidates_updated": 4, "observations_considered": 5},
"predictions": {"ok": true, "due": 1, "checked": 1, "results": []}
}Safety rules:
- Default rebuild/update paths preserve world-model rows.
- Only explicit scoped
mneme://...forgets cascade into world-model rows. predict dueis read/list behavior and does not create world-model tables on a graph-only DB.predict checkis intentionally mutating unless--dry-runis passed because it records prediction outcome/status.- Prediction IDs are content-hash deterministic when the payload omits
id, so replayedresolvepayloads do not duplicate expectations. - A missed prediction linked to
subject_assertion_idweakens that assertion's confidence once, using the fixed v1 factor. - Retrieval/preflight can include world-model rows with explicit
truth_policyvalues such ascurrent_state_assertion,open_prediction, andmissed_prediction. - Prediction matching is structured/deterministic over stored
sense_eventsand observations.
mneme thought now uses the proactive scorer by default: it ranks high-signal observations, open loops, deadlines, hint matches, important note types, and recently-surfaced penalties before rendering a card.
Inspect candidates before generating:
mneme candidates --db /tmp/mneme.sqlite --limit 5Explain scored and suppressed candidates:
mneme debug-candidates --db /tmp/mneme.sqlite --include-skippedGenerate the top thought card:
mneme thought --db /tmp/mneme.sqlite --out /tmp/mneme_outBuild a deterministic local context pack for an agent prompt:
mneme retrieve --db /tmp/mneme.sqlite --prompt "What needs follow-up for the supplier?" --budget 2500 --max-items 8retrieve uses the same scoring core as candidates and thought. It returns
source-backed observations, relevant edges, score factors, freshness/source
quality notes, skipped-item reasons, and a truth_policy for every edge. Killed
edges are excluded. Candidate semantic edges may be shown as candidate_only,
but they are not phrased as facts.
Use surface when an agent wants thought cards from the same cluster-aware,
brain-labelled retrieval path instead of a random walk:
mneme surface --db /tmp/mneme.sqlite --prompt "what should I remember about supplier launch readiness?" --limit 5Each surfaced thought keeps the generated title, insight, action, and
graph path, plus a surface block with the retrieval item, matched terms,
cluster, brain label, and truth policy that caused it to appear. The response
also includes suggested_actions. For example, a source-contained observation
may suggest appending a bullet under Next Actions; a candidate synapse may
suggest explicit validation or deletion before it is trusted.
Agents can add working memory to the graph without editing Markdown notes by
using a mneme:// source namespace:
mneme remember add --db /tmp/mneme.sqlite --file /tmp/agent-memory.json
mneme surface --db /tmp/mneme.sqlite --prompt "temporary validation memory"
mneme remember remove --db /tmp/mneme.sqlite --source-path mneme://test/validationPayloads may contain nodes, edges, and observations. Edges and
observations must reference nodes from the same payload, which keeps temporary
memory removable as a unit:
{
"source_path": "mneme://test/validation",
"nodes": [
{"ref": "agent", "type": "agent", "name": "Test agent"},
{"ref": "task", "type": "task", "name": "Validate retrieval"}
],
"edges": [
{"src": "agent", "dst": "task", "relation": "relates_to", "status": "active"}
],
"observations": [
{"node": "task", "kind": "fact", "text": "Validate retrieval before trusting output.", "score": 5}
]
}remember remove only accepts mneme:// sources. That keeps vault-ingested
notes and user-authored Markdown outside the deletion path.
The working-brain pipeline keeps graph structure deterministic and runs model labelling as a replaceable harness step. A local Ollama model is useful for dogfooding, while Hermes can pass its own command through the same interface.
mneme consolidate \
--db /tmp/mneme.sqlite \
--label-provider ollama \
--label-model gemma4:e4b \
--label-max-clusters 25
mneme brain label \
--db /tmp/mneme.sqlite \
--targets cluster,node,synapse,relationship \
--max-clusters 25 \
--max-nodes 50 \
--max-synapses 50 \
--max-relationships 25 \
--label-provider ollama \
--label-model gemma4:e4b
mneme brain report --db /tmp/mneme.sqlite
mneme retrieve --db /tmp/mneme.sqlite --prompt "what should the agent remember here?"Hermes can swap the model runner without changing Mneme's graph logic:
mneme brain label \
--db /tmp/mneme.sqlite \
--targets cluster,node,synapse,relationship \
--label-provider hermes \
--label-command "hermes label --json"For a single smoke script:
MNEME_LABEL_PROVIDER=ollama MNEME_LABEL_MODEL=gemma4:e4b \
scripts/hermes_brain_ready.sh /tmp/mneme.sqlite "retrieval prompt"The script runs the full harness path Hermes needs before trusting the DB:
consolidate, brain label, brain report, retrieve, and surface. Set
MNEME_SURFACE_LIMIT to change how many retrieval-backed thoughts the final
surface check returns.
Set MNEME_BRAIN_DEPTH when the agent needs a different pass size:
MNEME_BRAIN_DEPTH=smoke scripts/hermes_brain_ready.sh /tmp/mneme.sqlite
MNEME_BRAIN_DEPTH=default scripts/hermes_brain_ready.sh /tmp/mneme.sqlite
MNEME_BRAIN_DEPTH=deep scripts/hermes_brain_ready.sh /tmp/mneme.sqlite
MNEME_BRAIN_DEPTH=full scripts/hermes_brain_ready.sh /tmp/mneme.sqlitesmoke labels a tiny proof set, default labels the largest clusters plus top
nodes and synapses, deep labels every discovered cluster plus a broader active
frontier, and full attempts to label every eligible target. Individual
MNEME_LABEL_MAX_* values still override the preset. mneme brain report
returns per-target coverage so Hermes can tell whether the latest brain is
shallow, moderate, or deep before trusting retrieval.
retrieve includes clusters and brain_labels in its JSON response, and
returned items may include cluster and brain_label metadata showing why a
node or synapse entered the context pack.
mneme run-once --vault ./examples/vault --db /tmp/mneme.sqlite --out /tmp/mneme_outUseful flags:
--hints deadline,lease,tax— bias observation scoring and walks toward certain words--hops 5— number of graph hops in a thought path--max-notes 100— limit ingestion for a quick smoke test--append— keep existing nodes/edges instead of rebuilding; use carefully because stale data can remain--follow-symlinks— follow symlinked Markdown files that resolve inside the vault
mneme explain-edge <edge-id> --db /tmp/mneme.sqliteThis prints:
- the edge and its source/destination nodes
- evidence text and source path
- relationship type metadata
- whether the relationship type requires validation
- debug/audit timeline entries
Example use case: a graph workbench can show why two nodes are connected instead of merely drawing a line.
Mneme seeds a small relationship ontology in SQLite. Current categories include:
| Category | Examples | Meaning |
|---|---|---|
reference |
links_to, linked_from |
Navigational Markdown references. Useful, but not proof of a semantic claim. |
structure |
has_heading |
Document structure extracted from Markdown. |
extraction |
mentions_date, mentions_email |
Pattern-extracted facts from text. |
observation |
has_fact, has_risk, has_blocked, has_done |
Scored bullets/tasks that may be useful to an agent. |
semantic |
belongs_to, located_in, part_of, father_of, attends_activity |
Real-world claims; should be validated before being treated as facts. |
semantic_pending |
requested_activity |
Pending/requested real-world claims; useful for follow-up, not resolved truth. |
Unknown relationship types default to validation-required.
Every created edge can carry a debug entry explaining its origin. For example, an edge generated from [[Beta]] stores that it came from an explicit Markdown wikilink, not from semantic reasoning.
Agents and UIs should use this audit trail to answer:
- Why does this edge exist?
- Which source text created it?
- Is it a navigational reference or a semantic claim?
- Was it later validated, rejected, or superseded?
The public package currently logs creation events. Private deployments can extend the same table with validation, rejection, or lifecycle events.
Mneme's graph-building layer is intentionally location-agnostic: callers pass --vault, --db, and --out. A workbench should preserve that model rather than hard-coding deployment paths.
Recommended public packaging shape:
mneme ingest --vault /path/to/markdown --db /path/to/mneme.sqlite
mneme retrieve --db /path/to/mneme.sqlite --prompt "what should the agent remember here?"The prompt-time retrieval layer is available through the public mneme retrieve
CLI command. A future served workbench should be optional, read-only by default,
and configurable for:
- graph DB path
- host/port
- URL mount path
- auth/reverse-proxy layer
- output/static asset directory
- node/link limits
For large graphs, workbench implementations should:
- auto-frame from actual node bounds
- support pointer events: drag, pan, pinch-zoom, and double-tap/frame on mobile
- merge aliases/path entities/display-title notes into canonical nodes before rendering
- cull offscreen nodes/links
- cap physics simulation work
- display relationship type, evidence, source path, and audit status in the details panel
Mneme's long-term role is not just thought cards. It should also act as a fast context selector for agents:
user prompt
-> local Mneme retrieval over active/high-confidence graph context
-> compact evidence pack
-> model response grounded in source-backed memory
Recommended retrieval scoring direction:
- active semantic relationships
- strong active provenance/reference relationships
- high
strength × confidence - trusted source type
- freshness / cooldown / reinforcement age
- exact entity and lexical match
- observation fallback
- candidate or weak co-occurrence edges last
Killed/rejected edges should be excluded, and stale/low-strength/noisy observations should be demoted even when they lexically match the prompt.
This prompt-time retrieval layer is available through the public mneme retrieve CLI command.
- Markdown notes become graph nodes.
- Wikilinks, headings, tasks, dates, and email-like strings become connected nodes/edges.
- Each edge is classified through the seeded relationship ontology.
- Each edge gets a debug-log entry with source path, evidence text, confidence, and creation rationale.
- High-signal bullets and tasks become observations.
- Mneme chooses a biased seed node, walks nearby relationships, and creates a short thought.
- The renderer writes a card to the output directory.
This prototype is intentionally conservative: it does not claim a relationship is true just because two things co-occur. Treat thought cards as prompts for review unless the edge audit trail and relationship type support stronger claims.
python -m pytest -q
python scripts/privacy_scan.py
mneme run-once --vault ./examples/vault --db /tmp/mneme_smoke.sqlite --out /tmp/mneme_smoke_outThe privacy scan fails on common generated artifacts, private paths, emails, secret-like assignments, private-key blocks, and common token prefixes. Projects can add custom forbidden terms without storing them in the repo:
MNEME_FORBIDDEN_TERMS="private-project-name,internal-domain" python scripts/privacy_scan.pyBefore committing, also check for generated/private files:
find . -path ./.git -prune -o -name '*.sqlite*' -o -name 'thought_*.svg' -o -name 'thought_*.png' -o -name '*.pyc' -o -name '__pycache__' -printNear-term:
- configurable ontology files
- graph workbench API/server
- active/candidate/killed edge lifecycle helpers
- world-model action ledger producers (calendar, tasks, email, cron)
- semantic/latent embedding layer for fuzzy recall over claims and state
Longer-term:
- richer render themes
- agent framework adapters
- optional graph-native projection while keeping SQLite as the local audit ledger
- cross-vault world-model federation
