Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,11 @@
*.sh text eol=lf
.githooks/* text eol=lf
.githooks/*.d/* text eol=lf

# agent-memory — archive files are append-mostly cold storage (review sweeps append at
# EOF), so let git union-merge them instead of raising spurious add/add conflicts
# (v4.39.0). Safe here because appends dominate; the one wrong case — a reactivation's
# removed lines resurrected by the other branch — is caught deterministically by
# memory-lint ([both] / [over-archived] ERRORs). Live memory files (continuity.md,
# open-threads/) deliberately do NOT get union: there a conflict is signal (MERGE.md).
memory/archive/*.md merge=union
35 changes: 35 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
> introduced after 3.0.0 shipped), organized by capability rather than by individual
> commit. The capability ladder matches `VERSION` and `UPGRADE.md`.

## Version 4.39.0, 9/1/2026

> **Merge-scale memory: threads as files (MINOR).** As team adoption grew, `memory/continuity.md`
> merge conflicts became regular business — concentrated in `## Open Threads` (multi-line blocks
> appended and edited at one anchor) and the `last_session` scalar (bumped by nearly every
> session). This release removes those conflict surfaces structurally, with no merge-time
> machinery (design record: `docs/DESIGN-merge-scale.md`). It closes part of the `bp-multi-user`
> Blueprint gap: simultaneous contributors, hardened rather than assumed.
>
> - **One thread per file** — `memory/open-threads/thread-<id>.md`; filename = the thread's kebab
> fact id, content = exactly the bullet block that previously sat in continuity. Parallel work
> on *different* threads cannot conflict (different files); both sides editing the *same*
> thread conflicts per-file — the `MERGE.md` Tier 2 human gate, preserved by design. No index
> file: the directory is the index, like `sessions/`. Decay/pinning/supersession rules are
> unchanged; only the location moved.
> - **`last_session` dropped** from Project State — fully derivable (newest `sessions/` filename;
> the agent name is that log's `**Agent:**` header) and the most frequent scalar conflict.
> - **Archive files union-merge** — `memory/archive/*.md merge=union` in `.gitattributes`
> (git-native, no driver, no per-clone registration); the one wrong case (a reactivation's
> removal resurrected) is caught deterministically by `[both]` / `[over-archived]`.
> - **Reviews run serialized** (`REVIEW.md`): up-to-date default branch, committed promptly.
> - **Scripts:** `memory-lint`, `refresh-metadata`, and `archive-fact` treat thread files as
> fact surfaces (refresh edits footers in place — filenames never churn; the sweep moves a
> thread's block to the quarter archive and deletes the file). New lint checks:
> `[thread-file]` (filename = footer id; one block per file), `[duplicate-id]` (an id exists
> exactly once across the live layer — the silent-fork backstop), and `[duplicate-state-key]`
> (a Project State scalar set twice — **absorbed from PR #27, credit: Roland Heusser**, whose
> field artifact and merge-rehearsal test pattern also shaped this release; the PR's merge
> driver itself was closed after review findings, recorded in the design doc).
> - `tests/test_thread_layout_merge.sh` pins the merge contract with real git merges — 4 cases
> including a mutation check (stripping the union attribute must restore the conflict).
> - Suites: memory-lint 67 ×2, refresh-metadata 6 ×2, archive-fact 9 ×2, thread-layout merge 4.
> - Protocol text changed (open-threads read/create steps; `last_session` derivation) → ships
> the mandated Semantic steps row, plus the thread-migration semantic step for installed repos.

## Version 4.38.1, 8/25/2026

> **Scanner-neutral guidance constant (PATCH).** An enterprise security pipeline (Snyk) in
Expand Down
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ AI-enabling another repository.

The protocol and core memory files are imported below, so they are structurally present at
session start (presence is guaranteed; *attending* to them is still the protocol). Imports
can't express dynamic paths — still scan the newest 2–3 logs in `memory/sessions/` per the
protocol.
can't express dynamic paths — still list `memory/open-threads/` (read the unchecked
thread files) and scan the newest 2–3 logs in `memory/sessions/` per the protocol.

@AGENTS.md
@memory/PROTOCOL.md
Expand Down
22 changes: 14 additions & 8 deletions DECAY.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@

## 1. Fact metadata

Every fact in `memory/continuity.md` carries an HTML-comment footer. Invisible
when rendered, readable and editable by any agent or human, diff-friendly.
Every fact carries an HTML-comment footer. Invisible when rendered, readable and
editable by any agent or human, diff-friendly. Facts live on two surfaces that these
rules treat identically: `memory/continuity.md`, and — for Open Threads — one file per
thread under `memory/open-threads/` (`thread-<id>.md`, filename = the fact id;
v4.39.0, so concurrent thread work merges without conflict — see `.agent/schema.md`).

```markdown
- POST-only for mutations, no PUT/PATCH (legacy decision, do not change)
Expand All @@ -27,7 +30,7 @@ when rendered, readable and editable by any agent or human, diff-friendly.

| Field | Set | Recomputed at review? |
|---|---|---|
| `id` | once at creation; kebab-case, unique within the file; never changes | no |
| `id` | once at creation; kebab-case, unique across continuity + thread files; never changes | no |
| `created` | once at creation (date the fact entered memory) | no |
| `last_used` | date of the most recent session that referenced the id | **yes** |
| `uses` | count of sessions that referenced the id | **yes** |
Expand All @@ -50,8 +53,10 @@ rows above). `id` and `created` are immutable. Ordinary facts are born `working`

### Assigning an id
Lowercase, hyphenated, derived from the fact's gist (`webhook-fire-forget`,
`drizzle-over-prisma`). Unique within `continuity.md`. Once assigned it is
permanent — it is the handle that session logs use to reference the fact.
`drizzle-over-prisma`). Unique across the live layer — `continuity.md` and every
`memory/open-threads/thread-<id>.md` (`memory-lint` flags a `[duplicate-id]`). Once
assigned it is permanent — it is the handle that session logs use to reference the
fact, and for a thread it is also the filename.

---

Expand Down Expand Up @@ -258,9 +263,10 @@ Everything above is *backward*-looking — it keeps memory faithful to what happ
*intended*. Full design: `docs/DESIGN-vbdi-lifecycle.md`. The rule-level essentials the
memory layer enforces:

- **The primitives.** *Current State* = `continuity.md` (read at session start). *Vision* =
`memory/vision.md` (the target; `core`, invariant-verified). *Blueprint* = typed
`(blueprint)` Open Threads = the Vision↔Current-State gap. *Design* = Key Decisions /
- **The primitives.** *Current State* = `continuity.md` + the Open Thread files (read at
session start). *Vision* = `memory/vision.md` (the target; `core`, invariant-verified).
*Blueprint* = typed `(blueprint)` Open Threads (one file each under
`memory/open-threads/`) = the Vision↔Current-State gap. *Design* = Key Decisions /
Architectural Invariants (and, **optionally**, a human-facing `docs/arch-decisions/ADR.md` decision log
— Architecture Decision Records, read on demand, never in the per-session path; its
supersede/deprecate-never-delete lifecycle mirrors §9, and — once the log exists — is **kept in
Expand Down
42 changes: 23 additions & 19 deletions ENABLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -342,8 +342,8 @@ From this analysis, determine:
(`pom.xml` → `<version>`, `package.json` → `"version"`, `Cargo.toml` →
`version =`, `pyproject.toml` → `version =`, `*.gemspec` → `spec.version`).
If README, docs, comments, or other files reference a *different* version
string, **do not fix the drift** — log it as an Open Thread in
`memory/continuity.md`:
string, **do not fix the drift** — log it as an Open Thread
(`memory/open-threads/thread-….md`):
`- [ ] Version drift: build manifest is X.Y.Z but <file(s)> reference a different version — verify and align`
Resolving drift is the user's responsibility, not the enablement step.
8. **Hosting forge** — GitHub | GitLab | Azure DevOps | unknown (from the Structure-signals
Expand Down Expand Up @@ -408,7 +408,7 @@ Extract the durable, project-defining facts and feed them into the Step 5 seedin
(and seed **Architectural Invariants** in `continuity.md` from explicit
"must / never" rules; record an `(ADR-…)` cross-link only if an ADR log exists).
- Current goals, roadmap, in-flight work, kanban "in progress" / decision-log open
items → **Open Threads** in `continuity.md`, and the aspiration → the
items → **Open Threads** (one `memory/open-threads/thread-….md` file each), and the aspiration → the
**Current-state context** of `memory/vision.md` (5g) — still never *fabricate* the
target.
- Newcomer-facing knowledge → candidate **smoke-test questions** (5f).
Expand Down Expand Up @@ -465,24 +465,23 @@ Fill in:
- **`## Stack & Tools`** — the canonical live home for the current language version,
dependencies, and tool versions (the precise facts `instructions.md` defers here)
- Today's date as `last_enabled`
- `last_session`:
- If migrated from vendor history, use the most recent session date from those logs
- Otherwise point it at the **first enable session log** (Step 5c) — the enable *is* the
first session: `<today> | agent: <your agent name> (<the 5c log's filename stem>)`, e.g.
`2026-08-06 | agent: Claude Code (2026-08-06-142530)`. Fill it when you write that log —
the same moment its stem becomes the seeded facts' `origin`. Never leave `(none yet)`:
it is false the instant the enable completes, and it defeats the multi-agent continuity
check that reads this field (`memory/PROTOCOL.md` → Activate the session).
- `last_review`: `(none yet)`
- There is **no `last_session` field** (v4.39.0) — the newest `memory/sessions/` log *is*
the last session (its `**Agent:**` header names the agent); the Step 5c enable log
satisfies the multi-agent continuity check from day one
- **repo:** write the path `~`-relative (e.g. `~/projects/foo`) — never an absolute
`/Users/<name>/…` (or `/home/<name>/…`) path. `memory/` is committed to git and
shared across the team, so absolute home paths would leak the enabling user's
username to everyone.
- **Architectural Invariants:** seed from hard constraints in the build manifest /
README / `instructions.md` (things that must never change — e.g. "POST-only API",
"no runtime deps"). If none are obvious, remove the section. Facts here never decay.
- Open Threads: include any TODOs surfaced during analysis or migration
- **Greenfield only:** seed a `- [ ] Greenfield — no code yet` Open Thread listing what to
- Open Threads: create `memory/open-threads/` and write any TODOs surfaced during
analysis or migration as **one file per thread** — `thread-<id>.md`, whose content is
exactly the thread's bullet block with its footer (see `.agent/schema.md`); continuity's
`## Open Threads` section carries only the template's pointer note, never thread bodies
- **Greenfield only:** seed a `- [ ] Greenfield — no code yet` Open Thread (its own
`thread-…` file) listing what to
record as the first code lands: the stack in `## Stack & Tools`, coding conventions,
Architectural Invariants, **and the stack's build-output `.gitignore` entries** (apply the
Step 7 stack-aware seed table then — at enable there is no stack to seed)
Expand Down Expand Up @@ -515,9 +514,9 @@ Apply the **redaction rule** (`memory/PROTOCOL.md` → Write the session log): n
into the log — redact any pasted command output to `(REDACTED)` before persisting.

This makes the enable traceable, lets the facts you seed in 5b set a real `origin`, and
supplies the value 5b's `last_session` points at (the enable *is* the first session — never
leave `(none yet)`). (A `.gitkeep` is then unnecessary — the directory is non-empty; only add
one if for some reason no first log is written.)
is what the multi-agent continuity check reads as the last session (the enable *is* the
first session). (A `.gitkeep` is then unnecessary — the directory is non-empty; only add
one if for some reason no first log is written; same for `memory/open-threads/`.)

### 5d. `.agent/schema.md` [reconcile-covered]

Expand Down Expand Up @@ -568,7 +567,7 @@ target is the human's to set (same principle as User Preferences: never infer).
still the human's to confirm, never inferred).
- Leave the **target, success criteria, and non-goals as prompts** (the template's `(…)`
placeholders) — do not infer the aspiration. Keep the ⚠️ DRAFT banner.
- Raise a human-gate Open Thread in `memory/continuity.md`:
- Raise a human-gate Open Thread (`memory/open-threads/thread-vision-bootstrap.md`):
`- [ ] (vision-bootstrap) Confirm the Vision in memory/vision.md — set the target / success criteria / non-goals; then derive the Blueprint.`
- **Do not derive the Blueprint yet** — Blueprint gaps depend on a confirmed target. The
gate thread carries that forward. Until the Vision is confirmed, VBDI drift-detection is
Expand Down Expand Up @@ -960,8 +959,13 @@ The executable scripts (`*.sh`), git hook dispatchers (`.githooks/*`), and hook
*.sh text eol=lf
.githooks/* text eol=lf
.githooks/*.d/* text eol=lf
memory/archive/*.md merge=union
```

The `merge=union` rule (v4.39.0) lets git auto-merge concurrent appends to the
append-mostly archive files; live memory files deliberately never get union (a conflict
there is signal — `MERGE.md`).

Apply additively (same discipline as `.gitignore`): **no `.gitattributes`** → copy
`templates/.gitattributes` verbatim; **exists** → add only the LF rules not already present
(de-duplicate; never remove/reorder the user's entries). After adding, run `git add --renormalize .`
Expand Down Expand Up @@ -1025,7 +1029,7 @@ describe what was intended.
6. **Vision bootstrapped (not fabricated).** `memory/vision.md` exists with the
Current-state context filled and the target / success criteria / non-goals left as
prompts. The ⚠️ DRAFT banner and the `(…)` prompts are **intentional** — not unfilled
placeholders. A `- [ ] (vision-bootstrap)` Open Thread is present in `continuity.md`,
placeholders. A `- [ ] (vision-bootstrap)` Open Thread file is present in `memory/open-threads/`,
and no Blueprint gaps were derived yet (they await the confirmed Vision).

7. **Skills installed + promoted + adapters complete.** Confirm the **built-in skills**
Expand Down Expand Up @@ -1056,7 +1060,7 @@ describe what was intended.
(`instructions.md` / `continuity.md`) and **not** in a vendor steering file. Missing log ⇒
write it now (Step 5c).

Log any issue you cannot fix as an Open Thread in `memory/continuity.md` and
Log any issue you cannot fix as an Open Thread (`memory/open-threads/thread-….md`) and
note it in the report.

---
Expand Down
4 changes: 2 additions & 2 deletions GEMINI.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ AI-enabling another repository.

The protocol and core memory files are imported below, so they are structurally present at
session start (presence is guaranteed; *attending* to them is still the protocol). Imports
can't express dynamic paths — still scan the newest 2–3 logs in `memory/sessions/` per the
protocol.
can't express dynamic paths — still list `memory/open-threads/` (read the unchecked
thread files) and scan the newest 2–3 logs in `memory/sessions/` per the protocol.

@./AGENTS.md
@./memory/PROTOCOL.md
Expand Down
7 changes: 7 additions & 0 deletions MANIFEST.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ the sanctioned contributor/consumer fork structure (v4.38.0 — see the AGENTS.m
| memory/instructions.md | templates/memory/instructions.md | seed-generate | all | step:5a |
| memory/continuity.md | templates/memory/continuity.md | seed-generate | all | step:5b |
| memory/sessions/ | templates/memory/sessions/.gitkeep | seed-generate | all | step:5c |
| memory/open-threads/ | templates/memory/open-threads/.gitkeep | seed-generate | all | step:5b |
| memory/decay-policy.md | templates/memory/decay-policy.md | seed-generate | all | step:5e |
| memory/smoke-test.md | templates/memory/smoke-test.md | seed-generate | all | step:5f |
| memory/vision.md | templates/memory/vision.md | seed-generate | all | step:5g |
Expand Down Expand Up @@ -124,6 +125,10 @@ Row notes (the table stays machine-lean; nuance lives here):
- **memory/sessions/** — "present" means the directory exists with at least one file; the
first enable session log (Step 5c) is what normally satisfies it (`.gitkeep` only as a
fallback when no log is written).
- **memory/open-threads/** — one Open Thread per `thread-<id>.md` file (v4.39.0, the
merge-scale layout). "Present" means the directory exists with at least one file; the
threads Step 5b seeds (at minimum the `(vision-bootstrap)` gate thread) normally satisfy
it, `.gitkeep` only as a fallback. Thread bodies never live in `continuity.md`.
- **.gitlab-ci.yml** — seed-copy installs the canonical root file (include + the
`workflow:rules` guard) only when the target has none. A pre-existing root file is never
edited mechanically: the `wire` attr sends the agent to `ENABLE.md` Step 6 (add-only
Expand Down Expand Up @@ -159,6 +164,8 @@ in the named `UPGRADE.md` rung. Mode B = reconcile + the applicable rows + stamp
| 4.36.0 | 4.35.0 -> 4.36.0 | PRE-APPLY: If a hook entrypoint carries locally owned behavior (not the stock agent-memory monolith), move it into a differently named executable fragment (00- to 49- before agent-memory, 51- to 99- after) before accepting the dispatcher re-copy; never overwrite a differently named fragment; if local and agent-memory logic are interleaved, stop for a human decision. |
| 4.37.0 | 4.36.0 -> 4.37.0 | PRE-APPLY: Before any reconcile apply, prove recovery of the existing AGENTS.md, merge its local directives and any existing protocol into the target-only memory/PROTOCOL.md with provenance and authority checks, revalidate source hashes, then install the exact one-line shim. Stop before every write on an unsafe merge. |
| 4.38.0 | 4.37.0 -> 4.38.0 | Protocol text changed (consumer step-0, terse close records, optional ready-to-work checkpoint): re-copy a target memory/PROTOCOL.md that is still byte-identical to the 4.37.0 template; arbitrate a customized one per ENABLE.md 5i (add the new sections, never drop local directives). Optionally add closed_narrative_max_lines: 150 to memory/decay-policy.md (lint falls back to the default when absent). |
| 4.39.0 | 4.38.1 -> 4.39.0 | Thread migration (merge-scale layout): create memory/open-threads/ and move every Open Thread block out of memory/continuity.md into its own thread-<id>.md (verbatim cut-paste, checkbox + body + footer intact; mint a kebab id + footer first for a legacy thread that lacks one); replace continuity's Open Threads section body with the template's pointer note; delete the last_session line from Project State (derivable from the newest session log). Run memory-lint after - [thread-file]/[duplicate-id] gate the migration. |
| 4.39.0 | 4.38.1 -> 4.39.0 | Protocol text changed (open-threads read/create steps, last_session derivation): re-copy a target memory/PROTOCOL.md still byte-identical to the 4.38.0 template; arbitrate a customized one per ENABLE.md 5i (add the new wording, never drop local directives). |

## Tool-only (never installed)

Expand Down
Loading
Loading