# Strata

> 3-tier project memory (hot/warm/cold) with a unified issues backlog, operation-keyed learnings, generated indexes, immediate capture, and one-shot project initialization under .strata/. Invoke with no argument for rule lookup, "capture" to save a fresh finding/gotcha right away, or "init" to scaffold or migrate existing flat/0.0.1/0.0.2 memory without losing provenance. Used by /strata:save, /strata:load, and /strata:capture as the authoritative source of tier definitions and routing rules.

- Skill: `belousov-petr/strata` (Agent Skill, multi-file: 22 files)
- Install (CLI): `npx skillmds@latest add belousov-petr/strata`
- Raw SKILL.md: https://api.skillmd.com/api/skills/belousov-petr/strata/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Product & Planning
- Author: belousov-petr (https://skillmd.com/u/belousov-petr)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/belousov-petr/strata

---


# Strata — universal project memory

The **single source of truth** for the strata 0.0.3 pattern. Project memory is owned by the repo under `.strata/`, not by Claude, Codex, Gemini, or any other tool; `AGENTS.md`/`CLAUDE.md` are thin adapters pointing at `.strata/MANIFEST.md` and hold no separate memory.

This file is operational rules only. Depth lives elsewhere — link, don't restate:
**how it all works** → [docs/DESIGN.md](https://github.com/belousov-petr/strata/blob/main/docs/DESIGN.md) · **why** → [docs/decisions/](https://github.com/belousov-petr/strata/blob/main/docs/decisions/README.md) · **upgrades** → [MIGRATIONS.md](https://github.com/belousov-petr/strata/blob/main/MIGRATIONS.md)

Three entry points: **rule lookup** (default — commands read §§1–7 for decisions), **`capture`** (write a fresh finding/gotcha before context decays, §5), and **`init`** (scaffold or migrate a project, §8).

**Invocation.** The skill's canonical name is `strata`; Codex and other tools call `Skill(name='strata', …)`. Installed as the Claude Code plugin, commands and skill are namespaced under the plugin name — the commands are `/strata:init`, `/strata:save`, `/strata:load`, `/strata:capture`, and the skill is `Skill(name='strata:strata', …)`. Slash-command references below use the plugin form.

---

## 1. Tiers and stores

| Tier | Where | When loaded |
|---|---|---|
| **Hot** | `.strata/memory/` + `.strata/issues/ACTIVE.md` | Session start |
| **Warm** | `.strata/docs/` + individual `issues/*.md` | On demand, by task |
| **Cold** | `.strata/memory/archive/` + `.strata/issues/archive/` | Explicit history search only |

One routing key per store: `project_state.md` = recency ("what was I doing"), `learnings/` = operation ("what do I know about doing this"), `issues/` = status ("what work exists"), `docs/` = topic ("what is true and why"), `archive/` + `action_log.md` = time ("what happened"). Derivable knowledge (code, `git log`, folder structure) gets **no store**.

**Budgets (hard):** `MEMORY.md` ≤80 lines · `project_state.md` ≤200 lines, current + last completed session only. Warm and cold are unbudgeted — depth is free off the hot path.

**Contract file.** `.strata/MANIFEST.md` (with `layout_version: 3`) is the *only* per-project file stating structure and routing. `MEMORY.md` is a pure index: live pointers + the generated rules-by-trigger table — the **hot subset** of learnings (§4); the complete list is `learnings/INDEX.md`. Never re-add routing tables to it.

**Portability.** Project-relative paths only (`.strata/...`); no machine-specific absolute paths, usernames, or single-OS commands in memory — give PowerShell and POSIX variants when a saved command matters on both.

## 2. Routing — where new knowledge goes

| You produced / discovered | Write to | When |
|---|---|---|
| Finding, bug, improvement, debt, task, feature, initiative | `issues/<id>-<slug>.md`, status `open`, full rationale + diagnostics | **Immediately, mid-session** |
| Deferred work | same file, status `parked` + `revive-when:` | at capture or triage |
| Behavioral lesson (worked or burned you) | `memory/learnings/<slug>.md` | at `/strata:save`, `/strata:capture`, or immediately if hard-won |
| Shipped decision with non-obvious rationale | `docs/decisions/ADR-NNNN-<slug>.md` + source → `memory/archive/source-adr-NNNN-*` | **immediately when settled** (§5), or at `/strata:save` |
| Product requirement / PRD | `docs/product/<slug>.md` | when it exists |
| How a subsystem works | `docs/architecture/<slug>.md` + row in `docs/ARCHITECTURE.md` | when it stabilizes |
| Stable fact (paths, schemas, APIs, conventions) | `docs/reference/<slug>.md` | on second lookup |
| Procedure, runbook, incident pattern | `docs/ops/…` (`incidents/<symptom>.md`, `release-rollback.md`) | when it changes |
| Session narrative | `memory/project_state.md`, rollover → `archive/` | at `/strata:save` |
| Completed action with external artifact (PR, email, durable URL) | `memory/archive/action_log.md` append | at `/strata:save` |
| A doc this session made wrong | fix in place; *retired* docs → `docs/_archive/` | at `/strata:save` |

**Never store:** secret values (env-var *names* only); anything derivable from code/`git log`; raw transcripts, full stack traces, command dumps — concise root cause + evidence instead; shipped rationale with no next step outside an ADR.

**Discriminators:** a *rule* fires at an operation → learning; a *procedure* is steps you execute → ops; a *fact* is something you look up → reference. An *issue* can close; a *learning* outlives every issue that taught it. *State* is where you stand; anything with its own lifecycle is an issue.

## 3. Issues — the single backlog

States and types (canonical, defined here and in MANIFEST/DESIGN, reused verbatim):

- **Types:** `bug | improvement | debt | task | feature | initiative`
- **Statuses:** `open | in-progress | parked | resolved | wont-fix`
- **Severity:** `high | med | low`

Operational rules:

1. **Capture immediately and completely.** The moment a finding surfaces mid-task: write `issues/<id>-<slug>.md` (id `YYYYMMDD-NN`) from `_TEMPLATE.md` — What/Why, and for bugs Tried/Error/Hypothesis/Repro *at capture time* — status `open`, then return to the task. Compaction cannot eat what is on disk. Don't fix it unless it blocks the current task.
2. **Status changes are frontmatter edits.** No file moves while an item is alive.
3. **`parked` requires a concrete `revive-when:`** trigger; `/strata:save` checks triggers against the session and revives matches.
4. **Closing** fills **Resolution** (link the ADR/learning if the close produced durable knowledge); `resolved`/`wont-fix` files move to `issues/archive/` at the next `/strata:save`.
5. **Dedup at triage:** fold new evidence into an existing item instead of filing a near-duplicate.
6. **Views are generated, never hand-edited:** `ACTIVE.md` (in-progress), `OPEN.md` (open, by area, severity first), `PARKED.md` (+triggers) — regenerated from frontmatter at every `/strata:save`.

## 4. Learnings — operation-keyed behavioral memory

One lesson per `memory/learnings/<slug>.md`:

```
---
trigger: <when this applies — operation-keyed>
applies-when: <glob/area, optional>
origin: success | failure
hot: <true|false, optional — true loads the rule into MEMORY.md every session>
---
**Lesson:** <1–3 sentences>
```

- Capture **failures and successes** — a pitfall with its counterfactual fix is the highest-value item.
- `learnings/INDEX.md` (every learning) and the `MEMORY.md` rules-by-trigger table (the **hot subset**) are regenerated from frontmatter at `/strata:save`.
- **Hot subset.** The MEMORY table lists learnings marked `hot: true` — the broad/frequent rules worth loading every session. *Graceful default:* a project with **no** `hot:` flag anywhere keeps all learnings in the table (legacy, unchanged); the first `hot:` flag opts it into filtering. New learnings default `hot: false` (INDEX-only), so the hot table stays bounded as learnings accumulate — promote to `hot: true` only when a rule proves broadly triggered. Never auto-pick the set; `/strata:save` only *flags* an over-budget table and suggests curating (§6E).
- **Retrieval discipline:** consult the trigger table, open the one or two matching files at operation time. Never bulk-read the folder; never re-read at load.
- If a lesson needs more than 3 sentences, the surplus is reference or ops material — route it there.

## 5. Immediate capture — before context decays

Invoked via `Skill(name='strata', args='capture')`, `/strata:capture`, or any moment something worth keeping appears mid-task. Write every important moment to its home the instant it is clear, so the docs grow as you build instead of waiting on session end. Spend tokens now; a compacted-away diagnosis or rationale is more expensive than a small file write.

**Trigger:** a failed command/tool/API, retry loop, or workaround; surprising repo behavior or a brittle environment step; a bug, finding, or doc drift; a rule future agents should know before an operation; **a decision you settled** (with the rationale and the options you rejected); **a change of direction** that overturns a prior decision or spec; **how an outside system actually works**; or **a requirement, or the reasoning behind it**, worth a spec or PRD.

**Route** (write the home for what you captured; `/strata:save` is the safety net that files anything you miss):

- Closeable work -> `issues/<id>-<slug>.md` from `_TEMPLATE.md`, with `status: open` or `in-progress`, severity/area, What/Why, Tried/Error/Hypothesis/Repro, evidence, and next action.
- Reusable behavior -> `memory/learnings/<slug>.md`, with operation-keyed `trigger:`, optional `applies-when:`, `origin: success | failure`, and a 1-3 sentence lesson.
- Settled decision with non-obvious rationale -> `docs/decisions/ADR-NNNN-<slug>.md` (NNNN = highest existing + 1, the §6 collision scan), status `proposed`/`accepted`, with the considered options. A change of direction supersedes the old ADR per `docs/decisions/README.md` — new ADR, old one marked superseded, never an in-place rewrite.
- Durable knowledge -> the warm docs: a runbook or how-a-system-works under `docs/ops/` or `docs/architecture/`; a requirement or its reasoning under `docs/product/`.
- Several at once when one moment is more than one of these: e.g. a fixable bug (issue) that also taught a rule (learning).
- Flat mode -> append a concise "Fresh capture" entry to `.strata/memory/project_state.md` under Findings/Gotchas/Open Items.

**Write discipline:** targeted grep first to avoid duplicates; fold new evidence into an existing file when it matches. Keep evidence concise; no raw transcript dumps, full logs, or secret values. Capture writes the source file only — do not regenerate the views or the `ARCHITECTURE.md` index; `/strata:save` does that and finalizes anything left as a draft.

**Report and resume:** say which file(s) were written or updated, then continue the original task unless the capture reveals a blocker.

The hook may have pre-logged failures to the inbox; promote them per §5a.

### 5a. Inbox — deterministic capture backstop

The capture-guard hook (ADR-0011) auto-logs failed tool results to
`.strata/inbox/captures.jsonl` the moment they happen, so evidence survives
compaction without the agent acting. Each line is one redacted raw stub
`{ts, event, tool, signal, command, snippet, h}` — **raw evidence, not finished
memory.** The inbox is git-ignored transient scratch.

**Promote-and-clear (the read side, deterministic — no extra agent turn):**
- `/strata:capture` and `/strata:save`: read `.strata/inbox/captures.jsonl`,
  fold each real failure into an issue/learning (dedup against the backlog,
  drop secrets/stack-traces per §2), then **truncate** `captures.jsonl` and
  delete `.strata/inbox/.cursor.*.json`.
- `/strata:load`: report the un-promoted count in the orientation.
- A typo or already-known failure is dropped, not promoted. Promotion is the
  authoritative dedup; the hook's append-time window is only a first pass.

## 6. `/strata:save` — preview-execute contract

**A — Scan** the session into buckets: resumption point · issue events (new captures — verify the mid-session ones hit disk; status changes; resolutions) · learnings (both origins) · ADR candidates (file any not already written mid-session) · durable-doc impact · external completions · rollover (state beyond current + last completed) — also promote any un-promoted `.strata/inbox/` stubs (§5a) and clear the inbox.

**B — Preview**: ONE block listing every proposed change under `NEW FILES / APPENDS / UPDATES / MOVES / DELETIONS (section-only) / REGENERATED / SKIP`, then continue automatically. The preview is an audit record, not a confirmation gate. Empty plan → "no changes proposed", stop.

**C — Safeguards** (before preview):

- **Git-dirty check** — files to MOVE or DELETE-FROM with uncommitted edits go under SKIP, untouched.
- **ADR collision guard** — next number = highest existing + 1 (scan `docs/decisions/`).
- **Section-only deletions** — never remove whole files without explicit instruction.
- **Idempotent** — re-run with no new work proposes nothing.

**D — Execute** immediately after the preview, in order: writes → appends → updates (frontmatter/status) → moves → deletions → clear inbox (truncate captures.jsonl + drop cursor files — the physical clear; promotion happens in step A) → **regenerate all views last** (`ACTIVE/OPEN/PARKED`, `learnings/INDEX`, MEMORY trigger table; sync `MEMORY.md` pointers + `ARCHIVE.md`).

**E — Verify & report**: budgets hold (§1); views match frontmatter; resumption point actionable; hot memory and touched warm docs agree. **If the regenerated `MEMORY.md` would breach ≤80, don't auto-trim — report it and suggest curating the hot subset** (opt in by flagging the most-triggered learnings `hot: true`; the rest stay in `INDEX.md`, §4). Then a concise summary of what went where.

## 7. `/strata:load` — orientation contract

Load order (stop early if the task is already clear):

1. `.strata/MANIFEST.md` (check `layout_version: 3`; a legacy `strata_version: 0.0.3` stamp or any other mismatch → `MIGRATIONS.md`, stop)
2. `.strata/memory/MEMORY.md`
3. `.strata/issues/ACTIVE.md`
4. `.strata/memory/project_state.md` (current + last completed only)

On demand only: `OPEN.md` by area · the specific issue being resumed · warm docs the task touches. **Never auto-load:** learnings files, ADRs in bulk, item files in bulk, `archive/`, `action_log.md`.

**Verify against git** before presenting: `git status` (do listed uncommitted changes exist?), `git log --oneline -5` (commits since last session?), spot-check referenced paths and issue ids. State is a hint; the repo is truth; report conflicts, never silently absorb them.

**Present** ≤6 lines: last session · next up (issue id) · active count · prerequisites · fired parked-triggers · inbox un-promoted count · drift. Then ask: continue or something else?

## 8. `init` — scaffold or migrate a project

Invoked via `/strata:init` (Claude Code), `Skill(name='strata', args='init')` (Codex and other tools), or an explicit ask to set up project memory.

**Preconditions:**

1. CWD is the target project root, inside a git repo (`git rev-parse --is-inside-work-tree`; error out if not).
2. **Existing-memory routing.** Detect before writing:
   - Valid current layout (`.strata/MANIFEST.md` with `layout_version: 3`) → refuse: report the existing memory; re-bootstrap requires the user to move/delete it first.
   - Flat mode (`.strata/memory/project_state.md` exists, with no `.strata/MANIFEST.md` and no `.strata/memory/MEMORY.md`) → run the flat→0.0.3 rung in `MIGRATIONS.md`; never overwrite the flat file in place.
   - 0.0.1/0.0.2 fingerprints — `.claude/memory/`, `docs/PROJECT-MAP.md`, `.ai/` (or `.ai/MEMORY-MAP.md`), `open_action_items.md`, `project_<slug>.md` memory files, `docs/parked/`, or project files referencing the old `/save-point`//`/load-point` commands → run the matching `MIGRATIONS.md` rung(s), not a fresh scaffold.
   - Mixed or partial `.strata/` state that is not the flat fingerprint → stop, report every fingerprint, and ask the user to choose repair/migration; never guess and never overwrite.

**Questions** (single `AskUserQuestion`): project name; project type — "Code project (full `.strata/docs/` taxonomy)" vs "Knowledge/ops project (memory + issues; docs grow later)". During migration, derive these from existing memory when obvious and ask only for missing values.

**Fresh files to write** — templates from this skill's `templates/`, substituting `{{PROJECT_NAME}}` and `{{INIT_DATE}}` (today, `YYYY-MM-DD`) in **every** copied file:

| Template | Target | Condition |
|---|---|---|
| `templates/AGENTS.md` | `AGENTS.md` | only if absent |
| `templates/CLAUDE.md` | `CLAUDE.md` | only if absent |
| `templates/MANIFEST.md` | `.strata/MANIFEST.md` | always |
| `templates/memory/MEMORY.md` | `.strata/memory/MEMORY.md` | always |
| `templates/memory/project_state.md` | `.strata/memory/project_state.md` | always |
| `templates/memory/learnings/{INDEX,_TEMPLATE}.md` | `.strata/memory/learnings/` | always |
| `templates/memory/archive/{ARCHIVE,action_log}.md` | `.strata/memory/archive/` | always |
| `templates/issues/{README,_TEMPLATE,ACTIVE,OPEN,PARKED}.md` | `.strata/issues/` (+ create `issues/archive/`) | always |
| `templates/docs/ARCHITECTURE.md` + `templates/docs/{product,architecture,decisions,reference,ops}/README.md` | `.strata/docs/…` | code projects |
| `templates/inbox/.gitignore` | `.strata/inbox/.gitignore` | always |

Existing adapters are left unchanged and reported as such. Adapters are pointers only — never write project memory into them.

Migration writes may target the same paths, but source memory is archived first. Flat `project_state.md` becomes `.strata/memory/archive/source-flat-project-state-<date>.md` before a new hot `project_state.md` is written; extracted issues, learnings, and ADRs cite that archive path or the archived section heading. Ambiguous content stays in the archive and gets a triage issue, not a silent drop.

**Report** exactly:

```
strata 0.0.3 initialized in <cwd>.

Created:
- .strata/MANIFEST.md (contract, layout_version: 3)
- .strata/memory/ (MEMORY.md index, project_state.md, learnings/, archive/)
- .strata/issues/ (README, _TEMPLATE, ACTIVE/OPEN/PARKED views, archive/)
- .strata/inbox/ (git-ignored capture scratch)
<- .strata/docs/ (ARCHITECTURE.md + product/architecture/decisions/reference/ops) — code projects>
- AGENTS.md / CLAUDE.md adapters that were absent
<- Existing adapters left unchanged: ...>

Next:
- Describe the project in .strata/MANIFEST.md ("What <project> is")
- Work; use /strata:capture for findings/gotchas as they surface
- /strata:save at session end · /strata:load at session start
```

## 9. Versioning and migration

- **Two distinct version numbers, deliberately different formats so they cannot be confused** ([ADR-0013](https://github.com/belousov-petr/strata/blob/main/docs/decisions/ADR-0013-layout-version-integer.md)):
  - **Memory layout** — `layout_version: <integer>` in `MANIFEST.md` frontmatter; a generation counter. This skill writes **`layout_version: 3`** (the generation formerly stamped `strata_version: 0.0.3`; same structure, only the stamp label changed).
  - **Plugin release** — semver via git tags + `plugin.json`/`marketplace.json` (e.g. `0.0.6`), per ADR-0008. A plugin release can ship with no layout change.
- On `init`, any flat/0.0.1/0.0.2 fingerprint — or a legacy `strata_version: 0.0.3` stamp — routes to `MIGRATIONS.md` (detect → gated transform → rollback, per rung) instead of fresh scaffolding. On save/load version mismatch: stop, report, point at `MIGRATIONS.md`. Never double-initialize and never overwrite source memory before archiving it.
- Releases of strata itself: git tags + `CHANGELOG.md` (git-native versioning — no version-archive folders anywhere, one optional `docs/_archive/` for retired docs).

## 10. Common mistakes

| Mistake | Fix |
|---|---|
| Restating routing in commands, adapters, or MEMORY.md | MANIFEST + this skill own it; everything else links |
| Holding a mid-task finding "for save time" | Run `/strata:capture` or write the issue/learning file the moment it surfaces |
| Hand-editing ACTIVE/OPEN/PARKED or INDEX | Edit item frontmatter; views regenerate at save |
| Moving an item file to change its status | Status is frontmatter; files move only on close (→ archive) |
| `parked` without `revive-when:` | A concrete trigger or it isn't parked, it's abandoned |
| Bulk-loading learnings/ADRs/archive at load | Indexes + trigger table exist so you don't |
| Save waits for a y/n gate | One preview block, then execute automatically — invoking `/strata:save` is the confirmation |
| New ADR with a colliding number | Scan `docs/decisions/`, take highest + 1 |
| Capturing "architecture needs cleanup" | Evidence, affected paths, hypothesis, fix direction, acceptance criteria — in the issue |
| `init` over flat or legacy memory | Migrate via `MIGRATIONS.md`; archive source first, then write 0.0.3 files |

## 11. Relationship to other memory skills

`remember:remember` (single handoff note), `atlas-memory` (SQLite + vectors), `agentdb-*` (vector/RL backends) are storage mechanisms and are orthogonal. Strata is the **structural pattern** — where knowledge lives, when it loads, when it moves. They can coexist; strata files stay plain markdown + grep on purpose.

