diff --git a/packages/pi-coding-agent/src/config.ts b/packages/pi-coding-agent/src/config.ts index 2c971aaa3..70297cc16 100644 --- a/packages/pi-coding-agent/src/config.ts +++ b/packages/pi-coding-agent/src/config.ts @@ -77,29 +77,33 @@ export function getUpdateInstruction(packageName: string): string { * - For Node.js (dist/): returns __dirname (the dist/ directory) * - For tsx (src/): returns parent directory (the package root) */ +let _cachedPackageDir: string | undefined; + export function getPackageDir(): string { + if (_cachedPackageDir !== undefined) return _cachedPackageDir; + // Allow override via environment variable (useful for Nix/Guix where store paths tokenize poorly) const envDir = process.env.PI_PACKAGE_DIR; if (envDir) { - if (envDir === "~") return homedir(); - if (envDir.startsWith("~/")) return homedir() + envDir.slice(1); - return envDir; + if (envDir === "~") return (_cachedPackageDir = homedir()); + if (envDir.startsWith("~/")) return (_cachedPackageDir = homedir() + envDir.slice(1)); + return (_cachedPackageDir = envDir); } if (isBunBinary) { // Bun binary: process.execPath points to the compiled executable - return dirname(process.execPath); + return (_cachedPackageDir = dirname(process.execPath)); } // Node.js: walk up from __dirname until we find package.json let dir = __dirname; while (dir !== dirname(dir)) { if (existsSync(join(dir, "package.json"))) { - return dir; + return (_cachedPackageDir = dir); } dir = dirname(dir); } // Fallback (shouldn't happen) - return __dirname; + return (_cachedPackageDir = __dirname); } /** diff --git a/src/resources/extensions/gsd/activity-log.ts b/src/resources/extensions/gsd/activity-log.ts index 7aef8fc47..3e58543ec 100644 --- a/src/resources/extensions/gsd/activity-log.ts +++ b/src/resources/extensions/gsd/activity-log.ts @@ -8,10 +8,11 @@ * Diagnostic extraction is handled by session-forensics.ts. */ -import { writeFileSync, mkdirSync, readdirSync, unlinkSync, statSync } from "node:fs"; -import { existsSync } from "node:fs"; +import { writeFileSync, mkdirSync, readdirSync, unlinkSync, statSync, openSync, closeSync, constants } from "node:fs"; import { createHash } from "node:crypto"; import { join } from "node:path"; + +const SEQ_PREFIX_RE = /^(\d+)-/; import type { ExtensionContext } from "@gsd/pi-coding-agent"; import { gsdRoot } from "./paths.js"; @@ -26,7 +27,7 @@ function scanNextSequence(activityDir: string): number { let maxSeq = 0; try { for (const f of readdirSync(activityDir)) { - const match = f.match(/^(\d+)-/); + const match = f.match(SEQ_PREFIX_RE); if (match) maxSeq = Math.max(maxSeq, parseInt(match[1], 10)); } } catch { @@ -55,14 +56,24 @@ function nextActivityFilePath( unitType: string, safeUnitId: string, ): string { - while (true) { + // Use O_CREAT | O_EXCL for atomic "create if absent" — no directory scan needed. + for (let attempts = 0; attempts < 1000; attempts++) { const seq = String(state.nextSeq).padStart(3, "0"); const filePath = join(activityDir, `${seq}-${unitType}-${safeUnitId}.jsonl`); - if (!existsSync(filePath)) { + try { + const fd = openSync(filePath, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY); + closeSync(fd); return filePath; + } catch (err: any) { + if (err?.code === "EEXIST") { + state.nextSeq++; + continue; + } + throw err; } - state.nextSeq = scanNextSequence(activityDir); } + // Fallback: should never reach here in practice + throw new Error(`Failed to find available activity log sequence in ${activityDir}`); } export function saveActivityLog( @@ -99,7 +110,7 @@ export function pruneActivityLogs(activityDir: string, retentionDays: number): v const files = readdirSync(activityDir); const entries: { seq: number; filePath: string }[] = []; for (const f of files) { - const match = f.match(/^(\d+)-/); + const match = f.match(SEQ_PREFIX_RE); if (match) entries.push({ seq: parseInt(match[1], 10), filePath: join(activityDir, f) }); } if (entries.length === 0) return; diff --git a/src/resources/extensions/gsd/auto-prompts.ts b/src/resources/extensions/gsd/auto-prompts.ts index 301578b15..14c589884 100644 --- a/src/resources/extensions/gsd/auto-prompts.ts +++ b/src/resources/extensions/gsd/auto-prompts.ts @@ -202,6 +202,7 @@ export async function buildCarryForwardSection(priorSummaryPaths: string[], base const provided = summary.frontmatter.provides.slice(0, 2).join("; "); const decisions = summary.frontmatter.key_decisions.slice(0, 2).join("; "); const patterns = summary.frontmatter.patterns_established.slice(0, 2).join("; "); + const keyFiles = summary.frontmatter.key_files.slice(0, 3).join("; "); const diagnostics = extractMarkdownSection(content, "Diagnostics"); const parts = [summary.title || relPath]; @@ -209,6 +210,7 @@ export async function buildCarryForwardSection(priorSummaryPaths: string[], base if (provided) parts.push(`provides: ${provided}`); if (decisions) parts.push(`decisions: ${decisions}`); if (patterns) parts.push(`patterns: ${patterns}`); + if (keyFiles) parts.push(`key_files: ${keyFiles}`); if (diagnostics) parts.push(`diagnostics: ${oneLine(diagnostics)}`); return `- \`${relPath}\` — ${parts.join(" | ")}`; @@ -458,6 +460,7 @@ export async function buildResearchSlicePrompt( const outputRelPath = relSliceFile(base, mid, sid, "RESEARCH"); return loadPrompt("research-slice", { + workingDirectory: base, milestoneId: mid, sliceId: sid, sliceTitle: sTitle, slicePath: relSlicePath(base, mid, sid), roadmapPath: roadmapRel, @@ -495,6 +498,7 @@ export async function buildPlanSlicePrompt( const outputRelPath = relSliceFile(base, mid, sid, "PLAN"); return loadPrompt("plan-slice", { + workingDirectory: base, milestoneId: mid, sliceId: sid, sliceTitle: sTitle, slicePath: relSlicePath(base, mid, sid), roadmapPath: roadmapRel, @@ -557,6 +561,7 @@ export async function buildExecuteTaskPrompt( const taskSummaryPath = `${relSlicePath(base, mid, sid)}/tasks/${tid}-SUMMARY.md`; return loadPrompt("execute-task", { + workingDirectory: base, milestoneId: mid, sliceId: sid, sliceTitle: sTitle, taskId: tid, taskTitle: tTitle, planPath: relSliceFile(base, mid, sid, "PLAN"), slicePath: relSlicePath(base, mid, sid), @@ -610,6 +615,7 @@ export async function buildCompleteSlicePrompt( const sliceUatPath = `${sliceRel}/${sid}-UAT.md`; return loadPrompt("complete-slice", { + workingDirectory: base, milestoneId: mid, sliceId: sid, sliceTitle: sTitle, slicePath: sliceRel, roadmapPath: roadmapRel, diff --git a/src/resources/extensions/gsd/commands.ts b/src/resources/extensions/gsd/commands.ts index 1c130f7f9..56df01e4a 100644 --- a/src/resources/extensions/gsd/commands.ts +++ b/src/resources/extensions/gsd/commands.ts @@ -31,7 +31,7 @@ import { filterDoctorIssues, } from "./doctor.js"; import { loadPrompt } from "./prompt-loader.js"; -import { handleMigrate } from "./migrate/command.js"; + import { handleRemote } from "../remote-questions/remote-command.js"; import { handleHistory } from "./history.js"; import { handleUndo } from "./undo.js"; @@ -249,6 +249,7 @@ export function registerGSDCommand(pi: ExtensionAPI): void { } if (trimmed === "migrate" || trimmed.startsWith("migrate ")) { + const { handleMigrate } = await import("./migrate/command.js"); await handleMigrate(trimmed.replace(/^migrate\s*/, "").trim(), ctx, pi); return; } diff --git a/src/resources/extensions/gsd/docs/preferences-reference.md b/src/resources/extensions/gsd/docs/preferences-reference.md index da2711435..d7e5a3fe4 100644 --- a/src/resources/extensions/gsd/docs/preferences-reference.md +++ b/src/resources/extensions/gsd/docs/preferences-reference.md @@ -102,10 +102,10 @@ Setting `prefer_skills: []` does **not** disable skill discovery — it just mea - `git`: configures GSD's git behavior. All fields are optional — omit any to use defaults. Keys: - `auto_push`: boolean — automatically push commits to the remote after committing. Default: `false`. - - `push_branches`: boolean — push newly created slice branches to the remote. Default: `false`. + - `push_branches`: boolean — push the milestone branch to the remote after commits. Default: `false`. - `remote`: string — git remote name to push to. Default: `"origin"`. - `snapshots`: boolean — create snapshot commits (WIP saves) during long-running tasks. Default: `false`. - - `pre_merge_check`: boolean or `"auto"` — run pre-merge checks before merging a slice branch. `true` always runs, `false` never runs, `"auto"` runs when CI is detected. Default: `false`. + - `pre_merge_check`: boolean or `"auto"` — run pre-merge checks before merging a worktree back to the integration branch. `true` always runs, `false` never runs, `"auto"` runs when CI is detected. Default: `false`. - `commit_type`: string — override the conventional commit type prefix. Must be one of: `feat`, `fix`, `refactor`, `docs`, `test`, `chore`, `perf`, `ci`, `build`, `style`. Default: inferred from diff content. - `main_branch`: string — the primary branch name for new git repos (e.g., `"main"`, `"master"`, `"trunk"`). Also used by `getMainBranch()` as the preferred branch when auto-detection is ambiguous. Default: `"main"`. diff --git a/src/resources/extensions/gsd/guided-flow.ts b/src/resources/extensions/gsd/guided-flow.ts index 4d6dbd33c..eeda2128b 100644 --- a/src/resources/extensions/gsd/guided-flow.ts +++ b/src/resources/extensions/gsd/guided-flow.ts @@ -1112,7 +1112,7 @@ export async function showSmartEntry( inlineTemplate("uat", "UAT"), ].join("\n\n---\n\n"); dispatchWorkflow(pi, loadPrompt("guided-complete-slice", { - milestoneId, sliceId, sliceTitle, inlinedTemplates: completeSliceTemplates, + workingDirectory: basePath, milestoneId, sliceId, sliceTitle, inlinedTemplates: completeSliceTemplates, })); } else if (choice === "status") { const { fireStatusViaCommand } = await import("./commands.js"); diff --git a/src/resources/extensions/gsd/prompts/complete-milestone.md b/src/resources/extensions/gsd/prompts/complete-milestone.md index 2d3d51d1c..993f53da6 100644 --- a/src/resources/extensions/gsd/prompts/complete-milestone.md +++ b/src/resources/extensions/gsd/prompts/complete-milestone.md @@ -2,6 +2,10 @@ You are executing GSD auto-mode. ## UNIT: Complete Milestone {{milestoneId}} ("{{milestoneTitle}}") +## Your Role in the Pipeline + +All slices are done. You are closing out the milestone — verifying that the assembled work actually delivers the promised outcome, writing the milestone summary, and updating project state. The milestone summary is the final record. After you finish, the system merges the worktree back to the integration branch. If there are queued milestones, the next one starts its own research → plan → execute cycle from a clean slate — the milestone summary is how it learns what was already built. + All relevant context has been preloaded below — the roadmap, all slice summaries, requirements, decisions, and project context are inlined. Start working immediately without re-reading these files. {{inlinedContext}} diff --git a/src/resources/extensions/gsd/prompts/complete-slice.md b/src/resources/extensions/gsd/prompts/complete-slice.md index d96e02474..66070bdc9 100644 --- a/src/resources/extensions/gsd/prompts/complete-slice.md +++ b/src/resources/extensions/gsd/prompts/complete-slice.md @@ -2,6 +2,16 @@ You are executing GSD auto-mode. ## UNIT: Complete Slice {{sliceId}} ("{{sliceTitle}}") — Milestone {{milestoneId}} +## Working Directory + +Your working directory is `{{workingDirectory}}`. All file reads, writes, and shell commands MUST operate relative to this directory. Do NOT `cd` to any other directory. + +## Your Role in the Pipeline + +Executor agents built each task and wrote task summaries. You are the closer — verify the assembled work actually delivers the slice goal, then compress everything into a slice summary. After you finish, a **reassess-roadmap agent** reads your slice summary to decide if the remaining roadmap still makes sense. The slice summary is also the primary record of what this slice achieved — future slice researchers and planners read it as a dependency summary when their work builds on yours. + +Write the summary for those downstream readers. What did this slice actually deliver? What patterns did it establish? What should the next slice know? + All relevant context has been preloaded below — the slice plan, all task summaries, and the milestone roadmap are inlined. Start working immediately without re-reading these files. {{inlinedContext}} diff --git a/src/resources/extensions/gsd/prompts/execute-task.md b/src/resources/extensions/gsd/prompts/execute-task.md index 5757b3d6e..34c41b785 100644 --- a/src/resources/extensions/gsd/prompts/execute-task.md +++ b/src/resources/extensions/gsd/prompts/execute-task.md @@ -2,7 +2,11 @@ You are executing GSD auto-mode. ## UNIT: Execute Task {{taskId}} ("{{taskTitle}}") — Slice {{sliceId}} ("{{sliceTitle}}"), Milestone {{milestoneId}} -Start with the inlined context below. Treat the inlined task plan as the authoritative local execution contract for this unit. Use the referenced source artifacts to verify details, resolve ambiguity, and run the required checks — do not waste time reconstructing context that is already provided here. +## Working Directory + +Your working directory is `{{workingDirectory}}`. All file reads, writes, and shell commands MUST operate relative to this directory. Do NOT `cd` to any other directory. + +A researcher explored the codebase and a planner decomposed the work — you are the executor. The task plan below is your authoritative contract. It contains the specific files, steps, and verification you need. Don't re-research or re-plan — build what the plan says, verify it works, and document what happened. {{resumeSection}} @@ -54,7 +58,7 @@ Then: 16. Do not commit manually — the system auto-commits your changes after this unit completes. 17. Update `.gsd/STATE.md` -You are on the slice branch. All work stays here. +All work stays in your working directory: `{{workingDirectory}}`. **You MUST mark {{taskId}} as `[x]` in `{{planPath}}` AND write `{{taskSummaryPath}}` before finishing.** diff --git a/src/resources/extensions/gsd/prompts/guided-complete-slice.md b/src/resources/extensions/gsd/prompts/guided-complete-slice.md index 284eb28c2..edcf6dc9a 100644 --- a/src/resources/extensions/gsd/prompts/guided-complete-slice.md +++ b/src/resources/extensions/gsd/prompts/guided-complete-slice.md @@ -1,3 +1,3 @@ -Complete slice {{sliceId}} ("{{sliceTitle}}") of milestone {{milestoneId}}. All tasks are done. Use the **Slice Summary** and **UAT** output templates below. If a `GSD Skill Preferences` block is present in system context, use it to decide which skills to load and follow during completion, without relaxing required verification or artifact rules. Write `{{sliceId}}-SUMMARY.md` (compress task summaries), write `{{sliceId}}-UAT.md`, and fill the `UAT Type` plus `Not Proven By This UAT` sections explicitly so the artifact states what class of acceptance it covers and what still remains unproven. Review task summaries for `key_decisions` and ensure any significant ones are in `.gsd/DECISIONS.md`. Mark the slice checkbox done in the roadmap, update STATE.md, update milestone summary, and leave the slice branch clean for the extension to squash-merge back into the integration branch automatically. +Complete slice {{sliceId}} ("{{sliceTitle}}") of milestone {{milestoneId}}. Your working directory is `{{workingDirectory}}` — all file operations must use this path. All tasks are done. Your slice summary is the primary record of what was built — downstream agents (reassess-roadmap, future slice researchers) read it to understand what this slice delivered and what to watch out for. Use the **Slice Summary** and **UAT** output templates below. If a `GSD Skill Preferences` block is present in system context, use it to decide which skills to load and follow during completion, without relaxing required verification or artifact rules. Write `{{sliceId}}-SUMMARY.md` (compress task summaries), write `{{sliceId}}-UAT.md`, and fill the `UAT Type` plus `Not Proven By This UAT` sections explicitly so the artifact states what class of acceptance it covers and what still remains unproven. Review task summaries for `key_decisions` and ensure any significant ones are in `.gsd/DECISIONS.md`. Mark the slice checkbox done in the roadmap, update STATE.md, update milestone summary, Do not commit or merge manually — the system handles this after the unit completes. {{inlinedTemplates}} diff --git a/src/resources/extensions/gsd/prompts/guided-research-slice.md b/src/resources/extensions/gsd/prompts/guided-research-slice.md index e0f010a13..0707d879b 100644 --- a/src/resources/extensions/gsd/prompts/guided-research-slice.md +++ b/src/resources/extensions/gsd/prompts/guided-research-slice.md @@ -1,4 +1,6 @@ -Research slice {{sliceId}} ("{{sliceTitle}}") of milestone {{milestoneId}}. Read `.gsd/DECISIONS.md` if it exists — respect existing decisions, don't contradict them. Read `.gsd/REQUIREMENTS.md` if it exists — identify which Active requirements this slice owns or supports and target research toward risks, unknowns, and constraints that could affect delivery of those requirements. If a `GSD Skill Preferences` block is present in system context, use it to decide which skills to load and follow during research, without relaxing required verification or artifact rules. Explore the relevant code — use `rg`/`find` for targeted reads, or `scout` if the area is broad or unfamiliar. Check libraries with `resolve_library`/`get_library_docs`. Use the **Research** output template below. Write `{{sliceId}}-RESEARCH.md` in the slice directory with summary, don't-hand-roll, common pitfalls, and relevant code sections. +Research slice {{sliceId}} ("{{sliceTitle}}") of milestone {{milestoneId}}. Read `.gsd/DECISIONS.md` if it exists — respect existing decisions, don't contradict them. Read `.gsd/REQUIREMENTS.md` if it exists — identify which Active requirements this slice owns or supports and target research toward risks, unknowns, and constraints that could affect delivery of those requirements. If a `GSD Skill Preferences` block is present in system context, use it to decide which skills to load and follow during research, without relaxing required verification or artifact rules. Explore the relevant code — use `rg`/`find` for targeted reads, or `scout` if the area is broad or unfamiliar. Check libraries with `resolve_library`/`get_library_docs` — skip this for libraries already used in the codebase. Use the **Research** output template below. Write `{{sliceId}}-RESEARCH.md` in the slice directory. + +**You are the scout.** A planner agent reads your output in a fresh context to decompose this slice into tasks. Write for the planner — surface key files, where the work divides naturally, what to build first, and how to verify. If the research doc is vague, the planner re-explores code you already read. If it's precise, the planner decomposes immediately. ## Strategic Questions to Answer diff --git a/src/resources/extensions/gsd/prompts/plan-milestone.md b/src/resources/extensions/gsd/prompts/plan-milestone.md index d10d2381b..72c97a260 100644 --- a/src/resources/extensions/gsd/prompts/plan-milestone.md +++ b/src/resources/extensions/gsd/prompts/plan-milestone.md @@ -6,6 +6,12 @@ All relevant context has been preloaded below — start working immediately with {{inlinedContext}} +## Your Role in the Pipeline + +A **researcher agent** already explored the codebase and documented findings in the milestone research doc (inlined above, if present). It identified key files, technology choices, constraints, and risks. **Trust the research.** Your job is strategic decomposition — turning findings into an ordered set of demoable slices — not re-exploration. Don't read code files the research already summarized unless something is ambiguous or missing. + +After you finish, each slice goes through its own research → plan → execute cycle. Slice researchers dive deeper into the specific area. Slice planners decompose into tasks. Executors build each task. Your roadmap sets the strategic frame for all of them. + Narrate your decomposition reasoning — why you're grouping work this way, what risks are driving the order, what verification strategy you're choosing and why. Then: diff --git a/src/resources/extensions/gsd/prompts/plan-slice.md b/src/resources/extensions/gsd/prompts/plan-slice.md index a4ae2e63f..fe5036db4 100644 --- a/src/resources/extensions/gsd/prompts/plan-slice.md +++ b/src/resources/extensions/gsd/prompts/plan-slice.md @@ -2,6 +2,10 @@ You are executing GSD auto-mode. ## UNIT: Plan Slice {{sliceId}} ("{{sliceTitle}}") — Milestone {{milestoneId}} +## Working Directory + +Your working directory is `{{workingDirectory}}`. All file reads, writes, and shell commands MUST operate relative to this directory. Do NOT `cd` to any other directory. + All relevant context has been preloaded below — start working immediately without re-reading these files. {{inlinedContext}} @@ -12,6 +16,12 @@ Pay particular attention to **Forward Intelligence** sections — they contain h {{dependencySummaries}} +## Your Role in the Pipeline + +A **researcher agent** already explored the codebase and documented findings in the slice research doc (inlined above, if present). It identified key files, build order, constraints, and verification approach. **Trust the research.** Your job is decomposition — turning findings into executable tasks — not re-exploration. Don't read code files the research already summarized unless something is ambiguous or missing from its findings. + +After you finish, **executor agents** implement each task in isolated fresh context windows. They see only their task plan, the slice plan excerpt (goal/demo/verification), and compressed summaries of prior tasks. They do not see the research doc, the roadmap, or REQUIREMENTS.md. Everything an executor needs must be in the task plan itself — file paths, specific steps, expected inputs and outputs. + Narrate your decomposition reasoning — why you're grouping work this way, what risks are driving the order, what verification strategy you're choosing and why. Keep the narration proportional to the work — a simple slice doesn't need a long justification. **Right-size the plan.** If the slice is simple enough to be 1 task, plan 1 task. Don't split into multiple tasks just because you can identify sub-steps. Don't fill in sections with "None" when the section doesn't apply — omit them entirely. The plan's job is to guide execution, not to fill a template. @@ -48,7 +58,7 @@ Then: 10. Commit: `docs({{sliceId}}): add slice plan` 11. Update `.gsd/STATE.md` -The slice directory and tasks/ subdirectory already exist. Do NOT mkdir. You are on the slice branch; all work stays here. +The slice directory and tasks/ subdirectory already exist. Do NOT mkdir. All work stays in your working directory: `{{workingDirectory}}`. **You MUST write the file `{{outputPath}}` before finishing.** diff --git a/src/resources/extensions/gsd/prompts/reassess-roadmap.md b/src/resources/extensions/gsd/prompts/reassess-roadmap.md index eeb001fd4..31f4cfdae 100644 --- a/src/resources/extensions/gsd/prompts/reassess-roadmap.md +++ b/src/resources/extensions/gsd/prompts/reassess-roadmap.md @@ -2,6 +2,12 @@ You are executing GSD auto-mode. ## UNIT: Reassess Roadmap — Milestone {{milestoneId}} after {{completedSliceId}} +## Your Role in the Pipeline + +A slice just completed. The **complete-slice agent** verified the work and wrote a slice summary. You decide whether the remaining roadmap still makes sense given what was actually built. If you change the roadmap, the next slice's **researcher** and **planner** agents work from your updated version. If you confirm it's fine, the pipeline moves to the next slice immediately. + +Your assessment should be fast and decisive. Most of the time the plan is still good. + All relevant context has been preloaded below — the current roadmap, completed slice summary, project state, and decisions are inlined. Start working immediately without re-reading these files. {{inlinedContext}} diff --git a/src/resources/extensions/gsd/prompts/research-milestone.md b/src/resources/extensions/gsd/prompts/research-milestone.md index 70bc03a29..59c0184fa 100644 --- a/src/resources/extensions/gsd/prompts/research-milestone.md +++ b/src/resources/extensions/gsd/prompts/research-milestone.md @@ -6,19 +6,24 @@ All relevant context has been preloaded below — start working immediately with {{inlinedContext}} +## Your Role in the Pipeline + +You are the first deep look at this milestone. A **roadmap planner** reads your output to decide how to slice the work — what to build first, how to order by risk, what boundaries to draw between slices. Then individual slice researchers and planners dive deeper into each slice. Your research sets the strategic direction for all of them. + +Write for the roadmap planner. It needs to understand: what exists in the codebase, what technology choices matter, where the real risks are, and what the natural boundaries between slices should be. + +## Calibrate Depth + +A milestone adding a small feature to an established codebase needs targeted research — check the relevant code, confirm the approach, note constraints. A milestone introducing new technology, building a new system, or spanning multiple unfamiliar subsystems needs deep research — explore broadly, look up docs, investigate alternatives. Match your effort to the actual uncertainty, not the template's section count. Include only sections that have real content. + Then research the codebase and relevant technologies. Narrate key findings and surprises as you go — what exists, what's missing, what constrains the approach. 1. If a `GSD Skill Preferences` block is present in system context, use it to decide which skills to load and follow during research, without relaxing required verification or artifact rules 2. **Skill Discovery ({{skillDiscoveryMode}}):**{{skillDiscoveryInstructions}} 3. Explore relevant code. For small/familiar codebases, use `rg`, `find`, and targeted reads. For large or unfamiliar codebases, use `scout` to build a broad map efficiently before diving in. -4. Use `resolve_library` / `get_library_docs` for unfamiliar libraries -5. Use the **Research** output template from the inlined context above +4. Use `resolve_library` / `get_library_docs` for unfamiliar libraries — skip this for libraries already used in the codebase +5. Use the **Research** output template from the inlined context above — include only sections that have real content 6. If `.gsd/REQUIREMENTS.md` exists, research against it. Identify which Active requirements are table stakes, likely omissions, overbuilt risks, or domain-standard behaviors the user may or may not want. -7. Write `{{outputPath}}` with: - - Summary (2-3 paragraphs, primary recommendation) - - Don't Hand-Roll table (problems with existing solutions) - - Common Pitfalls (what goes wrong, how to avoid) - - Relevant Code (existing files, patterns, integration points) - - Sources +7. Write `{{outputPath}}` ## Strategic Questions to Answer diff --git a/src/resources/extensions/gsd/prompts/research-slice.md b/src/resources/extensions/gsd/prompts/research-slice.md index 192d30e0e..ee8fd7055 100644 --- a/src/resources/extensions/gsd/prompts/research-slice.md +++ b/src/resources/extensions/gsd/prompts/research-slice.md @@ -2,6 +2,10 @@ You are executing GSD auto-mode. ## UNIT: Research Slice {{sliceId}} ("{{sliceTitle}}") — Milestone {{milestoneId}} +## Working Directory + +Your working directory is `{{workingDirectory}}`. All file reads, writes, and shell commands MUST operate relative to this directory. Do NOT `cd` to any other directory. + All relevant context has been preloaded below — start working immediately without re-reading these files. {{inlinedContext}} @@ -12,13 +16,37 @@ Pay particular attention to **Forward Intelligence** sections — they contain h {{dependencySummaries}} -Then research what this slice needs. Narrate key findings and surprises as you go — what exists, what's missing, what constrains the approach. +## Your Role in the Pipeline + +You are the scout. After you finish, a **planner agent** reads your output in a fresh context with no memory of your exploration. It uses your findings to decompose this slice into executable tasks — deciding what files change, what order to build things, how to verify the work. Then **executor agents** build each task in isolated context windows. + +Write for the planner, not for a human. The planner needs: +- **What files exist and what they do** — so it can scope tasks to specific files +- **Where the natural seams are** — where work divides into independent units +- **What to build or prove first** — what's riskiest, what unblocks everything else +- **How to verify the result** — what commands, tests, or checks confirm the slice works + +If the research doc is vague, the planner will waste its context re-exploring code you already read. If it's precise, the planner can decompose immediately. + +## Calibrate Depth + +Read the slice title, the roadmap excerpt, and any milestone research above. Ask: does this slice involve unfamiliar technology, risky integration, novel architecture, or ambiguous requirements? Or is it straightforward application of known patterns to known code? + +- **Deep research** — new technology, unfamiliar APIs, risky integration, multiple viable approaches, or ambiguous scope. Explore broadly, look up docs, check libraries, investigate constraints. Write all template sections. This is the default when you're genuinely uncertain. +- **Targeted research** — known technology but new to this codebase, or moderately complex integration. Explore the relevant code, check one or two libraries, identify constraints. Omit Don't Hand-Roll and Sources if nothing applies. +- **Light research** — well-understood work using established patterns already in the codebase (wiring up existing APIs, adding standard UI components, CRUD operations, configuration changes). Read the relevant files to confirm the pattern, note any constraints, write Summary + Recommendation + Implementation Landscape. Skip the rest. A light research doc can be 15-20 lines. Don't manufacture pitfalls or risks for work that doesn't have them. + +An honest "this is straightforward, here's the pattern to follow" is more valuable than invented complexity. + +## Steps + +Research what this slice needs. Narrate key findings and surprises as you go — what exists, what's missing, what constrains the approach. 0. If `REQUIREMENTS.md` was preloaded above, identify which Active requirements this slice owns or supports. Research should target these requirements — surfacing risks, unknowns, and implementation constraints that could affect whether the slice actually delivers them. 1. If a `GSD Skill Preferences` block is present in system context, use it to decide which skills to load and follow during research, without relaxing required verification or artifact rules 2. **Skill Discovery ({{skillDiscoveryMode}}):**{{skillDiscoveryInstructions}} 3. Explore relevant code for this slice's scope. For targeted exploration, use `rg`, `find`, and reads. For broad or unfamiliar subsystems, use `scout` to map the relevant area first. -4. Use `resolve_library` / `get_library_docs` for unfamiliar libraries -5. Use the **Research** output template from the inlined context above +4. Use `resolve_library` / `get_library_docs` for unfamiliar libraries — skip this for libraries already used in the codebase +5. Use the **Research** output template from the inlined context above — include only sections that have real content 6. Write `{{outputPath}}` The slice directory already exists at `{{slicePath}}/`. Do NOT mkdir — just write the file. diff --git a/src/resources/extensions/gsd/prompts/system.md b/src/resources/extensions/gsd/prompts/system.md index fc50ad77c..58bd81ea5 100644 --- a/src/resources/extensions/gsd/prompts/system.md +++ b/src/resources/extensions/gsd/prompts/system.md @@ -62,19 +62,23 @@ Titles live inside file content (headings, frontmatter), not in file or director ``` .gsd/ - PROJECT.md (living doc - what the project is right now) - DECISIONS.md (append-only register of architectural and pattern decisions) - QUEUE.md (append-only log of queued milestones via /gsd queue) + PROJECT.md (living doc - what the project is right now) + REQUIREMENTS.md (requirement contract - tracks active/validated/deferred/out-of-scope) + DECISIONS.md (append-only register of architectural and pattern decisions) + QUEUE.md (append-only log of queued milestones via /gsd queue) STATE.md + runtime/ (system-managed — dispatch state, do not edit) + activity/ (system-managed — JSONL execution logs, do not edit) + worktrees/ (system-managed — auto-mode worktree checkouts, see below) milestones/ M001/ - M001-CONTEXT.md + M001-CONTEXT.md (milestone brief — scope, goals, constraints. May not exist for early milestones) M001-RESEARCH.md M001-ROADMAP.md M001-SUMMARY.md slices/ S01/ - S01-CONTEXT.md (optional) + S01-CONTEXT.md (slice brief — optional, present when slice needed scoping discussion) S01-RESEARCH.md (optional) S01-PLAN.md S01-SUMMARY.md @@ -84,16 +88,22 @@ Titles live inside file content (headings, frontmatter), not in file or director T01-SUMMARY.md ``` +### Worktree Model + +All auto-mode work happens inside a worktree at `.gsd/worktrees//`. This is a full git worktree on the `milestone/` branch — it has its own working copy of the project and its own `.gsd/` directory. Slices commit sequentially on this branch; there are no per-slice branches. When a milestone completes, the worktree is merged back to the integration branch. + +**If you are executing in auto-mode, your working directory is already set to the worktree.** Use relative paths or the path shown in the Working Directory section of your prompt. Do not navigate to any other copy of the project. + ### Conventions - **PROJECT.md** is a living document describing what the project is right now - current state only, updated at slice completion when stale +- **REQUIREMENTS.md** tracks the requirement contract — requirements move between Active, Validated, Deferred, Blocked, and Out of Scope as slices prove or invalidate them. Update at slice completion when evidence supports a status change. - **DECISIONS.md** is an append-only register of architectural and pattern decisions - read it during planning/research, append to it during execution when a meaningful decision is made +- **CONTEXT.md** files (milestone or slice level) capture the brief — scope, goals, constraints, and key decisions from discussion. When present, they are the authoritative source for what a milestone or slice is trying to achieve. Read them before planning or executing. - **Milestones** are major project phases (M001, M002, ...) - **Slices** are demoable vertical increments (S01, S02, ...) ordered by risk. After each slice completes, the roadmap is reassessed before the next slice begins. - **Tasks** are single-context-window units of work (T01, T02, ...) - Checkboxes in roadmap and plan files track completion (`[ ]` → `[x]`) -- Each slice gets its own git branch: `gsd/M001/S01` (or `gsd//M001/S01` when inside a worktree) -- Slices are squash-merged to the integration branch when complete (this is the branch GSD was started from — often `main`, but could be a feature branch like `f-123-new-thing`) - Summaries compress prior work - read them instead of re-reading all task details - `STATE.md` is the quick-glance status file - keep it updated after changes diff --git a/src/resources/extensions/gsd/templates/plan.md b/src/resources/extensions/gsd/templates/plan.md index a8d154448..bc2ad6025 100644 --- a/src/resources/extensions/gsd/templates/plan.md +++ b/src/resources/extensions/gsd/templates/plan.md @@ -105,13 +105,6 @@ - Do: {{specificImplementationStepsAndConstraints}} - Verify: {{testCommandOrRuntimeCheck}} - Done when: {{measurableAcceptanceCondition}} -- [ ] **T03: {{taskTitle}}** `est:{{estimate}}` - - Why: {{whyThisTaskExists}} - - Files: `{{filePath}}`, `{{filePath}}` - - Do: {{specificImplementationStepsAndConstraints}} - - Verify: {{testCommandOrRuntimeCheck}} - - Done when: {{measurableAcceptanceCondition}} - + {{placeholder}} diff --git a/src/resources/extensions/gsd/templates/research.md b/src/resources/extensions/gsd/templates/research.md index 8f0d65816..fb63e757e 100644 --- a/src/resources/extensions/gsd/templates/research.md +++ b/src/resources/extensions/gsd/templates/research.md @@ -2,6 +2,11 @@ **Date:** {{date}} + + ## Summary {{summary — 2-3 paragraphs with primary recommendation}} @@ -10,37 +15,65 @@ {{whatApproachToTake_AND_why}} +## Implementation Landscape + + + +### Key Files + +- `{{filePath}}` — {{whatItDoesAndHowItRelates}} +- `{{filePath}}` — {{whatNeedsToChange}} + +### Build Order + +{{whatToProveOrBuildFirst_AND_why — whatUnblocksDownstreamWork}} + +### Verification Approach + +{{howToConfirmTheSliceWorks — commands, tests, observable behaviors}} + + + ## Don't Hand-Roll + + | Problem | Existing Solution | Why Use It | |---------|------------------|------------| | {{problem}} | {{solution}} | {{why}} | -## Existing Code and Patterns - -- `{{filePath}}` — {{whatItDoesAndHowToReuseIt}} -- `{{filePath}}` — {{patternToFollowOrAvoid}} - ## Constraints + + - {{hardConstraintFromCodebaseOrRuntime}} - {{constraintFromDependencies}} ## Common Pitfalls + + - **{{pitfall}}** — {{howToAvoid}} - **{{pitfall}}** — {{howToAvoid}} ## Open Risks + + - {{riskThatCouldSurfaceDuringExecution}} ## Skills Discovered + + | Technology | Skill | Status | |------------|-------|--------| | {{technology}} | {{owner/repo@skill}} | {{installed / available / none found}} | ## Sources + + - {{whatWasLearned}} (source: [{{title}}]({{url}})) diff --git a/src/resources/extensions/gsd/templates/state.md b/src/resources/extensions/gsd/templates/state.md index 76ce20ee7..131f1e843 100644 --- a/src/resources/extensions/gsd/templates/state.md +++ b/src/resources/extensions/gsd/templates/state.md @@ -4,7 +4,6 @@ **Active Slice:** {{sliceId}}: {{sliceTitle}} **Active Task:** {{taskId}}: {{taskTitle}} **Phase:** {{phase}} -**Active Workspace:** {{activeWorkspace}} **Next Action:** {{nextAction}} **Last Updated:** {{date}} **Requirements Status:** {{activeCount}} active · {{validatedCount}} validated · {{deferredCount}} deferred · {{outOfScopeCount}} out of scope