jorgex-stack 1.0.19 → 1.0.21
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/README.md +1 -1
- package/package.json +1 -1
- package/stack/agents/README.md +1 -1
- package/stack/agents/orchestrator.md +6 -6
- package/stack/hooks/hooks.json +10 -0
- package/stack/plugins/opencode/worktree.ts +2 -4
- package/stack/scripts/repair-worktree-config.cjs +163 -0
- package/stack/skills/to-prd/SKILL.md +10 -0
- package/stack/skills/work-lifecycle/SKILL.md +25 -8
- package/stack/skills/work-lifecycle/references/plan-template.md +24 -9
- package/stack/system-prompt/AGENTS.md +5 -4
- package/stack/system-prompt/engram-protocol.md +1 -1
package/README.md
CHANGED
|
@@ -83,7 +83,7 @@ GitHub authentication: requests use `GH_TOKEN`/`GITHUB_TOKEN` from the environme
|
|
|
83
83
|
|
|
84
84
|
### OpenCode Goal Mode
|
|
85
85
|
|
|
86
|
-
Goal Mode is an OpenCode plugin for long-running goals
|
|
86
|
+
The normal work-lifecycle already supports multi-PR plans: `work/{name}/PRD.md` and `plan.md` stay alive across intermediate merges, `work/{name}/pr/{NN}` stores each checkpoint, and `work/{name}/done` is reserved for the final close. Goal Mode is separate: an OpenCode plugin for long-running goals, multiple sessions, multiple slices, multiple worktrees, and, when needed, multiple PRs. It is not meant for short tasks. If the change fits without extended autonomy, do not use `/goal`.
|
|
87
87
|
|
|
88
88
|
It only exists in OpenCode. Claude Code and Codex do not receive it.
|
|
89
89
|
|
package/package.json
CHANGED
package/stack/agents/README.md
CHANGED
|
@@ -30,4 +30,4 @@ Una sola fuente por agente. El instalador los traduce al formato de cada runtime
|
|
|
30
30
|
|
|
31
31
|
- Todo subagente termina con el **Result contract** (Status / Delegations / Risks) — el orchestrator lo procesa.
|
|
32
32
|
- Las delegaciones usan el formato `→ [agent]: [work] — [paths] — [inputs]` (skill `agent-delegation`).
|
|
33
|
-
- El flujo de trabajo lo define la skill `work-lifecycle
|
|
33
|
+
- El flujo de trabajo lo define la skill `work-lifecycle`: `work/{nombre}/plan.md` es el tablero de estado y se mantiene entre merges intermedios; las specs de tareas (`work/{nombre}/task/{NN}`), los resultados de fase (`work/{nombre}/{fase}`), los checkpoints de PR (`work/{nombre}/pr/{NN}`) y el cierre final (`work/{nombre}/done`) viven en Engram. Los subagentes reciben topic_key + título, nunca la tarea inline.
|
|
@@ -19,7 +19,7 @@ INIT → EXPLORE → SPEC → PLAN → EXECUTE → VERIFY → SHIP → CLOSE
|
|
|
19
19
|
|
|
20
20
|
### Autonomy
|
|
21
21
|
|
|
22
|
-
The human drives the flow UP TO the plan: the idea, the PRD review and the plan review are interactive. Once the plan is approved, EXECUTE → VERIFY → SHIP run **autonomously** — no questions, no confirmation pauses: plan approval authorizes commits, pushes to the work branch and the PR creation. Control returns to the user at CLOSE. Merging the PR is NEVER yours: it always requires an explicit user order.
|
|
22
|
+
The human drives the flow UP TO the plan: the idea, the PRD review and the plan review are interactive. Once the plan is approved, EXECUTE → VERIFY → SHIP run **autonomously** — no questions, no confirmation pauses: plan approval authorizes commits, pushes to the work branch and the PR creation. Control returns to the user at CLOSE. Merging the PR is NEVER yours: it always requires an explicit user order. For multi-PR work, each merge is a checkpoint; keep `work/{name}/PRD.md` and `plan.md` alive until the roadmap is finished.
|
|
23
23
|
|
|
24
24
|
## 1. INIT
|
|
25
25
|
|
|
@@ -96,11 +96,11 @@ If the work is large enough to benefit from explicit vertical slices, use the `t
|
|
|
96
96
|
|
|
97
97
|
The `work-lifecycle` skill is the single source of this flow. Summary — every piece has exactly ONE home:
|
|
98
98
|
|
|
99
|
-
- `work/{name}/` (gitignored, exists only while the work is in progress) holds the human-reviewed artifacts: `PRD.md` and `plan.md`. plan.md is the ONLY task status board — flip statuses with surgical edits; don't re-read the whole plan after every task (re-read it on resume).
|
|
99
|
+
- `work/{name}/` (gitignored, exists only while the work is in progress) holds the human-reviewed artifacts: `PRD.md` and `plan.md`. They stay resident across intermediate PR merges; `plan.md` is the ONLY task status board — flip statuses with surgical edits; don't re-read the whole plan after every task (re-read it on resume).
|
|
100
100
|
- The full spec of each atomic task → Engram, one `mem_save` per task under `work/{name}/task/{NN}`. When you delegate a task, pass the subagent its topic_key + title — never the task content inline; it retrieves the spec itself.
|
|
101
|
-
- Phase outcomes and
|
|
101
|
+
- Phase outcomes, decisions and PR checkpoints → Engram under `work/{name}/{phase}` and `work/{name}/pr/{NN}`; tell each subagent which topic_key to use for its saves.
|
|
102
102
|
- Pending work → the project's single `work/backlog` topic_key (one upserted list), or issues (`to-issues`) if the project uses a tracker. Never a TODOs folder.
|
|
103
|
-
- On close: `mem_save` the outcome under `work/{name}/done`, move the PRD to the project's docs only if it has lasting documentation value, then delete `work/{name}/`. History is memory + git.
|
|
103
|
+
- On final close: `mem_save` the outcome under `work/{name}/done`, move the PRD to the project's docs only if it has lasting documentation value, then delete `work/{name}/`. `work/{name}/done` is only for the last PR / final outcome. History is memory + git.
|
|
104
104
|
|
|
105
105
|
## Delegation map
|
|
106
106
|
|
|
@@ -118,7 +118,7 @@ Every subagent ends with a **Result contract** (Status / Delegations / Risks). P
|
|
|
118
118
|
|
|
119
119
|
Before the first task, create a git worktree for this work and run the ENTIRE execution inside it — implementation, tests, commits and pushes happen there, never on the user's main checkout.
|
|
120
120
|
|
|
121
|
-
Canonical location is mandatory: resolve the project root with `git rev-parse --show-toplevel`, ensure `worktrees/` is ignored in the repo-local `.git/info/exclude`, create `worktrees/` inside that root if needed, and create the worktree at `<project-root>/worktrees/<canonical-name>` (branch =
|
|
121
|
+
Canonical location is mandatory: resolve the project root with `git rev-parse --show-toplevel`, ensure `worktrees/` is ignored in the repo-local `.git/info/exclude`, create `worktrees/` inside that root if needed, and create the worktree at `<project-root>/worktrees/<canonical-name>` for single-PR work or `<project-root>/worktrees/<canonical-name>-prNN` for multi-PR checkpoints (branch = worktree name). Do not create worktrees next to the repo, in the repo root, under `work/`, or in any external temp/shared folder.
|
|
122
122
|
|
|
123
123
|
Every delegation prompt must state the worktree path as the ONLY allowed write root. After each writer subagent finishes, verify the user's main checkout is still clean (`git status` there); if the subagent wrote outside the worktree, STOP, move those changes into the worktree (patch/apply) and restore the main checkout before continuing. Subagent obedience is not a safety boundary — this check is.
|
|
124
124
|
|
|
@@ -178,7 +178,7 @@ When the plan is fully applied and VERIFY passes:
|
|
|
178
178
|
## 8. CLOSE
|
|
179
179
|
|
|
180
180
|
- STOP here and hand control back to the user: report what shipped, review findings applied vs deferred to `work/backlog`, and whether manual testing is advisable (recommend it for big or user-facing changes; small well-tested changes may not need it).
|
|
181
|
-
- NEVER merge the PR yourself — merge only on an explicit user order. After the merge: persist the outcome to memory, clean up `work/{name}/` and remove the worktree (see Work state).
|
|
181
|
+
- NEVER merge the PR yourself — merge only on an explicit user order. After each intermediate merge: persist the checkpoint to `work/{name}/pr/{NN}`, update `plan.md`, and keep `work/{name}/` alive. After the final merge: persist the final outcome to memory, clean up `work/{name}/` and remove the worktree (see Work state).
|
|
182
182
|
- If the repo has its own skill for the closing steps (release, deploy, git, cleanup), that skill takes precedence over the default behavior.
|
|
183
183
|
|
|
184
184
|
## Task rule
|
package/stack/hooks/hooks.json
CHANGED
|
@@ -12,6 +12,16 @@
|
|
|
12
12
|
"timeout": 30
|
|
13
13
|
}
|
|
14
14
|
]
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"matcher": "Bash|PowerShell|EnterWorktree|ExitWorktree",
|
|
18
|
+
"hooks": [
|
|
19
|
+
{
|
|
20
|
+
"type": "command",
|
|
21
|
+
"command": "node \"{{SCRIPTS_DIR}}/repair-worktree-config.cjs\"",
|
|
22
|
+
"timeout": 10
|
|
23
|
+
}
|
|
24
|
+
]
|
|
15
25
|
}
|
|
16
26
|
]
|
|
17
27
|
}
|
|
@@ -5,7 +5,6 @@ interface WorktreePluginConfig {
|
|
|
5
5
|
setupScript?: string;
|
|
6
6
|
docsReminderScript?: string;
|
|
7
7
|
pathContains?: string;
|
|
8
|
-
branchPrefix?: string;
|
|
9
8
|
reminderLines?: string[];
|
|
10
9
|
}
|
|
11
10
|
|
|
@@ -290,7 +289,6 @@ export const WorktreePlugin: Plugin = async ({ $, client, directory }) => {
|
|
|
290
289
|
let config: WorktreePluginConfig = {
|
|
291
290
|
setupScript: "scripts/setup-worktree.ps1",
|
|
292
291
|
pathContains: "worktrees/",
|
|
293
|
-
branchPrefix: "feature/",
|
|
294
292
|
reminderLines: [],
|
|
295
293
|
};
|
|
296
294
|
|
|
@@ -356,7 +354,7 @@ export const WorktreePlugin: Plugin = async ({ $, client, directory }) => {
|
|
|
356
354
|
const worktreeName = getWorktreeName(parsedWorktreePath);
|
|
357
355
|
if (!worktreeName) return;
|
|
358
356
|
|
|
359
|
-
const branchName =
|
|
357
|
+
const branchName = worktreeName;
|
|
360
358
|
|
|
361
359
|
// .quiet() suppresses stderr to prevent noisy TUI logs from git calls
|
|
362
360
|
const gitRoot = await $`git rev-parse --show-toplevel`.quiet().text();
|
|
@@ -372,7 +370,7 @@ export const WorktreePlugin: Plugin = async ({ $, client, directory }) => {
|
|
|
372
370
|
appendToolOutput(output, [
|
|
373
371
|
`Worktree path is not canonical: ${absoluteWorktreePath}`,
|
|
374
372
|
`Use the project-local path instead: ${expectedWorktreePath}`,
|
|
375
|
-
"Canonical rule: <project-root>/worktrees/<canonical-name
|
|
373
|
+
"Canonical rule: <project-root>/worktrees/<canonical-name> or <project-root>/worktrees/<canonical-name>-prNN.",
|
|
376
374
|
]);
|
|
377
375
|
return;
|
|
378
376
|
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Repara la config de git que el harness de worktrees de los agentes puede dejar
|
|
3
|
+
// corrupta cuando hay varios worktrees activos en la misma sesion:
|
|
4
|
+
// - core.bare=true en el repo principal -> rompe rev-parse --show-toplevel / marca (bare)
|
|
5
|
+
// - core.worktree apuntando a OTRO worktree -> show-toplevel/status/add operan sobre
|
|
6
|
+
// el working-tree equivocado (branch/HEAD/git-dir siguen correctos: sintoma enganoso)
|
|
7
|
+
//
|
|
8
|
+
// GATE DE ALCANCE: el bug SOLO lo causa el harness de worktrees, asi que este guardian
|
|
9
|
+
// solo actua en repos con worktrees ENLAZADOS. Un repo normal (o uno con layout legitimo
|
|
10
|
+
// --separate-git-dir sin worktrees) NUNCA se toca, aunque el hook se publique y corra en
|
|
11
|
+
// cada tool call de cualquier repo.
|
|
12
|
+
//
|
|
13
|
+
// El directorio del proyecto se toma del payload de stdin (data.cwd/directory/
|
|
14
|
+
// activeWorktreePath), igual que post-pr-review.cjs: en OpenCode el hook se ejecuta con
|
|
15
|
+
// cwd = dir de config, no el del proyecto, asi que fiarse de process.cwd() no repararia
|
|
16
|
+
// el repo correcto. Fallback a process.cwd() (Claude Code / Codex ya corren ahi).
|
|
17
|
+
//
|
|
18
|
+
// Cross-agent (Claude Code / Codex / OpenCode) y cross-platform: node puro, sin deps.
|
|
19
|
+
// Idempotente, INDEPENDIENTE del cwd de escritura (opera con --file sobre rutas absolutas),
|
|
20
|
+
// fail-open y exit 0 SIEMPRE (un guardian nunca debe bloquear una tool). Como el guardian
|
|
21
|
+
// hermano (block-destructive-git.cjs), un fail-open deja rastro en stderr para ser diagnosticable.
|
|
22
|
+
|
|
23
|
+
const { execFileSync } = require("node:child_process");
|
|
24
|
+
const fs = require("node:fs");
|
|
25
|
+
const path = require("node:path");
|
|
26
|
+
|
|
27
|
+
const TAG = "[repair-worktree-config]";
|
|
28
|
+
|
|
29
|
+
/** Ejecuta git en `cwd` y devuelve stdout recortado, o null si falla (fail-open). */
|
|
30
|
+
function git(args, cwd) {
|
|
31
|
+
try {
|
|
32
|
+
return execFileSync("git", args, {
|
|
33
|
+
cwd: cwd || undefined,
|
|
34
|
+
encoding: "utf8",
|
|
35
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
36
|
+
}).trim();
|
|
37
|
+
} catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Diagnostico a stderr (no bloquea): un no-op/fallo silencioso es indetectable. */
|
|
43
|
+
function warn(message) {
|
|
44
|
+
try {
|
|
45
|
+
process.stderr.write(`${TAG} ${message}\n`);
|
|
46
|
+
} catch {
|
|
47
|
+
/* stderr cerrado: no hay nada que hacer */
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** .git comun (compartido por todos los worktrees). Fiable aun con core.worktree
|
|
52
|
+
* envenenado: este afecta al work-tree, no al git-dir. */
|
|
53
|
+
function gitCommonDir(cwd) {
|
|
54
|
+
const abs = git(["rev-parse", "--path-format=absolute", "--git-common-dir"], cwd);
|
|
55
|
+
if (abs) return abs;
|
|
56
|
+
const rel = git(["rev-parse", "--git-common-dir"], cwd);
|
|
57
|
+
return rel ? path.resolve(cwd, rel) : null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Quita core.worktree de `file` si esta puesto. Devuelve la etiqueta reparada o null.
|
|
61
|
+
* Verifica el resultado: un unset fallido se avisa por stderr y NO se reporta reparado.
|
|
62
|
+
* Las ops --file son independientes del cwd (rutas absolutas). */
|
|
63
|
+
function unsetWorktree(file, label) {
|
|
64
|
+
if (!git(["config", "--file", file, "--get", "core.worktree"])) return null;
|
|
65
|
+
if (git(["config", "--file", file, "--unset-all", "core.worktree"]) === null) {
|
|
66
|
+
warn(`fallo al quitar core.worktree(${label}) - sigue puesto en ${file}`);
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
return `core.worktree(${label})`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function repair(cwd) {
|
|
73
|
+
const common = gitCommonDir(cwd);
|
|
74
|
+
if (!common) {
|
|
75
|
+
// Distinguir "git no disponible" de "no es un repo": un guardian muerto por
|
|
76
|
+
// falta de git seria un no-op PERMANENTE e invisible en cada tool call.
|
|
77
|
+
if (git(["--version"], cwd) === null) {
|
|
78
|
+
warn("git no esta disponible en el PATH - el guardian no puede reparar");
|
|
79
|
+
}
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (!fs.existsSync(common)) return;
|
|
83
|
+
|
|
84
|
+
// Gate de alcance: solo repos con worktrees enlazados (donde el bug es posible).
|
|
85
|
+
let entries = [];
|
|
86
|
+
try {
|
|
87
|
+
entries = fs
|
|
88
|
+
.readdirSync(path.join(common, "worktrees"), { withFileTypes: true })
|
|
89
|
+
.filter((entry) => entry.isDirectory());
|
|
90
|
+
} catch {
|
|
91
|
+
/* repo sin worktrees enlazados */
|
|
92
|
+
}
|
|
93
|
+
if (entries.length === 0) return;
|
|
94
|
+
|
|
95
|
+
const sharedCfg = path.join(common, "config");
|
|
96
|
+
const repaired = [];
|
|
97
|
+
|
|
98
|
+
// 1) core.bare -> false si quedo en true. Solo en layout normal (.git): nunca
|
|
99
|
+
// tocamos un repo genuinamente bare (cuyo git-dir no se llama ".git").
|
|
100
|
+
if (
|
|
101
|
+
path.basename(common) === ".git" &&
|
|
102
|
+
git(["config", "--file", sharedCfg, "--get", "core.bare"]) === "true"
|
|
103
|
+
) {
|
|
104
|
+
if (git(["config", "--file", sharedCfg, "core.bare", "false"]) === null) {
|
|
105
|
+
warn(`fallo al forzar core.bare=false en ${sharedCfg}`);
|
|
106
|
+
} else {
|
|
107
|
+
repaired.push("core.bare(shared)");
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 2) core.worktree en el config compartido (caso sin extensions.worktreeConfig)
|
|
112
|
+
const shared = unsetWorktree(sharedCfg, "shared");
|
|
113
|
+
if (shared) repaired.push(shared);
|
|
114
|
+
|
|
115
|
+
// 3) core.worktree en cada config.worktree por-worktree (caso worktreeConfig activo)
|
|
116
|
+
for (const entry of entries) {
|
|
117
|
+
const cw = path.join(common, "worktrees", entry.name, "config.worktree");
|
|
118
|
+
if (!fs.existsSync(cw)) continue;
|
|
119
|
+
const perWorktree = unsetWorktree(cw, entry.name);
|
|
120
|
+
if (perWorktree) repaired.push(perWorktree);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (repaired.length > 0) {
|
|
124
|
+
process.stdout.write(`${TAG} reparado: ${repaired.join(", ")}\n`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Directorio del proyecto desde el payload del hook; fallback a process.cwd(). */
|
|
129
|
+
function resolveCwd(data) {
|
|
130
|
+
const candidate =
|
|
131
|
+
data && (data.activeWorktreePath || data.worktreePath || data.cwd || data.directory);
|
|
132
|
+
return typeof candidate === "string" && candidate ? candidate : process.cwd();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function run(data) {
|
|
136
|
+
try {
|
|
137
|
+
repair(resolveCwd(data));
|
|
138
|
+
} catch (error) {
|
|
139
|
+
// fail-open: nunca bloquear una tool, pero deja rastro del fallo del propio guardian.
|
|
140
|
+
warn(`error inesperado: ${error && error.message ? error.message : String(error)}`);
|
|
141
|
+
}
|
|
142
|
+
process.exit(0);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Los 3 runtimes entregan el payload del hook por stdin (JSON). Sin stdin (ejecucion
|
|
146
|
+
// manual/TTY) no bloqueamos: reparamos contra process.cwd().
|
|
147
|
+
if (process.stdin.isTTY) {
|
|
148
|
+
run({});
|
|
149
|
+
} else {
|
|
150
|
+
let raw = "";
|
|
151
|
+
process.stdin.setEncoding("utf8");
|
|
152
|
+
process.stdin.on("data", (chunk) => (raw += chunk));
|
|
153
|
+
process.stdin.on("end", () => {
|
|
154
|
+
let data = {};
|
|
155
|
+
try {
|
|
156
|
+
data = JSON.parse(raw || "{}");
|
|
157
|
+
} catch {
|
|
158
|
+
data = {};
|
|
159
|
+
}
|
|
160
|
+
run(data);
|
|
161
|
+
});
|
|
162
|
+
process.stdin.on("error", () => run({}));
|
|
163
|
+
}
|
|
@@ -53,6 +53,16 @@ Do NOT include specific file paths or code snippets. They may end up being outda
|
|
|
53
53
|
|
|
54
54
|
Exception: if a prototype produced a snippet that encodes a decision more precisely than prose can (state machine, reducer, schema, type shape), inline it within the relevant decision and note briefly that it came from a prototype. Trim to the decision-rich parts — not a working demo, just the important bits.
|
|
55
55
|
|
|
56
|
+
## Delivery / PR Roadmap
|
|
57
|
+
|
|
58
|
+
This section captures the intended PR split only. Live status, checkpoints, and task progress belong in `plan.md`.
|
|
59
|
+
|
|
60
|
+
1. PR 01 — [scope / outcome]
|
|
61
|
+
2. PR 02 — [scope / outcome]
|
|
62
|
+
3. PR 03 — [scope / outcome]
|
|
63
|
+
|
|
64
|
+
Keep this static: describe the planned delivery slices, not the current state.
|
|
65
|
+
|
|
56
66
|
## Testing Decisions
|
|
57
67
|
|
|
58
68
|
A list of testing decisions that were made. Include:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: work-lifecycle
|
|
3
|
-
description: Single source for how a piece of work is tracked and advances — PRD and plan as files in work/{name}/ while in progress; task specs, phase outcomes and history in Engram memory. Use when starting, tracking, resuming or closing a piece of work, or when deciding where a PRD, plan, task or backlog item should live.
|
|
3
|
+
description: Single source for how a piece of work is tracked and advances — PRD and plan as files in work/{name}/ while in progress; task specs, phase outcomes, PR checkpoints and history in Engram memory. Use when starting, tracking, resuming or closing a piece of work, or when deciding where a PRD, plan, task or backlog item should live.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Work Lifecycle
|
|
@@ -9,7 +9,7 @@ One rule kills duplication: **every piece of information has exactly ONE home**.
|
|
|
9
9
|
|
|
10
10
|
## Identity
|
|
11
11
|
|
|
12
|
-
Every piece of work gets a **canonical kebab-case name** when it starts (e.g. `checkout-refactor`), shared with the branch
|
|
12
|
+
Every piece of work gets a **canonical kebab-case name** when it starts (e.g. `checkout-refactor`), shared with the single-PR branch/worktree name and the base name for multi-PR checkpoints. The name stays the same across its whole life — it is the key to everything else.
|
|
13
13
|
|
|
14
14
|
## Where everything lives
|
|
15
15
|
|
|
@@ -18,8 +18,9 @@ Every piece of work gets a **canonical kebab-case name** when it starts (e.g. `c
|
|
|
18
18
|
| PRD | `work/{name}/PRD.md` | Written once, reviewed by the human |
|
|
19
19
|
| Plan (goal, approach, task board) | `work/{name}/plan.md` | The status board: humans glance at it; statuses flip with surgical edits |
|
|
20
20
|
| Full spec of each atomic task | Engram `work/{name}/task/{NN}` | Only subagents consume it; visible from any worktree |
|
|
21
|
+
| PR checkpoint outcome | Engram `work/{name}/pr/{NN}` | Intermediate PR merge record |
|
|
21
22
|
| Phase outcomes, decisions, findings | Engram `work/{name}/{phase}` | History — must survive the folder and compactions |
|
|
22
|
-
| Final outcome | Engram `work/{name}/done` | Permanent record of what shipped |
|
|
23
|
+
| Final outcome | Engram `work/{name}/done` | Permanent record of what shipped after the last PR |
|
|
23
24
|
| Pending / backlog items | Engram `work/backlog` — ONE key per project | All pending ideas in a single upserted list |
|
|
24
25
|
|
|
25
26
|
`work/` is **scaffolding, not product**: add it to the project's `.gitignore`. It contains ONLY work in progress — an empty `work/` means nothing is half-done. No `1-TODOs/`, no `3-finalized/`, no phase subfolders.
|
|
@@ -28,16 +29,17 @@ Every piece of work gets a **canonical kebab-case name** when it starts (e.g. `c
|
|
|
28
29
|
|
|
29
30
|
1. Pick the canonical name and create `work/{name}/`. If the item came from the backlog, remove it from `work/backlog` in the same step.
|
|
30
31
|
2. Produce the PRD with the `to-prd` skill → `work/{name}/PRD.md`. The human reviews it there.
|
|
31
|
-
3. Write `work/{name}/plan.md` (structure in `references/plan-template.md`): goal, chosen approach, success criteria, and the task table — number, title, one-line description, status, wave, deps.
|
|
32
|
+
3. Write `work/{name}/plan.md` (structure in `references/plan-template.md`): goal, chosen approach, success criteria, PR roadmap, and the task table — number, PR, title, one-line description, status, wave, deps.
|
|
32
33
|
4. Save the full spec of each atomic task to memory: one `mem_save` per task with topic_key `work/{name}/task/{NN}` (content structure in `references/plan-template.md`).
|
|
33
34
|
|
|
34
35
|
## Executing
|
|
35
36
|
|
|
36
37
|
- Execution happens inside a git worktree created for the work; the user's main checkout stays untouched until merge.
|
|
37
|
-
- Worktree path is fixed: first resolve the project root with `git rev-parse --show-toplevel`, ensure `worktrees/` is ignored in the repo-local `.git/info/exclude`, then create/use `<project-root>/worktrees/<canonical-name>`
|
|
38
|
+
- Worktree path is fixed: first resolve the project root with `git rev-parse --show-toplevel`, ensure `worktrees/` is ignored in the repo-local `.git/info/exclude`, then create/use `<project-root>/worktrees/<canonical-name>` for single-PR work or `<project-root>/worktrees/<canonical-name>-prNN` for multi-PR checkpoints, with the branch matching the worktree name. Never place worktrees in the repo root, next to the repo, under `work/`, or outside the project.
|
|
38
39
|
- Delegation handoff: the subagent receives its **topic_key + task title**, never the task content inline. It retrieves the spec itself (`mem_search` → `mem_get_observation`).
|
|
39
40
|
- The subagent saves its phase outcome under the topic_key the orchestrator gave it (`work/{name}/{phase}`) BEFORE its final report.
|
|
40
|
-
- Task status lives ONLY in the
|
|
41
|
+
- Task status lives ONLY in the task table: flip it (⬜ → ✅) with a surgical edit when the task closes. PR status/evidence lives ONLY in the PR roadmap table. Do not mirror task progress into memory, and do not re-read the whole plan after every task — it is already in context; re-read it on resume.
|
|
42
|
+
- For multi-PR work, resume from the first PR/task not done in the roadmap/table. For single-PR work, the canonical name worktree/branch is enough and the roadmap collapses to one checkpoint.
|
|
41
43
|
|
|
42
44
|
## HTML review view (on demand)
|
|
43
45
|
|
|
@@ -61,13 +63,28 @@ If the project manages work through an issue tracker, issues (`to-issues`) take
|
|
|
61
63
|
|
|
62
64
|
## Closing
|
|
63
65
|
|
|
64
|
-
|
|
66
|
+
There are two close levels:
|
|
67
|
+
|
|
68
|
+
### PR checkpoint
|
|
69
|
+
|
|
70
|
+
When an intermediate PR is merged:
|
|
71
|
+
|
|
72
|
+
1. `mem_save` under `work/{name}/pr/{NN}`: what merged, what remains, and any blockers.
|
|
73
|
+
2. Update the PR roadmap and task statuses in `work/{name}/plan.md`.
|
|
74
|
+
3. Delete that PR's worktree if appropriate.
|
|
75
|
+
4. Keep `work/{name}/` alive for the remaining PRs.
|
|
76
|
+
|
|
77
|
+
### Final work close
|
|
78
|
+
|
|
79
|
+
When all PRs are merged, cancelled, or deferred:
|
|
65
80
|
|
|
66
81
|
1. `mem_save` under `work/{name}/done`: outcome, what shipped, anything left pending.
|
|
67
82
|
2. If the PRD has lasting documentation value, move it to where the project keeps docs (e.g. `docs/`); otherwise its key decisions already live in `done`.
|
|
68
|
-
3. **Delete `work/{name}/`** and remove the
|
|
83
|
+
3. **Delete `work/{name}/`** and remove the remaining worktree(s). Nothing to archive — git has the code, memory has the story.
|
|
69
84
|
4. `mem_session_summary` covers the session as usual.
|
|
70
85
|
|
|
86
|
+
For single-PR work, the PR checkpoint and final work close happen together: one merge, one `work/{name}/done`, then cleanup.
|
|
87
|
+
|
|
71
88
|
## Rules
|
|
72
89
|
|
|
73
90
|
- One piece of work = one canonical name, stable across its whole life.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Plan & Task Templates
|
|
2
2
|
|
|
3
|
-
Templates for the two artifacts of a piece of work: `plan.md` (file — the status board) and the atomic tasks (Engram observations). `[name]` is the canonical kebab-case name shared by `work/[name]
|
|
3
|
+
Templates for the two artifacts of a piece of work: `plan.md` (file — the status board) and the atomic tasks (Engram observations). `[name]` is the canonical kebab-case name shared by `work/[name]/` and every topic_key. PR branches/worktrees derive from it: `[name]` for single-PR work, `[name]-prNN` for multi-PR checkpoints.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -36,6 +36,19 @@ The full spec of each task is NOT a file: it lives in Engram, one observation pe
|
|
|
36
36
|
|
|
37
37
|
[Why it wasn't chosen]
|
|
38
38
|
|
|
39
|
+
## PR Roadmap
|
|
40
|
+
|
|
41
|
+
> This is the live PR-level board: scope, PR status, and merge evidence live here.
|
|
42
|
+
> Task-level status stays in the task table below.
|
|
43
|
+
> Full checkpoint history lives in Engram under `work/[name]/pr/[NN]`.
|
|
44
|
+
|
|
45
|
+
| PR | Scope | Branch | Worktree | Base | Status | Merge evidence |
|
|
46
|
+
|----|-------|--------|----------|------|--------|----------------|
|
|
47
|
+
| 01 | [scope] | [branch] | [worktree] | [base] | ⬜ | [evidence] |
|
|
48
|
+
| 02 | [scope] | [branch] | [worktree] | [base] | ⬜ | [evidence] |
|
|
49
|
+
|
|
50
|
+
> Intermediate PRs do not delete `work/[name]/`; only the final close does.
|
|
51
|
+
|
|
39
52
|
## Success criteria
|
|
40
53
|
|
|
41
54
|
- [ ] [Verifiable behavior 1]
|
|
@@ -45,14 +58,16 @@ The full spec of each task is NOT a file: it lives in Engram, one observation pe
|
|
|
45
58
|
## Tasks
|
|
46
59
|
|
|
47
60
|
> Full spec of task NN → Engram topic_key `work/[name]/task/NN`.
|
|
48
|
-
>
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
|
53
|
-
|
|
54
|
-
|
|
|
55
|
-
|
|
|
61
|
+
> Task status lives ONLY in this table — update it with a surgical edit per task.
|
|
62
|
+
> PR status/evidence lives in the PR Roadmap above.
|
|
63
|
+
> Map each task to the PR that carries it; intermediate PRs keep `work/[name]/` alive.
|
|
64
|
+
|
|
65
|
+
| # | PR | Task | One-liner | Status | Wave | Deps |
|
|
66
|
+
|---|----|------|-----------|--------|------|------|
|
|
67
|
+
| 01 | 01 | [descriptive name] | [one-line description] | ⬜ | 1 | — |
|
|
68
|
+
| 02 | 01 | [descriptive name] | [one-line description] | ⬜ | 1 | — |
|
|
69
|
+
| 03 | 02 | [descriptive name] | [one-line description] | ⬜ | 2 | 01 |
|
|
70
|
+
| 04 | 02 | [descriptive name] | [one-line description] | ⬜ | 2 | 01, 02 |
|
|
56
71
|
|
|
57
72
|
**Statuses**: ⬜ Pending → 🔴 RED → 🟢 GREEN → 🔍 Review → ✅ Done
|
|
58
73
|
```
|
|
@@ -90,11 +90,12 @@ docs/
|
|
|
90
90
|
|
|
91
91
|
Every piece of information about a piece of work has exactly ONE home — never two. The `work-lifecycle` skill is the single source of this flow.
|
|
92
92
|
|
|
93
|
-
- In-progress work lives in `work/{name}/` (gitignored): `PRD.md` + `plan.md`. plan.md is the ONLY task status board — update statuses with surgical edits. An empty `work/` means nothing is half-done.
|
|
94
|
-
- Execution worktrees
|
|
95
|
-
- Full task specs, phase outcomes and history live in Engram: `work/{name}/task/{NN}`, `work/{name}/{phase}`, `work/{name}/done`. Subagents receive a topic_key + title, never the task content inline.
|
|
93
|
+
- In-progress work lives in `work/{name}/` (gitignored): `PRD.md` + `plan.md`. They stay there across intermediate PR merges; `plan.md` is the ONLY task status board — update statuses with surgical edits. An empty `work/` means nothing is half-done.
|
|
94
|
+
- Execution worktrees and their branches always use the same name. Resolve the root with `git rev-parse --show-toplevel`, ensure `worktrees/` is ignored in the repo-local `.git/info/exclude`, then create/use `<project-root>/worktrees/<canonical-name>` for single-PR work or `<project-root>/worktrees/<canonical-name>-prNN` for multi-PR checkpoints; never create worktrees next to the repo, in the repo root, under `work/`, or in external temp/shared folders.
|
|
95
|
+
- Full task specs, phase outcomes, PR checkpoints and history live in Engram: `work/{name}/task/{NN}`, `work/{name}/{phase}`, `work/{name}/pr/{NN}`, `work/{name}/done`. Subagents receive a topic_key + title, never the task content inline.
|
|
96
96
|
- Pending work: the project's single `work/backlog` topic_key (one upserted list — never one key per idea), or issues (`to-issues`) if the project uses a tracker. Never a TODOs folder.
|
|
97
|
-
- On
|
|
97
|
+
- On intermediate PR merge: save the checkpoint under `work/{name}/pr/{NN}` and keep `work/{name}/` alive for the remaining PRs.
|
|
98
|
+
- On final close: save the outcome under `work/{name}/done`, move the PRD to the project's docs only if it has lasting value, then delete `work/{name}/`. `work/{name}/done` is the final outcome only. History is memory + git — no archive folders.
|
|
98
99
|
|
|
99
100
|
---
|
|
100
101
|
|
|
@@ -40,7 +40,7 @@ Use the `engram` subagent for non-trivial memory reads — it filters and return
|
|
|
40
40
|
|
|
41
41
|
## Work state
|
|
42
42
|
|
|
43
|
-
Work tracking follows the `work-lifecycle` skill: `work/{name}/plan.md` (file) is the only status board; memory holds the task specs (`work/{name}/task/{NN}`), phase outcomes (`work/{name}/{phase}`), the final `work/{name}/done
|
|
43
|
+
Work tracking follows the `work-lifecycle` skill: `work/{name}/plan.md` (file) is the only status board; memory holds the task specs (`work/{name}/task/{NN}`), phase outcomes (`work/{name}/{phase}`), PR checkpoints (`work/{name}/pr/{NN}`), and the final outcome in `work/{name}/done` only after the last PR; the project backlog stays under the single key `work/backlog`. Subagents retrieve their task by the topic_key the orchestrator passes them and save their phase outcome under the topic_key they were given BEFORE their final report.
|
|
44
44
|
|
|
45
45
|
## Before ending a session
|
|
46
46
|
|