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.
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.
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.
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.
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.
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.
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.
| Job | Script | Schedule | What 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. |
Each part of the system explains itself. Start with the shared store (green, middle) — that is the heart of it.
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.
| Machine | Persona(s) | Role | Memory folder |
|---|---|---|---|
| Elmar's MacBook / work laptop | lucienne | Chief of Staff | auto/lucienne/ |
| Mac mini (always-on companion) ⚠ not yet set up | miki | Coordinator / reconciler | auto/miki/ |
Hetzner (openclaw) — Claude Code / Codex | luci | Project Manager | auto/luci/ |
Hetzner (openclaw) — Hermes profile | iris | Second persona on Hetzner | auto/iris/ |
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.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.
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.
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.
PKA_PERSONA overrideSet 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.
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.
| Status | Meaning | Shows in recall? |
|---|---|---|
| unverified | Freshly extracted — a hypothesis, not a confirmed fact | Yes, but ranked below confirmed memories |
| active | A human confirmed it as accurate | Yes, full weight |
| curated | Human-written or heavily reviewed — highest authority | Yes, highest weight |
| superseded | Replaced by a newer, better memory | No — excluded |
| wrong | Confirmed incorrect | No — excluded |
| quarantined | Written from an unrecognised host, or flagged by the secret gate | No — excluded, human review needed |
When two memories cover the same topic, the one with higher authority wins:
Vault/memory/*.md — hand-kept, boot-loaded, always winsscan-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 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.
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/.
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.
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")
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.
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.
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.
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.
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.| Approach | When to use | Examples |
|---|---|---|
| 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 |
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.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.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.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.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.memory-manager.jsonl) to accumulate before it starts drafting promotions.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