ralphctl 0.2.1 → 0.2.3
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 +104 -86
- package/dist/{add-SEDQ3VK7.mjs → add-DWNLZQ7Q.mjs} +4 -4
- package/dist/{add-TGJTRHIF.mjs → add-K7LNOYQ4.mjs} +3 -3
- package/dist/{chunk-LG6B7QVO.mjs → chunk-7TBO6GOT.mjs} +1 -1
- package/dist/{chunk-ZDEVRTGY.mjs → chunk-GLDPHKEW.mjs} +9 -0
- package/dist/{chunk-KPTPKLXY.mjs → chunk-ITRZMBLJ.mjs} +1 -1
- package/dist/{chunk-Q3VWJARJ.mjs → chunk-LAERLCL5.mjs} +2 -2
- package/dist/{chunk-AXNZMHFQ.mjs → chunk-ORVGM6EV.mjs} +80 -18
- package/dist/{chunk-XPDI4SYI.mjs → chunk-QYF7QIZJ.mjs} +3 -3
- package/dist/{chunk-XQHEKKDN.mjs → chunk-V4ZUDZCG.mjs} +1 -1
- package/dist/cli.mjs +105 -16
- package/dist/{create-DJHCP7LN.mjs → create-5MILNF7E.mjs} +3 -3
- package/dist/{handle-CCTBNAJZ.mjs → handle-2BACSJLR.mjs} +1 -1
- package/dist/{project-ZYGNPVGL.mjs → project-XC7AXA4B.mjs} +2 -2
- package/dist/prompts/ideate-auto.md +15 -5
- package/dist/prompts/ideate.md +28 -12
- package/dist/prompts/plan-auto.md +27 -17
- package/dist/prompts/plan-common.md +67 -22
- package/dist/prompts/plan-interactive.md +26 -27
- package/dist/prompts/task-evaluation.md +149 -23
- package/dist/prompts/task-execution.md +60 -37
- package/dist/prompts/ticket-refine.md +25 -21
- package/dist/{resolver-L52KR4GY.mjs → resolver-CFY6DIOP.mjs} +2 -2
- package/dist/{sprint-LUXAV3Q3.mjs → sprint-F4VRAEWZ.mjs} +2 -2
- package/dist/{wizard-TFJXEYD2.mjs → wizard-RCQ4QQOL.mjs} +6 -6
- package/package.json +6 -6
- package/schemas/task-import.schema.json +7 -0
- package/schemas/tasks.schema.json +8 -0
|
@@ -6,14 +6,14 @@ import {
|
|
|
6
6
|
import {
|
|
7
7
|
listProjects,
|
|
8
8
|
projectExists
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-7TBO6GOT.mjs";
|
|
10
10
|
import {
|
|
11
11
|
assertSprintStatus,
|
|
12
12
|
generateUuid8,
|
|
13
13
|
getEditor,
|
|
14
14
|
resolveSprintId,
|
|
15
15
|
setEditor
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-ITRZMBLJ.mjs";
|
|
17
17
|
import {
|
|
18
18
|
ensureError,
|
|
19
19
|
unwrapOrThrow,
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
getSprintFilePath,
|
|
25
25
|
readValidatedJson,
|
|
26
26
|
writeValidatedJson
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-GLDPHKEW.mjs";
|
|
28
28
|
import {
|
|
29
29
|
IOError,
|
|
30
30
|
IssueFetchError,
|
package/dist/cli.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
addCheckScriptToRepository,
|
|
4
4
|
projectAddCommand
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-LAERLCL5.mjs";
|
|
6
6
|
import {
|
|
7
7
|
addTask,
|
|
8
8
|
areAllTasksDone,
|
|
@@ -52,13 +52,13 @@ import {
|
|
|
52
52
|
sprintStartCommand,
|
|
53
53
|
updateTaskStatus,
|
|
54
54
|
validateImportTasks
|
|
55
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-ORVGM6EV.mjs";
|
|
56
56
|
import {
|
|
57
57
|
escapableSelect
|
|
58
58
|
} from "./chunk-7LZ6GOGN.mjs";
|
|
59
59
|
import {
|
|
60
60
|
sprintCreateCommand
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-V4ZUDZCG.mjs";
|
|
62
62
|
import {
|
|
63
63
|
addTicket,
|
|
64
64
|
allRequirementsApproved,
|
|
@@ -73,7 +73,7 @@ import {
|
|
|
73
73
|
removeTicket,
|
|
74
74
|
ticketAddCommand,
|
|
75
75
|
updateTicket
|
|
76
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-QYF7QIZJ.mjs";
|
|
77
77
|
import {
|
|
78
78
|
EXIT_ERROR,
|
|
79
79
|
exitWithCode
|
|
@@ -84,7 +84,7 @@ import {
|
|
|
84
84
|
listProjects,
|
|
85
85
|
removeProject,
|
|
86
86
|
removeProjectRepo
|
|
87
|
-
} from "./chunk-
|
|
87
|
+
} from "./chunk-7TBO6GOT.mjs";
|
|
88
88
|
import {
|
|
89
89
|
DEFAULT_EVALUATION_ITERATIONS,
|
|
90
90
|
assertSprintStatus,
|
|
@@ -107,7 +107,7 @@ import {
|
|
|
107
107
|
setEditor,
|
|
108
108
|
setEvaluationIterations,
|
|
109
109
|
withFileLock
|
|
110
|
-
} from "./chunk-
|
|
110
|
+
} from "./chunk-ITRZMBLJ.mjs";
|
|
111
111
|
import {
|
|
112
112
|
ensureError,
|
|
113
113
|
wrapAsync
|
|
@@ -122,6 +122,7 @@ import {
|
|
|
122
122
|
TaskStatusSchema,
|
|
123
123
|
TasksSchema,
|
|
124
124
|
assertSafeCwd,
|
|
125
|
+
ensureDir,
|
|
125
126
|
expandTilde,
|
|
126
127
|
fileExists,
|
|
127
128
|
getDataDir,
|
|
@@ -133,7 +134,7 @@ import {
|
|
|
133
134
|
getTasksFilePath,
|
|
134
135
|
readValidatedJson,
|
|
135
136
|
validateProjectPath
|
|
136
|
-
} from "./chunk-
|
|
137
|
+
} from "./chunk-GLDPHKEW.mjs";
|
|
137
138
|
import {
|
|
138
139
|
DomainError,
|
|
139
140
|
NoCurrentSprintError,
|
|
@@ -3763,7 +3764,7 @@ async function interactiveMode() {
|
|
|
3763
3764
|
continue;
|
|
3764
3765
|
}
|
|
3765
3766
|
if (command === "wizard") {
|
|
3766
|
-
const { runWizard } = await import("./wizard-
|
|
3767
|
+
const { runWizard } = await import("./wizard-RCQ4QQOL.mjs");
|
|
3767
3768
|
await runWizard();
|
|
3768
3769
|
continue;
|
|
3769
3770
|
}
|
|
@@ -3898,6 +3899,87 @@ async function sprintSwitchCommand() {
|
|
|
3898
3899
|
log.newline();
|
|
3899
3900
|
}
|
|
3900
3901
|
|
|
3902
|
+
// src/commands/sprint/insights.ts
|
|
3903
|
+
import { writeFile as writeFile2 } from "fs/promises";
|
|
3904
|
+
import { join as join5 } from "path";
|
|
3905
|
+
async function sprintInsightsCommand(args) {
|
|
3906
|
+
const exportFlag = args.includes("--export");
|
|
3907
|
+
const positionalArgs = args.filter((a) => !a.startsWith("--"));
|
|
3908
|
+
const sprintId = positionalArgs[0];
|
|
3909
|
+
const sprintR = await wrapAsync(async () => {
|
|
3910
|
+
if (sprintId) return getSprint(sprintId);
|
|
3911
|
+
return getCurrentSprintOrThrow();
|
|
3912
|
+
}, ensureError);
|
|
3913
|
+
if (!sprintR.ok) {
|
|
3914
|
+
showError(sprintR.error.message);
|
|
3915
|
+
return;
|
|
3916
|
+
}
|
|
3917
|
+
const sprint = sprintR.value;
|
|
3918
|
+
const tasks = await getTasks(sprint.id);
|
|
3919
|
+
printHeader(`Sprint Insights: ${sprint.name}`, icons.sprint);
|
|
3920
|
+
const evaluatedTasks = tasks.filter((t) => t.evaluated);
|
|
3921
|
+
if (evaluatedTasks.length === 0) {
|
|
3922
|
+
log.info("No evaluation data found for this sprint.");
|
|
3923
|
+
return;
|
|
3924
|
+
}
|
|
3925
|
+
const totalTasks = tasks.length;
|
|
3926
|
+
const evaluatedCount = evaluatedTasks.length;
|
|
3927
|
+
const withOutput = evaluatedTasks.filter((t) => t.evaluationOutput && t.evaluationOutput.trim().length > 0);
|
|
3928
|
+
console.log(` Tasks evaluated: ${colors.accent(String(evaluatedCount))} / ${String(totalTasks)} total`);
|
|
3929
|
+
log.newline();
|
|
3930
|
+
if (withOutput.length > 0) {
|
|
3931
|
+
console.log(` ${colors.accent("Evaluation output:")}`);
|
|
3932
|
+
for (const task of withOutput) {
|
|
3933
|
+
const output = task.evaluationOutput ?? "";
|
|
3934
|
+
const truncated = output.length > 200 ? output.slice(0, 200) + "..." : output;
|
|
3935
|
+
console.log(` ${icons.bullet} ${colors.accent(task.name)}: ${colors.muted(truncated)}`);
|
|
3936
|
+
}
|
|
3937
|
+
log.newline();
|
|
3938
|
+
}
|
|
3939
|
+
console.log(` ${colors.accent("Harness recommendations:")}`);
|
|
3940
|
+
if (withOutput.length > 1) {
|
|
3941
|
+
console.log(
|
|
3942
|
+
` ${icons.bullet} Consider reviewing evaluation failure patterns and updating CLAUDE.md with lessons learned.`
|
|
3943
|
+
);
|
|
3944
|
+
}
|
|
3945
|
+
if (withOutput.length > 0) {
|
|
3946
|
+
console.log(
|
|
3947
|
+
` ${icons.bullet} Run: ${colors.muted("ralphctl sprint insights --export")} to save details to $RALPHCTL_ROOT/insights/<sprint-id>.md`
|
|
3948
|
+
);
|
|
3949
|
+
}
|
|
3950
|
+
log.newline();
|
|
3951
|
+
if (exportFlag) {
|
|
3952
|
+
await exportInsights(sprint, tasks);
|
|
3953
|
+
}
|
|
3954
|
+
}
|
|
3955
|
+
async function exportInsights(sprint, tasks) {
|
|
3956
|
+
const dir = join5(getDataDir(), "insights");
|
|
3957
|
+
await ensureDir(dir);
|
|
3958
|
+
const filePath = join5(dir, `${sprint.id}.md`);
|
|
3959
|
+
const evaluatedCount = tasks.filter((t) => t.evaluated).length;
|
|
3960
|
+
const lines = [
|
|
3961
|
+
`# Sprint Insights: ${sprint.name}`,
|
|
3962
|
+
"",
|
|
3963
|
+
`**Date:** ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
3964
|
+
`**Sprint ID:** ${sprint.id}`,
|
|
3965
|
+
`**Tasks evaluated:** ${String(evaluatedCount)} / ${String(tasks.length)} total`,
|
|
3966
|
+
"",
|
|
3967
|
+
"## Evaluation Details"
|
|
3968
|
+
];
|
|
3969
|
+
for (const task of tasks) {
|
|
3970
|
+
lines.push("");
|
|
3971
|
+
lines.push(`### ${task.name} (${task.id})`);
|
|
3972
|
+
lines.push(`**Status:** ${task.status}`);
|
|
3973
|
+
lines.push(`**Evaluated:** ${task.evaluated ? "yes" : "no"}`);
|
|
3974
|
+
lines.push("");
|
|
3975
|
+
lines.push(task.evaluationOutput ?? "No evaluation output");
|
|
3976
|
+
lines.push("");
|
|
3977
|
+
lines.push("---");
|
|
3978
|
+
}
|
|
3979
|
+
await writeFile2(filePath, lines.join("\n"), "utf-8");
|
|
3980
|
+
log.success(`Insights exported to ${colors.accent(filePath)}`);
|
|
3981
|
+
}
|
|
3982
|
+
|
|
3901
3983
|
// src/commands/sprint/index.ts
|
|
3902
3984
|
function registerSprintCommands(program2) {
|
|
3903
3985
|
const sprint = program2.command("sprint").description("Manage sprints");
|
|
@@ -3974,7 +4056,13 @@ Examples:
|
|
|
3974
4056
|
sprint.command("health").description("Check sprint health").action(async () => {
|
|
3975
4057
|
await sprintHealthCommand();
|
|
3976
4058
|
});
|
|
3977
|
-
sprint.command("
|
|
4059
|
+
sprint.command("insights [id]").description("Analyze evaluation results and suggest improvements").option("--export", "Export insights to $RALPHCTL_ROOT/insights/<sprint-id>.md").action(async (id, opts) => {
|
|
4060
|
+
const args = [];
|
|
4061
|
+
if (id) args.push(id);
|
|
4062
|
+
if (opts?.export) args.push("--export");
|
|
4063
|
+
await sprintInsightsCommand(args);
|
|
4064
|
+
});
|
|
4065
|
+
sprint.command("start [id]").description("Run automated implementation loop").option("-s, --session", "Interactive AI session (collaborate with your AI provider)").option("-t, --step", "Step through tasks with approval between each").option("-c, --count <n>", "Limit to N tasks").option("--no-commit", "Skip automatic git commit after each task completes").option("--concurrency <n>", "Max parallel tasks (default: auto based on unique repos)").option("--max-retries <n>", "Max rate-limit retries per task (default: 5)").option("--fail-fast", "Stop launching new tasks on first failure").option("-f, --force", "Skip precondition checks (e.g., unplanned tickets)").option("--refresh-check", "Force re-run check scripts even if they already ran this sprint").option("-b, --branch", "Create sprint branch (ralphctl/<sprint-id>) in all repos").option("--branch-name <name>", "Use a custom branch name for sprint execution").option("--max-budget-usd <amount>", "Max USD budget per AI task (Claude only)").option("--fallback-model <model>", "Fallback model when primary is overloaded (Claude only)").option("--max-turns <number>", "Max agentic turns per task (Claude only, default: 200)").addHelpText(
|
|
3978
4066
|
"after",
|
|
3979
4067
|
`
|
|
3980
4068
|
Exit Codes:
|
|
@@ -4012,6 +4100,7 @@ Branch Management:
|
|
|
4012
4100
|
if (opts?.branchName) args.push("--branch-name", opts.branchName);
|
|
4013
4101
|
if (opts?.maxBudgetUsd) args.push("--max-budget-usd", opts.maxBudgetUsd);
|
|
4014
4102
|
if (opts?.fallbackModel) args.push("--fallback-model", opts.fallbackModel);
|
|
4103
|
+
if (opts?.maxTurns) args.push("--max-turns", opts.maxTurns);
|
|
4015
4104
|
await sprintStartCommand(args);
|
|
4016
4105
|
}
|
|
4017
4106
|
);
|
|
@@ -4234,7 +4323,7 @@ Checks performed:
|
|
|
4234
4323
|
// package.json
|
|
4235
4324
|
var package_default = {
|
|
4236
4325
|
name: "ralphctl",
|
|
4237
|
-
version: "0.2.
|
|
4326
|
+
version: "0.2.3",
|
|
4238
4327
|
description: "Agent harness for long-running AI coding tasks \u2014 orchestrates Claude Code & GitHub Copilot across repositories",
|
|
4239
4328
|
homepage: "https://github.com/lukas-grigis/ralphctl",
|
|
4240
4329
|
type: "module",
|
|
@@ -4299,10 +4388,10 @@ var package_default = {
|
|
|
4299
4388
|
},
|
|
4300
4389
|
devDependencies: {
|
|
4301
4390
|
"@eslint/js": "^10.0.1",
|
|
4302
|
-
"@types/node": "^25.5.
|
|
4391
|
+
"@types/node": "^25.5.2",
|
|
4303
4392
|
"@types/tabtab": "^3.0.4",
|
|
4304
|
-
"@vitest/coverage-v8": "^4.1.
|
|
4305
|
-
eslint: "^10.
|
|
4393
|
+
"@vitest/coverage-v8": "^4.1.2",
|
|
4394
|
+
eslint: "^10.2.0",
|
|
4306
4395
|
"eslint-config-prettier": "^10.1.8",
|
|
4307
4396
|
globals: "^17.4.0",
|
|
4308
4397
|
husky: "^9.1.7",
|
|
@@ -4311,8 +4400,8 @@ var package_default = {
|
|
|
4311
4400
|
tsup: "^8.5.1",
|
|
4312
4401
|
tsx: "^4.21.0",
|
|
4313
4402
|
typescript: "^5.9.3",
|
|
4314
|
-
"typescript-eslint": "^8.
|
|
4315
|
-
vitest: "^4.1.
|
|
4403
|
+
"typescript-eslint": "^8.58.0",
|
|
4404
|
+
vitest: "^4.1.2"
|
|
4316
4405
|
},
|
|
4317
4406
|
"lint-staged": {
|
|
4318
4407
|
"*.ts": [
|
|
@@ -4356,7 +4445,7 @@ registerCompletionCommands(program);
|
|
|
4356
4445
|
registerDoctorCommands(program);
|
|
4357
4446
|
async function main() {
|
|
4358
4447
|
if (process.env["COMP_CWORD"] && process.env["COMP_POINT"] && process.env["COMP_LINE"]) {
|
|
4359
|
-
const { handleCompletionRequest } = await import("./handle-
|
|
4448
|
+
const { handleCompletionRequest } = await import("./handle-2BACSJLR.mjs");
|
|
4360
4449
|
if (await handleCompletionRequest(program)) return;
|
|
4361
4450
|
}
|
|
4362
4451
|
if (process.argv.length <= 2 || process.argv[2] === "interactive") {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
sprintCreateCommand
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-V4ZUDZCG.mjs";
|
|
5
|
+
import "./chunk-ITRZMBLJ.mjs";
|
|
6
6
|
import "./chunk-OEUJDSHY.mjs";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-GLDPHKEW.mjs";
|
|
8
8
|
import "./chunk-EDJX7TT6.mjs";
|
|
9
9
|
import "./chunk-QBXHAXHI.mjs";
|
|
10
10
|
export {
|
|
@@ -7,7 +7,7 @@ async function handleCompletionRequest(program) {
|
|
|
7
7
|
return false;
|
|
8
8
|
}
|
|
9
9
|
const tabtab = (await import("tabtab")).default;
|
|
10
|
-
const { resolveCompletions } = await import("./resolver-
|
|
10
|
+
const { resolveCompletions } = await import("./resolver-CFY6DIOP.mjs");
|
|
11
11
|
const tabEnv = tabtab.parseEnv(env);
|
|
12
12
|
const completions = await resolveCompletions(program, {
|
|
13
13
|
line: tabEnv.line,
|
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
removeProject,
|
|
10
10
|
removeProjectRepo,
|
|
11
11
|
updateProject
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
12
|
+
} from "./chunk-7TBO6GOT.mjs";
|
|
13
|
+
import "./chunk-GLDPHKEW.mjs";
|
|
14
14
|
import {
|
|
15
15
|
ProjectExistsError,
|
|
16
16
|
ProjectNotFoundError
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Autonomous Ideation to Implementation
|
|
2
2
|
|
|
3
|
-
You are a combined requirements analyst and task planner working autonomously.
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
You are a combined requirements analyst and task planner working autonomously. Turn a rough idea into refined
|
|
4
|
+
requirements and a dependency-ordered set of implementation tasks. Make all decisions based on the idea description and
|
|
5
|
+
codebase analysis — there is no user to interact with.
|
|
6
6
|
|
|
7
7
|
## Two-Phase Protocol
|
|
8
8
|
|
|
@@ -58,6 +58,12 @@ Explore the selected repositories and produce implementation tasks:
|
|
|
58
58
|
3. **Create tasks** — Following the Planning Common Context guidelines below
|
|
59
59
|
4. **Validate** — Ensure tasks are non-overlapping, properly ordered, and completable
|
|
60
60
|
|
|
61
|
+
### Blocker Handling
|
|
62
|
+
|
|
63
|
+
If you cannot produce a valid plan, signal the issue instead of outputting incomplete JSON:
|
|
64
|
+
|
|
65
|
+
- `<planning-blocked>reason</planning-blocked>`
|
|
66
|
+
|
|
61
67
|
## Idea to Implement
|
|
62
68
|
|
|
63
69
|
**Title:** {{IDEA_TITLE}}
|
|
@@ -90,8 +96,6 @@ Before outputting JSON, verify:
|
|
|
90
96
|
6. **Verification steps** — Every task ends with project-appropriate verification commands
|
|
91
97
|
7. **projectPath assigned** — Every task uses a path from the Selected Repositories
|
|
92
98
|
|
|
93
|
-
If you cannot produce a valid plan, signal: `<planning-blocked>reason</planning-blocked>`
|
|
94
|
-
|
|
95
99
|
## Output Format
|
|
96
100
|
|
|
97
101
|
Output a single JSON object with both requirements and tasks.
|
|
@@ -133,6 +137,12 @@ If you cannot produce a valid plan, output `<planning-blocked>reason</planning-b
|
|
|
133
137
|
"Add integration test in src/controllers/__tests__/export.test.ts for filtered and unfiltered queries",
|
|
134
138
|
"Run pnpm typecheck && pnpm lint && pnpm test — all pass"
|
|
135
139
|
],
|
|
140
|
+
"verificationCriteria": [
|
|
141
|
+
"TypeScript compiles with no errors",
|
|
142
|
+
"All existing tests pass plus new tests for date range filtering",
|
|
143
|
+
"GET /exports?startDate=invalid returns 400 with validation error",
|
|
144
|
+
"Filtered query returns only records within the specified date range"
|
|
145
|
+
],
|
|
136
146
|
"blockedBy": []
|
|
137
147
|
}
|
|
138
148
|
]
|
package/dist/prompts/ideate.md
CHANGED
|
@@ -9,12 +9,13 @@ requirements and a dependency-ordered set of implementation tasks in a single se
|
|
|
9
9
|
|
|
10
10
|
Focus: Clarify WHAT needs to be built (implementation-agnostic)
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
<constraints>
|
|
13
13
|
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
|
|
14
|
+
- Focus exclusively on requirements, acceptance criteria, and scope — codebase exploration happens in Phase 2
|
|
15
|
+
- Frame requirements as observable behavior, not implementation details — this keeps Phase 2 flexible
|
|
16
|
+
- Repositories are already selected; repository selection is not part of this phase
|
|
17
|
+
|
|
18
|
+
</constraints>
|
|
18
19
|
|
|
19
20
|
**Steps:**
|
|
20
21
|
|
|
@@ -77,6 +78,14 @@ Focus: Determine HOW to implement the approved requirements
|
|
|
77
78
|
|
|
78
79
|
**After requirements are approved, proceed to implementation planning.**
|
|
79
80
|
|
|
81
|
+
<constraints>
|
|
82
|
+
|
|
83
|
+
- This is a planning session — your only output is a JSON task plan written to the output file. Use tools for reading
|
|
84
|
+
and analysis only (search, read, explore). Creating files, writing code, or making commits would conflict with the
|
|
85
|
+
task execution phase that follows.
|
|
86
|
+
|
|
87
|
+
</constraints>
|
|
88
|
+
|
|
80
89
|
**Steps:**
|
|
81
90
|
|
|
82
91
|
1. **Explore the codebase** — Read the repository instruction files (`CLAUDE.md`, `.github/copilot-instructions.md`,
|
|
@@ -84,17 +93,15 @@ Focus: Determine HOW to implement the approved requirements
|
|
|
84
93
|
2. **Review approved requirements** — Understand WHAT was approved in Phase 1
|
|
85
94
|
3. **Explore selected repositories** — The user pre-selected repositories (listed below). Deep-dive to understand
|
|
86
95
|
patterns, conventions, and existing code
|
|
87
|
-
4. **Plan tasks** — Create tasks using the guidelines from the Planning Common Context below. Use tools
|
|
88
|
-
|
|
89
|
-
- **Grep/glob** — Find specific patterns, existing implementations
|
|
90
|
-
- **File reading** — Understand implementation details
|
|
96
|
+
4. **Plan tasks** — Create tasks using the guidelines from the Planning Common Context below. Use available tools to
|
|
97
|
+
search, explore, and read the codebase.
|
|
91
98
|
5. **Ask implementation questions** — Use AskUserQuestion for decisions (library choice, approach, architecture
|
|
92
99
|
patterns)
|
|
93
100
|
6. **Present task breakdown** — SHOW BEFORE WRITE. Present tasks in readable markdown:
|
|
94
101
|
- List each task with repository, blocked by, and steps
|
|
95
102
|
- Show dependency graph
|
|
96
103
|
- Ask: "Does this task breakdown look correct? Any changes needed?"
|
|
97
|
-
7. **Wait for confirmation** —
|
|
104
|
+
7. **Wait for confirmation** — write the JSON to the output file after the user confirms
|
|
98
105
|
|
|
99
106
|
## Idea to Refine and Plan
|
|
100
107
|
|
|
@@ -112,7 +119,8 @@ The user pre-selected these repositories for exploration:
|
|
|
112
119
|
|
|
113
120
|
{{REPOSITORIES}}
|
|
114
121
|
|
|
115
|
-
|
|
122
|
+
These paths are fixed — repository selection is a separate workflow step. If a critical repository seems missing,
|
|
123
|
+
mention it as an observation.
|
|
116
124
|
|
|
117
125
|
## Planning Common Context
|
|
118
126
|
|
|
@@ -120,7 +128,9 @@ The user pre-selected these repositories for exploration:
|
|
|
120
128
|
|
|
121
129
|
## Output Format
|
|
122
130
|
|
|
123
|
-
When BOTH phases are approved by the user, write to: {{OUTPUT_FILE}}
|
|
131
|
+
When BOTH phases are approved by the user, write the JSON to: {{OUTPUT_FILE}}
|
|
132
|
+
|
|
133
|
+
Write only this single output file — no code, no implementation. The harness feeds this plan to task executors.
|
|
124
134
|
|
|
125
135
|
Use this exact JSON Schema:
|
|
126
136
|
|
|
@@ -146,6 +156,12 @@ Use this exact JSON Schema:
|
|
|
146
156
|
"Write tests in src/controllers/__tests__/export.test.ts for: no dates, valid range, invalid range, start > end",
|
|
147
157
|
"Run pnpm typecheck && pnpm lint && pnpm test — all pass"
|
|
148
158
|
],
|
|
159
|
+
"verificationCriteria": [
|
|
160
|
+
"TypeScript compiles with no errors",
|
|
161
|
+
"All existing tests pass plus new tests for date range filtering",
|
|
162
|
+
"GET /api/export?startDate=invalid returns 400 with validation error",
|
|
163
|
+
"GET /api/export?startDate=2024-01-01&endDate=2024-12-31 returns only matching records"
|
|
164
|
+
],
|
|
149
165
|
"blockedBy": []
|
|
150
166
|
}
|
|
151
167
|
]
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
# Headless Task Planning Protocol
|
|
2
2
|
|
|
3
|
-
You are a task planning specialist. Your goal is to produce a dependency-ordered set of implementation tasks — each one
|
|
4
|
-
a
|
|
5
|
-
self-contained mini-spec that can be picked up cold and completed in a single AI session. Make all decisions
|
|
3
|
+
You are a task planning specialist. Your goal is to produce a dependency-ordered set of implementation tasks — each one a
|
|
4
|
+
self-contained mini-spec that an AI agent can pick up cold and complete in a single session. Make all decisions
|
|
6
5
|
autonomously based on codebase analysis — there is no user to interact with.
|
|
7
6
|
|
|
8
7
|
## Protocol
|
|
@@ -11,20 +10,18 @@ autonomously based on codebase analysis — there is no user to interact with.
|
|
|
11
10
|
|
|
12
11
|
Explore efficiently — read what matters, skip what does not:
|
|
13
12
|
|
|
14
|
-
1. **Read project instructions first** —
|
|
15
|
-
such
|
|
16
|
-
as `.github/copilot-instructions.md` when present. Follow any links to other documentation. Check `.claude/`
|
|
13
|
+
1. **Read project instructions first** — start with `CLAUDE.md` if it exists, and also check provider-specific files
|
|
14
|
+
such as `.github/copilot-instructions.md` when present. Follow any links to other documentation. Check `.claude/`
|
|
17
15
|
directory for agents, rules, and memory (see "Project Resources" section below).
|
|
18
16
|
2. **Read manifest files** — package.json, pyproject.toml, Cargo.toml, go.mod, pom.xml, etc. for dependencies and
|
|
19
17
|
scripts
|
|
20
|
-
3. **Read README** —
|
|
21
|
-
4. **Scan directory structure** —
|
|
22
|
-
5. **Find similar implementations** —
|
|
23
|
-
|
|
24
|
-
6. **Extract verification commands** — Find the exact build, test, lint, and typecheck commands
|
|
18
|
+
3. **Read README** — project overview, setup, and architecture
|
|
19
|
+
4. **Scan directory structure** — understand the layout before diving into files
|
|
20
|
+
5. **Find similar implementations** — look for existing features similar to what tickets require; follow their patterns
|
|
21
|
+
6. **Extract verification commands** — find the exact build, test, lint, and typecheck commands
|
|
25
22
|
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
Read project instruction files and README first, then only the specific files needed to understand patterns and plan
|
|
24
|
+
tasks — broad exploration wastes context budget without improving task quality.
|
|
28
25
|
|
|
29
26
|
### Step 2: Review Ticket Requirements
|
|
30
27
|
|
|
@@ -78,13 +75,14 @@ Before outputting JSON, verify EVERY item on this checklist:
|
|
|
78
75
|
6. **Verification steps** — Every task ends with project-appropriate verification commands from the repository
|
|
79
76
|
instructions
|
|
80
77
|
7. **projectPath assigned** — Every task has a `projectPath` from the project's repository paths
|
|
81
|
-
8. **
|
|
82
|
-
9. **Valid JSON** — The output parses as
|
|
78
|
+
8. **Verification criteria** — Every task has 2-4 verificationCriteria that are testable and unambiguous
|
|
79
|
+
9. **Valid JSON** — The output parses as valid JSON matching the schema
|
|
83
80
|
|
|
84
81
|
## Output
|
|
85
82
|
|
|
86
|
-
|
|
87
|
-
If you cannot produce tasks, output a
|
|
83
|
+
Output only valid JSON matching the schema below — no markdown, no explanation, no commentary. The harness parses
|
|
84
|
+
your raw output as JSON, so any surrounding text will cause a parse failure. If you cannot produce tasks, output a
|
|
85
|
+
`<planning-blocked>` signal instead.
|
|
88
86
|
|
|
89
87
|
JSON Schema:
|
|
90
88
|
|
|
@@ -113,6 +111,12 @@ JSON Schema:
|
|
|
113
111
|
"Add corresponding unit tests in src/utils/__tests__/validation.test.ts covering valid inputs, invalid inputs, and edge cases (empty strings, unicode)",
|
|
114
112
|
"Run pnpm typecheck && pnpm lint && pnpm test — all pass"
|
|
115
113
|
],
|
|
114
|
+
"verificationCriteria": [
|
|
115
|
+
"TypeScript compiles with no errors",
|
|
116
|
+
"All existing tests pass plus new validation utility tests",
|
|
117
|
+
"validateEmail rejects invalid formats and accepts valid ones",
|
|
118
|
+
"validateDateRange rejects reversed date ranges"
|
|
119
|
+
],
|
|
116
120
|
"blockedBy": []
|
|
117
121
|
},
|
|
118
122
|
{
|
|
@@ -128,6 +132,12 @@ JSON Schema:
|
|
|
128
132
|
"Write component tests in src/components/__tests__/RegistrationForm.test.ts for valid submission, validation errors, and API failure",
|
|
129
133
|
"Run pnpm typecheck && pnpm lint && pnpm test — all pass"
|
|
130
134
|
],
|
|
135
|
+
"verificationCriteria": [
|
|
136
|
+
"TypeScript compiles with no errors",
|
|
137
|
+
"All existing tests pass plus new component tests",
|
|
138
|
+
"Form displays inline error messages for invalid email and phone",
|
|
139
|
+
"Successful submission calls POST /api/users with form data"
|
|
140
|
+
],
|
|
131
141
|
"blockedBy": ["1"]
|
|
132
142
|
}
|
|
133
143
|
]
|