Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/fix-five-bugs-dotted-repos.md
Original file line number Diff line number Diff line change
@@ -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
82 changes: 82 additions & 0 deletions .squad-templates/ceremony-reference.md
Original file line number Diff line number Diff line change
@@ -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.
96 changes: 96 additions & 0 deletions .squad-templates/copilot-agent.md
Original file line number Diff line number Diff line change
@@ -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-auto-assign: true -->
### @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
<!-- copilot-auto-assign: true -->
```

| 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."
105 changes: 105 additions & 0 deletions .squad-templates/prd-intake.md
Original file line number Diff line number Diff line change
@@ -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
11 changes: 10 additions & 1 deletion packages/squad-cli/src/cli-entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,15 @@ async function main(): Promise<void> {
: { 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]! };
}
Comment on lines +549 to +556

// Load config: .squad/config.json merged with CLI overrides
const config = loadWatchConfig(getSquadStartDir(), {
interval,
Expand All @@ -570,7 +579,7 @@ async function main(): Promise<void> {
// 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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,14 @@ export class BoardCapability implements WatchCapability {

async execute(context: WatchContext): Promise<CapabilityResult> {
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 });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
}
Comment on lines +154 to +161

const fullPrompt = charterPrefix + prompt;
const { cmd, args } = buildAgentCommand(fullPrompt, context);

return new Promise<{ success: boolean; error?: string }>((resolve) => {
const cp: ChildProcess = execFile(
Expand Down
2 changes: 1 addition & 1 deletion packages/squad-cli/src/cli/shell/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ export const App: React.FC<AppProps> = ({ 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--) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ export const MessageStream: React.FC<MessageStreamProps> = ({
{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;

Expand Down Expand Up @@ -303,7 +303,7 @@ export const MessageStream: React.FC<MessageStreamProps> = ({
<Text color={noColor ? undefined : 'green'} bold>
{roleMap.has(agentName)
? `${getRoleEmoji(roleMap.get(agentName)!)} `
: ''}
: `${getRoleEmoji(agentName)} `}
{agentName === 'coordinator' ? 'Squad' : agentName}:
</Text>
<Text wrap="wrap">{renderMarkdownInline(wrapTableContent(content, contentWidth, tier))}</Text>
Expand Down
Loading
Loading