コンテンツにスキップ

The .reyn/ directory layout

This is the canonical reference for what lives under a project's .reyn/ directory: the five-way classification of every subtree, which subtrees are recovery-core (captured + restored by time-travel), the write-gate rule a workflow author hits, and where a new subsystem should put its data.

.reyn/ holds Reyn's own plumbing under the project root. The organizing principle is ownership + recovery role: Reyn time-travels the state it authors and that affects its in-memory runtime — not the user's project files, and not operator-owned config.

Rewind mechanics (how recovery-core is reconstructed — WAL replay + snapshot generations, seq addressing, rewind-record append, atomicity) live in Time travel. This doc owns what is in .reyn/; that doc owns how rewind works.

Classification

A .reyn/ subtree is recovery-core iff it (1) is authored by the run (agent/runtime, not the operator) and (2) affects in-memory runtime state that recovery reconstructs. Everything else is excluded, by one of four reasons:

Category Handling on rewind / recovery Subtrees
recovery-core captured + restored (reconstructed) state/, config/
persist (knowledge / decisions) survives rewind — never reverted memory/, approvals.yaml
audit (write-only record) kept as a record, never restored events/, traces/, logs/, audit-trail/, tool-results/, media/
cache (derived) rebuilt after restore cache/ (index/, action_index/, registry-cache/, *_cursor)
outside (operator/user-owned) not Reyn-managed for time-travel reyn.yaml, secrets.env, oauth_tokens.json, capability_profiles/

Canonical layout

.reyn/
├── state/                  RECOVERY-CORE — run-authored, reconstructs in-memory state
│   ├── wal.jsonl           the WAL (append-only, seq'd) — the recovery TRUTH
│   ├── tasks.db            the task backend (sqlite)
│   └── budget_ledger.jsonl the cost ledger
├── agents/<name>/state/    RECOVERY-CORE (per-agent) — reconstructed alongside the WAL
│   ├── snapshot.json       the agent's runtime snapshot (a derived projection of the WAL)
│   ├── generations/        snapshot generations (gen-<seq>.json) — the PITR base
│   └── sessions/<sid>/     per-spawned-session snapshot + generations
├── config/                 RECOVERY-CORE — agent-managed registries (reconstructed by replay)
│   ├── mcp.yaml            MCP servers   (mcp_install / mcp_drop_server)
│   ├── cron.yaml           cron jobs     (cron_register / …)
│   ├── hooks.yaml          push hooks    (hooks_add)
│   ├── integrations.yaml   integrations
│   └── index/sources.yaml  index source manifest (index ops)
├── memory/                 PERSIST — agent knowledge; survives rewind, never reverted
├── approvals.yaml          PERSIST — user-authored permission grants; survive rewind
├── events/ traces/ logs/   AUDIT — append-only forensic record; never restored
│   audit-trail/ tool-results/ media/
├── cache/                  DERIVED — rebuilt after restore
│   ├── index/              rag index data (sqlite)
│   ├── action_index/       action-index db
│   └── registry-cache/     mcp registry cache
└── topologies/             RECOVERY-CORE — agent topologies (reconstructed from topology_* WAL)

reyn.yaml, secrets.env, oauth_tokens.json, and capability_profiles/ are operator/user-owned and live under the project root / .reyn/ but are outside Reyn's time-travel — they are never captured or reverted.

Move map (clean break, no migration)

The reorg has no backward-compat shim: old top-level paths simply stop being read/written. Anyone with an older .reyn/ (config files directly under .reyn/, caches mixed in at the top level) should know things moved:

Was Now
.reyn/mcp.yaml, .reyn/cron.yaml, .reyn/hooks.yaml, .reyn/integrations.yaml .reyn/config/<x>.yaml
.reyn/index/sources.yaml .reyn/config/index/sources.yaml
.reyn/index/ (data), .reyn/action_index/, .reyn/registry-cache/ .reyn/cache/…
.reyn/approvals.yaml unchanged (top-level — it is persist, not recovery-core config)

Recovery-core: what the WAL + snapshot generators write

Recovery-core has two tiers — authoritative and derived — both reconstructed by the same rewind path (WAL replay + snapshot generations — see Time travel):

  • Authoritative (the recovery TRUTH — write-gated):
  • .reyn/state/wal.jsonl — the append-only, seq'd WAL: the complete event history everything else is replayed from. Also .reyn/state/tasks.db, .reyn/state/budget_ledger.jsonl.
  • .reyn/config/<x>.yaml — the agent-edited config registries. Each mutation goes through a dedicated op that writes a full-state config generation (seq-keyed, truncation-surviving); the .yaml is materialised from the generation at the target seq on rewind.
  • .reyn/state/agent_identity/<name>@<seq>.json — per-agent identity + frozen spawn lineage, recorded as a full-state generation (seq-keyed, truncation-surviving). The WAL event is dropped below the truncation floor, so rewind reconstructs the ⊆-parent cap from the generation — without it a long-lived agent's child runs un-capped on rewind.
  • Derived (reconstructable from the authoritative state — NOT write-gated):
  • .reyn/agents/<name>/state/: snapshot.json, generations/gen-<seq>.json, sessions/<sid>/…. Runtime snapshots are seq-keyed generations reconstructable from WAL replay (fall back to an earlier generation, or replay from genesis). A corrupted snapshot is recoverable, not data loss — the same reconstructability logic as cache/. Agent-identity and lineage are likewise stored as seq-keyed generation snapshots (truncation-surviving, same generation-store pattern as config). (This is why the write-gate, below, covers only the authoritative tier.)

The recovery-core write-gate (the rule you hit as a workflow author)

A raw file.write to .reyn/config/ or .reyn/state/ is DENIED. The authoritative recovery-core (the WAL at .reyn/state/ + the .reyn/config/ registries — see above) must be mutated through a dedicated op — never a generic file.write — so the change lands in the recovery stream (WAL entry or config generation) and can be reconstructed or reverted on rewind. The directory boundary is the write-gate boundary. (The derived per-agent snapshots under .reyn/agents/<name>/state/ are reconstructable from the WAL, so they are not write-gated — a corrupted snapshot is recoverable, not data loss.)

To change config, call the dedicated op (which writes the .yaml as a new config generation):

  • MCP servers → mcp_install / mcp_drop_server
  • cron → cron_register / cron_unregister / cron_enable
  • hooks → hooks_add
  • index sources → the index ops

approvals.yaml (top-level persist) is likewise write-gated — it is written only via the permission-approval flow (_persist), never a raw file.write. memory/, cache/, and other non-recovery-core .reyn/ paths are ordinary writable zones.

Where does a new subsystem put its data?

Ask the two recovery-core questions:

  1. Is it run-authored AND does it affect in-memory runtime state that recovery reconstructs?recovery-core: put it under state/ (and write it through a WAL-emitting durable path or a dedicated op — never a raw file.write). If it's a config-style registry the agent mutates, put it under config/ and give it a dedicated op that writes a config generation (full-state, seq-keyed).
  2. Otherwise pick the exclusion that fits:
  3. rebuildable from other state → cache/
  4. a write-only forensic record → events/ (or a sibling audit dir)
  5. knowledge / a decision that must survive rewind → memory/ (persist)
  6. operator/user-owned → it does not belong under Reyn's managed tree.

When in doubt, do not default to recovery-core — an over-broad recovery-core entry either bloats capture or, if it can't be reconstructed, breaks rewind.

See also