<svg width="100%" viewBox="0 0 760 720" role="img" xmlns="http://www.w3.org/2000/svg">
  <title>Per-user hermes lifecycle — from trigger to healthy</title>
  <desc>ensure_runtime is called on first use; if the container isn't running, _spawn docker-runs it with a volume + bind-mounted plugins + an entrypoint override that seeds config on every boot before handing off to upstream's gateway run.</desc>
  <style>
    text{font-family:"Anthropic Sans",-apple-system,system-ui,"Segoe UI",sans-serif}
    .t{font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:central}
    .s{font-size:12px;text-anchor:middle;dominant-baseline:central}
    .stp{font-size:12px;fill:#c2c0b6}
    .lbl{font-size:11px;fill:#9c9a92;text-anchor:middle}
    rect{stroke-width:.5}
    .blue{fill:#1f3b7a;stroke:#8aaef0}    .bt{fill:#cfdcf4} .bs{fill:#8aaef0}
    .orange{fill:#712b13;stroke:#f0997b}  .ot{fill:#f5c4b3} .os{fill:#f0997b}
    .neutral{fill:#444441;stroke:#b4b2a9} .nt{fill:#d3d1c7} .ns{fill:#b4b2a9}
    .arrow{fill:none;stroke:#9c9a92;stroke-width:1.5}
    .arrow-ok{fill:none;stroke:#1d9e75;stroke-width:1.5}
    .diamond{fill:#2a2826;stroke:#b4b2a9;stroke-width:.5}
  </style>
  <defs>
    <marker id="a" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
      <path d="M2 1L8 5L2 9" fill="none" stroke="context-stroke" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
    </marker>
  </defs>

  <text class="stp" x="40" y="64">1</text>
  <text class="stp" x="40" y="164">2</text>
  <text class="stp" x="40" y="284">3</text>
  <text class="stp" x="40" y="404">4</text>
  <text class="stp" x="40" y="524">5</text>
  <text class="stp" x="40" y="624">6</text>
  <text class="stp" x="40" y="704">7</text>

  <rect class="neutral" x="120" y="40" width="560" height="60" rx="8"/>
  <text class="t nt" x="400" y="64">Trigger</text>
  <text class="s ns" x="400" y="84">first voice turn · chat send · whatsapp inbound · /integrations opened</text>

  <rect class="blue" x="120" y="140" width="560" height="60" rx="8"/>
  <text class="t bt" x="400" y="164">ensure_runtime(user_id)</text>
  <text class="s bs" x="400" y="184">provisioner inside sudo-api</text>

  <polygon class="diamond" points="400,220 540,260 400,300 260,260"/>
  <text class="t nt" x="400" y="264">container running?</text>

  <text class="lbl" x="560" y="252">yes → return URL</text>
  <path class="arrow-ok" d="M 540 260 C 620 260, 680 260, 680 670" marker-end="url(#a)"/>

  <text class="lbl" x="240" y="252">no</text>

  <rect class="blue" x="120" y="380" width="560" height="60" rx="8"/>
  <text class="t bt" x="400" y="404">_spawn() · docker run</text>
  <text class="s bs" x="400" y="424">named volume · plugins bind-mount (ro) · entrypoint = /bin/sh -c _SEED_AND_EXEC</text>

  <rect class="blue" x="120" y="480" width="560" height="80" rx="8"/>
  <text class="t bt" x="400" y="504">_SEED_AND_EXEC (boot script, runs on every start)</text>
  <text class="s bs" x="400" y="524">writes /opt/data/config.yaml · seeds MEMORY.md</text>
  <text class="s bs" x="400" y="542">heals legacy state · exec upstream entrypoint</text>

  <rect class="orange" x="120" y="600" width="560" height="60" rx="8"/>
  <text class="t ot" x="400" y="624">gateway run</text>
  <text class="s os" x="400" y="644">api_server :8642 + twilio_whatsapp :8651 + sudo_chat :8652 + sudo_voice :8653</text>

  <rect class="blue" x="120" y="680" width="560" height="40" rx="8"/>
  <text class="t bt" x="400" y="700">_wait_healthy · poll GET /health until 200 (default 120s) → return URL</text>

  <path class="arrow" d="M 400 100 L 400 138" marker-end="url(#a)"/>
  <path class="arrow" d="M 400 200 L 400 218" marker-end="url(#a)"/>
  <path class="arrow" d="M 400 300 L 400 378" marker-end="url(#a)"/>
  <path class="arrow" d="M 400 440 L 400 478" marker-end="url(#a)"/>
  <path class="arrow" d="M 400 560 L 400 598" marker-end="url(#a)"/>
  <path class="arrow" d="M 400 660 L 400 678" marker-end="url(#a)"/>
</svg>
