wendkeep 0.68.0 → 0.68.5

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,73 @@ 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.5] — 2026-08-14
8
+
9
+ ### Fixed
10
+
11
+ - **O Stop passa a deixar um resultado durável por sessão, turno e estágio.** O ledger local,
12
+ append-only,
13
+ sanitizado distingue inserção, duplicata, caminho pulado, abortado, lock ocupado, falha e status
14
+ de observabilidade; o cursor só avança após confirmação da nota.
15
+ - **A importação Codex compartilha a normalização de conteúdo sintético e ferramentas.**
16
+ `subagent_notification` não vira prompt, `turn_aborted` é explícito e a saída de uma
17
+ `custom_tool_call` não é contada como uma segunda chamada.
18
+ - **O encerramento de uma sessão alinha a projeção e a autoridade causal.** O Stop marca a
19
+ activation e a sessão como `done` no `SESSION_REGISTRY.json` somente depois da publicação de
20
+ memória/observabilidade; `CURRENT_SESSION.md` continua sendo uma visão derivada e não lista
21
+ sessões já finalizadas.
22
+ - **O release automático publica no npm por OIDC antes de criar tag e GitHub Release.** O
23
+ `auto-tag.yml` usa Node 24, prepara o registry público, ignora versões já publicadas com
24
+ `--prefer-online` e deixa a provenance ser gerada pela própria publicação confiável.
25
+
26
+ ## [0.68.4] — 2026-08-14
27
+
28
+ ### Fixed
29
+
30
+ - **O guard de escopo do projeto passa a proteger mutações antes da ferramenta.** O `PreToolUse`
31
+ do Codex revalida sessão, projeto, raiz Git, remoto, branch/worktree e concorrência; mantém
32
+ `commit`, `push`, `pull`, `merge`, `publish` e operações destrutivas como capacidades
33
+ independentes, com bloqueio fail-closed para alvos ausentes ou divergentes.
34
+
35
+ ## [0.68.3] — 2026-08-13
36
+
37
+ ### Fixed
38
+
39
+ - **Deferred replay reancora candidates de memória na fonte causal final.** Depois de uma
40
+ promoção legacy válida, um assert moderno reaplicado pelo replay não deixa mais os
41
+ candidates posteriores presos à fonte intermediária. A promoção explícita continua
42
+ exigindo o guard causal e mantém o fail-closed para linhagens incompletas ou ambíguas;
43
+ o ledger permanece append-only.
44
+
45
+ ## [0.68.2] — 2026-08-08
46
+
47
+ ### Fixed
48
+
49
+ - **O guard do `npm run release` deixa de bloquear a tag criada pelo `auto-tag.yml`.** Os dois
50
+ automatismos assumem ordens opostas: o script publica no npm e então cria a tag, enquanto o
51
+ workflow cria a tag no merge em `main`, antes de qualquer publish. Quando o merge precedia o
52
+ publish — o caminho normal de um PR — o release abortava num estado perfeitamente publicável.
53
+ O guard passa a proteger a unicidade da versão no registry, não a ausência da tag: publica e
54
+ preserva a tag existente quando ela aponta para o commit corrente, e continua abortando se a
55
+ versão já foi lançada ou se a tag aponta para outro commit. A decisão virou função pura, então
56
+ a matriz de estados é verificável sem publicar nem mutar o repositório.
57
+
58
+ ## [0.68.1] — 2026-08-08
59
+
60
+ ### Fixed
61
+
62
+ - **A contenção de locks do Vault deixa de expor `VAULT_PATH_UNSAFE` no Windows.** A revalidação de
63
+ uma falha transiente de resolução do lock público passa a decidir por um walk fresco do
64
+ componente, e não pelo `errno` reportado pela plataforma. O Windows devolve `UNKNOWN`, `EBADF` ou
65
+ `EPERM` onde o Linux devolve `ENOENT`, então a guarda de retry nunca disparava lá e promoções FLOW
66
+ concorrentes falhavam de forma intermitente com o código de fronteira física em vez do conflito de
67
+ promoção. Sufixo ausente ou diretório canônico estabilizado autorizam o retry; junction, symlink,
68
+ reparse point, componente redirecionado ou estado irresolvível persistente continuam falhando
69
+ fechado, e o orçamento de retry permanece único e limitado por aquisição.
70
+ - **Falha de lock nos caminhos FLOW reporta o código do domínio.** `withFlowPromotionLock` e o store
71
+ de sessão passam a propagar `FLOW_VAULT_BOUNDARY` para a fronteira física, alinhando a superfície
72
+ de erro ao resto da saga de promoção.
73
+
7
74
  ## [0.68.0] — 2026-08-02
8
75
 
9
76
  ### Added
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`.
@@ -379,8 +382,9 @@ it does not expose memory values or content. After human review,
379
382
  new promotion accepts a later Stop from the same session/activation without recreating a conflict.
380
383
  A promotion written by 0.66.1 remains historical: if the next Stop forms a new candidate, update
381
384
  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
385
+ final modern source and, when causal supersession is proven, re-anchored to it; explicit promotion
386
+ uses that anchor and crosses only the physical predecessors required by replay. The same
387
+ 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
388
  replay, attempt identity, and absence of a real conflict; it creates a backup and audit without
385
389
  appending or rewriting events. Ambiguity stays queued for explicit curation. Do not publish or
386
390
  install 0.66.2; use 0.66.3 or later. Decisions survive repair/replay;
@@ -393,7 +397,11 @@ acknowledgement pending on 0.66.4 or later, first run the targeted dry run
393
397
  registry/checkpoint. See syntax, preconditions, and fail-closed behavior in
394
398
  [memory and curation](docs/en/commands/memory.md).
395
399
 
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.
400
+ 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.
401
+
402
+ On definitive close, the activation and session become `done` in `SESSION_REGISTRY.json` only
403
+ after memory/observability publication; `CURRENT_SESSION.md` is a derived view, not the identity
404
+ authority, and does not list finalized sessions.
397
405
 
398
406
  ## Retroactive memory (`import`) — install today, remember yesterday
399
407
 
@@ -521,7 +529,7 @@ The archive **gate** blocks unless: the change scaffold is filled (G0), no task
521
529
  - **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
530
  - **Search is keyword/frontmatter scoring**, not on‑device embeddings (that's on the roadmap).
523
531
  - **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).
532
+ - 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
533
  - **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
534
 
527
535
  ---
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`.
@@ -379,8 +382,9 @@ it does not expose memory values or content. After human review,
379
382
  new promotion accepts a later Stop from the same session/activation without recreating a conflict.
380
383
  A promotion written by 0.66.1 remains historical: if the next Stop forms a new candidate, update
381
384
  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
385
+ final modern source and, when causal supersession is proven, re-anchored to it; explicit promotion
386
+ uses that anchor and crosses only the physical predecessors required by replay. The same
387
+ 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
388
  replay, attempt identity, and absence of a real conflict; it creates a backup and audit without
385
389
  appending or rewriting events. Ambiguity stays queued for explicit curation. Do not publish or
386
390
  install 0.66.2; use 0.66.3 or later. Decisions survive repair/replay;
@@ -393,7 +397,11 @@ acknowledgement pending on 0.66.4 or later, first run the targeted dry run
393
397
  registry/checkpoint. See syntax, preconditions, and fail-closed behavior in
394
398
  [memory and curation](docs/en/commands/memory.md).
395
399
 
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.
400
+ 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.
401
+
402
+ On definitive close, the activation and session become `done` in `SESSION_REGISTRY.json` only
403
+ after memory/observability publication; `CURRENT_SESSION.md` is a derived view, not the identity
404
+ authority, and does not list finalized sessions.
397
405
 
398
406
  ## Retroactive memory (`import`) — install today, remember yesterday
399
407
 
@@ -521,7 +529,7 @@ The archive **gate** blocks unless: the change scaffold is filled (G0), no task
521
529
  - **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
530
  - **Search is keyword/frontmatter scoring**, not on‑device embeddings (that's on the roadmap).
523
531
  - **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).
532
+ - 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
533
  - **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
534
 
527
535
  ---
@@ -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`.
@@ -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`.
@@ -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