Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
c0cbf16
feat(watch): add /fleet hybrid dispatch mode for parallel execution (…
invalid-email-address Apr 3, 2026
3fd1f43
fix: resolve TS2769 execSync overload + add changeset for changelog-gate
invalid-email-address Apr 3, 2026
6d814d2
fix: address all 6 Copilot review comments on fleet dispatch
invalid-email-address Apr 3, 2026
7d57659
fix: remove context.log (not on WatchContext type)
invalid-email-address Apr 3, 2026
ba7f5ef
feat(cli): add cleanup watch capability for stale file housekeeping (…
invalid-email-address Apr 3, 2026
6571324
feat(cli): add --notify-level to control watch round noise (#803)
invalid-email-address Apr 4, 2026
8cb4a34
docs: add notification-level feature doc + v0.9.2 blog post
invalid-email-address Apr 4, 2026
7a62317
fix: update ralph-board test for notify-level default change
invalid-email-address Apr 4, 2026
db03b33
fix(docs): replace machine-specific hostname with generic example
invalid-email-address Apr 4, 2026
b1b78e1
feat(watch): health check — show running watch instance status (#808)
invalid-email-address Apr 4, 2026
309a202
feat(sdk): git-notes + orphan-branch state backends (#807)
invalid-email-address Apr 4, 2026
ff66f51
fix(watch): move PID file to OS temp dir for safety
invalid-email-address Apr 4, 2026
5f30058
Merge branch 'dev' into squad/775-fleet-dispatch
tamirdresher Apr 4, 2026
bc60dee
Merge branch 'dev' into squad/791-cleanup-ceremony
tamirdresher Apr 4, 2026
c72c908
Merge branch 'dev' into squad/803-quiet-notifications
tamirdresher Apr 4, 2026
9390fa7
Merge branch 'dev' into squad/808-watch-health
tamirdresher Apr 4, 2026
e84c7cc
Merge branch 'dev' into squad/807-git-state-backends
tamirdresher Apr 4, 2026
27113c4
fix: address Copilot review comments
invalid-email-address Apr 4, 2026
f2c734b
fix: address Copilot review comments
invalid-email-address Apr 4, 2026
ed6c014
fix: address Copilot review comments on cleanup ceremony
invalid-email-address Apr 4, 2026
376a55a
fix: address Copilot review comments
invalid-email-address Apr 4, 2026
052c62a
fix: address Copilot review comments
invalid-email-address Apr 4, 2026
a6436f2
fix: address Copilot review comments
invalid-email-address Apr 4, 2026
26c6289
fix(watch): delegate issue selection to agent with rich prompt (match…
invalid-email-address Apr 4, 2026
cb413bf
fix(watch): delegate issue selection to agent with rich prompt (match…
invalid-email-address Apr 4, 2026
facb602
fix(watch): add tiered error recovery matching PS1 remediation
invalid-email-address Apr 4, 2026
a0a3b49
fix(watch): self-pull with stash/restart detection (matches PS1)
invalid-email-address Apr 4, 2026
289579a
feat(watch): add overnight window + sentinel stop (matches PS1)
invalid-email-address Apr 4, 2026
3be0464
fix(watch): restore assignee + blocked-label filters in findExecutabl…
Apr 4, 2026
6495898
feat(watch): add ensureAuth() to platform adapter — replaces Set-GhCo…
invalid-email-address Apr 4, 2026
e07e8f9
test(execute): add classifyIssue + fleet/hybrid routing unit tests
Apr 4, 2026
34fe4a5
fix(watch): generic auth via --auth-user config flag + adapter.ensure…
invalid-email-address Apr 4, 2026
39a4b31
chore: remove stale temp file
invalid-email-address Apr 4, 2026
3727843
Merge branch 'squad/775-fleet-dispatch' of https://github.com/bradyga…
invalid-email-address Apr 4, 2026
4cf5445
Merge branch 'squad/781-watch-verbose-reliability' of https://github.…
invalid-email-address Apr 4, 2026
36b289e
Merge branch 'squad/791-cleanup-ceremony' of https://github.com/brady…
invalid-email-address Apr 4, 2026
fe1e14e
Merge branch 'squad/803-quiet-notifications' of https://github.com/br…
invalid-email-address Apr 4, 2026
68229c5
Merge branch 'squad/808-watch-health' of https://github.com/bradygast…
invalid-email-address Apr 4, 2026
9f957e9
Merge branch 'squad/807-git-state-backends' of https://github.com/bra…
invalid-email-address Apr 4, 2026
dfd05df
fix: restore classifyIssue, blocking-label filters, and -p tempfile p…
invalid-email-address Apr 4, 2026
24767f4
fix: resolve TS errors from merge (config types, state-backend, imports)
invalid-email-address Apr 4, 2026
ba0c4ee
fix(watch): add round timing messages + --log-file for diagnostics
invalid-email-address Apr 4, 2026
e0f9c8a
docs: update README, CHANGELOG, and watch docs for watch-next-gen
invalid-email-address Apr 4, 2026
cd19527
fix(watch): use spawn with stdio:inherit for real-time agent output
invalid-email-address Apr 4, 2026
e857529
fix(watch): resolve CI failures for PR #830
invalid-email-address Apr 4, 2026
8382867
Merge origin/dev into squad/watch-next-gen
invalid-email-address Apr 4, 2026
d420075
fix: add authUser to WatchConfig interface
invalid-email-address Apr 4, 2026
8b7d899
fix: re-export health.ts symbols from watch barrel for test imports
invalid-email-address Apr 4, 2026
95fbdad
Merge origin/dev and resolve upgrade.test.ts conflict
invalid-email-address Apr 4, 2026
0e3187b
fix: add notify-level options to reportBoard + skip ESM spy test
invalid-email-address Apr 4, 2026
c16d988
fix: expand wiring test to find subdir command files (watch/health.ts)
invalid-email-address Apr 4, 2026
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
12 changes: 12 additions & 0 deletions .changeset/cleanup-ceremony.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---

Copilot AI Apr 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This changeset file also appears to start with a UTF-8 BOM (---). Please remove the BOM so frontmatter parsing remains consistent across tools and platforms.

Suggested change
---
---

Copilot uses AI. Check for mistakes.
"@bradygaster/squad-cli": minor
---

Add cleanup watch capability for stale file housekeeping (#791)

- New `cleanup` capability in the `housekeeping` phase

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we should make sure to differentiate between the cleanup and nap commands but, maybe i just need to RTFM. :)

- Clears `.squad/.scratch/` (all ephemeral temp files)
- Archives orchestration-log and session-log entries older than 30 days
- Warns about stale decision inbox files (>7 days)
- Configurable: `everyNRounds` (default: 10), `maxAgeDays` (default: 30)
- 12 new tests
17 changes: 17 additions & 0 deletions .changeset/git-state-backends.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
"@bradygaster/squad-sdk": minor
"@bradygaster/squad-cli": minor
---

feat(sdk): git-notes + orphan-branch state backends for .squad/

Adds two git-native state storage backends as alternatives to the worktree
and external directory approaches:

- **git-notes** (`refs/notes/squad`): State stored in git notes ref. Survives
branch switches, invisible in diffs and PRs.
- **orphan-branch** (`squad-state`): Dedicated orphan branch with no common
ancestor. State files never appear in main.

Configure via `.squad/config.json`: `{ "stateBackend": "git-notes" }` or
the `--state-backend` CLI flag.
13 changes: 13 additions & 0 deletions .changeset/quiet-notifications.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@bradygaster/squad-cli": minor
---

Add `--notify-level` to control watch round reporting noise (#803)

- `--notify-level important` (default): only print rounds with actual work items
- `--notify-level all`: print every round including empty (old behavior)
- `--notify-level none`: suppress all round output
- Add machine name (`os.hostname()`) and repo name to round headers for attribution
(shown in round headers when the board has items, and in "Board is clear" message)
- Configurable via `.squad/config.json` watch section: `"notifyLevel": "important"`
- Empty rounds silenced by default — no more "Round 160, Round 161" spam
10 changes: 10 additions & 0 deletions .changeset/watch-health.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"@bradygaster/squad-cli": minor
---

feat(watch): health check — show running watch instance status (#808)

Adds `squad watch --health` to display the status of a running watch
instance: PID, uptime, auth account, capabilities, and auth drift
detection. Writes `.squad/.watch-pid.json` at startup for instance

Copilot AI Apr 4, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changeset text says the PID file is written to .squad/.watch-pid.json, but the implementation writes to an OS temp file (os.tmpdir()/squad-watch-{hash}.json) via getPidPath(). Please update the changeset (and any docs) to reflect the actual location, or change the implementation to match the documented .squad/ path.

Suggested change
detection. Writes `.squad/.watch-pid.json` at startup for instance
detection. Writes a watch PID file in the OS temp directory
(`os.tmpdir()/squad-watch-{hash}.json`) at startup for instance

Copilot uses AI. Check for mistakes.
tracking. Detects and cleans up stale PID files from crashed instances.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ coverage/
.squad/decisions/inbox/
.squad/sessions/
.squad/config.json

# Test temp dirs (created in cwd by vitest tests, cleaned in afterEach)
.test-*
# Docs site generated files
Expand Down
154 changes: 153 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ Use `--force` to re-apply updates even when your installed version already match
| `squad init` | **Init** — scaffold Squad in the current directory (idempotent — safe to run multiple times); alias: `hire`; use `--global` to init in personal squad directory, `--mode remote <path>` for dual-root mode |
| `squad upgrade` | Update Squad-owned files to latest; never touches your team state; use `--global` to upgrade personal squad, `--migrate-directory` to rename `.ai-team/` → `.squad/` |
| `squad status` | Show which squad is active and why |
| `squad triage` | Watch issues and auto-triage to team (aliases: `watch`, `loop`); use `--interval <minutes>` to set polling frequency (default: 10) |
| `squad triage` | **Watch mode** — poll for issues and auto-triage to team (aliases: `watch`, `loop`); use `--interval <minutes>` to set polling frequency (default: 10); with `--execute` dispatch Copilot agents; use `--agent-cmd`, `--copilot-flags`, `--auth-user` to customize agent execution; `--health` shows watch status; `--log-file` for diagnostics |
| `squad copilot` | Add/remove the Copilot coding agent (@copilot); use `--off` to remove, `--auto-assign` to enable auto-assignment |
| `squad doctor` | Check your setup and diagnose issues (alias: `heartbeat`) |
| `squad link <team-repo-path>` | Connect to a remote team |
Expand All @@ -114,6 +114,158 @@ Use `--force` to re-apply updates even when your installed version already match

---

## Watch Mode — Ralph's Autonomous Polling

Ralph continuously polls for work and dispatches agents to handle it. Watch mode is perfect for unmanned squad operations — let agents work while you're away.

### Quick Start

```bash
# Monitor for issues (triage mode — no execution)
npx @bradygaster/squad-cli watch

# Monitor and auto-execute against actionable issues
npx @bradygaster/squad-cli watch --execute --interval 5

# With custom agent runner and copilot flags
npx @bradygaster/squad-cli watch --execute \
--agent-cmd "agency copilot" \
--copilot-flags "--yolo --autopilot --mcp mail --agent squad" \
--auth-user myaccount

# Run watch with diagnostics
npx @bradygaster/squad-cli watch --execute --log-file ./watch.log --verbose

# Check health of running watch process
npx @bradygaster/squad-cli watch --health
```

### Key Flags

| Flag | Description |
|------|-------------|
| `--execute` | Enable agent execution (spawn Copilot sessions for actionable issues) |
| `--interval N` | Poll every N minutes (default: 10) |
| `--agent-cmd` | Custom agent command (default: `gh copilot`) |
| `--copilot-flags` | Flags passed to the agent runner (e.g., `--yolo --autopilot`) |
| `--auth-user` | GitHub/Azure DevOps account to use for agent auth |
| `--log-file` | Mirror output to file for later review and diagnostics |
| `--verbose` | Show extra diagnostic output (auth probes, callbacks, pulls) |
| `--health` | Show status of running watch: PID, uptime, auth readiness, capabilities |
| `--overnight-start HH:MM` | Pause watch during off-hours (e.g., `--overnight-start 18:00`) |
| `--overnight-end HH:MM` | Resume watch at this time (e.g., `--overnight-end 08:00`) |
| `--notify-level` | Control output verbosity (`all` / `important` / `none`, default: `important`) |
| `--state-backend` | Persistence strategy (`git-notes` or `orphan-branch`, default: in-memory) |

### How Watch Decides What to Execute

Ralph uses an **agent-delegated selection pattern**:

1. Ralph scans for triage-eligible issues (unassigned, labeled, etc.)
2. Ralph builds a context snapshot: issue list, squad state, recent decisions
3. Ralph writes this context to a **temp file** using the `-p <path>` flag
4. Ralph invokes the agent with that file: `gh copilot -p context.md`
5. The agent **decides which issue to work on** and **how**
6. Ralph monitors execution, logs results, updates issue status

This design gives **agents full autonomy** over issue selection while keeping the polling loop lean.

### Issue Selection & Escalation

Ralph provides a rich prompt scaffold to the agent:

```
## Work Context

### Available Issues (prioritized)
- #42 Urgent bug in auth (P0)
- #89 Performance review pending (P1)
- #123 Docs update (P2)

### Why These Issues Matter
...context from decision archive...

### Success Criteria
- Tests pass
- Changes match team conventions
- PR linked to issue

### When to Escalate
If blocker detected → pause, log, notify humans
```

Agents see **full context** and can decide intelligently rather than blindly executing random work.

### Error Recovery (4-Tier Escalation)

Watch includes a tiered remediation strategy:

1. **Tier 1 — Circuit Breaker Reset**: Clear and retry
2. **Tier 2 — Auth Reprobe**: Re-verify credentials
3. **Tier 3 — Git Pull**: Update local state
4. **Tier 4 — Pause 30m**: Back off for human intervention

This prevents watch from spamming the same failure endlessly.

### State Backends

Watch can persist its state in different ways:

```bash
# Default: in-memory (loses state on restart)
squad watch --execute

# Persist to git-notes (survives restarts, no new branches)
squad watch --execute --state-backend git-notes

# Persist to orphan branch (isolated history, easy to prune)
squad watch --execute --state-backend orphan-branch
```

### Graceful Shutdown

To stop a running watch process gracefully:

```bash
# Create sentinel file
touch .squad/ralph-stop

# Watch will finish current round and exit cleanly
# Logs final state, cleans scratch dirs
```

### Cleanup

Watch automatically prunes stale artifacts:
- Scratch directories older than 7 days
- Log files older than 30 days
- Orphaned orchestration state

### Monitoring Watch

Check on a running watch:

```bash
squad watch --health
```

Output example:
```
Ralph Watch Status

PID: 12345
Uptime: 2h 15m
Last Poll: 2 minutes ago

Auth: Ready (account: myaccount@github.com)
Capabilities: Issue triage, PR review, ADO sync

Next Poll: 14:35 (in 3 minutes)
Round: 42 / 1200
```

---

## Interactive Shell

Tired of typing `squad` followed by a command every time? Enter the interactive shell.
Expand Down
3 changes: 2 additions & 1 deletion cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
"Pydantic", "sdkgen", "ttft", "Strausz", "mycompany",
"slugified", "simplejwt", "pytest", "Luca", "Clemenza",
"Tessio", "Triaging", "Futurama", "mklink", "slnx", "jqlang",
"benleane", "TELMU", "Automator", "kedacore"
"benleane", "TELMU", "Automator", "kedacore",
"DEVBOX", "myaccount"
],
"dictionaries": ["en_US", "typescript", "node", "npm", "bash"],
"allowCompoundWords": true
Expand Down
Loading
Loading