@snappedly-tools/shipyard 0.5.0 → 0.7.0-staging.36081473933
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 +64 -117
- package/dist/MountConfig-BHnKnA4h.d.ts +145 -0
- package/dist/{chunk-WAXEMZUV.js → chunk-44I2BL6E.js} +225 -33
- package/dist/chunk-44I2BL6E.js.map +1 -0
- package/dist/{chunk-56TDSWFU.js → chunk-JI3HDDMS.js} +3 -3
- package/dist/{chunk-56TDSWFU.js.map → chunk-JI3HDDMS.js.map} +1 -1
- package/dist/{chunk-FDYOTN55.js → chunk-L6PX5QTU.js} +253 -878
- package/dist/chunk-L6PX5QTU.js.map +1 -0
- package/dist/index.d.ts +117 -97
- package/dist/index.js +349 -353
- package/dist/index.js.map +1 -1
- package/dist/main.js +285 -153
- package/dist/main.js.map +1 -1
- package/dist/sandboxes/docker.d.ts +1 -3
- package/dist/sandboxes/docker.js +2 -4
- package/dist/templates/parallel-planner/block-scope.sh +160 -0
- package/dist/templates/parallel-planner/conflict-prompt.md +22 -0
- package/dist/templates/parallel-planner/handoff.sh +175 -0
- package/dist/templates/parallel-planner/implement-prompt.md +10 -56
- package/dist/templates/parallel-planner/main.mts +493 -189
- package/dist/templates/parallel-planner/merge-prompt.md +9 -21
- package/dist/templates/parallel-planner/plan-prompt.md +5 -31
- package/dist/templates/parallel-planner/planner-branch.mts +151 -0
- package/dist/templates/parallel-planner/select-issues.mjs +788 -0
- package/dist/templates/parallel-planner/setup.sh +51 -0
- package/dist/templates/parallel-planner/spec-wave-prompt.md +16 -0
- package/dist/templates/parallel-planner/template.json +1 -1
- package/dist/templates/parallel-planner/triage-prompt.md +5 -0
- package/dist/templates/parallel-planner/verify-triage.sh +19 -0
- package/dist/templates/parallel-planner-with-review/block-scope.sh +160 -0
- package/dist/templates/parallel-planner-with-review/conflict-prompt.md +22 -0
- package/dist/templates/parallel-planner-with-review/handoff.sh +175 -0
- package/dist/templates/parallel-planner-with-review/implement-prompt.md +10 -56
- package/dist/templates/parallel-planner-with-review/main.mts +533 -207
- package/dist/templates/parallel-planner-with-review/merge-prompt.md +9 -21
- package/dist/templates/parallel-planner-with-review/plan-prompt.md +5 -31
- package/dist/templates/parallel-planner-with-review/planner-branch.mts +151 -0
- package/dist/templates/parallel-planner-with-review/review-prompt.md +11 -49
- package/dist/templates/parallel-planner-with-review/select-issues.mjs +788 -0
- package/dist/templates/parallel-planner-with-review/setup.sh +51 -0
- package/dist/templates/parallel-planner-with-review/spec-wave-prompt.md +16 -0
- package/dist/templates/parallel-planner-with-review/template.json +1 -1
- package/dist/templates/parallel-planner-with-review/triage-prompt.md +5 -0
- package/dist/templates/parallel-planner-with-review/verify-triage.sh +19 -0
- package/dist/templates/sequential-reviewer/block-scope.sh +160 -0
- package/dist/templates/sequential-reviewer/handoff.sh +175 -0
- package/dist/templates/sequential-reviewer/implement-prompt.md +12 -46
- package/dist/templates/sequential-reviewer/main.mts +248 -103
- package/dist/templates/sequential-reviewer/review-prompt.md +11 -49
- package/dist/templates/sequential-reviewer/select-issues.mjs +788 -0
- package/dist/templates/sequential-reviewer/setup.sh +51 -0
- package/dist/templates/sequential-reviewer/template.json +1 -1
- package/dist/templates/sequential-reviewer/triage-prompt.md +5 -0
- package/dist/templates/sequential-reviewer/verify-triage.sh +19 -0
- package/dist/templates/shared/block-scope.sh +160 -0
- package/dist/templates/shared/handoff.sh +175 -0
- package/dist/templates/shared/select-issues.mjs +788 -0
- package/dist/templates/shared/setup.sh +51 -0
- package/dist/templates/shared/triage-prompt.md +5 -0
- package/dist/templates/shared/verify-triage.sh +19 -0
- package/dist/templates/simple-loop/block-scope.sh +160 -0
- package/dist/templates/simple-loop/handoff.sh +175 -0
- package/dist/templates/simple-loop/main.mts +239 -45
- package/dist/templates/simple-loop/prompt.md +12 -46
- package/dist/templates/simple-loop/select-issues.mjs +788 -0
- package/dist/templates/simple-loop/setup.sh +51 -0
- package/dist/templates/simple-loop/template.json +1 -1
- package/dist/templates/simple-loop/triage-prompt.md +5 -0
- package/dist/templates/simple-loop/verify-triage.sh +19 -0
- package/package.json +1 -17
- package/dist/MountConfig-bZoCs4Dd.d.ts +0 -26
- package/dist/SandboxProvider-XJQqEdSf.d.ts +0 -261
- package/dist/chunk-ACD46ZM4.js +0 -136
- package/dist/chunk-ACD46ZM4.js.map +0 -1
- package/dist/chunk-FDYOTN55.js.map +0 -1
- package/dist/chunk-KMGNFXKN.js +0 -38
- package/dist/chunk-KMGNFXKN.js.map +0 -1
- package/dist/chunk-SOJTAJTF.js +0 -78
- package/dist/chunk-SOJTAJTF.js.map +0 -1
- package/dist/chunk-WAXEMZUV.js.map +0 -1
- package/dist/sandboxes/no-sandbox.d.ts +0 -37
- package/dist/sandboxes/no-sandbox.js +0 -4
- package/dist/sandboxes/no-sandbox.js.map +0 -1
- package/dist/sandboxes/vercel.d.ts +0 -104
- package/dist/sandboxes/vercel.js +0 -166
- package/dist/sandboxes/vercel.js.map +0 -1
- package/dist/templates/blank/main.mts +0 -13
- package/dist/templates/blank/prompt.md +0 -12
- package/dist/templates/blank/template.json +0 -4
|
@@ -1,51 +1,245 @@
|
|
|
1
|
-
|
|
1
|
+
// Simple loop: select one activated issue scope per iteration, implement it,
|
|
2
|
+
// then hand its verified commit to a human through a pull request.
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import * as shipyard from "@snappedly-tools/shipyard";
|
|
2
6
|
import { docker } from "@snappedly-tools/shipyard/sandboxes/docker";
|
|
3
7
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
8
|
+
if (process.loadEnvFile && existsSync(".shipyard/.env"))
|
|
9
|
+
process.loadEnvFile(".shipyard/.env");
|
|
10
|
+
type ModelRole = "routine" | "strong";
|
|
11
|
+
const CODEX_PROVIDER = true;
|
|
12
|
+
const agentFactory = shipyard.codex;
|
|
13
|
+
type AgentModel = Parameters<typeof agentFactory>[0];
|
|
14
|
+
const readRoleModel = (role: ModelRole): string | undefined => {
|
|
15
|
+
const envName = `SHIPYARD_${role.toUpperCase()}_MODEL`;
|
|
16
|
+
const model = process.env[envName];
|
|
17
|
+
if (model !== undefined && model.trim().length === 0)
|
|
18
|
+
throw new Error(`${envName} must not be empty`);
|
|
19
|
+
return model;
|
|
20
|
+
};
|
|
21
|
+
const roleModels = {
|
|
22
|
+
routine: readRoleModel("routine"),
|
|
23
|
+
strong: readRoleModel("strong"),
|
|
24
|
+
};
|
|
25
|
+
const CODEX_REASONING_EFFORTS = shipyard.CODEX_REASONING_EFFORTS;
|
|
26
|
+
type CodexReasoningEffort = shipyard.CodexReasoningEffort;
|
|
27
|
+
const readCodexReasoningEffort = (
|
|
28
|
+
role: ModelRole,
|
|
29
|
+
): CodexReasoningEffort | undefined => {
|
|
30
|
+
if (!CODEX_PROVIDER) return undefined;
|
|
31
|
+
const envName = `SHIPYARD_CODEX_${role.toUpperCase()}_REASONING_EFFORT`;
|
|
32
|
+
const effort = process.env[envName]?.trim();
|
|
33
|
+
if (!effort) return undefined;
|
|
34
|
+
if (!(CODEX_REASONING_EFFORTS as readonly string[]).includes(effort))
|
|
35
|
+
throw new Error(
|
|
36
|
+
`${envName} must be one of ${CODEX_REASONING_EFFORTS.join(", ")}; received "${effort}"`,
|
|
37
|
+
);
|
|
38
|
+
return effort as CodexReasoningEffort;
|
|
39
|
+
};
|
|
40
|
+
const roleEfforts = {
|
|
41
|
+
routine: readCodexReasoningEffort("routine"),
|
|
42
|
+
strong: readCodexReasoningEffort("strong"),
|
|
43
|
+
};
|
|
44
|
+
const readCodexRoleModel = (role: ModelRole, defaultModel: AgentModel) => {
|
|
45
|
+
if (!CODEX_PROVIDER || typeof defaultModel === "string") return defaultModel;
|
|
46
|
+
const envName = `SHIPYARD_CODEX_${role.toUpperCase()}_MODEL`;
|
|
47
|
+
const model = process.env[envName]?.trim();
|
|
48
|
+
return model ? { ...defaultModel, model } : defaultModel;
|
|
49
|
+
};
|
|
50
|
+
const roleAgent = (role: ModelRole, defaultModel: AgentModel) => {
|
|
51
|
+
const model = roleModels[role] ?? readCodexRoleModel(role, defaultModel);
|
|
52
|
+
const effort = roleEfforts[role];
|
|
53
|
+
if (typeof model !== "string")
|
|
54
|
+
return effort === undefined
|
|
55
|
+
? agentFactory(model)
|
|
56
|
+
: agentFactory(model, { effort });
|
|
57
|
+
return agentFactory(model, { effort: effort ?? null });
|
|
58
|
+
};
|
|
59
|
+
const targetBranch = execFileSync("git", ["branch", "--show-current"], {
|
|
60
|
+
encoding: "utf8",
|
|
61
|
+
}).trim();
|
|
62
|
+
const repository = execFileSync(
|
|
63
|
+
"gh",
|
|
64
|
+
["repo", "view", "--json", "nameWithOwner", "--jq", ".nameWithOwner"],
|
|
65
|
+
{ encoding: "utf8" },
|
|
66
|
+
).trim();
|
|
67
|
+
if (
|
|
68
|
+
!/^[A-Za-z0-9._/-]+$/.test(targetBranch) ||
|
|
69
|
+
!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(repository)
|
|
70
|
+
) {
|
|
71
|
+
throw new Error("Invalid target branch or GitHub repository");
|
|
72
|
+
}
|
|
73
|
+
process.env.GH_REPO = repository;
|
|
74
|
+
const hooks = {
|
|
75
|
+
sandbox: {
|
|
76
|
+
onSandboxReady: [
|
|
77
|
+
{ command: "timeout 300 bash .shipyard/setup.sh", timeoutMs: 300_000 },
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
const closeClean = async (sandbox: {
|
|
82
|
+
close: () => Promise<{ preservedWorktreePath?: string }>;
|
|
83
|
+
}) => {
|
|
84
|
+
const { preservedWorktreePath } = await sandbox.close();
|
|
85
|
+
if (preservedWorktreePath)
|
|
86
|
+
throw new Error(`Sandbox has uncommitted work at ${preservedWorktreePath}`);
|
|
87
|
+
};
|
|
88
|
+
const verifyTriage = (ticketId: string) => {
|
|
89
|
+
try {
|
|
90
|
+
execFileSync("bash", [".shipyard/verify-triage.sh", ticketId, repository], {
|
|
91
|
+
encoding: "utf8",
|
|
92
|
+
});
|
|
93
|
+
} catch (error) {
|
|
94
|
+
const detail = (error as { stderr?: string | Buffer }).stderr
|
|
95
|
+
?.toString()
|
|
96
|
+
.trim();
|
|
97
|
+
throw new Error(detail || `Could not verify triage for #${ticketId}`);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
24
100
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
101
|
+
const blockScope = (
|
|
102
|
+
scope: { id: string; branch: string; tickets?: Array<{ id: string }> },
|
|
103
|
+
error: unknown,
|
|
104
|
+
) => {
|
|
105
|
+
const reason = (error instanceof Error ? error.message : String(error)).slice(
|
|
106
|
+
0,
|
|
107
|
+
3000,
|
|
108
|
+
);
|
|
109
|
+
execFileSync(
|
|
110
|
+
"bash",
|
|
111
|
+
[
|
|
112
|
+
".shipyard/block-scope.sh",
|
|
113
|
+
scope.id,
|
|
114
|
+
scope.id,
|
|
115
|
+
repository,
|
|
116
|
+
[scope.id, ...(scope.tickets ?? []).map((ticket) => ticket.id)].join(","),
|
|
117
|
+
scope.branch,
|
|
118
|
+
],
|
|
119
|
+
{ input: reason, encoding: "utf8" },
|
|
120
|
+
);
|
|
121
|
+
console.error(`Shipyard blocked issue #${scope.id}: ${reason}`);
|
|
122
|
+
};
|
|
29
123
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
124
|
+
for (let iteration = 0; iteration < 3; iteration++) {
|
|
125
|
+
const issues = JSON.parse(
|
|
126
|
+
execFileSync("node", [".shipyard/select-issues.mjs"], { encoding: "utf8" }),
|
|
127
|
+
) as Array<{
|
|
128
|
+
id: string;
|
|
129
|
+
title: string;
|
|
130
|
+
branch: string;
|
|
131
|
+
kind: "standalone" | "spec";
|
|
132
|
+
body?: string;
|
|
133
|
+
tickets?: Array<{
|
|
134
|
+
id: string;
|
|
135
|
+
title: string;
|
|
136
|
+
body: string;
|
|
137
|
+
state: string;
|
|
138
|
+
blockedBy: Array<{ id: string; title: string; state: string }>;
|
|
139
|
+
}>;
|
|
140
|
+
completedTicketIds?: string[];
|
|
141
|
+
outstandingTicketIds?: string[];
|
|
142
|
+
}>;
|
|
143
|
+
const issue = issues[0];
|
|
144
|
+
if (!issue) break;
|
|
35
145
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
146
|
+
let handedOff = false;
|
|
147
|
+
let publicationUncertain = false;
|
|
148
|
+
try {
|
|
149
|
+
execFileSync("gh", [
|
|
150
|
+
"label",
|
|
151
|
+
"create",
|
|
152
|
+
"shipyard:pending",
|
|
153
|
+
"--repo",
|
|
154
|
+
repository,
|
|
155
|
+
"--color",
|
|
156
|
+
"1D76DB",
|
|
157
|
+
"--description",
|
|
158
|
+
"Shipyard is working on this ticket",
|
|
159
|
+
"--force",
|
|
160
|
+
]);
|
|
161
|
+
for (const ticketId of issue.kind === "spec"
|
|
162
|
+
? (issue.tickets ?? []).map((ticket) => ticket.id)
|
|
163
|
+
: [issue.id])
|
|
164
|
+
execFileSync("gh", [
|
|
165
|
+
"issue",
|
|
166
|
+
"edit",
|
|
167
|
+
ticketId,
|
|
168
|
+
"--repo",
|
|
169
|
+
repository,
|
|
170
|
+
"--add-label",
|
|
171
|
+
"shipyard:pending",
|
|
172
|
+
]);
|
|
173
|
+
const sandbox = await shipyard.createSandbox({
|
|
174
|
+
branch: issue.branch,
|
|
175
|
+
sandbox: docker(),
|
|
176
|
+
hooks,
|
|
177
|
+
});
|
|
178
|
+
let evidence: string;
|
|
179
|
+
try {
|
|
180
|
+
for (const ticketId of issue.kind === "spec"
|
|
181
|
+
? (issue.tickets ?? []).map((ticket) => ticket.id)
|
|
182
|
+
: [issue.id]) {
|
|
183
|
+
await sandbox.run({
|
|
184
|
+
name: `triage #${ticketId}`,
|
|
185
|
+
agent: roleAgent("routine", shipyard.CODEX_MODELS.routine),
|
|
186
|
+
maxIterations: 1,
|
|
187
|
+
promptFile: "./.shipyard/triage-prompt.md",
|
|
188
|
+
promptArgs: { TASK_ID: ticketId },
|
|
189
|
+
});
|
|
190
|
+
verifyTriage(ticketId);
|
|
191
|
+
}
|
|
192
|
+
const result = await sandbox.run({
|
|
193
|
+
name: "implementer",
|
|
194
|
+
agent: roleAgent("routine", shipyard.CODEX_MODELS.routine),
|
|
195
|
+
maxIterations: 1,
|
|
196
|
+
promptFile: "./.shipyard/prompt.md",
|
|
197
|
+
promptArgs: {
|
|
198
|
+
TASK_ID: issue.id,
|
|
199
|
+
ISSUE_TITLE: issue.title,
|
|
200
|
+
BRANCH: issue.branch,
|
|
201
|
+
SCOPE: JSON.stringify(issue),
|
|
202
|
+
SKILL: issue.kind === "spec" ? "/implement-spec" : "/implement",
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
const packet = [
|
|
206
|
+
...result.stdout.matchAll(/<handoff>([\s\S]*?)<\/handoff>/g),
|
|
207
|
+
]
|
|
208
|
+
.at(-1)?.[1]
|
|
209
|
+
?.trim();
|
|
210
|
+
if (!result.completionSignal || !packet)
|
|
211
|
+
throw new Error(
|
|
212
|
+
`Issue #${issue.id} has no verified completion evidence: ${result.stdout.trim().slice(-1200)}`,
|
|
213
|
+
);
|
|
214
|
+
evidence = packet;
|
|
215
|
+
} finally {
|
|
216
|
+
await closeClean(sandbox);
|
|
217
|
+
}
|
|
41
218
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
})
|
|
219
|
+
// Sync-out rewrites sandbox commits on the host. Publish from the synced
|
|
220
|
+
// branch so a later invocation can fast-forward the same PR.
|
|
221
|
+
const publication = await shipyard.createSandbox({
|
|
222
|
+
branch: issue.branch,
|
|
223
|
+
sandbox: docker(),
|
|
224
|
+
});
|
|
225
|
+
try {
|
|
226
|
+
publicationUncertain = true;
|
|
227
|
+
const handoff = await publication.exec(
|
|
228
|
+
`bash .shipyard/handoff.sh ${issue.id} ${issue.branch} ${targetBranch} ${repository} ${[issue.id, ...(issue.tickets ?? []).map((ticket) => ticket.id)].join(",")} ${issue.outstandingTicketIds?.join(",") || "-"} ${issue.completedTicketIds?.join(",") || "-"}`,
|
|
229
|
+
{ stdin: evidence },
|
|
230
|
+
);
|
|
231
|
+
publicationUncertain = handoff.exitCode === 75;
|
|
232
|
+
if (handoff.exitCode !== 0)
|
|
233
|
+
throw new Error(
|
|
234
|
+
`PR handoff for #${issue.id} failed: ${handoff.stderr || handoff.stdout}`,
|
|
235
|
+
);
|
|
236
|
+
console.log(handoff.stdout.trim());
|
|
237
|
+
handedOff = true;
|
|
238
|
+
} finally {
|
|
239
|
+
await publication.close();
|
|
240
|
+
}
|
|
241
|
+
} catch (error) {
|
|
242
|
+
if (handedOff || publicationUncertain) throw error;
|
|
243
|
+
blockScope(issue, error);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
@@ -1,53 +1,19 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Assigned issue scope
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Implement scope #{{TASK_ID}} ({{ISSUE_TITLE}}) on branch `{{BRANCH}}`.
|
|
4
|
+
Read it with `gh issue view {{TASK_ID}} --comments`, including acceptance criteria, and read `AGENTS.md`, `CONTEXT.md`, `docs/agents/workflow.md`, and relevant ADRs. The selector resolved the selected tickets and their dependencies below.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
Follow {{SKILL}} for this scope. For a planning spec, deliver only tickets in `SCOPE.tickets` in dependency order on this one branch. Other linked tickets are context; do not implement them. Integrate, clean up, and review the selected work before handoff. Child workers may follow `/implement` under `/implement-spec` coordination. Do not create separate child PRs. Use `/tdd` for changed logic, then `/code-cleanup` and `/code-review` as the skill and repository policy require. Run candidate dependency installation again after changing manifests: `bash .shipyard/setup.sh`. Complete the required checks, resolve review findings, and commit all task work. Do not close the issue, merge into the target branch, or publish the PR; the surrounding workflow handles handoff.
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
If requirements, checks, or review are unresolved, describe the blocker and stop without the completion marker. Only after the verified commit, finish with a concise evidence packet containing changed scope, `Checks: <commands and results>`, `Review: APPROVED`, and limitations:
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
!`git log --oneline --grep="RALPH" -10`
|
|
12
|
-
|
|
13
|
-
# Task
|
|
14
|
-
|
|
15
|
-
You are RALPH — an autonomous coding agent working through issues one at a time.
|
|
16
|
-
|
|
17
|
-
## Priority order
|
|
18
|
-
|
|
19
|
-
Work on issues in this order:
|
|
20
|
-
|
|
21
|
-
1. **Bug fixes** — broken behaviour affecting users
|
|
22
|
-
2. **Tracer bullets** — thin end-to-end slices that prove an approach works
|
|
23
|
-
3. **Polish** — improving existing functionality (error messages, UX, docs)
|
|
24
|
-
4. **Refactors** — internal cleanups with no user-visible change
|
|
25
|
-
|
|
26
|
-
Pick the highest-priority open issue that is not blocked by another open issue.
|
|
27
|
-
|
|
28
|
-
## Workflow
|
|
29
|
-
|
|
30
|
-
1. **Explore** — read the issue carefully. Pull in the parent PRD if referenced. Read the relevant source files and tests before writing any code.
|
|
31
|
-
2. **Plan** — decide what to change and why. Keep the change as small as possible.
|
|
32
|
-
3. **Execute** — use RGR (Red → Green → Repeat → Refactor): write a failing test first, then write the implementation to pass it.
|
|
33
|
-
4. **Verify** — read the repository's configured feedback-loop contract and run every applicable check for this change. Use the configured static check and focused behavior tests when they exist; include formatting, build, or broader checks when the contract or change requires them. Fix failures before proceeding.
|
|
34
|
-
5. **Commit** — make a single git commit. The message MUST:
|
|
35
|
-
- Start with `RALPH:` prefix
|
|
36
|
-
- Include the task completed and any PRD reference
|
|
37
|
-
- List key decisions made
|
|
38
|
-
- List files changed
|
|
39
|
-
- Note any blockers for the next iteration
|
|
40
|
-
6. **Close** — close the issue with `{{CLOSE_TASK_COMMAND}}` explaining what was done.
|
|
41
|
-
|
|
42
|
-
## Rules
|
|
43
|
-
|
|
44
|
-
- Work on **one issue per iteration**. Do not attempt multiple issues in a single iteration.
|
|
45
|
-
- Do not close an issue until you have committed the fix and verified tests pass.
|
|
46
|
-
- Do not leave commented-out code or TODO comments in committed code.
|
|
47
|
-
- If you are blocked (missing context, failing tests you cannot fix, external dependency), leave a comment on the issue and move on — do not close it.
|
|
10
|
+
<handoff>...</handoff>
|
|
11
|
+
<promise>COMPLETE</promise>
|
|
48
12
|
|
|
49
|
-
|
|
13
|
+
## Resolved scope
|
|
50
14
|
|
|
51
|
-
|
|
15
|
+
```json
|
|
16
|
+
{{SCOPE}}
|
|
17
|
+
```
|
|
52
18
|
|
|
53
|
-
|
|
19
|
+
Read the complete parent and child issue bodies and comments with `gh issue view`, including repository guidance and dependency links.
|