my-durable 0.0.0-stage → 0.0.2

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.
Files changed (259) hide show
  1. package/.env.example +7 -0
  2. package/LICENSE +21 -0
  3. package/README.md +328 -2
  4. package/ai_docs/durable_pi/announcement.md +860 -0
  5. package/ai_docs/durable_pi/changelog.md +51 -0
  6. package/ai_docs/durable_pi/chord-delta-findings.md +362 -0
  7. package/ai_docs/durable_pi/coding-agent-integration.md +70 -0
  8. package/ai_docs/durable_pi/pico-v5-chord-usage.md +391 -0
  9. package/ai_docs/durable_pi/pico-v5-handoff.md +921 -0
  10. package/ai_docs/durable_pi/readme.md +617 -0
  11. package/ai_docs/durable_pi/sources.md +22 -0
  12. package/ai_docs/durable_pi/spec.md +4696 -0
  13. package/ai_docs/durable_pi/vacation-planner.md +57 -0
  14. package/ai_docs/pi/chord.md +268 -0
  15. package/ai_docs/pi/cli-integration.md +110 -0
  16. package/ai_docs/pi/cli.md +325 -0
  17. package/ai_docs/pi/codemode.md +211 -0
  18. package/ai_docs/pi/compaction.md +467 -0
  19. package/ai_docs/pi/configuration.md +51 -0
  20. package/ai_docs/pi/containerization.md +187 -0
  21. package/ai_docs/pi/custom-provider.md +177 -0
  22. package/ai_docs/pi/environment-variables.md +102 -0
  23. package/ai_docs/pi/extensions.md +278 -0
  24. package/ai_docs/pi/how-pi-works.md +53 -0
  25. package/ai_docs/pi/index.md +43 -0
  26. package/ai_docs/pi/json.md +230 -0
  27. package/ai_docs/pi/keybindings.md +198 -0
  28. package/ai_docs/pi/llama-cpp.md +118 -0
  29. package/ai_docs/pi/mcp.md +274 -0
  30. package/ai_docs/pi/message-types.md +265 -0
  31. package/ai_docs/pi/models.md +209 -0
  32. package/ai_docs/pi/overview.md +166 -0
  33. package/ai_docs/pi/packages.md +133 -0
  34. package/ai_docs/pi/pi-agent-core.md +568 -0
  35. package/ai_docs/pi/pi-ai.md +1942 -0
  36. package/ai_docs/pi/prompt-templates.md +63 -0
  37. package/ai_docs/pi/providers.md +204 -0
  38. package/ai_docs/pi/quickstart.md +140 -0
  39. package/ai_docs/pi/readme.md +99 -0
  40. package/ai_docs/pi/rpc-commands.md +864 -0
  41. package/ai_docs/pi/rpc-extension-ui.md +204 -0
  42. package/ai_docs/pi/rpc.md +197 -0
  43. package/ai_docs/pi/sdk.md +151 -0
  44. package/ai_docs/pi/security.md +103 -0
  45. package/ai_docs/pi/session-format.md +297 -0
  46. package/ai_docs/pi/sessions.md +70 -0
  47. package/ai_docs/pi/settings.md +173 -0
  48. package/ai_docs/pi/shell-aliases.md +97 -0
  49. package/ai_docs/pi/skills.md +97 -0
  50. package/ai_docs/pi/slash-commands.md +64 -0
  51. package/ai_docs/pi/sources.md +57 -0
  52. package/ai_docs/pi/terminal-setup.md +223 -0
  53. package/ai_docs/pi/termux.md +121 -0
  54. package/ai_docs/pi/themes.md +140 -0
  55. package/ai_docs/pi/tmux.md +59 -0
  56. package/ai_docs/pi/toolkit.md +168 -0
  57. package/ai_docs/pi/tui.md +129 -0
  58. package/ai_docs/pi/usage.md +98 -0
  59. package/ai_docs/pi/virtual-models.md +118 -0
  60. package/ai_docs/pi/windows.md +71 -0
  61. package/apps/dpi-backend/.nvmrc +1 -0
  62. package/apps/dpi-backend/API.md +99 -0
  63. package/apps/dpi-backend/README.md +119 -0
  64. package/apps/dpi-backend/deploy/backend.env.example +9 -0
  65. package/apps/dpi-backend/deploy/dpi-backend.plist +26 -0
  66. package/apps/dpi-backend/deploy/dpi-backend.service +22 -0
  67. package/apps/dpi-backend/package.json +33 -0
  68. package/apps/dpi-backend/prompts/one_sentence.md +3 -0
  69. package/apps/dpi-backend/prompts/smart_ass_opus_fix.md +169 -0
  70. package/apps/dpi-backend/scripts/check-contract.mjs +151 -0
  71. package/apps/dpi-backend/scripts/migrate-playground.ts +66 -0
  72. package/apps/dpi-backend/scripts/record-nested-fixture.mts +154 -0
  73. package/apps/dpi-backend/scripts/token.ts +57 -0
  74. package/apps/dpi-backend/src/addons.ts +139 -0
  75. package/apps/dpi-backend/src/auth.ts +20 -0
  76. package/apps/dpi-backend/src/config.ts +54 -0
  77. package/apps/dpi-backend/src/contract-check.ts +118 -0
  78. package/apps/dpi-backend/src/errors.ts +50 -0
  79. package/apps/dpi-backend/src/extensions.ts +510 -0
  80. package/apps/dpi-backend/src/faux.ts +80 -0
  81. package/apps/dpi-backend/src/history.ts +165 -0
  82. package/apps/dpi-backend/src/idempotency.ts +20 -0
  83. package/apps/dpi-backend/src/jev.ts +43 -0
  84. package/apps/dpi-backend/src/jobs.ts +790 -0
  85. package/apps/dpi-backend/src/main.ts +76 -0
  86. package/apps/dpi-backend/src/model-catalog.ts +180 -0
  87. package/apps/dpi-backend/src/pairing-files.ts +142 -0
  88. package/apps/dpi-backend/src/pairing.ts +459 -0
  89. package/apps/dpi-backend/src/routes.ts +217 -0
  90. package/apps/dpi-backend/src/shared-state.ts +85 -0
  91. package/apps/dpi-backend/src/store.ts +1240 -0
  92. package/apps/dpi-backend/src/streams.ts +256 -0
  93. package/apps/dpi-backend/src/tunnel.ts +955 -0
  94. package/apps/dpi-backend/tsconfig.json +13 -0
  95. package/apps/dpi-playground/README.md +83 -0
  96. package/apps/dpi-playground/apps/dpi-playground-fe/dist/assets/index-CFGc7lHT.js +77 -0
  97. package/apps/dpi-playground/apps/dpi-playground-fe/dist/assets/index-DFdKpwm_.css +1 -0
  98. package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/anthropic.png +0 -0
  99. package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/deepseek.png +0 -0
  100. package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/durable-pi.svg +14 -0
  101. package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/gemini.png +0 -0
  102. package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/grok.png +0 -0
  103. package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/kimi.png +0 -0
  104. package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/lab.png +0 -0
  105. package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/meta.png +0 -0
  106. package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/minimax.png +0 -0
  107. package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/openai.png +0 -0
  108. package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/qwen.png +0 -0
  109. package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/xiaomi.png +0 -0
  110. package/apps/dpi-playground/apps/dpi-playground-fe/dist/icons/zai.png +0 -0
  111. package/apps/dpi-playground/apps/dpi-playground-fe/dist/index.html +16 -0
  112. package/apps/dpi-playground/apps/dpi-playground-fe/index.html +15 -0
  113. package/apps/dpi-playground/apps/dpi-playground-fe/package.json +5 -0
  114. package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/anthropic.png +0 -0
  115. package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/deepseek.png +0 -0
  116. package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/durable-pi.svg +14 -0
  117. package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/gemini.png +0 -0
  118. package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/grok.png +0 -0
  119. package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/kimi.png +0 -0
  120. package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/lab.png +0 -0
  121. package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/meta.png +0 -0
  122. package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/minimax.png +0 -0
  123. package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/openai.png +0 -0
  124. package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/qwen.png +0 -0
  125. package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/xiaomi.png +0 -0
  126. package/apps/dpi-playground/apps/dpi-playground-fe/public/icons/zai.png +0 -0
  127. package/apps/dpi-playground/apps/dpi-playground-fe/src/App.vue +180 -0
  128. package/apps/dpi-playground/apps/dpi-playground-fe/src/client/commands.ts +119 -0
  129. package/apps/dpi-playground/apps/dpi-playground-fe/src/client/composables.ts +129 -0
  130. package/apps/dpi-playground/apps/dpi-playground-fe/src/client/hub.ts +40 -0
  131. package/apps/dpi-playground/apps/dpi-playground-fe/src/client/icon-path.ts +7 -0
  132. package/apps/dpi-playground/apps/dpi-playground-fe/src/client/ids.ts +2 -0
  133. package/apps/dpi-playground/apps/dpi-playground-fe/src/client/jobs.ts +80 -0
  134. package/apps/dpi-playground/apps/dpi-playground-fe/src/client/link-policy.ts +16 -0
  135. package/apps/dpi-playground/apps/dpi-playground-fe/src/client/markdown-policy.ts +115 -0
  136. package/apps/dpi-playground/apps/dpi-playground-fe/src/client/markdown.ts +60 -0
  137. package/apps/dpi-playground/apps/dpi-playground-fe/src/client/pair-close.ts +23 -0
  138. package/apps/dpi-playground/apps/dpi-playground-fe/src/client/pair-handoff.ts +56 -0
  139. package/apps/dpi-playground/apps/dpi-playground-fe/src/client/pair.ts +166 -0
  140. package/apps/dpi-playground/apps/dpi-playground-fe/src/client/qrcode.ts +323 -0
  141. package/apps/dpi-playground/apps/dpi-playground-fe/src/client/signature.ts +146 -0
  142. package/apps/dpi-playground/apps/dpi-playground-fe/src/client/store.ts +373 -0
  143. package/apps/dpi-playground/apps/dpi-playground-fe/src/client/stream.ts +183 -0
  144. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/AgentView.vue +342 -0
  145. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/Composer.vue +198 -0
  146. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/ContextBar.vue +254 -0
  147. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/DeviceCredentialsDialog.vue +40 -0
  148. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/DeviceIcon.vue +56 -0
  149. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/DirBrowser.vue +95 -0
  150. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/ExtensionsPanel.vue +96 -0
  151. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/HelpDialog.vue +69 -0
  152. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/Inspector.vue +425 -0
  153. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/JobCard.vue +221 -0
  154. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/MobileNav.vue +39 -0
  155. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/ModelPicker.vue +71 -0
  156. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/NetworkSidebar.vue +236 -0
  157. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/NewSessionDialog.vue +114 -0
  158. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/OfflinePanel.vue +128 -0
  159. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/PairDeviceWizard.vue +433 -0
  160. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/PromptDialog.vue +89 -0
  161. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/StateEditor.vue +179 -0
  162. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/TasksPanel.vue +280 -0
  163. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/Toast.vue +11 -0
  164. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/TokenManager.vue +175 -0
  165. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/TopBar.vue +114 -0
  166. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/TranscriptItem.vue +152 -0
  167. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/TreeRow.vue +195 -0
  168. package/apps/dpi-playground/apps/dpi-playground-fe/src/components/TunnelStatusBar.vue +107 -0
  169. package/apps/dpi-playground/apps/dpi-playground-fe/src/extensions.css +105 -0
  170. package/apps/dpi-playground/apps/dpi-playground-fe/src/jobs.css +655 -0
  171. package/apps/dpi-playground/apps/dpi-playground-fe/src/main.ts +22 -0
  172. package/apps/dpi-playground/apps/dpi-playground-fe/src/network.css +675 -0
  173. package/apps/dpi-playground/apps/dpi-playground-fe/src/style.css +3203 -0
  174. package/apps/dpi-playground/apps/dpi-playground-fe/tsconfig.json +16 -0
  175. package/apps/dpi-playground/apps/dpi-playground-fe/vite.config.ts +14 -0
  176. package/apps/dpi-playground/apps/dpi-playground-hub/package.json +5 -0
  177. package/apps/dpi-playground/apps/dpi-playground-hub/src/audit.ts +406 -0
  178. package/apps/dpi-playground/apps/dpi-playground-hub/src/client-ip.ts +72 -0
  179. package/apps/dpi-playground/apps/dpi-playground-hub/src/credentials.ts +265 -0
  180. package/apps/dpi-playground/apps/dpi-playground-hub/src/guard.ts +43 -0
  181. package/apps/dpi-playground/apps/dpi-playground-hub/src/http-errors.ts +156 -0
  182. package/apps/dpi-playground/apps/dpi-playground-hub/src/identity.ts +60 -0
  183. package/apps/dpi-playground/apps/dpi-playground-hub/src/limiter.ts +165 -0
  184. package/apps/dpi-playground/apps/dpi-playground-hub/src/main.ts +460 -0
  185. package/apps/dpi-playground/apps/dpi-playground-hub/src/monitor.ts +320 -0
  186. package/apps/dpi-playground/apps/dpi-playground-hub/src/mux.ts +277 -0
  187. package/apps/dpi-playground/apps/dpi-playground-hub/src/pairing.ts +816 -0
  188. package/apps/dpi-playground/apps/dpi-playground-hub/src/proxy.ts +128 -0
  189. package/apps/dpi-playground/apps/dpi-playground-hub/src/rotation.ts +583 -0
  190. package/apps/dpi-playground/apps/dpi-playground-hub/src/seed.ts +11 -0
  191. package/apps/dpi-playground/apps/dpi-playground-hub/src/transport.ts +108 -0
  192. package/apps/dpi-playground/apps/dpi-playground-hub/src/tunnel-token.ts +11 -0
  193. package/apps/dpi-playground/apps/dpi-playground-hub/src/tunnel-transport.ts +560 -0
  194. package/apps/dpi-playground/apps/dpi-playground-hub/src/tunnel.ts +873 -0
  195. package/apps/dpi-playground/apps/dpi-playground-hub/tsconfig.json +13 -0
  196. package/apps/dpi-playground/package.json +37 -0
  197. package/apps/dpi-sdk/README.md +74 -0
  198. package/apps/dpi-sdk/package.json +20 -0
  199. package/apps/dpi-sdk/scripts/net.ts +73 -0
  200. package/apps/dpi-sdk/src/api.ts +631 -0
  201. package/apps/dpi-sdk/src/app-state.ts +111 -0
  202. package/apps/dpi-sdk/src/client.ts +330 -0
  203. package/apps/dpi-sdk/src/errors.ts +16 -0
  204. package/apps/dpi-sdk/src/jobs.ts +99 -0
  205. package/apps/dpi-sdk/src/models.ts +472 -0
  206. package/apps/dpi-sdk/src/node/chunk.ts +488 -0
  207. package/apps/dpi-sdk/src/node/config.ts +175 -0
  208. package/apps/dpi-sdk/src/node/drivers.ts +402 -0
  209. package/apps/dpi-sdk/src/node/ops.ts +114 -0
  210. package/apps/dpi-sdk/src/node/private-dir.ts +48 -0
  211. package/apps/dpi-sdk/src/node/registry-migration.ts +549 -0
  212. package/apps/dpi-sdk/src/node/registry.ts +390 -0
  213. package/apps/dpi-sdk/src/node/sse-writer.ts +151 -0
  214. package/apps/dpi-sdk/src/protocol/backoff.ts +31 -0
  215. package/apps/dpi-sdk/src/protocol/limits.ts +199 -0
  216. package/apps/dpi-sdk/src/protocol/pairing.ts +311 -0
  217. package/apps/dpi-sdk/src/protocol/rest-routes.ts +105 -0
  218. package/apps/dpi-sdk/src/protocol/tunnel.ts +331 -0
  219. package/apps/dpi-sdk/src/sse.ts +117 -0
  220. package/apps/dpi-sdk/src/transcript.ts +291 -0
  221. package/apps/dpi-sdk/tsconfig.json +13 -0
  222. package/apps/dpi-sdk/w +20 -0
  223. package/apps/dpi-tui/README.md +54 -0
  224. package/apps/dpi-tui/bin/dpi-tui.mjs +5 -0
  225. package/apps/dpi-tui/package.json +20 -0
  226. package/apps/dpi-tui/src/app.ts +433 -0
  227. package/apps/dpi-tui/src/commands.ts +151 -0
  228. package/apps/dpi-tui/src/main.ts +122 -0
  229. package/apps/dpi-tui/src/pairing.ts +287 -0
  230. package/apps/dpi-tui/src/pickers.ts +238 -0
  231. package/apps/dpi-tui/src/render.ts +164 -0
  232. package/apps/dpi-tui/src/theme.ts +57 -0
  233. package/apps/dpi-tui/tsconfig.json +14 -0
  234. package/bin/device.mjs +5 -0
  235. package/bin/hub.mjs +5 -0
  236. package/bin/tui.mjs +5 -0
  237. package/deploy/Caddyfile +120 -0
  238. package/docs/verification.md +102 -0
  239. package/dpi-network.example.yaml +62 -0
  240. package/images/01_durable_agent_network.svg +185 -0
  241. package/images/02_pi_made_durable.svg +204 -0
  242. package/images/03_restart_mid_tool.svg +168 -0
  243. package/images/07_one_api_every_client.svg +123 -0
  244. package/images/08_device_session_agent.svg +123 -0
  245. package/images/09_compact_keep_history.svg +143 -0
  246. package/images/10_shared_app_state.svg +177 -0
  247. package/images/11_durable_jobs_wait.svg +141 -0
  248. package/images/12_tools_change_mid_run.svg +231 -0
  249. package/images/13_hook_blocks_tool.svg +122 -0
  250. package/images/14_fork_at_any_entry.svg +119 -0
  251. package/images/15_web_client.png +0 -0
  252. package/images/16_terminal_client.svg +43 -0
  253. package/images/17_devices_are_data.svg +182 -0
  254. package/images/18_should_every_agent_be_durable.svg +118 -0
  255. package/images/19_sqlite_on_every_device.svg +155 -0
  256. package/images/20_admission_and_effects.svg +134 -0
  257. package/justfile +33 -0
  258. package/package.json +41 -4
  259. package/scripts/verify.mjs +210 -0
@@ -0,0 +1,185 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 620" width="1200" height="620" role="img" aria-labelledby="title desc" font-family="Inter, 'Segoe UI', Helvetica, Arial, sans-serif">
2
+ <title id="title">The Durable Agent Network</title>
3
+ <desc id="desc">Three clients, a web UI, dpi-tui and curl, connect to four devices that each run a durable pi agent; every client disconnects, and every device keeps writing its run's checkpoints to its own SQLite until the run is done.</desc>
4
+ <style>
5
+ .a { animation-duration: 14s; animation-iteration-count: infinite; animation-timing-function: ease-in-out; }
6
+ .ln { animation-timing-function: linear; }
7
+ .x { transform-box: fill-box; transform-origin: center; }
8
+ @keyframes cl0 { 0%, 1% { opacity: 0 } 4%, 42% { opacity: 1 } 46%, 96% { opacity: .35 } 100% { opacity: 0 } }
9
+ @keyframes lv0 { 0%, 4% { stroke-dashoffset: 1; opacity: 1 } 8%, 41.5% { stroke-dashoffset: 0; opacity: 1 } 44%, 100% { stroke-dashoffset: 0; opacity: 0 } }
10
+ @keyframes xr0 { 0%, 42% { opacity: 0; transform: scale(.3) } 44.5%, 96% { opacity: 1; transform: scale(1) } 100% { opacity: 0; transform: scale(1) } }
11
+ @keyframes dd0 { 0%, 42% { opacity: 0 } 44.5%, 96% { opacity: 1 } 100% { opacity: 0 } }
12
+ @keyframes cl1 { 0%, 2% { opacity: 0 } 5%, 42% { opacity: 1 } 46%, 96% { opacity: .35 } 100% { opacity: 0 } }
13
+ @keyframes lv1 { 0%, 5% { stroke-dashoffset: 1; opacity: 1 } 9%, 41.5% { stroke-dashoffset: 0; opacity: 1 } 44%, 100% { stroke-dashoffset: 0; opacity: 0 } }
14
+ @keyframes xr1 { 0%, 42.8% { opacity: 0; transform: scale(.3) } 45.3%, 96% { opacity: 1; transform: scale(1) } 100% { opacity: 0; transform: scale(1) } }
15
+ @keyframes dd1 { 0%, 42.8% { opacity: 0 } 45.3%, 96% { opacity: 1 } 100% { opacity: 0 } }
16
+ @keyframes cl2 { 0%, 3% { opacity: 0 } 6%, 42% { opacity: 1 } 46%, 96% { opacity: .35 } 100% { opacity: 0 } }
17
+ @keyframes lv2 { 0%, 6% { stroke-dashoffset: 1; opacity: 1 } 10%, 41.5% { stroke-dashoffset: 0; opacity: 1 } 44%, 100% { stroke-dashoffset: 0; opacity: 0 } }
18
+ @keyframes xr2 { 0%, 43.6% { opacity: 0; transform: scale(.3) } 46.1%, 96% { opacity: 1; transform: scale(1) } 100% { opacity: 0; transform: scale(1) } }
19
+ @keyframes dd2 { 0%, 43.6% { opacity: 0 } 46.1%, 96% { opacity: 1 } 100% { opacity: 0 } }
20
+ @keyframes bus { 0%, 9% { stroke-dashoffset: 1; opacity: 1 } 12.5%, 41.5% { stroke-dashoffset: 0; opacity: 1 } 44%, 100% { stroke-dashoffset: 0; opacity: 0 } }
21
+ @keyframes drop { 0%, 10.2% { stroke-dashoffset: 1; opacity: 1 } 11.4%, 41.5% { stroke-dashoffset: 0; opacity: 1 } 44%, 100% { stroke-dashoffset: 0; opacity: 0 } }
22
+ @keyframes jn { 0%, 7% { fill: #B9AAAE } 9%, 41.5% { fill: #FF5252 } 44%, 100% { fill: #B9AAAE } }
23
+ @keyframes cap { 0%, 62% { opacity: 0 } 65%, 96% { opacity: 1 } 100% { opacity: 0 } }
24
+ @keyframes mv0 { 0%, 10.5% { stroke-dashoffset: 0 } 56.5%, 100% { stroke-dashoffset: -132 } }
25
+ @keyframes mv1 { 0%, 10.5% { stroke-dashoffset: 0 } 47%, 100% { stroke-dashoffset: -99 } }
26
+ @keyframes mv2 { 0%, 10.5% { stroke-dashoffset: 0 } 62%, 100% { stroke-dashoffset: -143 } }
27
+ @keyframes mv3 { 0%, 10.5% { stroke-dashoffset: 0 } 54%, 100% { stroke-dashoffset: -121 } }
28
+ @keyframes q00 { 0%, 10.5% { fill: #141011; stroke: #6B5A5E } 11.1%, 13.2% { fill: #3A1D20; stroke: #FF5252 } 14%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
29
+ @keyframes q01 { 0%, 14% { fill: #141011; stroke: #6B5A5E } 14.6%, 21.7% { fill: #3A1D20; stroke: #FF5252 } 22.5%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
30
+ @keyframes q02 { 0%, 22.5% { fill: #141011; stroke: #6B5A5E } 23.1%, 30.2% { fill: #3A1D20; stroke: #FF5252 } 31%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
31
+ @keyframes q03 { 0%, 31% { fill: #141011; stroke: #6B5A5E } 31.6%, 38.7% { fill: #3A1D20; stroke: #FF5252 } 39.5%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
32
+ @keyframes q04 { 0%, 39.5% { fill: #141011; stroke: #6B5A5E } 40.1%, 47.2% { fill: #3A1D20; stroke: #FF5252 } 48%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
33
+ @keyframes q05 { 0%, 48% { fill: #141011; stroke: #6B5A5E } 48.6%, 55.7% { fill: #3A1D20; stroke: #FF5252 } 56.5%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
34
+ @keyframes q10 { 0%, 10.5% { fill: #141011; stroke: #6B5A5E } 11.1%, 11.2% { fill: #3A1D20; stroke: #FF5252 } 12%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
35
+ @keyframes q11 { 0%, 12% { fill: #141011; stroke: #6B5A5E } 12.6%, 18.2% { fill: #3A1D20; stroke: #FF5252 } 19%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
36
+ @keyframes q12 { 0%, 19% { fill: #141011; stroke: #6B5A5E } 19.6%, 25.2% { fill: #3A1D20; stroke: #FF5252 } 26%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
37
+ @keyframes q13 { 0%, 26% { fill: #141011; stroke: #6B5A5E } 26.6%, 32.2% { fill: #3A1D20; stroke: #FF5252 } 33%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
38
+ @keyframes q14 { 0%, 33% { fill: #141011; stroke: #6B5A5E } 33.6%, 39.2% { fill: #3A1D20; stroke: #FF5252 } 40%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
39
+ @keyframes q15 { 0%, 40% { fill: #141011; stroke: #6B5A5E } 40.6%, 46.2% { fill: #3A1D20; stroke: #FF5252 } 47%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
40
+ @keyframes q20 { 0%, 10.5% { fill: #141011; stroke: #6B5A5E } 11.1%, 14.2% { fill: #3A1D20; stroke: #FF5252 } 15%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
41
+ @keyframes q21 { 0%, 15% { fill: #141011; stroke: #6B5A5E } 15.6%, 23.6% { fill: #3A1D20; stroke: #FF5252 } 24.4%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
42
+ @keyframes q22 { 0%, 24.4% { fill: #141011; stroke: #6B5A5E } 25%, 33% { fill: #3A1D20; stroke: #FF5252 } 33.8%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
43
+ @keyframes q23 { 0%, 33.8% { fill: #141011; stroke: #6B5A5E } 34.4%, 42.4% { fill: #3A1D20; stroke: #FF5252 } 43.2%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
44
+ @keyframes q24 { 0%, 43.2% { fill: #141011; stroke: #6B5A5E } 43.8%, 51.8% { fill: #3A1D20; stroke: #FF5252 } 52.6%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
45
+ @keyframes q25 { 0%, 52.6% { fill: #141011; stroke: #6B5A5E } 53.2%, 61.2% { fill: #3A1D20; stroke: #FF5252 } 62%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
46
+ @keyframes q30 { 0%, 10.5% { fill: #141011; stroke: #6B5A5E } 11.1%, 12.2% { fill: #3A1D20; stroke: #FF5252 } 13%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
47
+ @keyframes q31 { 0%, 13% { fill: #141011; stroke: #6B5A5E } 13.6%, 20.4% { fill: #3A1D20; stroke: #FF5252 } 21.2%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
48
+ @keyframes q32 { 0%, 21.2% { fill: #141011; stroke: #6B5A5E } 21.8%, 28.6% { fill: #3A1D20; stroke: #FF5252 } 29.4%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
49
+ @keyframes q33 { 0%, 29.4% { fill: #141011; stroke: #6B5A5E } 30%, 36.8% { fill: #3A1D20; stroke: #FF5252 } 37.6%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
50
+ @keyframes q34 { 0%, 37.6% { fill: #141011; stroke: #6B5A5E } 38.2%, 45% { fill: #3A1D20; stroke: #FF5252 } 45.8%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
51
+ @keyframes q35 { 0%, 45.8% { fill: #141011; stroke: #6B5A5E } 46.4%, 53.2% { fill: #3A1D20; stroke: #FF5252 } 54%, 96% { fill: #FF5252; stroke: #FF5252 } 100% { fill: #141011; stroke: #6B5A5E } }
52
+ @media (prefers-reduced-motion: reduce) { * { animation: none !important; } }
53
+ </style>
54
+ <defs>
55
+ <symbol id="g-pi" viewBox="0 0 64 64">
56
+ <rect x="1.5" y="1.5" width="61" height="61" rx="12" fill="#141011" stroke="#FF5252" stroke-width="2.5"/>
57
+ <g fill="#FFFFFF" transform="translate(16 16) scale(8)">
58
+ <path d="M 0 0H3V2H2V1H0Z"/>
59
+ <path d="M 0 1H1V2H2V3H1V4H0Z"/>
60
+ <path d="M 3 2H4V4H3Z"/>
61
+ </g>
62
+ </symbol>
63
+ <symbol id="g-db" viewBox="0 0 48 60">
64
+ <path d="M 3 10 V50 A21 7 0 0 0 45 50 V10" fill="#3A1D20" stroke="#FF5252" stroke-width="2.5"/>
65
+ <ellipse cx="24" cy="10" rx="21" ry="7" fill="#5A2328" stroke="#FF5252" stroke-width="2.5"/>
66
+ <path d="M 3 24 A21 7 0 0 0 45 24 M 3 37 A21 7 0 0 0 45 37" fill="none" stroke="#FF5252" stroke-width="2.5"/>
67
+ </symbol>
68
+ <symbol id="g-laptop" viewBox="0 0 64 44">
69
+ <rect x="9" y="3" width="46" height="30" rx="4" fill="#21191B" stroke="#F3EDEE" stroke-width="2.5"/>
70
+ <rect x="15" y="9" width="34" height="18" rx="2" fill="#141011"/>
71
+ <path d="M 2 37 H62 L58 42 H6 Z" fill="#F3EDEE"/>
72
+ </symbol>
73
+ <symbol id="g-server" viewBox="0 0 64 44">
74
+ <rect x="3" y="4" width="58" height="16" rx="4" fill="#21191B" stroke="#F3EDEE" stroke-width="2.5"/>
75
+ <rect x="3" y="24" width="58" height="16" rx="4" fill="#21191B" stroke="#F3EDEE" stroke-width="2.5"/>
76
+ <circle cx="13" cy="12" r="2.6" fill="#FF5252"/><circle cx="13" cy="32" r="2.6" fill="#FF5252"/>
77
+ <path d="M 36 12 H53 M 36 32 H53" stroke="#B9AAAE" stroke-width="2.5" stroke-linecap="round"/>
78
+ </symbol>
79
+ <symbol id="g-cloud" viewBox="0 0 64 44">
80
+ <path d="M 18 38 H48 A11 11 0 0 0 48 16 A15 15 0 0 0 20 13 A12.5 12.5 0 0 0 18 38 Z" fill="#21191B" stroke="#F3EDEE" stroke-width="2.5" stroke-linejoin="round"/>
81
+ <rect x="25" y="22" width="16" height="10" rx="2" fill="none" stroke="#FF5252" stroke-width="2.2"/>
82
+ </symbol>
83
+ <symbol id="g-browser" viewBox="0 0 72 52">
84
+ <rect x="2" y="2" width="68" height="48" rx="6" fill="#21191B" stroke="#F3EDEE" stroke-width="2.5"/>
85
+ <path d="M 2 14 H70" stroke="#F3EDEE" stroke-width="2.5"/>
86
+ <circle cx="10" cy="8" r="2" fill="#FF5252"/><circle cx="17" cy="8" r="2" fill="#B9AAAE"/><circle cx="24" cy="8" r="2" fill="#B9AAAE"/>
87
+ <path d="M 12 26 H44 M 12 34 H58 M 12 42 H36" stroke="#B9AAAE" stroke-width="3" stroke-linecap="round"/>
88
+ </symbol>
89
+ <symbol id="g-terminal" viewBox="0 0 72 52">
90
+ <rect x="2" y="2" width="68" height="48" rx="6" fill="#21191B" stroke="#F3EDEE" stroke-width="2.5"/>
91
+ <path d="M 14 18 L24 26 L14 34" fill="none" stroke="#FF5252" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round"/>
92
+ <path d="M 30 36 H50" stroke="#F3EDEE" stroke-width="3.2" stroke-linecap="round"/>
93
+ </symbol>
94
+ <symbol id="g-cross" viewBox="0 0 32 32">
95
+ <circle cx="16" cy="16" r="13.5" fill="#141011" stroke="#FF5252" stroke-width="2.5"/>
96
+ <path d="M 11 11 L21 21 M 21 11 L11 21" stroke="#FF5252" stroke-width="3" stroke-linecap="round"/>
97
+ </symbol>
98
+ <marker id="ah" viewBox="0 0 10 10" refX="10" refY="5" markerUnits="userSpaceOnUse" markerWidth="11" markerHeight="11" orient="auto"><path d="M 0 0 L10 5 L0 10 Z" fill="#FF5252"/></marker>
99
+ </defs>
100
+ <rect width="1200" height="620" rx="18" fill="#141011"/>
101
+ <text x="48" y="70" font-size="34" font-weight="600" fill="#F3EDEE">The Durable Agent Network</text>
102
+ <text x="48" y="104" font-size="22" fill="#B9AAAE">Close every client. The work continues.</text>
103
+ <path d="M 177 330 V300 H1023 V330" fill="none" stroke="#B9AAAE" stroke-width="2.5" stroke-linejoin="round"/>
104
+ <path d="M 459 300 V330 M 741 300 V330" fill="none" stroke="#B9AAAE" stroke-width="2.5"/>
105
+ <g fill="none" stroke="#FF5252" stroke-width="3" stroke-linejoin="round" opacity="0" class="a ln" style="animation-name: bus"><path d="M 600 300 H177 V330" pathLength="1" stroke-dasharray="1 1"/><path d="M 600 300 H1023 V330" pathLength="1" stroke-dasharray="1 1"/></g>
106
+ <g fill="none" stroke="#FF5252" stroke-width="3" opacity="0" class="a ln" style="animation-name: drop"><path d="M 459 300 V330" pathLength="1" stroke-dasharray="1 1"/><path d="M 741 300 V330" pathLength="1" stroke-dasharray="1 1"/></g>
107
+ <path class="a" style="animation-name: dd0" d="M 430 250 L600 300" fill="none" stroke="#B9AAAE" stroke-width="2.5" stroke-dasharray="7 7"/>
108
+ <path class="a" style="animation-name: dd1" d="M 600 250 L600 300" fill="none" stroke="#B9AAAE" stroke-width="2.5" stroke-dasharray="7 7"/>
109
+ <path class="a" style="animation-name: dd2" d="M 770 250 L600 300" fill="none" stroke="#B9AAAE" stroke-width="2.5" stroke-dasharray="7 7"/>
110
+ <path class="a" style="animation-name: lv0" d="M 430 250 L600 300" pathLength="1" fill="none" stroke="#FF5252" stroke-width="3" stroke-dasharray="1 1" opacity="0"/>
111
+ <path class="a" style="animation-name: lv1" d="M 600 250 L600 300" pathLength="1" fill="none" stroke="#FF5252" stroke-width="3" stroke-dasharray="1 1" opacity="0"/>
112
+ <path class="a" style="animation-name: lv2" d="M 770 250 L600 300" pathLength="1" fill="none" stroke="#FF5252" stroke-width="3" stroke-dasharray="1 1" opacity="0"/>
113
+ <circle class="a" style="animation-name: jn" cx="600" cy="300" r="7" fill="#B9AAAE"/>
114
+ <g class="a" style="animation-name: cl0" opacity=".35"><use href="#g-browser" x="387" y="134" width="86" height="62"/><text x="430" y="224" text-anchor="middle" font-size="22" fill="#F3EDEE">web UI</text></g>
115
+ <g class="a" style="animation-name: cl1" opacity=".35"><use href="#g-terminal" x="557" y="134" width="86" height="62"/><text x="600" y="224" text-anchor="middle" font-family="'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace" font-size="22" fill="#F3EDEE">dpi-tui</text></g>
116
+ <g class="a" style="animation-name: cl2" opacity=".35"><rect x="728.5" y="135.5" width="83" height="59" rx="7" fill="#21191B" stroke="#F3EDEE" stroke-width="3"/><text x="770" y="174" text-anchor="middle" font-family="'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace" font-size="26" font-weight="700" fill="#FF5252">{ }</text><text x="770" y="224" text-anchor="middle" font-family="'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace" font-size="22" fill="#F3EDEE">curl</text></g>
117
+ <g class="a x" style="animation-name: xr0"><use href="#g-cross" x="417" y="237" width="26" height="26"/></g>
118
+ <g class="a x" style="animation-name: xr1"><use href="#g-cross" x="587" y="237" width="26" height="26"/></g>
119
+ <g class="a x" style="animation-name: xr2"><use href="#g-cross" x="757" y="237" width="26" height="26"/></g>
120
+ <g>
121
+ <rect x="48" y="330" width="258" height="214" rx="12" fill="#21191B" stroke="#443438" stroke-width="2"/>
122
+ <use href="#g-laptop" x="66" y="356" width="58" height="40"/>
123
+ <text x="138" y="374" font-family="'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace" font-size="24" fill="#F3EDEE">local</text>
124
+ <text x="138" y="400" font-size="20" fill="#B9AAAE">local</text>
125
+ <use href="#g-pi" x="66" y="420" width="60" height="60"/>
126
+ <use href="#g-db" x="242" y="421" width="46" height="58"/>
127
+ <path class="a ln" style="animation-name: mv0" d="M 138 450 H236" stroke="#FF5252" stroke-width="2.5" stroke-dasharray="6 5" marker-end="url(#ah)"/>
128
+ <text x="66" y="518" font-size="20" font-weight="600" letter-spacing="1" fill="#B9AAAE">RUN</text>
129
+ <rect class="a" style="animation-name: q00" x="123" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
130
+ <rect class="a" style="animation-name: q01" x="152" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
131
+ <rect class="a" style="animation-name: q02" x="181" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
132
+ <rect class="a" style="animation-name: q03" x="210" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
133
+ <rect class="a" style="animation-name: q04" x="239" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
134
+ <rect class="a" style="animation-name: q05" x="268" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
135
+ </g>
136
+ <g>
137
+ <rect x="330" y="330" width="258" height="214" rx="12" fill="#21191B" stroke="#443438" stroke-width="2"/>
138
+ <use href="#g-server" x="348" y="356" width="58" height="40"/>
139
+ <text x="420" y="374" font-family="'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace" font-size="24" fill="#F3EDEE">mac-mini</text>
140
+ <text x="420" y="400" font-size="20" fill="#B9AAAE">ssh</text>
141
+ <use href="#g-pi" x="348" y="420" width="60" height="60"/>
142
+ <use href="#g-db" x="524" y="421" width="46" height="58"/>
143
+ <path class="a ln" style="animation-name: mv1" d="M 420 450 H518" stroke="#FF5252" stroke-width="2.5" stroke-dasharray="6 5" marker-end="url(#ah)"/>
144
+ <text x="348" y="518" font-size="20" font-weight="600" letter-spacing="1" fill="#B9AAAE">RUN</text>
145
+ <rect class="a" style="animation-name: q10" x="405" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
146
+ <rect class="a" style="animation-name: q11" x="434" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
147
+ <rect class="a" style="animation-name: q12" x="463" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
148
+ <rect class="a" style="animation-name: q13" x="492" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
149
+ <rect class="a" style="animation-name: q14" x="521" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
150
+ <rect class="a" style="animation-name: q15" x="550" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
151
+ </g>
152
+ <g>
153
+ <rect x="612" y="330" width="258" height="214" rx="12" fill="#21191B" stroke="#443438" stroke-width="2"/>
154
+ <use href="#g-server" x="630" y="356" width="58" height="40"/>
155
+ <text x="702" y="374" font-family="'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace" font-size="24" fill="#F3EDEE">linux-box</text>
156
+ <text x="702" y="400" font-size="20" fill="#B9AAAE">ssh</text>
157
+ <use href="#g-pi" x="630" y="420" width="60" height="60"/>
158
+ <use href="#g-db" x="806" y="421" width="46" height="58"/>
159
+ <path class="a ln" style="animation-name: mv2" d="M 702 450 H800" stroke="#FF5252" stroke-width="2.5" stroke-dasharray="6 5" marker-end="url(#ah)"/>
160
+ <text x="630" y="518" font-size="20" font-weight="600" letter-spacing="1" fill="#B9AAAE">RUN</text>
161
+ <rect class="a" style="animation-name: q20" x="687" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
162
+ <rect class="a" style="animation-name: q21" x="716" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
163
+ <rect class="a" style="animation-name: q22" x="745" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
164
+ <rect class="a" style="animation-name: q23" x="774" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
165
+ <rect class="a" style="animation-name: q24" x="803" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
166
+ <rect class="a" style="animation-name: q25" x="832" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
167
+ </g>
168
+ <g>
169
+ <rect x="894" y="330" width="258" height="214" rx="12" fill="#21191B" stroke="#443438" stroke-width="2"/>
170
+ <use href="#g-cloud" x="912" y="356" width="58" height="40"/>
171
+ <text x="984" y="374" font-family="'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace" font-size="24" fill="#F3EDEE">vm-1</text>
172
+ <text x="984" y="400" font-size="20" fill="#B9AAAE">exe-dev</text>
173
+ <use href="#g-pi" x="912" y="420" width="60" height="60"/>
174
+ <use href="#g-db" x="1088" y="421" width="46" height="58"/>
175
+ <path class="a ln" style="animation-name: mv3" d="M 984 450 H1082" stroke="#FF5252" stroke-width="2.5" stroke-dasharray="6 5" marker-end="url(#ah)"/>
176
+ <text x="912" y="518" font-size="20" font-weight="600" letter-spacing="1" fill="#B9AAAE">RUN</text>
177
+ <rect class="a" style="animation-name: q30" x="969" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
178
+ <rect class="a" style="animation-name: q31" x="998" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
179
+ <rect class="a" style="animation-name: q32" x="1027" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
180
+ <rect class="a" style="animation-name: q33" x="1056" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
181
+ <rect class="a" style="animation-name: q34" x="1085" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
182
+ <rect class="a" style="animation-name: q35" x="1114" y="500" width="22" height="22" rx="4" fill="#FF5252" stroke="#FF5252" stroke-width="2"/>
183
+ </g>
184
+ <text class="a" style="animation-name: cap" x="600" y="588" text-anchor="middle" font-size="22" fill="#B9AAAE">No client connected. Every run keeps checkpointing to its device's SQLite.</text>
185
+ </svg>
@@ -0,0 +1,204 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 528" width="1200" height="528" role="img" aria-labelledby="title desc" font-family="Inter, 'Segoe UI', Helvetica, Arial, sans-serif">
2
+ <title id="title">Pi, made durable</title>
3
+ <desc id="desc">Pi keeps its history but loses the run when the process exits; Durable Pi commits history, queues, app state and task checkpoints to SQLite at every step, so the checkpointed run completes.</desc>
4
+ <defs>
5
+ <symbol id="g-pi" viewBox="0 0 64 64">
6
+ <rect x="1.5" y="1.5" width="61" height="61" rx="12" fill="#141011" stroke="#FF5252" stroke-width="2.5"/>
7
+ <g fill="#FFFFFF" transform="translate(16 16) scale(8)">
8
+ <path d="M0 0H3V2H2V1H0Z"/>
9
+ <path d="M0 1H1V2H2V3H1V4H0Z"/>
10
+ <path d="M3 2H4V4H3Z"/>
11
+ </g>
12
+ </symbol>
13
+ <symbol id="g-dpi" viewBox="0 0 9 5">
14
+ <g fill="#FFFFFF" transform="translate(.5 .5)">
15
+ <path d="M0 0H1V4H0Z"/>
16
+ <path d="M1 0H2V1H3V2H2V1H1Z"/>
17
+ <path d="M2 2H3V3H2V4H1V3H2Z"/>
18
+ <g transform="translate(4)">
19
+ <path d="M0 0H3V2H2V1H0Z"/>
20
+ <path d="M0 1H1V2H2V3H1V4H0Z"/>
21
+ <path d="M3 2H4V4H3Z"/>
22
+ </g>
23
+ </g>
24
+ </symbol>
25
+ <symbol id="g-db" viewBox="0 0 48 60">
26
+ <path d="M3 10 V50 A21 7 0 0 0 45 50 V10" fill="#3A1D20" stroke="#FF5252" stroke-width="2.5"/>
27
+ <ellipse cx="24" cy="10" rx="21" ry="7" fill="#5A2328" stroke="#FF5252" stroke-width="2.5"/>
28
+ <path d="M3 24 A21 7 0 0 0 45 24 M3 37 A21 7 0 0 0 45 37" fill="none" stroke="#FF5252" stroke-width="2.5"/>
29
+ </symbol>
30
+ <symbol id="g-check" viewBox="0 0 32 32">
31
+ <circle cx="16" cy="16" r="14" fill="#FF5252"/>
32
+ <path d="M9 16.5 L14 21.5 L23.5 11" fill="none" stroke="#141011" stroke-width="3.4" stroke-linecap="round" stroke-linejoin="round"/>
33
+ </symbol>
34
+ <symbol id="g-cross" viewBox="0 0 32 32">
35
+ <circle cx="16" cy="16" r="13.5" fill="#141011" stroke="#FF5252" stroke-width="2.5"/>
36
+ <path d="M11 11 L21 21 M21 11 L11 21" stroke="#FF5252" stroke-width="3" stroke-linecap="round"/>
37
+ </symbol>
38
+ <marker id="head-red" viewBox="0 0 12 10" refX="8" refY="5" markerWidth="12" markerHeight="10" markerUnits="userSpaceOnUse" orient="auto">
39
+ <path d="M0 0 L12 5 L0 10 Z" fill="#FF5252"/>
40
+ </marker>
41
+ <marker id="head-muted" viewBox="0 0 12 10" refX="8" refY="5" markerWidth="12" markerHeight="10" markerUnits="userSpaceOnUse" orient="auto">
42
+ <path d="M0 0 L12 5 L0 10 Z" fill="#B9AAAE"/>
43
+ </marker>
44
+ </defs>
45
+ <style>
46
+ .loop, .a { animation-duration: 12s; animation-iteration-count: infinite; animation-timing-function: ease-in-out; }
47
+ .pop { transform-box: fill-box; transform-origin: center; }
48
+ .loop { animation-name: loop; }
49
+ .l-tile { animation-name: l-tile; }
50
+ .l-db { animation-name: l-db; }
51
+ .l-arr { animation-name: l-arr; }
52
+ .l-arr-h { animation-name: l-arr-h; }
53
+ .l-box { animation-name: l-box; }
54
+ .l-run { opacity: 0; animation-name: l-run; }
55
+ .l-b1 { animation-name: l-b1; }
56
+ .l-b2 { animation-name: l-b2; }
57
+ .l-b3 { animation-name: l-b3; }
58
+ .l-cross { animation-name: l-cross; }
59
+ .l-lost { animation-name: l-lost; }
60
+ .r-tile { animation-name: r-tile; }
61
+ .r-dbs { animation-name: r-dbs; }
62
+ .r-bus { animation-name: r-bus; }
63
+ .r-drops { animation-name: r-drops; }
64
+ .r-rise1 { animation-name: r-rise1; }
65
+ .r-rise2 { animation-name: r-rise2; }
66
+ .r-rise-h { animation-name: r-rise-h; }
67
+ .r-arr { animation-name: r-arr; }
68
+ .r-arr-h { animation-name: r-arr-h; }
69
+ .r-strip { animation-name: r-strip; }
70
+ .r-b1 { animation-name: r-b1; }
71
+ .r-b2 { animation-name: r-b2; }
72
+ .r-b3 { animation-name: r-b3; }
73
+ .r-b4 { animation-name: r-b4; }
74
+ .r-b5 { animation-name: r-b5; }
75
+ .lid { opacity: 0; animation-name: lid; }
76
+ .r-check { animation-name: r-check; }
77
+ @keyframes loop { 0%, 96% { opacity: 1 } 99%, 100% { opacity: 0 } }
78
+ @keyframes l-tile { 0%, 2% { opacity: 0 } 5%, 22.5% { opacity: 1 } 24%, 27% { opacity: .3 } 29%, 100% { opacity: 1 } }
79
+ @keyframes l-db { 0%, 5% { opacity: 0 } 8%, 100% { opacity: 1 } }
80
+ @keyframes l-arr { 0%, 8% { stroke-dashoffset: 50 } 11.5%, 100% { stroke-dashoffset: 0 } }
81
+ @keyframes l-arr-h { 0%, 11% { opacity: 0 } 12%, 100% { opacity: 1 } }
82
+ @keyframes l-box { 0%, 12% { opacity: 0 } 14%, 100% { opacity: 1 } }
83
+ @keyframes l-run { 0%, 12% { opacity: 0 } 14%, 22.5% { opacity: 1 } 24.5%, 100% { opacity: 0 } }
84
+ @keyframes l-b1 { 0%, 15% { opacity: 0 } 16%, 100% { opacity: 1 } }
85
+ @keyframes l-b2 { 0%, 17.5% { opacity: 0 } 18.5%, 100% { opacity: 1 } }
86
+ @keyframes l-b3 { 0%, 20% { opacity: 0 } 21%, 100% { opacity: 1 } }
87
+ @keyframes l-cross { 0%, 24.5% { opacity: 0; transform: scale(.4) } 26.5%, 100% { opacity: 1; transform: scale(1) } }
88
+ @keyframes l-lost { 0%, 26.5% { opacity: 0 } 29%, 100% { opacity: 1 } }
89
+ @keyframes r-tile { 0%, 31% { opacity: 0 } 34%, 100% { opacity: 1 } }
90
+ @keyframes r-dbs { 0%, 37% { opacity: 0 } 40%, 100% { opacity: 1 } }
91
+ @keyframes r-bus { 0%, 40% { stroke-dashoffset: 407 } 43.5%, 100% { stroke-dashoffset: 0 } }
92
+ @keyframes r-drops { 0%, 40% { opacity: 0 } 42%, 100% { opacity: 1 } }
93
+ @keyframes r-rise1 { 0%, 43.5% { stroke-dashoffset: 22 } 45.5%, 100% { stroke-dashoffset: 0 } }
94
+ @keyframes r-rise2 { 0%, 43.5% { stroke-dashoffset: 36 } 45.5%, 100% { stroke-dashoffset: 0 } }
95
+ @keyframes r-rise-h { 0%, 45% { opacity: 0 } 46%, 100% { opacity: 1 } }
96
+ @keyframes r-arr { 0%, 33% { stroke-dashoffset: 220 } 36.5%, 100% { stroke-dashoffset: 0 } }
97
+ @keyframes r-arr-h { 0%, 36% { opacity: 0 } 37%, 100% { opacity: 1 } }
98
+ @keyframes r-strip { 0%, 35% { opacity: 0 } 38%, 100% { opacity: 1 } }
99
+ @keyframes r-b1 { 0%, 48% { opacity: 0 } 49%, 100% { opacity: 1 } }
100
+ @keyframes r-b2 { 0%, 50.5% { opacity: 0 } 51.5%, 100% { opacity: 1 } }
101
+ @keyframes r-b3 { 0%, 53% { opacity: 0 } 54%, 100% { opacity: 1 } }
102
+ @keyframes r-b4 { 0%, 55.5% { opacity: 0 } 56.5%, 100% { opacity: 1 } }
103
+ @keyframes r-b5 { 0%, 58% { opacity: 0 } 59%, 100% { opacity: 1 } }
104
+ @keyframes lid { 0%, 49% { opacity: 0 } 50% { opacity: .85 } 51.5% { opacity: 0 } 52.5% { opacity: .85 } 54% { opacity: 0 } 55% { opacity: .85 } 56.5% { opacity: 0 } 57.5% { opacity: .85 } 59% { opacity: 0 } 60% { opacity: .85 } 61.5%, 100% { opacity: 0 } }
105
+ @keyframes r-check { 0%, 61% { opacity: 0; transform: scale(.3) } 63%, 100% { opacity: 1; transform: scale(1) } }
106
+ @media (prefers-reduced-motion: reduce) { * { animation: none !important; } }
107
+ </style>
108
+
109
+ <rect width="1200" height="528" rx="18" fill="#141011"/>
110
+ <text x="48" y="70" font-size="34" font-weight="600" fill="#F3EDEE">Pi, made durable</text>
111
+
112
+ <!-- panels -->
113
+ <rect x="48" y="100" width="440" height="340" rx="12" fill="#21191B" stroke="#443438" stroke-width="2"/>
114
+ <rect x="512" y="100" width="640" height="340" rx="12" fill="#21191B" stroke="#443438" stroke-width="2"/>
115
+ <text x="80" y="144" font-size="24" font-weight="600" fill="#F3EDEE">Pi</text>
116
+ <use href="#g-dpi" x="541.4" y="120.6" width="46.8" height="26"/>
117
+ <text x="600" y="144" font-size="24" font-weight="600" fill="#F3EDEE">Durable Pi</text>
118
+
119
+ <g class="loop">
120
+ <!-- Pi: history survives, the run does not -->
121
+ <use class="a l-tile" href="#g-pi" x="80" y="172" width="80" height="80"/>
122
+ <g class="a l-db">
123
+ <use href="#g-db" x="92" y="310" width="56" height="70"/>
124
+ <text x="120" y="410" font-size="22" fill="#F3EDEE" text-anchor="middle">history</text>
125
+ </g>
126
+ <path class="a l-arr" d="M120 308 V260" stroke-dasharray="50 50" fill="none" stroke="#FF5252" stroke-width="2.5"/>
127
+ <path class="a l-arr-h" d="M120 308 V260" fill="none" stroke="none" marker-end="url(#head-red)"/>
128
+ <g class="a l-box">
129
+ <path d="M168 212 H212" fill="none" stroke="#B9AAAE" stroke-width="2.5" marker-end="url(#head-muted)"/>
130
+ <rect x="220" y="186" width="236" height="52" rx="10" fill="none" stroke="#B9AAAE" stroke-width="2" stroke-dasharray="8 6"/>
131
+ </g>
132
+ <g class="a l-run">
133
+ <rect x="220" y="186" width="236" height="52" rx="10" fill="#141011" stroke="#FF5252" stroke-width="2.5"/>
134
+ <g fill="#3A2C30">
135
+ <rect x="257" y="202" width="26" height="20" rx="3"/>
136
+ <rect x="291" y="202" width="26" height="20" rx="3"/>
137
+ <rect x="325" y="202" width="26" height="20" rx="3"/>
138
+ <rect x="359" y="202" width="26" height="20" rx="3"/>
139
+ <rect x="393" y="202" width="26" height="20" rx="3"/>
140
+ </g>
141
+ <g fill="#FF5252">
142
+ <rect class="a l-b1" x="257" y="202" width="26" height="20" rx="3"/>
143
+ <rect class="a l-b2" x="291" y="202" width="26" height="20" rx="3"/>
144
+ <rect class="a l-b3" x="325" y="202" width="26" height="20" rx="3"/>
145
+ </g>
146
+ </g>
147
+ <g class="a l-cross pop"><use href="#g-cross" x="321" y="195" width="34" height="34"/></g>
148
+ <text class="a l-lost" x="338" y="272" font-size="20" fill="#B9AAAE" text-anchor="middle">run state lost on exit</text>
149
+
150
+ <!-- Durable Pi: every step commits to SQLite -->
151
+ <use class="a r-tile" href="#g-pi" x="544" y="172" width="80" height="80"/>
152
+ <path class="a r-drops" d="M584 280 V308 M719 280 V308 M854 280 V308 M989 280 V308" fill="none" stroke="#FF5252" stroke-width="2.5"/>
153
+ <g class="a r-dbs">
154
+ <use href="#g-db" x="556" y="310" width="56" height="70"/>
155
+ <use href="#g-db" x="691" y="310" width="56" height="70"/>
156
+ <use href="#g-db" x="826" y="310" width="56" height="70"/>
157
+ <use href="#g-db" x="961" y="310" width="56" height="70"/>
158
+ <g font-size="22" fill="#F3EDEE" text-anchor="middle">
159
+ <text x="584" y="410">history</text>
160
+ <text x="719" y="410">queues</text>
161
+ <text x="854" y="410">app state</text>
162
+ <text x="989" y="410">tasks</text>
163
+ </g>
164
+ </g>
165
+ <g class="a lid" fill="#FF5252">
166
+ <ellipse cx="584" cy="321.7" rx="24.5" ry="8.2"/>
167
+ <ellipse cx="719" cy="321.7" rx="24.5" ry="8.2"/>
168
+ <ellipse cx="854" cy="321.7" rx="24.5" ry="8.2"/>
169
+ <ellipse cx="989" cy="321.7" rx="24.5" ry="8.2"/>
170
+ </g>
171
+ <path class="a r-bus" d="M584 280 H989" stroke-dasharray="407 407" fill="none" stroke="#FF5252" stroke-width="2.5"/>
172
+ <path class="a r-rise1" d="M584 280 V260" stroke-dasharray="22 22" fill="none" stroke="#FF5252" stroke-width="2.5"/>
173
+ <path class="a r-rise2" d="M989 280 V246" stroke-dasharray="36 36" fill="none" stroke="#FF5252" stroke-width="2.5"/>
174
+ <g class="a r-rise-h">
175
+ <path d="M584 280 V260" fill="none" stroke="none" marker-end="url(#head-red)"/>
176
+ <path d="M989 280 V246" fill="none" stroke="none" marker-end="url(#head-red)"/>
177
+ </g>
178
+ <path class="a r-arr" d="M632 212 H850" stroke-dasharray="220 220" fill="none" stroke="#FF5252" stroke-width="2.5"/>
179
+ <path class="a r-arr-h" d="M632 212 H850" fill="none" stroke="none" marker-end="url(#head-red)"/>
180
+ <g class="a r-strip">
181
+ <text x="989" y="172" font-size="22" fill="#F3EDEE" text-anchor="middle">checkpointed run</text>
182
+ <rect x="858" y="186" width="262" height="52" rx="10" fill="#141011" stroke="#FF5252" stroke-width="2.5"/>
183
+ <path d="M876 199 V225" stroke="#F3EDEE" stroke-width="2.5" stroke-linecap="round"/>
184
+ <path d="M877 199 L893 204.5 L877 210 Z" fill="#F3EDEE"/>
185
+ <g fill="#3A2C30">
186
+ <rect x="904" y="202" width="26" height="20" rx="3"/>
187
+ <rect x="938" y="202" width="26" height="20" rx="3"/>
188
+ <rect x="972" y="202" width="26" height="20" rx="3"/>
189
+ <rect x="1006" y="202" width="26" height="20" rx="3"/>
190
+ <rect x="1040" y="202" width="26" height="20" rx="3"/>
191
+ </g>
192
+ </g>
193
+ <g fill="#FF5252">
194
+ <rect class="a r-b1" x="904" y="202" width="26" height="20" rx="3"/>
195
+ <rect class="a r-b2" x="938" y="202" width="26" height="20" rx="3"/>
196
+ <rect class="a r-b3" x="972" y="202" width="26" height="20" rx="3"/>
197
+ <rect class="a r-b4" x="1006" y="202" width="26" height="20" rx="3"/>
198
+ <rect class="a r-b5" x="1040" y="202" width="26" height="20" rx="3"/>
199
+ </g>
200
+ <g class="a r-check pop"><use href="#g-check" x="1078" y="197" width="30" height="30"/></g>
201
+ </g>
202
+
203
+ <text x="48" y="490" font-size="22" fill="#B9AAAE">History, queues, app state and task checkpoints commit to SQLite before anything is shown.</text>
204
+ </svg>
@@ -0,0 +1,168 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 520" width="1200" height="520" role="img" aria-labelledby="title desc" font-family="Inter, 'Segoe UI', Helvetica, Arial, sans-serif">
2
+ <title id="title">Restart mid-tool. Keep going.</title>
3
+ <desc id="desc">The device restarts while a bash call is running; the agent resumes from its SQLite checkpoint, records bash as interrupted, and carries on with the next tool call.</desc>
4
+ <defs>
5
+ <symbol id="g-pi" viewBox="0 0 64 64">
6
+ <rect x="1.5" y="1.5" width="61" height="61" rx="12" fill="#141011" stroke="#FF5252" stroke-width="2.5"/>
7
+ <g fill="#FFFFFF" transform="translate(16 16) scale(8)">
8
+ <path d="M0 0H3V2H2V1H0Z"/>
9
+ <path d="M0 1H1V2H2V3H1V4H0Z"/>
10
+ <path d="M3 2H4V4H3Z"/>
11
+ </g>
12
+ </symbol>
13
+ <symbol id="g-db" viewBox="0 0 48 60">
14
+ <path d="M3 10 V50 A21 7 0 0 0 45 50 V10" fill="#3A1D20" stroke="#FF5252" stroke-width="2.5"/>
15
+ <ellipse cx="24" cy="10" rx="21" ry="7" fill="#5A2328" stroke="#FF5252" stroke-width="2.5"/>
16
+ <path d="M3 24 A21 7 0 0 0 45 24 M3 37 A21 7 0 0 0 45 37" fill="none" stroke="#FF5252" stroke-width="2.5"/>
17
+ </symbol>
18
+ <symbol id="g-server" viewBox="0 0 64 44">
19
+ <rect x="3" y="4" width="58" height="16" rx="4" fill="#21191B" stroke="#F3EDEE" stroke-width="2.5"/>
20
+ <rect x="3" y="24" width="58" height="16" rx="4" fill="#21191B" stroke="#F3EDEE" stroke-width="2.5"/>
21
+ <circle cx="13" cy="12" r="2.6" fill="#FF5252"/><circle cx="13" cy="32" r="2.6" fill="#FF5252"/>
22
+ <path d="M36 12 H53 M36 32 H53" stroke="#B9AAAE" stroke-width="2.5" stroke-linecap="round"/>
23
+ </symbol>
24
+ <symbol id="g-check" viewBox="0 0 32 32">
25
+ <circle cx="16" cy="16" r="14" fill="#FF5252"/>
26
+ <path d="M9 16.5 L14 21.5 L23.5 11" fill="none" stroke="#141011" stroke-width="3.4" stroke-linecap="round" stroke-linejoin="round"/>
27
+ </symbol>
28
+ <symbol id="g-check-o" viewBox="0 0 32 32">
29
+ <circle cx="16" cy="16" r="13.5" fill="none" stroke="#FF5252" stroke-width="2.5"/>
30
+ <path d="M9.5 16.5 L14 21 L22.5 11.5" fill="none" stroke="#FF5252" stroke-width="2.8" stroke-linecap="round" stroke-linejoin="round"/>
31
+ </symbol>
32
+ <symbol id="g-cross" viewBox="0 0 32 32">
33
+ <circle cx="16" cy="16" r="13.5" fill="#141011" stroke="#FF5252" stroke-width="2.5"/>
34
+ <path d="M11 11 L21 21 M21 11 L11 21" stroke="#FF5252" stroke-width="3" stroke-linecap="round"/>
35
+ </symbol>
36
+ <marker id="head-red" viewBox="0 0 12 10" refX="8" refY="5" markerWidth="12" markerHeight="10" markerUnits="userSpaceOnUse" orient="auto">
37
+ <path d="M0 0 L12 5 L0 10 Z" fill="#FF5252"/>
38
+ </marker>
39
+ <marker id="head-muted" viewBox="0 0 12 10" refX="8" refY="5" markerWidth="12" markerHeight="10" markerUnits="userSpaceOnUse" orient="auto">
40
+ <path d="M0 0 L12 5 L0 10 Z" fill="#B9AAAE"/>
41
+ </marker>
42
+ </defs>
43
+ <style>
44
+ .loop, .a { animation-duration: 14s; animation-iteration-count: infinite; animation-timing-function: ease-in-out; }
45
+ .pop { transform-box: fill-box; transform-origin: center; }
46
+ .grow { transform-box: fill-box; transform-origin: 0 50%; }
47
+ .mono { font-family: 'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace; }
48
+ .loop { animation-name: loop; }
49
+ .dev { animation-name: dev; }
50
+ .rst-txt { opacity: 0; animation-name: rst-txt; }
51
+ .arr-w-vis { animation-name: arr-w-vis; }
52
+ .arr-w { animation-name: arr-w; }
53
+ .arr-w-h { animation-name: arr-w-h; }
54
+ .arr-r { animation-name: arr-r; }
55
+ .arr-r-h { animation-name: arr-r-h; }
56
+ .lid { opacity: 0; animation-name: lid; }
57
+ .c-read { animation-name: c-read; }
58
+ .k-read { animation-name: k-read; }
59
+ .c-write { animation-name: c-write; }
60
+ .k-write { animation-name: k-write; }
61
+ .c-bash { animation-name: c-bash; }
62
+ .bash-solid { opacity: 0; animation-name: bash-solid; }
63
+ .bash-prog { opacity: 0; animation-name: bash-prog; }
64
+ .k-bash { animation-name: k-bash; }
65
+ .t-int { animation-name: t-int; }
66
+ .c-rst { animation-name: c-rst; }
67
+ .card { animation-name: card; }
68
+ .c-edit { animation-name: c-edit; }
69
+ .edit-prog { opacity: 0; animation-name: edit-prog; }
70
+ .k-edit { animation-name: k-edit; }
71
+ .t-res { animation-name: t-res; }
72
+ @keyframes loop { 0%, 96% { opacity: 1 } 99%, 100% { opacity: 0 } }
73
+ @keyframes dev { 0%, 31% { opacity: 1 } 32.5%, 41% { opacity: .2 } 42.5%, 100% { opacity: 1 } }
74
+ @keyframes rst-txt { 0%, 32.5% { opacity: 0 } 33.5%, 40.5% { opacity: 1 } 41.5%, 100% { opacity: 0 } }
75
+ @keyframes arr-w-vis { 0%, 31% { opacity: 1 } 32%, 41.5% { opacity: 0 } 43%, 100% { opacity: 1 } }
76
+ @keyframes arr-w { 0%, 9% { stroke-dashoffset: 522 } 12%, 100% { stroke-dashoffset: 0 } }
77
+ @keyframes arr-w-h { 0%, 11.5% { opacity: 0 } 12.5%, 100% { opacity: 1 } }
78
+ @keyframes arr-r { 0%, 43% { stroke-dashoffset: 522 } 46.5%, 100% { stroke-dashoffset: 0 } }
79
+ @keyframes arr-r-h { 0%, 46% { opacity: 0 } 47%, 100% { opacity: 1 } }
80
+ @keyframes lid { 0%, 12% { opacity: 0 } 13% { opacity: .85 } 14.5%, 19.5% { opacity: 0 } 20.5% { opacity: .85 } 22%, 61.5% { opacity: 0 } 62.5% { opacity: .85 } 64%, 100% { opacity: 0 } }
81
+ @keyframes c-read { 0%, 4% { opacity: 0 } 6%, 100% { opacity: 1 } }
82
+ @keyframes k-read { 0%, 9% { opacity: 0; transform: scale(.4) } 10.5%, 100% { opacity: 1; transform: scale(1) } }
83
+ @keyframes c-write { 0%, 13% { opacity: 0 } 15%, 100% { opacity: 1 } }
84
+ @keyframes k-write { 0%, 18% { opacity: 0; transform: scale(.4) } 19.5%, 100% { opacity: 1; transform: scale(1) } }
85
+ @keyframes c-bash { 0%, 21% { opacity: 0 } 23%, 100% { opacity: 1 } }
86
+ @keyframes bash-solid { 0%, 21% { opacity: 0 } 23%, 47% { opacity: 1 } 49%, 100% { opacity: 0 } }
87
+ @keyframes bash-prog { 0%, 23% { opacity: 0; transform: scaleX(0) } 24% { opacity: 1 } 31% { opacity: 1; transform: scaleX(.62) } 33%, 100% { opacity: 0; transform: scaleX(.62) } }
88
+ @keyframes k-bash { 0%, 48% { opacity: 0; transform: scale(.4) } 50%, 100% { opacity: 1; transform: scale(1) } }
89
+ @keyframes t-int { 0%, 49% { opacity: 0 } 51%, 100% { opacity: 1 } }
90
+ @keyframes c-rst { 0%, 31.5% { opacity: 0 } 33.5%, 100% { opacity: 1 } }
91
+ @keyframes card { 0%, 51% { opacity: 0 } 53.5%, 100% { opacity: 1 } }
92
+ @keyframes c-edit { 0%, 54% { opacity: 0 } 56%, 100% { opacity: 1 } }
93
+ @keyframes edit-prog { 0%, 56% { opacity: 0; transform: scaleX(0) } 56.5% { opacity: 1 } 60% { opacity: 1; transform: scaleX(1) } 61.5%, 100% { opacity: 0; transform: scaleX(1) } }
94
+ @keyframes k-edit { 0%, 60% { opacity: 0; transform: scale(.4) } 62%, 100% { opacity: 1; transform: scale(1) } }
95
+ @keyframes t-res { 0%, 61% { opacity: 0 } 63%, 100% { opacity: 1 } }
96
+ @media (prefers-reduced-motion: reduce) { * { animation: none !important; } }
97
+ </style>
98
+
99
+ <rect width="1200" height="520" rx="18" fill="#141011"/>
100
+ <text x="48" y="70" font-size="34" font-weight="600" fill="#F3EDEE">Restart mid-tool. Keep going.</text>
101
+
102
+ <!-- device panel -->
103
+ <rect x="48" y="100" width="1104" height="192" rx="12" fill="#21191B" stroke="#443438" stroke-width="2"/>
104
+ <use href="#g-db" x="972" y="154" width="56" height="70"/>
105
+ <text x="1000" y="254" font-size="22" fill="#F3EDEE" text-anchor="middle">checkpoint</text>
106
+
107
+ <g class="loop">
108
+ <g class="a dev">
109
+ <use href="#g-server" x="80" y="165.25" width="72" height="49.5"/>
110
+ <text class="mono" x="172" y="198" font-size="24" fill="#F3EDEE">mac-mini</text>
111
+ <use href="#g-pi" x="360" y="150" width="80" height="80"/>
112
+ </g>
113
+ <g class="a arr-w-vis">
114
+ <path class="a arr-w" d="M446 178 H965.5" stroke-dasharray="522 522" fill="none" stroke="#B9AAAE" stroke-width="2.5"/>
115
+ <path class="a arr-w-h" d="M446 178 H965.5" fill="none" stroke="none" marker-end="url(#head-muted)"/>
116
+ </g>
117
+ <text class="a rst-txt" x="708" y="198" font-size="22" fill="#B9AAAE" text-anchor="middle">restarting…</text>
118
+ <path class="a arr-r" d="M969.5 202 H450" stroke-dasharray="522 522" fill="none" stroke="#FF5252" stroke-width="2.5"/>
119
+ <path class="a arr-r-h" d="M969.5 202 H450" fill="none" stroke="none" marker-end="url(#head-red)"/>
120
+ <ellipse class="a lid" cx="1000" cy="165.7" rx="24.5" ry="8.2" fill="#FF5252"/>
121
+
122
+ <!-- tool calls, left to right -->
123
+ <g class="a c-read">
124
+ <rect x="48" y="324" width="128" height="56" rx="10" fill="#21191B" stroke="#443438" stroke-width="2"/>
125
+ <text class="mono" x="104" y="360" font-size="22" fill="#B9AAAE">read</text>
126
+ </g>
127
+ <g class="a k-read pop"><use href="#g-check-o" x="64" y="338" width="28" height="28"/></g>
128
+
129
+ <g class="a c-write">
130
+ <rect x="190" y="324" width="140" height="56" rx="10" fill="#21191B" stroke="#443438" stroke-width="2"/>
131
+ <text class="mono" x="246" y="360" font-size="22" fill="#B9AAAE">write</text>
132
+ </g>
133
+ <g class="a k-write pop"><use href="#g-check-o" x="206" y="338" width="28" height="28"/></g>
134
+
135
+ <g class="a c-bash">
136
+ <rect x="344" y="324" width="305" height="56" rx="10" fill="#2A1A1D" stroke="#FF5252" stroke-width="2" stroke-dasharray="8 6"/>
137
+ <rect class="a bash-prog grow" x="346" y="326" width="301" height="52" rx="8" fill="#6E2A31"/>
138
+ <rect class="a bash-solid" x="344" y="324" width="305" height="56" rx="10" fill="none" stroke="#FF5252" stroke-width="2.5"/>
139
+ <text class="mono" x="364" y="360" font-size="22" fill="#F3EDEE">bash</text>
140
+ </g>
141
+ <text class="a t-int" x="589" y="360" font-size="22" fill="#FF5252" text-anchor="end">interrupted</text>
142
+ <g class="a k-bash pop"><use href="#g-cross" x="601" y="336" width="32" height="32"/></g>
143
+
144
+ <g class="a c-rst">
145
+ <rect x="663" y="324" width="170" height="56" rx="10" fill="none" stroke="#6B5A5E" stroke-width="2" stroke-dasharray="8 6"/>
146
+ <g fill="none" stroke="#B9AAAE" stroke-width="2.5" stroke-linecap="round">
147
+ <path d="M708.07 344.93 A10 10 0 1 1 693.93 344.93"/>
148
+ <path d="M701 340 V350"/>
149
+ </g>
150
+ <text x="723" y="360" font-size="22" fill="#B9AAAE">restart</text>
151
+ </g>
152
+
153
+ <g class="a c-edit">
154
+ <rect x="847" y="324" width="305" height="56" rx="10" fill="#3A1D20" stroke="#FF5252" stroke-width="2.5"/>
155
+ <rect class="a edit-prog grow" x="849" y="326" width="301" height="52" rx="8" fill="#6E2A31"/>
156
+ <text class="mono" x="867" y="360" font-size="22" fill="#F3EDEE">edit</text>
157
+ </g>
158
+ <text class="a t-res" x="1092" y="360" font-size="22" fill="#F3EDEE" text-anchor="end">resumed</text>
159
+ <g class="a k-edit pop"><use href="#g-check" x="1104" y="336" width="32" height="32"/></g>
160
+
161
+ <!-- what the agent gets back for the interrupted call -->
162
+ <g class="a card">
163
+ <path d="M372 382 V406" fill="none" stroke="#B9AAAE" stroke-width="2.5" marker-end="url(#head-muted)"/>
164
+ <rect x="344" y="412" width="726" height="52" rx="10" fill="#21191B" stroke="#443438" stroke-width="2"/>
165
+ <text class="mono" x="364" y="445" font-size="22" fill="#F3EDEE">Tool bash was interrupted and may have partially run</text>
166
+ </g>
167
+ </g>
168
+ </svg>