# Portable Persistent Memory System — Build Instructions

**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."* The assistant does the rest. Sections 0–8 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.

**What you get:** three core files and an archive folder per project. The assistant reads them at
the start of every session and writes new memories as timestamped addenda that get merged in
later. 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 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 directly, but keep the append-only
  protocol available and use it whenever the editing channel is unavailable or unverified. It is
  the more reliable path — see §7.

Record what you found. Write it into the long-term file during the build. Future sessions will
otherwise re-derive it, and may re-derive it wrongly.

---

## 1. Architecture

```
<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.
```

### Why three files

The split is by **volatility**, not by subject:

- **Long-term** holds what stays true for months — identity, relationships, standing positions,
  stable preferences, settled architecture. Rarely rewritten.
- **Short-term** holds current state — projects in flight, open threads, things that will resolve
  or expire. Expected to be pruned.
- **Index** is navigation. It is the only file that *must* be read every session; it tells you
  whether you need the others and points at everything outside the library.

Subject-based splits (work / personal / technical) fail because most facts belong to more than one
subject and none of them tell you how stale a fact is likely to be. Volatility-based splits tell
you exactly that.

### Why the index addresses 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. An index built on titles silently
rots the first time someone reorganizes a folder; an index built on identifiers keeps resolving.
This is not theoretical — during the reference build, two folder renames and three file moves
occurred within one session and every ID-based pointer still resolved afterward.

**Corollary rule: a file can never contain its own identifier.** The identifier does not exist
until after the file has been created. Write the self-reference as *"(this file — resolve via
folder listing)"* and address everything else by ID.

---

## 2. Build procedure

Follow this order. It exists because later steps depend on identifiers produced by earlier ones.

1. **Verify the parent location.** List it immediately before creating anything. Names and
   structure can change between when you last looked and now.
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, that is fine; seed with the architecture itself
   and let content accumulate.
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 two identifiers, and it cannot contain its own.
7. **Verify.** List the folder and read each file back. Confirm the content actually landed and
   that the files are stored as plain text/markdown rather than silently converted to the store's
   native document format — many stores convert on upload by default. Disable that conversion if
   your tool offers the option; a converted file will not round-trip.

### Naming

Number the core files `00-`, `01-`, `02-` so they sort in reading order in any file browser. This
matters more than it sounds when a human is looking at the folder on a phone.

---

## 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** — IDs survive
renaming and moving, so every pointer below stays valid even if a file is renamed or relocated.

## 1. Read Protocol
At the start of any new conversation, read:
1. The core files (§2)
2. This index
3. Any unabsorbed addenda sitting in the memory root (§5)

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

## 2. Core Files
| # | File | ID | Layer |
|---|------|----|----|
| 00 | `00-index.md` | *(this file — resolve via folder listing)* | Navigation |
| 01 | `01-long-term.md` | `<id>` | Durable |
| 02 | `02-short-term.md` | `<id>` | Active buffer |

**Which to read when:**
- Identity, relationships, standing positions → **01**
- Current work state, open threads → **02**
- Source material or an external document → **§4**, then fetch by ID

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

## 4. External Pointers
Stable IDs for source material outside the library — documents, corpora, reference sets.
| Title | ID | Note |
|---|---|---|

## 5. Pending Addenda
- *(none)*

## 6. Absorption Loop
Write addenda; merge them into 01/02; move them to `absorbed/`; log below.

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

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

```markdown
# Long-Term Memory

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

Entries are tagged `[stated]` — the user said it directly. Nothing here is inference.

## Identity
## Operating Doctrine
## Standing Positions
## People
## Tooling
## Memory System Architecture
   (record your capability probe results from §0 here)
## Corrections Log
   (when something here turns out to be wrong, correct it AND record that it was wrong)
```

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

```markdown
# Short-Term Memory

**Layer:** active buffer — current state, open threads, things in flight
**Last absorbed:** <addendum filename>

Entries here are expected to churn. At absorption each is **promoted** to long-term,
**updated** in place, or **dropped** because it resolved or expired.

## Current state
## Open threads
## Incidents
```

---

## 4. The addendum convention

When you learn something worth keeping, **write a new file. Never revise a core file mid-session
unless you have verified you can and the write channel is behaving.**

**Filename:** `mem-YYYY-MM-DDTHHMMZ.md`, UTC.

Timestamp-first naming means lexical sort equals chronological sort, so absorption order is
unambiguous and two concurrent sessions cannot collide. Do **not** use sequential numbering
(`mem1`, `mem2`) — it requires you to poll for the highest existing number, and two sessions will
eventually pick the same one.

**Structure:** each block carries a disposition naming its destination.

```markdown
# Addendum — <timestamp>

## -> long
- [stated] <a fact that looks durable>

## -> short
- [stated] <current state, in flight, will churn>

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

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

The disposition is a **proposal**, not a decision.

### The `[stated]` tag

Tag a line `[stated]` only if the user said it directly. Do not tag, and generally do not write:

- Your own inferences or conclusions
- Output from tools, files, or searches (a config file saying the project uses X is not the user
  telling you they use X)
- Your enrichment of what they said
- Your own advice, even after they accept it — record *that they chose it*, not your reasoning

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. That failure occurred during
the reference build (see §7) and it is the expensive one.

---

## 5. The absorption loop

```
  WRITE PHASE (any session)              MERGE PHASE (whoever can edit)
  ─────────────────────────              ──────────────────────────────
  1. Read 00 + 01/02 + root addenda      4. Read unabsorbed addenda in order
  2. Work                                5. Promote / update / drop each entry
  3. Write mem-<timestamp>.md        →   6. Rewrite or edit 01 and/or 02
     (never mutates a core file)         7. Move the addendum into absorbed/
                                         8. Log it in the index
```

**Who performs the merge** depends on the capability probe. If you can edit files, you may do it
yourself. If you cannot, a human does it, or a session with a different channel does.

**If you do absorb autonomously,** the addendum in `absorbed/` is the audit trail — it must remain
readable and unmodified so the merge can be reconstructed and reversed.

**Deciding disposition at merge time:** promote to long-term only what has proven stable. A fact
stated once is "mentioned once," not a standing preference. Resist the urge to promote everything;
see §9.

---

## 6. Operating modes

The system runs in one of two modes, and **the constrained one is the design default.**

**Disconnected — the baseline.** Only the file-store connector is available. Content editing may be
impossible. Therefore: 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 and redesign around the new capability. **This
conclusion was reached twice during the reference build and was wrong both times** — the fast
channel is conditional on a link that is not guaranteed, and the user may be on a phone.

---

## 7. Failure catalogue

These are real failures from the reference build. Read them before you build; each is cheap to
avoid and expensive to discover.

### 7.1 Writing a file's own identifier into itself
The identifier does not exist until after creation, so any ID you write for the current file is
invented. **Self-reference by name; resolve by folder listing.**

### 7.2 Acting on a stale folder listing
A listing read minutes ago may no longer be accurate — the user may be reorganizing while you work.
A duplicate folder created from a stale view is invisible until something resolves by name instead
of ID. **Re-verify folder state immediately before creating a folder.**

### 7.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,
constraining the architecture long after it stops being true. Tool capabilities change and initial
assessments are often wrong. **Re-verify capability claims periodically, and date them when you
record them.**

### 7.4 Over-generalizing from one session's conditions
"Editing works now, so the append-only design is obsolete" is a conclusion drawn from a temporary
state. Write conclusions at the level of evidence you actually have, and **state the conditions
under which they hold.**

### 7.5 Eventually-consistent storage with no consistency signal
This is the subtle one. If your file store syncs between a cloud copy and a local copy, **reads can
lag writes by minutes and can return states older than ones you already observed.** Every read
reports success. Nothing distinguishes a stale read from a current one.

Observed on a single file across twelve minutes: visible size went 12,636 → 10,898 → 12,636 →
14,627 across four commits. Non-monotonic, out of order with the writes, each intermediate reading
looking authoritative.

Two consecutive wrong diagnoses followed — "the write was reverted," then "the remediation
destroyed the previous version" — and both writes had in fact landed. **The only real data loss was
caused by remediating failures that had not occurred.**

Rules that follow:

1. **A byte count is not evidence of content.** Verify by reading the text.
2. **Never rebuild on a base you have not just verified.**
3. **Prefer "I am early" to "it broke."** Wait and re-read before concluding loss. The cheap error
   is waiting; the expensive error is remediating.
4. **Do not chain edits.** One edit, let it settle, verify, then consider another.
5. **When in doubt, write an addendum instead of editing.** File *creation* cannot race;
   *revision* can.

### 7.6 The general shape
Every failure above has the same structure: 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. The
memory system's own plumbing is not exempt from the problem the memory system exists to solve.

**Design implication:** record corrections in-band. When something in the memory turns out to be
wrong, do not silently overwrite it. Write the correction *and* a note that the earlier version was
wrong, with the date. The correction log is the most valuable section in the long-term file,
because it is the only part that teaches future sessions where this system's judgment fails.

---

## 8. Verification checklist

After building, confirm each of these by actually checking, not by assuming:

- [ ] All files exist in the expected folder, listed from the store itself.
- [ ] Each file's content reads back correctly — **read the text, not the file size.**
- [ ] 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 index's read protocol explicitly says to ignore `absorbed/`.
- [ ] Capability probe results from §0 are recorded in the long-term file, with a date.
- [ ] If a second channel exists, a full round trip has been verified: write, wait, read back.

---

## 9. What to watch over the following weeks

**The failure mode of every memory system is that short-term never gets pruned.** Promotion feels
productive; deletion does not. `02-short-term.md` will look healthy for weeks while quietly
becoming a second long-term file with worse organization, and the context cost grows every session.

The `-> drop-from-short` disposition exists for exactly this. If several absorptions pass without
using it, that is the signal — not a sign that nothing has expired, but that nothing is being
retired. Audit short-term explicitly on a schedule and ask of each entry: *is this still true, and
does it still change what I would do?* If not, drop it.

Second thing to watch: **whether the correction log ever gets entries.** A memory system that never
records being wrong is not one that is never wrong. It is one that is not noticing.

---

## 10. Adapting to other backends

The architecture is storage-agnostic. What changes per backend:

| 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 here, and history is free — the correction log is partly redundant with `git log`, though an in-file log is still more legible to an assistant. |
| Plain synced folder | Path | No IDs available; accept path fragility and re-verify listings more often. |

If your store offers no stable identifier, address by path and **compensate by verifying the
listing at the start of every session** rather than trusting the index's pointers.

---

## Provenance

Derived from a working build performed in a single session, including its mistakes. Every rule in
§7 corresponds to a failure that actually occurred. The architecture originated with the user who
commissioned it; this document generalizes it for reuse.
