From 2bc8d0cdd38807cb45b6f806bc92f1deeff005b9 Mon Sep 17 00:00:00 2001 From: Mikael Hugo Date: Thu, 30 Apr 2026 22:02:41 +0200 Subject: [PATCH] fix: route vision debate subagents correctly --- .../sf/prompts/guided-plan-milestone.md | 2 +- .../extensions/sf/prompts/plan-milestone.md | 2 +- src/resources/extensions/subagent/index.ts | 44 ++++++++++++------- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/resources/extensions/sf/prompts/guided-plan-milestone.md b/src/resources/extensions/sf/prompts/guided-plan-milestone.md index 252f97d94..ed2ba8156 100644 --- a/src/resources/extensions/sf/prompts/guided-plan-milestone.md +++ b/src/resources/extensions/sf/prompts/guided-plan-milestone.md @@ -1,6 +1,6 @@ Plan milestone {{milestoneId}} ("{{milestoneTitle}}"). Read `.sf/DECISIONS.md` if it exists — respect existing decisions. Read `.sf/REQUIREMENTS.md` if it exists and treat Active requirements as the capability contract. If `REQUIREMENTS.md` is missing, continue in legacy compatibility mode but explicitly note missing requirement coverage. Use the **Roadmap** output template below to shape the milestone planning payload you send to `sf_plan_milestone`. Call `sf_plan_milestone` to persist the milestone planning fields and render `{{milestoneId}}-ROADMAP.md` from DB state. Do **not** write `{{milestoneId}}-ROADMAP.md`, `ROADMAP.md`, or other planning artifacts manually. If planning produces structural decisions, append them to `.sf/DECISIONS.md`. {{skillActivation}} Fill the Horizontal Checklist section with cross-cutting concerns considered during planning (requirements re-read, decisions re-evaluated, graceful shutdown, revenue paths, auth boundary, shared resources, reconnection). Omit for trivial milestones. -Before calling `sf_plan_milestone`, run a bounded **Vision Alignment Meeting** for the milestone and roadmap as a real multi-agent review. Use the `subagent` tool in `mode: "debate"` with `rounds: 2` and a separate task for each participant lens below. Do **not** merely simulate every participant inside this planner response. If the `subagent` tool is unavailable or fails after one retry, record that explicitly in `trigger` and run the structured meeting inline as a degraded fallback. This is allowed to be broader and more nuanced than slice planning. Include at least these participant lenses: +Before calling `sf_plan_milestone`, run a bounded **Vision Alignment Meeting** for the milestone and roadmap as a real multi-agent review. Use the `subagent` tool in `mode: "debate"` with `rounds: 2` and a separate task for each participant lens below. Do **not** merely simulate every participant inside this planner response. Use only supported agent names: `planner`, `reviewer`, `researcher`, and `scout`. Put the stakeholder role name inside the task text; do not invent agent names such as `combatant`, `delivery-lead`, `product-manager`, or `customer-panel`. If the `subagent` tool is unavailable or fails after one retry, record that explicitly in `trigger` and run the structured meeting inline as a degraded fallback. This is allowed to be broader and more nuanced than slice planning. Include at least these participant lenses: - Product Manager - User Advocate - Customer Panel diff --git a/src/resources/extensions/sf/prompts/plan-milestone.md b/src/resources/extensions/sf/prompts/plan-milestone.md index a096fbb51..72f01ce52 100644 --- a/src/resources/extensions/sf/prompts/plan-milestone.md +++ b/src/resources/extensions/sf/prompts/plan-milestone.md @@ -43,7 +43,7 @@ If milestone research exists (inlined above), trust those findings and skip redu 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. Use complete sentences rather than planner shorthand or fragmentary notes. -Before you persist the roadmap, run a bounded **Vision Alignment Meeting** as a real multi-agent review. Use the `subagent` tool in `mode: "debate"` with `rounds: 2` and a separate task for each participant lens below. Do **not** merely simulate every participant inside this planner response. If the `subagent` tool is unavailable or fails after one retry, record that explicitly in `trigger` and run the structured meeting inline as a degraded fallback. This is broader than slice planning and should feel allowed to be chatty and nuanced. Gather the strongest additions, cuts, and ordering changes from these participant lenses: +Before you persist the roadmap, run a bounded **Vision Alignment Meeting** as a real multi-agent review. Use the `subagent` tool in `mode: "debate"` with `rounds: 2` and a separate task for each participant lens below. Do **not** merely simulate every participant inside this planner response. Use only supported agent names: `planner`, `reviewer`, `researcher`, and `scout`. Put the stakeholder role name inside the task text; do not invent agent names such as `combatant`, `delivery-lead`, `product-manager`, or `customer-panel`. If the `subagent` tool is unavailable or fails after one retry, record that explicitly in `trigger` and run the structured meeting inline as a degraded fallback. This is broader than slice planning and should feel allowed to be chatty and nuanced. Gather the strongest additions, cuts, and ordering changes from these participant lenses: - **Product Manager:** what is the real product move and what should the roadmap prove? - **User Advocate:** what must matter for the user experience and trust surface? - **Customer Panel:** multiple likely customer viewpoints, not a single flattened “user”. diff --git a/src/resources/extensions/subagent/index.ts b/src/resources/extensions/subagent/index.ts index 49f8b1222..7e645d751 100644 --- a/src/resources/extensions/subagent/index.ts +++ b/src/resources/extensions/subagent/index.ts @@ -50,6 +50,15 @@ const AGENT_ALIASES: Record = { default: "worker", code: "reviewer", coder: "typescript-pro", + "product-manager": "planner", + "user-advocate": "reviewer", + "customer-panel": "reviewer", + business: "planner", + "delivery-lead": "planner", + partner: "reviewer", + combatant: "reviewer", + architect: "planner", + moderator: "planner", ["g" + "sd-executor"]: "worker", "sf-worker": "worker", "sf-scout": "scout", @@ -918,7 +927,13 @@ function buildSubagentProcessArgs( tmpPromptPath: string | null, modelOverride?: string, ): string[] { - const args: string[] = ["--mode", "json", "-p", "--no-session"]; + const args: string[] = [ + ...getBundledExtensionCliArgs(), + "--mode", + "json", + "-p", + "--no-session", + ]; const modelToUse = modelOverride ?? agent.model; if (modelToUse) args.push("--model", modelToUse); if (agent.tools && agent.tools.length > 0) @@ -928,6 +943,14 @@ function buildSubagentProcessArgs( return args; } +function getBundledExtensionCliArgs(): string[] { + return (process.env.SF_BUNDLED_EXTENSION_PATHS ?? "") + .split(path.delimiter) + .map((s) => s.trim()) + .filter(Boolean) + .flatMap((p) => ["--extension", p]); +} + interface SubagentLaunchSpec { command: string; args: string[]; @@ -1204,14 +1227,9 @@ async function runSingleAgent( let wasAborted = false; const exitCode = await new Promise((resolve) => { - const bundledPaths = (process.env.SF_BUNDLED_EXTENSION_PATHS ?? "") - .split(path.delimiter) - .map((s) => s.trim()) - .filter(Boolean); - const extensionArgs = bundledPaths.flatMap((p) => ["--extension", p]); const proc = spawn( launchSpec.command, - [...extensionArgs, ...launchSpec.args], + launchSpec.args, { cwd: cwd ?? defaultCwd, env: launchSpec.env, @@ -1388,15 +1406,9 @@ async function runSingleAgentInCmuxSplit( ); } - const bundledPaths = (process.env.SF_BUNDLED_EXTENSION_PATHS ?? "") - .split(path.delimiter) - .map((s) => s.trim()) - .filter(Boolean); - const extensionArgs = bundledPaths.flatMap((p) => ["--extension", p]); - const launchSpec = resolveSubagentLaunchSpec([ - ...extensionArgs, - ...buildSubagentProcessArgs(agent, task, tmpPromptPath, modelOverride), - ]); + const launchSpec = resolveSubagentLaunchSpec( + buildSubagentProcessArgs(agent, task, tmpPromptPath, modelOverride), + ); const launcherPath = writeNodeSubagentLauncher( launchSpec, cwd ?? defaultCwd,