wendkeep 0.68.1 → 0.68.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,66 @@ All notable changes to **wendkeep** are documented here. Format based on
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this project follows
5
5
  [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.68.6] — 2026-08-16
8
+
9
+ ### Fixed
10
+
11
+ - **A orientação de atualização em monorepos pnpm agora resolve a versão publicada antes da
12
+ instalação.** README e guias bilíngues deixam de oferecer `X.Y.Z` como argumento copiável,
13
+ explicam o cooldown silencioso de `@latest` e orientam a regeneração segura do lock quando a
14
+ integridade do tarball divergir.
15
+
16
+ ## [0.68.5] — 2026-08-14
17
+
18
+ ### Fixed
19
+
20
+ - **O Stop passa a deixar um resultado durável por sessão, turno e estágio.** O ledger local,
21
+ append-only,
22
+ sanitizado distingue inserção, duplicata, caminho pulado, abortado, lock ocupado, falha e status
23
+ de observabilidade; o cursor só avança após confirmação da nota.
24
+ - **A importação Codex compartilha a normalização de conteúdo sintético e ferramentas.**
25
+ `subagent_notification` não vira prompt, `turn_aborted` é explícito e a saída de uma
26
+ `custom_tool_call` não é contada como uma segunda chamada.
27
+ - **O encerramento de uma sessão alinha a projeção e a autoridade causal.** O Stop marca a
28
+ activation e a sessão como `done` no `SESSION_REGISTRY.json` somente depois da publicação de
29
+ memória/observabilidade; `CURRENT_SESSION.md` continua sendo uma visão derivada e não lista
30
+ sessões já finalizadas.
31
+ - **O release automático publica no npm por OIDC antes de criar tag e GitHub Release.** O
32
+ `auto-tag.yml` usa Node 24, prepara o registry público, ignora versões já publicadas com
33
+ `--prefer-online` e deixa a provenance ser gerada pela própria publicação confiável.
34
+
35
+ ## [0.68.4] — 2026-08-14
36
+
37
+ ### Fixed
38
+
39
+ - **O guard de escopo do projeto passa a proteger mutações antes da ferramenta.** O `PreToolUse`
40
+ do Codex revalida sessão, projeto, raiz Git, remoto, branch/worktree e concorrência; mantém
41
+ `commit`, `push`, `pull`, `merge`, `publish` e operações destrutivas como capacidades
42
+ independentes, com bloqueio fail-closed para alvos ausentes ou divergentes.
43
+
44
+ ## [0.68.3] — 2026-08-13
45
+
46
+ ### Fixed
47
+
48
+ - **Deferred replay reancora candidates de memória na fonte causal final.** Depois de uma
49
+ promoção legacy válida, um assert moderno reaplicado pelo replay não deixa mais os
50
+ candidates posteriores presos à fonte intermediária. A promoção explícita continua
51
+ exigindo o guard causal e mantém o fail-closed para linhagens incompletas ou ambíguas;
52
+ o ledger permanece append-only.
53
+
54
+ ## [0.68.2] — 2026-08-08
55
+
56
+ ### Fixed
57
+
58
+ - **O guard do `npm run release` deixa de bloquear a tag criada pelo `auto-tag.yml`.** Os dois
59
+ automatismos assumem ordens opostas: o script publica no npm e então cria a tag, enquanto o
60
+ workflow cria a tag no merge em `main`, antes de qualquer publish. Quando o merge precedia o
61
+ publish — o caminho normal de um PR — o release abortava num estado perfeitamente publicável.
62
+ O guard passa a proteger a unicidade da versão no registry, não a ausência da tag: publica e
63
+ preserva a tag existente quando ela aponta para o commit corrente, e continua abortando se a
64
+ versão já foi lançada ou se a tag aponta para outro commit. A decisão virou função pura, então
65
+ a matriz de estados é verificável sem publicar nem mutar o repositório.
66
+
7
67
  ## [0.68.1] — 2026-08-08
8
68
 
9
69
  ### Fixed
package/README.en.md CHANGED
@@ -91,8 +91,11 @@ Decisions, dead ends, the reason you chose X over Y — gone next session. The p
91
91
 
92
92
  ## Requirements
93
93
 
94
+ The Codex scope guard treats `commit`, `push`, `pull`, `merge`, `publish`, and destructive
95
+ operations as independent capabilities, including inside compound commands.
96
+
94
97
  - Node.js ≥ 18
95
- - An AI coding agent with hooks. `init` wires **Claude Code** and **Codex** automatically — Codex gets the seven hooks its event model supports and enumerates them untrusted, so approve its “Hooks need review” prompt once at startup (see [Notes & roadmap](#notes--roadmap))
98
+ - An AI coding agent with hooks. `init` wires **Claude Code** and **Codex** automatically — Codex gets eight compatible hooks, including the scoped `PreToolUse` guard, and enumerates them untrusted, so approve its “Hooks need review” prompt once at startup (see [Notes & roadmap](#notes--roadmap))
96
99
  - Obsidian (to view the graph) — optional but the point
97
100
 
98
101
  ## Install & set up
@@ -107,7 +110,7 @@ npx wendkeep init
107
110
 
108
111
  1. Create the vault folder taxonomy and a templated `README.md` (default vault: `<project>/.<project-name>-vault`, e.g. `.MyApp-vault`; override with `--vault`).
109
112
  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.
110
- 3. Wire the Codex session hooks in **`.codex/hooks.json`** — seven of the twelve: `brain-inject` + `session-start` on `SessionStart`, `session-ensure` + `change-context` on `UserPromptSubmit`, `session-stop` + `change-nag` on `Stop`, `subagent-stop` on `SubagentStop`, always in the `npx wendkeep hook <name>` form. The other five are left out because Codex offers no equivalent payload, tool *or* event: `change-guard` (a `PreToolUse` gate reading `tool_input.command`, but Codex's `exec` carries `tool_input` as a raw string rather than an object, so the gate would fail *open*), `change-warn` (a `PostToolUse` nudge resolving `tool_input.file_path`, a field `apply_patch`'s envelope does not carry — nothing to resolve, and nothing to gate), `plan-capture` (there is no `ExitPlanMode`; `update_plan` is a running TODO list, not an approval), `decision-capture` (`AskUserQuestion` is a Claude-only tool) and `task-log` (`TaskCompleted` is not in Codex's event enum). See [Notes & roadmap](#notes--roadmap) for the per-hook detail. The merge is non-destructive, on the same discipline as `settings.json`: it recognizes an already-wired group and never duplicates on re-init, preserves third-party hooks, saves a `.bak`, and `--force` updates `timeoutSec`/`statusMessage` in place; an unparseable `.codex/hooks.json` is left untouched with the merge written to `.codex/hooks.json.new`. **Codex enumerates every hook as untrusted and runs none of them until you approve the “Hooks need review” prompt at startup — `init` cannot pre-approve them**, and it prints a warning saying so. Anyone who already had hand-written wendkeep hooks in Codex gets one re-review prompt: `init` migrates the legacy `timeout` key (which Codex neither rejects nor reads, falling through to a 600s default) to `timeoutSec`, and that changes the hook's hashed identity.
113
+ 3. Wire the Codex hooks in **`.codex/hooks.json`** — eight of the twelve: `brain-inject` + `session-start` on `SessionStart`, `session-ensure` + `change-context` on `UserPromptSubmit`, `session-stop` + `change-nag` on `Stop`, `subagent-stop` 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. 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. 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**.
111
114
  4. Add the **`wendkeep-vault`** MCP server to `.mcp.json` so the agent can read/write the vault. Skip with `--no-mcp` — e.g. when the agent already has a vault MCP. (`--no-mcp` skips *only wendkeep's own* MCP; companion MCPs still follow `--companions`.)
112
115
  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:
113
116
  - **`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`.
@@ -173,24 +176,37 @@ The install stays outside `sync` on purpose: a running process cannot replace it
173
176
  keep going — the code in memory would still be the old one.
174
177
 
175
178
  In a **pnpm** monorepo the install command differs (`npm` in a pnpm repo fails with
176
- `Cannot read properties of null (reading 'matches')`) and the version must be **exact**:
177
-
178
- ```bash
179
- pnpm add -D -w wendkeep@X.Y.Z --config.minimumReleaseAge=0 && npx --no-install wendkeep sync --project . --yes
179
+ `Cannot read properties of null (reading 'matches')`). Resolve the published version first and
180
+ reuse exactly the value returned:
181
+
182
+ ```powershell
183
+ $version = pnpm view wendkeep version
184
+ pnpm add -D -w "wendkeep@$version" --config.minimumReleaseAge=0
185
+ pnpm install --update-checksums --config.minimumReleaseAge=0
186
+ pnpm exec wendkeep sync --project . --yes
180
187
  ```
181
188
 
182
189
  > **Do not ask pnpm for `wendkeep@latest`.** pnpm 11 ignores packages published in the last
183
190
  > 24h by default (`minimumReleaseAge`, a supply-chain guard) — and it does not complain: it
184
191
  > installs the previous version, exits 0, and the only hint is a quiet `(X.Y.Z is available)`
185
192
  > in the output. You end up on the old version thinking you upgraded. Check with
186
- > `npx wendkeep --version`.
193
+ > `pnpm exec wendkeep --version`.
194
+ >
195
+ > Do not edit only the version or integrity in `pnpm-lock.yaml`. `pnpm add` and
196
+ > `pnpm install --update-checksums` must recalculate the complete entry. If the lock is already
197
+ > inconsistent and `ERR_PNPM_TARBALL_INTEGRITY` appears, prune the local store and repeat:
198
+ >
199
+ > ```powershell
200
+ > pnpm store prune
201
+ > pnpm install --update-checksums --config.minimumReleaseAge=0
202
+ > ```
187
203
  >
188
204
  > After installing, record the exception in `pnpm-workspace.yaml` — **pnpm does not write
189
205
  > that line for you**:
190
206
  >
191
207
  > ```yaml
192
208
  > minimumReleaseAgeExclude:
193
- > - wendkeep@X.Y.Z
209
+ > - wendkeep@<the version returned by pnpm view>
194
210
  > ```
195
211
  >
196
212
  > Without it, CI's `pnpm install` fails with `ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION` until
@@ -379,8 +395,9 @@ it does not expose memory values or content. After human review,
379
395
  new promotion accepts a later Stop from the same session/activation without recreating a conflict.
380
396
  A promotion written by 0.66.1 remains historical: if the next Stop forms a new candidate, update
381
397
  to 0.66.3 and run `memory repair`. During replay, a transient candidate is re-evaluated against the
382
- final modern source: the same session/activation/epoch and a higher turn advances; a lower turn is
383
- superseded. Repair migrates the checkpoint and mirror only when it proves the exact previous
398
+ final modern source and, when causal supersession is proven, re-anchored to it; explicit promotion
399
+ uses that anchor and crosses only the physical predecessors required by replay. The same
400
+ 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
384
401
  replay, attempt identity, and absence of a real conflict; it creates a backup and audit without
385
402
  appending or rewriting events. Ambiguity stays queued for explicit curation. Do not publish or
386
403
  install 0.66.2; use 0.66.3 or later. Decisions survive repair/replay;
@@ -393,7 +410,11 @@ acknowledgement pending on 0.66.4 or later, first run the targeted dry run
393
410
  registry/checkpoint. See syntax, preconditions, and fail-closed behavior in
394
411
  [memory and curation](docs/en/commands/memory.md).
395
412
 
396
- 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. 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.
413
+ 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.
414
+
415
+ On definitive close, the activation and session become `done` in `SESSION_REGISTRY.json` only
416
+ after memory/observability publication; `CURRENT_SESSION.md` is a derived view, not the identity
417
+ authority, and does not list finalized sessions.
397
418
 
398
419
  ## Retroactive memory (`import`) — install today, remember yesterday
399
420
 
@@ -521,7 +542,7 @@ The archive **gate** blocks unless: the change scaffold is filled (G0), no task
521
542
  - **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.
522
543
  - **Search is keyword/frontmatter scoring**, not on‑device embeddings (that's on the roadmap).
523
544
  - **Transcript formats are agent‑internal** and can change between agent versions; parsing is isolated but may need updates.
524
- - Installer wires **both agents**: `.claude/settings.json` + `.mcp.json` for Claude Code, `.codex/hooks.json` for Codex. **Five hooks stay Claude‑only** because Codex has no equivalent payload, tool or event: `change-guard` (a `PreToolUse` gate that reads `tool_input.command`, but Codex's `exec` carries `tool_input` as a raw string rather than an object the gate would fail *open*), `change-warn` (a `PostToolUse` nudge that resolves `tool_input.file_path`, which `apply_patch`'s envelope simply does not carry — nothing to resolve, and nothing to gate), `plan-capture` (no `ExitPlanMode` — `update_plan` is a running TODO list, not an approval), `decision-capture` (`AskUserQuestion` is Claude‑only) and `task-log` (`TaskCompleted` is not in Codex's event enum).
545
+ - 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`.
525
546
  - **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.
526
547
 
527
548
  ---
package/README.md CHANGED
@@ -91,8 +91,11 @@ Decisions, dead ends, the reason you chose X over Y — gone next session. The p
91
91
 
92
92
  ## Requirements
93
93
 
94
+ The Codex scope guard treats `commit`, `push`, `pull`, `merge`, `publish`, and destructive
95
+ operations as independent capabilities, including inside compound commands.
96
+
94
97
  - Node.js ≥ 18
95
- - An AI coding agent with hooks. `init` wires **Claude Code** and **Codex** automatically — Codex gets the seven hooks its event model supports and enumerates them untrusted, so approve its “Hooks need review” prompt once at startup (see [Notes & roadmap](#notes--roadmap))
98
+ - An AI coding agent with hooks. `init` wires **Claude Code** and **Codex** automatically — Codex gets eight compatible hooks, including the scoped `PreToolUse` guard, and enumerates them untrusted, so approve its “Hooks need review” prompt once at startup (see [Notes & roadmap](#notes--roadmap))
96
99
  - Obsidian (to view the graph) — optional but the point
97
100
 
98
101
  ## Install & set up
@@ -107,7 +110,7 @@ npx wendkeep init
107
110
 
108
111
  1. Create the vault folder taxonomy and a templated `README.md` (default vault: `<project>/.<project-name>-vault`, e.g. `.MyApp-vault`; override with `--vault`).
109
112
  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.
110
- 3. Wire the Codex session hooks in **`.codex/hooks.json`** — seven of the twelve: `brain-inject` + `session-start` on `SessionStart`, `session-ensure` + `change-context` on `UserPromptSubmit`, `session-stop` + `change-nag` on `Stop`, `subagent-stop` on `SubagentStop`, always in the `npx wendkeep hook <name>` form. The other five are left out because Codex offers no equivalent payload, tool *or* event: `change-guard` (a `PreToolUse` gate reading `tool_input.command`, but Codex's `exec` carries `tool_input` as a raw string rather than an object, so the gate would fail *open*), `change-warn` (a `PostToolUse` nudge resolving `tool_input.file_path`, a field `apply_patch`'s envelope does not carry — nothing to resolve, and nothing to gate), `plan-capture` (there is no `ExitPlanMode`; `update_plan` is a running TODO list, not an approval), `decision-capture` (`AskUserQuestion` is a Claude-only tool) and `task-log` (`TaskCompleted` is not in Codex's event enum). See [Notes & roadmap](#notes--roadmap) for the per-hook detail. The merge is non-destructive, on the same discipline as `settings.json`: it recognizes an already-wired group and never duplicates on re-init, preserves third-party hooks, saves a `.bak`, and `--force` updates `timeoutSec`/`statusMessage` in place; an unparseable `.codex/hooks.json` is left untouched with the merge written to `.codex/hooks.json.new`. **Codex enumerates every hook as untrusted and runs none of them until you approve the “Hooks need review” prompt at startup — `init` cannot pre-approve them**, and it prints a warning saying so. Anyone who already had hand-written wendkeep hooks in Codex gets one re-review prompt: `init` migrates the legacy `timeout` key (which Codex neither rejects nor reads, falling through to a 600s default) to `timeoutSec`, and that changes the hook's hashed identity.
113
+ 3. Wire the Codex hooks in **`.codex/hooks.json`** — eight of the twelve: `brain-inject` + `session-start` on `SessionStart`, `session-ensure` + `change-context` on `UserPromptSubmit`, `session-stop` + `change-nag` on `Stop`, `subagent-stop` 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. 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. 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**.
111
114
  4. Add the **`wendkeep-vault`** MCP server to `.mcp.json` so the agent can read/write the vault. Skip with `--no-mcp` — e.g. when the agent already has a vault MCP. (`--no-mcp` skips *only wendkeep's own* MCP; companion MCPs still follow `--companions`.)
112
115
  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:
113
116
  - **`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`.
@@ -173,24 +176,37 @@ The install stays outside `sync` on purpose: a running process cannot replace it
173
176
  keep going — the code in memory would still be the old one.
174
177
 
175
178
  In a **pnpm** monorepo the install command differs (`npm` in a pnpm repo fails with
176
- `Cannot read properties of null (reading 'matches')`) and the version must be **exact**:
177
-
178
- ```bash
179
- pnpm add -D -w wendkeep@X.Y.Z --config.minimumReleaseAge=0 && npx --no-install wendkeep sync --project . --yes
179
+ `Cannot read properties of null (reading 'matches')`). Resolve the published version first and
180
+ reuse exactly the value returned:
181
+
182
+ ```powershell
183
+ $version = pnpm view wendkeep version
184
+ pnpm add -D -w "wendkeep@$version" --config.minimumReleaseAge=0
185
+ pnpm install --update-checksums --config.minimumReleaseAge=0
186
+ pnpm exec wendkeep sync --project . --yes
180
187
  ```
181
188
 
182
189
  > **Do not ask pnpm for `wendkeep@latest`.** pnpm 11 ignores packages published in the last
183
190
  > 24h by default (`minimumReleaseAge`, a supply-chain guard) — and it does not complain: it
184
191
  > installs the previous version, exits 0, and the only hint is a quiet `(X.Y.Z is available)`
185
192
  > in the output. You end up on the old version thinking you upgraded. Check with
186
- > `npx wendkeep --version`.
193
+ > `pnpm exec wendkeep --version`.
194
+ >
195
+ > Do not edit only the version or integrity in `pnpm-lock.yaml`. `pnpm add` and
196
+ > `pnpm install --update-checksums` must recalculate the complete entry. If the lock is already
197
+ > inconsistent and `ERR_PNPM_TARBALL_INTEGRITY` appears, prune the local store and repeat:
198
+ >
199
+ > ```powershell
200
+ > pnpm store prune
201
+ > pnpm install --update-checksums --config.minimumReleaseAge=0
202
+ > ```
187
203
  >
188
204
  > After installing, record the exception in `pnpm-workspace.yaml` — **pnpm does not write
189
205
  > that line for you**:
190
206
  >
191
207
  > ```yaml
192
208
  > minimumReleaseAgeExclude:
193
- > - wendkeep@X.Y.Z
209
+ > - wendkeep@<the version returned by pnpm view>
194
210
  > ```
195
211
  >
196
212
  > Without it, CI's `pnpm install` fails with `ERR_PNPM_MINIMUM_RELEASE_AGE_VIOLATION` until
@@ -379,8 +395,9 @@ it does not expose memory values or content. After human review,
379
395
  new promotion accepts a later Stop from the same session/activation without recreating a conflict.
380
396
  A promotion written by 0.66.1 remains historical: if the next Stop forms a new candidate, update
381
397
  to 0.66.3 and run `memory repair`. During replay, a transient candidate is re-evaluated against the
382
- final modern source: the same session/activation/epoch and a higher turn advances; a lower turn is
383
- superseded. Repair migrates the checkpoint and mirror only when it proves the exact previous
398
+ final modern source and, when causal supersession is proven, re-anchored to it; explicit promotion
399
+ uses that anchor and crosses only the physical predecessors required by replay. The same
400
+ 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
384
401
  replay, attempt identity, and absence of a real conflict; it creates a backup and audit without
385
402
  appending or rewriting events. Ambiguity stays queued for explicit curation. Do not publish or
386
403
  install 0.66.2; use 0.66.3 or later. Decisions survive repair/replay;
@@ -393,7 +410,11 @@ acknowledgement pending on 0.66.4 or later, first run the targeted dry run
393
410
  registry/checkpoint. See syntax, preconditions, and fail-closed behavior in
394
411
  [memory and curation](docs/en/commands/memory.md).
395
412
 
396
- 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. 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.
413
+ 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.
414
+
415
+ On definitive close, the activation and session become `done` in `SESSION_REGISTRY.json` only
416
+ after memory/observability publication; `CURRENT_SESSION.md` is a derived view, not the identity
417
+ authority, and does not list finalized sessions.
397
418
 
398
419
  ## Retroactive memory (`import`) — install today, remember yesterday
399
420
 
@@ -521,7 +542,7 @@ The archive **gate** blocks unless: the change scaffold is filled (G0), no task
521
542
  - **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.
522
543
  - **Search is keyword/frontmatter scoring**, not on‑device embeddings (that's on the roadmap).
523
544
  - **Transcript formats are agent‑internal** and can change between agent versions; parsing is isolated but may need updates.
524
- - Installer wires **both agents**: `.claude/settings.json` + `.mcp.json` for Claude Code, `.codex/hooks.json` for Codex. **Five hooks stay Claude‑only** because Codex has no equivalent payload, tool or event: `change-guard` (a `PreToolUse` gate that reads `tool_input.command`, but Codex's `exec` carries `tool_input` as a raw string rather than an object the gate would fail *open*), `change-warn` (a `PostToolUse` nudge that resolves `tool_input.file_path`, which `apply_patch`'s envelope simply does not carry — nothing to resolve, and nothing to gate), `plan-capture` (no `ExitPlanMode` — `update_plan` is a running TODO list, not an approval), `decision-capture` (`AskUserQuestion` is Claude‑only) and `task-log` (`TaskCompleted` is not in Codex's event enum).
545
+ - 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`.
525
546
  - **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.
526
547
 
527
548
  ---
@@ -70,6 +70,18 @@ npx wendkeep sensors add api-contracts "npm run test:contracts" --severity criti
70
70
  An archived change promotes its delta into the living spec, preserves proposal/design/tasks/proof,
71
71
  and mints an ADR. Archive passes only with closed tasks, green required sensors, and a fresh verdict.
72
72
 
73
+ ## Tool-scope fence
74
+
75
+ `change-guard` is also projected to Codex `PreToolUse`. Before a Git mutation or supported writing
76
+ tool runs, it compares the session, project, Git root, remote, branch, and worktree with the lease
77
+ recorded in `SESSION_REGISTRY.json`. Missing, ambiguous, concurrent, or cross-project targets are
78
+ blocked before the tool.
79
+
80
+ Codex blocks with `permissionDecision: "deny"`; `ask` is not a valid `PreToolUse` decision.
81
+ `commit`, `push`, `pull`, `merge`, `publish`, and destructive operations remain separate capabilities,
82
+ including when one command contains multiple actions. Switching projects requires a new explicit
83
+ selection/lease; never carry authorization from another conversation.
84
+
73
85
  ## Common errors and diagnosis
74
86
 
75
87
  - `no change`: select one with `change use <slug>` or pass `--change`.
@@ -60,14 +60,22 @@ npm install --save-dev wendkeep@latest
60
60
  npx wendkeep sync --yes
61
61
  ```
62
62
 
63
- With pnpm, pin a concrete version because minimum-release-age policies may keep `latest` silently
64
- behind:
63
+ With pnpm, query the published version and reuse the returned value. Minimum-release-age policies
64
+ may keep `latest` silently behind; in a monorepo, `-w` targets the workspace root:
65
65
 
66
- ```bash
67
- pnpm add -D wendkeep@X.Y.Z --config.minimumReleaseAge=0
66
+ ```powershell
67
+ $version = pnpm view wendkeep version
68
+ pnpm add -D -w "wendkeep@$version" --config.minimumReleaseAge=0
69
+ pnpm install --update-checksums --config.minimumReleaseAge=0
68
70
  pnpm exec wendkeep sync --yes
69
71
  ```
70
72
 
73
+ Do not edit only the version or integrity in `pnpm-lock.yaml`. If
74
+ `ERR_PNPM_TARBALL_INTEGRITY` appears after a manual edit, run `pnpm store prune` and repeat
75
+ `pnpm install --update-checksums --config.minimumReleaseAge=0`. The
76
+ `minimumReleaseAgeExclude` entry in `pnpm-workspace.yaml` is also manual and must use the
77
+ version returned by `pnpm view`; pnpm does not write that line.
78
+
71
79
  ## Expected result
72
80
 
73
81
  The project receives `.wendkeep.json`, managed Claude/Codex hooks, skill definitions, and an
@@ -108,7 +108,9 @@ npx wendkeep validate-memory --vault <v2-vault>
108
108
  the already validated JSON value without string coercion and copies the selected event's
109
109
  `canonical_session_id`, activation/epoch, `source_turn_id`, and `turn_sequence`. A later Stop
110
110
  from the same session/activation therefore advances the value instead of opening another candidate.
111
- During replay, a transient candidate is re-evaluated against the final modern source. The same
111
+ During replay, a transient candidate is re-evaluated and, when causal supersession is proven,
112
+ re-anchored to the final modern source; explicit promotion uses that new anchor and includes only
113
+ the physical predecessors needed for replay. The same
112
114
  session/activation/epoch and a higher turn applies the Stop; a lower turn is superseded. A
113
115
  different, incomplete, or ambiguous identity keeps the candidate queued for curation. `memory
114
116
  repair` compares the old and current replay and migrates checkpoint+mirror only with exact
@@ -33,6 +33,17 @@ change.
33
33
  - For FLOW, a Git repository, a path allowlist, a reason, and at least one existing sensor in
34
34
  `wendkeep.sensors.json`.
35
35
 
36
+ ### Tool scope and Git authorization
37
+
38
+ Under `GOVERN`/`ASSURE`, Codex `PreToolUse` and the equivalent Claude gate validate the project lease
39
+ before mutations. The lease includes the session, `project_id`, project root, Git root, remote,
40
+ branch/worktree, and provider. `commit`, `push`, `pull`, `merge`, `publish`, and destructive operations
41
+ are independent capabilities, including in compound commands; authorization never crosses projects or
42
+ branches.
43
+
44
+ If the host does not expose the effective directory, or the session is conflicted, the mutation is
45
+ denied with a sanitized diagnostic. Read-only inspection may continue for investigation.
46
+
36
47
  ## Syntax
37
48
 
38
49
  ```bash
@@ -63,6 +63,13 @@ npx wendkeep import [options]
63
63
  - Observability is tri-state: `complete` publishes the full snapshot; `none` means zero proven by
64
64
  a causal Stop or stable offline scan; `degraded` preserves the previous snapshot and allowlisted
65
65
  diagnostics. An isolated `SubagentStop` never publishes `none`.
66
+ - Every terminal `Stop`/`SubagentStop` attempt leaves a sanitized receipt in
67
+ `.brain/SESSION_ITERATION_OUTCOMES.jsonl`, keyed by session, `turn_id`, and stage. States
68
+ distinguish `inserted`, `duplicate`, `skipped`, `aborted`, `busy`, `failed`, and observability
69
+ statuses; the cursor advances only after the note is confirmed. The ledger is local, append-only,
70
+ idempotent, and never persists prompts, payloads, raw arguments, or raw errors.
71
+ - In Codex, `subagent_notification` remains synthetic, `turn_aborted` is an explicit terminal
72
+ state, and `custom_tool_call_output` closes the existing call without counting a second tool.
66
73
  - When compacting conversations into `## Iterações`, the hook escapes code delimiters cut by the
67
74
  size limit; inline backticks and fences never remain open and consume the following line.
68
75
  - `session list` reads `SESSION_REGISTRY`; `show` displays one session and `use` only changes human
@@ -73,6 +80,10 @@ npx wendkeep import [options]
73
80
  - `import` reconciles observability even when no `wk-turn` is missing: a legacy schema, stale
74
81
  frontier, or unproven manifest triggers recomposition without duplicating iterations. A fresh
75
82
  checkpoint remains byte-identical; `degraded` is reported and does not change the note.
83
+ - On definitive close, Stop marks the activation and session `done` in `SESSION_REGISTRY.json`
84
+ only after memory/observability publication; `CURRENT_SESSION.md` is a derived view and no
85
+ longer lists the finalized session. Hooks resolve identity from the registry and transcript,
86
+ never from the global pointer.
76
87
  - `hook session-backfill` recovers missing `wk-turn` markers for the selected session. Without
77
88
  `--write`, it only reports. On Codex, `missingTurns` contains only turns with `task_complete`;
78
89
  open turns appear under `incompleteTurns` and are never written. `--write` applies only completed
@@ -105,6 +116,8 @@ only recognized generated fields under `Iterações` and `Encerramento` are migr
105
116
  authored prose.
106
117
  Duplicate/stale hooks converge on the same frontier, and imports may refresh only observability
107
118
  without creating a new turn block.
119
+ The per-attempt receipt in `SESSION_ITERATION_OUTCOMES.jsonl` distinguishes a confirmed duplicate
120
+ from a busy lock or skipped path without reopening the original session.
108
121
 
109
122
  ## Common errors and diagnosis
110
123
 
@@ -122,6 +135,8 @@ without creating a new turn block.
122
135
  - Contaminated cost: validate `session_id → session_file → transcript_path → provider`.
123
136
  - `degraded` observability: preserve the note and run a targeted rebuild dry-run; never force a
124
137
  partial snapshot over the last `complete` one.
138
+ - Missing or `busy` outcome ledger: preserve the transcript and note, inspect the Vault lock, and
139
+ retry the bounded hook/replay path; never mark the turn projected by hand.
125
140
 
126
141
  ## Next steps
127
142
 
@@ -70,6 +70,18 @@ npx wendkeep sensors add api-contracts "npm run test:contracts" --severity criti
70
70
  A change arquivada move seu delta para o spec vivo, preserva proposta/design/tarefas/evidência e
71
71
  gera um ADR. O archive só passa com tarefas fechadas, sensores exigidos verdes e verdict atual.
72
72
 
73
+ ## Cerca de escopo para ferramentas
74
+
75
+ O `change-guard` também é projetado para o `PreToolUse` do Codex. Antes de uma mutação Git ou de
76
+ uma ferramenta de escrita suportada, ele compara sessão, projeto, raiz Git, remoto, branch e
77
+ worktree com a lease registrada no `SESSION_REGISTRY.json`. Um alvo ausente, ambíguo, concorrente ou
78
+ fora do projeto é bloqueado antes da ferramenta.
79
+
80
+ No Codex o bloqueio usa `permissionDecision: "deny"`; `ask` não é uma decisão válida de
81
+ `PreToolUse`. `commit`, `push`, `pull`, `merge`, `publish` e operações destrutivas continuam
82
+ capacidades separadas, inclusive quando um comando contém mais de uma ação. A troca de projeto
83
+ exige uma nova seleção/lease; não use autorização de outra conversa.
84
+
73
85
  ## Erros comuns e diagnóstico
74
86
 
75
87
  - `no change`: selecione com `change use <slug>` ou informe `--change`.
@@ -60,14 +60,22 @@ npm install --save-dev wendkeep@latest
60
60
  npx wendkeep sync --yes
61
61
  ```
62
62
 
63
- Com pnpm, informe uma versão concreta porque políticas de idade mínima podem manter `latest`
64
- atrasado silenciosamente:
63
+ Com pnpm, consulte a versão publicada e reutilize o valor retornado. Políticas de idade mínima
64
+ podem manter `latest` atrasado silenciosamente; em um monorepo, `-w` aponta para o workspace raiz:
65
65
 
66
- ```bash
67
- pnpm add -D wendkeep@X.Y.Z --config.minimumReleaseAge=0
66
+ ```powershell
67
+ $version = pnpm view wendkeep version
68
+ pnpm add -D -w "wendkeep@$version" --config.minimumReleaseAge=0
69
+ pnpm install --update-checksums --config.minimumReleaseAge=0
68
70
  pnpm exec wendkeep sync --yes
69
71
  ```
70
72
 
73
+ Não edite apenas a versão ou a integridade no `pnpm-lock.yaml`. Se aparecer
74
+ `ERR_PNPM_TARBALL_INTEGRITY` depois de uma edição manual, rode `pnpm store prune` e repita
75
+ `pnpm install --update-checksums --config.minimumReleaseAge=0`. A exceção
76
+ `minimumReleaseAgeExclude` do `pnpm-workspace.yaml` também é manual e deve usar a versão
77
+ retornada por `pnpm view`; o pnpm não escreve essa linha.
78
+
71
79
  ## Resultado esperado
72
80
 
73
81
  O projeto recebe `.wendkeep.json`, hooks gerenciados de Claude/Codex, definições de skills e um
@@ -106,7 +106,9 @@ npx wendkeep validate-memory --vault <cofre-v2>
106
106
  A decisão conserva, sem coerção para string, o valor JSON já validado e copia do evento escolhido
107
107
  `canonical_session_id`, activation/epoch, `source_turn_id` e `turn_sequence`. Por isso, um Stop
108
108
  posterior da mesma sessão/activation avança o valor em vez de abrir outro candidate. Durante o
109
- replay, um candidate transitório é reavaliado contra a fonte moderna final. Mesma
109
+ replay, um candidate transitório é reavaliado e, quando a supersession causal é provada,
110
+ reancorado contra a fonte moderna final; a promoção explícita usa essa nova âncora e inclui
111
+ somente os predecessores físicos necessários. Mesma
110
112
  sessão/activation/epoch e turno maior aplica o Stop; turno menor fica superseded. Identidade
111
113
  divergente, incompleta ou ambígua mantém o candidate para curadoria. `memory repair` compara o
112
114
  replay anterior e o atual e só migra checkpoint+espelho com identidade exata, backup, audit e
@@ -33,6 +33,17 @@ gates/policies do WendKeep; promova o trabalho para uma change.
33
33
  - Para FLOW, repositório Git, allowlist de paths, motivo e ao menos um sensor existente em
34
34
  `wendkeep.sensors.json`.
35
35
 
36
+ ### Escopo de ferramenta e autorização Git
37
+
38
+ Em `GOVERN`/`ASSURE`, o `PreToolUse` do Codex e o gate equivalente do Claude validam a lease de
39
+ projeto antes de mutações. A lease inclui sessão, `project_id`, raiz do projeto, raiz Git, remoto,
40
+ branch/worktree e provider. `commit`, `push`, `pull`, `merge`, `publish` e operações destrutivas são
41
+ capacidades independentes, inclusive em comandos compostos; uma autorização não atravessa projetos
42
+ nem branches.
43
+
44
+ Se o host não expuser o diretório efetivo, ou se a sessão estiver em conflito, a mutação é negada
45
+ com diagnóstico sanitizado. Somente leitura pode continuar para investigação.
46
+
36
47
  ## Sintaxe
37
48
 
38
49
  ```bash
@@ -62,6 +62,13 @@ npx wendkeep import [opções]
62
62
  - A observabilidade usa tri-state: `complete` publica o snapshot integral; `none` representa zero
63
63
  comprovado por Stop causal ou scan offline estável; `degraded` preserva o snapshot anterior e
64
64
  diagnostics allowlisted. `SubagentStop` isolado nunca publica `none`.
65
+ - Cada tentativa terminal de `Stop`/`SubagentStop` deixa um recibo sanitizado em
66
+ `.brain/SESSION_ITERATION_OUTCOMES.jsonl`, indexado por sessão, `turn_id` e estágio. Os estados
67
+ distinguem `inserted`, `duplicate`, `skipped`, `aborted`, `busy`, `failed` e os status de
68
+ observabilidade; o cursor só avança depois da confirmação da nota. O ledger é local, append-only,
69
+ idempotente e nunca persiste prompt, payload, argumento bruto ou erro bruto.
70
+ - No Codex, `subagent_notification` continua sintético, `turn_aborted` é terminal explícito e
71
+ `custom_tool_call_output` fecha a chamada existente sem contar uma segunda ferramenta.
65
72
  - Ao compactar conversas em `## Iterações`, o hook escapa delimitadores de código cortados pelo
66
73
  limite de tamanho; backticks inline ou fences nunca ficam abertos para engolir a linha seguinte.
67
74
  - `session list` lê `SESSION_REGISTRY`; `show` exibe uma sessão e `use` muda apenas o foco humano
@@ -72,6 +79,10 @@ npx wendkeep import [opções]
72
79
  - `import` reconcilia a observabilidade mesmo quando nenhum `wk-turn` está ausente: schema legado,
73
80
  frontier stale ou manifest não comprovado disparam recomposição sem duplicar iterações. Um
74
81
  checkpoint fresco permanece byte-idêntico; `degraded` é reportado e não altera a nota.
82
+ - No encerramento definitivo, o Stop fecha a activation e a sessão como `done` no
83
+ `SESSION_REGISTRY.json` depois de memória/observabilidade; `CURRENT_SESSION.md` é uma visão
84
+ derivada e deixa de listar a sessão finalizada. Hooks resolvem identidade pelo registry e pelo
85
+ transcript, nunca pelo ponteiro global.
75
86
  - `hook session-backfill` recupera `wk-turn` ausente da sessão selecionada. Sem `--write`, apenas
76
87
  relata. Em Codex, `missingTurns` contém somente turnos com `task_complete`; turnos ainda abertos
77
88
  aparecem em `incompleteTurns` e nunca são gravados. `--write` aplica apenas os candidatos
@@ -104,6 +115,8 @@ ao finalizar uma nota antiga, somente campos gerados reconhecíveis em `Iteraç
104
115
  `Encerramento` são migrados, sem reescrever a prosa autoral. Hooks
105
116
  duplicados/stale convergem no mesmo frontier, e importações podem atualizar só a observabilidade
106
117
  sem criar um novo bloco de turno.
118
+ O recibo de cada tentativa em `SESSION_ITERATION_OUTCOMES.jsonl` permite diferenciar uma duplicata
119
+ confirmada de um lock ocupado ou de um caminho que foi pulado, sem reabrir a sessão original.
107
120
 
108
121
  ## Erros comuns e diagnóstico
109
122
 
@@ -121,6 +134,8 @@ sem criar um novo bloco de turno.
121
134
  - Custo contaminado: valide `session_id → session_file → transcript_path → provider`.
122
135
  - Observabilidade `degraded`: preserve a nota e rode o rebuild direcionado em dry-run; não force
123
136
  um snapshot parcial sobre o último `complete`.
137
+ - Ledger de resultado ausente ou com `busy`: preserve o transcript e a nota, confira o lock do Vault
138
+ e repita o hook/replay limitado; nunca marque o turno como projetado manualmente.
124
139
 
125
140
  ## Próximos passos
126
141