prloom 0.1.1 → 0.1.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/dist/cli/index.js +174 -39
- package/package.json +1 -1
- package/prompts/designer_new.md +47 -22
package/dist/cli/index.js
CHANGED
|
@@ -7238,14 +7238,46 @@ var init_execa = __esm(() => {
|
|
|
7238
7238
|
} = getIpcExport());
|
|
7239
7239
|
});
|
|
7240
7240
|
|
|
7241
|
+
// src/lib/adapters/tmux.ts
|
|
7242
|
+
async function waitForTmuxSession(sessionName) {
|
|
7243
|
+
while (true) {
|
|
7244
|
+
const { exitCode } = await execa("tmux", ["has-session", "-t", sessionName], {
|
|
7245
|
+
reject: false
|
|
7246
|
+
});
|
|
7247
|
+
if (exitCode !== 0) {
|
|
7248
|
+
return;
|
|
7249
|
+
}
|
|
7250
|
+
await new Promise((resolve5) => setTimeout(resolve5, 1000));
|
|
7251
|
+
}
|
|
7252
|
+
}
|
|
7253
|
+
var init_tmux = __esm(() => {
|
|
7254
|
+
init_execa();
|
|
7255
|
+
});
|
|
7256
|
+
|
|
7241
7257
|
// src/lib/adapters/codex.ts
|
|
7242
7258
|
var codexAdapter;
|
|
7243
7259
|
var init_codex = __esm(() => {
|
|
7244
7260
|
init_execa();
|
|
7261
|
+
init_tmux();
|
|
7245
7262
|
codexAdapter = {
|
|
7246
7263
|
name: "codex",
|
|
7247
|
-
async execute({ cwd, prompt }) {
|
|
7248
|
-
const
|
|
7264
|
+
async execute({ cwd, prompt, tmux }) {
|
|
7265
|
+
const args = ["exec", prompt, "--full-auto"];
|
|
7266
|
+
if (tmux) {
|
|
7267
|
+
await execa("tmux", [
|
|
7268
|
+
"new-session",
|
|
7269
|
+
"-d",
|
|
7270
|
+
"-s",
|
|
7271
|
+
tmux.sessionName,
|
|
7272
|
+
"-c",
|
|
7273
|
+
cwd,
|
|
7274
|
+
"codex",
|
|
7275
|
+
...args
|
|
7276
|
+
], { reject: false });
|
|
7277
|
+
await waitForTmuxSession(tmux.sessionName);
|
|
7278
|
+
return { exitCode: 0 };
|
|
7279
|
+
}
|
|
7280
|
+
const result = await execa("codex", args, {
|
|
7249
7281
|
cwd,
|
|
7250
7282
|
timeout: 0,
|
|
7251
7283
|
reject: false
|
|
@@ -7266,9 +7298,25 @@ var init_codex = __esm(() => {
|
|
|
7266
7298
|
var opencodeAdapter;
|
|
7267
7299
|
var init_opencode = __esm(() => {
|
|
7268
7300
|
init_execa();
|
|
7301
|
+
init_tmux();
|
|
7269
7302
|
opencodeAdapter = {
|
|
7270
7303
|
name: "opencode",
|
|
7271
|
-
async execute({ cwd, prompt }) {
|
|
7304
|
+
async execute({ cwd, prompt, tmux }) {
|
|
7305
|
+
if (tmux) {
|
|
7306
|
+
await execa("tmux", [
|
|
7307
|
+
"new-session",
|
|
7308
|
+
"-d",
|
|
7309
|
+
"-s",
|
|
7310
|
+
tmux.sessionName,
|
|
7311
|
+
"-c",
|
|
7312
|
+
cwd,
|
|
7313
|
+
"opencode",
|
|
7314
|
+
"run",
|
|
7315
|
+
prompt
|
|
7316
|
+
], { reject: false });
|
|
7317
|
+
await waitForTmuxSession(tmux.sessionName);
|
|
7318
|
+
return { exitCode: 0 };
|
|
7319
|
+
}
|
|
7272
7320
|
const result = await execa("opencode", ["run", prompt], {
|
|
7273
7321
|
cwd,
|
|
7274
7322
|
timeout: 0,
|
|
@@ -7290,10 +7338,26 @@ var init_opencode = __esm(() => {
|
|
|
7290
7338
|
var claudeAdapter;
|
|
7291
7339
|
var init_claude = __esm(() => {
|
|
7292
7340
|
init_execa();
|
|
7341
|
+
init_tmux();
|
|
7293
7342
|
claudeAdapter = {
|
|
7294
7343
|
name: "claude",
|
|
7295
|
-
async execute({ cwd, prompt }) {
|
|
7296
|
-
const
|
|
7344
|
+
async execute({ cwd, prompt, tmux }) {
|
|
7345
|
+
const args = ["-p", prompt, "--dangerously-skip-permissions"];
|
|
7346
|
+
if (tmux) {
|
|
7347
|
+
await execa("tmux", [
|
|
7348
|
+
"new-session",
|
|
7349
|
+
"-d",
|
|
7350
|
+
"-s",
|
|
7351
|
+
tmux.sessionName,
|
|
7352
|
+
"-c",
|
|
7353
|
+
cwd,
|
|
7354
|
+
"claude",
|
|
7355
|
+
...args
|
|
7356
|
+
], { reject: false });
|
|
7357
|
+
await waitForTmuxSession(tmux.sessionName);
|
|
7358
|
+
return { exitCode: 0 };
|
|
7359
|
+
}
|
|
7360
|
+
const result = await execa("claude", args, {
|
|
7297
7361
|
cwd,
|
|
7298
7362
|
timeout: 0,
|
|
7299
7363
|
reject: false
|
|
@@ -7314,7 +7378,7 @@ var manualAdapter;
|
|
|
7314
7378
|
var init_manual = __esm(() => {
|
|
7315
7379
|
manualAdapter = {
|
|
7316
7380
|
name: "manual",
|
|
7317
|
-
async execute({ cwd, prompt }) {
|
|
7381
|
+
async execute({ cwd, prompt, tmux }) {
|
|
7318
7382
|
console.log("⚠️ Manual agent: execute() called but should be skipped by dispatcher.");
|
|
7319
7383
|
console.log(" This plan is intended for IDE-driven execution.");
|
|
7320
7384
|
return { exitCode: 0 };
|
|
@@ -16690,23 +16754,32 @@ var init_prompt_sources = __esm(() => {
|
|
|
16690
16754
|
BUILTIN_PROMPTS = {
|
|
16691
16755
|
designer_new: `# Designer: Create a New Plan
|
|
16692
16756
|
|
|
16693
|
-
You are helping a software engineer **plan** a coding task
|
|
16757
|
+
You are helping a software engineer **plan** a coding task.
|
|
16694
16758
|
|
|
16695
16759
|
> [!CAUTION] > **You are PLANNING, not building.**
|
|
16696
16760
|
>
|
|
16697
16761
|
> - Do NOT modify any code files
|
|
16698
16762
|
> - The ONLY file you may edit is: \`{{plan_path}}\`
|
|
16699
16763
|
|
|
16700
|
-
##
|
|
16764
|
+
## Repository Context
|
|
16701
16765
|
|
|
16702
|
-
You are working
|
|
16766
|
+
You are working in:
|
|
16703
16767
|
|
|
16704
|
-
- **
|
|
16705
|
-
- **
|
|
16706
|
-
- **
|
|
16707
|
-
- Only fill in details if the user explicitly says "fill in the details" or similar
|
|
16768
|
+
- **Repo**: \`{{repo_path}}\`
|
|
16769
|
+
- **Base branch**: \`{{base_branch}}\`
|
|
16770
|
+
- **Worker agent**: \`{{worker_agent}}\`
|
|
16708
16771
|
|
|
16709
|
-
|
|
16772
|
+
Explore the codebase freely to understand context. Do NOT ask questions you can answer by exploring (e.g., test commands, file locations, package.json contents).
|
|
16773
|
+
|
|
16774
|
+
## Your Philosophy
|
|
16775
|
+
|
|
16776
|
+
You are working with a technical user who knows what they want. Your job is to **extract requirements** and **discuss implementation**, not to make decisions for them.
|
|
16777
|
+
|
|
16778
|
+
- **Explore the codebase** to understand context before asking questions
|
|
16779
|
+
- **Ask clarifying questions** about user preferences and acceptance criteria
|
|
16780
|
+
- **Discuss implementation approach** — do not jump straight to writing the plan
|
|
16781
|
+
- **Defer to the user's judgment** on design decisions
|
|
16782
|
+
- Only fill in the plan when the user confirms they're ready
|
|
16710
16783
|
|
|
16711
16784
|
{{#if user_description}}
|
|
16712
16785
|
|
|
@@ -16714,35 +16787,51 @@ The user will give you information bit by bit. Your responsibility is to synthes
|
|
|
16714
16787
|
|
|
16715
16788
|
> {{user_description}}
|
|
16716
16789
|
|
|
16717
|
-
|
|
16790
|
+
Explore relevant files, then discuss the implementation approach with the user before writing the plan.
|
|
16718
16791
|
{{else}}
|
|
16719
16792
|
|
|
16720
16793
|
## Your First Step
|
|
16721
16794
|
|
|
16722
16795
|
Ask the user: **What would you like to build?**
|
|
16723
16796
|
|
|
16724
|
-
Then
|
|
16797
|
+
Then:
|
|
16725
16798
|
|
|
16726
|
-
|
|
16727
|
-
|
|
16728
|
-
|
|
16729
|
-
|
|
16730
|
-
|
|
16799
|
+
1. Explore the codebase to understand the relevant areas
|
|
16800
|
+
2. Discuss how to implement it (files to change, approach, trade-offs)
|
|
16801
|
+
3. Confirm acceptance criteria
|
|
16802
|
+
4. When the user is ready, write the plan
|
|
16803
|
+
{{/if}}
|
|
16731
16804
|
|
|
16732
16805
|
## Plan Structure
|
|
16733
16806
|
|
|
16734
|
-
|
|
16807
|
+
The plan file already has a template with these sections. Fill them in:
|
|
16735
16808
|
|
|
16736
16809
|
- **Objective**: What will be built (1-2 sentences)
|
|
16737
|
-
- **Context**: Files to modify,
|
|
16738
|
-
- **TODO**:
|
|
16810
|
+
- **Context**: Files to modify, constraints, any notes the Worker needs
|
|
16811
|
+
- **TODO (Commits)**: Each item is ONE commit the Worker will make
|
|
16739
16812
|
|
|
16740
|
-
|
|
16813
|
+
### TODO Rules
|
|
16814
|
+
|
|
16815
|
+
Each TODO item represents a **single commit**. Think of them as the git log you want to see:
|
|
16816
|
+
|
|
16817
|
+
✅ Good TODOs (commits):
|
|
16818
|
+
|
|
16819
|
+
- \`Fix PDF viewer to load beyond 10 pages\`
|
|
16820
|
+
- \`Add horizontal resize handle to Learn panel\`
|
|
16821
|
+
- \`Update LearnStore to trigger page prefetch\`
|
|
16822
|
+
|
|
16823
|
+
❌ Bad TODOs (not commits):
|
|
16824
|
+
|
|
16825
|
+
- \`Run npm test\` — this is verification, not a commit
|
|
16826
|
+
- \`Trace the code to understand X\` — this is research, not a commit
|
|
16827
|
+
- \`Validate acceptance criteria\` — this is testing, not a commit
|
|
16828
|
+
|
|
16829
|
+
The Worker will run tests and type-checks before each commit automatically.
|
|
16741
16830
|
|
|
16742
|
-
##
|
|
16831
|
+
## Important
|
|
16743
16832
|
|
|
16744
|
-
-
|
|
16745
|
-
-
|
|
16833
|
+
- The plan template already has a \`## Progress Log\` section — do NOT duplicate it
|
|
16834
|
+
- Leave the frontmatter (\`id\`, \`status\`, \`agent\`, \`base_branch\`) alone
|
|
16746
16835
|
`,
|
|
16747
16836
|
designer_edit: `# Designer: Edit an Existing Plan
|
|
16748
16837
|
|
|
@@ -16886,10 +16975,11 @@ function renderWorkerPrompt(repoRoot, plan, todo) {
|
|
|
16886
16975
|
plan: plan.raw
|
|
16887
16976
|
});
|
|
16888
16977
|
}
|
|
16889
|
-
function renderDesignerNewPrompt(planPath, baseBranch, workerAgent, userDescription) {
|
|
16978
|
+
function renderDesignerNewPrompt(repoPath, planPath, baseBranch, workerAgent, userDescription) {
|
|
16890
16979
|
const template = BUILTIN_PROMPTS["designer_new"];
|
|
16891
16980
|
const compiled = import_handlebars.default.compile(template);
|
|
16892
16981
|
return compiled({
|
|
16982
|
+
repo_path: repoPath,
|
|
16893
16983
|
plan_path: planPath,
|
|
16894
16984
|
base_branch: baseBranch,
|
|
16895
16985
|
worker_agent: workerAgent,
|
|
@@ -17266,7 +17356,7 @@ async function runNew(repoRoot, planId, agentOverride, noDesigner) {
|
|
|
17266
17356
|
console.log(`Designer agent: ${designerAgent}`);
|
|
17267
17357
|
console.log("");
|
|
17268
17358
|
console.log("Starting Designer session to fill in the plan...");
|
|
17269
|
-
const prompt = renderDesignerNewPrompt(planPath, baseBranch, workerAgent);
|
|
17359
|
+
const prompt = renderDesignerNewPrompt(repoRoot, planPath, baseBranch, workerAgent);
|
|
17270
17360
|
await adapter.interactive({ cwd: repoRoot, prompt });
|
|
17271
17361
|
console.log("Designer session ended.");
|
|
17272
17362
|
console.log("Plan is now in inbox. Run 'prloom start' to dispatch.");
|
|
@@ -17556,7 +17646,7 @@ __export(exports_dispatcher, {
|
|
|
17556
17646
|
});
|
|
17557
17647
|
import { join as join9 } from "path";
|
|
17558
17648
|
import { existsSync as existsSync9, statSync as statSync5 } from "fs";
|
|
17559
|
-
async function runDispatcher(repoRoot) {
|
|
17649
|
+
async function runDispatcher(repoRoot, options2 = {}) {
|
|
17560
17650
|
const config = loadConfig(repoRoot);
|
|
17561
17651
|
const worktreesDir = resolveWorktreesDir(repoRoot, config);
|
|
17562
17652
|
acquireLock(repoRoot);
|
|
@@ -17584,7 +17674,7 @@ async function runDispatcher(repoRoot) {
|
|
|
17584
17674
|
await handleCommand2(state, cmd);
|
|
17585
17675
|
}
|
|
17586
17676
|
await ingestInboxPlans(repoRoot, worktreesDir, config, state);
|
|
17587
|
-
await processActivePlans(repoRoot, config, state, botLogin);
|
|
17677
|
+
await processActivePlans(repoRoot, config, state, botLogin, options2);
|
|
17588
17678
|
saveState(repoRoot, state);
|
|
17589
17679
|
await sleepUntilIpcOrTimeout(repoRoot, state.control_cursor, config.poll_interval_ms);
|
|
17590
17680
|
} catch (error) {
|
|
@@ -17641,7 +17731,7 @@ function getFeedbackPollDecision(opts) {
|
|
|
17641
17731
|
shouldUpdateLastPolledAt: !pollOnce && shouldPoll
|
|
17642
17732
|
};
|
|
17643
17733
|
}
|
|
17644
|
-
async function processActivePlans(repoRoot, config, state, botLogin) {
|
|
17734
|
+
async function processActivePlans(repoRoot, config, state, botLogin, options2 = {}) {
|
|
17645
17735
|
for (const [planId, ps] of Object.entries(state.plans)) {
|
|
17646
17736
|
try {
|
|
17647
17737
|
const planPath = join9(ps.worktree, ps.planRelpath);
|
|
@@ -17676,7 +17766,7 @@ async function processActivePlans(repoRoot, config, state, botLogin) {
|
|
|
17676
17766
|
if (newFeedback.length > 0) {
|
|
17677
17767
|
console.log(`\uD83D\uDCAC ${newFeedback.length} new feedback for ${planId}`);
|
|
17678
17768
|
if (!isManualAgent) {
|
|
17679
|
-
await runTriage(repoRoot, config, ps, plan, newFeedback);
|
|
17769
|
+
await runTriage(repoRoot, config, ps, plan, newFeedback, options2);
|
|
17680
17770
|
}
|
|
17681
17771
|
plan = parsePlan(planPath);
|
|
17682
17772
|
const maxIds = getMaxFeedbackIds(newFeedback);
|
|
@@ -17699,7 +17789,15 @@ async function processActivePlans(repoRoot, config, state, botLogin) {
|
|
|
17699
17789
|
const prompt = renderWorkerPrompt(repoRoot, plan, todo);
|
|
17700
17790
|
const agentName = plan.frontmatter.agent ?? config.agents.default;
|
|
17701
17791
|
const adapter = getAdapter(agentName);
|
|
17702
|
-
|
|
17792
|
+
const tmuxConfig = options2.tmux ? { sessionName: `prloom-${planId}` } : undefined;
|
|
17793
|
+
if (tmuxConfig) {
|
|
17794
|
+
ps.tmuxSession = tmuxConfig.sessionName;
|
|
17795
|
+
console.log(` [spawned in tmux session: ${tmuxConfig.sessionName}]`);
|
|
17796
|
+
}
|
|
17797
|
+
await adapter.execute({ cwd: ps.worktree, prompt, tmux: tmuxConfig });
|
|
17798
|
+
if (tmuxConfig) {
|
|
17799
|
+
ps.tmuxSession = undefined;
|
|
17800
|
+
}
|
|
17703
17801
|
const committed = await commitAll(ps.worktree, `[prloom] ${planId}: TODO #${todo.index}`);
|
|
17704
17802
|
if (committed) {
|
|
17705
17803
|
await push(ps.worktree, ps.branch);
|
|
@@ -17747,13 +17845,14 @@ async function pollNewFeedback(repoRoot, ps, botLogin) {
|
|
|
17747
17845
|
};
|
|
17748
17846
|
return filterNewFeedback(allFeedback, cursors, botLogin);
|
|
17749
17847
|
}
|
|
17750
|
-
async function runTriage(repoRoot, config, ps, plan, feedback) {
|
|
17848
|
+
async function runTriage(repoRoot, config, ps, plan, feedback, options2 = {}) {
|
|
17751
17849
|
ensureWorktreePrloomDir(ps.worktree);
|
|
17752
17850
|
const triageAgent = config.agents.designer ?? config.agents.default;
|
|
17753
17851
|
const adapter = getAdapter(triageAgent);
|
|
17754
17852
|
const prompt = renderTriagePrompt(repoRoot, plan, feedback);
|
|
17755
17853
|
console.log(`\uD83D\uDD0D Running triage for ${plan.frontmatter.id}...`);
|
|
17756
|
-
|
|
17854
|
+
const tmuxConfig = options2.tmux ? { sessionName: `prloom-triage-${plan.frontmatter.id}` } : undefined;
|
|
17855
|
+
await adapter.execute({ cwd: ps.worktree, prompt, tmux: tmuxConfig });
|
|
17757
17856
|
try {
|
|
17758
17857
|
const result = readTriageResultFile(ps.worktree);
|
|
17759
17858
|
if (result.rebase_requested) {
|
|
@@ -17967,6 +18066,35 @@ var init_open = __esm(() => {
|
|
|
17967
18066
|
init_adapters();
|
|
17968
18067
|
});
|
|
17969
18068
|
|
|
18069
|
+
// src/cli/watch.ts
|
|
18070
|
+
var exports_watch = {};
|
|
18071
|
+
__export(exports_watch, {
|
|
18072
|
+
runWatch: () => runWatch
|
|
18073
|
+
});
|
|
18074
|
+
async function runWatch(repoRoot, planId) {
|
|
18075
|
+
const state = loadState(repoRoot);
|
|
18076
|
+
const ps = state.plans[planId];
|
|
18077
|
+
if (!ps) {
|
|
18078
|
+
console.error(`Plan not found in state: ${planId}`);
|
|
18079
|
+
console.error("Make sure the plan has been dispatched at least once.");
|
|
18080
|
+
process.exit(1);
|
|
18081
|
+
}
|
|
18082
|
+
if (!ps.tmuxSession) {
|
|
18083
|
+
console.error(`No active tmux session for ${planId}`);
|
|
18084
|
+
console.error("This plan may not be running, or dispatcher wasn't started with --tmux");
|
|
18085
|
+
process.exit(1);
|
|
18086
|
+
}
|
|
18087
|
+
console.log(`Attaching to ${ps.tmuxSession} (read-only)...`);
|
|
18088
|
+
console.log("Press Ctrl+B D to detach without interrupting the worker.");
|
|
18089
|
+
await execa("tmux", ["attach", "-t", ps.tmuxSession, "-r"], {
|
|
18090
|
+
stdio: "inherit"
|
|
18091
|
+
});
|
|
18092
|
+
}
|
|
18093
|
+
var init_watch = __esm(() => {
|
|
18094
|
+
init_execa();
|
|
18095
|
+
init_state();
|
|
18096
|
+
});
|
|
18097
|
+
|
|
17970
18098
|
// src/cli/logs.ts
|
|
17971
18099
|
var exports_logs = {};
|
|
17972
18100
|
__export(exports_logs, {
|
|
@@ -23482,9 +23610,13 @@ yargs_default(hideBin(process.argv)).scriptName("prloom").usage("$0 <command> [o
|
|
|
23482
23610
|
}), async (argv) => {
|
|
23483
23611
|
const { runEdit: runEdit2 } = await Promise.resolve().then(() => (init_edit(), exports_edit));
|
|
23484
23612
|
await runEdit2(await getRepoRoot(), argv["plan-id"], argv.agent, argv["no-designer"]);
|
|
23485
|
-
}).command("start", "Start the dispatcher", () =>
|
|
23613
|
+
}).command("start", "Start the dispatcher", (yargs) => yargs.option("tmux", {
|
|
23614
|
+
type: "boolean",
|
|
23615
|
+
describe: "Run workers in tmux sessions for observation",
|
|
23616
|
+
default: false
|
|
23617
|
+
}), async (argv) => {
|
|
23486
23618
|
const { runDispatcher: runDispatcher2 } = await Promise.resolve().then(() => (init_dispatcher(), exports_dispatcher));
|
|
23487
|
-
await runDispatcher2(await getRepoRoot());
|
|
23619
|
+
await runDispatcher2(await getRepoRoot(), { tmux: argv.tmux });
|
|
23488
23620
|
}).command("status", "Show plan states", () => {}, async () => {
|
|
23489
23621
|
const { runStatus: runStatus2 } = await Promise.resolve().then(() => (init_status(), exports_status));
|
|
23490
23622
|
await runStatus2(await getRepoRoot());
|
|
@@ -23497,6 +23629,9 @@ yargs_default(hideBin(process.argv)).scriptName("prloom").usage("$0 <command> [o
|
|
|
23497
23629
|
}).command("open <plan-id>", "Open TUI for manual work (requires paused)", (yargs) => yargs.positional("plan-id", { type: "string", demandOption: true }), async (argv) => {
|
|
23498
23630
|
const { runOpen: runOpen2 } = await Promise.resolve().then(() => (init_open(), exports_open));
|
|
23499
23631
|
await runOpen2(await getRepoRoot(), argv["plan-id"]);
|
|
23632
|
+
}).command("watch <plan-id>", "Observe a running worker (requires --tmux mode)", (yargs) => yargs.positional("plan-id", { type: "string", demandOption: true }), async (argv) => {
|
|
23633
|
+
const { runWatch: runWatch2 } = await Promise.resolve().then(() => (init_watch(), exports_watch));
|
|
23634
|
+
await runWatch2(await getRepoRoot(), argv["plan-id"]);
|
|
23500
23635
|
}).command("logs <plan-id>", "Show session ID for a plan", (yargs) => yargs.positional("plan-id", { type: "string", demandOption: true }), async (argv) => {
|
|
23501
23636
|
const { runLogs: runLogs2 } = await Promise.resolve().then(() => (init_logs(), exports_logs));
|
|
23502
23637
|
await runLogs2(await getRepoRoot(), argv["plan-id"]);
|
package/package.json
CHANGED
package/prompts/designer_new.md
CHANGED
|
@@ -1,22 +1,31 @@
|
|
|
1
1
|
# Designer: Create a New Plan
|
|
2
2
|
|
|
3
|
-
You are helping a software engineer **plan** a coding task
|
|
3
|
+
You are helping a software engineer **plan** a coding task.
|
|
4
4
|
|
|
5
5
|
> [!CAUTION] > **You are PLANNING, not building.**
|
|
6
6
|
>
|
|
7
7
|
> - Do NOT modify any code files
|
|
8
8
|
> - The ONLY file you may edit is: `{{plan_path}}`
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Repository Context
|
|
11
|
+
|
|
12
|
+
You are working in:
|
|
13
|
+
|
|
14
|
+
- **Repo**: `{{repo_path}}`
|
|
15
|
+
- **Base branch**: `{{base_branch}}`
|
|
16
|
+
- **Worker agent**: `{{worker_agent}}`
|
|
11
17
|
|
|
12
|
-
|
|
18
|
+
Explore the codebase freely to understand context. Do NOT ask questions you can answer by exploring (e.g., test commands, file locations, package.json contents).
|
|
13
19
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
- Only fill in details if the user explicitly says "fill in the details" or similar
|
|
20
|
+
## Your Philosophy
|
|
21
|
+
|
|
22
|
+
You are working with a technical user who knows what they want. Your job is to **extract requirements** and **discuss implementation**, not to make decisions for them.
|
|
18
23
|
|
|
19
|
-
|
|
24
|
+
- **Explore the codebase** to understand context before asking questions
|
|
25
|
+
- **Ask clarifying questions** about user preferences and acceptance criteria
|
|
26
|
+
- **Discuss implementation approach** — do not jump straight to writing the plan
|
|
27
|
+
- **Defer to the user's judgment** on design decisions
|
|
28
|
+
- Only fill in the plan when the user confirms they're ready
|
|
20
29
|
|
|
21
30
|
{{#if user_description}}
|
|
22
31
|
|
|
@@ -24,32 +33,48 @@ The user will give you information bit by bit. Your responsibility is to synthes
|
|
|
24
33
|
|
|
25
34
|
> {{user_description}}
|
|
26
35
|
|
|
27
|
-
|
|
36
|
+
Explore relevant files, then discuss the implementation approach with the user before writing the plan.
|
|
28
37
|
{{else}}
|
|
29
38
|
|
|
30
39
|
## Your First Step
|
|
31
40
|
|
|
32
41
|
Ask the user: **What would you like to build?**
|
|
33
42
|
|
|
34
|
-
Then
|
|
43
|
+
Then:
|
|
35
44
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
45
|
+
1. Explore the codebase to understand the relevant areas
|
|
46
|
+
2. Discuss how to implement it (files to change, approach, trade-offs)
|
|
47
|
+
3. Confirm acceptance criteria
|
|
48
|
+
4. When the user is ready, write the plan
|
|
49
|
+
{{/if}}
|
|
41
50
|
|
|
42
51
|
## Plan Structure
|
|
43
52
|
|
|
44
|
-
|
|
53
|
+
The plan file already has a template with these sections. Fill them in:
|
|
45
54
|
|
|
46
55
|
- **Objective**: What will be built (1-2 sentences)
|
|
47
|
-
- **Context**: Files to modify,
|
|
48
|
-
- **TODO**:
|
|
56
|
+
- **Context**: Files to modify, constraints, any notes the Worker needs
|
|
57
|
+
- **TODO (Commits)**: Each item is ONE commit the Worker will make
|
|
58
|
+
|
|
59
|
+
### TODO Rules
|
|
60
|
+
|
|
61
|
+
Each TODO item represents a **single commit**. Think of them as the git log you want to see:
|
|
62
|
+
|
|
63
|
+
✅ Good TODOs (commits):
|
|
64
|
+
|
|
65
|
+
- `Fix PDF viewer to load beyond 10 pages`
|
|
66
|
+
- `Add horizontal resize handle to Learn panel`
|
|
67
|
+
- `Update LearnStore to trigger page prefetch`
|
|
68
|
+
|
|
69
|
+
❌ Bad TODOs (not commits):
|
|
70
|
+
|
|
71
|
+
- `Run npm test` — this is verification, not a commit
|
|
72
|
+
- `Trace the code to understand X` — this is research, not a commit
|
|
73
|
+
- `Validate acceptance criteria` — this is testing, not a commit
|
|
49
74
|
|
|
50
|
-
|
|
75
|
+
The Worker will run tests and type-checks before each commit automatically.
|
|
51
76
|
|
|
52
|
-
##
|
|
77
|
+
## Important
|
|
53
78
|
|
|
54
|
-
-
|
|
55
|
-
-
|
|
79
|
+
- The plan template already has a `## Progress Log` section — do NOT duplicate it
|
|
80
|
+
- Leave the frontmatter (`id`, `status`, `agent`, `base_branch`) alone
|