crates/jera/.nornir/assets/agents-multimachine.svg
<svg xmlns="http://www.w3.org/2000/svg" width="860" height="440" viewBox="0 0 860 440" font-family="ui-sans-serif,system-ui,sans-serif">
<defs>
<marker id="arr" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M0 0 L10 5 L0 10 z" fill="#6fd3f5"/>
</marker>
<marker id="arrK" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M0 0 L10 5 L0 10 z" fill="#e0785a"/>
</marker>
</defs>
<style>
.box{fill:#0f1720;stroke:#6fd3f5;stroke-width:1.5;rx:8}
.grp{fill:#0c1a12;stroke:#5fbf7f;stroke-width:1.4;rx:8}
.skel{fill:#1a130c;stroke:#7fb0cc;stroke-width:1.4;stroke-dasharray:5 4;rx:8}
.t{fill:#dfe9f0;font-size:13px}
.h{fill:#6fd3f5;font-size:13px;font-weight:700}
.hg{fill:#7fe0a0;font-size:13px;font-weight:700}
.s{fill:#9fb3c0;font-size:11px}
.k{fill:#e0785a;font-size:11px;font-weight:700}
.e{stroke:#6fd3f5;stroke-width:1.6;fill:none}
.ek{stroke:#e0785a;stroke-width:1.6;fill:none;stroke-dasharray:4 3}
</style>
<text x="20" y="26" class="h" font-size="15">jera::agent — multi-machine worker-groups</text>
<text x="20" y="44" class="s">control-plane matches a ready WorkUnit → a capable idle agent in its group; bidirectional kill</text>
<!-- WorkUnit -->
<rect class="box" x="20" y="80" width="170" height="86"/>
<text x="30" y="104" class="h">WorkUnit</text>
<text x="30" y="124" class="t">id · group</text>
<text x="30" y="142" class="t">required_caps ⊆ agent.caps</text>
<text x="30" y="160" class="s">Rust xtask step / boot job</text>
<!-- Scheduler -->
<rect class="box" x="250" y="72" width="200" height="104"/>
<text x="262" y="96" class="h">Scheduler (control-plane)</text>
<text x="262" y="118" class="t">match: idle ∧ group== ∧ caps⊇</text>
<text x="262" y="137" class="t">first eligible, deterministic</text>
<text x="262" y="156" class="s">none → None (re-queue, no drop)</text>
<path class="e" d="M190 123 H250" marker-end="url(#arr)"/>
<!-- worker-group box -->
<rect class="grp" x="520" y="56" width="320" height="230"/>
<text x="534" y="78" class="hg">worker-group "loki"</text>
<!-- LocalAgent -->
<rect class="box" x="540" y="92" width="280" height="86"/>
<text x="552" y="115" class="h">LocalAgent — ships now ✓</text>
<text x="552" y="135" class="t">1 std thread / unit · LocalRunner</text>
<text x="552" y="154" class="t">state: Idle · Busy · Offline</text>
<text x="552" y="171" class="s">real + tested (7 tests, no network)</text>
<!-- GrpcAgent skeleton -->
<rect class="skel" x="540" y="190" width="280" height="80"/>
<text x="552" y="213" class="t" font-weight="700">GrpcAgent — remote (skeleton)</text>
<text x="552" y="232" class="s">reports Offline → never scheduled</text>
<text x="552" y="250" class="s">TODO: gRPC dispatch/poll/kill</text>
<text x="552" y="266" class="k">the ONE thing to build for multi-machine</text>
<path class="e" d="M450 118 C490 118 500 130 540 132" marker-end="url(#arr)"/>
<!-- WorkHandle + lifecycle -->
<rect class="box" x="250" y="228" width="200" height="96"/>
<text x="262" y="252" class="h">WorkHandle</text>
<text x="262" y="273" class="t">poll() → status</text>
<text x="262" y="292" class="t">Pending→Running→Done|Failed</text>
<text x="262" y="311" class="k">|Killed (never a silent stall)</text>
<path class="e" d="M600 178 C560 210 480 250 450 262" marker-end="url(#arr)"/>
<!-- bidirectional kill -->
<path class="ek" d="M350 324 C350 372 620 372 680 270" marker-end="url(#arrK)"/>
<text x="380" y="366" class="k">kill(): cancel → remote kill · agent offline → in-flight Killed</text>
</svg>