@bradygaster/squad-sdk 0.8.25 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter/client.d.ts +17 -0
- package/dist/adapter/client.d.ts.map +1 -1
- package/dist/adapter/client.js +101 -1
- package/dist/adapter/client.js.map +1 -1
- package/dist/agents/history-shadow.d.ts.map +1 -1
- package/dist/agents/history-shadow.js +99 -32
- package/dist/agents/history-shadow.js.map +1 -1
- package/dist/agents/index.d.ts +1 -0
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +2 -0
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/model-selector.d.ts +2 -0
- package/dist/agents/model-selector.d.ts.map +1 -1
- package/dist/agents/model-selector.js +41 -35
- package/dist/agents/model-selector.js.map +1 -1
- package/dist/agents/personal.d.ts +35 -0
- package/dist/agents/personal.d.ts.map +1 -0
- package/dist/agents/personal.js +67 -0
- package/dist/agents/personal.js.map +1 -0
- package/dist/builders/index.d.ts +3 -2
- package/dist/builders/index.d.ts.map +1 -1
- package/dist/builders/index.js +28 -0
- package/dist/builders/index.js.map +1 -1
- package/dist/builders/types.d.ts +13 -0
- package/dist/builders/types.d.ts.map +1 -1
- package/dist/config/init.d.ts +8 -0
- package/dist/config/init.d.ts.map +1 -1
- package/dist/config/init.js +131 -20
- package/dist/config/init.js.map +1 -1
- package/dist/config/models.d.ts +112 -0
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js +329 -18
- package/dist/config/models.js.map +1 -1
- package/dist/coordinator/index.js +2 -2
- package/dist/coordinator/index.js.map +1 -1
- package/dist/index.d.ts +8 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -2
- package/dist/index.js.map +1 -1
- package/dist/platform/azure-devops.d.ts +42 -0
- package/dist/platform/azure-devops.d.ts.map +1 -1
- package/dist/platform/azure-devops.js +75 -0
- package/dist/platform/azure-devops.js.map +1 -1
- package/dist/platform/comms-file-log.d.ts.map +1 -1
- package/dist/platform/comms-file-log.js +2 -1
- package/dist/platform/comms-file-log.js.map +1 -1
- package/dist/platform/index.d.ts +2 -1
- package/dist/platform/index.d.ts.map +1 -1
- package/dist/platform/index.js +1 -0
- package/dist/platform/index.js.map +1 -1
- package/dist/ralph/capabilities.d.ts +67 -0
- package/dist/ralph/capabilities.d.ts.map +1 -0
- package/dist/ralph/capabilities.js +111 -0
- package/dist/ralph/capabilities.js.map +1 -0
- package/dist/ralph/index.d.ts +2 -0
- package/dist/ralph/index.d.ts.map +1 -1
- package/dist/ralph/index.js +6 -5
- package/dist/ralph/index.js.map +1 -1
- package/dist/ralph/rate-limiting.d.ts +99 -0
- package/dist/ralph/rate-limiting.d.ts.map +1 -0
- package/dist/ralph/rate-limiting.js +170 -0
- package/dist/ralph/rate-limiting.js.map +1 -0
- package/dist/resolution.d.ts +24 -2
- package/dist/resolution.d.ts.map +1 -1
- package/dist/resolution.js +106 -6
- package/dist/resolution.js.map +1 -1
- package/dist/roles/catalog-categories.d.ts +146 -0
- package/dist/roles/catalog-categories.d.ts.map +1 -0
- package/dist/roles/catalog-categories.js +374 -0
- package/dist/roles/catalog-categories.js.map +1 -0
- package/dist/roles/catalog-engineering.d.ts +212 -0
- package/dist/roles/catalog-engineering.d.ts.map +1 -0
- package/dist/roles/catalog-engineering.js +549 -0
- package/dist/roles/catalog-engineering.js.map +1 -0
- package/dist/roles/catalog.d.ts +24 -0
- package/dist/roles/catalog.d.ts.map +1 -0
- package/dist/roles/catalog.js +28 -0
- package/dist/roles/catalog.js.map +1 -0
- package/dist/roles/index.d.ts +69 -0
- package/dist/roles/index.d.ts.map +1 -0
- package/dist/roles/index.js +197 -0
- package/dist/roles/index.js.map +1 -0
- package/dist/roles/types.d.ts +87 -0
- package/dist/roles/types.d.ts.map +1 -0
- package/dist/roles/types.js +14 -0
- package/dist/roles/types.js.map +1 -0
- package/dist/runtime/benchmarks.js +5 -5
- package/dist/runtime/benchmarks.js.map +1 -1
- package/dist/runtime/constants.d.ts +2 -2
- package/dist/runtime/constants.d.ts.map +1 -1
- package/dist/runtime/constants.js +5 -3
- package/dist/runtime/constants.js.map +1 -1
- package/dist/runtime/cross-squad.d.ts +118 -0
- package/dist/runtime/cross-squad.d.ts.map +1 -0
- package/dist/runtime/cross-squad.js +234 -0
- package/dist/runtime/cross-squad.js.map +1 -0
- package/dist/runtime/otel-init.d.ts +24 -17
- package/dist/runtime/otel-init.d.ts.map +1 -1
- package/dist/runtime/otel-init.js +29 -20
- package/dist/runtime/otel-init.js.map +1 -1
- package/dist/runtime/otel-metrics.d.ts +5 -0
- package/dist/runtime/otel-metrics.d.ts.map +1 -1
- package/dist/runtime/otel-metrics.js +54 -0
- package/dist/runtime/otel-metrics.js.map +1 -1
- package/dist/runtime/rework.d.ts +71 -0
- package/dist/runtime/rework.d.ts.map +1 -0
- package/dist/runtime/rework.js +107 -0
- package/dist/runtime/rework.js.map +1 -0
- package/dist/runtime/scheduler.d.ts +128 -0
- package/dist/runtime/scheduler.d.ts.map +1 -0
- package/dist/runtime/scheduler.js +427 -0
- package/dist/runtime/scheduler.js.map +1 -0
- package/dist/runtime/squad-observer.d.ts.map +1 -1
- package/dist/runtime/squad-observer.js +4 -0
- package/dist/runtime/squad-observer.js.map +1 -1
- package/dist/runtime/streaming.d.ts +2 -0
- package/dist/runtime/streaming.d.ts.map +1 -1
- package/dist/runtime/streaming.js +6 -0
- package/dist/runtime/streaming.js.map +1 -1
- package/dist/runtime/telemetry.d.ts +2 -0
- package/dist/runtime/telemetry.d.ts.map +1 -1
- package/dist/runtime/telemetry.js +6 -0
- package/dist/runtime/telemetry.js.map +1 -1
- package/dist/sharing/consult.d.ts +2 -2
- package/dist/sharing/consult.js +6 -6
- package/dist/sharing/consult.js.map +1 -1
- package/dist/sharing/export.d.ts.map +1 -1
- package/dist/sharing/export.js +17 -4
- package/dist/sharing/export.js.map +1 -1
- package/dist/skills/handler-types.d.ts +271 -0
- package/dist/skills/handler-types.d.ts.map +1 -0
- package/dist/skills/handler-types.js +31 -0
- package/dist/skills/handler-types.js.map +1 -0
- package/dist/skills/index.d.ts +3 -0
- package/dist/skills/index.d.ts.map +1 -1
- package/dist/skills/index.js +3 -0
- package/dist/skills/index.js.map +1 -1
- package/dist/skills/skill-script-loader.d.ts +65 -0
- package/dist/skills/skill-script-loader.d.ts.map +1 -0
- package/dist/skills/skill-script-loader.js +227 -0
- package/dist/skills/skill-script-loader.js.map +1 -0
- package/dist/skills/skill-source.d.ts.map +1 -1
- package/dist/skills/skill-source.js +5 -1
- package/dist/skills/skill-source.js.map +1 -1
- package/dist/tools/index.d.ts +10 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +49 -8
- package/dist/tools/index.js.map +1 -1
- package/dist/upstream/resolver.d.ts.map +1 -1
- package/dist/upstream/resolver.js +14 -5
- package/dist/upstream/resolver.js.map +1 -1
- package/package.json +34 -3
- package/templates/casting/Futurama.json +10 -0
- package/templates/casting-policy.json +4 -2
- package/templates/casting-reference.md +104 -0
- package/templates/cooperative-rate-limiting.md +229 -0
- package/templates/issue-lifecycle.md +412 -0
- package/templates/keda-scaler.md +164 -0
- package/templates/machine-capabilities.md +75 -0
- package/templates/mcp-config.md +0 -8
- package/templates/orchestration-log.md +27 -27
- package/templates/package.json +3 -0
- package/templates/ralph-circuit-breaker.md +313 -0
- package/templates/ralph-triage.js +543 -0
- package/templates/routing.md +5 -20
- package/templates/schedule.json +19 -0
- package/templates/scribe-charter.md +1 -1
- package/templates/skills/agent-collaboration/SKILL.md +42 -0
- package/templates/skills/agent-conduct/SKILL.md +24 -0
- package/templates/skills/architectural-proposals/SKILL.md +151 -0
- package/templates/skills/ci-validation-gates/SKILL.md +84 -0
- package/templates/skills/cli-wiring/SKILL.md +47 -0
- package/templates/skills/client-compatibility/SKILL.md +89 -0
- package/templates/skills/cross-squad/SKILL.md +114 -0
- package/templates/skills/distributed-mesh/SKILL.md +287 -0
- package/templates/skills/distributed-mesh/mesh.json.example +30 -0
- package/templates/skills/distributed-mesh/sync-mesh.ps1 +111 -0
- package/templates/skills/distributed-mesh/sync-mesh.sh +104 -0
- package/templates/skills/docs-standards/SKILL.md +71 -0
- package/templates/skills/economy-mode/SKILL.md +114 -0
- package/templates/skills/external-comms/SKILL.md +329 -0
- package/templates/skills/gh-auth-isolation/SKILL.md +183 -0
- package/templates/skills/git-workflow/SKILL.md +204 -0
- package/templates/skills/github-multi-account/SKILL.md +95 -0
- package/templates/skills/history-hygiene/SKILL.md +36 -0
- package/templates/skills/humanizer/SKILL.md +105 -0
- package/templates/skills/init-mode/SKILL.md +102 -0
- package/templates/skills/model-selection/SKILL.md +117 -0
- package/templates/skills/nap/SKILL.md +24 -0
- package/templates/skills/personal-squad/SKILL.md +57 -0
- package/templates/skills/release-process/SKILL.md +423 -0
- package/templates/skills/reskill/SKILL.md +92 -0
- package/templates/skills/reviewer-protocol/SKILL.md +79 -0
- package/templates/skills/secret-handling/SKILL.md +200 -0
- package/templates/skills/session-recovery/SKILL.md +155 -0
- package/templates/skills/squad-conventions/SKILL.md +69 -0
- package/templates/skills/test-discipline/SKILL.md +37 -0
- package/templates/skills/windows-compatibility/SKILL.md +74 -0
- package/templates/squad.agent.md +1287 -1146
- package/templates/workflows/squad-docs.yml +8 -4
- package/templates/workflows/squad-heartbeat.yml +55 -200
- package/templates/workflows/squad-insider-release.yml +1 -1
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# Cooperative Rate Limiting for Multi-Agent Deployments
|
|
2
|
+
|
|
3
|
+
> Coordinate API quota across multiple Ralph instances to prevent cascading failures.
|
|
4
|
+
|
|
5
|
+
## Problem
|
|
6
|
+
|
|
7
|
+
The [circuit breaker template](ralph-circuit-breaker.md) handles single-instance rate limiting well. But when multiple Ralphs run across machines (or pods on K8s), each instance independently hits API limits:
|
|
8
|
+
|
|
9
|
+
- **No coordination** — 5 Ralphs each think they have full API quota
|
|
10
|
+
- **Thundering herd** — All Ralphs retry simultaneously after rate limit resets
|
|
11
|
+
- **Priority inversion** — Low-priority work exhausts quota before critical work runs
|
|
12
|
+
- **Reactive only** — Circuit opens AFTER 429, wasting the failed request
|
|
13
|
+
|
|
14
|
+
## Solution: 6-Pattern Architecture
|
|
15
|
+
|
|
16
|
+
These patterns layer on top of the existing circuit breaker. Each is independent — adopt one or all.
|
|
17
|
+
|
|
18
|
+
### Pattern 1: Traffic Light (RAAS — Rate-Aware Agent Scheduling)
|
|
19
|
+
|
|
20
|
+
Map GitHub API `X-RateLimit-Remaining` to traffic light states:
|
|
21
|
+
|
|
22
|
+
| State | Remaining % | Behavior |
|
|
23
|
+
|-------|------------|----------|
|
|
24
|
+
| 🟢 GREEN | >20% | Normal operation |
|
|
25
|
+
| 🟡 AMBER | 5–20% | Only P0 agents proceed |
|
|
26
|
+
| 🔴 RED | <5% | Block all except emergency P0 |
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
type TrafficLight = 'green' | 'amber' | 'red';
|
|
30
|
+
|
|
31
|
+
function getTrafficLight(remaining: number, limit: number): TrafficLight {
|
|
32
|
+
const pct = remaining / limit;
|
|
33
|
+
if (pct > 0.20) return 'green';
|
|
34
|
+
if (pct > 0.05) return 'amber';
|
|
35
|
+
return 'red';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function shouldProceed(light: TrafficLight, agentPriority: number): boolean {
|
|
39
|
+
if (light === 'green') return true;
|
|
40
|
+
if (light === 'amber') return agentPriority === 0; // P0 only
|
|
41
|
+
return false; // RED — block all
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Pattern 2: Cooperative Token Pool (CMARP)
|
|
46
|
+
|
|
47
|
+
A shared JSON file (`~/.squad/rate-pool.json`) distributes API quota:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"totalLimit": 5000,
|
|
52
|
+
"resetAt": "2026-03-22T20:00:00Z",
|
|
53
|
+
"allocations": {
|
|
54
|
+
"picard": { "priority": 0, "allocated": 2000, "used": 450, "leaseExpiry": "2026-03-22T19:55:00Z" },
|
|
55
|
+
"data": { "priority": 1, "allocated": 1750, "used": 200, "leaseExpiry": "2026-03-22T19:55:00Z" },
|
|
56
|
+
"ralph": { "priority": 2, "allocated": 1250, "used": 100, "leaseExpiry": "2026-03-22T19:55:00Z" }
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Rules:**
|
|
62
|
+
- P0 agents (Lead) get 40% of quota
|
|
63
|
+
- P1 agents (specialists) get 35%
|
|
64
|
+
- P2 agents (Ralph, Scribe) get 25%
|
|
65
|
+
- Stale leases (>5 minutes without heartbeat) are auto-recovered
|
|
66
|
+
- Each agent checks their remaining allocation before making API calls
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
interface RatePoolAllocation {
|
|
70
|
+
priority: number;
|
|
71
|
+
allocated: number;
|
|
72
|
+
used: number;
|
|
73
|
+
leaseExpiry: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
interface RatePool {
|
|
77
|
+
totalLimit: number;
|
|
78
|
+
resetAt: string;
|
|
79
|
+
allocations: Record<string, RatePoolAllocation>;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function canUseQuota(pool: RatePool, agentName: string): boolean {
|
|
83
|
+
const alloc = pool.allocations[agentName];
|
|
84
|
+
if (!alloc) return true; // Unknown agent — allow (graceful)
|
|
85
|
+
|
|
86
|
+
// Reclaim stale leases from crashed agents
|
|
87
|
+
const now = new Date();
|
|
88
|
+
for (const [name, a] of Object.entries(pool.allocations)) {
|
|
89
|
+
if (new Date(a.leaseExpiry) < now && name !== agentName) {
|
|
90
|
+
a.allocated = 0; // Reclaim
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return alloc.used < alloc.allocated;
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Pattern 3: Predictive Circuit Breaker (PCB)
|
|
99
|
+
|
|
100
|
+
Opens the circuit BEFORE getting a 429 by predicting when quota will run out:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
interface RateSample {
|
|
104
|
+
timestamp: number; // Date.now()
|
|
105
|
+
remaining: number; // from X-RateLimit-Remaining header
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
class PredictiveCircuitBreaker {
|
|
109
|
+
private samples: RateSample[] = [];
|
|
110
|
+
private readonly maxSamples = 10;
|
|
111
|
+
private readonly warningThresholdSeconds = 120;
|
|
112
|
+
|
|
113
|
+
addSample(remaining: number): void {
|
|
114
|
+
this.samples.push({ timestamp: Date.now(), remaining });
|
|
115
|
+
if (this.samples.length > this.maxSamples) {
|
|
116
|
+
this.samples.shift();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Predict seconds until quota exhaustion using linear regression */
|
|
121
|
+
predictExhaustion(): number | null {
|
|
122
|
+
if (this.samples.length < 3) return null;
|
|
123
|
+
|
|
124
|
+
const n = this.samples.length;
|
|
125
|
+
const first = this.samples[0];
|
|
126
|
+
const last = this.samples[n - 1];
|
|
127
|
+
|
|
128
|
+
const elapsedMs = last.timestamp - first.timestamp;
|
|
129
|
+
if (elapsedMs === 0) return null;
|
|
130
|
+
|
|
131
|
+
const consumedPerMs = (first.remaining - last.remaining) / elapsedMs;
|
|
132
|
+
if (consumedPerMs <= 0) return null; // Not consuming — safe
|
|
133
|
+
|
|
134
|
+
const msUntilExhausted = last.remaining / consumedPerMs;
|
|
135
|
+
return msUntilExhausted / 1000;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
shouldOpen(): boolean {
|
|
139
|
+
const eta = this.predictExhaustion();
|
|
140
|
+
if (eta === null) return false;
|
|
141
|
+
return eta < this.warningThresholdSeconds;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Pattern 4: Priority Retry Windows (PWJG)
|
|
147
|
+
|
|
148
|
+
Non-overlapping jitter windows prevent thundering herd:
|
|
149
|
+
|
|
150
|
+
| Priority | Retry Window | Description |
|
|
151
|
+
|----------|-------------|-------------|
|
|
152
|
+
| P0 (Lead) | 500ms–5s | Recovers first |
|
|
153
|
+
| P1 (Specialists) | 2s–30s | Moderate delay |
|
|
154
|
+
| P2 (Ralph/Scribe) | 5s–60s | Most patient |
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
function getRetryDelay(priority: number, attempt: number): number {
|
|
158
|
+
const windows: Record<number, [number, number]> = {
|
|
159
|
+
0: [500, 5000], // P0: 500ms–5s
|
|
160
|
+
1: [2000, 30000], // P1: 2s–30s
|
|
161
|
+
2: [5000, 60000], // P2: 5s–60s
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
const [min, max] = windows[priority] ?? windows[2];
|
|
165
|
+
const base = Math.min(min * Math.pow(2, attempt), max);
|
|
166
|
+
const jitter = Math.random() * base * 0.5;
|
|
167
|
+
return base + jitter;
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Pattern 5: Resource Epoch Tracker (RET)
|
|
172
|
+
|
|
173
|
+
Heartbeat-based lease system for multi-machine deployments:
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
interface ResourceLease {
|
|
177
|
+
agent: string;
|
|
178
|
+
machine: string;
|
|
179
|
+
leaseStart: string;
|
|
180
|
+
leaseExpiry: string; // Typically 5 minutes from now
|
|
181
|
+
allocated: number;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Each agent renews its lease every 2 minutes
|
|
185
|
+
// If lease expires (agent crashed), allocation is reclaimed
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Pattern 6: Cascade Dependency Detector (CDD)
|
|
189
|
+
|
|
190
|
+
Track downstream failures and apply backpressure:
|
|
191
|
+
|
|
192
|
+
```
|
|
193
|
+
Agent A (rate limited) → Agent B (waiting for A) → Agent C (waiting for B)
|
|
194
|
+
↑ Backpressure signal: "don't start new work"
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
When a dependency is rate-limited, upstream agents should pause new work rather than queuing requests that will fail.
|
|
198
|
+
|
|
199
|
+
## Kubernetes Integration
|
|
200
|
+
|
|
201
|
+
On K8s, cooperative rate limiting can use KEDA to scale pods based on API quota:
|
|
202
|
+
|
|
203
|
+
```yaml
|
|
204
|
+
apiVersion: keda.sh/v1alpha1
|
|
205
|
+
kind: ScaledObject
|
|
206
|
+
spec:
|
|
207
|
+
scaleTargetRef:
|
|
208
|
+
name: ralph-deployment
|
|
209
|
+
triggers:
|
|
210
|
+
- type: external
|
|
211
|
+
metadata:
|
|
212
|
+
scalerAddress: keda-copilot-scaler:6000
|
|
213
|
+
# Scaler returns 0 when rate limited → pods scale to zero
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
See [keda-copilot-scaler](https://github.com/tamirdresher/keda-copilot-scaler) for a complete implementation.
|
|
217
|
+
|
|
218
|
+
## Quick Start
|
|
219
|
+
|
|
220
|
+
1. **Minimum viable:** Adopt Pattern 1 (Traffic Light) — read `X-RateLimit-Remaining` from API responses
|
|
221
|
+
2. **Multi-machine:** Add Pattern 2 (Cooperative Pool) — shared `rate-pool.json`
|
|
222
|
+
3. **Production:** Add Pattern 3 (Predictive CB) — prevent 429s entirely
|
|
223
|
+
4. **Kubernetes:** Add KEDA scaler for automatic pod scaling
|
|
224
|
+
|
|
225
|
+
## References
|
|
226
|
+
|
|
227
|
+
- [Circuit Breaker Template](ralph-circuit-breaker.md) — Foundation patterns
|
|
228
|
+
- [Squad on AKS](https://github.com/tamirdresher/squad-on-aks) — Production K8s deployment
|
|
229
|
+
- [KEDA Copilot Scaler](https://github.com/tamirdresher/keda-copilot-scaler) — Custom KEDA external scaler
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
# Issue Lifecycle — Repo Connection & PR Flow
|
|
2
|
+
|
|
3
|
+
Reference for connecting Squad to a repository and managing the issue→branch→PR→merge lifecycle.
|
|
4
|
+
|
|
5
|
+
## Repo Connection Format
|
|
6
|
+
|
|
7
|
+
When connecting Squad to an issue tracker, store the connection in `.squad/team.md`:
|
|
8
|
+
|
|
9
|
+
```markdown
|
|
10
|
+
## Issue Source
|
|
11
|
+
|
|
12
|
+
**Repository:** {owner}/{repo}
|
|
13
|
+
**Connected:** {date}
|
|
14
|
+
**Platform:** {GitHub | Azure DevOps | Planner}
|
|
15
|
+
**Filters:**
|
|
16
|
+
- Labels: `{label-filter}`
|
|
17
|
+
- Project: `{project-name}` (ADO/Planner only)
|
|
18
|
+
- Plan: `{plan-id}` (Planner only)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Detection triggers:**
|
|
22
|
+
- User says "connect to {repo}"
|
|
23
|
+
- User says "monitor {repo} for issues"
|
|
24
|
+
- Ralph is activated without an issue source
|
|
25
|
+
|
|
26
|
+
## Platform-Specific Issue States
|
|
27
|
+
|
|
28
|
+
Each platform tracks issue lifecycle differently. Squad normalizes these into a common board state.
|
|
29
|
+
|
|
30
|
+
### GitHub
|
|
31
|
+
|
|
32
|
+
| GitHub State | GitHub API Fields | Squad Board State |
|
|
33
|
+
|--------------|-------------------|-------------------|
|
|
34
|
+
| Open, no assignee | `state: open`, `assignee: null` | `untriaged` |
|
|
35
|
+
| Open, assigned, no branch | `state: open`, `assignee: @user`, no linked PR | `assigned` |
|
|
36
|
+
| Open, branch exists | `state: open`, linked branch exists | `inProgress` |
|
|
37
|
+
| Open, PR opened | `state: open`, PR exists, `reviewDecision: null` | `needsReview` |
|
|
38
|
+
| Open, PR approved | `state: open`, PR `reviewDecision: APPROVED` | `readyToMerge` |
|
|
39
|
+
| Open, changes requested | `state: open`, PR `reviewDecision: CHANGES_REQUESTED` | `changesRequested` |
|
|
40
|
+
| Open, CI failure | `state: open`, PR `statusCheckRollup: FAILURE` | `ciFailure` |
|
|
41
|
+
| Closed | `state: closed` | `done` |
|
|
42
|
+
|
|
43
|
+
**Issue labels used by Squad:**
|
|
44
|
+
- `squad` — Issue is in Squad backlog
|
|
45
|
+
- `squad:{member}` — Assigned to specific agent
|
|
46
|
+
- `squad:untriaged` — Needs triage
|
|
47
|
+
- `go:needs-research` — Needs investigation before implementation
|
|
48
|
+
- `priority:p{N}` — Priority level (0=critical, 1=high, 2=medium, 3=low)
|
|
49
|
+
- `next-up` — Queued for next agent pickup
|
|
50
|
+
|
|
51
|
+
**Branch naming convention:**
|
|
52
|
+
```
|
|
53
|
+
squad/{issue-number}-{kebab-case-slug}
|
|
54
|
+
```
|
|
55
|
+
Example: `squad/42-fix-login-validation`
|
|
56
|
+
|
|
57
|
+
### Azure DevOps
|
|
58
|
+
|
|
59
|
+
| ADO State | Squad Board State |
|
|
60
|
+
|-----------|-------------------|
|
|
61
|
+
| New | `untriaged` |
|
|
62
|
+
| Active, no branch | `assigned` |
|
|
63
|
+
| Active, branch exists | `inProgress` |
|
|
64
|
+
| Active, PR opened | `needsReview` |
|
|
65
|
+
| Active, PR approved | `readyToMerge` |
|
|
66
|
+
| Resolved | `done` |
|
|
67
|
+
| Closed | `done` |
|
|
68
|
+
|
|
69
|
+
**Work item tags used by Squad:**
|
|
70
|
+
- `squad` — Work item is in Squad backlog
|
|
71
|
+
- `squad:{member}` — Assigned to specific agent
|
|
72
|
+
|
|
73
|
+
**Branch naming convention:**
|
|
74
|
+
```
|
|
75
|
+
squad/{work-item-id}-{kebab-case-slug}
|
|
76
|
+
```
|
|
77
|
+
Example: `squad/1234-add-auth-module`
|
|
78
|
+
|
|
79
|
+
### Microsoft Planner
|
|
80
|
+
|
|
81
|
+
Planner does not have native Git integration. Squad uses Planner for task tracking and GitHub/ADO for code management.
|
|
82
|
+
|
|
83
|
+
| Planner Status | Squad Board State |
|
|
84
|
+
|----------------|-------------------|
|
|
85
|
+
| Not Started | `untriaged` |
|
|
86
|
+
| In Progress, no PR | `inProgress` |
|
|
87
|
+
| In Progress, PR opened | `needsReview` |
|
|
88
|
+
| Completed | `done` |
|
|
89
|
+
|
|
90
|
+
**Planner→Git workflow:**
|
|
91
|
+
1. Task created in Planner bucket
|
|
92
|
+
2. Agent reads task from Planner
|
|
93
|
+
3. Agent creates branch in GitHub/ADO repo
|
|
94
|
+
4. Agent opens PR referencing Planner task ID in description
|
|
95
|
+
5. Agent marks task as "Completed" when PR merges
|
|
96
|
+
|
|
97
|
+
## Issue → Branch → PR → Merge Lifecycle
|
|
98
|
+
|
|
99
|
+
### 1. Issue Assignment (Triage)
|
|
100
|
+
|
|
101
|
+
**Trigger:** Ralph detects an untriaged issue or user manually assigns work.
|
|
102
|
+
|
|
103
|
+
**Actions:**
|
|
104
|
+
1. Read `.squad/routing.md` to determine which agent should handle the issue
|
|
105
|
+
2. Apply `squad:{member}` label (GitHub) or tag (ADO)
|
|
106
|
+
3. Transition issue to `assigned` state
|
|
107
|
+
4. Optionally spawn agent immediately if issue is high-priority
|
|
108
|
+
|
|
109
|
+
**Issue read command:**
|
|
110
|
+
```bash
|
|
111
|
+
# GitHub
|
|
112
|
+
gh issue view {number} --json number,title,body,labels,assignees
|
|
113
|
+
|
|
114
|
+
# Azure DevOps
|
|
115
|
+
az boards work-item show --id {id} --output json
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### 2. Branch Creation (Start Work)
|
|
119
|
+
|
|
120
|
+
**Trigger:** Agent accepts issue assignment and begins work.
|
|
121
|
+
|
|
122
|
+
**Actions:**
|
|
123
|
+
1. Ensure working on latest base branch (usually `main` or `dev`)
|
|
124
|
+
2. Create feature branch using Squad naming convention
|
|
125
|
+
3. Transition issue to `inProgress` state
|
|
126
|
+
|
|
127
|
+
**Branch creation commands:**
|
|
128
|
+
|
|
129
|
+
**Standard (single-agent, no parallelism):**
|
|
130
|
+
```bash
|
|
131
|
+
git checkout main && git pull && git checkout -b squad/{issue-number}-{slug}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Worktree (parallel multi-agent):**
|
|
135
|
+
```bash
|
|
136
|
+
git worktree add ../worktrees/{issue-number} -b squad/{issue-number}-{slug}
|
|
137
|
+
cd ../worktrees/{issue-number}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
> **Note:** Worktree support is in progress (#525). Current implementation uses standard checkout.
|
|
141
|
+
|
|
142
|
+
### 3. Implementation & Commit
|
|
143
|
+
|
|
144
|
+
**Actions:**
|
|
145
|
+
1. Agent makes code changes
|
|
146
|
+
2. Commits reference the issue number
|
|
147
|
+
3. Pushes branch to remote
|
|
148
|
+
|
|
149
|
+
**Commit message format:**
|
|
150
|
+
```
|
|
151
|
+
{type}({scope}): {description} (#{issue-number})
|
|
152
|
+
|
|
153
|
+
{detailed explanation if needed}
|
|
154
|
+
|
|
155
|
+
{breaking change notice if applicable}
|
|
156
|
+
|
|
157
|
+
Closes #{issue-number}
|
|
158
|
+
|
|
159
|
+
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**Commit types:** `feat`, `fix`, `docs`, `refactor`, `test`, `chore`, `perf`, `style`, `build`, `ci`
|
|
163
|
+
|
|
164
|
+
**Push command:**
|
|
165
|
+
```bash
|
|
166
|
+
git push -u origin squad/{issue-number}-{slug}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### 4. PR Creation
|
|
170
|
+
|
|
171
|
+
**Trigger:** Agent completes implementation and is ready for review.
|
|
172
|
+
|
|
173
|
+
**Actions:**
|
|
174
|
+
1. Open PR from feature branch to base branch
|
|
175
|
+
2. Reference issue in PR description
|
|
176
|
+
3. Apply labels if needed
|
|
177
|
+
4. Transition issue to `needsReview` state
|
|
178
|
+
|
|
179
|
+
**PR creation commands:**
|
|
180
|
+
|
|
181
|
+
**GitHub:**
|
|
182
|
+
```bash
|
|
183
|
+
gh pr create --title "{title}" \
|
|
184
|
+
--body "Closes #{issue-number}\n\n{description}" \
|
|
185
|
+
--head squad/{issue-number}-{slug} \
|
|
186
|
+
--base main
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Azure DevOps:**
|
|
190
|
+
```bash
|
|
191
|
+
az repos pr create --title "{title}" \
|
|
192
|
+
--description "Closes #{work-item-id}\n\n{description}" \
|
|
193
|
+
--source-branch squad/{work-item-id}-{slug} \
|
|
194
|
+
--target-branch main
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**PR description template:**
|
|
198
|
+
```markdown
|
|
199
|
+
Closes #{issue-number}
|
|
200
|
+
|
|
201
|
+
## Summary
|
|
202
|
+
{what changed}
|
|
203
|
+
|
|
204
|
+
## Changes
|
|
205
|
+
- {change 1}
|
|
206
|
+
- {change 2}
|
|
207
|
+
|
|
208
|
+
## Testing
|
|
209
|
+
{how this was tested}
|
|
210
|
+
|
|
211
|
+
{If working as a squad member:}
|
|
212
|
+
Working as {member} ({role})
|
|
213
|
+
|
|
214
|
+
{If needs human review:}
|
|
215
|
+
⚠️ This task was flagged as "needs review" — please have a squad member review before merging.
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### 5. PR Review & Updates
|
|
219
|
+
|
|
220
|
+
**Review states:**
|
|
221
|
+
- **Approved** → `readyToMerge`
|
|
222
|
+
- **Changes requested** → `changesRequested`
|
|
223
|
+
- **CI failure** → `ciFailure`
|
|
224
|
+
|
|
225
|
+
**When changes are requested:**
|
|
226
|
+
1. Agent addresses feedback
|
|
227
|
+
2. Commits fixes to the same branch
|
|
228
|
+
3. Pushes updates
|
|
229
|
+
4. Requests re-review
|
|
230
|
+
|
|
231
|
+
**Update workflow:**
|
|
232
|
+
```bash
|
|
233
|
+
# Make changes
|
|
234
|
+
git add .
|
|
235
|
+
git commit -m "fix: address review feedback"
|
|
236
|
+
git push
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
**Re-request review (GitHub):**
|
|
240
|
+
```bash
|
|
241
|
+
gh pr ready {pr-number}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### 6. PR Merge
|
|
245
|
+
|
|
246
|
+
**Trigger:** PR is approved and CI passes.
|
|
247
|
+
|
|
248
|
+
**Merge strategies:**
|
|
249
|
+
|
|
250
|
+
**GitHub (merge commit):**
|
|
251
|
+
```bash
|
|
252
|
+
gh pr merge {pr-number} --merge --delete-branch
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
**GitHub (squash):**
|
|
256
|
+
```bash
|
|
257
|
+
gh pr merge {pr-number} --squash --delete-branch
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
**Azure DevOps:**
|
|
261
|
+
```bash
|
|
262
|
+
az repos pr update --id {pr-id} --status completed --delete-source-branch true
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**Post-merge actions:**
|
|
266
|
+
1. Issue automatically closes (if "Closes #{number}" is in PR description)
|
|
267
|
+
2. Feature branch is deleted
|
|
268
|
+
3. Squad board state transitions to `done`
|
|
269
|
+
4. Worktree cleanup (if worktree was used — #525)
|
|
270
|
+
|
|
271
|
+
### 7. Cleanup
|
|
272
|
+
|
|
273
|
+
**Standard workflow cleanup:**
|
|
274
|
+
```bash
|
|
275
|
+
git checkout main
|
|
276
|
+
git pull
|
|
277
|
+
git branch -d squad/{issue-number}-{slug}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
**Worktree cleanup (future, #525):**
|
|
281
|
+
```bash
|
|
282
|
+
cd {original-cwd}
|
|
283
|
+
git worktree remove ../worktrees/{issue-number}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Spawn Prompt Additions for Issue Work
|
|
287
|
+
|
|
288
|
+
When spawning an agent to work on an issue, include this context block:
|
|
289
|
+
|
|
290
|
+
```markdown
|
|
291
|
+
## ISSUE CONTEXT
|
|
292
|
+
|
|
293
|
+
**Issue:** #{number} — {title}
|
|
294
|
+
**Platform:** {GitHub | Azure DevOps | Planner}
|
|
295
|
+
**Repository:** {owner}/{repo}
|
|
296
|
+
**Assigned to:** {member}
|
|
297
|
+
|
|
298
|
+
**Description:**
|
|
299
|
+
{issue body}
|
|
300
|
+
|
|
301
|
+
**Labels/Tags:**
|
|
302
|
+
{labels}
|
|
303
|
+
|
|
304
|
+
**Acceptance Criteria:**
|
|
305
|
+
{criteria if present in issue}
|
|
306
|
+
|
|
307
|
+
**Branch:** `squad/{issue-number}-{slug}`
|
|
308
|
+
|
|
309
|
+
**Your task:**
|
|
310
|
+
{specific directive to the agent}
|
|
311
|
+
|
|
312
|
+
**After completing work:**
|
|
313
|
+
1. Commit with message referencing issue number
|
|
314
|
+
2. Push branch
|
|
315
|
+
3. Open PR using:
|
|
316
|
+
```
|
|
317
|
+
gh pr create --title "{title}" --body "Closes #{number}\n\n{description}" --head squad/{issue-number}-{slug} --base {base-branch}
|
|
318
|
+
```
|
|
319
|
+
4. Report PR URL to coordinator
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## Ralph's Role in Issue Lifecycle
|
|
323
|
+
|
|
324
|
+
Ralph (the work monitor) continuously checks issue and PR state:
|
|
325
|
+
|
|
326
|
+
1. **Triage:** Detects untriaged issues, assigns `squad:{member}` labels
|
|
327
|
+
2. **Spawn:** Launches agents for assigned issues
|
|
328
|
+
3. **Monitor:** Tracks PR state transitions (needsReview → changesRequested → readyToMerge)
|
|
329
|
+
4. **Merge:** Automatically merges approved PRs
|
|
330
|
+
5. **Cleanup:** Marks issues as done when PRs merge
|
|
331
|
+
|
|
332
|
+
**Ralph's work-check cycle:**
|
|
333
|
+
```
|
|
334
|
+
Scan → Categorize → Dispatch → Watch → Report → Loop
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
See `.squad/templates/ralph-reference.md` for Ralph's full lifecycle.
|
|
338
|
+
|
|
339
|
+
## PR Review Handling
|
|
340
|
+
|
|
341
|
+
### Automated Approval (CI-only projects)
|
|
342
|
+
|
|
343
|
+
If the project has no human reviewers configured:
|
|
344
|
+
1. PR opens
|
|
345
|
+
2. CI runs
|
|
346
|
+
3. If CI passes, Ralph auto-merges
|
|
347
|
+
4. Issue closes
|
|
348
|
+
|
|
349
|
+
### Human Review Required
|
|
350
|
+
|
|
351
|
+
If the project requires human approval:
|
|
352
|
+
1. PR opens
|
|
353
|
+
2. Human reviewer is notified (GitHub/ADO notifications)
|
|
354
|
+
3. Reviewer approves or requests changes
|
|
355
|
+
4. If approved + CI passes, Ralph merges
|
|
356
|
+
5. If changes requested, agent addresses feedback
|
|
357
|
+
|
|
358
|
+
### Squad Member Review
|
|
359
|
+
|
|
360
|
+
If the issue was assigned to a squad member and they authored the PR:
|
|
361
|
+
1. Another squad member reviews (conflict of interest avoidance)
|
|
362
|
+
2. Original author is locked out from re-working rejected code (rejection lockout)
|
|
363
|
+
3. Reviewer can approve edits or reject outright
|
|
364
|
+
|
|
365
|
+
## Common Issue Lifecycle Patterns
|
|
366
|
+
|
|
367
|
+
### Pattern 1: Quick Fix (Single Agent, No Review)
|
|
368
|
+
```
|
|
369
|
+
Issue created → Assigned to agent → Branch created → Code fixed →
|
|
370
|
+
PR opened → CI passes → Auto-merged → Issue closed
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### Pattern 2: Feature Development (Human Review)
|
|
374
|
+
```
|
|
375
|
+
Issue created → Assigned to agent → Branch created → Feature implemented →
|
|
376
|
+
PR opened → Human reviews → Changes requested → Agent fixes →
|
|
377
|
+
Re-reviewed → Approved → Merged → Issue closed
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
### Pattern 3: Research-Then-Implement
|
|
381
|
+
```
|
|
382
|
+
Issue created → Labeled `go:needs-research` → Research agent spawned →
|
|
383
|
+
Research documented → Research PR merged → Implementation issue created →
|
|
384
|
+
Implementation agent spawned → Feature built → PR merged
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### Pattern 4: Parallel Multi-Agent (Future, #525)
|
|
388
|
+
```
|
|
389
|
+
Epic issue created → Decomposed into sub-issues → Each sub-issue assigned →
|
|
390
|
+
Multiple agents work in parallel worktrees → PRs opened concurrently →
|
|
391
|
+
All PRs reviewed → All PRs merged → Epic closed
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
## Anti-Patterns
|
|
395
|
+
|
|
396
|
+
- ❌ Creating branches without linking to an issue
|
|
397
|
+
- ❌ Committing without issue reference in message
|
|
398
|
+
- ❌ Opening PRs without "Closes #{number}" in description
|
|
399
|
+
- ❌ Merging PRs before CI passes
|
|
400
|
+
- ❌ Leaving feature branches undeleted after merge
|
|
401
|
+
- ❌ Using `checkout -b` when parallel agents are active (causes working directory conflicts)
|
|
402
|
+
- ❌ Manually transitioning issue states — let the platform and Squad automation handle it
|
|
403
|
+
- ❌ Skipping the branch naming convention — breaks Ralph's tracking logic
|
|
404
|
+
|
|
405
|
+
## Migration Notes
|
|
406
|
+
|
|
407
|
+
**v0.8.x → v0.9.x (Worktree Support):**
|
|
408
|
+
- `checkout -b` → `git worktree add` for parallel agents
|
|
409
|
+
- Worktree cleanup added to post-merge flow
|
|
410
|
+
- `TEAM_ROOT` passing to agents to support worktree-aware state resolution
|
|
411
|
+
|
|
412
|
+
This template will be updated as worktree lifecycle support lands in #525.
|