wendkeep 0.32.0 → 0.33.0

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,25 @@ 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.33.0] — 2026-07-11
8
+
9
+ ### Added
10
+
11
+ - **Visão global de changes abertas**: `SessionStart`, `UserPromptSubmit`, `wendkeep change list`
12
+ e `wendkeep change status` sem slug mostram todas as pendências, inclusive as iniciadas por
13
+ outro agente.
14
+ - Ações de takeover explícitas no contexto: Claude, Codex ou outro agente podem retomar uma
15
+ change existente sem perder o restante do backlog.
16
+
17
+ ### Changed
18
+
19
+ - `.brain/CURRENT_CHANGE.md` continua como ponteiro global único, agora marcado como change
20
+ **atual**. Comandos implícitos (`done`, `verify`, `archive`, `abandon`) continuam restritos a ela.
21
+ - Mudanças em qualquer `tarefas.md` invalidam o hash do hook de contexto e reinjetam a lista global
22
+ na sessão afetada.
23
+ - `change-nag` permanece local à change atual; pendências de outra frente não bloqueiam o agente
24
+ em foco.
25
+
7
26
  ## [0.32.0] — 2026-07-09
8
27
 
9
28
  ### Added
package/README.md CHANGED
@@ -112,7 +112,7 @@ No re‑copying, no snapshot to re‑sync — the package is the single source o
112
112
  |---|---|
113
113
  | `wendkeep init` | Set up wendkeep in a project (vault taxonomy + settings + MCP + skills). |
114
114
  | `wendkeep hook <name>` | Run a session hook; invoked by `settings.json` (reads agent JSON on stdin). |
115
- | `wendkeep change <sub>` | Change lifecycle: `new [--simple]` / `list` / `show` / `status` / `done <id>` / `undone <id>` / `diff` / `archive [--force]`. |
115
+ | `wendkeep change <sub>` | Change lifecycle: `new [--simple]` / `list` (global backlog) / `show` / `status [slug]` / `done <id> [--change slug]` / `undone <id> [--change slug]` / `diff` / `archive [--force]`. |
116
116
  | `wendkeep verify [--deep]` | Run the change's task sensors; `--deep` assembles the independent-verification package. |
117
117
  | `wendkeep spec <sub>` | Living specs: `list` / `show <capability>`. |
118
118
  | `wendkeep sensors <sub>` | `list` / `add <id> "<command>"` — view/edit `wendkeep.sensors.json` (JSON Schema shipped). |
@@ -148,7 +148,7 @@ Beyond capturing sessions, wendkeep is a **harness**: a native, zero‑dependenc
148
148
  explore → propose → apply (TDD) → verify → archive
149
149
  ```
150
150
 
151
- - **Propose** — `wendkeep change new <slug>` scaffolds `08-Mudanças/<slug>/` (`proposta.md`, `design.md`, `tarefas.md`, and a `specs/` delta). The change becomes *active* and is injected at the next `SessionStart`, so the agent resumes work‑in‑progress.
151
+ - **Propose** — `wendkeep change new <slug>` scaffolds `08-Mudanças/<slug>/` (`proposta.md`, `design.md`, `tarefas.md`, and a `specs/` delta). It becomes the global *current* change. Multiple changes may remain open: hooks and `change list/status` expose every pending task, while commands without `--change` use only the current one.
152
152
  - **Apply** — implement each `tarefas.md` task. Tag a task that needs machine proof with `[sensor:<id>]`.
153
153
  - **Verify** — `wendkeep verify` runs the sensors your tasks declared (from `wendkeep.sensors.json` at the project root) and records `evidencia.json`. A critical red fails the gate; a `warning` red is advisory.
154
154
  - **Archive** — `wendkeep change archive <slug>` **gates** on the evidence (blocks unless every declared critical sensor is green), promotes each capability's spec delta (`ADDED`/`MODIFIED`/`REMOVED`) into the living `07-Specs/<capability>.md`, moves the change to `_arquivo/`, and mints an ADR in `04-Decisões/`.
@@ -175,6 +175,8 @@ Declare the capability in `proposta.md` (`specs: [ui]`) and author its delta in
175
175
 
176
176
  ```bash
177
177
  npx wendkeep change status # one screen: tasks / sensors / verdict
178
+ npx wendkeep change list # all open changes + pending tasks
179
+ npx wendkeep change status dark-mode # one change in detail
178
180
  npx wendkeep change done 1.1 # tick a task from the CLI
179
181
  npx wendkeep verify # run the declared sensors -> evidencia.json
180
182
  npx wendkeep verify --deep # assemble the verification package
@@ -194,7 +196,7 @@ agent session ──hooks──▶ wendkeep ──▶ Markdown in vault ──
194
196
  (Claude/Codex) (Node) (02-Sessões/…) (CORE+DIGEST, backlinks)
195
197
  ```
196
198
 
197
- The agent's settings.json points each hook at `npx wendkeep hook …`. On `Stop`, wendkeep parses the session transcript, appends the turn, updates the token/cost table, and (idempotently) emits any decision/bug/learning notes. On every `SessionStart`, `brain-inject` injects back the curated memory (CORE + DIGEST), the active change, project lessons, and a `<wk_process>` router that routes any non‑trivial task through the a2 loop (plan `change new` + fill the scaffold TDD → verify → archive).
199
+ The agent's settings.json points each hook at `npx wendkeep hook …`. On `Stop`, wendkeep parses the session transcript, appends the turn, updates the token/cost table, and (idempotently) emits any decision/bug/learning notes. On every `SessionStart`, `brain-inject` injects back curated memory (CORE + DIGEST), every open change with its pending tasks, the global current-change marker, project lessons, and a `<wk_process>` router. Claude, Codex, or another agent can therefore resume work started elsewhere without hiding the rest of the backlog.
198
200
 
199
201
  The archive **gate** blocks unless: the change scaffold is filled (G0), no task is open (G1), every declared critical sensor is green (with fresh evidence), and — when the change declares `[req:]` — an independent `verdict.json` covers them. `--force` is the human escape hatch; the agent is instructed never to use it on its own.
200
202
 
package/README.pt-BR.md CHANGED
@@ -110,7 +110,7 @@ Sem recopiar, sem snapshot pra re‑sincronizar — o pacote é a única fonte d
110
110
  |---|---|
111
111
  | `wendkeep init` | Configura o wendkeep num projeto (taxonomia do cofre + settings + MCP + skills). |
112
112
  | `wendkeep hook <name>` | Roda um hook de sessão; invocado pelo `settings.json` (lê o JSON do agente no stdin). |
113
- | `wendkeep change <sub>` | Ciclo de mudança: `new [--simple]` / `list` / `show` / `status` / `done <id>` / `undone <id>` / `diff` / `archive [--force]`. |
113
+ | `wendkeep change <sub>` | Ciclo de mudança: `new [--simple]` / `list` (backlog global) / `show` / `status [slug]` / `done <id> [--change slug]` / `undone <id> [--change slug]` / `diff` / `archive [--force]`. |
114
114
  | `wendkeep verify [--deep]` | Roda os sensores das tarefas da change; `--deep` monta o pacote de verificação independente. |
115
115
  | `wendkeep spec <sub>` | Specs vivos: `list` / `show <capability>`. |
116
116
  | `wendkeep sensors <sub>` | `list` / `add <id> "<comando>"` — vê/edita `wendkeep.sensors.json` (JSON Schema incluso). |
@@ -147,7 +147,7 @@ Além de capturar sessões, o wendkeep é um **harness**: um loop nativo e sem d
147
147
  explore → propose → apply (TDD) → verify → archive
148
148
  ```
149
149
 
150
- - **Propose** — `wendkeep change new <slug>` faz o scaffold de `08-Mudanças/<slug>/` (`proposta.md`, `design.md`, `tarefas.md` e um delta `specs/`). A change vira *ativa* e é injetada no próximo `SessionStart`, então o agente retoma o trabalho em curso.
150
+ - **Propose** — `wendkeep change new <slug>` faz o scaffold de `08-Mudanças/<slug>/` (`proposta.md`, `design.md`, `tarefas.md` e um delta `specs/`). A change vira a *atual* global. Várias changes podem ficar abertas: hooks e `change list/status` mostram todas as pendências, enquanto comandos sem `--change` usam somente a atual.
151
151
  - **Apply** — implemente cada tarefa de `tarefas.md`. Taggeie a tarefa que precisa de prova de máquina com `[sensor:<id>]`.
152
152
  - **Verify** — `wendkeep verify` roda os sensores que suas tarefas declararam (do `wendkeep.sensors.json` na raiz do projeto) e grava `evidencia.json`. Um vermelho crítico falha o gate; um vermelho `warning` é aviso.
153
153
  - **Archive** — `wendkeep change archive <slug>` faz **gate** na evidência (bloqueia a não ser que todo sensor crítico declarado esteja verde), promove o delta de cada capability (`ADDED`/`MODIFIED`/`REMOVED`) pro `07-Specs/<capability>.md` vivo, move a change pro `_arquivo/` e cunha um ADR em `04-Decisões/`.
@@ -163,7 +163,7 @@ sessão do agente ──hooks──▶ wendkeep ──▶ Markdown no cofre ─
163
163
  (Claude/Codex) (Node) (02-Sessões/…) (CORE+DIGEST, backlinks)
164
164
  ```
165
165
 
166
- O settings.json do agente aponta cada hook pra `npx wendkeep hook …`. No `Stop`, o wendkeep parseia o transcript, anexa o turno, atualiza a tabela de tokens/custo e (idempotentemente) emite qualquer nota de decisão/bug/aprendizado. Em todo `SessionStart`, o `brain-inject` injeta de volta a memória curada (CORE + DIGEST), a change ativa, as lições do projeto e um roteador `<wk_process>` que roteia qualquer tarefa não‑trivial pelo loop a2 (planejar `change new` + preencher o scaffold TDD → verify → archive).
166
+ O settings.json do agente aponta cada hook pra `npx wendkeep hook …`. No `Stop`, o wendkeep parseia o transcript, anexa o turno, atualiza a tabela de tokens/custo e (idempotentemente) emite qualquer nota de decisão/bug/aprendizado. Em todo `SessionStart`, o `brain-inject` injeta a memória curada (CORE + DIGEST), todas as changes abertas com suas pendências, o marcador global da change atual, as lições do projeto e o roteador `<wk_process>`. Claude, Codex ou outro agente podem assim retomar trabalho iniciado em outro lugar sem ocultar o restante do backlog.
167
167
 
168
168
  O **gate** do archive bloqueia a não ser que: o scaffold da change esteja preenchido (G0), nenhuma tarefa esteja aberta (G1), todo sensor crítico declarado esteja verde (com evidência fresca) e — quando a change declara `[req:]` — um `verdict.json` independente cubra eles. O `--force` é a saída de emergência humana; o agente é instruído a nunca usar por conta própria.
169
169
 
@@ -1,6 +1,6 @@
1
1
  // .agent/hooks/brain-inject.mjs
2
2
  // Injeção da camada quente no SessionStart (Claude/Codex/Copilot): CORE curado +
3
- // DIGEST auto + 1-linha pointer do recall. Budget-capada. Nunca derruba o hook.
3
+ // DIGEST auto + 1-linha pointer do recall + backlog completo de changes. Nunca derruba o hook.
4
4
  // Uso (hook): node .agent/hooks/brain-inject.mjs (input JSON via stdin)
5
5
  import { readFileSync } from 'node:fs';
6
6
  import { join } from 'node:path';
@@ -72,8 +72,8 @@ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href)
72
72
  additionalContext: buildInjection(vaultBase),
73
73
  },
74
74
  });
75
- // Sentinela do change-context: a change ativa acabou de ser injetada aqui, então o hook de
76
- // UserPromptSubmit não precisa re-pingar no 1º prompt. Bônus — nunca derruba a injeção.
75
+ // Sentinela do change-context: o backlog completo acabou de ser injetado aqui, então o hook
76
+ // UserPromptSubmit não precisa re-pingar no 1º prompt. Bônus — nunca derruba a injeção.
77
77
  try {
78
78
  const st = changeCtxState(vaultBase);
79
79
  if (st) writeSentinel(vaultBase, 'ctx', input.session_id || input.sessionId || '', st.hash);
@@ -1,14 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  // UserPromptSubmit hook. Dois papéis, ambos quiet-by-default (a maioria dos prompts não injeta nada):
3
- // 1. Com change ativa: re-injeta <active_change_ping> (slug + tarefas abertas) SÓ quando o
4
- // estado mudou desde a última injeção (hash em sentinela por sessão) — o nudge do
5
- // SessionStart dilui/compacta; este devolve o loop ao contexto no momento certo.
6
- // 2. Sem change ativa: prompt com cara de tarefa ganha <wk_skill_gate> mandando invocar a
3
+ // 1. Com changes abertas: re-injeta <open_changes_ping> (backlog completo) SÓ quando o estado
4
+ // mudou desde a última injeção (hash em sentinela por sessão).
5
+ // 2. Sem changes abertas: prompt com cara de tarefa ganha <wk_skill_gate> mandando invocar a
7
6
  // Skill wk-workflow ANTES de editar — 1x por sessão. É o empurrão de ativação da skill.
8
7
  // Fail-open; brain-inject grava a sentinela ctx no SessionStart para não duplicar no 1º prompt.
9
8
  import { pathToFileURL } from 'node:url';
10
9
  import { getVaultBase, readHookInput, writeHookOutput } from './obsidian-common.mjs';
11
- import { changeCtxState, readSentinel, writeSentinel } from './change-core.mjs';
10
+ import { changeCtxState, readSentinel, renderOpenChanges, writeSentinel } from './change-core.mjs';
12
11
 
13
12
  // Conservador de propósito: verbos de tarefa comuns (pt+en) + tamanho mínimo. Falso-negativo
14
13
  // custa só o nudge; falso-positivo em pergunta curta viraria ruído.
@@ -25,17 +24,9 @@ export function buildChangePing(vaultBase, sessionId, prompt = '') {
25
24
  if (st) {
26
25
  if (readSentinel(vaultBase, 'ctx', sessionId) === st.hash) return null;
27
26
  writeSentinel(vaultBase, 'ctx', sessionId, st.hash);
28
- const lines = st.openTasks.map((t) => `- [ ] ${t.id} ${t.text}`);
29
- const context = [
30
- '<active_change_ping>',
31
- `Mudança ativa: ${st.slug}${st.openTasks.length ? ` — tarefa(s) aberta(s):` : ' — sem tarefas abertas.'}`,
32
- ...lines,
33
- 'Ao concluir uma tarefa: `wendkeep change done <id>`. Antes de arquivar: `wendkeep verify`.',
34
- '</active_change_ping>',
35
- ].join('\n');
36
- return { context, hash: st.hash };
27
+ return { context: renderOpenChanges(st, { tag: 'open_changes_ping' }), hash: st.hash };
37
28
  }
38
- // Sem change ativa: gate de skill para prompt-tarefa, 1x por sessão.
29
+ // Sem changes abertas: gate de skill para prompt-tarefa, 1x por sessão.
39
30
  if (!looksLikeTask(prompt)) return null;
40
31
  if (readSentinel(vaultBase, 'gate', sessionId)) return null;
41
32
  writeSentinel(vaultBase, 'gate', sessionId);
@@ -167,22 +167,67 @@ export function listChanges(vaultBase) {
167
167
  try {
168
168
  archived = readdirSync(join(base, ARCHIVE_DIR)).filter((n) => !n.startsWith('.'));
169
169
  } catch { /* none */ }
170
- return { active, archived };
170
+ return { active: active.sort(), archived: archived.sort() };
171
171
  }
172
172
 
173
- export function buildActiveChangeInjection(vaultBase, { maxTasks = 8 } = {}) {
174
- const slug = activeChange(vaultBase);
175
- if (!slug) return '';
173
+ // Visão derivada de TODAS as changes abertas. CURRENT_CHANGE continua sendo o único foco para
174
+ // comandos implícitos; provider/session nunca filtram a fila, para que outro agente possa assumir
175
+ // o trabalho. O hash leva o conteúdo inteiro de cada tarefas.md — não apenas as contagens — pois
176
+ // ele controla a reinjeção por sessão dos hooks.
177
+ export function allChangesState(vaultBase) {
178
+ const current = activeChange(vaultBase);
179
+ const { active } = listChanges(vaultBase);
176
180
  const chDir = getLocale(vaultBase).folders.changes;
177
- let md = '';
178
- try { md = readFileSync(join(vaultBase, chDir, slug, 'tarefas.md'), 'utf8'); } catch { return ''; }
179
- const open = parseTasks(md).filter((t) => !t.done).slice(0, maxTasks);
180
- const lines = open.map((t) => `- [ ] ${t.id} ${t.text}`);
181
- const more = open.length === maxTasks ? '\n*…mais tarefas em tarefas.md*' : '';
182
- return `<active_change>
183
- Mudança ativa: ${slug} — [[${chDir}/${slug}/proposta]]. Tarefas abertas:
184
- ${lines.join('\n')}${more}
185
- </active_change>`;
181
+ const fingerprint = [`current:${current}`];
182
+ const changes = active.map((slug) => {
183
+ let md = '';
184
+ let warning = '';
185
+ try { md = readFileSync(join(vaultBase, chDir, slug, 'tarefas.md'), 'utf8'); }
186
+ catch { warning = 'tarefas.md ausente ou ilegível'; }
187
+ const tasks = parseTasks(md);
188
+ const openTasks = tasks.filter((t) => !t.done);
189
+ fingerprint.push(`slug:${slug}`, `tasks:${md}`, `warning:${warning}`);
190
+ return {
191
+ slug,
192
+ current: slug === current,
193
+ openTasks,
194
+ openCount: openTasks.length,
195
+ doneCount: tasks.length - openTasks.length,
196
+ warning,
197
+ };
198
+ });
199
+ changes.sort((a, b) => Number(b.current) - Number(a.current) || a.slug.localeCompare(b.slug));
200
+ const pointerWarning = current && !changes.some((change) => change.current)
201
+ ? `CURRENT_CHANGE aponta para change inexistente: ${current}`
202
+ : '';
203
+ if (pointerWarning) fingerprint.push(`pointer-warning:${pointerWarning}`);
204
+ return { current, changes, pointerWarning, hash: tasksHashOf(fingerprint.join('\n')) };
205
+ }
206
+
207
+ export function renderOpenChanges(state, { tag = 'open_changes' } = {}) {
208
+ if (!state?.changes?.length && !state?.pointerWarning) return '';
209
+ const lines = [];
210
+ if (tag) lines.push(`<${tag}>`);
211
+ if (state.current) lines.push(`Change atual (comandos sem --change): ${state.current}.`);
212
+ else lines.push('Nenhuma change atual selecionada; comandos sem --change continuam recusados.');
213
+ if (state.pointerWarning) lines.push(`Aviso: ${state.pointerWarning}.`);
214
+ for (const change of state.changes || []) {
215
+ const label = change.current ? 'ATUAL' : 'ABERTA';
216
+ lines.push(`### ${label} — ${change.slug} (${change.openCount} aberta(s), ${change.doneCount} concluída(s))`);
217
+ if (change.warning) lines.push(`- Aviso: ${change.warning}.`);
218
+ else if (!change.openTasks.length) lines.push('- Nenhuma tarefa aberta.');
219
+ else for (const task of change.openTasks) lines.push(`- [ ] ${task.id} ${task.text}`);
220
+ }
221
+ if (state.current) lines.push('Para change atual: `wendkeep change done <id>`; antes de archive: `wendkeep verify`.');
222
+ lines.push('Qualquer agente pode assumir uma change: selecione-a com `wendkeep change new <slug-existente>` ou use `--change <slug>` quando disponível.');
223
+ if (tag) lines.push(`</${tag}>`);
224
+ return lines.join('\n');
225
+ }
226
+
227
+ // Mantém o nome exportado para consumidores internos existentes, mas agora injeta o backlog
228
+ // completo em vez de ocultar changes não selecionadas.
229
+ export function buildActiveChangeInjection(vaultBase) {
230
+ return renderOpenChanges(allChangesState(vaultBase));
186
231
  }
187
232
 
188
233
  export function activeChangeLink(vaultBase) {
@@ -232,14 +277,18 @@ export function writeSentinel(vaultBase, kind, sid, value = '1') {
232
277
  } catch { /* fail-open: pior caso = aviso repetido */ }
233
278
  }
234
279
 
235
- // Estado da change ativa para o ping do change-context: hash inclui o slug para que trocar de
236
- // change com tarefas idênticas ainda re-pingue.
237
- export function changeCtxState(vaultBase, { maxTasks = 5 } = {}) {
238
- const slug = activeChange(vaultBase);
239
- if (!slug) return null;
240
- let md = '';
241
- try { md = readFileSync(join(vaultBase, getLocale(vaultBase).folders.changes, slug, 'tarefas.md'), 'utf8'); } catch { /* sem tarefas */ }
242
- return { slug, hash: tasksHashOf(`${slug}\n${md}`), openTasks: parseTasks(md).filter((t) => !t.done).slice(0, maxTasks) };
280
+ // Estado global usado pelo change-context: hash cobre qualquer tarefa aberta, inclusive de uma
281
+ // change que não esteja no ponteiro. As propriedades slug/openTasks preservam compatibilidade com
282
+ // consumidores antigos e descrevem somente a atual.
283
+ export function changeCtxState(vaultBase) {
284
+ const state = allChangesState(vaultBase);
285
+ if (!state.changes.length && !state.pointerWarning) return null;
286
+ const selected = state.changes.find((change) => change.current);
287
+ return {
288
+ ...state,
289
+ slug: state.current,
290
+ openTasks: selected?.openTasks || [],
291
+ };
243
292
  }
244
293
 
245
294
  // GC das sentinelas (>7 dias) — seleção pura separada da execução (testável sem depender de
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wendkeep",
3
- "version": "0.32.0",
3
+ "version": "0.33.0",
4
4
  "description": "A persistent-memory harness for AI coding agents on your Obsidian vault: turn-by-turn session capture plus a native, zero-dependency spec→change→verify→archive loop (sensor-gated, independent verdict, mutation discrimination). Local-first, agent-agnostic (Claude Code, Codex, Cursor…).",
5
5
  "type": "module",
6
6
  "bin": {
package/src/change.mjs CHANGED
@@ -4,7 +4,9 @@ import { isAbsolute, join, resolve } from 'node:path';
4
4
  import {
5
5
  newChange,
6
6
  activeChange,
7
+ allChangesState,
7
8
  listChanges,
9
+ renderOpenChanges,
8
10
  parseTasks,
9
11
  setTaskDone,
10
12
  archiveChange,
@@ -61,9 +63,9 @@ export function runChange(argv) {
61
63
  }
62
64
 
63
65
  if (sub === 'list') {
64
- const { active, archived } = listChanges(vaultBase);
65
- const cur = activeChange(vaultBase);
66
- process.stdout.write(`active: ${active.map((s) => (s === cur ? `*${s}` : s)).join(', ') || '(none)'}\n`);
66
+ const state = allChangesState(vaultBase);
67
+ const { archived } = listChanges(vaultBase);
68
+ process.stdout.write(`${renderOpenChanges(state, { tag: '' }) || 'open changes: (none)'}\n`);
67
69
  process.stdout.write(`archived: ${archived.join(', ') || '(none)'}\n`);
68
70
  process.exit(0);
69
71
  }
@@ -82,8 +84,16 @@ export function runChange(argv) {
82
84
  }
83
85
 
84
86
  if (sub === 'status') {
85
- const slug = slugArg() || activeChange(vaultBase);
86
- if (!slug) { process.stderr.write('wendkeep change status: no change (arg or active)\n'); process.exit(2); }
87
+ const slug = slugArg();
88
+ if (!slug) {
89
+ const state = allChangesState(vaultBase);
90
+ if (!state.changes.length && !state.pointerWarning) {
91
+ process.stderr.write('wendkeep change status: no open changes\n');
92
+ process.exit(2);
93
+ }
94
+ process.stdout.write(`${renderOpenChanges(state, { tag: '' })}\n`);
95
+ process.exit(0);
96
+ }
87
97
  const dir = join(vaultBase, getLocale(vaultBase).folders.changes, slug);
88
98
  let tarefasMd;
89
99
  try { tarefasMd = readFileSync(join(dir, 'tarefas.md'), 'utf8'); }
@@ -29,8 +29,9 @@ vault cego. Exceção única: mudança trivial (typo, 1 linha).
29
29
  - \`proposta.md\` — *por quê* e *o que muda* (o WHAT).
30
30
  - \`design.md\` — a abordagem técnica.
31
31
  - \`tarefas.md\` — a lista de tarefas \`- [ ] N.N descrição\`.
32
- A mudança vira a *ativa* (ponteiro \`.brain/CURRENT_CHANGE.md\`) e é injetada no
33
- próximo SessionStart, então você retoma o trabalho em curso automaticamente.
32
+ A mudança vira a *atual* (ponteiro global \`.brain/CURRENT_CHANGE.md\`). Podem existir
33
+ várias changes abertas: hooks e \`change list/status\` mostram todas as pendências; comandos
34
+ sem \`--change\` usam somente a atual.
34
35
  Antes de implementar, resolva \`spec_impact\` na proposta:
35
36
  - \`required\`: liste a capability em \`specs:\` e preencha
36
37
  \`specs/<capability>/spec.md\` com ADDED/MODIFIED/REMOVED; ligue tarefas com \`[req:ID]\`.
@@ -53,7 +54,9 @@ vault cego. Exceção única: mudança trivial (typo, 1 linha).
53
54
 
54
55
  ## Regras
55
56
 
56
- - Uma mudança ativa por vez. Termine (archive) antes de abrir outra.
57
+ - Várias changes podem ficar abertas. \`CURRENT_CHANGE.md\` marca uma atual, sem esconder as
58
+ outras pendências. Claude, Codex ou outro agente podem assumir uma change existente com
59
+ \`wendkeep change new <slug-existente>\` ou \`--change <slug>\` quando disponível.
57
60
  - Se uma tarefa não precisa de prova automatizada, não declare sensor — o gate só exige
58
61
  o que você declarou. Sem \`[sensor:]\`, o archive não trava.
59
62
  - A proposta linka a sessão de origem; a sessão linka a mudança ativa. É de propósito:
@@ -248,8 +251,9 @@ leaves the vault blind. Single exception: a trivial change (typo, one line).
248
251
 
249
252
  1. **Explore** — understand the problem before proposing.
250
253
  2. **Propose** — \`wendkeep change new <slug>\` scaffolds \`08-Changes/<slug>/\`
251
- (proposta/design/tarefas + a \`specs/\` delta). The change becomes *active* and is
252
- injected at the next SessionStart.
254
+ (proposta/design/tarefas + a \`specs/\` delta). The change becomes *current* through global
255
+ \`.brain/CURRENT_CHANGE.md\`. Multiple changes may stay open; hooks and \`change list/status\`
256
+ show every pending task, while commands without \`--change\` use only the current change.
253
257
  Before implementation, resolve \`spec_impact\`: \`required\` needs the capability listed in
254
258
  \`specs:\` plus a real \`specs/<capability>/spec.md\` delta and \`[req:ID]\` links; \`none\`
255
259
  needs a real \`spec_impact_reason\`. \`pending\` is never ready for implementation/archive.
@@ -263,7 +267,9 @@ leaves the vault blind. Single exception: a trivial change (typo, one line).
263
267
  verdict AND no open tasks. It promotes the delta into \`07-Specs\` and mints an ADR.
264
268
 
265
269
  ## Rules
266
- - One active change at a time. Finish (archive) before starting another.
270
+ - Multiple changes may stay open. \`CURRENT_CHANGE.md\` marks one current change without hiding
271
+ other pending tasks. Any agent may take over an existing change with
272
+ \`wendkeep change new <existing-slug>\` or \`--change <slug>\` where available.
267
273
  - No \`[sensor:]\` on a task = no automated gate for it. No \`[req:]\` = no independent verdict.
268
274
  - The graph links session ↔ change ↔ requirement ↔ decision. That is the point.
269
275
  `;