diff --git a/.changeset/fix-five-bugs-dotted-repos.md b/.changeset/fix-five-bugs-dotted-repos.md new file mode 100644 index 000000000..d488b2ec4 --- /dev/null +++ b/.changeset/fix-five-bugs-dotted-repos.md @@ -0,0 +1,6 @@ +--- +'@bradygaster/squad-cli': patch +'@bradygaster/squad-sdk': patch +--- + +Fix 5 bugs: dotted repo names, icon spacing, board owner, charter passing, missing playbooks diff --git a/.squad-templates/ceremony-reference.md b/.squad-templates/ceremony-reference.md new file mode 100644 index 000000000..78995215a --- /dev/null +++ b/.squad-templates/ceremony-reference.md @@ -0,0 +1,82 @@ +# Ceremony Reference + +On-demand reference for ceremony configuration, facilitator spawn, and execution rules. + +## Config Format + +Ceremonies are declared in `.squad/ceremonies.md`. Each ceremony is a section with a table of fields: + +```markdown +## {CeremonyName} + +| Field | Value | +|-------|-------| +| **Trigger** | auto \| manual | +| **When** | before \| after | +| **Condition** | {when auto-triggered: natural language condition} | +| **Facilitator** | lead \| {specific-agent} | +| **Participants** | all-relevant \| all-involved \| {comma-separated names} | +| **Time budget** | focused \| extended | +| **Enabled** | ✅ yes \| ❌ no | + +**Agenda:** +1. {Step 1} +2. {Step 2} +... +``` + +### Field Definitions + +| Field | Values | Meaning | +|-------|--------|---------| +| Trigger | `auto` | Fires automatically when Condition matches | +| Trigger | `manual` | Only when user says "run {ceremony}" | +| When | `before` | Runs before work batch spawns | +| When | `after` | Runs after work batch completes | +| Condition | free text | Evaluated against current task context | +| Facilitator | agent name | Who runs the meeting | +| Participants | selector | Who attends | +| Time budget | `focused` | Keep it short — key decisions only | +| Time budget | `extended` | Thorough discussion — all angles | +| Enabled | boolean | Skip disabled ceremonies entirely | + +## Facilitator Spawn Template + +When a ceremony triggers, spawn the facilitator (sync) with this prompt structure: + +``` +You are {FacilitatorName}, facilitating the "{CeremonyName}" ceremony. + +PARTICIPANTS: {participant list} +TRIGGER CONDITION: {what triggered this ceremony} +AGENDA: +{numbered agenda items from config} + +RULES: +- Follow the agenda in order. +- For each agenda item, spawn relevant participants as sub-tasks to gather their input. +- Synthesize participant input into clear decisions and action items. +- Keep to the time budget: {focused|extended}. +- Output a structured summary at the end. + +TASK CONTEXT: +{description of the work that triggered this ceremony} +``` + +## Execution Rules + +1. **Before ceremonies** fire AFTER routing decisions but BEFORE agent spawn. The ceremony summary is included in all subsequent work-batch spawn prompts. +2. **After ceremonies** fire when ALL agents in the batch have completed (success or failure). +3. **Manual ceremonies** fire only on explicit user request ("run retro", "do a design review"). +4. **Cooldown:** After a ceremony completes, skip auto-trigger checks for the immediately following step. This prevents ceremony loops. +5. **Participant resolution:** + - `all-relevant` → agents routed to the current task + - `all-involved` → agents that participated in the completed batch + - Named agents → spawn only those specific agents +6. **Scribe integration:** Spawn Scribe (background) at ceremony start to record decisions and action items. +7. **Output format:** + ``` + 📋 {CeremonyName} completed — facilitated by {Facilitator}. + Decisions: {count} | Action items: {count}. + ``` +8. **Failure handling:** If the facilitator fails or times out, log a warning and proceed with work. Ceremonies must never block the pipeline indefinitely. diff --git a/.squad-templates/copilot-agent.md b/.squad-templates/copilot-agent.md new file mode 100644 index 000000000..e8ae4612c --- /dev/null +++ b/.squad-templates/copilot-agent.md @@ -0,0 +1,96 @@ +# Copilot Coding Agent Member + +On-demand reference for adding the GitHub Copilot coding agent (@copilot) to the Squad roster. + +## Adding @copilot + +When the user says "add copilot", "add the coding agent", or "use @copilot for issues": + +1. **Add to team.md roster:** + ```markdown + | @copilot | Coding Agent | — | 🤖 Coding Agent | + ``` +2. **Add capability profile** (below the roster table): + ```markdown + + ### @copilot — Capability Profile + + | Capability | Level | Notes | + |-----------|-------|-------| + | Bug fixes (well-scoped) | 🟢 | Best for isolated, test-covered fixes | + | Feature implementation | 🟡 | Works well with clear specs; may need review | + | Refactoring | 🟡 | Handles mechanical refactors; verify scope | + | Architecture decisions | 🔴 | Cannot make cross-cutting design choices | + | Multi-repo coordination | 🔴 | Limited to single-repo context | + | Test writing | 🟢 | Strong at adding tests for existing code | + | Documentation | 🟢 | Generates docs from code effectively | + ``` +3. **Add routing entries** to routing.md for appropriate work types. +4. **Do not create** `charter.md` — @copilot uses `copilot-instructions.md` instead. + +## Comparison: Spawned Agent vs. @copilot + +| | Spawned Agent | @copilot | +|---|--------------|----------| +| Execution model | Sync sub-task within session | Async — picks up assigned issues | +| Branch convention | `squad/{issue}-{slug}` | `copilot/{slug}` | +| Trigger | Coordinator spawns directly | Issue assignment | +| Charter source | `.squad/agents/{name}/charter.md` | `.github/copilot-instructions.md` | +| Context window | Inherits full session context | Fresh context per issue | +| Reviewer gating | ✅ Enforced by coordinator | ✅ Via PR review process | +| Speed | Immediate (in-session) | Minutes (async queue) | + +## Roster Format + +In `team.md`, @copilot always appears as: + +```markdown +| @copilot | Coding Agent | — | 🤖 Coding Agent | +``` + +- **No casting** — always "@copilot" (literal handle). +- **No charter file** — configuration lives in `.github/copilot-instructions.md`. +- **No history file** — work is tracked via PRs and issue comments. + +## Auto-Assign Behavior + +Controlled by the HTML comment in team.md: + +```markdown + +``` + +| Setting | Behavior | +|---------|----------| +| `true` | Lead assigns routed issues to @copilot automatically via `gh issue edit --add-assignee @copilot` | +| `false` | Lead presents recommendation; user confirms before assignment | + +## Lead Triage Integration + +During triage, Lead evaluates each issue against @copilot's capability profile: + +1. **🟢 Match** — Auto-assign (if enabled) or recommend assignment. +2. **🟡 Match** — Assign with note: "⚠️ May need review — @copilot is 🟡 for this type of work." +3. **🔴 Match** — Skip @copilot; route to appropriate spawned agent or human. + +## Routing Details + +Add to `routing.md`: + +```markdown +| bug fixes (isolated, test-covered) | @copilot 🤖 | Single-file fixes, test additions | +| documentation updates | @copilot 🤖 | README, API docs, inline comments | +| test coverage gaps | @copilot 🤖 | Adding missing test cases | +``` + +Work that routes to @copilot: +- Creates/assigns the GitHub issue (if not already) +- Does NOT spawn a sub-agent — @copilot works asynchronously +- Coordinator reports: "🤖 Assigned #{number} to @copilot — will open a PR when ready." +- Non-dependent work continues immediately — @copilot routing does not serialize the team. + +## Monitoring @copilot Work + +On each watch cycle (or when user asks "status"): +- Check for open PRs from `copilot/*` branches. +- Report: "🤖 @copilot: {N} PRs open ({list}). {M} issues assigned, pending." diff --git a/.squad-templates/prd-intake.md b/.squad-templates/prd-intake.md new file mode 100644 index 000000000..4bc2438c6 --- /dev/null +++ b/.squad-templates/prd-intake.md @@ -0,0 +1,105 @@ +# PRD Intake + +On-demand reference for ingesting a PRD, decomposing it into work items, and managing updates. + +## Triggers + +| User says | Action | +|-----------|--------| +| "here's the PRD" / "work from this spec" | Expect file path or pasted content | +| "read the PRD at {path}" | Read the file at that path | +| "the PRD changed" / "updated the spec" | Re-read and diff against previous decomposition | +| (pastes requirements text) | Treat as inline PRD | + +## Intake Flow + +1. **Detect source:** File path, pasted text, or URL. Store a reference in `.squad/team.md` under `## PRD Source`. +2. **Store PRD reference:** + ```markdown + ## PRD Source + + **Path:** {path-or-inline} + **Ingested:** {ISO date} + **Hash:** {sha256 of content, for change detection} + ``` +3. **Spawn Lead (sync, premium bump)** with decomposition prompt (see below). +4. **Present work items** to user for approval in table format. +5. **On approval:** Route items to agents respecting dependency order. + +## Lead Decomposition Spawn Template + +``` +You are the Lead, decomposing a PRD into actionable work items. + +PRD CONTENT: +{full PRD text} + +TEAM ROSTER: +{roster from team.md} + +TASK: Break this PRD into discrete, implementable work items. For each item provide: +- Title (imperative mood, concise) +- Description (acceptance criteria, technical notes) +- Estimated complexity: S / M / L +- Dependencies (list other item titles this blocks on) +- Suggested assignee (agent name from roster, based on expertise match) + +OUTPUT FORMAT: +Return a markdown table: + +| # | Title | Complexity | Dependencies | Assignee | Status | +|---|-------|-----------|--------------|----------|--------| +| 1 | {title} | {S/M/L} | — | {agent} | pending | + +RULES: +- Items must be independently implementable (no item requires partial completion of another). +- Maximum 1 day of work per item (split larger items). +- Respect team expertise — don't assign frontend work to a backend specialist. +- Order by dependency graph (items with no deps first). +- Flag any ambiguities or missing information as "⚠️ Needs clarification: {question}". +``` + +## Work Item Presentation Format + +Present to user as: + +``` +📋 PRD decomposed into {N} work items: + +| # | Title | Size | Depends on | Assignee | +|---|-------|------|-----------|----------| +| 1 | ... | S | — | {Agent} | +| 2 | ... | M | #1 | {Agent} | + +Ready to proceed? I'll route items respecting the dependency order. +⚠️ Clarifications needed: {list any flagged items} +``` + +## Mid-Project Updates + +When the user says the PRD changed: + +1. Re-read the PRD content. +2. Compute diff against stored hash. +3. Spawn Lead (sync) with a delta-decomposition prompt: + - Show only NEW or CHANGED sections. + - Ask Lead to identify: new items, modified items, obsoleted items. +4. Present changes to user: + ``` + 📋 PRD update detected: + - New items: {count} + - Modified: {count} + - Obsoleted: {count} (will be cancelled if approved) + + {table of changes} + + Approve these updates? + ``` +5. On approval: Cancel obsoleted work (if not yet started), update items, re-route. + +## State Tracking + +Active PRD state lives in team.md: +- `## PRD Source` section (path, date, hash) +- Work items tracked as issues (GitHub) or in `.squad/backlog.md` (offline mode) +- Completion percentage displayed in status checks diff --git a/packages/squad-cli/src/cli-entry.ts b/packages/squad-cli/src/cli-entry.ts index 4ce442e45..da93ba536 100644 --- a/packages/squad-cli/src/cli-entry.ts +++ b/packages/squad-cli/src/cli-entry.ts @@ -546,6 +546,15 @@ async function main(): Promise { : { projectNumber: parseInt(args[boardProjectIdx + 1]!, 10) }; } + // --board-owner sets the project owner (org or user login) + const boardOwnerIdx = args.indexOf('--board-owner'); + if (boardOwnerIdx !== -1 && args[boardOwnerIdx + 1]) { + const existing = capabilities['board']; + capabilities['board'] = typeof existing === 'object' && existing !== null + ? { ...existing, owner: args[boardOwnerIdx + 1]! } + : { owner: args[boardOwnerIdx + 1]! }; + } + // Load config: .squad/config.json merged with CLI overrides const config = loadWatchConfig(getSquadStartDir(), { interval, @@ -570,7 +579,7 @@ async function main(): Promise { // After parsing all flags, check for positional args that look like prompts. // Skip values that follow known value-flags (e.g. "--interval 5" → "5" is not positional). const knownValueFlags = new Set([ - '--interval', '--copilot-flags', '--agent-cmd', '--max-concurrent', '--timeout', '--board-project', '--auth-user', + '--interval', '--copilot-flags', '--agent-cmd', '--max-concurrent', '--timeout', '--board-project', '--board-owner', '--auth-user', '--dispatch-mode', '--log-file', '--notify-level', '--overnight-start', '--overnight-end', '--sentinel-file', '--state-backend', ]); const watchArgStart = args.indexOf(cmd) + 1; diff --git a/packages/squad-cli/src/cli/commands/watch/capabilities/board.ts b/packages/squad-cli/src/cli/commands/watch/capabilities/board.ts index 0f3f191d8..670c23d57 100644 --- a/packages/squad-cli/src/cli/commands/watch/capabilities/board.ts +++ b/packages/squad-cli/src/cli/commands/watch/capabilities/board.ts @@ -26,13 +26,14 @@ export class BoardCapability implements WatchCapability { async execute(context: WatchContext): Promise { const projectNumber = (context.config['projectNumber'] as number) ?? 1; + const owner = (context.config['owner'] as string) ?? '@me'; let mismatches = 0; try { // Reconcile: move closed issues to Done, open issues out of Done const { stdout: itemsJson } = await execFileAsync('gh', [ 'project', 'item-list', String(projectNumber), - '--owner', '@me', + '--owner', owner, '--format', 'json', '--limit', '300', ], { maxBuffer: 10 * 1024 * 1024 }); diff --git a/packages/squad-cli/src/cli/commands/watch/capabilities/execute.ts b/packages/squad-cli/src/cli/commands/watch/capabilities/execute.ts index e583926c8..0a38de7d9 100644 --- a/packages/squad-cli/src/cli/commands/watch/capabilities/execute.ts +++ b/packages/squad-cli/src/cli/commands/watch/capabilities/execute.ts @@ -8,6 +8,7 @@ import path from 'node:path'; import type { WatchCapability, WatchContext, PreflightResult, CapabilityResult } from '../types.js'; import type { MachineCapabilities } from '@bradygaster/squad-sdk/ralph/capabilities'; import { createVerboseLogger } from '../verbose.js'; +import { loadAgentCharter } from '../../../shell/spawn.js'; /** Normalized work item for execution. */ export interface ExecutableWorkItem { @@ -149,7 +150,18 @@ async function executeAll( timeoutMs: number, ): Promise<{ success: boolean; error?: string }> { const prompt = buildAgentPrompt(issues, context.teamRoot); - const { cmd, args } = buildAgentCommand(prompt, context); + + // Load Ralph's charter to give the spawned session full specialist context. + let charterPrefix = ''; + try { + const charter = await loadAgentCharter('ralph', context.teamRoot); + charterPrefix = `You are an AI agent on a software development team.\n\nYOUR CHARTER:\n${charter}\n\nADDITIONAL CONTEXT:\n`; + } catch { + // Fall back gracefully if no charter exists (e.g., fresh setup) + } + + const fullPrompt = charterPrefix + prompt; + const { cmd, args } = buildAgentCommand(fullPrompt, context); return new Promise<{ success: boolean; error?: string }>((resolve) => { const cp: ChildProcess = execFile( diff --git a/packages/squad-cli/src/cli/shell/components/App.tsx b/packages/squad-cli/src/cli/shell/components/App.tsx index 56ad6a310..51a747676 100644 --- a/packages/squad-cli/src/cli/shell/components/App.tsx +++ b/packages/squad-cli/src/cli/shell/components/App.tsx @@ -425,7 +425,7 @@ export const App: React.FC = ({ registry, renderer, teamRoot, version, const { msg, idx: i } = item; const isNewTurn = msg.role === 'user' && i > 0; const agentRole = msg.agentName ? roleMap.get(msg.agentName) : undefined; - const emoji = agentRole ? getRoleEmoji(agentRole) : ''; + const emoji = msg.agentName ? getRoleEmoji(agentRole ?? msg.agentName) : ''; let duration: string | null = null; if (msg.role === 'agent') { for (let j = i - 1; j >= 0; j--) { diff --git a/packages/squad-cli/src/cli/shell/components/MessageStream.tsx b/packages/squad-cli/src/cli/shell/components/MessageStream.tsx index 23f95df10..d5a75b6b1 100644 --- a/packages/squad-cli/src/cli/shell/components/MessageStream.tsx +++ b/packages/squad-cli/src/cli/shell/components/MessageStream.tsx @@ -263,7 +263,7 @@ export const MessageStream: React.FC = ({ {visible.map((msg, i) => { const isNewTurn = msg.role === 'user' && i > 0; const agentRole = msg.agentName ? roleMap.get(msg.agentName) : undefined; - const emoji = agentRole ? getRoleEmoji(agentRole) : ''; + const emoji = msg.agentName ? getRoleEmoji(agentRole ?? msg.agentName) : ''; const duration = getResponseDuration(i); const isFading = fadingCount > 0 && i >= visible.length - fadingCount; @@ -303,7 +303,7 @@ export const MessageStream: React.FC = ({ {roleMap.has(agentName) ? `${getRoleEmoji(roleMap.get(agentName)!)} ` - : ''} + : `${getRoleEmoji(agentName)} `} {agentName === 'coordinator' ? 'Squad' : agentName}: {renderMarkdownInline(wrapTableContent(content, contentWidth, tier))} diff --git a/packages/squad-cli/templates/ceremony-reference.md b/packages/squad-cli/templates/ceremony-reference.md new file mode 100644 index 000000000..78995215a --- /dev/null +++ b/packages/squad-cli/templates/ceremony-reference.md @@ -0,0 +1,82 @@ +# Ceremony Reference + +On-demand reference for ceremony configuration, facilitator spawn, and execution rules. + +## Config Format + +Ceremonies are declared in `.squad/ceremonies.md`. Each ceremony is a section with a table of fields: + +```markdown +## {CeremonyName} + +| Field | Value | +|-------|-------| +| **Trigger** | auto \| manual | +| **When** | before \| after | +| **Condition** | {when auto-triggered: natural language condition} | +| **Facilitator** | lead \| {specific-agent} | +| **Participants** | all-relevant \| all-involved \| {comma-separated names} | +| **Time budget** | focused \| extended | +| **Enabled** | ✅ yes \| ❌ no | + +**Agenda:** +1. {Step 1} +2. {Step 2} +... +``` + +### Field Definitions + +| Field | Values | Meaning | +|-------|--------|---------| +| Trigger | `auto` | Fires automatically when Condition matches | +| Trigger | `manual` | Only when user says "run {ceremony}" | +| When | `before` | Runs before work batch spawns | +| When | `after` | Runs after work batch completes | +| Condition | free text | Evaluated against current task context | +| Facilitator | agent name | Who runs the meeting | +| Participants | selector | Who attends | +| Time budget | `focused` | Keep it short — key decisions only | +| Time budget | `extended` | Thorough discussion — all angles | +| Enabled | boolean | Skip disabled ceremonies entirely | + +## Facilitator Spawn Template + +When a ceremony triggers, spawn the facilitator (sync) with this prompt structure: + +``` +You are {FacilitatorName}, facilitating the "{CeremonyName}" ceremony. + +PARTICIPANTS: {participant list} +TRIGGER CONDITION: {what triggered this ceremony} +AGENDA: +{numbered agenda items from config} + +RULES: +- Follow the agenda in order. +- For each agenda item, spawn relevant participants as sub-tasks to gather their input. +- Synthesize participant input into clear decisions and action items. +- Keep to the time budget: {focused|extended}. +- Output a structured summary at the end. + +TASK CONTEXT: +{description of the work that triggered this ceremony} +``` + +## Execution Rules + +1. **Before ceremonies** fire AFTER routing decisions but BEFORE agent spawn. The ceremony summary is included in all subsequent work-batch spawn prompts. +2. **After ceremonies** fire when ALL agents in the batch have completed (success or failure). +3. **Manual ceremonies** fire only on explicit user request ("run retro", "do a design review"). +4. **Cooldown:** After a ceremony completes, skip auto-trigger checks for the immediately following step. This prevents ceremony loops. +5. **Participant resolution:** + - `all-relevant` → agents routed to the current task + - `all-involved` → agents that participated in the completed batch + - Named agents → spawn only those specific agents +6. **Scribe integration:** Spawn Scribe (background) at ceremony start to record decisions and action items. +7. **Output format:** + ``` + 📋 {CeremonyName} completed — facilitated by {Facilitator}. + Decisions: {count} | Action items: {count}. + ``` +8. **Failure handling:** If the facilitator fails or times out, log a warning and proceed with work. Ceremonies must never block the pipeline indefinitely. diff --git a/packages/squad-cli/templates/copilot-agent.md b/packages/squad-cli/templates/copilot-agent.md new file mode 100644 index 000000000..e8ae4612c --- /dev/null +++ b/packages/squad-cli/templates/copilot-agent.md @@ -0,0 +1,96 @@ +# Copilot Coding Agent Member + +On-demand reference for adding the GitHub Copilot coding agent (@copilot) to the Squad roster. + +## Adding @copilot + +When the user says "add copilot", "add the coding agent", or "use @copilot for issues": + +1. **Add to team.md roster:** + ```markdown + | @copilot | Coding Agent | — | 🤖 Coding Agent | + ``` +2. **Add capability profile** (below the roster table): + ```markdown + + ### @copilot — Capability Profile + + | Capability | Level | Notes | + |-----------|-------|-------| + | Bug fixes (well-scoped) | 🟢 | Best for isolated, test-covered fixes | + | Feature implementation | 🟡 | Works well with clear specs; may need review | + | Refactoring | 🟡 | Handles mechanical refactors; verify scope | + | Architecture decisions | 🔴 | Cannot make cross-cutting design choices | + | Multi-repo coordination | 🔴 | Limited to single-repo context | + | Test writing | 🟢 | Strong at adding tests for existing code | + | Documentation | 🟢 | Generates docs from code effectively | + ``` +3. **Add routing entries** to routing.md for appropriate work types. +4. **Do not create** `charter.md` — @copilot uses `copilot-instructions.md` instead. + +## Comparison: Spawned Agent vs. @copilot + +| | Spawned Agent | @copilot | +|---|--------------|----------| +| Execution model | Sync sub-task within session | Async — picks up assigned issues | +| Branch convention | `squad/{issue}-{slug}` | `copilot/{slug}` | +| Trigger | Coordinator spawns directly | Issue assignment | +| Charter source | `.squad/agents/{name}/charter.md` | `.github/copilot-instructions.md` | +| Context window | Inherits full session context | Fresh context per issue | +| Reviewer gating | ✅ Enforced by coordinator | ✅ Via PR review process | +| Speed | Immediate (in-session) | Minutes (async queue) | + +## Roster Format + +In `team.md`, @copilot always appears as: + +```markdown +| @copilot | Coding Agent | — | 🤖 Coding Agent | +``` + +- **No casting** — always "@copilot" (literal handle). +- **No charter file** — configuration lives in `.github/copilot-instructions.md`. +- **No history file** — work is tracked via PRs and issue comments. + +## Auto-Assign Behavior + +Controlled by the HTML comment in team.md: + +```markdown + +``` + +| Setting | Behavior | +|---------|----------| +| `true` | Lead assigns routed issues to @copilot automatically via `gh issue edit --add-assignee @copilot` | +| `false` | Lead presents recommendation; user confirms before assignment | + +## Lead Triage Integration + +During triage, Lead evaluates each issue against @copilot's capability profile: + +1. **🟢 Match** — Auto-assign (if enabled) or recommend assignment. +2. **🟡 Match** — Assign with note: "⚠️ May need review — @copilot is 🟡 for this type of work." +3. **🔴 Match** — Skip @copilot; route to appropriate spawned agent or human. + +## Routing Details + +Add to `routing.md`: + +```markdown +| bug fixes (isolated, test-covered) | @copilot 🤖 | Single-file fixes, test additions | +| documentation updates | @copilot 🤖 | README, API docs, inline comments | +| test coverage gaps | @copilot 🤖 | Adding missing test cases | +``` + +Work that routes to @copilot: +- Creates/assigns the GitHub issue (if not already) +- Does NOT spawn a sub-agent — @copilot works asynchronously +- Coordinator reports: "🤖 Assigned #{number} to @copilot — will open a PR when ready." +- Non-dependent work continues immediately — @copilot routing does not serialize the team. + +## Monitoring @copilot Work + +On each watch cycle (or when user asks "status"): +- Check for open PRs from `copilot/*` branches. +- Report: "🤖 @copilot: {N} PRs open ({list}). {M} issues assigned, pending." diff --git a/packages/squad-cli/templates/prd-intake.md b/packages/squad-cli/templates/prd-intake.md new file mode 100644 index 000000000..4bc2438c6 --- /dev/null +++ b/packages/squad-cli/templates/prd-intake.md @@ -0,0 +1,105 @@ +# PRD Intake + +On-demand reference for ingesting a PRD, decomposing it into work items, and managing updates. + +## Triggers + +| User says | Action | +|-----------|--------| +| "here's the PRD" / "work from this spec" | Expect file path or pasted content | +| "read the PRD at {path}" | Read the file at that path | +| "the PRD changed" / "updated the spec" | Re-read and diff against previous decomposition | +| (pastes requirements text) | Treat as inline PRD | + +## Intake Flow + +1. **Detect source:** File path, pasted text, or URL. Store a reference in `.squad/team.md` under `## PRD Source`. +2. **Store PRD reference:** + ```markdown + ## PRD Source + + **Path:** {path-or-inline} + **Ingested:** {ISO date} + **Hash:** {sha256 of content, for change detection} + ``` +3. **Spawn Lead (sync, premium bump)** with decomposition prompt (see below). +4. **Present work items** to user for approval in table format. +5. **On approval:** Route items to agents respecting dependency order. + +## Lead Decomposition Spawn Template + +``` +You are the Lead, decomposing a PRD into actionable work items. + +PRD CONTENT: +{full PRD text} + +TEAM ROSTER: +{roster from team.md} + +TASK: Break this PRD into discrete, implementable work items. For each item provide: +- Title (imperative mood, concise) +- Description (acceptance criteria, technical notes) +- Estimated complexity: S / M / L +- Dependencies (list other item titles this blocks on) +- Suggested assignee (agent name from roster, based on expertise match) + +OUTPUT FORMAT: +Return a markdown table: + +| # | Title | Complexity | Dependencies | Assignee | Status | +|---|-------|-----------|--------------|----------|--------| +| 1 | {title} | {S/M/L} | — | {agent} | pending | + +RULES: +- Items must be independently implementable (no item requires partial completion of another). +- Maximum 1 day of work per item (split larger items). +- Respect team expertise — don't assign frontend work to a backend specialist. +- Order by dependency graph (items with no deps first). +- Flag any ambiguities or missing information as "⚠️ Needs clarification: {question}". +``` + +## Work Item Presentation Format + +Present to user as: + +``` +📋 PRD decomposed into {N} work items: + +| # | Title | Size | Depends on | Assignee | +|---|-------|------|-----------|----------| +| 1 | ... | S | — | {Agent} | +| 2 | ... | M | #1 | {Agent} | + +Ready to proceed? I'll route items respecting the dependency order. +⚠️ Clarifications needed: {list any flagged items} +``` + +## Mid-Project Updates + +When the user says the PRD changed: + +1. Re-read the PRD content. +2. Compute diff against stored hash. +3. Spawn Lead (sync) with a delta-decomposition prompt: + - Show only NEW or CHANGED sections. + - Ask Lead to identify: new items, modified items, obsoleted items. +4. Present changes to user: + ``` + 📋 PRD update detected: + - New items: {count} + - Modified: {count} + - Obsoleted: {count} (will be cancelled if approved) + + {table of changes} + + Approve these updates? + ``` +5. On approval: Cancel obsoleted work (if not yet started), update items, re-route. + +## State Tracking + +Active PRD state lives in team.md: +- `## PRD Source` section (path, date, hash) +- Work items tracked as issues (GitHub) or in `.squad/backlog.md` (offline mode) +- Completion percentage displayed in status checks diff --git a/packages/squad-sdk/src/platform/detect.ts b/packages/squad-sdk/src/platform/detect.ts index 1d351b3a7..0393667e9 100644 --- a/packages/squad-sdk/src/platform/detect.ts +++ b/packages/squad-sdk/src/platform/detect.ts @@ -28,13 +28,13 @@ export interface AzureDevOpsRemoteInfo { */ export function parseGitHubRemote(url: string): GitHubRemoteInfo | null { // HTTPS: https://github.com/owner/repo.git - const httpsMatch = url.match(/github\.com\/([^/]+)\/([^/.]+?)(?:\.git)?$/i); + const httpsMatch = url.match(/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/i); if (httpsMatch) { return { owner: httpsMatch[1]!, repo: httpsMatch[2]! }; } // SSH: git@github.com:owner/repo.git - const sshMatch = url.match(/github\.com:([^/]+)\/([^/.]+?)(?:\.git)?$/i); + const sshMatch = url.match(/github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/i); if (sshMatch) { return { owner: sshMatch[1]!, repo: sshMatch[2]! }; } @@ -54,7 +54,7 @@ export function parseAzureDevOpsRemote(url: string): AzureDevOpsRemoteInfo | nul // HTTPS dev.azure.com: https://dev.azure.com/org/project/_git/repo // Also handles: https://org@dev.azure.com/org/project/_git/repo const devAzureHttps = url.match( - /dev\.azure\.com\/([^/]+)\/([^/]+)\/_git\/([^/.]+?)(?:\.git)?$/i, + /dev\.azure\.com\/([^/]+)\/([^/]+)\/_git\/([^/]+?)(?:\.git)?$/i, ); if (devAzureHttps) { return { org: devAzureHttps[1]!, project: devAzureHttps[2]!, repo: devAzureHttps[3]! }; @@ -62,7 +62,7 @@ export function parseAzureDevOpsRemote(url: string): AzureDevOpsRemoteInfo | nul // SSH dev.azure.com: git@ssh.dev.azure.com:v3/org/project/repo const devAzureSsh = url.match( - /ssh\.dev\.azure\.com:v3\/([^/]+)\/([^/]+)\/([^/.]+?)(?:\.git)?$/i, + /ssh\.dev\.azure\.com:v3\/([^/]+)\/([^/]+)\/([^/]+?)(?:\.git)?$/i, ); if (devAzureSsh) { return { org: devAzureSsh[1]!, project: devAzureSsh[2]!, repo: devAzureSsh[3]! }; @@ -70,7 +70,7 @@ export function parseAzureDevOpsRemote(url: string): AzureDevOpsRemoteInfo | nul // Legacy visualstudio.com: https://org.visualstudio.com/project/_git/repo const vsMatch = url.match( - /([^/.]+)\.visualstudio\.com\/([^/]+)\/_git\/([^/.]+?)(?:\.git)?$/i, + /([^/.]+)\.visualstudio\.com\/([^/]+)\/_git\/([^/]+?)(?:\.git)?$/i, ); if (vsMatch) { return { org: vsMatch[1]!, project: vsMatch[2]!, repo: vsMatch[3]! }; diff --git a/packages/squad-sdk/templates/ceremony-reference.md b/packages/squad-sdk/templates/ceremony-reference.md new file mode 100644 index 000000000..78995215a --- /dev/null +++ b/packages/squad-sdk/templates/ceremony-reference.md @@ -0,0 +1,82 @@ +# Ceremony Reference + +On-demand reference for ceremony configuration, facilitator spawn, and execution rules. + +## Config Format + +Ceremonies are declared in `.squad/ceremonies.md`. Each ceremony is a section with a table of fields: + +```markdown +## {CeremonyName} + +| Field | Value | +|-------|-------| +| **Trigger** | auto \| manual | +| **When** | before \| after | +| **Condition** | {when auto-triggered: natural language condition} | +| **Facilitator** | lead \| {specific-agent} | +| **Participants** | all-relevant \| all-involved \| {comma-separated names} | +| **Time budget** | focused \| extended | +| **Enabled** | ✅ yes \| ❌ no | + +**Agenda:** +1. {Step 1} +2. {Step 2} +... +``` + +### Field Definitions + +| Field | Values | Meaning | +|-------|--------|---------| +| Trigger | `auto` | Fires automatically when Condition matches | +| Trigger | `manual` | Only when user says "run {ceremony}" | +| When | `before` | Runs before work batch spawns | +| When | `after` | Runs after work batch completes | +| Condition | free text | Evaluated against current task context | +| Facilitator | agent name | Who runs the meeting | +| Participants | selector | Who attends | +| Time budget | `focused` | Keep it short — key decisions only | +| Time budget | `extended` | Thorough discussion — all angles | +| Enabled | boolean | Skip disabled ceremonies entirely | + +## Facilitator Spawn Template + +When a ceremony triggers, spawn the facilitator (sync) with this prompt structure: + +``` +You are {FacilitatorName}, facilitating the "{CeremonyName}" ceremony. + +PARTICIPANTS: {participant list} +TRIGGER CONDITION: {what triggered this ceremony} +AGENDA: +{numbered agenda items from config} + +RULES: +- Follow the agenda in order. +- For each agenda item, spawn relevant participants as sub-tasks to gather their input. +- Synthesize participant input into clear decisions and action items. +- Keep to the time budget: {focused|extended}. +- Output a structured summary at the end. + +TASK CONTEXT: +{description of the work that triggered this ceremony} +``` + +## Execution Rules + +1. **Before ceremonies** fire AFTER routing decisions but BEFORE agent spawn. The ceremony summary is included in all subsequent work-batch spawn prompts. +2. **After ceremonies** fire when ALL agents in the batch have completed (success or failure). +3. **Manual ceremonies** fire only on explicit user request ("run retro", "do a design review"). +4. **Cooldown:** After a ceremony completes, skip auto-trigger checks for the immediately following step. This prevents ceremony loops. +5. **Participant resolution:** + - `all-relevant` → agents routed to the current task + - `all-involved` → agents that participated in the completed batch + - Named agents → spawn only those specific agents +6. **Scribe integration:** Spawn Scribe (background) at ceremony start to record decisions and action items. +7. **Output format:** + ``` + 📋 {CeremonyName} completed — facilitated by {Facilitator}. + Decisions: {count} | Action items: {count}. + ``` +8. **Failure handling:** If the facilitator fails or times out, log a warning and proceed with work. Ceremonies must never block the pipeline indefinitely. diff --git a/packages/squad-sdk/templates/copilot-agent.md b/packages/squad-sdk/templates/copilot-agent.md new file mode 100644 index 000000000..e8ae4612c --- /dev/null +++ b/packages/squad-sdk/templates/copilot-agent.md @@ -0,0 +1,96 @@ +# Copilot Coding Agent Member + +On-demand reference for adding the GitHub Copilot coding agent (@copilot) to the Squad roster. + +## Adding @copilot + +When the user says "add copilot", "add the coding agent", or "use @copilot for issues": + +1. **Add to team.md roster:** + ```markdown + | @copilot | Coding Agent | — | 🤖 Coding Agent | + ``` +2. **Add capability profile** (below the roster table): + ```markdown + + ### @copilot — Capability Profile + + | Capability | Level | Notes | + |-----------|-------|-------| + | Bug fixes (well-scoped) | 🟢 | Best for isolated, test-covered fixes | + | Feature implementation | 🟡 | Works well with clear specs; may need review | + | Refactoring | 🟡 | Handles mechanical refactors; verify scope | + | Architecture decisions | 🔴 | Cannot make cross-cutting design choices | + | Multi-repo coordination | 🔴 | Limited to single-repo context | + | Test writing | 🟢 | Strong at adding tests for existing code | + | Documentation | 🟢 | Generates docs from code effectively | + ``` +3. **Add routing entries** to routing.md for appropriate work types. +4. **Do not create** `charter.md` — @copilot uses `copilot-instructions.md` instead. + +## Comparison: Spawned Agent vs. @copilot + +| | Spawned Agent | @copilot | +|---|--------------|----------| +| Execution model | Sync sub-task within session | Async — picks up assigned issues | +| Branch convention | `squad/{issue}-{slug}` | `copilot/{slug}` | +| Trigger | Coordinator spawns directly | Issue assignment | +| Charter source | `.squad/agents/{name}/charter.md` | `.github/copilot-instructions.md` | +| Context window | Inherits full session context | Fresh context per issue | +| Reviewer gating | ✅ Enforced by coordinator | ✅ Via PR review process | +| Speed | Immediate (in-session) | Minutes (async queue) | + +## Roster Format + +In `team.md`, @copilot always appears as: + +```markdown +| @copilot | Coding Agent | — | 🤖 Coding Agent | +``` + +- **No casting** — always "@copilot" (literal handle). +- **No charter file** — configuration lives in `.github/copilot-instructions.md`. +- **No history file** — work is tracked via PRs and issue comments. + +## Auto-Assign Behavior + +Controlled by the HTML comment in team.md: + +```markdown + +``` + +| Setting | Behavior | +|---------|----------| +| `true` | Lead assigns routed issues to @copilot automatically via `gh issue edit --add-assignee @copilot` | +| `false` | Lead presents recommendation; user confirms before assignment | + +## Lead Triage Integration + +During triage, Lead evaluates each issue against @copilot's capability profile: + +1. **🟢 Match** — Auto-assign (if enabled) or recommend assignment. +2. **🟡 Match** — Assign with note: "⚠️ May need review — @copilot is 🟡 for this type of work." +3. **🔴 Match** — Skip @copilot; route to appropriate spawned agent or human. + +## Routing Details + +Add to `routing.md`: + +```markdown +| bug fixes (isolated, test-covered) | @copilot 🤖 | Single-file fixes, test additions | +| documentation updates | @copilot 🤖 | README, API docs, inline comments | +| test coverage gaps | @copilot 🤖 | Adding missing test cases | +``` + +Work that routes to @copilot: +- Creates/assigns the GitHub issue (if not already) +- Does NOT spawn a sub-agent — @copilot works asynchronously +- Coordinator reports: "🤖 Assigned #{number} to @copilot — will open a PR when ready." +- Non-dependent work continues immediately — @copilot routing does not serialize the team. + +## Monitoring @copilot Work + +On each watch cycle (or when user asks "status"): +- Check for open PRs from `copilot/*` branches. +- Report: "🤖 @copilot: {N} PRs open ({list}). {M} issues assigned, pending." diff --git a/packages/squad-sdk/templates/prd-intake.md b/packages/squad-sdk/templates/prd-intake.md new file mode 100644 index 000000000..4bc2438c6 --- /dev/null +++ b/packages/squad-sdk/templates/prd-intake.md @@ -0,0 +1,105 @@ +# PRD Intake + +On-demand reference for ingesting a PRD, decomposing it into work items, and managing updates. + +## Triggers + +| User says | Action | +|-----------|--------| +| "here's the PRD" / "work from this spec" | Expect file path or pasted content | +| "read the PRD at {path}" | Read the file at that path | +| "the PRD changed" / "updated the spec" | Re-read and diff against previous decomposition | +| (pastes requirements text) | Treat as inline PRD | + +## Intake Flow + +1. **Detect source:** File path, pasted text, or URL. Store a reference in `.squad/team.md` under `## PRD Source`. +2. **Store PRD reference:** + ```markdown + ## PRD Source + + **Path:** {path-or-inline} + **Ingested:** {ISO date} + **Hash:** {sha256 of content, for change detection} + ``` +3. **Spawn Lead (sync, premium bump)** with decomposition prompt (see below). +4. **Present work items** to user for approval in table format. +5. **On approval:** Route items to agents respecting dependency order. + +## Lead Decomposition Spawn Template + +``` +You are the Lead, decomposing a PRD into actionable work items. + +PRD CONTENT: +{full PRD text} + +TEAM ROSTER: +{roster from team.md} + +TASK: Break this PRD into discrete, implementable work items. For each item provide: +- Title (imperative mood, concise) +- Description (acceptance criteria, technical notes) +- Estimated complexity: S / M / L +- Dependencies (list other item titles this blocks on) +- Suggested assignee (agent name from roster, based on expertise match) + +OUTPUT FORMAT: +Return a markdown table: + +| # | Title | Complexity | Dependencies | Assignee | Status | +|---|-------|-----------|--------------|----------|--------| +| 1 | {title} | {S/M/L} | — | {agent} | pending | + +RULES: +- Items must be independently implementable (no item requires partial completion of another). +- Maximum 1 day of work per item (split larger items). +- Respect team expertise — don't assign frontend work to a backend specialist. +- Order by dependency graph (items with no deps first). +- Flag any ambiguities or missing information as "⚠️ Needs clarification: {question}". +``` + +## Work Item Presentation Format + +Present to user as: + +``` +📋 PRD decomposed into {N} work items: + +| # | Title | Size | Depends on | Assignee | +|---|-------|------|-----------|----------| +| 1 | ... | S | — | {Agent} | +| 2 | ... | M | #1 | {Agent} | + +Ready to proceed? I'll route items respecting the dependency order. +⚠️ Clarifications needed: {list any flagged items} +``` + +## Mid-Project Updates + +When the user says the PRD changed: + +1. Re-read the PRD content. +2. Compute diff against stored hash. +3. Spawn Lead (sync) with a delta-decomposition prompt: + - Show only NEW or CHANGED sections. + - Ask Lead to identify: new items, modified items, obsoleted items. +4. Present changes to user: + ``` + 📋 PRD update detected: + - New items: {count} + - Modified: {count} + - Obsoleted: {count} (will be cancelled if approved) + + {table of changes} + + Approve these updates? + ``` +5. On approval: Cancel obsoleted work (if not yet started), update items, re-route. + +## State Tracking + +Active PRD state lives in team.md: +- `## PRD Source` section (path, date, hash) +- Work items tracked as issues (GitHub) or in `.squad/backlog.md` (offline mode) +- Completion percentage displayed in status checks diff --git a/templates/ceremony-reference.md b/templates/ceremony-reference.md new file mode 100644 index 000000000..78995215a --- /dev/null +++ b/templates/ceremony-reference.md @@ -0,0 +1,82 @@ +# Ceremony Reference + +On-demand reference for ceremony configuration, facilitator spawn, and execution rules. + +## Config Format + +Ceremonies are declared in `.squad/ceremonies.md`. Each ceremony is a section with a table of fields: + +```markdown +## {CeremonyName} + +| Field | Value | +|-------|-------| +| **Trigger** | auto \| manual | +| **When** | before \| after | +| **Condition** | {when auto-triggered: natural language condition} | +| **Facilitator** | lead \| {specific-agent} | +| **Participants** | all-relevant \| all-involved \| {comma-separated names} | +| **Time budget** | focused \| extended | +| **Enabled** | ✅ yes \| ❌ no | + +**Agenda:** +1. {Step 1} +2. {Step 2} +... +``` + +### Field Definitions + +| Field | Values | Meaning | +|-------|--------|---------| +| Trigger | `auto` | Fires automatically when Condition matches | +| Trigger | `manual` | Only when user says "run {ceremony}" | +| When | `before` | Runs before work batch spawns | +| When | `after` | Runs after work batch completes | +| Condition | free text | Evaluated against current task context | +| Facilitator | agent name | Who runs the meeting | +| Participants | selector | Who attends | +| Time budget | `focused` | Keep it short — key decisions only | +| Time budget | `extended` | Thorough discussion — all angles | +| Enabled | boolean | Skip disabled ceremonies entirely | + +## Facilitator Spawn Template + +When a ceremony triggers, spawn the facilitator (sync) with this prompt structure: + +``` +You are {FacilitatorName}, facilitating the "{CeremonyName}" ceremony. + +PARTICIPANTS: {participant list} +TRIGGER CONDITION: {what triggered this ceremony} +AGENDA: +{numbered agenda items from config} + +RULES: +- Follow the agenda in order. +- For each agenda item, spawn relevant participants as sub-tasks to gather their input. +- Synthesize participant input into clear decisions and action items. +- Keep to the time budget: {focused|extended}. +- Output a structured summary at the end. + +TASK CONTEXT: +{description of the work that triggered this ceremony} +``` + +## Execution Rules + +1. **Before ceremonies** fire AFTER routing decisions but BEFORE agent spawn. The ceremony summary is included in all subsequent work-batch spawn prompts. +2. **After ceremonies** fire when ALL agents in the batch have completed (success or failure). +3. **Manual ceremonies** fire only on explicit user request ("run retro", "do a design review"). +4. **Cooldown:** After a ceremony completes, skip auto-trigger checks for the immediately following step. This prevents ceremony loops. +5. **Participant resolution:** + - `all-relevant` → agents routed to the current task + - `all-involved` → agents that participated in the completed batch + - Named agents → spawn only those specific agents +6. **Scribe integration:** Spawn Scribe (background) at ceremony start to record decisions and action items. +7. **Output format:** + ``` + 📋 {CeremonyName} completed — facilitated by {Facilitator}. + Decisions: {count} | Action items: {count}. + ``` +8. **Failure handling:** If the facilitator fails or times out, log a warning and proceed with work. Ceremonies must never block the pipeline indefinitely. diff --git a/templates/copilot-agent.md b/templates/copilot-agent.md new file mode 100644 index 000000000..e8ae4612c --- /dev/null +++ b/templates/copilot-agent.md @@ -0,0 +1,96 @@ +# Copilot Coding Agent Member + +On-demand reference for adding the GitHub Copilot coding agent (@copilot) to the Squad roster. + +## Adding @copilot + +When the user says "add copilot", "add the coding agent", or "use @copilot for issues": + +1. **Add to team.md roster:** + ```markdown + | @copilot | Coding Agent | — | 🤖 Coding Agent | + ``` +2. **Add capability profile** (below the roster table): + ```markdown + + ### @copilot — Capability Profile + + | Capability | Level | Notes | + |-----------|-------|-------| + | Bug fixes (well-scoped) | 🟢 | Best for isolated, test-covered fixes | + | Feature implementation | 🟡 | Works well with clear specs; may need review | + | Refactoring | 🟡 | Handles mechanical refactors; verify scope | + | Architecture decisions | 🔴 | Cannot make cross-cutting design choices | + | Multi-repo coordination | 🔴 | Limited to single-repo context | + | Test writing | 🟢 | Strong at adding tests for existing code | + | Documentation | 🟢 | Generates docs from code effectively | + ``` +3. **Add routing entries** to routing.md for appropriate work types. +4. **Do not create** `charter.md` — @copilot uses `copilot-instructions.md` instead. + +## Comparison: Spawned Agent vs. @copilot + +| | Spawned Agent | @copilot | +|---|--------------|----------| +| Execution model | Sync sub-task within session | Async — picks up assigned issues | +| Branch convention | `squad/{issue}-{slug}` | `copilot/{slug}` | +| Trigger | Coordinator spawns directly | Issue assignment | +| Charter source | `.squad/agents/{name}/charter.md` | `.github/copilot-instructions.md` | +| Context window | Inherits full session context | Fresh context per issue | +| Reviewer gating | ✅ Enforced by coordinator | ✅ Via PR review process | +| Speed | Immediate (in-session) | Minutes (async queue) | + +## Roster Format + +In `team.md`, @copilot always appears as: + +```markdown +| @copilot | Coding Agent | — | 🤖 Coding Agent | +``` + +- **No casting** — always "@copilot" (literal handle). +- **No charter file** — configuration lives in `.github/copilot-instructions.md`. +- **No history file** — work is tracked via PRs and issue comments. + +## Auto-Assign Behavior + +Controlled by the HTML comment in team.md: + +```markdown + +``` + +| Setting | Behavior | +|---------|----------| +| `true` | Lead assigns routed issues to @copilot automatically via `gh issue edit --add-assignee @copilot` | +| `false` | Lead presents recommendation; user confirms before assignment | + +## Lead Triage Integration + +During triage, Lead evaluates each issue against @copilot's capability profile: + +1. **🟢 Match** — Auto-assign (if enabled) or recommend assignment. +2. **🟡 Match** — Assign with note: "⚠️ May need review — @copilot is 🟡 for this type of work." +3. **🔴 Match** — Skip @copilot; route to appropriate spawned agent or human. + +## Routing Details + +Add to `routing.md`: + +```markdown +| bug fixes (isolated, test-covered) | @copilot 🤖 | Single-file fixes, test additions | +| documentation updates | @copilot 🤖 | README, API docs, inline comments | +| test coverage gaps | @copilot 🤖 | Adding missing test cases | +``` + +Work that routes to @copilot: +- Creates/assigns the GitHub issue (if not already) +- Does NOT spawn a sub-agent — @copilot works asynchronously +- Coordinator reports: "🤖 Assigned #{number} to @copilot — will open a PR when ready." +- Non-dependent work continues immediately — @copilot routing does not serialize the team. + +## Monitoring @copilot Work + +On each watch cycle (or when user asks "status"): +- Check for open PRs from `copilot/*` branches. +- Report: "🤖 @copilot: {N} PRs open ({list}). {M} issues assigned, pending." diff --git a/templates/prd-intake.md b/templates/prd-intake.md new file mode 100644 index 000000000..4bc2438c6 --- /dev/null +++ b/templates/prd-intake.md @@ -0,0 +1,105 @@ +# PRD Intake + +On-demand reference for ingesting a PRD, decomposing it into work items, and managing updates. + +## Triggers + +| User says | Action | +|-----------|--------| +| "here's the PRD" / "work from this spec" | Expect file path or pasted content | +| "read the PRD at {path}" | Read the file at that path | +| "the PRD changed" / "updated the spec" | Re-read and diff against previous decomposition | +| (pastes requirements text) | Treat as inline PRD | + +## Intake Flow + +1. **Detect source:** File path, pasted text, or URL. Store a reference in `.squad/team.md` under `## PRD Source`. +2. **Store PRD reference:** + ```markdown + ## PRD Source + + **Path:** {path-or-inline} + **Ingested:** {ISO date} + **Hash:** {sha256 of content, for change detection} + ``` +3. **Spawn Lead (sync, premium bump)** with decomposition prompt (see below). +4. **Present work items** to user for approval in table format. +5. **On approval:** Route items to agents respecting dependency order. + +## Lead Decomposition Spawn Template + +``` +You are the Lead, decomposing a PRD into actionable work items. + +PRD CONTENT: +{full PRD text} + +TEAM ROSTER: +{roster from team.md} + +TASK: Break this PRD into discrete, implementable work items. For each item provide: +- Title (imperative mood, concise) +- Description (acceptance criteria, technical notes) +- Estimated complexity: S / M / L +- Dependencies (list other item titles this blocks on) +- Suggested assignee (agent name from roster, based on expertise match) + +OUTPUT FORMAT: +Return a markdown table: + +| # | Title | Complexity | Dependencies | Assignee | Status | +|---|-------|-----------|--------------|----------|--------| +| 1 | {title} | {S/M/L} | — | {agent} | pending | + +RULES: +- Items must be independently implementable (no item requires partial completion of another). +- Maximum 1 day of work per item (split larger items). +- Respect team expertise — don't assign frontend work to a backend specialist. +- Order by dependency graph (items with no deps first). +- Flag any ambiguities or missing information as "⚠️ Needs clarification: {question}". +``` + +## Work Item Presentation Format + +Present to user as: + +``` +📋 PRD decomposed into {N} work items: + +| # | Title | Size | Depends on | Assignee | +|---|-------|------|-----------|----------| +| 1 | ... | S | — | {Agent} | +| 2 | ... | M | #1 | {Agent} | + +Ready to proceed? I'll route items respecting the dependency order. +⚠️ Clarifications needed: {list any flagged items} +``` + +## Mid-Project Updates + +When the user says the PRD changed: + +1. Re-read the PRD content. +2. Compute diff against stored hash. +3. Spawn Lead (sync) with a delta-decomposition prompt: + - Show only NEW or CHANGED sections. + - Ask Lead to identify: new items, modified items, obsoleted items. +4. Present changes to user: + ``` + 📋 PRD update detected: + - New items: {count} + - Modified: {count} + - Obsoleted: {count} (will be cancelled if approved) + + {table of changes} + + Approve these updates? + ``` +5. On approval: Cancel obsoleted work (if not yet started), update items, re-route. + +## State Tracking + +Active PRD state lives in team.md: +- `## PRD Source` section (path, date, hash) +- Work items tracked as issues (GitHub) or in `.squad/backlog.md` (offline mode) +- Completion percentage displayed in status checks diff --git a/test/platform-adapter.test.ts b/test/platform-adapter.test.ts index c14748973..86a6324d7 100644 --- a/test/platform-adapter.test.ts +++ b/test/platform-adapter.test.ts @@ -96,6 +96,21 @@ describe('parseGitHubRemote', () => { // trailing slash is not standard git remote but shouldn't crash expect(parseGitHubRemote('https://github.com/owner/')).toBeNull(); }); + + it('parses repo name containing dots (HTTPS)', () => { + const result = parseGitHubRemote('https://github.com/owner/my.repo.name'); + expect(result).toEqual({ owner: 'owner', repo: 'my.repo.name' }); + }); + + it('parses repo name containing dots with .git suffix', () => { + const result = parseGitHubRemote('https://github.com/owner/my.repo.name.git'); + expect(result).toEqual({ owner: 'owner', repo: 'my.repo.name' }); + }); + + it('parses SSH repo name containing dots', () => { + const result = parseGitHubRemote('git@github.com:org/api.service.git'); + expect(result).toEqual({ owner: 'org', repo: 'api.service' }); + }); }); // ─── Azure DevOps Remote Parsing ─────────────────────────────────────── @@ -152,6 +167,26 @@ describe('parseAzureDevOpsRemote', () => { const result = parseAzureDevOpsRemote('https://dev.azure.com/org/My-Project/_git/my-repo'); expect(result).toEqual({ org: 'org', project: 'My-Project', repo: 'my-repo' }); }); + + it('parses repo name containing dots (HTTPS)', () => { + const result = parseAzureDevOpsRemote('https://dev.azure.com/myorg/myproject/_git/my.service.api'); + expect(result).toEqual({ org: 'myorg', project: 'myproject', repo: 'my.service.api' }); + }); + + it('parses repo name containing dots with .git suffix', () => { + const result = parseAzureDevOpsRemote('https://dev.azure.com/myorg/myproject/_git/my.service.api.git'); + expect(result).toEqual({ org: 'myorg', project: 'myproject', repo: 'my.service.api' }); + }); + + it('parses SSH repo name containing dots', () => { + const result = parseAzureDevOpsRemote('git@ssh.dev.azure.com:v3/myorg/myproject/core.lib.git'); + expect(result).toEqual({ org: 'myorg', project: 'myproject', repo: 'core.lib' }); + }); + + it('parses visualstudio.com repo name containing dots', () => { + const result = parseAzureDevOpsRemote('https://contoso.visualstudio.com/WebApp/_git/api.service.git'); + expect(result).toEqual({ org: 'contoso', project: 'WebApp', repo: 'api.service' }); + }); }); // ─── WorkItem Type Shape ───────────────────────────────────────────────