gabriel / musehub public
docs_muse_coordination.html html
904 lines 53.2 KB
Raw
sha256:9f5112c9a633a22e53a831c6d3af637093d0ceb914393749905187046f1c548a chore: renumber phases — merge is 05, shift harmony through… Sonnet 4.6 patch 1 day ago
1 {% extends "musehub/base.html" %}
2
3 {% block container_extra_class %} page-container{% endblock %}
4 {% block title %}Agent Coordination — Muse Developer Docs{% endblock %}
5 {% block page_json %}{"page":"docs-coordination"}{% endblock %}
6
7 {% block content %}
8 <div class="devdocs">
9 <div class="devdocs-layout">
10
11 {# ── Sidebar ─────────────────────────────────────────────────────────────── #}
12 <aside class="devdocs-sidebar">
13 <nav class="devdocs-nav" aria-label="Docs navigation">
14 <div class="devdocs-nav-group">
15 <div class="devdocs-nav-group-label">Sections</div>
16 {% for slug, num, title, desc in phases %}
17 <a class="devdocs-nav-link devdocs-nav-link--phase{% if slug == current %} devdocs-nav-link--active{% endif %}"
18 href="/muse/{{ slug }}">{{ num }} {{ title }}</a>
19 {% endfor %}
20 </div>
21 <div class="devdocs-nav-group">
22 <div class="devdocs-nav-group-label">On this page</div>
23 <a class="devdocs-nav-link devdocs-nav-link--sub" href="#overview">Overview</a>
24 <a class="devdocs-nav-link devdocs-nav-link--sub" href="#scenario">Multi-agent scenario</a>
25 <a class="devdocs-nav-link devdocs-nav-link--sub" href="#queues">Work queues</a>
26 <a class="devdocs-nav-link devdocs-nav-link--sub" href="#lifecycle">Claim lifecycle</a>
27 <a class="devdocs-nav-link devdocs-nav-link--sub" href="#reservations">Reservations</a>
28 <a class="devdocs-nav-link devdocs-nav-link--sub" href="#heartbeat">Heartbeat</a>
29 <a class="devdocs-nav-link devdocs-nav-link--sub" href="#dag">Dependency DAG</a>
30 <a class="devdocs-nav-link devdocs-nav-link--sub" href="#sharding">Sharding</a>
31 <a class="devdocs-nav-link devdocs-nav-link--sub" href="#forecast">Forecasting</a>
32 <a class="devdocs-nav-link devdocs-nav-link--sub" href="#watch">Watch</a>
33 <a class="devdocs-nav-link devdocs-nav-link--sub" href="#sync">Sync</a>
34 <a class="devdocs-nav-link devdocs-nav-link--sub" href="#storage">Storage layout</a>
35 <a class="devdocs-nav-link devdocs-nav-link--sub" href="#cli">CLI reference</a>
36 </div>
37 </nav>
38 </aside>
39
40 {# ── Main content ─────────────────────────────────────────────────────────── #}
41 <main class="devdocs-content" id="main-content">
42
43 <div class="devdocs-breadcrumb">
44 <a href="/muse">Developer Docs</a>
45 <span>›</span>
46 <span>Agent Coordination</span>
47 </div>
48
49 <div class="devdocs-phase-header">
50 <span class="devdocs-phase-num">PHASE 07</span>
51 <h1 class="devdocs-phase-title">Agent Coordination</h1>
52 <p class="devdocs-phase-desc">
53 Muse's coordination layer lets multiple agents work a shared codebase in parallel
54 without stepping on each other. It provides file-backed work queues with POSIX-atomic
55 claiming, advisory symbol reservations with heartbeat keep-alive, a dependency DAG for
56 ordering, import-graph sharding for zero-interference parallelism, and a three-pass
57 conflict forecast before a single line of code changes.
58 </p>
59 </div>
60
61 <div class="devdocs-callout">
62 {{ icon("info", 16, "devdocs-callout-icon") }}
63 <div>
64 <strong>File-backed, no broker required</strong> — all coordination state lives in
65 <code>.muse/coordination/</code> as content-addressed JSON. Remote sync to MuseHub
66 is optional; everything works offline.
67 </div>
68 </div>
69
70 {# ── Overview ──────────────────────────────────────────────────────────── #}
71 <section class="devdocs-section" id="overview">
72 <h2>Overview</h2>
73 <p>
74 Two independent primitives compose the system:
75 </p>
76 <table class="devdocs-table">
77 <thead><tr><th>Primitive</th><th>Purpose</th><th>Atomicity</th></tr></thead>
78 <tbody>
79 <tr>
80 <td><strong>Task queue</strong></td>
81 <td>Distribute discrete units of work across agents. Producer enqueues; consumers race to claim; winner completes or fails.</td>
82 <td><code>open(O_CREAT|O_EXCL)</code> — POSIX-guaranteed single winner</td>
83 </tr>
84 <tr>
85 <td><strong>Reservations</strong></td>
86 <td>Advisory symbol-address leases. Agents declare intent before touching a symbol; <code>muse coord forecast</code> detects overlaps before they happen.</td>
87 <td><code>write_text_atomic()</code> (atomic rename); content-addressed ID prevents duplicates</td>
88 </tr>
89 </tbody>
90 </table>
91
92 <p>
93 A typical multi-agent pipeline:
94 </p>
95 <div class="devdocs-code-block">
96 <pre><span class="tok-cmt"># Orchestrator shards the repo into N parallel zones</span>
97 <span class="tok-fn">muse</span> coord shard <span class="tok-kw">--agents</span> <span class="tok-num">4</span> <span class="tok-kw">--json</span>
98
99 <span class="tok-cmt"># Orchestrator enqueues one task per shard</span>
100 <span class="tok-fn">muse</span> coord enqueue <span class="tok-str">"Refactor shard 1"</span> <span class="tok-kw">--queue</span> refactor \
101 <span class="tok-kw">--payload</span> <span class="tok-str">'{"files":["src/billing.py","src/models.py"]}'</span> \
102 <span class="tok-kw">--run-id</span> orchestrator <span class="tok-kw">--json</span>
103
104 <span class="tok-cmt"># Each worker claims one task</span>
105 <span class="tok-fn">muse</span> coord claim <span class="tok-kw">--queue</span> refactor <span class="tok-kw">--run-id</span> agent-1 <span class="tok-kw">--json</span>
106
107 <span class="tok-cmt"># Worker reserves the symbols it will touch</span>
108 <span class="tok-fn">muse</span> coord reserve <span class="tok-str">"src/billing.py::compute_total"</span> \
109 <span class="tok-kw">--run-id</span> agent-1 <span class="tok-kw">--op</span> modify <span class="tok-kw">--ttl</span> <span class="tok-num">7200</span> <span class="tok-kw">--json</span>
110
111 <span class="tok-cmt"># Forecast before any writes</span>
112 <span class="tok-fn">muse</span> coord forecast <span class="tok-kw">--json</span>
113
114 <span class="tok-cmt"># Work … commit … then release and complete</span>
115 <span class="tok-fn">muse</span> coord release &lt;reservation_id&gt; <span class="tok-kw">--run-id</span> agent-1 <span class="tok-kw">--json</span>
116 <span class="tok-fn">muse</span> coord complete &lt;task_id&gt; <span class="tok-kw">--run-id</span> agent-1 <span class="tok-kw">--json</span></pre>
117 </div>
118 </section>
119
120 {# ── Multi-agent scenario ─────────────────────────────────────────────── #}
121 <section class="devdocs-section" id="scenario">
122 <h2 class="devdocs-section-title"><a href="#scenario">Multi-agent scenario — orchestrator + 3 workers</a></h2>
123
124 <p>
125 This scenario shows a complete pipeline: one orchestrator shards the repo, enqueues
126 three tasks, three workers race to claim them, a forecast catches a symbol overlap
127 before any code changes, and the orchestrator collects all results.
128 </p>
129
130 <h3 class="devdocs-subsection-title"><a href="#scenario-shard">Step 1 — shard and enqueue</a></h3>
131
132 <div class="devdocs-code-block">
133 <div class="devdocs-code-header">
134 <span class="devdocs-code-lang">bash</span>
135 <span class="devdocs-code-label">orchestrator — shard into 3 zones, enqueue 3 tasks</span>
136 </div>
137 <pre><code><span class="tok-cmt"># 1. Split the import graph into 3 parallel-safe zones</span>
138 muse coord shard --agents <span class="tok-num">3</span> --json \
139 | python3 -c "import sys,json; [print(s['shard'], s['files']) for s in json.load(sys.stdin)['shards']]"
140 <span class="tok-cmt"># 1 ['src/billing.py', 'src/models.py']</span>
141 <span class="tok-cmt"># 2 ['src/auth.py', 'src/tokens.py']</span>
142 <span class="tok-cmt"># 3 ['src/api.py', 'src/middleware.py']</span>
143
144 <span class="tok-cmt"># 2. Enqueue one task per shard</span>
145 muse coord enqueue "Refactor shard 1" --queue refactor --priority <span class="tok-num">10</span> \
146 --payload '{"files":["src/billing.py","src/models.py"]}' \
147 --run-id orchestrator --json
148 muse coord enqueue "Refactor shard 2" --queue refactor --priority <span class="tok-num">10</span> \
149 --payload '{"files":["src/auth.py","src/tokens.py"]}' \
150 --run-id orchestrator --json
151 muse coord enqueue "Refactor shard 3" --queue refactor --priority <span class="tok-num">10</span> \
152 --payload '{"files":["src/api.py","src/middleware.py"]}' \
153 --run-id orchestrator --json</code></pre>
154 </div>
155
156 <h3 class="devdocs-subsection-title"><a href="#scenario-claim">Step 2 — workers race to claim</a></h3>
157
158 <div class="devdocs-code-block">
159 <div class="devdocs-code-header">
160 <span class="devdocs-code-lang">bash</span>
161 <span class="devdocs-code-label">three workers run this concurrently — each gets a different task</span>
162 </div>
163 <pre><code><span class="tok-cmt"># Each worker claims from the refactor queue (POSIX-atomic, one winner per task)</span>
164 TASK=$(muse coord claim --queue refactor --run-id agent-1 --json)
165 TASK_ID=$(echo "$TASK" | python3 -c "import sys,json; print(json.load(sys.stdin)['task_id'])")
166 FILES=$(echo "$TASK" | python3 -c "import sys,json; print(json.load(sys.stdin)['payload']['files'])")</code></pre>
167 </div>
168 <div class="devdocs-code-block devdocs-code-block--output">
169 <div class="devdocs-code-header">
170 <span class="devdocs-code-lang">json</span>
171 <span class="devdocs-code-label">agent-1 claim response</span>
172 </div>
173 <pre><code>{
174 <span class="tok-key">"task_id"</span>: <span class="tok-str">"sha256:4e8b2f1a3c7d..."</span>,
175 <span class="tok-key">"title"</span>: <span class="tok-str">"Refactor shard 1"</span>,
176 <span class="tok-key">"queue"</span>: <span class="tok-str">"refactor"</span>,
177 <span class="tok-key">"claimer_run_id"</span>: <span class="tok-str">"agent-1"</span>,
178 <span class="tok-key">"claimed_at"</span>: <span class="tok-str">"2026-04-21T16:00:00Z"</span>,
179 <span class="tok-key">"expires_at"</span>: <span class="tok-str">"2026-04-21T17:00:00Z"</span>,
180 <span class="tok-key">"payload"</span>: { <span class="tok-key">"files"</span>: [<span class="tok-str">"src/billing.py"</span>, <span class="tok-str">"src/models.py"</span>] }
181 }</code></pre>
182 </div>
183
184 <h3 class="devdocs-subsection-title"><a href="#scenario-reserve">Step 3 — reserve symbols, run forecast</a></h3>
185
186 <div class="devdocs-code-block">
187 <div class="devdocs-code-header">
188 <span class="devdocs-code-lang">bash</span>
189 <span class="devdocs-code-label">each worker reserves before touching — agent-1 and agent-2 both reserve compute_total</span>
190 </div>
191 <pre><code><span class="tok-cmt"># agent-1: billing shard</span>
192 muse coord reserve "src/billing.py::compute_total" \
193 --run-id agent-1 --op modify --ttl <span class="tok-num">7200</span> --json
194
195 <span class="tok-cmt"># agent-2: auth shard — also touches compute_total (import chain)</span>
196 muse coord reserve "src/billing.py::compute_total" \
197 --run-id agent-2 --op rename --ttl <span class="tok-num">7200</span> --json
198
199 <span class="tok-cmt"># orchestrator: forecast before any agent writes code</span>
200 muse coord forecast --json</code></pre>
201 </div>
202 <div class="devdocs-code-block devdocs-code-block--output">
203 <div class="devdocs-code-header">
204 <span class="devdocs-code-lang">json</span>
205 <span class="devdocs-code-label">forecast — overlap detected</span>
206 </div>
207 <pre><code>{
208 <span class="tok-key">"active_reservations"</span>: <span class="tok-num">3</span>,
209 <span class="tok-key">"call_graph_available"</span>: <span class="tok-kw">true</span>,
210 <span class="tok-key">"partial_forecast"</span>: <span class="tok-kw">false</span>,
211 <span class="tok-key">"conflicts"</span>: [
212 {
213 <span class="tok-key">"conflict_type"</span>: <span class="tok-str">"address_overlap"</span>,
214 <span class="tok-key">"addresses"</span>: [<span class="tok-str">"src/billing.py::compute_total"</span>],
215 <span class="tok-key">"agents"</span>: [<span class="tok-str">"agent-1@feat/refactor"</span>, <span class="tok-str">"agent-2@feat/auth"</span>],
216 <span class="tok-key">"confidence"</span>: <span class="tok-num">1.0</span>,
217 <span class="tok-key">"description"</span>: <span class="tok-str">"Symbol reserved by 2 agents on different branches"</span>
218 },
219 {
220 <span class="tok-key">"conflict_type"</span>: <span class="tok-str">"operation_conflict"</span>,
221 <span class="tok-key">"addresses"</span>: [<span class="tok-str">"src/billing.py::compute_total"</span>],
222 <span class="tok-key">"agents"</span>: [<span class="tok-str">"agent-1@feat/refactor"</span>, <span class="tok-str">"agent-2@feat/auth"</span>],
223 <span class="tok-key">"confidence"</span>: <span class="tok-num">0.9</span>,
224 <span class="tok-key">"description"</span>: <span class="tok-str">"Incompatible operations: modify vs rename on same symbol"</span>
225 }
226 ],
227 <span class="tok-key">"high_risk"</span>: <span class="tok-num">2</span>,
228 <span class="tok-key">"medium_risk"</span>: <span class="tok-num">0</span>,
229 <span class="tok-key">"low_risk"</span>: <span class="tok-num">0</span>
230 }</code></pre>
231 </div>
232
233 <p>
234 Orchestrator sees the conflict and serializes the work: agent-1 renames first,
235 agent-2's reservation is updated to <code>depends-on</code> agent-1's:
236 </p>
237
238 <div class="devdocs-code-block">
239 <div class="devdocs-code-header">
240 <span class="devdocs-code-lang">bash</span>
241 <span class="devdocs-code-label">orchestrator resolves the overlap — serialize via depends-on</span>
242 </div>
243 <pre><code><span class="tok-cmt"># Agent-2 releases its reservation and re-reserves with depends-on</span>
244 muse coord release &lt;agent-2-reservation-id&gt; --run-id agent-2 --json
245 muse coord reserve "src/billing.py::compute_total" \
246 --run-id agent-2 --op modify --ttl <span class="tok-num">7200</span> \
247 --depends-on &lt;agent-1-reservation-id&gt; --json</code></pre>
248 </div>
249
250 <h3 class="devdocs-subsection-title"><a href="#scenario-complete">Step 4 — work, commit, release, complete</a></h3>
251
252 <div class="devdocs-code-block">
253 <div class="devdocs-code-header">
254 <span class="devdocs-code-lang">bash</span>
255 <span class="devdocs-code-label">each worker — do work, commit, then release and complete</span>
256 </div>
257 <pre><code><span class="tok-cmt"># ... agent does work on its branch ...</span>
258 muse commit -m "refactor: shard 1 billing module" \
259 --agent-id claude-code --model-id claude-sonnet-4-6 --sign
260
261 <span class="tok-cmt"># Release all reservations for this run</span>
262 muse coord release --all-for-run agent-1 --run-id agent-1 --json
263
264 <span class="tok-cmt"># Complete the task with a structured result</span>
265 muse coord complete sha256:4e8b2f1a3c7d... \
266 --run-id agent-1 \
267 --result '{"symbols_modified": 12, "tests_passing": true}' \
268 --json</code></pre>
269 </div>
270
271 <h3 class="devdocs-subsection-title"><a href="#scenario-collect">Step 5 — orchestrator collects results</a></h3>
272
273 <div class="devdocs-code-block">
274 <div class="devdocs-code-header">
275 <span class="devdocs-code-lang">bash</span>
276 <span class="devdocs-code-label">orchestrator — wait for all tasks to complete</span>
277 </div>
278 <pre><code>muse coord tasks --queue refactor --status completed --json \
279 | python3 -c "
280 import sys, json
281 data = json.load(sys.stdin)
282 for t in data['tasks']:
283 print(t['title'], '→', t['result'])
284 "</code></pre>
285 </div>
286 <div class="devdocs-code-block devdocs-code-block--output">
287 <div class="devdocs-code-header">
288 <span class="devdocs-code-lang">text</span>
289 <span class="devdocs-code-label">output</span>
290 </div>
291 <pre><code>Refactor shard 1 → {'symbols_modified': 12, 'tests_passing': True}
292 Refactor shard 2 → {'symbols_modified': 8, 'tests_passing': True}
293 Refactor shard 3 → {'symbols_modified': 5, 'tests_passing': True}</code></pre>
294 </div>
295 </section>
296
297 {# ── Work queues ───────────────────────────────────────────────────────── #}
298 <section class="devdocs-section" id="queues">
299 <h2>Work queues</h2>
300 <p>
301 Tasks are content-addressed by their inputs — same title + queue + payload + priority
302 + creator always produces the same <code>task_id</code>. Queues are named strings;
303 any alphanumeric-plus-hyphen-or-underscore name up to 64 chars is valid.
304 </p>
305
306 <h3>TaskRecord fields</h3>
307 <table class="devdocs-table">
308 <thead><tr><th>Field</th><th>Type</th><th>Description</th></tr></thead>
309 <tbody>
310 <tr><td><code>task_id</code></td><td>str (sha256:…)</td><td>Content-addressed; same inputs → same ID (idempotent enqueue)</td></tr>
311 <tr><td><code>title</code></td><td>str ≤256</td><td>Short human-readable description of the work unit</td></tr>
312 <tr><td><code>payload</code></td><td>dict</td><td>Arbitrary JSON — agent-specific data passed to the claimer</td></tr>
313 <tr><td><code>priority</code></td><td>int</td><td>Higher = claimed first; ties broken by <code>created_at</code> FIFO</td></tr>
314 <tr><td><code>queue</code></td><td>str ≤64</td><td>Queue name <code>[a-zA-Z0-9_-]+</code>; default <code>"default"</code></td></tr>
315 <tr><td><code>created_at</code></td><td>datetime (UTC)</td><td>Enqueue timestamp</td></tr>
316 <tr><td><code>created_by</code></td><td>str ≤256</td><td><code>run_id</code> of the enqueuing agent</td></tr>
317 <tr><td><code>ttl_seconds</code></td><td>int</td><td>Seconds from <code>created_at</code> before pending task expires; default 86400 (24h)</td></tr>
318 <tr><td><code>tags</code></td><td>list[str]</td><td>Up to 32 tags, each ≤64 chars; for filtering and grouping</td></tr>
319 </tbody>
320 </table>
321
322 <div class="devdocs-code-block">
323 <pre><span class="tok-fn">muse</span> coord enqueue <span class="tok-str">"Lint billing module"</span> \
324 <span class="tok-kw">--queue</span> lint \
325 <span class="tok-kw">--priority</span> <span class="tok-num">10</span> \
326 <span class="tok-kw">--payload</span> <span class="tok-str">'{"file": "src/billing.py"}'</span> \
327 <span class="tok-kw">--ttl</span> <span class="tok-num">3600</span> \
328 <span class="tok-kw">--tags</span> billing python \
329 <span class="tok-kw">--run-id</span> orch <span class="tok-kw">--json</span></pre>
330 </div>
331 </section>
332
333 {# ── Claim lifecycle ───────────────────────────────────────────────────── #}
334 <section class="devdocs-section" id="lifecycle">
335 <h2>Claim lifecycle</h2>
336 <p>
337 Task state is derived from two files: the task record (immutable) and the claim record
338 (mutable). The claim file is created with <code>open(O_CREAT|O_EXCL)</code> — POSIX
339 guarantees exactly one agent wins the race; all others get <code>FileExistsError</code>.
340 </p>
341
342 <div class="devdocs-code-block">
343 <pre>pending ──[O_CREAT|O_EXCL, one winner]──→ claimed
344
345 ┌───────────────────────────┼────────────────┐
346 ↓ ↓ ↓
347 completed failed cancelled
348 (result set) (error set)
349
350 ↑ Re-claim path (timed_out):
351 claimed ──[expires_at ≤ now]──→ timed_out ──[write_atomic + nonce]──→ claimed</pre>
352 </div>
353
354 <h3>ClaimRecord fields</h3>
355 <table class="devdocs-table">
356 <thead><tr><th>Field</th><th>Type</th><th>Description</th></tr></thead>
357 <tbody>
358 <tr><td><code>task_id</code></td><td>str (sha256:…)</td><td>Links to the immutable TaskRecord</td></tr>
359 <tr><td><code>claimer_run_id</code></td><td>str ≤256</td><td>Agent that claimed the task</td></tr>
360 <tr><td><code>claimed_at</code></td><td>datetime (UTC)</td><td>Initial claim timestamp</td></tr>
361 <tr><td><code>expires_at</code></td><td>datetime (UTC)</td><td>Claim TTL; default 3600s; extended by heartbeat</td></tr>
362 <tr><td><code>status</code></td><td>str</td><td><code>"claimed"</code> <code>"completed"</code> <code>"failed"</code> <code>"cancelled"</code> <code>"timed_out"</code></td></tr>
363 <tr><td><code>heartbeat_at</code></td><td>datetime (UTC)</td><td>Last heartbeat timestamp</td></tr>
364 <tr><td><code>claim_nonce</code></td><td>str</td><td>Optimistic concurrency token for re-claim race resolution</td></tr>
365 <tr><td><code>result</code></td><td>dict | null</td><td>Set by <code>muse coord complete --result JSON</code></td></tr>
366 <tr><td><code>error</code></td><td>str | null</td><td>Set by <code>muse coord fail-task --error MSG</code></td></tr>
367 </tbody>
368 </table>
369
370 <h3>Claiming and re-claiming</h3>
371 <p>
372 <code>muse coord claim</code> scans the queue sorted by <em>priority descending, then
373 created_at ascending</em> (FIFO within a priority band). It tries each candidate in
374 order:
375 </p>
376 <ol>
377 <li><strong>Pending task</strong> — <code>open(O_CREAT|O_EXCL)</code>. POSIX-atomic. First agent to call wins; rest loop to the next candidate.</li>
378 <li><strong>Timed-out task</strong> — <code>write_text_atomic</code> with a fresh <code>claim_nonce</code>, then read back. If the nonce matches, the agent won the re-claim race. If not, another agent beat it; loop to the next candidate.</li>
379 </ol>
380
381 <div class="devdocs-code-block">
382 <pre><span class="tok-fn">muse</span> coord claim <span class="tok-kw">--queue</span> refactor <span class="tok-kw">--run-id</span> agent-1 <span class="tok-kw">--json</span>
383
384 <span class="tok-fn">muse</span> coord complete &lt;task_id&gt; <span class="tok-kw">--run-id</span> agent-1 \
385 <span class="tok-kw">--result</span> <span class="tok-str">'{"symbols_renamed": 7}'</span> <span class="tok-kw">--json</span>
386
387 <span class="tok-fn">muse</span> coord fail-task &lt;task_id&gt; <span class="tok-kw">--run-id</span> agent-1 \
388 <span class="tok-kw">--error</span> <span class="tok-str">"AST parse failed on line 42"</span> <span class="tok-kw">--json</span>
389
390 <span class="tok-fn">muse</span> coord cancel-task &lt;task_id&gt; <span class="tok-kw">--run-id</span> orch <span class="tok-kw">--json</span>
391
392 <span class="tok-fn">muse</span> coord tasks <span class="tok-kw">--queue</span> refactor <span class="tok-kw">--status</span> pending <span class="tok-kw">--json</span></pre>
393 </div>
394
395 <div class="devdocs-callout">
396 {{ icon("info", 16, "devdocs-callout-icon") }}
397 <div>
398 Only the <code>claimer_run_id</code> may call <code>complete</code>, <code>fail-task</code>,
399 or <code>heartbeat</code> on a claim. Orchestrators use <code>cancel-task</code>.
400 </div>
401 </div>
402 </section>
403
404 {# ── Reservations ──────────────────────────────────────────────────────── #}
405 <section class="devdocs-section" id="reservations">
406 <h2>Reservations</h2>
407 <p>
408 A reservation is an advisory symbol-address lease. It does not prevent writes
409 (no lock server required) — it signals intent so <code>muse coord forecast</code>
410 can detect overlaps before they produce merge conflicts.
411 </p>
412
413 <h3>ReservationRecord fields</h3>
414 <table class="devdocs-table">
415 <thead><tr><th>Field</th><th>Type</th><th>Description</th></tr></thead>
416 <tbody>
417 <tr><td><code>reservation_id</code></td><td>str (sha256:…)</td><td>Content-addressed: <code>SHA-256(run_id, branch, sorted(addresses), operation)</code></td></tr>
418 <tr><td><code>run_id</code></td><td>str ≤256</td><td>Agent identifier — use your pipeline ID</td></tr>
419 <tr><td><code>branch</code></td><td>str</td><td>Branch this agent is working on</td></tr>
420 <tr><td><code>addresses</code></td><td>list[str]</td><td>Symbol addresses; <code>fnmatch</code> glob patterns supported (<code>"billing.py::*"</code>)</td></tr>
421 <tr><td><code>created_at</code></td><td>datetime (UTC)</td><td>Reservation creation time</td></tr>
422 <tr><td><code>expires_at</code></td><td>datetime (UTC)</td><td>Hard TTL expiry; extended by heartbeat</td></tr>
423 <tr><td><code>operation</code></td><td>str | null</td><td><code>"modify"</code> <code>"rename"</code> <code>"delete"</code> <code>"extract"</code> <code>"move"</code> — used by Tier 3 forecast</td></tr>
424 </tbody>
425 </table>
426
427 <div class="devdocs-callout">
428 {{ icon("info", 16, "devdocs-callout-icon") }}
429 <div>
430 The reservation ID is <em>content-addressed</em> — calling <code>muse coord reserve</code>
431 twice with the same arguments returns the same ID and writes a single file. Idempotent.
432 </div>
433 </div>
434
435 <div class="devdocs-code-block">
436 <pre><span class="tok-cmt"># reserve one symbol</span>
437 <span class="tok-fn">muse</span> coord reserve <span class="tok-str">"src/billing.py::compute_total"</span> \
438 <span class="tok-kw">--run-id</span> agent-1 <span class="tok-kw">--op</span> modify <span class="tok-kw">--ttl</span> <span class="tok-num">7200</span> <span class="tok-kw">--json</span>
439
440 <span class="tok-cmt"># reserve an entire file with a glob</span>
441 <span class="tok-fn">muse</span> coord reserve <span class="tok-str">"src/billing.py::*"</span> \
442 <span class="tok-kw">--run-id</span> agent-1 <span class="tok-kw">--op</span> rename <span class="tok-kw">--json</span>
443
444 <span class="tok-cmt"># release when done</span>
445 <span class="tok-fn">muse</span> coord release &lt;reservation_id&gt; <span class="tok-kw">--run-id</span> agent-1 <span class="tok-kw">--json</span>
446
447 <span class="tok-cmt"># release everything for a run (end of pipeline)</span>
448 <span class="tok-fn">muse</span> coord release <span class="tok-kw">--all-for-run</span> agent-1 <span class="tok-kw">--run-id</span> agent-1 <span class="tok-kw">--json</span></pre>
449 </div>
450
451 <h3>Active-reservation check</h3>
452 <p>A reservation is active when <em>all</em> of the following hold:</p>
453 <ol>
454 <li>No release tombstone exists for <code>reservation_id</code></li>
455 <li><code>now &lt; max(expires_at, heartbeat.extended_expires_at)</code></li>
456 </ol>
457 <p>
458 Once a release tombstone is written it is checked before full JSON parsing — the
459 stem-only scan makes active-check O(n) in file count, not file size.
460 </p>
461 </section>
462
463 {# ── Heartbeat ─────────────────────────────────────────────────────────── #}
464 <section class="devdocs-section" id="heartbeat">
465 <h2>Heartbeat — TTL extension</h2>
466 <p>
467 Long-running agents extend their reservations and claim TTLs with heartbeats.
468 Each heartbeat atomically rewrites a single file with a new <code>extended_expires_at</code>.
469 </p>
470
471 <table class="devdocs-table">
472 <thead><tr><th>Field</th><th>Description</th></tr></thead>
473 <tbody>
474 <tr><td><code>reservation_id</code></td><td>Which reservation this keep-alive extends</td></tr>
475 <tr><td><code>run_id</code></td><td>Must match the reservation's <code>run_id</code></td></tr>
476 <tr><td><code>last_beat_at</code></td><td>This heartbeat's timestamp</td></tr>
477 <tr><td><code>extended_expires_at</code></td><td><code>now + extension_seconds</code> — new effective expiry</td></tr>
478 </tbody>
479 </table>
480
481 <div class="devdocs-code-block">
482 <pre><span class="tok-cmt"># extend reservation TTL</span>
483 <span class="tok-fn">muse</span> coord heartbeat &lt;reservation_id&gt; <span class="tok-kw">--run-id</span> agent-1 <span class="tok-kw">--json</span>
484
485 <span class="tok-cmt"># extend task claim TTL</span>
486 <span class="tok-fn">muse</span> coord heartbeat &lt;task_id&gt; <span class="tok-kw">--run-id</span> agent-1 <span class="tok-kw">--json</span>
487
488 <span class="tok-cmt"># recommended poll interval: extension_seconds / 2</span>
489 <span class="tok-cmt"># default extension: 3600s → heartbeat every ~1800s</span></pre>
490 </div>
491
492 <p>
493 Reservation TTL defaults: 3600s. Claim TTL defaults: 3600s. Task pending TTL defaults: 86400s
494 (24h). Extension range: 1s – 31,536,000s (1 year).
495 </p>
496 </section>
497
498 {# ── Dependency DAG ────────────────────────────────────────────────────── #}
499 <section class="devdocs-section" id="dag">
500 <h2>Dependency DAG</h2>
501 <p>
502 Reservations can declare dependencies on other reservations — "I cannot start until
503 agent-B's rename is complete." The DAG enforces ordering without a central scheduler.
504 Acyclicity is checked at write time; cycles are structurally impossible on disk.
505 </p>
506
507 <h3 class="devdocs-subsection-title"><a href="#dag-depends-on">Three-step dependency chain</a></h3>
508
509 <p>
510 A rename must happen before modify, which must happen before the test update.
511 Each reservation declares its predecessor with <code>--depends-on</code>:
512 </p>
513
514 <div class="devdocs-code-block">
515 <div class="devdocs-code-header">
516 <span class="devdocs-code-lang">bash</span>
517 <span class="devdocs-code-label">build a rename → modify → test chain</span>
518 </div>
519 <pre><code><span class="tok-cmt"># Step 1 — agent-A renames the symbol (no dependency)</span>
520 RENAME_ID=$(muse coord reserve "src/billing.py::compute_total" \
521 --run-id agent-A --op rename --json \
522 | python3 -c "import sys,json; print(json.load(sys.stdin)['reservation_id'])")
523
524 <span class="tok-cmt"># Step 2 — agent-B modifies the renamed symbol (waits for step 1)</span>
525 MODIFY_ID=$(muse coord reserve "src/billing.py::compute_invoice_total" \
526 --run-id agent-B --op modify --depends-on $RENAME_ID --json \
527 | python3 -c "import sys,json; print(json.load(sys.stdin)['reservation_id'])")
528
529 <span class="tok-cmt"># Step 3 — agent-C updates tests (waits for step 2)</span>
530 muse coord reserve "tests/test_billing.py::test_total" \
531 --run-id agent-C --op modify --depends-on $MODIFY_ID --json</code></pre>
532 </div>
533
534 <p>
535 Check whether agent-B is blocked before it starts work:
536 </p>
537
538 <div class="devdocs-code-block">
539 <div class="devdocs-code-header">
540 <span class="devdocs-code-lang">bash</span>
541 <span class="devdocs-code-label">inspect the DAG</span>
542 </div>
543 <pre><code>muse coord dag --json</code></pre>
544 </div>
545 <div class="devdocs-code-block devdocs-code-block--output">
546 <div class="devdocs-code-header">
547 <span class="devdocs-code-lang">json</span>
548 <span class="devdocs-code-label">DAG output — topological order and blocked nodes</span>
549 </div>
550 <pre><code>{
551 <span class="tok-key">"nodes"</span>: [
552 { <span class="tok-key">"reservation_id"</span>: <span class="tok-str">"a1b2c3..."</span>, <span class="tok-key">"run_id"</span>: <span class="tok-str">"agent-A"</span>,
553 <span class="tok-key">"addresses"</span>: [<span class="tok-str">"src/billing.py::compute_total"</span>],
554 <span class="tok-key">"operation"</span>: <span class="tok-str">"rename"</span>, <span class="tok-key">"status"</span>: <span class="tok-str">"active"</span>, <span class="tok-key">"depends_on"</span>: [] },
555 { <span class="tok-key">"reservation_id"</span>: <span class="tok-str">"d4e5f6..."</span>, <span class="tok-key">"run_id"</span>: <span class="tok-str">"agent-B"</span>,
556 <span class="tok-key">"addresses"</span>: [<span class="tok-str">"src/billing.py::compute_invoice_total"</span>],
557 <span class="tok-key">"operation"</span>: <span class="tok-str">"modify"</span>, <span class="tok-key">"status"</span>: <span class="tok-str">"blocked"</span>, <span class="tok-key">"depends_on"</span>: [<span class="tok-str">"a1b2c3..."</span>] },
558 { <span class="tok-key">"reservation_id"</span>: <span class="tok-str">"g7h8i9..."</span>, <span class="tok-key">"run_id"</span>: <span class="tok-str">"agent-C"</span>,
559 <span class="tok-key">"addresses"</span>: [<span class="tok-str">"tests/test_billing.py::test_total"</span>],
560 <span class="tok-key">"operation"</span>: <span class="tok-str">"modify"</span>, <span class="tok-key">"status"</span>: <span class="tok-str">"blocked"</span>, <span class="tok-key">"depends_on"</span>: [<span class="tok-str">"d4e5f6..."</span>] }
561 ],
562 <span class="tok-key">"edges"</span>: [
563 { <span class="tok-key">"from"</span>: <span class="tok-str">"a1b2c3..."</span>, <span class="tok-key">"to"</span>: <span class="tok-str">"d4e5f6..."</span>, <span class="tok-key">"reason"</span>: <span class="tok-str">"depends_on"</span> },
564 { <span class="tok-key">"from"</span>: <span class="tok-str">"d4e5f6..."</span>, <span class="tok-key">"to"</span>: <span class="tok-str">"g7h8i9..."</span>, <span class="tok-key">"reason"</span>: <span class="tok-str">"depends_on"</span> }
565 ],
566 <span class="tok-key">"topological_order"</span>: [<span class="tok-str">"a1b2c3..."</span>, <span class="tok-str">"d4e5f6..."</span>, <span class="tok-str">"g7h8i9..."</span>],
567 <span class="tok-key">"cycles"</span>: [],
568 <span class="tok-key">"active_count"</span>: <span class="tok-num">1</span>,
569 <span class="tok-key">"blocked_count"</span>: <span class="tok-num">2</span>
570 }</code></pre>
571 </div>
572
573 <div class="devdocs-code-block">
574 <div class="devdocs-code-header">
575 <span class="devdocs-code-lang">text</span>
576 <span class="devdocs-code-label">visual (topological order — safe execution sequence)</span>
577 </div>
578 <pre><code>agent-A rename compute_total [ACTIVE]
579 └─[depends_on]──▶ agent-B modify compute_invoice_total [BLOCKED]
580 └─[depends_on]──▶ agent-C modify test_total [BLOCKED]</code></pre>
581 </div>
582
583 <div class="devdocs-code-block">
584 <div class="devdocs-code-header">
585 <span class="devdocs-code-lang">bash</span>
586 <span class="devdocs-code-label">inspect and release commands</span>
587 </div>
588 <pre><code><span class="tok-cmt"># inspect the full DAG</span>
589 <span class="tok-fn">muse</span> coord dag <span class="tok-kw">--json</span>
590
591 <span class="tok-cmt"># show only active (unblocked) nodes</span>
592 <span class="tok-fn">muse</span> coord dag <span class="tok-kw">--active-only</span> <span class="tok-kw">--json</span></code></pre>
593 </div>
594
595 <h3 class="devdocs-subsection-title"><a href="#dag-record">DependencyRecord fields</a></h3>
596 <table class="devdocs-table">
597 <thead><tr><th>Field</th><th>Description</th></tr></thead>
598 <tbody>
599 <tr><td><code>reservation_id</code></td><td>The dependent — this reservation waits</td></tr>
600 <tr><td><code>depends_on</code></td><td>List of reservation IDs it waits for (max 256)</td></tr>
601 <tr><td><code>created_at</code></td><td>UTC timestamp</td></tr>
602 </tbody>
603 </table>
604
605 <p>
606 <code>is_blocked(reservation_id)</code> returns <code>true</code> if any dependency
607 is still active. <code>get_blocking(reservation_id)</code> returns the list of active
608 dependencies. DAG output includes topological order (dependencies before dependents —
609 safe execution sequence) and detects cycles if one somehow exists.
610 </p>
611 </section>
612
613 {# ── Sharding ──────────────────────────────────────────────────────────── #}
614 <section class="devdocs-section" id="sharding">
615 <h2>Sharding</h2>
616 <p>
617 <code>muse coord shard</code> partitions the import graph into parallel-safe work zones.
618 Agents assigned to different shards never touch the same files, eliminating merge
619 conflicts by construction.
620 </p>
621
622 <h3>Algorithm</h3>
623 <ol>
624 <li>Build the import graph from the HEAD snapshot: file → file edges from import pseudo-symbols.</li>
625 <li>Compute weakly-connected components via DFS.</li>
626 <li>Apply LPT (Longest Processing Time) heuristic: greedily assign the largest component to the shard with the fewest symbols so far, minimizing makespan.</li>
627 <li>Count <code>cross_shard_edges</code>: imports that cross shard boundaries (lower = better isolation).</li>
628 </ol>
629
630 <div class="devdocs-code-block">
631 <pre><span class="tok-fn">muse</span> coord shard <span class="tok-kw">--agents</span> <span class="tok-num">4</span> <span class="tok-kw">--json</span>
632 <span class="tok-fn">muse</span> coord shard <span class="tok-kw">--agents</span> <span class="tok-num">8</span> <span class="tok-kw">--language</span> Python <span class="tok-kw">--json</span>
633 <span class="tok-fn">muse</span> coord shard <span class="tok-kw">--agents</span> <span class="tok-num">4</span> <span class="tok-kw">--commit</span> HEAD~10 <span class="tok-kw">--json</span></pre>
634 </div>
635
636 <h3>ShardPlan output</h3>
637 <div class="devdocs-code-block">
638 <pre>{
639 <span class="tok-key">"commit"</span>: <span class="tok-str">"f3c14a89"</span>, <span class="tok-cmt">// 8-char display ID</span>
640 <span class="tok-key">"full_commit_id"</span>: <span class="tok-str">"sha256:f3c14a89cd37…"</span>,
641 <span class="tok-key">"agents"</span>: <span class="tok-num">4</span>,
642 <span class="tok-key">"shards_created"</span>: <span class="tok-num">4</span>, <span class="tok-cmt">// may be &lt; agents if repo has fewer components</span>
643 <span class="tok-key">"total_files"</span>: <span class="tok-num">87</span>,
644 <span class="tok-key">"total_symbols"</span>: <span class="tok-num">1204</span>,
645 <span class="tok-key">"cross_shard_edges"</span>: <span class="tok-num">3</span>, <span class="tok-cmt">// lower = better isolation</span>
646 <span class="tok-key">"shards"</span>: [
647 {
648 <span class="tok-key">"shard"</span>: <span class="tok-num">1</span>,
649 <span class="tok-key">"files"</span>: [<span class="tok-str">"src/billing.py"</span>, <span class="tok-str">"src/models.py"</span>],
650 <span class="tok-key">"symbol_count"</span>: <span class="tok-num">312</span>,
651 <span class="tok-key">"coupling_score"</span>: <span class="tok-num">1</span> <span class="tok-cmt">// edges from this shard to others</span>
652 }
653 ]
654 }</pre>
655 </div>
656
657 <div class="devdocs-callout">
658 {{ icon("info", 16, "devdocs-callout-icon") }}
659 <div>
660 If the repo has fewer weakly-connected components than <code>--agents</code>,
661 <code>shards_created &lt; agents</code>. The extra agents have nothing to claim and
662 should idle or handle a different queue.
663 </div>
664 </div>
665 </section>
666
667 {# ── Forecasting ───────────────────────────────────────────────────────── #}
668 <section class="devdocs-section" id="forecast">
669 <h2>Conflict forecasting</h2>
670 <p>
671 <code>muse coord forecast</code> predicts merge conflicts before any agent writes code.
672 It runs three independent passes over active reservations and intents, each with a
673 calibrated confidence score.
674 </p>
675
676 <table class="devdocs-table">
677 <thead><tr><th>Pass</th><th>Conflict type</th><th>Confidence</th><th>Condition</th></tr></thead>
678 <tbody>
679 <tr>
680 <td>1</td>
681 <td><code>"address_overlap"</code></td>
682 <td>1.0</td>
683 <td>Same symbol address reserved by two or more different <code>run_id</code>s</td>
684 </tr>
685 <tr>
686 <td>2</td>
687 <td><code>"blast_radius_overlap"</code></td>
688 <td>0.75</td>
689 <td>One reserved address is a transitive caller of another (requires <code>muse code index</code>); skipped if call graph unavailable</td>
690 </tr>
691 <tr>
692 <td>3</td>
693 <td><code>"operation_conflict"</code></td>
694 <td>0.9</td>
695 <td>Intents on the same address combine incompatible operations: <code>delete</code> vs <code>modify</code>, <code>rename</code>, or <code>extract</code></td>
696 </tr>
697 </tbody>
698 </table>
699
700 <div class="devdocs-code-block">
701 <pre><span class="tok-fn">muse</span> coord forecast <span class="tok-kw">--json</span>
702 <span class="tok-fn">muse</span> coord forecast <span class="tok-kw">--branch</span> feat/auth <span class="tok-kw">--json</span>
703 <span class="tok-fn">muse</span> coord forecast <span class="tok-kw">--min-confidence</span> <span class="tok-num">0.9</span> <span class="tok-kw">--json</span> <span class="tok-cmt"># high-risk only</span></pre>
704 </div>
705
706 <h3>Output</h3>
707 <div class="devdocs-code-block">
708 <pre>{
709 <span class="tok-key">"active_reservations"</span>: <span class="tok-num">12</span>,
710 <span class="tok-key">"call_graph_available"</span>: <span class="tok-kw">true</span>,
711 <span class="tok-key">"partial_forecast"</span>: <span class="tok-kw">false</span>,
712 <span class="tok-key">"conflicts"</span>: [
713 {
714 <span class="tok-key">"conflict_type"</span>: <span class="tok-str">"address_overlap"</span>,
715 <span class="tok-key">"addresses"</span>: [<span class="tok-str">"src/billing.py::compute_total"</span>],
716 <span class="tok-key">"agents"</span>: [<span class="tok-str">"agent-1@feat/auth"</span>, <span class="tok-str">"agent-2@feat/payments"</span>],
717 <span class="tok-key">"confidence"</span>: <span class="tok-num">1.0</span>,
718 <span class="tok-key">"description"</span>: <span class="tok-str">"Symbol reserved by 2 agents on different branches"</span>
719 }
720 ],
721 <span class="tok-key">"high_risk"</span>: <span class="tok-num">1</span>, <span class="tok-cmt">// confidence &gt;= 0.9</span>
722 <span class="tok-key">"medium_risk"</span>: <span class="tok-num">0</span>, <span class="tok-cmt">// 0.5 &lt;= confidence &lt; 0.9</span>
723 <span class="tok-key">"low_risk"</span>: <span class="tok-num">0</span> <span class="tok-cmt">// confidence &lt; 0.5</span>
724 }</pre>
725 </div>
726
727 <p>
728 Agents are shown as <code>"run_id@branch"</code>. Pass 2 is silently skipped when the
729 code intelligence index is unavailable, setting <code>partial_forecast: true</code>.
730 </p>
731 </section>
732
733 {# ── Watch ─────────────────────────────────────────────────────────────── #}
734 <section class="devdocs-section" id="watch">
735 <h2>Watch — real-time event stream</h2>
736 <p>
737 <code>muse coord watch</code> streams coordination events as NDJSON (one JSON object
738 per line). On macOS/BSD it uses kqueue (zero CPU between events); on Linux it falls
739 back to polling at a configurable interval (default 1.0s).
740 </p>
741
742 <div class="devdocs-code-block">
743 <pre><span class="tok-fn">muse</span> coord watch <span class="tok-kw">--json</span>
744 <span class="tok-fn">muse</span> coord watch <span class="tok-kw">--once</span> <span class="tok-kw">--json</span> <span class="tok-cmt"># exit after first event</span>
745 <span class="tok-fn">muse</span> coord watch <span class="tok-kw">--kind</span> reservation <span class="tok-kw">--json</span> <span class="tok-cmt"># filter by kind</span>
746 <span class="tok-fn">muse</span> coord watch <span class="tok-kw">--run-id</span> agent-1 <span class="tok-kw">--json</span> <span class="tok-cmt"># filter by agent</span></pre>
747 </div>
748
749 <h3>Event types and fields</h3>
750 <table class="devdocs-table">
751 <thead><tr><th>Field</th><th>Values</th><th>Description</th></tr></thead>
752 <tbody>
753 <tr><td><code>event_type</code></td><td><code>"snapshot"</code> <code>"added"</code> <code>"modified"</code> <code>"removed"</code> <code>"expired"</code></td><td>What happened to the record</td></tr>
754 <tr><td><code>kind</code></td><td><code>"reservation"</code> <code>"intent"</code> <code>"release"</code> <code>"heartbeat"</code></td><td>Type of coordination record</td></tr>
755 <tr><td><code>id</code></td><td>str</td><td>ID of the changed record</td></tr>
756 <tr><td><code>timestamp</code></td><td>datetime (UTC)</td><td>When the event occurred</td></tr>
757 <tr><td><code>data</code></td><td>dict</td><td>Parsed record content; empty dict for removed records with no cache</td></tr>
758 </tbody>
759 </table>
760
761 <p>
762 <code>"snapshot"</code> events fire on startup for each existing record — useful for
763 replaying current state before watching for changes.
764 </p>
765 </section>
766
767 {# ── Sync ──────────────────────────────────────────────────────────────── #}
768 <section class="devdocs-section" id="sync">
769 <h2>Remote sync</h2>
770 <p>
771 Coordination state can be pushed to and pulled from MuseHub, enabling multi-machine
772 agent pipelines. Remote records are stored read-only under
773 <code>.muse/coordination/remote/</code>.
774 </p>
775
776 <div class="devdocs-code-block">
777 <pre><span class="tok-cmt"># push local coordination records to MuseHub (batches of 500)</span>
778 <span class="tok-fn">muse</span> coord sync push \
779 <span class="tok-kw">--hub</span> {{ site_base_url() }} \
780 <span class="tok-kw">--owner</span> gabriel <span class="tok-kw">--slug</span> muse <span class="tok-kw">--json</span>
781
782 <span class="tok-cmt"># pull remote records (paginated, use --since-id for incremental)</span>
783 <span class="tok-fn">muse</span> coord sync pull \
784 <span class="tok-kw">--hub</span> {{ site_base_url() }} \
785 <span class="tok-kw">--owner</span> gabriel <span class="tok-kw">--slug</span> muse \
786 <span class="tok-kw">--since-id</span> 1024 <span class="tok-kw">--limit</span> <span class="tok-num">500</span> <span class="tok-kw">--json</span></pre>
787 </div>
788
789 <p>
790 Push is idempotent: the hub responds with <code>{"inserted": N, "skipped": M}</code>.
791 Pull returns a <code>cursor</code> to use as <code>--since-id</code> in the next call.
792 Supported kinds: <code>reservation</code>, <code>intent</code>, <code>release</code>,
793 <code>heartbeat</code>, <code>task</code>, <code>claim</code>, <code>dependency</code>.
794 </p>
795 </section>
796
797 {# ── Storage layout ────────────────────────────────────────────────────── #}
798 <section class="devdocs-section" id="storage">
799 <h2>Storage layout</h2>
800 <p>
801 All coordination state is file-backed under <code>.muse/coordination/</code>. Every
802 file is JSON. IDs are content-addressed sha256 hex strings used directly as filenames.
803 </p>
804
805 <div class="devdocs-code-block">
806 <pre>.muse/coordination/
807 reservations/&lt;sha256-hex&gt;.json <span class="tok-cmt">← write-once advisory symbol lease</span>
808 intents/&lt;sha256-hex&gt;.json <span class="tok-cmt">← write-once operation declaration (no TTL)</span>
809 releases/&lt;sha256-hex&gt;.json <span class="tok-cmt">← write-once tombstone (completed/cancelled)</span>
810 heartbeats/&lt;sha256-hex&gt;.json <span class="tok-cmt">← mutable keep-alive; atomically overwritten</span>
811 tasks/&lt;sha256-hex&gt;.json <span class="tok-cmt">← immutable task definition</span>
812 claims/&lt;sha256-hex&gt;.json <span class="tok-cmt">← mutable claim state (O_CREAT|O_EXCL then atomic)</span>
813 dependencies/&lt;sha256-hex&gt;.json <span class="tok-cmt">← write-once DAG edges</span>
814 remote/ <span class="tok-cmt">← records synced from MuseHub (read-only)</span></pre>
815 </div>
816
817 <h3>GC policy</h3>
818 <p>
819 <code>muse coord gc</code> collects stale records after a configurable grace period
820 (default 300s = 5 min, protecting against agents mid-read). Run dry-run first:
821 </p>
822 <div class="devdocs-code-block">
823 <pre><span class="tok-fn">muse</span> coord gc <span class="tok-kw">--json</span> <span class="tok-cmt"># dry-run, shows what would be collected</span>
824 <span class="tok-fn">muse</span> coord gc <span class="tok-kw">--execute</span> <span class="tok-kw">--json</span> <span class="tok-cmt"># actually delete</span></pre>
825 </div>
826 <table class="devdocs-table">
827 <thead><tr><th>Collected</th><th>Condition</th></tr></thead>
828 <tbody>
829 <tr><td>Expired reservations</td><td>TTL exhausted (including heartbeat extensions), past grace period</td></tr>
830 <tr><td>Released reservations</td><td>Release tombstone present, older than grace period</td></tr>
831 <tr><td>Orphaned releases</td><td>Tombstone exists but reservation file gone</td></tr>
832 <tr><td>Orphaned heartbeats</td><td>Heartbeat exists but reservation file gone</td></tr>
833 <tr><td>Old intents (opt-in)</td><td><code>--include-intents</code>; older than <code>--max-intent-age</code> (default 7 days)</td></tr>
834 </tbody>
835 </table>
836 </section>
837
838 {# ── CLI Reference ─────────────────────────────────────────────────────── #}
839 <section class="devdocs-section" id="cli">
840 <h2>CLI reference</h2>
841 <p>All commands accept <code>--json</code>.</p>
842
843 <table class="devdocs-table">
844 <thead><tr><th>Task</th><th>Command</th></tr></thead>
845 <tbody>
846 <tr><td>Enqueue a task</td><td><code>muse coord enqueue "title" --run-id orch --json</code></td></tr>
847 <tr><td>Claim next pending task</td><td><code>muse coord claim --run-id agent-1 --json</code></td></tr>
848 <tr><td>Claim from specific queue</td><td><code>muse coord claim --queue refactor --run-id agent-1 --json</code></td></tr>
849 <tr><td>Complete a task</td><td><code>muse coord complete &lt;task_id&gt; --run-id agent-1 --json</code></td></tr>
850 <tr><td>Fail a task</td><td><code>muse coord fail-task &lt;task_id&gt; --run-id agent-1 --error "msg" --json</code></td></tr>
851 <tr><td>Cancel a task</td><td><code>muse coord cancel-task &lt;task_id&gt; --run-id orch --json</code></td></tr>
852 <tr><td>List tasks</td><td><code>muse coord tasks --status pending --json</code></td></tr>
853 <tr><td>Reserve symbol addresses</td><td><code>muse coord reserve "billing.py::Fn" --run-id agent-1 --op modify --json</code></td></tr>
854 <tr><td>Reserve with TTL</td><td><code>muse coord reserve "billing.py::Fn" --run-id agent-1 --ttl 7200 --json</code></td></tr>
855 <tr><td>Reserve with dependency</td><td><code>muse coord reserve "billing.py::Fn" --run-id agent-B --depends-on &lt;id&gt; --json</code></td></tr>
856 <tr><td>Release a reservation</td><td><code>muse coord release &lt;id&gt; --run-id agent-1 --json</code></td></tr>
857 <tr><td>Release all for a run</td><td><code>muse coord release --all-for-run agent-1 --run-id agent-1 --json</code></td></tr>
858 <tr><td>Heartbeat (reservation)</td><td><code>muse coord heartbeat &lt;reservation_id&gt; --run-id agent-1 --json</code></td></tr>
859 <tr><td>Heartbeat (claim)</td><td><code>muse coord heartbeat &lt;task_id&gt; --run-id agent-1 --json</code></td></tr>
860 <tr><td>List active reservations</td><td><code>muse coord list --json</code></td></tr>
861 <tr><td>Inspect DAG</td><td><code>muse coord dag --json</code></td></tr>
862 <tr><td>Shard codebase</td><td><code>muse coord shard --agents 4 --json</code></td></tr>
863 <tr><td>Forecast conflicts</td><td><code>muse coord forecast --json</code></td></tr>
864 <tr><td>Reconcile merge order</td><td><code>muse coord reconcile --json</code></td></tr>
865 <tr><td>Watch events</td><td><code>muse coord watch --json</code></td></tr>
866 <tr><td>Push to MuseHub</td><td><code>muse coord sync push --hub URL --owner O --slug S --json</code></td></tr>
867 <tr><td>Pull from MuseHub</td><td><code>muse coord sync pull --hub URL --owner O --slug S --json</code></td></tr>
868 <tr><td>GC stale records (dry-run)</td><td><code>muse coord gc --json</code></td></tr>
869 <tr><td>GC (execute)</td><td><code>muse coord gc --execute --json</code></td></tr>
870 </tbody>
871 </table>
872
873 <h3>Default TTLs</h3>
874 <table class="devdocs-table">
875 <thead><tr><th>Entity</th><th>Default TTL</th></tr></thead>
876 <tbody>
877 <tr><td>Reservation</td><td>3600s (1h)</td></tr>
878 <tr><td>Task claim</td><td>3600s (1h)</td></tr>
879 <tr><td>Task pending</td><td>86400s (24h)</td></tr>
880 <tr><td>Heartbeat extension</td><td>3600s</td></tr>
881 <tr><td>Intent</td><td>No TTL — permanent until GC with <code>--include-intents</code></td></tr>
882 <tr><td>GC grace period</td><td>300s (5 min)</td></tr>
883 </tbody>
884 </table>
885
886 <nav class="devdocs-phase-nav" aria-label="Phase navigation">
887 <a class="devdocs-phase-nav-btn devdocs-phase-nav-btn--prev" href="/muse/harmony">
888 {{ icon("arrow-left", 14) }}
889 Phase 06: Harmony
890 </a>
891 <a class="devdocs-phase-nav-btn devdocs-phase-nav-btn--next" href="/muse/mcp">
892 Phase 08: MCP Tooling
893 {{ icon("arrow-right", 14) }}
894 </a>
895 </nav>
896 </section>
897
898 </main>
899 </div>{# /.devdocs-layout #}
900 </div>{# /.devdocs #}
901 {% endblock %}
902
903 {% block page_scripts %}
904 {% endblock %}
File History 1 commit
sha256:9f5112c9a633a22e53a831c6d3af637093d0ceb914393749905187046f1c548a chore: renumber phases — merge is 05, shift harmony through… Sonnet 4.6 patch 1 day ago