← Reports

PKA Memory System — Interactive Explainer

One shared memory channel across every machine and AI tool  ·  updated 2026-06-05
The big idea in one sentence.

There is one shared folder — PKA/Vault/memory/ — that all of Elmar's AI tools read from and write to. Markdown files are the real record (no lock-in, travels via git). The database is just a rebuildable search index on top. What one tool learns, every other tool can find.

What you are looking at

Use the tabs above to explore each part. The Pipeline tab shows the flow from conversation to shared memory. Architecture is a clickable system map. Personas explains who owns what on which machine. Tools shows which tools are wired up. Trust covers how memories gain or lose authority. Standard is the technical contract every tool follows. Playbook is the step-by-step guide for adding a new tool.

The shared channel

Every AI tool (Claude Code, Codex, Hermes, and future ones) publishes durable learnings into Vault/memory/. Git keeps it in sync across machines. No memory gets stranded on one tool or one machine.

Markdown = the real record

The database (vault.db) is rebuilt from the markdown on each machine. You can delete it and rebuild any time. The markdown files in git are what actually matter — no vendor lock-in.

Live now
Claude Code, Codex, Hermes, Kimi, and agy all feeding the shared channel. Five feeds wired by 2026-06-05.

To wire
Luci/Iris (Hetzner — resolver ready), Miki (Mac mini), Windows XPS.

The contract
Interoperability standard lives at docs/standards/pka-agent-memory.md.

Current state: shared store live · Claude Code + Codex + Hermes/Iris proven · persona resolution hardened (Safair-wifi bug fixed 2026-06-05) · secret gate active.

How it flows — the pipeline

Every conversation you have with an AI tool can result in a shared memory note. Here is the path from chat to the shared folder.

Claude Code sessions / transcripts Codex ~/.codex/sessions Hermes / Iris self-publishes directly Kimi / agy live self-publish path Librarian (extractor) session-memory-extractor.py every 4 hours · Sonnet judge durable? Vault/memory/ auto/<persona>/*.md git-tracked · all tools read it

The librarian

The extractor script reads recent conversation transcripts from each tool. It sends them to Claude Sonnet at medium effort. Sonnet decides what is durable enough to keep — a preference, a correction, a decision, a useful fact. Anything that passes gets written as a short markdown note into the shared folder.

What "durable" means

Not chit-chat. Not one-off instructions. Things worth remembering across sessions: a preference Elmar stated, a path that got corrected, a decision that was made and why, a pattern that keeps recurring. The Sonnet judge is deliberately strict — noisy extraction is worse than none.

The two background jobs

JobScriptScheduleWhat it does
Session extractor session-memory-extractor.py Every 4 hours, both machines Reads transcripts → Sonnet judge → writes markdown notes into auto/<persona>/. Dedup ledger prevents re-extraction. 5-minute guard skips still-writing transcripts.
Dream cycle dream-cycle.py Nightly 01:15 Ranks auto-memories by how often they get recalled. Drafts summaries for the best ones into _pending_promotion/. Elmar promotes the good ones manually. Currently idle — needs a salience log to accumulate first.
Git sync autopush hooks Mac on commit, Luci hourly Pushes markdown to GitHub. Luci pulls hourly. Memory written on the Mac is searchable on Luci within the hour.
Notes born this way start life as unverified — a hypothesis, not a fact. See the Trust tab for how memories gain authority over time.

System map — click any box

Lucienne (Mac) Luci (Hetzner) GitHub (sync hub) Other AI tools
GitHub · conrelma/PKA single source of truth (git) push/pull hourly pull Lucienne — Mac ~/PKA · Claude Code Luci — Hetzner ~/workspace/PKA Miki — Mac mini coordinator · to set up built-in memory path → SYMLINK → shared store self-healing guard every session boot PKA/Vault/memory/ — the shared store curated tier + auto/lucienne + auto/luci + auto/iris · git-tracked Hermes · Codex · Kimi · agy run inside ~/PKA → read it vault.db (search index) per-machine · gitignored · rebuildable

Click a box

Each part of the system explains itself. Start with the shared store (green, middle) — that is the heart of it.

Personas by machine

Memory belongs to a persona, not a tool. The persona is generally decided by the machine — with one exception: Hetzner hosts two personas (luci and iris) on the same box, disambiguated by the Hermes profile or the PKA_PERSONA signal. Conceptually, each machine maps to an allowed set of personas plus a default; most machines have a 1:1 set, Hetzner has a 1:2 set.

MachinePersona(s)RoleMemory folder
Elmar's MacBook / work laptoplucienneChief of Staffauto/lucienne/
Mac mini (always-on companion) ⚠ not yet set upmikiCoordinator / reconcilerauto/miki/
Hetzner (openclaw) — Claude Code / CodexluciProject Managerauto/luci/
Hetzner (openclaw) — Hermes profileirisSecond persona on Hetznerauto/iris/
The 3 Hermes profiles Elmar currently talks to: Lucienne (MacBook), Luci (Hetzner), Iris (Hetzner). The persona is the identity, not the tool or the machine. Iris and Luci share the same Hetzner box but are separate personas with separate memory folders.
Never create a tool-named folder like auto/codex/ or auto/hermes/. The persona is the owner, not the runtime. Codex on the Mac writes to auto/lucienne/, same as Claude Code on the Mac.

Iris wiring prerequisite

The extractor resolver currently treats Hetzner as a single-persona machine. Wiring Iris into the extraction pipeline requires a resolver change to support the multi-persona allowed-set model — so the extractor can distinguish a Luci session from an Iris session on the same host. This change is tracked separately and is not yet done.

How the machine is recognised

The extractor tries several methods to find the hostname, in order: socket.gethostname(), the first dotted label from that, and on macOS scutil --get LocalHostName which gives the stable network-independent name. All three are checked against a fixed allowlist table. This was hardened in commit 14c423a5 on 2026-06-05.

Why fail-closed matters — the Safair wifi story

Before the hardening, when Elmar connected his MacBook to the Safair corporate Wi-Fi, the network assigned the machine a name like CC_Q24.SAFAIR.LOCAL. The extractor didn't recognise that name — it wasn't in the table. The old code defaulted to lucienne anyway.

That was wrong: a tool running on an unrecognised host could silently contaminate auto/lucienne/ with memories from a completely different context. The fix: if the hostname doesn't match the table and there is no PKA_PERSONA override, the memory goes to Vault/memory/quarantine/. It is recorded but kept out of normal recall until a human checks it. An unrecognised host never silently masquerades as a known persona.

The PKA_PERSONA override

Set PKA_PERSONA=luci or PKA_PERSONA=iris to disambiguate between Hetzner personas — this is the primary signal when a machine hosts more than one persona. Set to any known persona to force a specific identity on a new machine not yet in the allowlist. An unknown value still routes to quarantine.

Per-tool status

Hermes / Iris was proven end-to-end on 2026-06-05. To add the remaining tools, see the Playbook tab.

Trust lifecycle

Every memory note is born with a trust level. That level controls whether it shows in recall and how much weight it carries. Trust can only be upgraded by a human — it is never automatic.

Click a status to see what it means.

unverified
New note
active
Confirmed
curated
Authoritative
Click a status above.

Full status table

StatusMeaningShows in recall?
unverifiedFreshly extracted — a hypothesis, not a confirmed factYes, but ranked below confirmed memories
activeA human confirmed it as accurateYes, full weight
curatedHuman-written or heavily reviewed — highest authorityYes, highest weight
supersededReplaced by a newer, better memoryNo — excluded
wrongConfirmed incorrectNo — excluded
quarantinedWritten from an unrecognised host, or flagged by the secret gateNo — excluded, human review needed

Authority hierarchy

When two memories cover the same topic, the one with higher authority wins:

  1. Manual memory files in Vault/memory/*.md — hand-kept, boot-loaded, always wins
  2. Curated auto-memories — drafted by the dream cycle, promoted by Elmar
  3. Active auto-memories — confirmed by Elmar in a session
  4. Unverified auto-memories — fresh from the extractor, treat as a hypothesis
The secret gate: a pre-commit hook runs scan-memory-secrets.py on every staged memory file. If it finds anything that looks like a key or credential, the commit is blocked. Secrets belong in ~/.claude/vault/secrets/, referenced by name from memory — never written out.

The technical standard

The interoperability contract every tool follows lives at docs/standards/pka-agent-memory.md. Hand that file to any AI tool and tell it to make itself compliant. Here are the key points.

The one rule: Vault/memory/ (markdown files in the PKA git repo) is the shared source of truth. Your tool's native memory is only a cache — other tools cannot see it. Anything durable must also land in Vault/memory/.

Where memory lives

Every auto-extracted memory file goes to Vault/memory/auto/<persona>/<name>.md where the persona is determined by the machine (see the Personas tab). If the persona cannot be determined, the file goes to Vault/memory/quarantine/ — never to a default.

The frontmatter every tool must write

All memory files must start with this YAML header — exactly this shape. This is what makes memories from different tools searchable together.

---
type: auto-memory            # or "curated" for human-confirmed
source: session-transcript   # session-transcript | self-published | imported
session_id: <id>
extracted_at: <UTC ISO-8601>
status: unverified           # always starts unverified -- a human promotes it
quality_flag: none
persona: <lucienne|luci|iris|miki>
runtime: <claude|codex|hermes|kimi|gemini>
model: <model id that wrote it>
machine: <hostname>
source_hash: <sha256 of the source>
---
- one concise bullet per line
- preserve the EXACT wording of any rejected decision
  (if something was rejected, say "rejected X" -- never let it become "chose X")

The recall rule

Before saying something is unknown, a tool must check: (1) known wiki pages, (2) Vault/memory/ directly or via vault.db through the Vault MCP tools, (3) qmd for exact-keyword fallback. Recall already excludes wrong/superseded/quarantined notes and ranks unverified below confirmed ones.

Self-adoption prompt

To make any AI tool compliant with this standard, paste this into it:

You are an AI tool in Elmar's PKA system. Read
/Users/elmar/PKA/docs/standards/pka-agent-memory.md and make yourself compliant.
Key points: PKA markdown in Vault/memory/ is the shared source of truth; your private
memory is only a cache; you are a runtime, not a memory owner. When you learn a durable
fact/decision/correction, publish it to Vault/memory/auto/<persona>/ in the exact
frontmatter format in the standard (status: unverified, with persona/runtime/model/
machine/source_hash), and preserve the polarity of any rejected decision verbatim.
To recall, search Vault/memory/ (or vault.db via Vault MCP / pka-recall) before
claiming something is unknown. Do NOT create your own canonical memory store, do NOT
commit raw transcripts, do NOT write secrets into memory.
Then tell me: what you changed, where you will publish, and a sample memory path.
What this standard deliberately does not do

Kept minimal by design — one user, four personas. No conformance-certification ceremony, no per-tool adoption reports. The approach: pilot one tool (Hermes/Iris) end-to-end, prove it works, then generalise to the others. Richer governance only if the fleet grows substantially.

Tools keep their own native memory as a cache — this standard does not touch that. The only requirement is that durable learnings also land in the shared channel.

How to add a new tool — 6 steps

Use this checklist to bring Luci/Iris (Hetzner), Miki (Mac mini), the Windows XPS, or any future tool into the shared memory channel. Click each step to expand it.

Full details for each step are in docs/standards/pka-agent-memory.md section 5. The standard also has the self-adoption prompt (section 6) which you can paste directly into the target tool.

Which approach: extractor adapter or self-publish?

ApproachWhen to useExamples
Add an extractor adapter The tool writes sessions to a known folder on disk. Add a reader for that folder to session-memory-extractor.py. Codex, Hermes, Kimi, agy — all read a session folder this way
Self-publish The tool can write files reliably and you want it to decide what is durable itself. Paste the self-adoption prompt into it. Hermes/Iris (already does this)
Dry-run first Test the persona resolves correctly before going live. Run the extractor with --dry-run. Any new machine or new tool

Why it works this way

Why markdown files instead of a database?
No vendor lock-in. The database (vault.db) is rebuilt from the markdown — you can delete it and rebuild any time. The markdown travels via git, works offline, is readable in any text editor, and survives any tool change or migration. If Claude Code disappeared tomorrow, the memories would still exist as plain text files.
Why a symlink instead of a setting?
Claude Code's autoMemoryDirectory setting is only honoured from the user-scope ~/.claude/settings.json — it is silently ignored at project scope (a security measure). A symlink is an OS-level shortcut that works regardless: whatever the built-in memory writes to its native path physically lands in the git-tracked store. A self-healing guard re-creates the symlink if a Claude Code update clobbers it.
Why two MEMORY.md files?
Two tiers with different jobs. The curated tier (Vault/memory/MEMORY.md plus the top-level files) is hand-kept, loaded at every session boot, and always wins on conflict. The auto tier (auto/<persona>/) is the automatic captures from the extractor. Both live in the same git-tracked folder and both feed the vault.db search index.
What does Luci see, and when?
Luci pulls the PKA repo hourly. A memory written on the Mac is searchable on Luci within the hour. Luci rebuilds her own local vault.db from the synced markdown. Her built-in memory is symlinked into auto/luci/ so writes from both machines land in the right persona folder.
Is it safe — what about secrets?
The repo is private, so nothing was publicly exposed. A pre-commit hook runs scan-memory-secrets.py on every staged memory file and blocks the commit if it finds anything that looks like a key or credential. Secrets belong in ~/.claude/vault/secrets/, referenced by name from memory — never written out. The proper gate (gitleaks + GitHub push-protection) is parked as MC-4127.
What is the Mac mini's role?
Miki (Mac mini) is intended as an always-on coordinator: health checks, MEMORY.md index regeneration, reconciliation across personas. It is not a replacement for the Mac or the Hetzner server. It is a low-cost companion that can run jobs the MacBook can't (it goes to sleep) and is physically local (unlike Hetzner). The integration surface is still being proven.
What is still open?
gitleaks gate (MC-4127, parked): replace the hand-rolled secret scanner with gitleaks plus GitHub push-protection and a one-time history scan.

Promotion pipeline idle: the dream cycle needs a salience log (memory-manager.jsonl) to accumulate before it starts drafting promotions.

Tools to wire: Luci/Iris on Hetzner (resolver ready), Miki on Mac mini, Windows XPS.
Updated 2026-06-05 · built from wiki/memory-system.md + docs/standards/pka-agent-memory.md · Hermes/Iris proven live 2026-06-05 · persona resolution hardened commit 14c423a5 · PKA dashboard port 8787