# Portable Persistent Memory System — Build Instructions (v2)

**Version 2, October 2026.** Version 1 (September 2026) is still available as
`portable-ai-memory-system-v1.md`. What changed and why is in the changelog at the end. Everything
new in v2 came from six weeks of daily use of the reference library, and every new rule corresponds
to something that actually went wrong.

**What this is:** a complete, transferable specification for giving an AI assistant durable memory
in a cloud file store, so that context survives across sessions, devices, and conversations.

**How to use it:** hand this file to an AI assistant that has read/write access to a cloud file
store (Google Drive, OneDrive, Dropbox, SharePoint, or a synced local folder) and say *"build
this."* To upgrade a v1 library, say *"upgrade this library to v2"* and point it at §12. Sections
0–11 are written as instructions to the assistant.

**Prerequisites:**

- An assistant with a connector or tool that can at minimum **create** and **read** files in a
  cloud file store. Everything else is optional and the design adapts.
- Roughly 20 minutes for the initial build.
- Optionally, desktop sync (e.g. Google Drive for Desktop) plus a bridge that lets the assistant
  read and write local files. This makes the system faster, not more capable.
- Strongly recommended: a way to make the assistant consult this system **at the moment it files
  something**, not only at session start: a skill, a hook, a custom instruction that triggers on
  filing words. See §5.

**What you get:** three core files and an archive folder per project to start, growing into a few
subject files when the record gets big. The assistant reads the core at the start of every session,
counts what is waiting, writes new memories as timestamped addenda, and merges them in on a
regular cadence. It works from a phone with nothing but a file connector, and works better when a
desktop is reachable.

---
---

# INSTRUCTIONS TO THE ASSISTANT

Everything below is addressed to you, the assistant building or running this system.

---

## 0. Probe your capabilities before you design anything

**Do not assume what your tools can do. Test each one and record the result.** The single most
consequential design decision depends on the answers, and getting it wrong from an assumption is
the most common way this build goes bad.

Determine, by actually trying, whether you can:

| Capability | Why it matters |
|---|---|
| **Create** a file with content | Baseline. Without this, stop — you cannot build the system. |
| **Read** a file's content | Baseline. |
| **Create** a folder | Needed for the layout. If unavailable, use a filename prefix convention instead. |
| **Rename** a file or folder | Affects whether you can correct mistakes cheaply. |
| **Move** a file between folders (reparent) | Needed to archive absorbed addenda yourself. |
| **Trash / delete** a file | Needed to retire superseded versions. |
| **Edit file content in place** (append or patch) | **The decisive one.** See below. |
| A **second channel** — local synced folder plus shell or stage/commit access | Optional accelerant. |

### The decisive question

**Can you modify the content of an existing file, or can you only create new ones?**

Many cloud-storage connectors expose "update" operations that change only *metadata* — title,
parent folder, sharing — and cannot touch bytes. Read your tool's documentation carefully, then
verify empirically. Do not trust the operation's name.

- **If you cannot edit content:** the system is **append-only**. You may never revise a core file.
  New memories are written as new files and merged by a process that *can* edit. This is the
  baseline design and everything below assumes it.
- **If you can edit content:** you may revise core files during an absorption, but keep the
  append-only protocol for everything else. It is the more reliable path, not a fallback — see §7.

Record what you found, with a date, in the long-term file. Future sessions will otherwise
re-derive it, and may re-derive it wrongly.

---

## 1. Architecture

### Start with three core files

```
<Project Name>/
└── Memory/
    ├── 00-index.md          Navigation and addressing. Read every session.
    ├── 01-long-term.md      Durable facts. Changes slowly.
    ├── 02-short-term.md     Active buffer. Expected to churn.
    ├── absorbed/            Archive of merged addenda. NEVER read at session start.
    └── mem-<timestamp>.md   Unabsorbed addenda stage here in the Memory root.
```

The first split is by **volatility**:

- **Long-term** holds what stays true for months — identity, relationships, standing positions,
  stable preferences, settled architecture, lessons. Appended to; rarely rewritten.
- **Short-term** holds current state — projects in flight, open threads, things that will resolve
  or expire. Rewritten at every absorption. Expected to be pruned.
- **Index** is navigation. It says what the others contain, when to open them, and points at
  everything outside the library.

### Then split the long record by subject, when size forces it (new in v2)

v1 said never to split by subject. That was right for the first split and wrong as a permanent
rule. A busy library's long-term record grows until reading it at every session start costs more
than the session can afford. In the reference library that happened at about 135KB, and again at
about 285KB.

When it does, keep the volatility split and **move whole subjects out of the long-term record into
their own on-demand files**:

```
Memory/
├── 00-index.md        every session   (routing table: which subject lives where)
├── 01-long-term.md    every session   (identity, people, standing positions, doctrine)
├── 02-short-term.md   every session   (current state for ALL subjects, one entry each)
├── 03-<subject>.md    on demand       (read only when the work touches that subject)
├── 04-<subject>.md    on demand
├── ...
├── 0n-method.md       before building (dated lessons: testing, delivery, review)
├── absorbed/          never
└── mem-*.md           counted at session start
```

Rules for the split:

- **Ask the user first.** It changes the architecture. In the reference library it was approved
  three times, once per split.
- Current state stays in short-term for every subject. Only the durable record moves.
- Move subjects **whole**; do not rewrite them on the way. Create the new file first and verify it,
  then trim the old one, then update the index, then short-term. At no point should a subject exist
  in only one place unverified, or in no place.
- The index's routing table is authoritative: when this document and the index disagree, the index
  is right.
- Method lessons (how to build, test, deliver, review) are a good first candidate for their own
  file, read before work rather than at every start.

### Address everything by file ID, not by title

**Use whatever stable, opaque identifier your store provides** — Google Drive file IDs, OneDrive
item IDs, or equivalent. Not filenames, not paths. Titles and paths change; identifiers survive
renames and moves. During the reference build, two folder renames and three file moves occurred
within one session and every ID-based pointer still resolved. Later, 151 addenda were moved into
the archive in one pass and every one kept its ID.

**Corollary: a file can never contain its own identifier.** The identifier does not exist until
after the file has been created, nor does the ID of a file created in the same step. Create first,
read the ID from the result, then write the reference. Self-reference by name; resolve by folder
listing.

---

## 2. Build procedure

Follow this order. Later steps depend on identifiers produced by earlier ones.

1. **Verify the parent location.** List it immediately before creating anything.
2. **Create the project folder,** then `Memory/` inside it, then `absorbed/` inside that.
3. **Gather the seed content first.** Do not write files yet. Pull whatever durable context you
   already hold about this user — prior memory, an export from another assistant, an interview, or
   a document they hand you. If you have nothing, seed with the architecture itself.
4. **Sort the seed by volatility** into long-term and short-term. When unsure, put it in
   short-term. Promotion is easy; demoting something that was wrongly enshrined is not.
5. **Write `01-long-term.md`,** then `02-short-term.md`. Record their identifiers.
6. **Write `00-index.md` last.** It needs the other identifiers, and it cannot contain its own.
7. **Verify.** List the folder and read each file back. Confirm the content landed and that the
   files are stored as plain text/markdown rather than converted to the store's native document
   format. Disable conversion if your tool offers the option; a converted file will not round-trip.
8. **Set up the filing-time trigger** (§5) if your platform allows one.

Number the core files `00-`, `01-`, `02-` so they sort in reading order in any file browser.

---

## 3. File templates

### `00-index.md`

```markdown
# <Project> — Memory Index

**Owner:** <name> · **Created:** <date>

Master directory for this project's memory. Addressed by **file ID, not title**.

## 1. Read Protocol
When the user says "memory", they mean this library, not any built-in memory feature.

At the start of any new conversation:
1. Read this index, 01 and 02.
2. **Count the unabsorbed addenda in the Memory root.** More than about fifteen: say so to the
   user before doing anything else, and offer to absorb.
3. Read the unabsorbed addenda.
4. Read a subject file only when the work touches that subject (§2).

**Ignore everything inside `absorbed/`.** That is what prevents double-merging and bounds the
context window.

## 2. Core Files and Routing
| # | File | ID | Read |
|---|------|----|------|
| 00 | `00-index.md` | *(this file — resolve via folder listing)* | every session |
| 01 | `01-long-term.md` | `<id>` | every session |
| 02 | `02-short-term.md` | `<id>` | every session |
| 0n | `0n-<subject>.md` | `<id>` | when the work touches <subject> |

## 3. Folders
| Folder | ID | Role |
|---|---|---|
| `<Project>` | `<id>` | Project root |
| `Memory` | `<id>` | Core files; unabsorbed addenda stage here |
| `absorbed` | `<id>` | Merged addenda and pass manifests — **not read at session start** |

## 4. External Pointers
| Title | ID | Note |
|---|---|---|

## 5. Absorption Loop
Write addenda; absorb them on a cadence (§6 of the spec); archive them; log below.

## 6. Pending Addenda
- *(count them; do not trust this line)*

## 7. Absorption Log
| Date | Addenda | Notes |
|---|---|---|
```

### `01-long-term.md`

```markdown
# Long-Term Memory

**Layer:** durable — facts that stay true for months or years
**Last absorbed:** <addendum filename>

Lines tagged `[stated]` are the user's own words or choices. Untagged lines are the assistant's
own knowledge from its work. `[inferred]` marks a conclusion. Nothing inferred is written as stated.

## Identity
## Operating Doctrine
## Standing Positions
## People
## Tooling
## Memory System Architecture
   (capability probe results from §0, dated)
## Record since <date>
   (dated entries appended verbatim at absorption, one per absorbed block)
## Corrections Log
   (when something here turns out to be wrong, correct it AND record that it was wrong, with the date)
```

### `02-short-term.md`

```markdown
# Short-Term Memory

**Layer:** current state — one entry per subject, rewritten at every absorption
**Last absorbed:** <addendum filename>

## <Subject>
State as of <date>. Open items. Pending decisions (whose call).

## Carried up from state notes
   (durable lines that were filed as state by mistake, kept verbatim until they reach long-term)
```

---

## 4. The addendum convention

When you learn something worth keeping, **write a new file. Never revise a core file outside an
absorption.**

### Naming

`mem-YYYY-MM-DDTHHMMZ.md`, UTC, in the Memory **root** (not `absorbed/`).

- **Take the timestamp from the clock** (e.g. `date -u +"%Y-%m-%dT%H%MZ"`), never from your own
  sense of the time, so that lexical sort is chronological.
- **List the root immediately before creating.** If the name is taken, use the next minute.
  Minute stamps collide when sessions run in parallel; in the reference library, four times.
- **Create through a connector that refuses to overwrite,** even when you could write by path.
  A path write silently replaces whatever is there. One note was lost exactly that way: one session
  created it, and twenty seconds later another session, which had listed the root just before,
  wrote its own note to the same path.
- Do not use sequential numbering (`mem1`, `mem2`). It requires polling for the highest number,
  and two sessions will eventually pick the same one.

### Structure

Each block carries a disposition **and a subject**, because the subject is what routes it:

```markdown
# Addendum — <timestamp>

Session: <surface>. Mode: <connected | disconnected>. Subject: <subject>.

## -> long | <subject>
- [stated] <the user's own words or choice, quoted exactly>
- <something you know from your own work, untagged>

## -> short | <subject>
- <current state, pending item, open question>

## -> index
- pointer: <title> · `<id>` · <one-line description>

## -> drop-from-short
- <entry in short-term that has resolved or expired, and why>
```

- **One subject per addendum** is easiest to absorb.
- **A general lesson** (not about one piece of work) goes under a `method` subject.
- **Never file a durable fact as `-> short`.** Short-term is rewritten at absorption; a durable
  line hiding there survives only if someone notices.
- The disposition is a **proposal**. The absorber decides.

### Provenance: the `[stated]` tag

Tag a line `[stated]` only if the user said it. Quote exactly, typos included, and say how it was
said:

- An option picked from a list is recorded as a choice ("picked 'Yes, split it'"), not as words
  typed.
- Your own knowledge from the work is written **without** a tag.
- An inference is marked `[inferred]`.
- Output from tools, files or searches is not the user telling you anything.
- **Your suggestions are not the user's decisions**, even when the user reacted warmly. Record that
  they chose something, not your reasoning for it.

This distinction is the difference between a memory system and a rumour mill. Without it, one
confident guess becomes a "fact" that shapes every later decision.

### Carrying text for a file you cannot edit

When the right destination is a file you cannot edit from where you are (a ledger, a canon list, a
file in another folder), put the **exact text to append** in the addendum, marked for the next
connected session, with the position or number it expects. Do not paraphrase it later; append it
verbatim.

---

## 5. Filing at filing time (new in v2)

**An instruction read at session start does not fire at filing time.**

In the reference library, a standing instruction to file in the library sat at the top of the
index. It was read at session start on at least two of the occasions when it was then ignored.
Sessions kept filing durable material into whatever was nearest to hand — the platform's built-in
memory, project documents — and wrote the library only when the user asked. Four times in five
days.

What fixed it was a trigger at the moment of filing: a skill whose description fires on the words
that precede filing (*file, document, note, record, remember, commit, write this down, update the
memory, consolidate, absorb*) and on finishing any substantial piece of work. It asks one question:
**library first?**

If your platform has skills, hooks or per-tool instructions, build that trigger. If it has none,
put the rule in the instructions that are attached to the filing tool itself, not only in a file.

Built-in memory and project documents can still be written. They are convenience copies. Writing
them is not filing.

---

## 6. The absorption loop

```
  WRITE PHASE (any session)                 ABSORB PHASE (a connected session)
  ─────────────────────────                 ──────────────────────────────────
  1. Read 00 + 01 + 02                      5. Stage core files + root addenda
  2. COUNT the root addenda                 6. Long blocks: append verbatim
  3. Work                                   7. Short blocks: rewrite state
  4. File: mem-<timestamp>.md          →    8. Verify each core file (§7)
     (never mutates a core file)            9. Archive addenda; list root again
                                           10. Log the pass in the index
```

### What goes where

- **`-> long`** is appended **verbatim** as a new dated entry at the end of that subject's record,
  headed `#### <date> · <title> · <addendum name>`. Never rewritten. If it corrects or supersedes an
  earlier entry, both stay, and a dated note goes above the earlier one.
- **`-> index`** rides with the same entry, unless the pointer is library-wide.
- **`-> short` and `-> drop-from-short`** are resolved into that subject's entry in short-term,
  which is **rewritten as current state**, not appended to. Later notes win; resolved items go;
  unresolved ones stay. A durable line that was filed as state and exists nowhere in the record is
  carried up verbatim into "Carried up from state notes".

### Cadence (new in v2)

**Filing is half the job.** In the reference library, once filing worked, the opposite failure
followed: most sessions ran disconnected, each wrote its addendum correctly and stopped, and nothing
was absorbed for fourteen days. The root held 151 addenda, about 528KB, against 189KB of core
files, and short-term was describing a setup that no longer existed. Every session had done its
job. The library was still wrong.

So:

- **Count the root at every session start** and say so when it passes about fifteen.
- **Absorb on a cadence**, not when it feels necessary. With several sessions a day, 25 to 35
  addenda a day is normal load. Daily absorption by whichever session has the editing channel has
  held since.
- A library that is only written to is a log.

### Big passes (new in v2)

For more than a handful of addenda:

1. Split the addenda into blocks mechanically and classify each in a **manifest**.
2. Lift by script, with a **line-for-line accounting check**: every line of every addendum is
   lifted, turned into state, or skipped with a reason.
3. Rebuild state per subject, with an audit line per state block.
4. **Have an independent reader audit the result before committing** — another assistant
   instance or a human, one that did not do the absorption.
5. Save the manifest to `absorbed/` beside the addenda.

The independent audit found real errors on every pass where it was used: 18 on one, 9 on the next.
Open items that existed only in state, an inference written as fact, facts cited to notes that did
not hold them. You will not catch your own.

When an addendum says it continues another note "from the same session", check that the named note
is in the root and is about the same subject. That check is what found the overwritten note in §4.

---

## 7. Operating modes and the verify loop

### Modes

**Disconnected — the baseline.** Only the file-store connector is available. Content editing may
be impossible. Never attempt to revise a core file; write an addendum and stop.

**Connected — the accelerant.** A second channel (desktop sync plus local file access) allows
in-place edits and end-to-end absorption. Use it when present; never depend on it, and never trust
it silently.

Design every convention to work in disconnected mode. It is tempting, once the faster channel
appears, to conclude the constraint has been lifted. **That conclusion was reached twice in the
reference library and was wrong both times.** File creation cannot race. Editing can. Append-only is
the reliable path, not merely the mobile fallback.

### The verify loop (expanded in v2)

1. **Stage everything first.**
2. **Patch locally with a script,** using anchored substitutions that **assert a unique match**.
   Never retype file content by hand.
3. **Commit one core file, from a fresh path.** A path that was already committed once can deliver
   its earlier copy. Wait about 45 seconds.
4. **Read it back and compare the text** — a checksum or a diff — never a byte count, never a
   modification time. In the reference library the modification time once advanced while the
   content did not change.
5. **Only then start the next file.** New files may be created together; edits go one at a time.
   Order for a restructure: create and verify new files, trim the old, then the long-term file, then
   short-term, then the index.
6. **Archive the addenda last**, through an operation that preserves their IDs.
7. **List the root again** before writing the log: other sessions file while you work.

---

## 8. Failure catalogue

Real failures from the reference library. Read them before you build; each is cheap to avoid and
expensive to discover. 8.1–8.6 date from the initial build (v1); the rest from the six weeks after.

### 8.1 Writing a file's own identifier into itself
The identifier does not exist until after creation. **Self-reference by name; resolve by folder
listing.**

### 8.2 Acting on a stale folder listing
A listing read minutes ago may no longer be accurate. **Re-verify folder state immediately before
creating anything.**

### 8.3 Believing your own outdated notes about your tools
A note recorded early ("this connector cannot move files") will be inherited and treated as fact
long after it stops being true. **Re-verify capability claims periodically, and date them.**

### 8.4 Over-generalizing from one session's conditions
"Editing works now, so append-only is obsolete" is a conclusion drawn from a temporary state.
**State the conditions under which a conclusion holds.**

### 8.5 Eventually-consistent storage with no consistency signal
Reads can lag writes by minutes and can return states older than ones already observed. Every read
reports success. One file's visible size went 12,636 → 10,898 → 12,636 → 14,627 bytes across four
commits in twelve minutes. Two wrong diagnoses followed ("the write was reverted", then "the
remediation destroyed the previous version"); both writes had landed. **The only real data loss was
caused by remediating failures that had not occurred.**

1. A byte count is not evidence of content. Neither is a modification time.
2. Never rebuild on a base you have not just verified.
3. Prefer "I am early" to "it broke" — **but check again later. A write that has not appeared by the
   next session did not happen.**
4. Do not chain edits.
5. When in doubt, write an addendum instead of editing.

### 8.6 The general shape
The explicit system reported success and never lied, but had no way to express **what it did not
know** — and that gap got filled with inference. **Record corrections in-band**: write the
correction *and* a dated note that the earlier version was wrong. The correction log is the most
valuable section in the library, because it is the only part that teaches a future session where
this system's judgment fails.

### 8.7 Filing drift (v2)
Durable material filed into convenience copies; the library written only when asked; four times in
five days with the instruction present and read. **Trigger at filing time (§5).**

### 8.8 The unabsorbed backlog (v2)
Every session filed correctly; nothing was absorbed for fourteen days; the core files described a
world that no longer existed. **Count the root; absorb on a cadence (§6).**

### 8.9 Name collisions and silent overwrites (v2)
Parallel sessions chose the same minute four times; one path write destroyed another session's
note. **List before creating; next minute if taken; create through a channel that refuses to
overwrite (§4).**

### 8.10 Repeating a count from a summary (v2)
"About 60 unabsorbed addenda" went into a note from a session summary; the root had been absorbed
the day before and held 18. **Before repeating a count, list the thing.**

### 8.11 State read as fact (v2)
A short-term line saying a device or project is in some state is the record's last word, not the
world's. Entries carried forward unconfirmed look as current as fresh ones. **Mark the date state
was last confirmed, and check the thing before trusting the line.**

### 8.12 Short-term that only grows (v2)
In the reference library short-term grew at every pass (181KB, 214KB, 237KB across three passes),
because entries gain a paragraph per piece of work and rarely lose one. **See §10.**

---

## 9. Verification checklist

After building, confirm each of these by actually checking:

- [ ] All files exist in the expected folder, listed from the store itself.
- [ ] Each file's content reads back correctly — **read the text, not the size or the timestamp.**
- [ ] Files are stored as plain text/markdown, not converted to a native document format.
- [ ] Every identifier in the index resolves to the file it claims.
- [ ] No file contains its own identifier.
- [ ] The `absorbed/` folder exists and is empty (or holds only genuinely merged addenda).
- [ ] The read protocol says to ignore `absorbed/` **and to count the root**.
- [ ] Capability probe results from §0 are recorded in the long-term file, with a date.
- [ ] A filing-time trigger exists (§5), or the reason it cannot is recorded.
- [ ] If a second channel exists, a full round trip has been verified: write, wait, read back.

---

## 10. What to watch over the following weeks

**Short-term that never gets pruned.** Promotion feels productive; deletion does not. If several
absorptions pass without a single `-> drop-from-short`, that is the signal — not that nothing has
expired, but that nothing is being retired. Run a retire-only pass now and then: for each entry,
*is this still true, and does it still change what I would do?*

**The session-start read.** Measure it. When the core files read at every start become most of a
session's budget, propose a split (§1). Do not do it unasked.

**The root.** If it is growing faster than it is absorbed, the cadence has slipped.

**The correction log.** A memory system that never records being wrong is not one that is never
wrong. It is one that is not noticing.

You will know the system is healthy if three things are true: the root stays small, the core files
describe the world as it is today, and the correction log keeps growing.

---

## 11. More than one assistant (new in v2)

The same library can be written by more than one assistant, or two assistants can keep sibling
libraries on the same pattern.

- Each writes **attributed addenda** (name the writer in the header). The addendum is the unit of
  contribution, so nobody edits anyone else's core text mid-session.
- Keep separate libraries separate: do **not** merge one library's addenda into another library's
  core files. A handoff to the other library is an addendum filed in *its* root.
- Same file name is not same file. When two writers produce notes under the same name in two
  places, compare the text before assuming they match.

---

## 12. Upgrading a v1 library to v2

1. Absorb everything in the root first, so the upgrade starts clean.
2. Add the count step and the "memory means this library" line to the index's read protocol.
3. Add the subject to every disposition from now on; leave old addenda as they are.
4. Set up the filing-time trigger (§5).
5. Add `[inferred]` and the untagged-own-knowledge convention to the long-term header.
6. Add "Carried up from state notes" to short-term.
7. Do **not** split by subject yet unless the session-start read is already too large. Propose it
   to the user when it is.
8. Write one addendum recording the upgrade, with a date, and absorb it.

---

## 13. Adapting to other backends

| Backend | Identifier to address by | Notes |
|---|---|---|
| Google Drive | File ID | Disable conversion to native Docs format on upload. |
| OneDrive / SharePoint | Item ID | Similar conversion behaviour; check it. |
| Dropbox | File ID (not path) | Paths change on move; IDs do not. |
| Git repository | File path | Paths are stable and history is free; an in-file correction log is still more legible to an assistant. Commits give you the verify loop for free. |
| Plain synced folder | Path | No IDs; accept path fragility and verify the listing every session. |

---

## Changelog

**v2 (October 2026)**, from six weeks of daily use:

- New §5: file at filing time — a trigger, not only an instruction read at session start.
- Read protocol counts the root; more than about fifteen addenda is reported to the user.
- Absorption on a cadence; big passes get a manifest, line-for-line accounting and an independent
  audit.
- Architecture: volatility split first, then whole subjects moved to on-demand files when size
  forces it (with the user's approval). Reverses v1's flat "never split by subject".
- Naming: timestamp from the clock; list before creating; next minute if taken; create through a
  channel that refuses to overwrite.
- Dispositions carry a subject; one subject per addendum; durable facts never filed as short.
- Provenance: picked options recorded as choices; own knowledge untagged; `[inferred]` for
  inferences; suggestions are not decisions.
- Verify loop: fresh paths, text comparison only (not size, not time), one file at a time, archive
  last, list again.
- New failures 8.7–8.12; new §11 (more than one assistant) and §12 (upgrading).

**v1 (September 2026):** the initial build: three files split by volatility, addenda, absorbed/,
ID addressing, `[stated]`, disconnected mode as the default, failures 8.1–8.6.

## Provenance

Derived from a working library that has run daily since September 2026, including its mistakes.
Every rule in §8 corresponds to a failure that actually occurred. The architecture originated with
the user who commissioned it; this document generalizes it for reuse.
