# wendkeep

[Português](README.md) · **English**

> **Your AI coding agent forgets every session. wendkeep makes it remember — in the Obsidian vault you already use.**

[![npm](https://img.shields.io/npm/v/wendkeep.svg)](https://www.npmjs.com/package/wendkeep)
![test](https://github.com/rogersialves/wendkeep/actions/workflows/test.yml/badge.svg)
![zero deps](https://img.shields.io/badge/runtime%20deps-0-brightgreen)
![node](https://img.shields.io/badge/node-%E2%89%A518-blue)

[![wendkeep — persistent memory for AI coding agents, shown as a knowledge graph of sessions, decisions, bugs, learnings and changes](docs/assets/wendkeep-hero.svg)](docs/index.html)

**In the graph:** 🔵 session · 🟣 decision · 🔴 bug · 🟢 learning · 🟡 change — every note, backlinked.

**Persistent memory for AI coding agents, built on your Obsidian vault.** Every Claude Code **and Codex** session is captured turn by turn into local Markdown — `init` wires both (Codex asks you to approve its hooks once; `import` backfills past sessions either way) — with token/cost tracking and automatically extracted decisions, bugs, and learnings. That always-on plane is **Keep Core**. On top of it, **Wend Runtime** provides a native, zero-dependency lifecycle (spec → change → TDD → sensor-gated archive), selected through the `OFF`, `FLOW`, `GUIDE`, `GOVERN`, and `ASSURE` Operating Profiles. 100% local, open-core.

When projecting sessions, trailing internal metadata is removed only from assistant responses;
user reports remain intact. XML-like tags are written as escaped text so Obsidian Reading view
does not interpret them as HTML.

The runtime is being separated into six physical boundaries — `cli`, `harness`, `vault`, `mcp`,
`integrations`, and `pi` — without fragmenting installation. The private `cli`, `harness`,
`vault`, `mcp`, and `integrations` workspaces now canonically own the executable runtime,
Operating Profiles/the sensor engine, safe binding/the Shared Project Memory v2 kernel, the MCP
configuration kernel, and pure Claude/Codex integration rules, respectively. The root package
exposes Harness and Vault through `wendkeep/harness` and `wendkeep/vault`; CLI, MCP, and
Integrations remain private surfaces, reached only through the binaries, the configuration effects
of `init`, and historical facades. Historical imports keep working through compatibility facades
and no session data needs migration;
see the [modular architecture](docs/en/architecture.md).

In the **0.66 Integrations Kernel** phase, `packages/integrations/src/` becomes the canonical
authority for the hook catalog and projection, the envelope/provider, transcript content and usage
filters and parsers, and session identity. These rules are pure: stdin/stdout, environment,
filesystem, Vault, and registry effects remain in the historical facades. MCP and Integrations are
sibling adapters with no dependency between them, and the direction remains
`cli/mcp/integrations/pi → Harness → Vault`. Hooks, sessions, paths, configuration, and schemas
remain equivalent; the private `@wendkeep/integrations` workspace stays inside the single
published `wendkeep` package, with no public `wendkeep/integrations` subpath. Pi is the next phase.

The **native MCP** workspace now serves semantic project, context, memory, change, spec, task,
handoff, evidence, and Observer tools through `wendkeep mcp serve`. A versioned, verified catalog
declares every effect/capability; known reads skip the mutation gate, while writes require a
capability, session, active context, lease, and reason. Stable schemas, pagination, byte budgets,
timeouts, cancellation, redaction, and payload-free local audit bound the surface. `init` preserves
the `.mcp.json` merge while invoking the installed package through
`npx --no-install wendkeep mcp serve`—with no dynamic `@latest` dependency or arbitrary filesystem
access. Stdio may start outside a bound project; without `--vault`, each call resolves and audits
only its declared `project_root`. The workspace remains private inside the single `wendkeep` package.

In the **0.64 CLI Runtime** phase, `packages/cli/src/index.mjs` owns help, version reporting, Vault
selection, error presentation, and lazy dispatch. `bin/wendkeep.mjs` is reduced to the shebang and
a `runCli()` invocation. The tarball remains a single artifact and proves both aliases in an
isolated consumer; there is no public `wendkeep/cli` subpath in this phase.

In the **0.63 Harness FLOW Store** phase, `packages/vault/src/locale.mjs` becomes the canonical
source for Vault locale and taxonomy, while `packages/harness/src/flow-store.mjs` becomes the
canonical durable FLOW store. The historical `hooks/locale.mjs` and
`hooks/vault-runtime-store.mjs` facades preserve export identity. Harness depends only on Vault's
public index — never the reverse — with no migration of paths, schemas, or locks; the tarball
remains a single artifact published by the root `wendkeep` package.
Under multiprocess contention, transient release of the public lock and its owner/lease metadata
is revalidated with a bounded budget/deadline, including final cleanup; junctions, reparse points,
dangling locks, and non-transient errors are still rejected before any write.

```bash
npm i -D wendkeep && npx wendkeep init      # captures from the next session on
npx wendkeep import                          # backfill past Claude + Codex sessions
```

**▶ Interactive demo:** [`docs/index.html`](docs/index.html) — a self-contained page with the live knowledge‑graph hero. It lives in the [GitHub repo](https://github.com/rogersialves/wendkeep/tree/main/docs) (the npm tarball ships only the runtime), so clone or download `docs/` to open it locally or serve it on any static host. The image above is a static render of it.

> **From one real production vault** (`npx wendkeep stats`): **308** sessions · **1,696** prompts · **$4,836** captured across **46 active days** (Jan–Jul 2026) · **15** models — every one a note in the graph.

<!-- Optional: drop a real Obsidian graph screenshot at docs/assets/graph.png and add it here (see docs/21-graph-screenshot.md). -->

> Extracted from a system in daily production use: the capture engine, cost tracking and graph wiring are battle‑tested; the cross‑platform installer (`wendkeep init`) and the native change loop are the newer parts. See [`docs/`](https://github.com/rogersialves/wendkeep/tree/main/docs) for the project's strategy and decision log.

---

## The problem: the context dies when the window closes

Decisions, dead ends, the reason you chose X over Y — gone next session. The pieces to fix that exist but are scattered (qmd‑sessions, memsearch, Nexus, hand‑written hooks). wendkeep ships local capture plus an optional Docker Observer that keeps complete memory browsable without depending on Obsidian.

| | |
|---|---|
| **Capture** — every turn, on disk | `SessionStart` / `Stop` hooks write each session to a dated Markdown note: prompts, iterations, files touched, wikilinks. |
| **Derive** — decisions, bugs, learnings | Pulled from the transcript into their own notes, backlinked to the session. Your history becomes navigable, not archival. |
| **Recall** — injected back | Canonical `CORE` + operational `SHARED_MEMORY` enter on `startup`, `/clear`, and `/compact`; on every prompt, the local chunk index selects a few passages with source, authority, and validity under an explicit budget. |
| **Cost** — what it all cost | Per‑model, cache‑aware token pricing per session — plus `cost --trend` with a run‑rate projection across the whole vault; research previews without a final rate remain unestimated. |
| **Multi‑agent** — one vault, both agents | `init` wires the session hooks into `.claude/settings.json` *and* `.codex/hooks.json`, and every note is tagged with the agent that wrote it: Claude Code is detected from its environment, anything else is recorded as Codex. One shared graph, whichever agent you are in. |
| **Local‑first** — no cloud, no account | Everything is plain Markdown on your disk. The native MCP queries local semantic state and gates writes by capability/context/lease. |
| **Local Observer** — many projects, one view | `wendkeep observer` keeps documents, FTS5 chunks, sessions, agents, tokens, costs, calls, and transcripts in SQLite. Identities and foreign keys are project-scoped; each event is atomic. Hooks publish only what changed; `observer reconcile --url` ignores the incremental cursor to regenerate the complete projection while preserving local/remote revision baselines. |

During historical migration, the Observer preserves differences between frontmatter totals and the
ledger as explicit reconciliation rows, and disambiguates duplicate `session_id` values per file
without inventing calls.

## Requirements

The Codex scope guard treats `commit`, `push`, `pull`, `merge`, `publish`, and destructive
operations as independent capabilities, including inside compound commands.

- Node.js ≥ 18
- An AI coding agent with hooks. `init` wires **Claude Code** and **Codex** automatically — Codex gets twelve compatible hooks, including per-prompt recall and the scoped `PreToolUse` guard, and enumerates them untrusted, so approve its “Hooks need review” prompt once at startup (see [Notes & roadmap](#notes--roadmap))
- Obsidian (to view the graph) — optional but the point

## Install & set up

```bash
# in your project
npm install --save-dev wendkeep   # or: npm install -g wendkeep
npx wendkeep init
```

`wendkeep init` is interactive and **idempotent**. It will:

1. Create the vault folder taxonomy and a templated `README.md` (default vault: `<project>/.<project-name>-vault`, e.g. `.MyApp-vault`; override with `--vault`).
2. Write a provider-neutral **`.wendkeep.json`** binding at the project root and a matching `.brain/PROJECT.json` marker in the vault, then merge the session hooks into **`.claude/settings.json`**. The binding is provider-neutral by design: any agent resolves the same vault from its session `cwd`, with no machine-global environment variable. Older registrations already in `.claude/settings.json` are adopted automatically.
3. Wire the Codex hooks in **`.codex/hooks.json`** — twelve compatible entries: `brain-inject` + `session-start` + `observer-publish` on `SessionStart`, `session-ensure` + `evidence-context` + `change-context` on `UserPromptSubmit`, `session-stop` + `observer-publish` + `change-nag` on `Stop`, `subagent-stop` + `observer-publish` on `SubagentStop`, and `change-guard` on `PreToolUse` for `Bash`, `exec_command`, `apply_patch`, and mutable MCP tools, always in the `npx wendkeep hook <name>` form. For the Observer, `SessionStart` only drains the outbox, `Stop` enqueues the changed session, and `SubagentStop` enqueues only the affected transcript; full scanning is explicit through `observer reconcile`. When the host omits `work_session_id`, `session-start` and `session-ensure` derive it from the canonical `session_id`, preserving an explicit handoff and the already registered value first. The guard accepts object, raw-string, and argv Codex payloads; before a mutation it compares the session with the project, Git root, remote, branch, and worktree, denying missing or divergent targets. A raw `git checkout/switch` branch transition is denied before it can strand the session; use `wendkeep context switch <branch> [--create]`, which moves Git and the causal scope together in the same worktree with an audited revision and rollback. If a divergence is already quarantined, `context status --session <id>` inventories sanitized `reserved`/`observed` candidates; `context recover --session <id> --select <reserved|observed> --revision <n> --reason <text>` requires an explicit choice, CAS, and current-checkout proof, failing closed before clearing the conflict if revalidation changes. `doctor` diagnoses orphaned active contexts, removed worktrees, and expired `request-stop` leases without writing; `context repair --key <key> --revision <n> --reason <text> --session <id>` revalidates under lock, closes only the ownerless/removed context or expires only its lease, while preserving the record and all historical memory. The change lifecycle uses `active_contexts`, identified by `repository_id` + `worktree_id` + `work_session_id`; two matching sessions fail with ambiguity instead of selecting silently, `CURRENT_CHANGE.md` is only a derived projection for one unambiguous context, and migration never invents a worktree or session identity. The other four stay out because Codex offers no equivalent payload, tool, or event: `change-warn` (no reliable `tool_input.file_path`), `plan-capture` (no `ExitPlanMode`), `decision-capture` (`AskUserQuestion` is Claude-only), and `task-log` (`TaskCompleted` is not in Codex's event enum). Codex scope blocks use `permissionDecision: "deny"`; `ask` is never emitted in `PreToolUse`. The merge remains non-destructive, preserves third-party hooks, and migrates legacy `timeout` to `timeoutSec`. **Codex enumerates every hook as untrusted and runs none until you approve the “Hooks need review” prompt at startup — `init` cannot pre-approve them**.
   Once `active_contexts` is initialized, `brain-inject` and `change-context` mark only the causal context's change as current; the backlog remains global, and an empty or ambiguous store never revives `CURRENT_CHANGE.md`.
4. Add the native semantic **`wendkeep-vault`** MCP server to `.mcp.json`. It offers bounded reads and capability-gated writes without arbitrary filesystem access or an `@latest` download. Skip with `--no-mcp`. (`--no-mcp` skips *only wendkeep's own* MCP; companion MCPs still follow `--companions`.)
5. Offer to pin **companion** plugins/MCP (multi-choice; **none** pre-checked — wendkeep is a neutral harness and presumes no third-party plugin). Each is wired the most agent-agnostic way it supports:
   - **`context-mode`** — context optimizer + FTS5 memory, wired as a Claude Code plugin. It ships its own MCP server, so wendkeep deliberately adds no `.mcp.json` entry (registering both cold-started two servers at once). On non-Claude agents, add the MCP by hand: `npx -y context-mode`.
   - **`understand-anything`** — project domain graph, via a `understand-inject` SessionStart hook that injects the graph when generated.
   - **`caveman`** — token-compression mode; runs its own cross-agent installer on non-Claude agents.
   - **`dotcontext`** — *legacy, not recommended, and hidden from the picker.* wendkeep's native a2 loop (`change` / `verify` / gate) already does its job, so installing it **duplicates the harness**. Reachable only via an explicit `--companions dotcontext` for anyone already invested (tune with `--dotcontext-mcp` / `--dotcontext-hooks`).

   Control with `--companions <csv>` or `--no-companions`. The Claude Code plugin layer (`extraKnownMarketplaces` + `enabledPlugins`) is wired as a bonus where the companion has one.
6. Install a **color system** into the vault's `.obsidian/`: a CSS snippet that accents notes by type (session/decision/bug/learning, via the `cssclasses` the hooks emit) plus graph color groups by folder. Non-destructive merge into `appearance.json`/`graph.json`; skip with `--no-colors`. Re-apply it any time on an existing vault with `wendkeep theme sync` — Obsidian owns `graph.json` and can drop the color groups (a grey graph); the re-sync restores them without a full re-`init`.
7. Seed **Shared Project Memory v2** without overwriting existing artifacts: `.brain/CORE.md`, `.brain/SHARED_MEMORY.md`, `.brain/MEMORY_EVENTS.jsonl`, `.brain/MEMORY_CANDIDATES.jsonl`, and `.brain/COMPACTION_PROTOCOL.md`. The durable outbox appears under `.brain/memory-outbox/`; `EVIDENCE_INDEX.jsonl` is rebuilt locally from chunks while `DIGEST.md`/`index.jsonl` remain compatible. Everything stays in the vault.
8. Seed the **definitions + skills layer**: `.brain/agents/` + `.brain/skills/` (versioned source of truth), including the native process skills `wk-workflow` / `wk-tdd` / `wk-debugging` / `wk-brainstorming` / `wk-planning` / `wk-verify` (some ship templates — e.g. `wk-verify`'s `verdict-template.json` + reviewer prompt). `init` runs `wendkeep sync-defs` for you, delivering the skills to `.claude/skills/` and `.agents/skills/`, and the agent definitions (`.brain/agents/*.toml`) to `.codex/agents/`, plus a managed section in `AGENTS.md` that indexes the skills for Codex; `sync-defs --check` detects stale copies (re-run `sync-defs` after editing `.brain`).
9. Seed the **change/spec lifecycle**: the `07-Specs/` + `08-Mudanças/` folders and a native `wendkeep.sensors.json` — critical memory validation/health sensors plus one for each of `typecheck` / `test` / `lint` / `build` found in your `package.json`. `memory-health` blocks delivery on corruption or projection divergence; semantic conflicts degrade only the affected keys and await curation. Pending outbox events and ordinary candidates are warnings. Add sensors with `wendkeep sensors add`. Drives `wendkeep change` / `wendkeep verify` — see **Change lifecycle** below.

```bash
npx wendkeep init --vault "~/vaults/work" --project . --yes   # non-interactive (no companions unless you ask)
npx wendkeep init --companions "context-mode,understand-anything" --yes
npx wendkeep init --no-companions --no-mcp --yes              # zero companions, no wendkeep MCP
```

### `init` options

| Flag | What it does |
|---|---|
| `--vault <path>` | Vault folder. Default `<project>/.<project-name>-vault`; interactive init asks. Point it at an existing vault to install into it. |
| `--project <path>` | Project root to wire (default: current directory). |
| `--locale <pt-BR\|en>` | Vault language — folder names, scaffold, skills. Interactive init asks; locked at init. |
| `--companions <csv>` | Companions to pin: `context-mode,caveman,understand-anything` (default: **none** — opt in explicitly; `dotcontext` is legacy). |
| `--no-companions` | Pin no companions. |
| `--no-mcp` | Skip **wendkeep's own** vault MCP (`wendkeep-vault`). Companion MCPs still follow `--companions`. |
| `--no-colors` | Skip the Obsidian color system (`.obsidian` snippet + graph groups). |
| `--vscode-worktree-tasks` | Create a local, Git-excluded `.vscode/tasks.json` for creating/listing/opening/finishing worktrees; never overwrites an existing file. Also accepted by `sync`. |
| `--yes`, `-y` | Non-interactive; accept defaults (skips the language / vault / companion prompts). |
| `--force` | Overwrite existing wendkeep config blocks. |

Then open the vault in Obsidian, send a test prompt in your agent, and confirm a note appears under `02-Sessões/…` (or `02-Sessions/…` for an `en` vault).

### Project isolation

Each project owns a `.wendkeep.json` containing a stable `projectId` and its vault path.
Relative paths (for example `.NutriGymBrain`) are resolved from the project root; absolute
paths are also supported. Hooks search upward from the agent's `cwd`, so nested packages use
the nearest binding. The vault carries the same identity in `.brain/PROJECT.json`; a mismatch
is rejected before any session is written. If no binding exists, hooks fail closed and never
create the historical `~/wendkeep-vault` fallback.
In linked worktrees, `profile use` and `profile status` resolve the main worktree's canonical
binding through the shared Git registry; the persistent selection applies project-wide without
rewriting the current worktree's versioned `.wendkeep.json`.

`OBSIDIAN_VAULT_PATH` remains only as legacy/manual CLI compatibility. It is not used to
route automatic Codex or Claude hooks and a project-local binding overrides an inherited
machine value.

## Updating

The hooks live inside the installed package, so upgrading means installing the new version
and re-wiring the project. `sync` does the three steps (`init` → `sync-defs` → `doctor`) in
one command:

```bash
npm install --save-dev wendkeep@latest && npx --no-install wendkeep sync --project . --yes
```

`sync` lets its own `init` stage validate or rebuild the binding before resolving the Vault for
later stages. An invalid `.wendkeep.json` stops at `init` without falling back to an inherited global Vault.

The install stays outside `sync` on purpose: a running process cannot replace itself and
keep going — the code in memory would still be the old one.

In WendKeep's own development checkout, do not install `wendkeep` in `devDependencies`. Use
`node ./bin/wendkeep.mjs sync --project . --yes`: the installer recognizes the self-checkout and
keeps hooks on the working tree without duplicating consumer `npx` commands.

In a **pnpm** monorepo the install command differs (`npm` in a pnpm repo fails with
`Cannot read properties of null (reading 'matches')`). Resolve the published version first and
reuse exactly the value returned:

```powershell
$version = pnpm view wendkeep version
pnpm add -D -w "wendkeep@$version" --config.minimumReleaseAge=0
pnpm install --update-checksums --config.minimumReleaseAge=0
pnpm exec wendkeep sync --project . --yes
```

> **Do not ask pnpm for `wendkeep@latest`.** pnpm 11 ignores packages published in the last
> 24h by default (`minimumReleaseAge`, a supply-chain guard) — and it does not complain: it
> installs the previous version, exits 0, and the only hint is a quiet `(X.Y.Z is available)`
> in the output. You end up on the old version thinking you upgraded. Check with
> `pnpm exec wendkeep --version`.
>
> Do not edit only the version or integrity in `pnpm-lock.yaml`. `pnpm add` and
> `pnpm install --update-checksums` must recalculate the complete entry. If the lock is already
> inconsistent and `ERR_PNPM_TARBALL_INTEGRITY` appears, prune the local store and repeat:
>
> ```powershell
> pnpm store prune
> pnpm install --update-checksums --config.minimumReleaseAge=0
> ```
>
> After installing, record the exception in `pnpm-workspace.yaml` — **pnpm does not write
> that line for you**:
>
> ```yaml
> minimumReleaseAgeExclude:
>   - wendkeep@<the version returned by pnpm view>
> ```
>
> Without it, CI's `pnpm install` fails with `ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION` until
> the version turns 24h old.

Restart Codex and Claude Code afterwards — the generated skills are read at startup.

`sync` **reseeds** the `wk-*` skills from the installed version's seeds. That is not an
extra: they are package artifacts, and merely copying `.brain/skills` would propagate the
previous version's content while stamping the new version into the metadata — `doctor` would
stop reporting `defs stale` without a single skill having been updated. If you hand-edited a
`wk-*`, that edit is overwritten; your own customisation belongs in a skill of your own,
which the reseed never touches.

## Features by group

The README is the map; the guides provide syntax, options, exit codes, examples, and diagnosis.

| Group | Use it for | Detailed guide |
|---|---|---|
| **Installation and updates** | `init`, `sync`, companions, and the first project↔vault binding | [Installation and first use](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/getting-started.md) |
| **Managed worktrees** | `worktree create/list/status/open/finish/cleanup/remove/prune`, merge proof, preflight, crash-safe cleanup/common gate, and receipts | [Managed worktrees](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/worktrees.md) |
| **Active context** | `active_contexts` by `repository_id`/`worktree_id`/`work_session_id`, causal transition, quarantine, and explicit recovery | [Active context](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/context.md) |
| **Portable state** | `portable status/export/import/diff`, authored/runtime boundary, redaction, and the `active-work` snapshot | [Portable state](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/portable.md) |
| **Local-first sync** | `sync status/push/pull/conflicts/resolve`, revision/CAS, outbox, leases, and explicit conflicts | [Sync protocol](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/sync-protocol.md) |
| **Native MCP** | semantic tools, effects/capabilities, stdio, schemas, pagination, budgets, audit, and client configuration | [Native MCP](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/mcp.md) |
| **Host capabilities** | versioned lifecycle/effect matrix, degraded mode, human waivers, and evidence/Observer coverage | [Host capabilities](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/capabilities.md) |
| **Operating profiles** | `profile`, `flow`, always-on Keep Core, and Wend Runtime governance | [Operating profiles](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/operating-profiles.md) |
| **Changes and verification** | `change`, specs, sensors, TDD, evidence, Task Contracts, and archive | [Changes and verification](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/changes-and-verification.md) |
| **Shared memory** | CORE, SHARED, status, validation, repair, and curation | [Memory](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/memory.md) |
| **Sessions and import** | causal hooks, observability reconciliation, and Claude/Codex backfill | [Sessions and import](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/sessions-and-import.md) |
| **Notes and knowledge** | BUG/APR/ADR, repairs, renumbering, lessons, and dashboard | [Notes and knowledge](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/notes-and-knowledge.md) |
| **Costs and observability** | safe dry-run, tri-state, aggregation, trends, and historical rebuild | [Costs and observability](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/costs-and-observability.md) |
| **Maintenance and diagnostics** | doctor, frontier/manifest freshness, drift, version, and help | [Maintenance and diagnostics](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/maintenance-and-diagnostics.md) |
| **Local Observer** | `observer serve`, registration, incremental publication, `reconcile`, outbox, and multi-project index | [Local Observer](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/observer.md) |

Operations that deserve step-by-step guidance: [verify and exits 0/1/2](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/verify.md),
[causal TDD attestation](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/tdd.md),
[legacy-memory migration](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/memory-migration.md), and
[safe retroactive import](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/retroactive-import.md).

## Operating Profiles — Keep Core is always active

**Keep Core is always active**: the Vault, sessions, identity, CORE/SHARED, lessons, costs,
and persistence do not turn off with the harness. **Wend Runtime** controls only the automatic
governance layer. Even under `OFF`, explicit WendKeep commands remain available; invoking one is a
deliberate opt-in and runs that command's own validations:

| Profile | Route | Use |
|---|---|---|
| `OFF` | LLM-native harness | No Wend router, skill gate, or gates; explicit selection only. |
| `FLOW` | E → V | Microcontract with Git baseline, allowlist, sensor, and receipt, without a change. |
| `GUIDE` | P → E → V | Compact change; no automatic design/spec/ADR when contract impact is none. |
| `GOVERN` | P → R → E → V | Current a2 loop and compatible fallback. |
| `ASSURE` | P → R → E → V → C | Governance with confirmation and handoff. |

A route is a sequence of work stages, not a list of command names:

- `P` = **Plan/Propose** — understand the request, bound the scope, and record the approach when a change is needed.
- `R` = **Review** — inspect the proposal/design before execution; this is the formal a2-loop review.
- `E` = **Execute** — edit the permitted code or artifacts.
- `V` = **Validate** — run tests, sensors, and checks and record evidence.
- `C` = **Confirm/hand off** — obtain explicit confirmation and complete the handoff.

Thus, `P → R → E → V` means “plan/propose, review, execute, and validate”. `FLOW` starts at the
execution/validation microcontract; `OFF` applies no automatic Wend route and returns process
ownership to the native LLM harness.

### Who selects the profile, and for how long?

The LLM harness (Codex, Claude, or another agent) **classifies the current implementation** and can
record a temporary choice with `wendkeep profile route`. Wend Runtime does not interpret prompt
text or use diff size, heuristics, or environment variables: it validates the choice, applies the
route in hooks, and expires the lease when the request ends. With no recorded route, the configured
base profile remains effective.

Resolution follows this order:

1. a valid lease for the current request in `SESSION_REGISTRY.json`;
2. a persistent session override in that registry;
3. `harness.profile` in the project's `.wendkeep.json`;
4. `GOVERN` when no valid setting exists.

Without `--session`, `profile use` changes the **project default** for conversations/hooks that do
not have a session override. With `--session <id>`, it changes only that session and leaves the
project default untouched. Therefore, `profile use OFF` without `--session` is not an isolated
test: it writes the project binding and can be shared if `.wendkeep.json` is committed.

`profile route` is different: it requires `--session` and `--reason`, accepts only `FLOW`, `GUIDE`,
`GOVERN`, or `ASSURE`, does not rewrite the project/persistent override, and applies only to the
current causal prompt. An accepted `Stop` consumes the lease; if the process dies first, the next
prompt advances the sequence and makes the old lease ineffective. `OFF` is never selected
automatically.

```bash
npx wendkeep profile status
npx wendkeep profile use GUIDE                 # project default
npx wendkeep profile use FLOW --session <id>   # one session only
npx wendkeep profile route FLOW --session <id> --reason "local fix"  # current request
npx wendkeep profile status --session <id>     # session-effective profile
```

In human `status --session` output, `base=<profile>/<source>` and `lease=<state>` accompany the
effective profile; `--json` exposes the same data as `base_profile`, `base_source`, and
`task_lease`. `profile route` only accepts a session after `UserPromptSubmit` has recorded a
positive causal turn and sequence that agree in the registry.

### Which profile fits a simple request?

“Small” describes size, not risk. The harness uses this matrix to choose and record a temporary
route; semantic inference remains in the agent, not Wend Runtime:

| Situation | Work kind | Suggested profile | New change |
|---|---|---|---|
| Question, inspection, or diagnosis with no mutation | `inspection` | No transition | No |
| Local, reversible fix with an allowlist and no contract/spec change | `maintenance` | `FLOW` (`E → V`) | No |
| Small behavior change without formal review | `implementation` | `GUIDE` (`P → E → V`) | Yes, compact |
| Public contract, security, schema, dependency, CI/release workflow, or policy | `implementation` | `GOVERN`/`ASSURE` | Yes |
| Merge, push, tag, or publication of approved behavior | `delivery` | `ASSURE` | No |
| Operational recovery without code/config correction | `recovery` | `FLOW`/`ASSURE` | No |

Work kind, profile, contract impact, and operational risk are independent dimensions. A
`delivery` records authorized capabilities and an append-only receipt without creating a change,
spec, or ADR. If delivery requires a code/config edit, it pauses and work returns to
`implementation`:

In multi-context Vaults, `active_contexts[].delivery_id` is authoritative and `--session <id>`
selects the caller explicitly. `CURRENT_DELIVERY` is only a derived projection when there is one
single, unambiguous context; hooks consult only the causal delivery, and an ID from another context
fails with `WENDKEEP_DELIVERY_CONTEXT_MISMATCH`.

`operating_profile_task` belongs to the causal work session's active context. `profile route` and
`profile status --session <id>`, hooks, and Stop read/consume only that lease; a temporary route
never crosses into a sibling. Legacy session fallback exists only without `active_contexts`;
an initialized registry never copies a global authorization without proven identity.

```bash
npx wendkeep delivery start release-0-74-0 --allow git:merge --allow git:push --allow publish --source-change <slug> --source-commit <sha> --session <id>
npx wendkeep delivery status release-0-74-0 --session <id>
npx wendkeep delivery finish release-0-74-0 --target origin/main --ci-url <url> --version 0.74.0 --npm-integrity <sha512> --release-url <url> --session <id>
```

For `git:merge` and `git:push` capabilities, `delivery finish` requires
`--target <remote>/<branch>` (for example, `--target origin/main`). `delivery start` binds the
`origin` remote to the expected `repository`; during finish, the target is resolved again with
`git ls-remote`. If the target cannot be resolved or the origin/repository binding diverges, the
delivery is blocked before provenance adapters run.

The provenance gate re-derives authority against the current subject before archive, delivery,
release, or cleanup. Its single taxonomy is `verified`, `reported`, `legacy-unbound`, `stale`,
`conflict`, and `unproven`; only `verified` authorizes required proof. Evidence, a verdict, or a
receipt captured before amend/rebase, from another branch/worktree/session, or backed only by a
reported/offline external claim fails closed with objective recovery. New receipts use schema v2,
`previous_hash`, `receipt_hash`, and a separate checkpoint to detect tampering and truncation.
Stable codes are `WENDKEEP_PROVENANCE_GATE_BLOCKED`, `WENDKEEP_RECEIPT_LEDGER_BUSY`,
`WENDKEEP_RECEIPT_LEDGER_CONFLICT`, `WENDKEEP_RECEIPT_LEDGER_CORRUPT`, and
`WENDKEEP_RECEIPT_LEDGER_TRUNCATED`. Safe recovery reads `state`, `reasonCodes`, `diagnostics`,
and `repair.command` in `--json` output, runs `npx --no-install wendkeep verify --deep --json` or
the indicated status command, and recaptures proof; it never prints raw stderr, tokens, private URLs,
or Vault paths, and never edits the ledger/checkpoint.

If the harness does not record a lease, a small fix remains under the configured profile —
`GOVERN` by default. `OFF` does not mean “simple task”: it is a persistent human choice that hands
governance to the native harness. The LLM may temporarily elevate an `OFF` base to a Wend route,
but it can never select `OFF` on its own.

A corrupt binding never selects `OFF`: with one unambiguous explicit or legacy Vault, Keep Core
remains active under `GOVERN`, the error stays visible, and mutation guards fail closed. Additional
roots that FLOW must protect can be declared as project-relative paths under
`harness.flow.protectedRoots` in `.wendkeep.json`; any change below them requires promotion.
Invalid local config, marker, or identity never silently falls back to a parent/global Vault.

`wendkeep profile status/use/route` makes the choice observable; `wendkeep flow
start/finish/promote` handles local adjustments without manufacturing an ADR and fails closed on
physical escapes, Git metadata/hidden flags, mutating sensors, protected surfaces, or incomplete
session projection. Bounded no-follow discovery sees empty/ignored protected aliases; Vault writes
and owner+lease locks validate physical topology. Concurrent promotion elects one owner and supports
retry through `--change-slug`. Read the complete
[Operating profiles guide](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/operating-profiles.md).

`wendkeep doctor` separates structural errors, workflow attention, repairable debt, and semantic
ambiguity. Use `--scope core` for Keep Core health, `--scope runtime` for governance, and
`--strict` in CI/release; `wendkeep sync` validates Core only so work in progress does not become
an installation failure.

To resume a change in another clone without tracking transcripts, tokens, paths, leases, or outboxes,
`wendkeep portable export` creates `.wendkeep/portable/state.json` with sanitized authored
CORE/ADRs/specs/deltas and a compact `active-work` projection. `portable import` validates project,
hashes, revisions, and paths before writing; stale or conflicting state never silently replaces local
state. Git tracking is opt-in and the command never adds files automatically.

## Shared Project Memory v2

Hot memory now separates human authorship, operational state, and evidence:

- **`CORE.md` is canonical.** It is the short, hand-curated nucleus for durable preferences, active patterns, and open issues; no projector may infer or overwrite it.
- **`SHARED_MEMORY.md` is bounded generated operational state.** The `Stop` hook turns the session handoff into sanitized events; the projector deterministically reduces the ledger and publishes a verifiable revision, cursor, and hash. Admission prioritizes critical operational state and never publishes beyond 48 lines/6 KiB; omitted events remain in the append-only authority and surface only as verifiable counts. Facts are `verified` only with local evidence; unsupported reports remain `reported`, and disagreements become candidates for human judgment.
- **`MEMORY_EVENTS.jsonl` is the append-only authority.** `Stop` makes events durable in the outbox before acknowledging the attempt; the projector runs outside the registry lock and retries reuse the same IDs. Repeating an identical `event_id`/payload is a no-op; reusing the ID with different bytes is observable corruption.
- **`MEMORY_CANDIDATES.jsonl` is the curation queue.** Conflicts and legacy content are never silently promoted. `promote` and `reject` record the decision as a new event; promotion preserves the selected event's JSON type, session, activation/epoch, and source turn.
- **Registers are scoped.** `git.local-head`, handoffs, verdicts, and change status carry project, work-session, change, branch, or worktree scope. Two branches do not create a global conflict; only events in the same scope and causal lineage may advance automatically. Once `active_contexts` is initialized, `Stop` derives `work_session_id`, `repository_id`, `worktree_id`, branch, and change from the causal active context; a divergent handoff fails before CAS, note, outbox, or ledger mutation. Legacy compatibility exists only without the contextual store.
- **`EVIDENCE_INDEX.jsonl` is local recall.** Markdown is chunked by headings and blocks without requiring the Observer. Ranking combines BM25, exact phrases, field weights, authority, validity, bounded recency, and source diversity. The automatic `UserPromptSubmit` hook is read-only: it never migrates `CURRENT_CHANGE.md` or mutates the registry; it excludes passages owned by an active sibling session or change while preserving global and historical evidence. Explicit `/brain-recall` remains global.

Artifacts stay under `.brain/` only. Sanitization strips secrets, tokens, local paths, transcripts, and harness payloads both before persistence and before injection. Events carry a `project_id`, and one vault never accepts another project's events.

Lifecycle in brief: each `SessionStart` opens an epoch that spans multiple `Stop` events;
`UserPromptSubmit` advances the native turn and recovers exactly one closed legacy activation.
Codex uses `session_id`/`turn_id` plus transcript order, with no artificial causal fields. See
[sessions and hooks](docs/en/commands/sessions-and-import.md) and
[memory](docs/en/commands/memory.md).

### Injection and budgets

`CORE.md` is the only manual layer: it accepts up to 40 lines, warns from 35, keeps a 4 KiB ceiling, and caps each line at 320 characters. `SHARED_MEMORY.md` is generated exclusively by the projector and ledger; never edit it to repair state. `brain-inject` delivers the same revision/hash on `startup`, `/clear`, and `/compact` `SessionStart` events, always placing CORE and SHARED before change context. The full envelope is capped at 24 KiB; SHARED reserves up to 48 lines/6 KiB. Under pressure, lessons are removed first, then non-current changes. CORE is never sliced and SHARED admits deterministic whole events rather than prefix-slicing; a missing, invalid, or over-budget layer becomes a visible, repairable `<wk_memory_error>`.

`memory status --gate` and `validate-memory --vault` also check semantic coverage: they report a code, counts, and active/projected/missing keys. An empty v2 bundle is neutral; a bounded omission that exactly reproduces ledger selection is an operational warning. An arbitrarily missing event, false count, placeholders as the only content, or an unresolved decision link remains explicitly degraded/blocking without printing memory values.

`DIGEST.md` is no longer the operational handoff: it remains the `/brain-recall` bridge and legacy-vault fallback. A vault without SHARED receives CORE+DIGEST with a deprecation warning; migrate during the compatibility window:

```bash
npx --no-install wendkeep memory status --gate --vault .MyApp-vault
npx --no-install wendkeep memory migrate --vault .MyApp-vault          # preview, zero writes
npx --no-install wendkeep memory migrate --apply --vault .MyApp-vault  # backup + candidates + v2 bundle
npx --no-install wendkeep memory rescope --vault .MyApp-vault          # preview without values
npx --no-install wendkeep memory rescope --apply --vault .MyApp-vault  # append-only and idempotent
```

### Health and recovery

Use `npx --no-install wendkeep memory status --gate --vault <vault>` in CI and before `verify`/`archive`. Revision 0
immediately after valid migration is healthy. The gate correlates `last_memory_attempt`, outbox,
ledger, SHARED, and checkpoint: `degraded` with a durable outbox is a warning; an ambiguous attempt,
lost publication, or mismatched checkpoint blocks. See [migration](docs/en/commands/memory-migration.md)
and [diagnostics](docs/en/commands/maintenance-and-diagnostics.md).

If status blocks, preserve the evidence and run `npx --no-install wendkeep memory repair --vault <vault>` to back up
the corrupt ledger, retain valid lines, and re-project. Repair remains structural: its only narrow
acknowledgement exception covers attempts entirely represented by the outbox consumed by that same
run; it does not scan or reclassify historical attempts. Valid pre-0.59 causal checkpoints and
exactly re-derived assert-only historical prefixes are
CAS-migrated on both the attempt and `memory_checkpoint` to the correct physical boundary with
backup/audit; divergent mirrors fail closed. A demonstrably superseded
ambiguity uses `memory reconcile <session> --by-session <successor>
--reason <reason>` as a dry run and requires `--apply`; the decision is backed up and audited
without rewriting ledger, CORE, or notes. Run `status --gate` again afterwards. `memory rescope`
append-only separates legacy handoffs with proven identity even when they already participate in
candidates; it never selects a winner. Actionable conflicts require explicit, durable curation.
Start with `memory curate --vault <vault>`: the menu shows actionable conflicts only, groups them
under friendly names, shows sanitized previews, and confirms every write with default `no`.
`memory curate --all` includes proven historical handoffs and lets `H` batch-close them after
confirmation. In a non-TTY environment, use
`memory candidates --active --vault <vault>` to list only safe IDs and metadata in read-only mode —
it does not expose memory values or content. After human review,
`memory promote <id> --event <event-id>` selects one event from the candidate, while
`memory reject <id>` keeps the current value. `memory repair` does not choose a winner. The decision is idempotent, and a
new promotion accepts a later Stop from the same session/activation without recreating a conflict.
A promotion written by 0.66.1 remains historical: if the next Stop forms a new candidate, update
to 0.66.3 and run `memory repair`. During replay, a transient candidate is re-evaluated against the
final modern source and, when causal supersession is proven, re-anchored to it; explicit promotion
uses that anchor and crosses only the physical predecessors required by replay. The same
session/activation/epoch and a higher turn advances; a lower turn is superseded. Repair migrates the checkpoint and mirror only when it proves the exact previous
replay, attempt identity, and absence of a real conflict; it creates a backup and audit without
appending or rewriting events. Ambiguity stays queued for explicit curation. Do not publish or
install 0.66.2; use 0.66.3 or later. Decisions survive repair/replay;
`blocked_by_core` cannot override CORE. Doctor only diagnoses, now with human-readable output and
the guided next action; its health hook preserves JSON for automation. A missing Vault or unsafe
boundary/registry also yields blocked memory, a safe command with the resolved path, and structured
JSON—never a false “intact bundle” or a stack trace. When status/doctor reports projected
acknowledgement pending on 0.66.4 or later, first run the targeted dry run
`memory recover-attempt <session> --vault <vault>`, then authorize `--apply`; it changes only
registry/checkpoint. See syntax, preconditions, and fail-closed behavior in
[memory and curation](docs/en/commands/memory.md).

Session notes use one live `## Agentes, tokens e custos` snapshot. Main-agent and subagent hooks recompose it atomically, with costs, token dimensions, reasoning tokens and effort per model/source. On Codex, subagent prompts register their rollout for observability without advancing the main agent's sequence; `SubagentStop` reads the child from `agent_transcript_path` and persists its signal only when `parent_thread_id` matches a validated session root. The main Stop uses the registry's causal `turn_id` mapping before falling back to local transcript order. Every terminal attempt writes a sanitized, idempotent receipt to `.brain/SESSION_ITERATION_OUTCOMES.jsonl`, distinguishing insertion, duplicate, skipped, aborted, busy-lock, failure, and observability status; the cursor advances only after note confirmation. `subagent_notification` is not a human prompt, `turn_aborted` is explicit, and custom tool output is not double-counted. To recover missing markers while a conversation is open, `hook session-backfill` is a dry-run by default and never writes a Codex turn without `task_complete`. Every hook that rewrites a session note takes a per-file lock and writes through a temp file + rename, so the `SubagentStop` fan-out (one hook run per subagent) can never leave a note half-written; a note whose frontmatter reads back damaged is left untouched rather than patched.

On definitive close, the activation and session become `done` in `SESSION_REGISTRY.json` only
after memory/observability publication; `CURRENT_SESSION.md` is a derived view, not the identity
authority, and does not list finalized sessions.

## Retroactive memory (`import`) — install today, remember yesterday

Install wendkeep into an existing project and it only remembers sessions **from now on**. `wendkeep import` fixes that: one command backfills your project's past **Claude & Codex** sessions into the vault — deduped, dated, with cost — so the graph starts full, not empty. It rebuilds each transcript as a full session note in its **real** date folder — frontmatter (tagged with the transcript's real provider), one iteration block per turn, cost + subagent telemetry, derived decision/bug/learning notes, finalized closing. An offline replay of the live capture flow, so an imported note is indistinguishable from a captured one.

```bash
wendkeep import --vault .myproject-vault --dry-run   # preview what would be imported (both agents)
wendkeep import --vault .myproject-vault             # write the notes
wendkeep import --vault .myproject-vault --source codex   # just Codex
```

- **Both agents by default** (`--source all`). Claude sessions come from `~/.claude/projects/<slug>/`; Codex rollouts from `~/.codex/sessions/**`, scoped to this project by the `cwd` recorded in each session (case- and separator-insensitive, subdirs included). Narrow with `--source claude` / `--source codex`.
- Every note records its **`session_id`** and **`provider`** in frontmatter (live capture and import alike). Backfill older notes with `wendkeep import --stamp-ids` (fills the id from the registry; idempotent).
- **Deduped** by `session_id` against the vault's `SESSION_REGISTRY` **and** existing notes' frontmatter — only sessions not already present are imported, and it never overwrites an existing note. Re-running is a no-op.
- **`--from <dir>`** / **`--codex-from <dir>`** point at the transcript folders explicitly (use if the auto-derived path misses). Also: `--since <date>`, `--limit <n>`, `--rescan-decisions`, `--json`.
- Once imported, `wendkeep cost` aggregates your entire history — retroactively, across both agents.

## Derived notes — numbered like ADRs (`note new`, `renumber-*`)

Decisions, bugs and learnings are **derived notes**: they live in the month folder of their tree (`<folder>/<year>/<MM-MON>/`) and carry a sequential id — `ADR-0001`, `BUG-0001`, `APR-0001`. One glance tells you what a note is and where it sits in the project's history. No day-level subfolders: a `DIA N` folder holding one note is noise, and it hides the note from folder-wide search.

**Creating one** (never write the file by hand — the command owns the number, the folder and the frontmatter):

```bash
wendkeep note new --type bug "login 500s when the token expires mid-refresh"
# → 05-Bugs/2026/07-JUL/BUG-0007-login-500s-when-the-token-expires-mid-refresh.md

wendkeep note new --type learning "a regex without /g only ever returns the first match"
# → 06-Aprendizados/2026/07-JUL/APR-0003-a-regex-without-g-only-ever-returns-the-first-match.md
```

It prints the created path, numbers from the current max (recursive scan), files it in the month folder for today (`--date YYYY-MM-DD` to override), and links the active session in `source:` so the graph stays connected. Agents get this rule injected at SessionStart — they call the command instead of guessing a filename.

**Reconnecting legacy notes.** Derived notes created by older versions carry no `source:` session and sit as islands in the graph. `wendkeep note relink` backfills them: each orphan inherits the modal source session of its type/month cohort (the session its non-orphan siblings already point to). Dry-run by default; `--apply` writes; notes with no sibling to infer from are skipped and reported.

**Migrating an existing vault.** Notes created before `0.41.0` have date-prefixed names (`2026-07-16-bug-<slug>.md`) and may sit in legacy `DIA N` subfolders. One command per tree renumbers them chronologically, moves them up into the month folder, and rewrites every wikilink across the vault:

```bash
# Bugs — 05-Bugs → BUG-NNNN
wendkeep renumber-bugs                  # preview: prints every from → to, writes nothing
wendkeep renumber-bugs --apply          # migrate

# Learnings — 06-Aprendizados → APR-NNNN
wendkeep renumber-learnings             # preview
wendkeep renumber-learnings --apply     # migrate

# Decisions — 04-Decisões → ADR-NNNN (since 0.30.0)
wendkeep renumber-decisions             # preview
wendkeep renumber-decisions --apply     # migrate
```

- **Preview is the default.** Nothing is written until `--apply` — read the `from → to` list first; that is where a mangled slug shows up, before it touches your files.
- **One tree at a time, on purpose.** There is no `renumber-all`: each folder is migrated and reviewed on its own.
- **Order is chronological**, derived from the note's date (frontmatter → filename prefix → folder), so `BUG-0001` is genuinely the oldest bug — not the first one the scanner happened to read.
- **Wikilinks are rewritten vault-wide** (full-path and basename forms, aliases preserved), the body's `type`/`bug:`/`apr:`/H1 are normalized, and emptied `DIA` folders are removed. **Idempotent**: a second `--apply` renames nothing. Close Obsidian while migrating, and commit the vault first if it is under git.

## Change lifecycle — the a2 loop (spec‑driven, native)

Beyond capturing sessions, wendkeep is a **harness**: a native, zero‑dependency loop that keeps *intent* (specs), *work* (changes) and *proof* (sensors) together in the vault, wikilinked into the Obsidian graph.

```
explore → propose → apply (TDD) → verify → archive
```

- **Propose** — `wendkeep change new <slug>` scaffolds `08-Mudanças/<slug>/` (`proposta.md`, `design.md`, `tarefas.md`; `--simple` skips the design). `--guide` creates the compact GUIDE contract and omits automatic design/spec/ADR when `contract_impact:none`. It becomes the global *current* change. When the change declares `spec_impact: required`, you author the delta yourself at `specs/<capability>/spec.md` — there is no placeholder to delete. Multiple changes may remain open: `change list`/`status` and the hooks show every pending one, while commands without `--change` act on the current one alone. `change use <slug>` changes focus and `change continue <archived> <new>` creates an auditable continuation.
- **Apply** — implement each `tarefas.md` task. Mark machine proof with one or more `[sensor:<id>]` tags on the same task: every distinct ID enters the gate once, in declaration order. Also mark satisfied requirements with one or more `[req:<ID>]` tags. For causal TDD, add `[tdd]` and record `wendkeep tdd red|green`; the [TDD attestation guide](docs/en/commands/tdd.md) covers profiles, waivers, and exit codes.
- **Verify** — `wendkeep verify` runs declared sensors and writes an **Evidence Envelope v2** to `evidencia.json`, SHA-256-bound to project/repository/worktree/session, HEAD, index tree, normalized worktree digest, tasks, effective spec, TDD attestations, and sensor configuration. Each sensor records a sanitized command, execution window, duration, exit code, output digest, and a sanitized tail bounded to 2,000 characters. If HEAD changes during the run, no new envelope is published. `change status` reports `bound`, `stale`, `context-mismatch`, or `legacy-unbound`; v1 evidence remains readable but cannot satisfy v2 authority. The public schema is [`schema/wendkeep.evidence-envelope-v2.schema.json`](schema/wendkeep.evidence-envelope-v2.schema.json). `verify --deep` binds the package, attestations, and verdict to the current `envelope_id`.
- **Archive** — `wendkeep change archive <slug>` **gates** on the evidence (blocks unless every declared critical sensor is green), promotes each applicable spec delta (`ADDED`/`MODIFIED`/`REMOVED`) into the living `07-Specs/<capability>.md` and moves the change to `_arquivo/`. GOVERN/ASSURE mint an ADR in `04-Decisões/`; compact GUIDE with no contract impact does not mint one automatically.

> The gate blocks unless the scaffold is filled, no task is open, evidence is fresh, and every declared requirement is covered. **`--force` waives exactly one of those — the open-task check — and is the human's call, never the agent's.** An unfilled scaffold, a red critical sensor, stale evidence, an orphan requirement or a missing verdict block regardless.

After the fix, archive requires a **final** recapture with
`wendkeep verify --deep --change <slug>`. The package is complete and canonical; the verdict must
also be complete and canonical, with both bound to the same checkout, change, tasks, spec, and sensors. Before any mutation, the command
writes an authorization receipt to the separate `change-archive-receipts-v2` ledger; only after
that receipt is valid may it promote the spec/ADR or move the change. `change archive --json`
returns the serializable `state`, `reason_codes`, `diagnostics`, and `repair` fields. Corruption
or truncation in any ledger fails closed before mutation. `--force` does not bypass provenance,
integrity, package, verdict, corruption, or truncation; the exact recovery is the recapture above.

Archive sealing uses the runtime lock and a private ASCII transaction at
`.brain/runtime/archive-transactions/<uuid>/{original,authorized}`: it atomically renames the live
change to `original`, checks the digest, and promotes only `authorized`. On a seal or divergence
failure, it removes the snapshot and restores `original` without partial promotion. Multi-spec
promotion is one atomic unit: it captures before-images/digests, rolls back before/after writes,
and permits retry only after reconciliation and fresh verification. The post-release finalizer
validates original/destination digests, but the `completed` journal keeps the `original` retained;
no destructive cleanup is automatic. A failure leaves `published-recovery-required`. Text and --json
keep the same sanitized diagnostic (code, operation, state, blocker, expected, observed, recovery).

The archive uses a `directory lock` with a token-specific marker and lease: acquisition prepares a
sibling `.pending` directory and publishes it by atomic rename, uses no hardlink, and allows at most
3 topology attempts. A live owner returns `WENDKEEP_ARCHIVE_BUSY`, a dead owner is safely reaped,
an invalid marker returns `WENDKEEP_ARCHIVE_LOCK_UNAVAILABLE`, and ownership loss returns
`WENDKEEP_ARCHIVE_LOCK_OWNERSHIP_LOST`. The transaction keeps `archive-transaction.json` with
phases `prepared` → `isolated` → `copied` → `sealed` → `published` → `promotion-prepared` →
`promotion-applied` → `completed` or `recovery-required`. A pending journal blocks a new archive for
the same slug before the gate. On
a collision/post-publication failure, `original` is retained and the state is
`published-recovery-required`; `operation_id` and `transaction_phase` are sanitized. Inspect it
with `wendkeep change archive recover <operation-id> --change <slug> [--spec-action rollback|resume] [--json]`:
without `--spec-action`, this is a read-only, fail-closed, idempotent operation that returns
sanitized actions without promoting or deleting. `rollback` restores before-images and `resume`
converges after-images for a `promotion-prepared` promotion, while retaining the journal for
reconciliation. When an operation ID exists, `repair.command` points to that recovery; do not treat
`command:null` as the normal flow.

`wendkeep init` seeds process skills into the vault's `.brain/skills` and delivers identical copies to `.claude/skills/` and `.agents/skills/`; Codex gets the agent definitions (`.brain/agents/*.toml` → `.codex/agents/`) plus a managed section in `AGENTS.md` that indexes the skills. Every skill carries source hash/version metadata; `doctor` warns when reseed + agent restart is required.

### The loop in five minutes

```bash
npx wendkeep init --yes                        # vault + hooks + sensors + skills
npx wendkeep change new dark-mode              # proposta/design/tarefas — change is now active
```

Edit `tarefas.md` — tag proof and requirement per task:

```markdown
- [ ] 1.1 toggle persists across sessions [req:UI-1] [sensor:tests] [tdd]
```

Declare the capability in `proposta.md` (`specs: [ui]`) and author its delta only in
`08-Mudanças/<slug>/specs/ui/spec.md`. `07-Specs` is generated/read-only. Then:

```bash
npx wendkeep change status                     # every open change + its pending tasks
npx wendkeep change list                       # same backlog, plus the archived ones
npx wendkeep change status dark-mode           # one screen for one change: specs / tasks / sensors / verdict
npx wendkeep spec effective --change dark-mode # living contract + this change's delta
npx wendkeep change done 1.1                   # tick a task from the CLI
npx wendkeep tdd red 1.1 --requirement UI-1 --test tests/ui.test.mjs --command "npm test"
# implement; then observe GREEN in the same causal context
npx wendkeep tdd green 1.1 --command "npm test"
npx wendkeep verify                            # run the declared sensors -> evidencia.json
npx wendkeep verify --deep                     # assemble the verification package
# the wk-verify skill (fresh, read-only pass) writes verdict.json
npx wendkeep change diff                       # preview what will land in 07-Specs
npx wendkeep change archive dark-mode          # gate: sensors + verdict + no open tasks
```

The archive promotes the delta into generated `07-Specs/ui.md`, mints an ADR, and the
Obsidian graph now links *session ↔ change ↔ requirement ↔ decision*. Every generated
artifact (`design`/`tarefas`) is born linking its change's `proposta` hub, and hand-authored
`spec.md` deltas are auto-linked on `verify`/`archive` — no change artifact is a graph island.
To backfill older changes that predate this, run `wendkeep change backlink --apply` (dry-run
without `--apply`). A change that names no `[req:]` still runs `verify --deep`, but skips the
`wk-verify` reading pass: the command writes a trivial verdict on its own and the sensor gate
is the real proof.

## How it works

```
agent session ──hooks──▶ wendkeep ──▶ Markdown in vault ──▶ .brain memory + Obsidian graph
   (Claude/Codex)        (Node)      (02-Sessões/…)        (CORE+SHARED, ledger, backlinks)
```

The agent's settings.json points each hook at `npx wendkeep hook …`; **in Claude Code** the change-lifecycle hooks instead run the installed script directly (`node` on `${CLAUDE_PROJECT_DIR}/node_modules/wendkeep/hooks/<name>.mjs`) when the package is present locally, skipping an npx resolve on every event. `.codex/hooks.json` mirrors the same groups with PascalCase event keys, but always uses the `npx` form (`${CLAUDE_PROJECT_DIR}` does not exist in Codex) and spells its timeout `timeoutSec` — a plain `timeout` is neither a field nor an error there, it silently falls through to a 600s default, so `init` migrates that legacy key in place. On `Stop`, wendkeep parses the session transcript, appends the turn, updates token/cost data, emits derived notes, and publishes the sanitized handoff to the memory outbox. On `SessionStart` — startup, `/clear`, and `/compact` — `brain-inject` injects CORE + SHARED, every open change with its pending tasks, the causal current-change marker, project lessons, and a `<wk_process>` router. The inventory remains global, but `CURRENT` and the sentinel hash come from the session's active context; `active_contexts: {}` fails closed instead of reviving `CURRENT_CHANGE.md`. Claude, Codex, or another agent can therefore resume work started elsewhere without hiding the rest of the backlog.

The archive **gate** blocks unless: the change scaffold is filled (G0), no task is open (G1), every declared critical sensor is green (with fresh evidence), and a `verdict.json` is present and current. `--force` waives G1 only — G0 is inescapable by design (a placeholder change forced through once minted a fake ADR), and no flag turns a red sensor or a missing verdict green. The agent is instructed never to use it on its own.

## Notes & roadmap

- **Vault folder names default to Portuguese** (`02-Sessões`, `04-Decisões`, …). Pass `wendkeep init --locale en` for an English vault (`02-Sessions`, `04-Decisions`, English scaffold/skills). The locale is a vault property, locked at init; parsers are bilingual so mixed content never breaks.
- **Search is keyword/frontmatter scoring**, not on‑device embeddings (that's on the roadmap).
- **Transcript formats are agent‑internal** and can change between agent versions; parsing is isolated but may need updates.
- Installer wires **both agents**: `.claude/settings.json` + `.mcp.json` for Claude Code, `.codex/hooks.json` for Codex. **Eight Codex hooks are compatible**; `change-guard` validates the project lease in `PreToolUse` and denies mutations outside it. The four hooks without an equivalent remain Claude-only: `change-warn`, `plan-capture`, `decision-capture`, and `task-log`.
- **Codex hooks start untrusted.** They are enumerated but not executed until you approve the “Hooks need review” prompt; `init` cannot pre‑approve them (`--dangerously-bypass-hook-trust` is per‑invocation and stores no trusted hash). Trust is keyed to the hook's identity, so hand‑written wendkeep Codex hooks predating `0.46.0` — which ran at the 600s default because they used `timeout` instead of `timeoutSec` — cost one re‑review after `init` corrects the key. Expected, not a regression. `import --source codex` still backfills past Codex sessions either way.

---

## Stop re‑explaining your codebase every morning

```bash
npm i -D wendkeep && npx wendkeep init
```

**[Install from npm](https://www.npmjs.com/package/wendkeep)** · **[Star on GitHub](https://github.com/rogersialves/wendkeep)** — MIT · open‑core · your data never leaves your disk.

## License

MIT
