diff --git a/CHANGELOG.md b/CHANGELOG.md index f4651c121..5dab04371 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Added — Full Work Monitor for squad watch (#708) +- `--execute` flag spawns Copilot sessions to work on actionable issues autonomously +- Multi-platform support — auto-detects GitHub vs Azure DevOps from git remote URL +- Azure DevOps support: uses SDK PlatformAdapter for work items, tags, and PRs +- `--monitor-teams` / `--monitor-email` scan Teams/email for actionable items via WorkIQ +- `--board` enables project board lifecycle (In Progress → Done/Blocked + reconciliation) +- `--two-pass` lightweight scan then hydrate only actionable issues (saves API quota) +- `--wave-dispatch` parallel sub-task execution within issues (dependency-aware) +- `--retro` enforces retrospective checks (Fridays or when missed >7 days) +- `--decision-hygiene` auto-merges decision inbox when >5 files +- `--max-concurrent N` controls parallel issue execution (default: 1) +- `--timeout N` sets per-issue execution timeout in minutes (default: 30) +- `--copilot-flags "..."` passes extra flags to Copilot CLI sessions +- SubSquad discovery: automatically detects `.squad/subsquads/` for routing +- All features disabled by default — existing `squad watch` behavior unchanged + ### Added — StorageProvider Abstraction Layer - **StorageProvider interface** (#640) — pluggable I/O contract decoupling the runtime from `node:fs` - **FSStorageProvider** (#640) — Node.js `fs` wrapper, default provider for CLI and local workflows diff --git a/docs/src/content/blog/watch-monitor.md b/docs/src/content/blog/watch-monitor.md new file mode 100644 index 000000000..2f4383302 --- /dev/null +++ b/docs/src/content/blog/watch-monitor.md @@ -0,0 +1,174 @@ +--- +title: "From Triage Bot to Work Monitor" +date: 2026-03-30 +author: "Brady" +tags: [squad, ralph, watch, work-monitor, automation, execution] +status: published +hero: "Ralph started as a label router that idled when the board was clear. Now he spawns Copilot sessions and actually does the work." +--- + +# From Triage Bot to Work Monitor + +> ⚠️ **Experimental** — Squad is alpha software. APIs, commands, and behavior may change between releases. + +> _Ralph started as a label router that idled when the board was clear. Now he spawns Copilot sessions and actually does the work._ + +## What Changed + +`squad watch` used to be a simple triage loop. Every N minutes, it would: + +1. Fetch open issues with the `squad` label +2. Route them to team members based on routing rules +3. Add labels like `squad:eecom` or `squad:gnc` +4. Idle when done + +That's it. Ralph was a label router — useful, but not autonomous. When the board cleared, Ralph just sat there waiting for humans to do the work. + +**Issue #708 changed that.** + +With `--execute`, Ralph transforms from a triage bot into a full work monitor. He doesn't just label issues — he spawns Copilot CLI sessions to actually work on them. + +```bash +squad watch --execute --interval 15 +``` + +This one flag turns Ralph from a watcher into a worker. + +## The Unix Pipe Philosophy + +The design follows the Unix philosophy: each flag is a composable feature that does one thing well. + +- `--execute` → spawn Copilot sessions for actionable issues +- `--monitor-teams` → scan Teams messages via WorkIQ +- `--monitor-email` → scan email for alerts and action items +- `--board` → manage project board lifecycle (In Progress / Done / Blocked) +- `--two-pass` → lightweight scan, then hydrate only actionable issues +- `--wave-dispatch` → parallel sub-task execution within issues +- `--retro` → enforce retrospective checks (Fridays or >7 days) +- `--decision-hygiene` → auto-merge decision inbox when >5 files + +Each flag is opt-in. Existing `squad watch` behavior is unchanged — triage only, no execution. + +## Code Example: From Simple to Full Monitor + +**Basic triage (original behavior):** +```bash +squad watch +``` + +**Add execution:** +```bash +squad watch --execute +``` + +**Add project board lifecycle:** +```bash +squad watch --execute --board +``` + +**Full monitor with all features:** +```bash +squad watch --execute \ + --board \ + --two-pass \ + --monitor-teams \ + --retro \ + --decision-hygiene \ + --max-concurrent 2 \ + --interval 15 +``` + +## Architecture of a Round + +When all features are enabled, each round follows this cycle: + +1. **Self-pull**: `git fetch && git pull --ff-only` to stay current +2. **Scan**: Fetch open issues (two-pass if enabled: lightweight list → hydrate actionable only) +3. **Triage**: Label untriaged issues based on routing rules +4. **Execute**: Spawn Copilot sessions for actionable issues + - Issues are actionable if: assigned to a squad member, not assigned to a human, and not blocked + - Wave dispatch groups sub-tasks by dependency and runs them in parallel + - Max concurrency controlled by `--max-concurrent N` (default: 1) + - Each issue gets a timeout (`--timeout N` minutes, default: 30) +5. **Board**: Update project board status columns + - Move claimed issues to "In Progress" + - Move completed issues to "Done" + - Reconcile mismatches (closed issues not in Done, open issues in Done) +6. **Monitor**: Scan Teams/email for new actionable items + - Teams: query WorkIQ for action items, reviews, urgent requests + - Email: query for CI failures, Dependabot alerts, security vulnerabilities + - Create GitHub issues with bridge labels (`teams-bridge`, `email-bridge`) +7. **Housekeep**: Governance checks + - Retro: if it's Friday after 14:00 UTC or last retro was >7 days ago, spawn a retro session + - Decision hygiene: if `.squad/decisions/inbox/` has >5 files, spawn a merge session +8. **Report**: Log round summary, sleep until next interval + +## Example Execution Output + +``` +🔄 Ralph — Round 1 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + 🔴 Untriaged: 2 + 🟡 Assigned: 5 + 🚀 Executed: 3 + +▶ [14:23:10] Executing #42 "Fix auth redirect bug" → gh copilot --message "Work on issue #42..." +✓ [14:25:43] #42 completed + +▶ [14:25:44] Executing #45 "Add retry logic" → gh copilot --message "Work on issue #45..." +✓ [14:28:20] #45 completed + +▶ [14:28:21] Executing #47 "Update docs" → gh copilot --message "Work on issue #47..." +✗ [14:58:21] #47 failed: Timed out after 30m + +[14:58:22] Two-pass: 15 total → 3 actionable (hydrated) +[14:58:23] Board: #42 → Done +[14:58:23] Board: #45 → Done +✓ [14:58:24] Teams monitor scan complete +✓ [14:58:25] Email monitor scan complete +[14:58:26] Round 1 complete — sleeping 15 minutes +``` + +## The Three Layers of Ralph + +| Layer | When | How | +|-------|------|-----| +| **In-session** | You're at the keyboard | "Ralph, go" — active loop while work exists | +| **Local watchdog** | You're away but machine is on | `squad watch --execute` | +| **Cloud heartbeat** | Fully unattended | `squad-heartbeat.yml` GitHub Actions events | + +The in-session loop is ephemeral — it lives only while the Copilot session is active. The local watchdog runs as a separate process and polls at your chosen interval. The cloud heartbeat is the fully unattended layer that triggers on GitHub events (issue close, PR merge, manual dispatch). + +## Why This Matters + +Before #708, Ralph was a coordinator. He routed work to team members but never picked up the tools himself. + +Now, Ralph is a worker. He claims issues, posts comments, spawns Copilot sessions, manages the project board, scans Teams and email, and enforces governance checks. + +This closes the gap between "someone triaged this issue" and "someone is working on this issue." Ralph doesn't just label the work — he starts it. + +## What's Next + +The next iteration will add: + +- **SubSquad discovery**: automatically detect `.squad/subsquads/` for routing across multiple codebases +- **Channel routing**: route notifications to specific Teams channels based on work type +- **Multi-machine coordination**: distribute work across multiple Ralph instances + +Ralph is no longer just a triage bot. He's a work monitor — and he's just getting started. + +--- + +**Try it:** +```bash +squad watch --execute --interval 15 +``` + +**Full feature set:** +```bash +squad watch --execute --board --two-pass --monitor-teams --retro --decision-hygiene --max-concurrent 2 +``` + +--- + +_PR #709 · Issue #708 · Shipped 2026-03-30_ diff --git a/docs/src/content/docs/features/ralph.md b/docs/src/content/docs/features/ralph.md index 6d28b8c4a..3a12c2ad7 100644 --- a/docs/src/content/docs/features/ralph.md +++ b/docs/src/content/docs/features/ralph.md @@ -190,7 +190,11 @@ Ralph does **not** ask permission to continue — he keeps working. The only thi ## Watch Mode (`squad watch`) -Ralph's in-session loop processes work while it exists, then idles. For **persistent polling** when you're away from the keyboard, run the `squad watch` command in a separate terminal: +Ralph's in-session loop processes work while it exists, then idles. For **persistent polling** when you're away from the keyboard, run the `squad watch` command in a separate terminal. + +### Triage Mode (Default) + +Basic usage — triage only, no execution: ```bash squad watch # polls every 10 minutes (default) @@ -204,12 +208,157 @@ This runs as a standalone local process (not inside Copilot) that: - Assigns @copilot to `squad:copilot` issues (if auto-assign is enabled) - Runs until Ctrl+C +### Full Work Monitor Mode (`--execute`) + +Add `--execute` to transform Ralph from a triage bot into a full work monitor that spawns Copilot sessions and actually does the work: + +```bash +squad watch --execute # basic work monitor +squad watch --execute --interval 15 # check every 15 minutes +squad watch --execute --max-concurrent 2 # work on 2 issues in parallel +``` + +When `--execute` is enabled, Ralph spawns Copilot CLI sessions for actionable issues (assigned to a squad member, not blocked, not already assigned to a human). + +**Example execution output:** + +``` +🔄 Ralph — Round 1 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + 🔴 Untriaged: 2 + 🟡 Assigned: 5 + 🚀 Executed: 3 + +▶ [14:23:10] Executing #42 "Fix auth redirect bug" → gh copilot --message "Work on issue #42..." +✓ [14:25:43] #42 completed +▶ [14:25:44] Executing #45 "Add retry logic" → gh copilot --message "Work on issue #45..." +✓ [14:28:20] #45 completed +``` + +### All Watch Flags + +All new features are **opt-in** and disabled by default. Existing `squad watch` behavior is unchanged. + +#### Execution Control + +| Flag | Description | Example | +|------|-------------|---------| +| `--execute` | Enable work execution (spawn Copilot to work on issues) | `squad watch --execute` | +| `--max-concurrent N` | Max parallel issues per round (default: 1) | `squad watch --execute --max-concurrent 3` | +| `--timeout N` | Per-issue timeout in minutes (default: 30) | `squad watch --execute --timeout 45` | +| `--copilot-flags "..."` | Pass extra flags to Copilot CLI | `squad watch --execute --copilot-flags "--model gpt-4"` | + +#### Issue Scanning + +| Flag | Description | Example | +|------|-------------|---------| +| `--two-pass` | Lightweight list → hydrate actionable only (saves API quota) | `squad watch --two-pass` | +| `--wave-dispatch` | Parallel sub-task execution within issues (dependency-aware) | `squad watch --execute --wave-dispatch` | + +#### Communication Bridges + +| Flag | Description | Example | +|------|-------------|---------| +| `--monitor-teams` | Scan Teams for actionable messages each round (requires WorkIQ MCP) | `squad watch --monitor-teams` | +| `--monitor-email` | Scan email for alerts and action items each round (requires WorkIQ MCP) | `squad watch --monitor-email` | + +#### Project Board Lifecycle + +| Flag | Description | Example | +|------|-------------|---------| +| `--board` | Enable project board lifecycle (In Progress / Done / Blocked + reconciliation) | `squad watch --board` | +| `--board-project N` | Project board number (default: 1) | `squad watch --board --board-project 2` | + +#### Housekeeping & Governance + +| Flag | Description | Example | +|------|-------------|---------| +| `--retro` | Enforce retrospective checks (Fridays or when missed >7 days) | `squad watch --retro` | +| `--decision-hygiene` | Auto-merge decision inbox when >5 files | `squad watch --decision-hygiene` | +| `--channel-routing` | Route notifications to specific Teams channels (requires `.squad/teams-channels.json`) | `squad watch --channel-routing` | + +### Common Workflows + +**Basic triage + work execution:** +```bash +squad watch --execute --interval 10 +``` + +**Full monitor with all features:** +```bash +squad watch --execute --board --two-pass --monitor-teams --retro --decision-hygiene --max-concurrent 2 --interval 15 +``` + +**Cost-conscious (two-pass, lower concurrency):** +```bash +squad watch --execute --two-pass --max-concurrent 1 --timeout 20 +``` + +**Teams + email bridge only (no issue execution):** +```bash +squad watch --monitor-teams --monitor-email --interval 5 +``` + +### Round Cycle (Full Monitor) + +When all features are enabled, each round follows this cycle: + +1. **Self-pull**: `git fetch && git pull --ff-only` to stay current +2. **Scan**: Fetch open issues (two-pass if enabled) +3. **Triage**: Label untriaged issues based on routing rules +4. **Execute**: Spawn Copilot sessions for actionable issues (wave dispatch if enabled) +5. **Board**: Update project board status, reconcile mismatches +6. **Monitor**: Scan Teams/email for new actionable items +7. **Housekeep**: Check for retro, merge decision inbox if needed +8. **Report**: Log round summary, sleep until next interval + +### Advanced: `--agent-cmd` (Hidden Flag) + +For advanced users who know what they're doing: + +```bash +squad watch --execute --agent-cmd "custom-agent-wrapper" +``` + +This fully overrides the agent command. The default is `gh copilot --message ""` plus any `--copilot-flags`. Use this to plug in custom agent wrappers or alternative Copilot entry points. + +### Azure DevOps Support + +Ralph supports Azure DevOps repos and work items via the SDK's PlatformAdapter. When your git remote points to `dev.azure.com` or `visualstudio.com`, Ralph auto-detects ADO — no flag needed. + +**Setup:** + +1. Install Azure CLI: `az extension add --name azure-devops` +2. Authenticate: `az login` +3. Add ADO config to `.squad/config.json`: +```json +{ + "platform": "ado", + "ado": { + "org": "YOUR_ORG", + "project": "YOUR_PROJECT" + } +} +``` + +**Usage:** +```bash +squad watch # auto-detects from git remote +squad watch --execute # full work monitor (auto-detects platform) +``` + +**Key differences from GitHub:** +- ADO uses **tags** instead of labels — `squad:data` becomes a tag on the work item +- ADO uses `az boards` CLI instead of `gh` — Ralph checks `az` availability +- ADO rate limiting is handled differently — the circuit breaker skips quota checks +- ADO PRs don't expose `statusCheckRollup` — CI status columns may be empty + ### Three layers of Ralph | Layer | When | How | |-------|------|-----| | **In-session** | You're at the keyboard | "Ralph, go" — active loop while work exists | -| **Local watchdog** | You're away but machine is on | `squad watch --interval 10` | +| **Local watchdog** | You're away but machine is on | `squad watch --interval 10` (triage) or `squad watch --execute` (full monitor) | | **Cloud heartbeat** | Fully unattended | `squad-heartbeat.yml` GitHub Actions events (issue close, PR merge, manual dispatch) | ## Ralph's Board View diff --git a/docs/src/content/docs/reference/cli.md b/docs/src/content/docs/reference/cli.md index 2e1df542c..d472a3e60 100644 --- a/docs/src/content/docs/reference/cli.md +++ b/docs/src/content/docs/reference/cli.md @@ -38,6 +38,17 @@ squad init | `squad link ` | Link project to a remote team root | Yes | | `squad triage` | Auto-triage issues and assign to team (primary name; `watch` is an alias) | Yes | | `squad triage --interval ` | Continuous triage (default: every 10 min) | Yes | +| `squad watch --execute` | Enable work execution (spawn Copilot to work on issues) | Yes | +| `squad watch --monitor-teams` | Scan Teams for actionable messages each round | Yes | +| `squad watch --monitor-email` | Scan email for alerts and action items each round | Yes | +| `squad watch --board` | Enable project board lifecycle management | Yes | +| `squad watch --two-pass` | Use two-pass scanning (lightweight → hydrate) | Yes | +| `squad watch --wave-dispatch` | Parallel sub-task execution within issues | Yes | +| `squad watch --retro` | Enforce retrospective checks | Yes | +| `squad watch --decision-hygiene` | Auto-merge decision inbox | Yes | +| `squad watch --max-concurrent N` | Max parallel issues per round (default: 1) | Yes | +| `squad watch --timeout N` | Per-issue timeout in minutes (default: 30) | Yes | +| `squad watch --copilot-flags "..."` | Extra flags for Copilot CLI | Yes | | `squad copilot` | Add the @copilot coding agent to the team | Yes | | `squad copilot --off` | Remove @copilot from the team | Yes | | `squad copilot --auto-assign` | Enable auto-assignment for @copilot | Yes | diff --git a/packages/squad-cli/package.json b/packages/squad-cli/package.json index 239ce8395..57be67836 100644 --- a/packages/squad-cli/package.json +++ b/packages/squad-cli/package.json @@ -121,8 +121,8 @@ "import": "./dist/cli/commands/init-remote.js" }, "./commands/watch": { - "types": "./dist/cli/commands/watch.d.ts", - "import": "./dist/cli/commands/watch.js" + "types": "./dist/cli/commands/watch/index.d.ts", + "import": "./dist/cli/commands/watch/index.js" }, "./commands/start": { "types": "./dist/cli/commands/start.d.ts", diff --git a/packages/squad-cli/src/cli-entry.ts b/packages/squad-cli/src/cli-entry.ts index ba8f1f228..c6101a71c 100644 --- a/packages/squad-cli/src/cli-entry.ts +++ b/packages/squad-cli/src/cli-entry.ts @@ -159,8 +159,24 @@ async function main(): Promise { console.log(` ${BOLD}cost${RESET} Report token usage from orchestration logs`); console.log(` Flags: --all, --agent `); console.log(` ${BOLD}triage${RESET} Scan for work and categorize issues`); - console.log(` Usage: triage [--interval ]`); + console.log(` Usage: triage [--interval ] [--execute]`); console.log(` Default: checks every 10 minutes (Ctrl+C to stop)`); + console.log(` Core flags:`); + console.log(` --execute (spawn agents to work on issues)`); + console.log(` --copilot-flags "..." (extra copilot CLI flags)`); + console.log(` --max-concurrent N (parallel issue limit, default 1)`); + console.log(` --timeout N (max minutes per issue, default 30)`); + console.log(` Capabilities (opt-in via -- or config.json):`); + console.log(` --self-pull git fetch/pull at round start`); + console.log(` --board project board lifecycle + reconciliation`); + console.log(` --board-project N project number (default 1)`); + console.log(` --monitor-teams scan Teams for actionable messages`); + console.log(` --monitor-email scan email for actionable items`); + console.log(` --two-pass lightweight list then hydrate actionable`); + console.log(` --wave-dispatch wave-based parallel sub-task dispatch`); + console.log(` --retro enforce retrospective checks`); + console.log(` --decision-hygiene auto-merge decision inbox`); + console.log(` Disable: --no- overrides config.json`); console.log(` ${BOLD}loop${RESET} Continuous work loop (Ralph mode)`); console.log(` Usage: loop [--filter