For agents, and for the people working beside them

What an agent has to know to write into a store, what it costs, and two prompts meant to be copied as they are.

01

The write protocol

One block answers one question on its own. Keep it under about 800 tokens; split a longer one into blocks that each stand alone. Give it a one-line title and three to eight keywords -- the words a future reader would actually type. Put it under the parent its subject puts it under. Do not rewrite the source bytes when you are moving something in: no polishing, no translating, no dropping sentences.

02

One daemon, thin clients

One store, one daemon. theourgia serve <store> holds the store's write lock and keeps the reduced state in memory. The client is thin: it knows the transport and nothing else, and it starts a daemon itself if it cannot reach one. Requests and answers are S-expression envelopes over a unix socket. The MCP shell is thin in the same way -- it asks the daemon for the tool list with describe rather than carrying its own copy.

Two sets of figures, because they were taken under different conditions. Over MCP with the shell resident and the store at 387 blocks, a tool call took 1 ms to read a block, 2 ms for an outline and 48-68 ms for a search; initialize took 39 ms and tools/list 121 ms, the latter including the describe round trip to the daemon. Measured separately, from a source-form client with four other agents writing into the same store at the time, an insert of a 3 KB body took 108 ms end to end, including the client process starting. A client process starts in 30-50 ms once it is running from compiled objects. search is a full scan and grows with the store.

03

What it costs

What it costs to move a memory in

import-md opens the files itself, so the bytes never enter the agent's context. Measured on 113 documents totalling 2,717,039 bytes: 0 tokens of context to convert, against roughly 1,082,000 if the same agent had read them first. This holds only while the split needs no judgement -- import-md cuts at headings. A corpus that needs a human decision about where to cut does not get the zero.

Recall, measured against markdown

Twenty real questions about a real agent memory, answered blind by two agents: one allowed only the store, one allowed only the markdown files. Both scored 20/20, and the answers were checked against each other question by question. The store route read 14% more bytes, all of it from search: its replies have no upper bound yet, and a broad query returns every hit with its full keyword list. That is a known open item, not a property of the model.

04

Prompt: move an existing markdown memory in

Give this to an agent together with the list of files to migrate. One agent per group of files works, and several may write into one store at the same time, each under its own writer id.

You are moving an existing markdown memory into a theourgia store through
its command-line client, following the store's write protocol. The store is
the target of everything you write; the markdown files are read-only source.

Environment (every shell):
  export THEOURGIA_ACTOR=<your-name> THEOURGIA_WRITER=<your-name>
  STORE=<path of the store>
  theourgia <verb> --store $STORE ... --wire
The first stderr line `(theourgia machine-home ...)` is a banner; ignore it.

Write protocol:
  - A block is the unit of writing: one block answers one question on its
    own. Keep a block under about 800 tokens (roughly 3000 bytes); split a
    longer one into blocks that each stand alone.
  - Give every block a one-line title and 3 to 8 keywords, comma separated,
    the words a future reader would actually type when searching.
  - Place a block under the parent its subject puts it under (--under).
  - Do not rewrite the source bytes: do not polish, translate or drop
    sentences. Frontmatter stays out of the body; its description may become
    the title, its name and type belong in the keywords.
  - A memory file is usually one block. A file holding several independent
    dated instances that together exceed the limit is split by instance,
    each block titled with the file's name.

Per file:
  theourgia insert --store $STORE --under <parent-id> --title "<title>" \
    --keywords "<k1>, <k2>, ..." --text "<body verbatim>" --wire
A success answers (ok (events ...) (state ((<id> . <hash>))) ...); record
<id>. Record any other answer verbatim, with the command minus the body;
retry at most once.

Ledger (write it to <ledger path> as JSON):
  {"group": ..., "files": [{"file": ..., "chars": n,
     "blocks": [{"id": ..., "title": ..., "keywords": ..., "bytes": n}],
     "refusals": [{"cmd": ..., "answer": ...}]}],
   "totals": {"files": n, "blocks": n, "refusals": n, "wall_seconds": n},
   "friction": ["one sentence per thing that was awkward: command line,
                 answers, protocol, speed"]}
Every id in the ledger comes from a real answer; never write a placeholder.

Do not modify any source file. Do not touch git. Do not kill processes. Do
nothing to the store except insert under the parents you were given. If the
client fails more than three times in a row, stop, record, report.
05

Prompt: use a store as Claude Code's memory

Three pieces. Turn the markdown memory off, put the store's outline into the session at startup, and tell the agent how to recall and how to write.

The session hook

{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "startup",
        "hooks": [
          {
            "type": "command",
            "command": "theourgia outline --store /path/to/memory-store --depth 1"
          }
        ]
      }
    ]
  }
}

What goes in CLAUDE.md

## Memory lives in theourgia, not in markdown files

The store at /path/to/memory-store is my memory. The markdown memory
directory is retired: do not read it and do not write to it.

Identity: export THEOURGIA_ACTOR=<agent name> and THEOURGIA_WRITER=<agent
name> before the first call. One writer id is held by one live agent at a
time; a later session may bind the same id and carry on with its drafts.
Two agents that need to edit the same draft copy it (drafts --writer w1,
restore <version> --writer w2) instead of sharing the id.

Recall, before starting a task:
  theourgia search --store $STORE <two or three words from the task>
  theourgia read --store $STORE <id>          # the hits that look relevant
  theourgia outline --store $STORE <id>       # to see what sits under a block
Read what the search returns; do not page through the whole store. If a
search finds nothing, try the other words a past self would have used, then
stop: absence of a memory is an answer.

Write, when something worth keeping happens (a correction, a decision, a
fact about the environment, a lesson):
  theourgia insert --store $STORE --under <section id> --title "<one line>" \
    --keywords "<3-8 words a future reader would search for>" \
    --text "<the fact, then Why: and How to apply:>"
One block answers one question; keep it under about 800 tokens. Put it under
the section it belongs to (the outline shows them). Before inserting, search
for an existing block on the same fact and update that one with `write`
followed by `commit --based-on` rather than adding a duplicate. Keep the
markdown habits that still apply: say why, say how to apply, link related
blocks by id in the text.

Do not put into the store what the repository already records (code
structure, git history, CLAUDE.md itself), and nothing that only matters to
the current conversation.

Over MCP instead of a shell

claude mcp add theourgia -- theourgia-mcp --store /path/to/memory-store \
  --actor <agent name> --writer <agent name>