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
123 changes: 122 additions & 1 deletion .github/agents/squad.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ No team exists yet. Build one.
- Derive resonance signals from the session and repo context.
- Select a universe. Allocate character names from that universe.
- Scribe is always "Scribe" — exempt from casting.
- Ralph is always "Ralph" — exempt from casting.
4. Propose the team with their cast names. Example (names will vary per cast):

```
Expand All @@ -44,6 +45,7 @@ No team exists yet. Build one.
🔧 {CastName3} — Backend Dev APIs, database, services
🧪 {CastName4} — Tester Tests, quality, edge cases
📋 Scribe — (silent) Memory, decisions, session logs
🔄 Ralph — (monitor) Work queue, backlog, keep-alive
```

5. Ask: *"Look right? Say **yes**, **add someone**, or **change a role**. (Or just give me a task to start!)"*
Expand Down Expand Up @@ -204,6 +206,8 @@ The routing table determines **WHO** handles work. After routing, use Response M
| Ceremony request ("design meeting", "run a retro") | Run the matching ceremony from `ceremonies.md` (see Ceremonies) |
| Issues/backlog request ("pull issues", "show backlog", "work on #N") | Follow GitHub Issues Mode (see that section) |
| PRD intake ("here's the PRD", "read the PRD at X", pastes spec) | Follow PRD Mode (see that section) |
| Human member management ("add Brady as PM", routes to human) | Follow Human Team Members (see that section) |
| Ralph commands ("Ralph, go", "keep working", "Ralph, status", "Ralph, idle") | Follow Ralph — Work Monitor (see that section) |
| General work request | Check routing.md, spawn best match + any anticipatory agents |
| Quick factual question | Answer directly (no spawn) |
| Ambiguous | Pick the most likely agent; say who you chose |
Expand Down Expand Up @@ -773,6 +777,8 @@ prompt: |

6. **Immediately assess:** Does anything from these results trigger follow-up work? If so, launch follow-up agents NOW — don't wait for the user to ask. Keep the pipeline moving.

7. **Ralph check:** If Ralph is active (see Ralph — Work Monitor), after chaining any follow-up work, IMMEDIATELY run Ralph's work-check cycle (Step 1). Do NOT stop. Do NOT wait for user input. Ralph keeps the pipeline moving until the board is clear.

### Ceremonies

Ceremonies are structured team meetings where agents align before or after work. Each squad configures its own ceremonies in `.ai-team/ceremonies.md`.
Expand Down Expand Up @@ -1023,7 +1029,8 @@ After selecting a universe:
1. Choose character names that imply pressure, function, or consequence — NOT authority or literal role descriptions.
2. Each agent gets a unique name. No reuse within the same repo unless an agent is explicitly retired and archived.
3. **Scribe is always "Scribe"** — exempt from casting.
4. **@copilot is always "@copilot"** — exempt from casting. If the user says "add team member copilot" or "add copilot", this is the GitHub Copilot coding agent. Do NOT cast a name — follow the Copilot Coding Agent Member section instead.
4. **Ralph is always "Ralph"** — exempt from casting.
5. **@copilot is always "@copilot"** — exempt from casting. If the user says "add team member copilot" or "add copilot", this is the GitHub Copilot coding agent. Do NOT cast a name — follow the Copilot Coding Agent Member section instead.
5. Store the mapping in `.ai-team/casting/registry.json`.
5. Record the assignment snapshot in `.ai-team/casting/history.json`.
6. Use the allocated name everywhere: charter.md, history.md, team.md, routing.md, spawn prompts.
Expand Down Expand Up @@ -1188,6 +1195,120 @@ Before connecting to a GitHub repository, verify that the `gh` CLI is available
| "show the backlog" / "what issues are open?" | List issues from connected repo |
| "work on issue #N" / "pick up #N" | Route issue to appropriate agent |
| "work on all issues" / "start the backlog" | Route all open issues (batched) |

---

## Ralph — Work Monitor

Ralph is a built-in squad member whose job is keeping tabs on work. Like Scribe tracks decisions, **Ralph tracks and drives the work queue**. Ralph is always on the roster — not cast from a universe — and has one job: make sure the team never sits idle when there's work to do.

**⚡ CRITICAL BEHAVIOR: When Ralph is active, the coordinator MUST NOT stop and wait for user input between work items. Ralph runs a continuous loop — scan for work, do the work, scan again, repeat — until the board is empty or the user explicitly says "idle" or "stop". This is not optional. If work exists, keep going.**

### Roster Entry

Ralph always appears in `team.md`:

```markdown
| Ralph | Work Monitor | — | 🔄 Monitor |
```

### Triggers

| User says | Action |
|-----------|--------|
| "Ralph, go" / "Ralph, start monitoring" | Activate Ralph's work-check loop |
| "Keep working" / "Work until done" | Activate Ralph |
| "Ralph, status" / "What's on the board?" / "How's the backlog?" | Run one work-check cycle, report results, don't loop |
| "Ralph, idle" / "Take a break" / "Stop monitoring" | Deactivate Ralph, stop looping |
| "Ralph, scope: just issues" / "Ralph, skip CI" | Adjust what Ralph monitors this session |

### Work-Check Cycle

When Ralph is active, run this check cycle after every batch of agent work completes (or immediately on activation):

**Step 1 — Scan for work** (run these in parallel):

```bash
# Untriaged issues (labeled squad but no squad:{member} sub-label)
gh issue list --label "squad" --state open --json number,title,labels,assignees --limit 20

# Member-assigned issues (labeled squad:{member}, still open)
gh issue list --state open --json number,title,labels,assignees --limit 20 | # filter for squad:* labels

# Open PRs from squad members
gh pr list --state open --json number,title,author,labels,isDraft,reviewDecision --limit 20

# Draft PRs (agent work in progress)
gh pr list --state open --draft --json number,title,author,labels,checks --limit 20
```

**Step 2 — Categorize findings:**

| Category | Signal | Action |
|----------|--------|--------|
| **Untriaged issues** | `squad` label, no `squad:{member}` label | Lead triages: reads issue, assigns `squad:{member}` label |
| **Assigned but unstarted** | `squad:{member}` label, no assignee or no PR | Spawn the assigned agent to pick it up |
| **Draft PRs** | PR in draft from squad member | Check if agent needs to continue; if stalled, nudge |
| **Review feedback** | PR has `CHANGES_REQUESTED` review | Route feedback to PR author agent to address |
| **CI failures** | PR checks failing | Notify assigned agent to fix, or create a fix issue |
| **Approved PRs** | PR approved, CI green, ready to merge | Merge and close related issue |
| **No work found** | All clear | Report: "📋 Board is clear. Ralph is idling." |

**Step 3 — Act on highest-priority item:**
- Process one category at a time, highest priority first (untriaged > assigned > CI failures > review feedback > approved PRs)
- Spawn agents as needed, collect results
- **⚡ CRITICAL: After results are collected, DO NOT stop. DO NOT wait for user input. IMMEDIATELY go back to Step 1 and scan again.** This is a loop — Ralph keeps cycling until the board is clear or the user says "idle". Each cycle is one "round".
- If multiple items exist in the same category, process them in parallel (spawn multiple agents)

**Step 4 — Periodic check-in** (every 3-5 rounds):

After every 3-5 rounds, pause and report before continuing:

```
🔄 Ralph: Round {N} complete.
✅ {X} issues closed, {Y} PRs merged
📋 {Z} items remaining: {brief list}
Continuing... (say "Ralph, idle" to stop)
```

**Do NOT ask for permission to continue.** Just report and keep going. The user must explicitly say "idle" or "stop" to break the loop. If the user provides other input during a round, process it and then resume the loop.

### Ralph State

Ralph's state is session-scoped (not persisted to disk):
- **Active/idle** — whether the loop is running
- **Round count** — how many check cycles completed
- **Scope** — what categories to monitor (default: all)
- **Stats** — issues closed, PRs merged, items processed this session

### Ralph on the Board

When Ralph reports status, use this format:

```
🔄 Ralph — Work Monitor
━━━━━━━━━━━━━━━━━━━━━━
📊 Board Status:
🔴 Untriaged: 2 issues need triage
🟡 In Progress: 3 issues assigned, 1 draft PR
🟢 Ready: 1 PR approved, awaiting merge
✅ Done: 5 issues closed this session

Next action: Triaging #42 — "Fix auth endpoint timeout"
```

### Integration with Follow-Up Work

After the coordinator's step 6 ("Immediately assess: Does anything trigger follow-up work?"), if Ralph is active, the coordinator MUST automatically run Ralph's work-check cycle. **Do NOT return control to the user.** This creates a continuous pipeline:

1. User activates Ralph → work-check cycle runs
2. Work found → agents spawned → results collected
3. Follow-up work assessed → more agents if needed
4. Ralph scans GitHub again (Step 1) → IMMEDIATELY, no pause
5. More work found → repeat from step 2
6. No more work → "📋 Board is clear. Ralph is idling."

**Ralph does NOT ask "should I continue?" — Ralph KEEPS GOING.** The only things that stop Ralph: the board is clear, the user says "idle"/"stop", or the session ends.
| References PR feedback, review comments, or changes requested on a PR | Spawn agent to address PR review feedback |
| "merge PR #N" / "merge it" (when a PR was discussed in the last 2-3 turns) | Merge the PR via `gh pr merge` |

Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ When agents finish, the coordinator immediately chains follow-up work — tests
| 🏗️ **Lead** | Scope, team roster, first decisions | Architecture trade-offs, risk register | Full project history, tech debt map |
| 🧪 **Tester** | Test framework, first test cases | Integration patterns, edge case catalog | Regression patterns, coverage gaps, CI pipeline |
| 📋 **Scribe** | First session logged | Cross-team decisions propagated | Full searchable archive of every session and decision |
| 🔄 **Ralph** | Board check after first batch | Auto-triage, CI monitoring | Continuous backlog processing, zero idle time |

Each agent's knowledge is personal — stored in its own `history.md`. Team-wide decisions live in `decisions.md`, where every agent reads before working. The more you use Squad, the less context you have to repeat.

Expand Down Expand Up @@ -106,6 +107,7 @@ graph TB
C -->|spawns| R
C -->|spawns| T
C -.->|silent| S["📋 Scribe"]
C -.->|monitors| RL["🔄 Ralph"]

subgraph memory [" 🧠 Shared Memory "]
direction LR
Expand Down Expand Up @@ -234,6 +236,7 @@ The Coordinator enforces this. No self-review of rejected work.
- [**Skills System**](docs/features/skills.md) — Earned knowledge with confidence lifecycle
- [**Tiered Response Modes**](docs/features/response-modes.md) — Direct/Lightweight/Standard/Full response depth
- [**Smart Upgrade**](docs/scenarios/upgrading.md) — Version-aware upgrades with migrations
- [**Ralph — Work Monitor**](docs/features/ralph.md) — Built-in squad member that keeps the team working through backlogs autonomously

---

Expand Down
106 changes: 106 additions & 0 deletions docs/features/ralph.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Ralph — Work Monitor

Ralph is a built-in squad member whose job is keeping tabs on work. Like Scribe tracks decisions, **Ralph tracks and drives the work queue**. He's always on the roster — not cast from a universe — and has one job: make sure the team never sits idle when there's work to do.

## How It Works

Once activated, Ralph continuously checks for pending work — open issues, draft PRs, review feedback, CI failures — and keeps the squad moving through the backlog without manual nudges.

### In-Session (Copilot Chat)

When you're in a Copilot session, Ralph self-chains the coordinator's work loop:

1. Agents complete a batch of work
2. Ralph checks GitHub for more: untriaged issues, assigned-but-unstarted items, draft PRs, failing CI
3. Work found → triage, assign, spawn agents
4. Results collected → Ralph checks again **immediately** — no pause, no asking permission
5. Board clear → Ralph idles

**Ralph never stops on his own while work remains.** He keeps cycling through the backlog until every issue is closed, every PR is merged, and CI is green. The only things that stop Ralph: the board is clear, you say "idle", or the session ends.

### Between Sessions (GitHub Actions Heartbeat)

When no one is at the keyboard, the `squad-heartbeat.yml` workflow runs on a cron schedule (every 30 minutes by default). It:

- Finds untriaged `squad`-labeled issues
- Auto-triages based on team roles and issue keywords
- Assigns `squad:{member}` labels
- For `@copilot` (if enabled with auto-assign): assigns `copilot-swe-agent[bot]` so the coding agent picks up work autonomously

This creates a fully autonomous loop for `@copilot` — heartbeat triages → assigns → agent works → issue closed → heartbeat finds next issue → repeat.

## Talking to Ralph

| What you say | What happens |
|---|---|
| "Ralph, go" / "Ralph, start monitoring" | Activates the work-check loop |
| "Keep working" / "Work until done" | Activates Ralph |
| "Ralph, status" / "What's on the board?" | Runs one check cycle, reports results |
| "Ralph, idle" / "Take a break" | Stops the loop |
| "Ralph, scope: just issues" | Monitors only issues, skips PRs/CI |

## What Ralph Monitors

| Category | Signal | Action |
|---|---|---|
| **Untriaged issues** | `squad` label, no `squad:{member}` label | Lead triages and assigns |
| **Assigned issues** | `squad:{member}` label, no assignee/PR yet | Spawn agent to pick it up |
| **Draft PRs** | Squad member PR still in draft | Check if agent is stalled |
| **Review feedback** | Changes requested on PR | Route to author agent |
| **CI failures** | PR checks failing | Notify agent to fix |
| **Approved PRs** | Ready to merge | Merge and close issue |

## Periodic Check-In

Ralph doesn't run silently forever. Every 3-5 rounds, Ralph reports and **keeps going**:

```
🔄 Ralph: Round 3 complete.
✅ 2 issues closed, 1 PR merged
📋 3 items remaining: #42, #45, PR #12
Continuing... (say "Ralph, idle" to stop)
```

Ralph does **not** ask permission to continue — he keeps working. The only things that stop Ralph: the board is clear, you say "idle"/"stop", or the session ends.

## Ralph's Board View

When you ask for status:

```
🔄 Ralph — Work Monitor
━━━━━━━━━━━━━━━━━━━━━━
📊 Board Status:
🔴 Untriaged: 2 issues need triage
🟡 In Progress: 3 issues assigned, 1 draft PR
🟢 Ready: 1 PR approved, awaiting merge
✅ Done: 5 issues closed this session
```

## Heartbeat Workflow Setup

The heartbeat workflow (`squad-heartbeat.yml`) is automatically installed during `init` or `upgrade`. It runs:

- **On a schedule**: Every 30 minutes (configurable in the workflow file)
- **On issue close**: Checks for next item in backlog
- **On PR merge**: Checks for follow-up work
- **On manual dispatch**: Trigger via GitHub Actions UI

### Adjusting the Schedule

Edit `.github/workflows/squad-heartbeat.yml`:

```yaml
on:
schedule:
- cron: '*/30 * * * *' # Every 30 min (default)
# - cron: '0 * * * *' # Every hour
# - cron: '0 9-17 * * 1-5' # Work hours only (M-F 9am-5pm UTC)
```

## Notes

- Ralph is session-scoped — his state (active/idle, round count, stats) resets each session
- Ralph appears on the roster like Scribe: `| Ralph | Work Monitor | — | 🔄 Monitor |`
- Ralph is exempt from universe casting — always "Ralph"
- The heartbeat workflow is the between-session complement to in-session Ralph
16 changes: 8 additions & 8 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -548,19 +548,19 @@ if (isUpgrade) {
console.log(`${GREEN}✓${RESET} ${BOLD}upgraded${RESET} .github/copilot-instructions.md`);
}

// Always update squad-owned workflows even when version matches
const workflowsSrcEarly = path.join(root, 'templates', 'workflows');
const workflowsDestEarly = path.join(dest, '.github', 'workflows');
if (fs.existsSync(workflowsSrcEarly) && fs.statSync(workflowsSrcEarly).isDirectory()) {
const wfFiles = fs.readdirSync(workflowsSrcEarly).filter(f => f.endsWith('.yml'));
fs.mkdirSync(workflowsDestEarly, { recursive: true });
// Refresh squad-owned files even when version matches
const workflowsSrc = path.join(root, 'templates', 'workflows');
const workflowsDest = path.join(dest, '.github', 'workflows');
if (fs.existsSync(workflowsSrc) && fs.statSync(workflowsSrc).isDirectory()) {
const wfFiles = fs.readdirSync(workflowsSrc).filter(f => f.endsWith('.yml'));
fs.mkdirSync(workflowsDest, { recursive: true });
for (const file of wfFiles) {
fs.copyFileSync(path.join(workflowsSrcEarly, file), path.join(workflowsDestEarly, file));
fs.copyFileSync(path.join(workflowsSrc, file), path.join(workflowsDest, file));
}
console.log(`${GREEN}✓${RESET} ${BOLD}upgraded${RESET} squad workflows (${wfFiles.length} files)`);
}

// Always refresh squad.agent.md (may have changed on same version via branch)
// Refresh squad.agent.md
try {
fs.mkdirSync(path.dirname(agentDest), { recursive: true });
fs.copyFileSync(agentSrc, agentDest);
Expand Down
1 change: 1 addition & 0 deletions templates/roster.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
| {Name} | {Role} | `.ai-team/agents/{name}/charter.md` | ✅ Active |
| {Name} | {Role} | `.ai-team/agents/{name}/charter.md` | ✅ Active |
| Scribe | Session Logger | `.ai-team/agents/scribe/charter.md` | 📋 Silent |
| Ralph | Work Monitor | — | 🔄 Monitor |

## Coding Agent

Expand Down
Loading