wendkeep 0.79.0 → 0.80.1

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,43 @@ 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.80.1] — 2026-08-24
8
+
9
+ ### Fixed
10
+
11
+ - **Bootstrap causal das sessões Codex.** `session-start` e `session-ensure` agora derivam um
12
+ `work_session_id` estável do `session_id` canônico quando o host não envia essa identidade,
13
+ preservando primeiro handoff explícito e valor já registrado. Novas sessões deixam de falhar em
14
+ `profile route`, `change new` e active context por identidade ausente, sem relaxar as validações
15
+ de projeto, repositório, worktree ou branch; README e o guia de contexto foram atualizados em
16
+ PT-BR/EN.
17
+
18
+ ## [0.80.0] — 2026-08-24
19
+
20
+ ### Added
21
+
22
+ - **Task Contract v1.** `wendkeep task list/show/evaluate/claim/release` deriva contratos tipados
23
+ da change e do active context, com IDs estáveis, hashes de HEAD/tarefas/spec/manifesto,
24
+ diagnósticos estruturados e leases exclusivos recuperáveis sob o lock do `SESSION_REGISTRY`.
25
+ - **Artifact gates bounded.** Manifestos v1 suportam `name`, `path`, `glob` e `file-count`, com
26
+ fallback de filesystem explícito, ignores seguros, limites de tempo/quantidade e bloqueio de
27
+ path escape, symlink ou junction externo.
28
+ - **Handoff Contract v1.** SessionStop publica handoff causal com task, artifacts, Evidence
29
+ Envelope, decisões, próximas ações, blockers e hashes; ASSURE exige contrato verificado e
30
+ handoffs históricos permanecem `legacy-reported`.
31
+ - **Schemas e guias bilíngues.** Schemas públicos de task/handoff/artifacts, README e guias PT-BR/EN
32
+ documentam comandos, erros, recovery, autoridade e compatibilidade.
33
+
34
+ ### Changed
35
+
36
+ - **Execute → Verify machine-checkable.** `verify` preserva o Evidence Envelope recém-capturado,
37
+ grava `task-evaluation.json` e bloqueia sucesso/pacote deep quando checkbox, requisito, sensor,
38
+ artifact, dependência ou binding causal ainda estiver aberto; `[phase:verify]` separa a tarefa
39
+ final de revisão/arquivo sem enfraquecer o gate de archive.
40
+ - **Memória e Observer sem autoridade duplicada.** `handoff.latest` passa a transportar o contrato
41
+ estruturado verificado pela mesma outbox sanitizada; resumos heurísticos continuam apenas como
42
+ projeção reportada.
43
+
7
44
  ## [0.79.0] — 2026-08-23
8
45
 
9
46
  ### Added
package/README.en.md CHANGED
@@ -115,7 +115,7 @@ npx wendkeep init
115
115
 
116
116
  1. Create the vault folder taxonomy and a templated `README.md` (default vault: `<project>/.<project-name>-vault`, e.g. `.MyApp-vault`; override with `--vault`).
117
117
  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.
118
- 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`. 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**.
118
+ 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**.
119
119
  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`.
120
120
  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`.)
121
121
  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:
@@ -242,7 +242,7 @@ The README is the map; the guides provide syntax, options, exit codes, examples,
242
242
  | **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) |
243
243
  | **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) |
244
244
  | **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) |
245
- | **Changes and verification** | `change`, specs, sensors, TDD, evidence, and archive | [Changes and verification](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/changes-and-verification.md) |
245
+ | **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) |
246
246
  | **Shared memory** | CORE, SHARED, status, validation, repair, and curation | [Memory](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/memory.md) |
247
247
  | **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) |
248
248
  | **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) |
package/README.md CHANGED
@@ -115,7 +115,7 @@ npx wendkeep init
115
115
 
116
116
  1. Create the vault folder taxonomy and a templated `README.md` (default vault: `<project>/.<project-name>-vault`, e.g. `.MyApp-vault`; override with `--vault`).
117
117
  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.
118
- 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`. 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**.
118
+ 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**.
119
119
  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`.
120
120
  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`.)
121
121
  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:
@@ -242,7 +242,7 @@ The README is the map; the guides provide syntax, options, exit codes, examples,
242
242
  | **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) |
243
243
  | **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) |
244
244
  | **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) |
245
- | **Changes and verification** | `change`, specs, sensors, TDD, evidence, and archive | [Changes and verification](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/changes-and-verification.md) |
245
+ | **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) |
246
246
  | **Shared memory** | CORE, SHARED, status, validation, repair, and curation | [Memory](https://github.com/rogersialves/wendkeep/blob/main/docs/en/commands/memory.md) |
247
247
  | **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) |
248
248
  | **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) |
@@ -29,6 +29,8 @@ npx wendkeep change new <slug> [--simple|--guide] [--session <id>]
29
29
  npx wendkeep change status [slug] [--session <id>]
30
30
  npx wendkeep spec effective [--change <slug>] [--session <id>]
31
31
  npx wendkeep sensors list
32
+ npx wendkeep task list [--change <slug>] [--session <id>] [--json]
33
+ npx wendkeep task evaluate <task-id> [--change <slug>] [--session <id>] [--json]
32
34
  npx wendkeep verify [--deep] [--change <slug>] [--session <id>]
33
35
  npx wendkeep change archive <slug> [--json] [--session <id>]
34
36
  npx wendkeep change archive recover <operation-id> --change <slug> [--spec-action rollback|resume] [--json]
@@ -48,6 +50,8 @@ npx wendkeep change archive recover <operation-id> --change <slug> [--spec-actio
48
50
  only one unambiguous active context for the worktree is accepted; ambiguity returns exit `2`.
49
51
  - `change relink [--apply]` and `change backlink [--apply]` repair graph links; preview is default.
50
52
  - `change abandon <slug>` drops work without an ADR; `archive --force` needs explicit human choice.
53
+ - `task list/show/evaluate` derives read-only contracts from change authorship. `task claim/release`
54
+ controls owner/lease in the causal active context.
51
55
  - `change archive recover <operation-id> --change <slug> [--spec-action rollback|resume]` inspects a
52
56
  pending transaction by default; with `rollback` or `resume`, it converges only the spec
53
57
  promotion prepared in the journal, under the operation lock and validation. It never promotes the
@@ -148,6 +152,52 @@ cleanup is automatic. Sanitized `operation_id` and
148
152
  Text and --json use the same sanitized diagnostic with code, operation, state, blocker, expected,
149
153
  observed, recovery, reason_codes, diagnostics, and repair.
150
154
 
155
+ ## Task Contracts, artifacts, and handoffs
156
+
157
+ Task Contract v1 is a rebuildable projection whose authorship remains in `tarefas.md`, the
158
+ effective spec, and the change's `artifacts.json`. The contract neither copies spec text nor infers
159
+ a requirement from chat. Project, active context, HEAD, and tasks/spec/manifest hashes bind the
160
+ projection; any mismatch yields `stale`.
161
+
162
+ ```markdown
163
+ - [ ] 2.3 produce report [req:REP-1] [sensor:tests] [depends:2.2] [artifact:report]
164
+ - [ ] 9.1 review the deep package and archive [req:REP-1] [phase:verify]
165
+ ```
166
+
167
+ ```powershell
168
+ npx wendkeep task list --session <id> [--change <slug>] [--json]
169
+ npx wendkeep task show 2.3 --session <id> [--json]
170
+ npx wendkeep task evaluate 2.3 --session <id> [--json]
171
+ npx wendkeep task claim 2.3 --session <id> [--lease-seconds 900] [--json]
172
+ npx wendkeep task release 2.3 --session <id> [--json]
173
+ ```
174
+
175
+ `list`, `show`, and `evaluate` do not write. `claim` and `release` use the atomic
176
+ `SESSION_REGISTRY` lock, are scoped by repository/worktree/work session/change/task, and reject a
177
+ concurrent owner. An expired lease can be recovered; release by a non-owner fails with
178
+ `TASK_LEASE_NOT_OWNER`.
179
+
180
+ An artifact manifest uses `schema_version: 1` and an `artifacts` list; each named entry may use
181
+ type `name`, `path`, `glob`, or `file-count`. The `fromFilesystem` fallback is explicit, never reads
182
+ content, ignores `.git`, `.worktrees`, `node_modules`, and `dist`, has time/entry limits, and fails
183
+ closed on path escape or an external symlink/junction.
184
+
185
+ A checkbox is an authored signal, not proof. `task evaluate` returns `can_complete`, missing
186
+ requirements, sensors, artifacts, dependencies, and `blocking_findings`. In a causal active
187
+ context, `verify` may write `evidencia.json`, but it cannot report success or create the deep
188
+ package while any default `execute` task is blocked; diagnostics live in `task-evaluation.json`.
189
+ Use `[phase:verify]` only for the review/archive task that necessarily runs after the deep package:
190
+ it does not participate in the Execute → Verify gate, remains blocked in individual evaluation,
191
+ and must still be completed before `change archive`.
192
+
193
+ SessionStop binds source/target, task, artifacts, Evidence Envelope, decisions, next actions,
194
+ blockers, and HEAD/tasks/spec hashes. ASSURE requires a verified Handoff Contract v1; it is optional
195
+ in other profiles. Historical summaries remain `legacy-reported`. Shared memory, brain injection,
196
+ and Observer consume the same sanitized projection.
197
+
198
+ Public schemas: `schema/task-contract-v1.schema.json`,
199
+ `schema/artifact-manifest-v1.schema.json`, and `schema/handoff-contract-v1.schema.json`.
200
+
151
201
  ## Tool-scope fence
152
202
 
153
203
  `change-guard` is also projected to Codex `PreToolUse`. Before a Git mutation or supported writing
@@ -108,6 +108,11 @@ identified by `repository_id` + `worktree_id` + `work_session_id`; branch, HEAD,
108
108
  belong to that entry. Two worktrees can therefore select different changes without overwriting
109
109
  each other's operational focus.
110
110
 
111
+ During the session lifecycle, `session-start` and `session-ensure` first preserve an explicit
112
+ handoff `work_session_id`, then the already registered value, and, when the host supplies neither,
113
+ derive the stable identity from the canonical `session_id`. Providers such as Codex can therefore
114
+ initialize an active context without weakening project, repository, worktree, or branch checks.
115
+
111
116
  With an explicit causal session, change, spec, and verify resolve only the matching entry. Without
112
117
  a session, only one active entry for the worktree is accepted; two sessions produce ambiguity and
113
118
  the operation must fail closed without silently selecting a change.
@@ -142,3 +142,9 @@ from a busy lock or skipped path without reopening the original session.
142
142
 
143
143
  Read [Operating profiles](operating-profiles.md), [retroactive import](retroactive-import.md),
144
144
  [costs and observability](costs-and-observability.md), and [notes](notes-and-knowledge.md).
145
+ # Handoff Contract v1
146
+
147
+ In a causal active context, SessionStop projects a typed handoff with task, artifacts, Evidence
148
+ Envelope, decisions, next actions, blockers, and HEAD/tasks/spec hashes. ASSURE blocks publication
149
+ when that verified contract cannot be produced; other profiles preserve the optional fallback.
150
+ Historical handoffs remain `legacy-reported`. See [Changes and verification](changes-and-verification.md).
@@ -154,3 +154,12 @@ destructive cleanup is automatic. A failure retains `published-recovery-required
154
154
  Return to the [change lifecycle](changes-and-verification.md) for archive, review
155
155
  [Operating profiles](operating-profiles.md), or use [maintenance](maintenance-and-diagnostics.md)
156
156
  when no change exists.
157
+ # Task Contract gate
158
+
159
+ After running sensors and writing the current Evidence Envelope, `verify` evaluates Task Contracts
160
+ for the causal active context. An open checkbox, missing requirement/sensor/artifact, open
161
+ dependency, or stale binding returns exit `1`, preserves `evidencia.json`, writes
162
+ `task-evaluation.json`, and does not create the deep package. Tasks explicitly authored with
163
+ `[phase:verify]` are excluded only from this transition because they depend on the deep package;
164
+ they remain open for the archive gate. See
165
+ [Changes and verification](changes-and-verification.md).
@@ -29,6 +29,8 @@ npx wendkeep change new <slug> [--simple|--guide] [--session <id>]
29
29
  npx wendkeep change status [slug] [--session <id>]
30
30
  npx wendkeep spec effective [--change <slug>] [--session <id>]
31
31
  npx wendkeep sensors list
32
+ npx wendkeep task list [--change <slug>] [--session <id>] [--json]
33
+ npx wendkeep task evaluate <task-id> [--change <slug>] [--session <id>] [--json]
32
34
  npx wendkeep verify [--deep] [--change <slug>] [--session <id>]
33
35
  npx wendkeep change archive <slug> [--json] [--session <id>]
34
36
  npx wendkeep change archive recover <operation-id> --change <slug> [--spec-action rollback|resume] [--json]
@@ -48,6 +50,8 @@ npx wendkeep change archive recover <operation-id> --change <slug> [--spec-actio
48
50
  somente um contexto ativo inequívoco da worktree é aceito; ambiguidade retorna exit `2`.
49
51
  - `change relink [--apply]` e `change backlink [--apply]` reparam o grafo; dry-run é o padrão.
50
52
  - `change abandon <slug>` descarta sem ADR; `archive --force` exige decisão humana explícita.
53
+ - `task list/show/evaluate` projeta contratos read-only da autoria da change. `task claim/release`
54
+ controla owner/lease no active context causal.
51
55
  - `change archive recover <operation-id> --change <slug> [--spec-action rollback|resume]` inspeciona
52
56
  uma transação pendente por padrão; com `rollback` ou `resume`, converge somente a promoção de
53
57
  specs preparada no journal, sob lock e validação. Não promove a change, não apaga o journal e não
@@ -147,6 +151,52 @@ destrutivo automático. Os campos sanitizados
147
151
  Texto e --json usam o mesmo diagnóstico sanitizado com code, operation, state, blocker, expected,
148
152
  observed, recovery, reason_codes, diagnostics e repair.
149
153
 
154
+ ## Task Contracts, artifacts e handoffs
155
+
156
+ Task Contract v1 é uma projeção reconstruível cuja autoria permanece em `tarefas.md`, na spec
157
+ efetiva e no `artifacts.json` da change. O contrato não copia a spec nem infere requisito do chat.
158
+ Projeto, active context, HEAD e hashes de tarefas/spec/manifesto vinculam a projeção; divergência
159
+ resulta em `stale`.
160
+
161
+ ```markdown
162
+ - [ ] 2.3 gerar relatório [req:REP-1] [sensor:tests] [depends:2.2] [artifact:report]
163
+ - [ ] 9.1 revisar pacote deep e arquivar [req:REP-1] [phase:verify]
164
+ ```
165
+
166
+ ```powershell
167
+ npx wendkeep task list --session <id> [--change <slug>] [--json]
168
+ npx wendkeep task show 2.3 --session <id> [--json]
169
+ npx wendkeep task evaluate 2.3 --session <id> [--json]
170
+ npx wendkeep task claim 2.3 --session <id> [--lease-seconds 900] [--json]
171
+ npx wendkeep task release 2.3 --session <id> [--json]
172
+ ```
173
+
174
+ `list`, `show` e `evaluate` não escrevem. `claim` e `release` usam o lock atômico do
175
+ `SESSION_REGISTRY`, são escopados por repository/worktree/work session/change/task e recusam owner
176
+ concorrente. Lease expirada pode ser retomada; release por não-owner falha com
177
+ `TASK_LEASE_NOT_OWNER`.
178
+
179
+ Um manifesto de artifacts usa `schema_version: 1` e uma lista `artifacts`; cada entrada nomeada
180
+ pode ter tipo `name`, `path`, `glob` ou `file-count`. O fallback `fromFilesystem` é explícito, não
181
+ lê conteúdo, ignora `.git`, `.worktrees`, `node_modules` e `dist`, tem limites de tempo/quantidade
182
+ e falha fechado em path escape, symlink ou junction externo.
183
+
184
+ Checkbox é sinal autoral, não prova. `task evaluate` retorna `can_complete`, requisitos, sensores,
185
+ artifacts e dependências ausentes, além de `blocking_findings`. No active context causal, `verify`
186
+ pode gravar `evidencia.json`, mas não anuncia sucesso nem cria o pacote deep enquanto houver task
187
+ bloqueada na fase padrão `execute`; o diagnóstico fica em `task-evaluation.json`. Use
188
+ `[phase:verify]` somente para a tarefa de revisão/arquivo que necessariamente ocorre depois do
189
+ pacote deep: ela não integra o gate Execute → Verify, permanece bloqueada na avaliação individual
190
+ e ainda precisa ser concluída antes de `change archive`.
191
+
192
+ SessionStop vincula origem/destino, task, artifacts, Evidence Envelope, decisões, próximas ações,
193
+ blockers e hashes de HEAD/tarefas/spec. ASSURE exige Handoff Contract v1 verificado; nos demais
194
+ perfis ele é opcional. Handoffs históricos permanecem `legacy-reported`. Memória compartilhada,
195
+ brain injection e Observer consomem a mesma projeção sanitizada.
196
+
197
+ Schemas públicos: `schema/task-contract-v1.schema.json`,
198
+ `schema/artifact-manifest-v1.schema.json` e `schema/handoff-contract-v1.schema.json`.
199
+
150
200
  ## Cerca de escopo para ferramentas
151
201
 
152
202
  O `change-guard` também é projetado para o `PreToolUse` do Codex. Antes de uma mutação Git ou de
@@ -105,6 +105,12 @@ identificada por `repository_id` + `worktree_id` + `work_session_id`; branch, HE
105
105
  pertencem a essa entrada. Assim, duas worktrees podem selecionar changes diferentes sem
106
106
  sobrescrever o foco uma da outra.
107
107
 
108
+ No lifecycle de sessão, `session-start` e `session-ensure` preservam primeiro um
109
+ `work_session_id` explícito do handoff, depois o valor já registrado e, quando o host não fornece
110
+ nenhum deles, derivam a identidade estável do `session_id` canônico. Assim, providers como o Codex
111
+ podem inicializar o active context sem enfraquecer as validações de projeto, repositório, worktree
112
+ ou branch.
113
+
108
114
  Com sessão causal explícita, change, spec e verify resolvem somente a entrada correspondente. Sem
109
115
  sessão, uma única entrada ativa da worktree pode ser usada; duas sessões compatíveis causam
110
116
  ambiguidade e a operação falha fechada, sem escolher uma change em silêncio.
@@ -141,3 +141,10 @@ confirmada de um lock ocupado ou de um caminho que foi pulado, sem reabrir a ses
141
141
 
142
142
  Leia [Perfis de Operação](operating-profiles.md), [importação retroativa](retroactive-import.md),
143
143
  [custos e observabilidade](costs-and-observability.md) e [notas](notes-and-knowledge.md).
144
+ # Handoff Contract v1
145
+
146
+ Em active context causal, o SessionStop projeta um handoff tipado com task, artifacts, Evidence
147
+ Envelope, decisões, próximas ações, blockers e hashes de HEAD/tarefas/spec. ASSURE bloqueia a
148
+ publicação quando esse contrato verificado não pode ser produzido; outros perfis preservam o
149
+ fallback opcional. Handoffs históricos continuam `legacy-reported`. Veja
150
+ [Changes e verificação](changes-and-verification.md).
@@ -155,3 +155,11 @@ destrutivo automático. Falha mantém `published-recovery-required`.
155
155
  Volte ao [ciclo de changes](changes-and-verification.md) para archive, confira os
156
156
  [Perfis de Operação](operating-profiles.md) ou consulte
157
157
  [manutenção](maintenance-and-diagnostics.md) quando não houver change.
158
+ # Gate de Task Contract
159
+
160
+ Depois de executar sensores e gravar o Evidence Envelope atual, `verify` avalia os Task Contracts
161
+ do active context causal. Checkbox aberta, requisito/sensor/artifact ausente, dependência aberta ou
162
+ binding stale bloqueia exit `1`, preserva `evidencia.json`, grava `task-evaluation.json` e não cria
163
+ o pacote deep. Tasks explicitamente autoradas com `[phase:verify]` ficam fora apenas desta
164
+ transição porque dependem do pacote deep; continuam abertas para o gate de archive. Veja
165
+ [Changes e verificação](changes-and-verification.md).
@@ -283,18 +283,36 @@ export function parseTasks(md) {
283
283
  const re = /^-\s+\[( |x)\]\s+(\S+)\s+(.*)$/gm;
284
284
  const sensorReG = /\[sensor:\s*([\w.-]+)\]/g;
285
285
  const reqReG = new RegExp(`\\[req:\\s*(${REQ_ID_RE_SRC})\\]`, 'g');
286
+ const dependencyReG = /\[depends:\s*([\w.-]+)\]/g;
287
+ const artifactReG = /\[artifact:\s*([\w.-]+)\]/g;
288
+ const phaseReG = /\[phase:\s*([\w.-]+)\]/g;
286
289
  let m;
287
290
  while ((m = re.exec(String(md))) !== null) {
288
291
  let text = m[3].trim();
289
292
  const sensors = [...new Set([...text.matchAll(sensorReG)].map((entry) => entry[1]))];
290
293
  const reqs = [...text.matchAll(reqReG)].map((r) => r[1]);
294
+ const dependencies = [...new Set([...text.matchAll(dependencyReG)].map((entry) => entry[1]))];
295
+ const artifacts = [...new Set([...text.matchAll(artifactReG)].map((entry) => entry[1]))];
296
+ const phases = [...new Set([...text.matchAll(phaseReG)].map((entry) => entry[1]))];
291
297
  const sensor = sensors[0];
292
298
  if (sensors.length) text = text.replace(sensorReG, '');
293
299
  if (reqs.length) text = text.replace(reqReG, '');
300
+ if (dependencies.length) text = text.replace(dependencyReG, '');
301
+ if (artifacts.length) text = text.replace(artifactReG, '');
302
+ if (phases.length) text = text.replace(phaseReG, '');
294
303
  text = text.replace(/\s+/g, ' ').trim();
295
304
  // `sensor` stays as alias of the first id — older consumers keep working.
296
305
  // `req` stays as alias of the first id — older consumers keep working.
297
- tasks.push({ id: m[2], text, done: m[1] === 'x', ...(sensor ? { sensor, sensors } : {}), ...(reqs.length ? { req: reqs[0], reqs } : {}) });
306
+ tasks.push({
307
+ id: m[2],
308
+ text,
309
+ done: m[1] === 'x',
310
+ ...(sensor ? { sensor, sensors } : {}),
311
+ ...(reqs.length ? { req: reqs[0], reqs } : {}),
312
+ ...(dependencies.length ? { dependencies } : {}),
313
+ ...(artifacts.length ? { artifacts } : {}),
314
+ ...(phases.length ? { phase: phases[0] } : {}),
315
+ });
298
316
  }
299
317
  return tasks;
300
318
  }
@@ -32,31 +32,19 @@ import {
32
32
  writeHookOutput,
33
33
  yamlQuote,
34
34
  } from './obsidian-common.mjs';
35
- import { resolveSessionIdentity } from './session-identity.mjs';
35
+ import { resolveSessionIdentity, sessionWorkSessionPatch } from './session-identity.mjs';
36
36
  import { readCodexRolloutMeta } from './codex-rollout-meta.mjs';
37
37
  import { mutateSessionNote } from './session-note-io.mjs';
38
38
  import { captureProjectScope, projectScopePatch } from './project-scope.mjs';
39
- import { sanitizeMemoryText } from './memory-schema.mjs';
40
39
 
41
40
  function sessionIdFromInput(input) {
42
41
  return input.session_id || input.sessionId || input.codex_session_id || '';
43
42
  }
44
43
 
45
- function workSessionIdFromInput(input = {}) {
46
- const shared = input.shared || input.handoff?.shared;
47
- const value = input.work_session_id
48
- || input.workSessionId
49
- || shared?.work_session_id
50
- || shared?.workSessionId
51
- || input.handoff?.work_session_id
52
- || input.handoff?.workSessionId
53
- || '';
54
- return sanitizeMemoryText(value).trim();
55
- }
56
-
57
- function workSessionPatch(input = {}) {
58
- const workSessionId = workSessionIdFromInput(input);
59
- return workSessionId ? { work_session_id: workSessionId } : {};
44
+ function workSessionPatch(vaultBase, sessionId, input = {}) {
45
+ const existingWorkSessionId = readSessionRegistry(vaultBase)
46
+ .sessions?.[sessionId]?.work_session_id || '';
47
+ return sessionWorkSessionPatch({ input, sessionId, existingWorkSessionId });
60
48
  }
61
49
 
62
50
  function turnSequenceFromInput(input = {}) {
@@ -308,7 +296,7 @@ function activateExistingSession({ vaultBase, relPath, startedAt, sessionId, inp
308
296
  transcript_path: identity.transcriptPath,
309
297
  transcript_id: identity.transcriptId,
310
298
  provider: identity.provider,
311
- ...workSessionPatch(input),
299
+ ...workSessionPatch(vaultBase, sessionId, input),
312
300
  ...scopePatch,
313
301
  ...causalTurnPatch(input, now),
314
302
  });
@@ -337,7 +325,7 @@ function createSession({ vaultBase, sessionId, input, now, identity, scopePatch
337
325
  transcript_path: identity.transcriptPath,
338
326
  transcript_id: identity.transcriptId,
339
327
  provider: identity.provider,
340
- ...workSessionPatch(input),
328
+ ...workSessionPatch(vaultBase, sessionId, input),
341
329
  ...scopePatch,
342
330
  ...causalTurnPatch(input, now),
343
331
  });
@@ -381,7 +369,7 @@ function main() {
381
369
  upsertSessionRegistry(vaultBase, sessionId, {
382
370
  transcript_paths: [identity.transcriptPath],
383
371
  provider: identity.provider,
384
- ...workSessionPatch(input),
372
+ ...workSessionPatch(vaultBase, sessionId, input),
385
373
  });
386
374
  }
387
375
  writeHookOutput({});
@@ -419,7 +407,7 @@ function main() {
419
407
  transcript_path: identity.transcriptPath,
420
408
  transcript_id: identity.transcriptId,
421
409
  provider: identity.provider,
422
- ...workSessionPatch(input),
410
+ ...workSessionPatch(vaultBase, sessionId, input),
423
411
  ...scopePatch,
424
412
  ...causalTurnPatch(input, now),
425
413
  });
@@ -465,7 +453,7 @@ function main() {
465
453
  transcript_path: identity.transcriptPath,
466
454
  transcript_id: identity.transcriptId,
467
455
  provider: identity.provider,
468
- ...workSessionPatch(input),
456
+ ...workSessionPatch(vaultBase, sessionId || control.session_id, input),
469
457
  ...scopePatch,
470
458
  ...causalTurnPatch(input, now),
471
459
  });
@@ -6,6 +6,26 @@ import {
6
6
  resolveSessionIdentitySnapshot,
7
7
  } from '../packages/integrations/src/session-identity.mjs';
8
8
  import { readCodexRolloutMeta } from './codex-rollout-meta.mjs';
9
+ import { sanitizeMemoryText } from './memory-schema.mjs';
10
+
11
+ export function sessionWorkSessionPatch({
12
+ input = {},
13
+ sessionId = '',
14
+ existingWorkSessionId = '',
15
+ } = {}) {
16
+ const shared = input.shared || input.handoff?.shared;
17
+ const explicit = input.work_session_id
18
+ || input.workSessionId
19
+ || shared?.work_session_id
20
+ || shared?.workSessionId
21
+ || input.handoff?.work_session_id
22
+ || input.handoff?.workSessionId
23
+ || '';
24
+ const workSessionId = sanitizeMemoryText(
25
+ explicit || existingWorkSessionId || sessionId,
26
+ ).trim();
27
+ return workSessionId ? { work_session_id: workSessionId } : {};
28
+ }
9
29
 
10
30
  function unknownTranscriptIdentity() {
11
31
  return {
@@ -32,7 +32,7 @@ import {
32
32
  writeHookOutput,
33
33
  yamlQuote,
34
34
  } from './obsidian-common.mjs';
35
- import { resolveSessionIdentity } from './session-identity.mjs';
35
+ import { resolveSessionIdentity, sessionWorkSessionPatch } from './session-identity.mjs';
36
36
  import { captureProjectScope, projectScopePatch } from './project-scope.mjs';
37
37
 
38
38
  export function buildSessionContent({ relPath, now, summary = 'session', provider: providerId, sessionId = '' }) {
@@ -183,11 +183,18 @@ function main() {
183
183
  readSessionRegistry(vaultBase).sessions?.[canonicalSessionId]?.project_scope,
184
184
  { ...initialScope, sessionId: canonicalSessionId },
185
185
  );
186
+ const workSessionPatchFor = (canonicalSessionId) => sessionWorkSessionPatch({
187
+ input,
188
+ sessionId: canonicalSessionId,
189
+ existingWorkSessionId: readSessionRegistry(vaultBase)
190
+ .sessions?.[canonicalSessionId]?.work_session_id || '',
191
+ });
186
192
  const control = readControl(vaultBase);
187
193
  const activationId = input.activation_id || input.activationId || randomUUID();
188
194
  const activationStartedAt = formatLocalIso(now);
189
195
  const registerActivation = (canonicalSessionId, patch) => upsertSessionRegistry(vaultBase, canonicalSessionId, {
190
196
  ...patch,
197
+ ...workSessionPatchFor(canonicalSessionId),
191
198
  ...scopePatchFor(canonicalSessionId),
192
199
  activation_id: activationId,
193
200
  activation_started_at: activationStartedAt,
@@ -27,6 +27,11 @@ import {
27
27
  import { enqueueMemoryEvent, projectMemoryOutbox } from './memory-store.mjs';
28
28
  import { detectMemoryMode } from './memory-mode.mjs';
29
29
  import { sanitizeMemoryText } from './memory-schema.mjs';
30
+ import {
31
+ buildStructuredTaskHandoff,
32
+ buildTaskContractSnapshot,
33
+ evaluateTaskContracts,
34
+ } from '../src/task-contracts.mjs';
30
35
  import { assertVaultPathSafe } from './vault-path-safety.mjs';
31
36
  import {
32
37
  projectStopMemoryAttempt,
@@ -1406,6 +1411,40 @@ export async function main({
1406
1411
  summary: finalSummary,
1407
1412
  noteRel: sessionRel,
1408
1413
  });
1414
+ let structuredSharedHandoff = sharedHandoff;
1415
+ const effectiveProfile = String(
1416
+ handoffEvidenceAuthority?.context?.operating_profile_task?.profile
1417
+ || entry?.operating_profile_task?.profile
1418
+ || 'GOVERN',
1419
+ ).toUpperCase();
1420
+ if (handoffEvidenceAuthority?.mode === 'contextual') {
1421
+ try {
1422
+ const taskSnapshot = activeContextChangeSlug
1423
+ ? buildTaskContractSnapshot({
1424
+ vaultBase,
1425
+ projectRoot: input.cwd || process.cwd(),
1426
+ changeSlug: activeContextChangeSlug,
1427
+ identity: handoffEvidenceAuthority.identity,
1428
+ })
1429
+ : null;
1430
+ structuredSharedHandoff = buildStructuredTaskHandoff({
1431
+ profile: effectiveProfile,
1432
+ sessionId,
1433
+ snapshot: taskSnapshot,
1434
+ evaluations: taskSnapshot ? evaluateTaskContracts(taskSnapshot) : [],
1435
+ context: handoffEvidenceAuthority.context,
1436
+ shared: sharedHandoff,
1437
+ });
1438
+ } catch (error) {
1439
+ if (effectiveProfile === 'ASSURE') {
1440
+ const detail = `${error?.code || 'HANDOFF_STRUCTURED_REQUIRED'}: ${error?.message || error}`;
1441
+ process.stderr.write(`[wendkeep] Stop ASSURE bloqueado: ${detail}\n`);
1442
+ writeHookOutput({ systemMessage: `wendkeep: Stop ASSURE exige handoff estruturado: ${detail}` });
1443
+ return;
1444
+ }
1445
+ structuredSharedHandoff = sharedHandoff;
1446
+ }
1447
+ }
1409
1448
  memoryHandoff = {
1410
1449
  projectId,
1411
1450
  identity,
@@ -1418,7 +1457,7 @@ export async function main({
1418
1457
  observedAt: turnIdentity.observedAt || new Date(0).toISOString(),
1419
1458
  summary: finalSummary,
1420
1459
  evidence: memoryEvidence,
1421
- ...(sharedHandoff ? { shared: sharedHandoff } : {}),
1460
+ ...(structuredSharedHandoff ? { shared: structuredSharedHandoff } : {}),
1422
1461
  };
1423
1462
  memoryAttempt = stageMemory(vaultBase, {
1424
1463
  handoff: memoryHandoff,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wendkeep",
3
- "version": "0.79.0",
3
+ "version": "0.80.1",
4
4
  "description": "Vault-first persistent memory for AI coding agents, with an optional profile-aware governance runtime: OFF, FLOW, GUIDE, GOVERN, or ASSURE. Local-first and agent-agnostic (Claude Code, Codex, Cursor…).",
5
5
  "type": "module",
6
6
  "workspaces": [
@@ -41,7 +41,7 @@
41
41
  "node": ">=18"
42
42
  },
43
43
  "scripts": {
44
- "precheck": "node --check src/change.mjs && node --check src/archive-operation-lock.mjs && node --check src/worktree.mjs && node --check src/worktree-cleanup.mjs && node --check src/provenance-gate.mjs && node --check src/provenance-sources.mjs && node --check src/receipt-ledger.mjs && node --check src/evidence-envelope.mjs && node --check src/context.mjs && node --check src/active-context-health.mjs && node --check src/active-context-runtime.mjs && node --check hooks/active-context-store.mjs && node --check hooks/change-core.mjs && node --check hooks/brain-inject.mjs && node --check hooks/change-context.mjs && node --check packages/vault/src/worktree-metadata.mjs && node --check packages/vault/src/evidence-envelope.mjs",
44
+ "precheck": "node --check src/task-contracts.mjs && node --check src/task-leases.mjs && node --check src/task.mjs && node --check src/change.mjs && node --check src/archive-operation-lock.mjs && node --check src/worktree.mjs && node --check src/worktree-cleanup.mjs && node --check src/provenance-gate.mjs && node --check src/provenance-sources.mjs && node --check src/receipt-ledger.mjs && node --check src/evidence-envelope.mjs && node --check src/context.mjs && node --check src/active-context-health.mjs && node --check src/active-context-runtime.mjs && node --check hooks/active-context-store.mjs && node --check hooks/change-core.mjs && node --check hooks/brain-inject.mjs && node --check hooks/change-context.mjs && node --check hooks/session-stop.mjs && node --check packages/vault/src/worktree-metadata.mjs && node --check packages/vault/src/evidence-envelope.mjs && node --check packages/vault/src/memory-handoff.mjs",
45
45
  "check": "node --check scripts/release.mjs && node --check scripts/release-plan.mjs && node --check scripts/release-provenance.mjs && node --check scripts/run-scope.mjs && node --check src/release-provenance.mjs && node --check bin/wendkeep.mjs && node --check packages/cli/src/index.mjs && node --check src/init.mjs && node --check src/doctor.mjs && node --check src/active-context-health.mjs && node --check src/project-vault.mjs && node --check src/observer-auth.mjs && node --check src/observer-privacy.mjs && node --check src/observer-snapshot.mjs && node --check src/observer-store.mjs && node --check src/observer-memory.mjs && node --check src/observer-memory-publish.mjs && node --check src/observer-sql-store.mjs && node --check src/observer-sql-migrate.mjs && node --check src/observer-sql-publish.mjs && node --check src/observer-transcript-store.mjs && node --check src/observer-server.mjs && node --check src/observer.mjs && node --check src/observer-publish.mjs && node --check src/operating-profile.mjs && node --check src/profile.mjs && node --check src/flow.mjs && node --check src/work-kind.mjs && node --check src/delivery.mjs && node --check web/observer/app.mjs && node --check hooks/observer-publish.mjs && node --check hooks/evidence-context.mjs && node --check hooks/active-context-handoff-evidence.mjs && node --check hooks/evidence-recall.mjs && node --check hooks/memory-scope.mjs && node --check hooks/operating-profile-runtime.mjs && node --check hooks/operating-profile-task-store.mjs && node --check hooks/flow-core.mjs && node --check hooks/flow-protected-policy.mjs && node --check hooks/git-snapshot.mjs && node --check hooks/vault-path-safety.mjs && node --check hooks/vault-runtime-store.mjs && node --check packages/harness/src/index.mjs && node --check packages/harness/src/flow-store.mjs && node --check packages/harness/src/operating-profile.mjs && node --check packages/harness/src/sensors-core.mjs && node --check packages/integrations/src/host-hooks.mjs && node --check packages/integrations/src/hook-envelope.mjs && node --check packages/integrations/src/prompt-content.mjs && node --check packages/integrations/src/transcript-usage.mjs && node --check packages/integrations/src/transcripts.mjs && node --check packages/integrations/src/session-identity.mjs && node --check packages/integrations/src/index.mjs && node --check packages/mcp/src/config.mjs && node --check packages/mcp/src/index.mjs && node --check packages/vault/src/index.mjs && node --check packages/vault/src/project-vault.mjs && node --check packages/vault/src/vault-path-safety.mjs && node --check packages/vault/src/locale.mjs && node --check packages/vault/src/memory-schema.mjs && node --check packages/vault/src/memory-mode.mjs && node --check packages/vault/src/memory-scope.mjs && node --check packages/vault/src/memory-candidate-policy.mjs && node --check packages/vault/src/evidence-recall.mjs && node --check packages/vault/src/memory-handoff.mjs && node --check packages/vault/src/memory-store.mjs && node --check packages/vault/src/validate-core.mjs && node --check packages/vault/src/validate-memory.mjs",
46
46
  "test": "node --test --test-concurrency=2",
47
47
  "test:core": "node scripts/run-scope.mjs core",
@@ -64,6 +64,8 @@ Usage:
64
64
  wendkeep context repair --key <repository:worktree:work-session> --revision <n> --reason <text> --session <id> [--json]
65
65
  Inspect or explicitly recover a quarantined causal scope conflict.
66
66
  Repair revalidates orphan/removed contexts or expired request leases without deleting history.
67
+ wendkeep task <sub> Typed task contracts: list | show | evaluate | claim | release.
68
+ Resolves the change from the causal active context; supports --session/--change/--json.
67
69
  wendkeep change <sub> Change lifecycle: new [--simple|--guide] | use | bind <slug> --session <id> | continue | list | show |
68
70
  status | done <id> | undone <id> | diff | archive [--force] | abandon | relink | backlink.
69
71
  --session <id> selects the causal active_context for implicit change operations.
@@ -292,6 +294,11 @@ async function main(argv) {
292
294
  runChange(rest);
293
295
  break;
294
296
  }
297
+ case 'task': {
298
+ const { runTask } = await import('../../../src/task.mjs');
299
+ process.exit(runTask(rest));
300
+ break;
301
+ }
295
302
  case 'session': {
296
303
  const { runSession } = await import('../../../src/session.mjs');
297
304
  runSession(rest);