main
md 434 lines 10.4 KB
Rendered Raw
1 # Skill: Cross-Machine Coordination Pattern
2
3 **Skill ID:** `cross-machine-coordination`
4 **Owner:** Ralph (Work Monitor)
5 **Squad Integration:** All agents
6 **Status:** Specification (ready for implementation)
7
8 ---
9
10 ## Overview
11
12 Enables squad agents running on different machines (laptop, DevBox, Azure VM) to securely share work, coordinate execution, and pass results without manual intervention.
13
14 **Pattern:** Git-based task queuing + GitHub Issues supplement
15
16 ---
17
18 ## Usage
19
20 ### For Task Sources (Orchestrating Machine)
21
22 **To assign work to DevBox:**
23
24 ```bash
25 # Create task file
26 cat > .squad/cross-machine/tasks/2026-03-14T1530Z-laptop-gpu-voice-clone.yaml << 'EOF'
27 id: gpu-voice-clone-001
28 source_machine: laptop-machine
29 target_machine: devbox
30 priority: high
31 created_at: 2026-03-14T15:30:00Z
32 task_type: gpu_workload
33 payload:
34 command: "python scripts/voice-clone.py --input voice.wav --output cloned.wav"
35 expected_duration_min: 15
36 resources:
37 gpu: true
38 memory_gb: 8
39 status: pending
40 EOF
41
42 # Commit & push
43 git add .squad/cross-machine/tasks/
44 git commit -m "Cross-machine task: GPU voice cloning [squad:machine-devbox]"
45 git push origin main
46 ```
47
48 Ralph on DevBox will:
49 1. Pull the task on next cycle (5-10 min)
50 2. Validate schema & command whitelist
51 3. Execute the GPU workload
52 4. Write result to `.squad/cross-machine/results/gpu-voice-clone-001.yaml`
53 5. Commit & push the result
54
55 ---
56
57 ### For Task Executors (DevBox, Azure VMs)
58
59 Ralph automatically watches `.squad/cross-machine/tasks/` for work targeted at this machine.
60
61 **On each cycle (5-10 min):**
62
63 ```python
64 # Pseudo-code (Ralph implementation)
65 1. git pull origin main
66 2. Load all .yaml files in .squad/cross-machine/tasks/
67 3. Filter for status=pending AND target_machine=HOSTNAME
68 4. For each task:
69 a. Validate schema (must have: id, source_machine, target_machine, payload)
70 b. Validate command against whitelist
71 c. Execute task (with timeout)
72 d. Write result to .squad/cross-machine/results/{id}.yaml
73 e. Commit & push result
74 ```
75
76 ---
77
78 ### For Urgent/Ad-Hoc Tasks
79
80 **Use GitHub Issues with `squad:machine-{name}` label:**
81
82 ```bash
83 # Create issue
84 gh issue create \
85 --title "GPU: Clone voice profile from sample.wav" \
86 --body "Execute voice cloning on DevBox. Input: /path/to/voice-input.wav" \
87 --label "squad:machine-devbox" \
88 --label "urgent"
89 ```
90
91 Ralph on DevBox will:
92 1. Detect issue with `squad:machine-devbox` label
93 2. Parse task from issue body
94 3. Execute task
95 4. Comment with result
96 5. Close issue
97
98 ---
99
100 ## File Formats
101
102 ### Task File (YAML)
103
104 **Location:** `.squad/cross-machine/tasks/{timestamp}-{machine}-{task-id}.yaml`
105
106 **Required Fields:**
107 ```yaml
108 id: {task-id} # Unique identifier (alphanumeric + dash)
109 source_machine: {hostname} # Where task was created
110 target_machine: {hostname} # Where task will execute
111 priority: high|normal|low # Execution priority
112 created_at: 2026-03-14T15:30:00Z # ISO 8601 timestamp
113 task_type: gpu_workload|script|... # Category
114 payload:
115 command: "..." # Shell command to execute
116 expected_duration_min: 15 # Timeout (minutes)
117 resources:
118 gpu: true|false
119 memory_gb: 8
120 cpu_cores: 4
121 status: pending|executing|completed|failed
122 ```
123
124 **Optional Fields:**
125 ```yaml
126 description: "Human-readable task description"
127 timeout_override_min: 120 # Override default timeout
128 retry_count: 3 # Retry failed tasks
129 ```
130
131 ### Result File (YAML)
132
133 **Location:** `.squad/cross-machine/results/{task-id}.yaml`
134
135 ```yaml
136 id: {task-id} # Links back to task
137 target_machine: devbox # Executed on
138 completed_at: 2026-03-14T15:45:00Z # When it finished
139 status: completed|failed|timeout # Outcome
140 exit_code: 0 # Shell exit code
141 stdout: "..." # Captured output
142 stderr: "..." # Captured errors
143 duration_seconds: 900 # How long it took
144 artifacts:
145 - path: "/path/to/artifacts/..." # Location of results
146 type: audio|text|model|...
147 size_mb: 2.5
148 ```
149
150 ---
151
152 ## Security Model
153
154 ### Validation Pipeline
155
156 All tasks go through:
157
158 1. **Schema Validation**
159 - YAML structure matches spec
160 - Required fields present
161 - No unexpected fields (reject)
162
163 2. **Command Whitelist**
164 - Only approved commands allowed
165 - Path validation (no `../../` escapes)
166 - Environment variable sanitization
167 - No inline shell operators (`&&`, `|`, `>`)
168
169 3. **Resource Limits**
170 - Timeout enforced (default: 60 min)
171 - Memory cap: 16GB (adjustable)
172 - CPU threads: 4 (adjustable)
173 - Disk write: 100GB (adjustable)
174
175 4. **Execution Isolation**
176 - Runs as unprivileged user
177 - Temp directory cleaned after execution
178 - Network access: read-only (no outbound writes)
179
180 5. **Audit Trail**
181 - All executions logged to git
182 - Commit signed with Ralph's key
183 - Result stored immutably
184
185 ### Threat Mitigations
186
187 | Threat | Mitigation |
188 |--------|-----------|
189 | **Malicious task injection** | Branch protection + PR review before merge |
190 | **Credential leakage** | Pre-commit secret scan + environment scrubbing |
191 | **Resource exhaustion** | Timeout + memory limits |
192 | **Code injection** | Command whitelist + no shell evaluation |
193 | **Result tampering** | Git commit history is immutable |
194
195 ---
196
197 ## Configuration
198
199 Ralph reads config from `.squad/config.json`:
200
201 ```json
202 {
203 "cross_machine": {
204 "enabled": true,
205 "poll_interval_seconds": 300,
206 "this_machine": "devbox",
207 "max_concurrent_tasks": 2,
208 "task_timeout_minutes": 60,
209 "command_whitelist": [
210 "python scripts/voice-clone.py",
211 "python scripts/data-process.py",
212 "bash scripts/cleanup.sh"
213 ],
214 "result_ttl_days": 30
215 }
216 }
217 ```
218
219 ---
220
221 ## Examples
222
223 ### Example 1: GPU Voice Cloning (Laptop → DevBox)
224
225 **1. Laptop creates task:**
226
227 ```yaml
228 # .squad/cross-machine/tasks/2026-03-14T1530Z-laptop-gpu-001.yaml
229 id: gpu-voice-clone-001
230 source_machine: laptop-machine
231 target_machine: devbox
232 priority: high
233 created_at: 2026-03-14T15:30:00Z
234 task_type: gpu_workload
235 payload:
236 command: "python scripts/voice-clone.py --input voice.wav --output cloned.wav"
237 expected_duration_min: 15
238 resources:
239 gpu: true
240 memory_gb: 8
241 status: pending
242 ```
243
244 **2. Laptop commits & pushes:**
245
246 ```bash
247 git add .squad/cross-machine/tasks/
248 git commit -m "Task: GPU voice cloning [squad:machine-devbox]"
249 git push origin main
250 ```
251
252 **3. DevBox Ralph (5 min later):**
253
254 ```
255 [Ralph Watch Cycle]
256 - Pulled origin/main
257 - Detected: gpu-voice-clone-001 (status: pending, target: devbox)
258 - Validation: ✅ Schema OK, command whitelisted
259 - Executing: python scripts/voice-clone.py ...
260 - [15 minutes of processing]
261 - Completed: exit code 0
262 - Writing result...
263 - Committing & pushing...
264 ```
265
266 **4. Laptop Ralph (next cycle) sees result:**
267
268 ```yaml
269 # .squad/cross-machine/results/gpu-voice-clone-001.yaml
270 id: gpu-voice-clone-001
271 target_machine: devbox
272 completed_at: 2026-03-14T15:45:00Z
273 status: completed
274 exit_code: 0
275 stdout: "Voice cloning completed. Output written to /tmp/cloned.wav"
276 stderr: ""
277 duration_seconds: 900
278 artifacts:
279 - path: "/path/to/artifacts/voice-clone-001/output.wav"
280 type: audio
281 size_mb: 2.5
282 ```
283
284 ---
285
286 ### Example 2: Urgent Debug Request (Human → DevBox via Issue)
287
288 **Create issue:**
289
290 ```bash
291 gh issue create \
292 --title "DevBox: Debug voice model failure" \
293 --body "Error: Model failed to load on last run. Please check /tmp/model.log and report findings." \
294 --label "squad:machine-devbox" \
295 --label "urgent"
296 ```
297
298 **DevBox Ralph detects → executes → comments:**
299
300 ```
301 ✅ Executed on devbox at 2026-03-14 15:47:00
302 Command: python scripts/debug-model.py
303
304 Result:
305 ------
306 Model file: /tmp/model-v2.bin (OK)
307 Checksum: a1b2c3d4e5f6 (matches expected)
308 Memory available: 12 GB (sufficient)
309
310 ERROR FOUND: Config file permission issue
311 - File: ~/.config/voice/model.yaml
312 - Permissions: -rw------- (owner-only)
313 - Expected: -rw-r--r-- (world-readable for service)
314
315 FIX: Run: chmod 644 ~/.config/voice/model.yaml
316 ```
317
318 ---
319
320 ## Error Handling
321
322 ### Task Execution Failures
323
324 If a task fails (exit code != 0):
325
326 1. Result written with `status: failed` + exit code
327 2. stderr captured in result
328 3. Committed to git for audit
329 4. Source machine can retry by re-pushing task with `status: pending`
330
331 ### Stalled Tasks
332
333 If a task doesn't complete within timeout:
334
335 1. Process killed
336 2. Result written with `status: timeout`
337 3. stderr: "Execution exceeded X minutes"
338 4. Source can investigate or retry
339
340 ### Network Failures
341
342 If git push/pull fails:
343
344 - Ralph retries on next cycle
345 - Tasks queue locally until connectivity restored
346 - No tasks lost (stored in local repo)
347
348 ---
349
350 ## Monitoring & Debugging
351
352 ### Check Task Queue
353
354 ```bash
355 ls -la .squad/cross-machine/tasks/
356 cat .squad/cross-machine/tasks/*.yaml | grep -E "^(id|status|target_machine):"
357 ```
358
359 ### Check Results
360
361 ```bash
362 ls -la .squad/cross-machine/results/
363 cat .squad/cross-machine/results/{task-id}.yaml
364 ```
365
366 ### View Execution History
367
368 ```bash
369 git log --oneline .squad/cross-machine/ | head -20
370 ```
371
372 ### Monitor Ralph Cycles
373
374 ```bash
375 tail -f .squad/log/ralph-watch.log | grep "cross-machine"
376 ```
377
378 ---
379
380 ## Integration with Ralph Watch
381
382 Ralph automatically includes this pattern in its watch loop:
383
384 ```
385 Ralph Watch Cycle (every 5-10 min):
386 1. Fetch GitHub issues with squad:machine-* labels
387 2. Poll .squad/cross-machine/tasks/
388 3. For each matching task:
389 - Validate
390 - Execute
391 - Write result
392 - Commit & push
393 4. Update status in issue (if applicable)
394 5. Sleep until next cycle
395 ```
396
397 No manual Ralph configuration needed — just create task files or issues with the right labels.
398
399 ---
400
401 ## Migration from Manual Handoff
402
403 **Before (today):**
404 - Laptop → user manually copies file to Teams chat
405 - user pastes into target terminal
406 - user copies output back
407 - user pastes result manually
408
409 **After (with this pattern):**
410 - Laptop Ralph writes task file → git push
411 - DevBox Ralph auto-executes → git push result
412 - Laptop Ralph auto-reads result
413 - 0 human intervention needed
414
415 ---
416
417 ## Future Enhancements
418
419 Potential expansions (Phase 2+):
420
421 1. **Task Priorities:** Execution order based on priority field
422 2. **Serial Pipelines:** Machine A → B → C task chains
423 3. **GPU Availability Polling:** Query DevBox before submitting work
424 4. **Cost Tracking:** Log resource usage per task
425 5. **Notification Webhooks:** Alert on task completion
426 6. **Web Dashboard:** Real-time task status visualization
427
428 ---
429
430 ## Questions?
431
432 Refer to research report: `research/active/cross-machine-agents/README.md`
433
434 Contact: Seven (Research & Docs) or Ralph (Work Monitor)