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,177 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 668" width="1200" height="668" role="img" aria-labelledby="title desc" font-family="Inter, 'Segoe UI', Helvetica, Arial, sans-serif">
2
+ <title id="title">One shared App State</title>
3
+ <desc id="desc">Three agents on one device change a shared App State one path at a time: Main sets release.ready (rev 3 to 4), Fork reads, and Subagent increments incidents.open (rev 4 to 5); the web UI renders each change live, and its full JSON save from stale rev 3 gets 409 conflict.</desc>
4
+ <style>
5
+ .mono { font-family: 'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace; }
6
+ @keyframes chipM { 0%, 4.62% { opacity: 0; transform: scale(0.55) } 6.12% { opacity: 1; transform: scale(1.12) } 6.92%, 96% { opacity: 1; transform: scale(1) } 100% { opacity: 0; transform: scale(0.55) } }
7
+ .chipM { animation: chipM 13s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
8
+ @keyframes m1 { 0%, 6.92% { stroke-dashoffset: 336.0 } 12.31%, 96% { stroke-dashoffset: 0 } 100% { stroke-dashoffset: 336.0 } }
9
+ .m1 { animation: m1 13s ease-in-out infinite; }
10
+ @keyframes chkM { 0%, 12.31% { opacity: 0; transform: scale(0.55) } 13.81% { opacity: 1; transform: scale(1.12) } 14.62%, 96% { opacity: 1; transform: scale(1) } 100% { opacity: 0; transform: scale(0.55) } }
11
+ .chkM { animation: chkM 13s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
12
+ @keyframes revM { 0%, 13.08% { opacity: 0 } 15.38%, 96% { opacity: 1 } 100% { opacity: 0 } }
13
+ .revM { animation: revM 13s ease-in-out infinite; }
14
+ @keyframes m2 { 0%, 14.62% { stroke-dashoffset: 147.4 } 17.31%, 96% { stroke-dashoffset: 0 } 100% { stroke-dashoffset: 147.4 } }
15
+ .m2 { animation: m2 13s ease-in-out infinite; }
16
+ @keyframes m2h { 0%, 16.92% { opacity: 0 } 17.69%, 96% { opacity: 1 } 100% { opacity: 0 } }
17
+ .m2h { animation: m2h 13s ease-in-out infinite; }
18
+ @keyframes rev3 { 0%, 17.31% { opacity: 1 } 18.85%, 96% { opacity: 0 } 100% { opacity: 1 } }
19
+ .rev3 { animation: rev3 13s ease-in-out infinite; }
20
+ @keyframes rev4 { 0%, 17.31% { opacity: 0 } 18.85%, 46.54% { opacity: 1 } 48.08%, 100% { opacity: 0 } }
21
+ .rev4 { animation: rev4 13s ease-in-out infinite; }
22
+ @keyframes ui { 0%, 19.23% { stroke-dashoffset: 55.0 } 21.92%, 96% { stroke-dashoffset: 0 } 100% { stroke-dashoffset: 55.0 } }
23
+ .ui { animation: ui 13s ease-in-out infinite; }
24
+ @keyframes uih { 0%, 21.54% { opacity: 0 } 22.31%, 96% { opacity: 1 } 100% { opacity: 0 } }
25
+ .uih { animation: uih 13s ease-in-out infinite; }
26
+ @keyframes knob { 0%, 22.31% { transform: translateX(-40px); fill: #B9AAAE } 24.62%, 96% { transform: translateX(0); fill: #FF5252 } 100% { transform: translateX(-40px); fill: #B9AAAE } }
27
+ .knob { animation: knob 13s ease-in-out infinite; }
28
+ @keyframes pill { 0%, 22.31% { fill: #2C2225; stroke: #6B5A5E } 24.62%, 96% { fill: #5A2328; stroke: #FF5252 } 100% { fill: #2C2225; stroke: #6B5A5E } }
29
+ .pill { animation: pill 13s ease-in-out infinite; }
30
+ @keyframes cardA { 0%, 22.31% { stroke: #443438 } 23.46%, 27.69% { stroke: #FF5252 } 30.38%, 48.08% { stroke: #443438 } 49.23%, 53.46% { stroke: #FF5252 } 56.15%, 100% { stroke: #443438 } }
31
+ .cardA { animation: cardA 13s ease-in-out infinite; }
32
+ @keyframes fk { 0%, 27.69% { stroke-dashoffset: 477.0 } 33.08%, 96% { stroke-dashoffset: 0 } 100% { stroke-dashoffset: 477.0 } }
33
+ .fk { animation: fk 13s ease-in-out infinite; }
34
+ @keyframes fkh { 0%, 32.69% { opacity: 0 } 33.46%, 96% { opacity: 1 } 100% { opacity: 0 } }
35
+ .fkh { animation: fkh 13s ease-in-out infinite; }
36
+ @keyframes chipS { 0%, 35.38% { opacity: 0; transform: scale(0.55) } 36.88% { opacity: 1; transform: scale(1.12) } 37.69%, 96% { opacity: 1; transform: scale(1) } 100% { opacity: 0; transform: scale(0.55) } }
37
+ .chipS { animation: chipS 13s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
38
+ @keyframes s1 { 0%, 37.69% { stroke-dashoffset: 336.0 } 43.08%, 96% { stroke-dashoffset: 0 } 100% { stroke-dashoffset: 336.0 } }
39
+ .s1 { animation: s1 13s ease-in-out infinite; }
40
+ @keyframes chkS { 0%, 43.08% { opacity: 0; transform: scale(0.55) } 44.58% { opacity: 1; transform: scale(1.12) } 45.38%, 96% { opacity: 1; transform: scale(1) } 100% { opacity: 0; transform: scale(0.55) } }
41
+ .chkS { animation: chkS 13s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
42
+ @keyframes revS { 0%, 43.85% { opacity: 0 } 46.15%, 96% { opacity: 1 } 100% { opacity: 0 } }
43
+ .revS { animation: revS 13s ease-in-out infinite; }
44
+ @keyframes s2 { 0%, 45.38% { stroke-dashoffset: 147.4 } 48.08%, 96% { stroke-dashoffset: 0 } 100% { stroke-dashoffset: 147.4 } }
45
+ .s2 { animation: s2 13s ease-in-out infinite; }
46
+ @keyframes s2h { 0%, 47.69% { opacity: 0 } 48.46%, 96% { opacity: 1 } 100% { opacity: 0 } }
47
+ .s2h { animation: s2h 13s ease-in-out infinite; }
48
+ @keyframes rev5 { 0%, 46.54% { opacity: 0 } 48.08%, 96% { opacity: 1 } 100% { opacity: 0 } }
49
+ .rev5 { animation: rev5 13s ease-in-out infinite; }
50
+ @keyframes n1 { 0%, 48.46% { opacity: 1 } 50%, 96% { opacity: 0 } 100% { opacity: 1 } }
51
+ .n1 { animation: n1 13s ease-in-out infinite; }
52
+ @keyframes n2 { 0%, 48.46% { opacity: 0 } 50%, 96% { opacity: 1 } 100% { opacity: 0 } }
53
+ .n2 { animation: n2 13s ease-in-out infinite; }
54
+ @keyframes save { 0%, 53.08% { stroke: #B9AAAE; fill: #21191B } 53.85%, 55.77% { stroke: #FF5252; fill: #3A1D20 } 57.31%, 100% { stroke: #B9AAAE; fill: #21191B } }
55
+ .save { animation: save 13s ease-in-out infinite; }
56
+ @keyframes b409 { 0%, 56.15% { opacity: 0; transform: scale(0.55) } 57.65% { opacity: 1; transform: scale(1.12) } 58.46%, 96% { opacity: 1; transform: scale(1) } 100% { opacity: 0; transform: scale(0.55) } }
57
+ .b409 { animation: b409 13s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
58
+ @keyframes note { 0%, 58.46% { opacity: 0 } 60.77%, 96% { opacity: 1 } 100% { opacity: 0 } }
59
+ .note { animation: note 13s ease-in-out infinite; }
60
+ @media (prefers-reduced-motion: reduce) { * { animation: none !important; } }
61
+ </style>
62
+ <defs>
63
+ <symbol id="g-pi" viewBox="0 0 64 64">
64
+ <rect x="1.5" y="1.5" width="61" height="61" rx="12" fill="#141011" stroke="#FF5252" stroke-width="2.5"/>
65
+ <g fill="#FFFFFF" transform="translate(16 16) scale(8)">
66
+ <path d="M0 0H3V2H2V1H0Z"/>
67
+ <path d="M0 1H1V2H2V3H1V4H0Z"/>
68
+ <path d="M3 2H4V4H3Z"/>
69
+ </g>
70
+ </symbol>
71
+ <symbol id="g-db" viewBox="0 0 48 60">
72
+ <path d="M3 10 V50 A21 7 0 0 0 45 50 V10" fill="#3A1D20" stroke="#FF5252" stroke-width="2.5"/>
73
+ <ellipse cx="24" cy="10" rx="21" ry="7" fill="#5A2328" stroke="#FF5252" stroke-width="2.5"/>
74
+ <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"/>
75
+ </symbol>
76
+ <symbol id="g-server" viewBox="0 0 64 44">
77
+ <rect x="3" y="4" width="58" height="16" rx="4" fill="#21191B" stroke="#F3EDEE" stroke-width="2.5"/>
78
+ <rect x="3" y="24" width="58" height="16" rx="4" fill="#21191B" stroke="#F3EDEE" stroke-width="2.5"/>
79
+ <circle cx="13" cy="12" r="2.6" fill="#FF5252"/><circle cx="13" cy="32" r="2.6" fill="#FF5252"/>
80
+ <path d="M36 12 H53 M36 32 H53" stroke="#B9AAAE" stroke-width="2.5" stroke-linecap="round"/>
81
+ </symbol>
82
+ <symbol id="g-check-o" viewBox="0 0 32 32">
83
+ <circle cx="16" cy="16" r="13.5" fill="none" stroke="#FF5252" stroke-width="2.5"/>
84
+ <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"/>
85
+ </symbol>
86
+ <marker id="ah-red" viewBox="0 0 12 12" refX="4" refY="6" markerWidth="12" markerHeight="12" markerUnits="userSpaceOnUse" orient="auto"><path d="M0 1 L12 6 L0 11 Z" fill="#FF5252"/></marker>
87
+ <marker id="ah-muted" viewBox="0 0 12 12" refX="4" refY="6" markerWidth="12" markerHeight="12" markerUnits="userSpaceOnUse" orient="auto"><path d="M0 1 L12 6 L0 11 Z" fill="#B9AAAE"/></marker>
88
+ </defs>
89
+
90
+ <rect width="1200" height="668" rx="18" fill="#141011"/>
91
+ <text x="48" y="70" font-size="34" font-weight="600" fill="#F3EDEE">One shared App State</text>
92
+
93
+ <!-- Device panel: three agents on mac-mini share one App State -->
94
+ <rect x="48" y="100" width="736" height="464" rx="12" fill="#21191B" stroke="#443438" stroke-width="2"/>
95
+ <use href="#g-server" x="72" y="120" width="64" height="44"/>
96
+ <text class="mono" x="150" y="150" font-size="22" fill="#F3EDEE">mac-mini</text>
97
+ <use href="#g-pi" x="96" y="196" width="64" height="64"/>
98
+ <text x="128" y="290" text-anchor="middle" font-size="22" fill="#F3EDEE">Main</text>
99
+ <use href="#g-pi" x="96" y="320" width="64" height="64"/>
100
+ <text x="128" y="414" text-anchor="middle" font-size="22" fill="#F3EDEE">Fork</text>
101
+ <use href="#g-pi" x="96" y="444" width="64" height="64"/>
102
+ <text x="128" y="538" text-anchor="middle" font-size="22" fill="#F3EDEE">Subagent</text>
103
+
104
+ <!-- The App State document and its revision -->
105
+ <use href="#g-db" x="648" y="292" width="96" height="120"/>
106
+ <text x="696" y="248" text-anchor="middle" font-size="22" fill="#F3EDEE">app state</text>
107
+ <text class="mono rev3" x="696" y="280" text-anchor="middle" font-size="24" fill="#F3EDEE" opacity="0">rev <tspan fill="#F3EDEE">3</tspan></text>
108
+ <text class="mono rev4" x="696" y="280" text-anchor="middle" font-size="24" fill="#F3EDEE" opacity="0">rev <tspan fill="#FF5252">4</tspan></text>
109
+ <text class="mono rev5" x="696" y="280" text-anchor="middle" font-size="24" fill="#F3EDEE">rev <tspan fill="#FF5252">5</tspan></text>
110
+
111
+ <!-- Fork reads -->
112
+ <path class="fk" d="M650 352 L174 352" stroke="#B9AAAE" stroke-width="2.5" fill="none" stroke-dasharray="477.0"/>
113
+ <path class="fkh" d="M175 352 L174 352" stroke="#B9AAAE" stroke-width="2.5" fill="none" marker-end="url(#ah-muted)"/>
114
+
115
+ <!-- Main sets one path: accepted, rev 3 -> 4 -->
116
+ <path class="m1" d="M172 228 H507" stroke="#FF5252" stroke-width="2.5" fill="none" stroke-dasharray="336.0"/>
117
+ <path class="m2" d="M541 228 H572 L646.8 315.9" stroke="#FF5252" stroke-width="2.5" fill="none" stroke-dasharray="147.4"/>
118
+ <path class="m2h" d="M646.2 315.1 L646.8 315.9" stroke="#FF5252" stroke-width="2.5" fill="none" marker-end="url(#ah-red)"/>
119
+ <g class="chipM">
120
+ <rect x="194" y="210" width="272" height="36" rx="8" fill="#141011" stroke="#FF5252" stroke-width="2"/>
121
+ <text class="mono" x="330" y="235" text-anchor="middle" font-size="20" fill="#F3EDEE">release.ready = true</text>
122
+ </g>
123
+ <g class="chkM">
124
+ <circle cx="524" cy="228" r="17" fill="#21191B"/>
125
+ <use href="#g-check-o" x="508" y="212" width="32" height="32"/>
126
+ </g>
127
+ <text class="mono revM" x="524" y="204" text-anchor="middle" font-size="20" fill="#B9AAAE">rev 3 → 4</text>
128
+
129
+ <!-- Subagent increments one path atomically: accepted, rev 4 -> 5 -->
130
+ <path class="s1" d="M172 476 H507" stroke="#FF5252" stroke-width="2.5" fill="none" stroke-dasharray="336.0"/>
131
+ <path class="s2" d="M541 476 H572 L646.8 388.1" stroke="#FF5252" stroke-width="2.5" fill="none" stroke-dasharray="147.4"/>
132
+ <path class="s2h" d="M646.2 388.9 L646.8 388.1" stroke="#FF5252" stroke-width="2.5" fill="none" marker-end="url(#ah-red)"/>
133
+ <g class="chipS">
134
+ <rect x="200" y="458" width="260" height="36" rx="8" fill="#141011" stroke="#FF5252" stroke-width="2"/>
135
+ <text class="mono" x="330" y="483" text-anchor="middle" font-size="20" fill="#F3EDEE">incidents.open += 1</text>
136
+ </g>
137
+ <g class="chkS">
138
+ <circle cx="524" cy="476" r="17" fill="#21191B"/>
139
+ <use href="#g-check-o" x="508" y="460" width="32" height="32"/>
140
+ </g>
141
+ <text class="mono revS" x="524" y="518" text-anchor="middle" font-size="20" fill="#B9AAAE">rev 4 → 5</text>
142
+
143
+ <!-- DB -> web UI -->
144
+ <path class="ui" d="M750 352 L804 352" stroke="#FF5252" stroke-width="2.5" fill="none" stroke-dasharray="55.0"/>
145
+ <path class="uih" d="M803 352 L804 352" stroke="#FF5252" stroke-width="2.5" fill="none" marker-end="url(#ah-red)"/>
146
+
147
+ <!-- Web UI: live controls, and the JSON editor's full-document save -->
148
+ <rect x="816" y="100" width="336" height="464" rx="12" fill="#21191B" stroke="#F3EDEE" stroke-width="2"/>
149
+ <path d="M816 152 H1152" stroke="#F3EDEE" stroke-width="2"/>
150
+ <circle cx="842" cy="126" r="5" fill="#FF5252"/>
151
+ <circle cx="862" cy="126" r="5" fill="#B9AAAE"/>
152
+ <circle cx="882" cy="126" r="5" fill="#B9AAAE"/>
153
+ <text x="984" y="134" text-anchor="middle" font-size="22" fill="#F3EDEE">web UI</text>
154
+
155
+ <rect class="cardA" x="840" y="176" width="288" height="164" rx="10" fill="#141011" stroke="#443438" stroke-width="2"/>
156
+ <text class="mono" x="860" y="225" font-size="20" fill="#B9AAAE">release.ready</text>
157
+ <rect class="pill" x="1028" y="198" width="80" height="40" rx="20" fill="#5A2328" stroke="#FF5252" stroke-width="2.5"/>
158
+ <circle class="knob" cx="1088" cy="218" r="13" fill="#FF5252"/>
159
+ <path d="M860 258 H1108" stroke="#443438" stroke-width="1.5"/>
160
+ <text class="mono" x="860" y="305" font-size="20" fill="#B9AAAE">incidents.open</text>
161
+ <text class="n1" x="1106" y="314" text-anchor="end" font-size="44" font-weight="600" fill="#F3EDEE" opacity="0">1</text>
162
+ <text class="n2" x="1106" y="314" text-anchor="end" font-size="44" font-weight="600" fill="#F3EDEE">2</text>
163
+
164
+ <rect x="840" y="364" width="288" height="177" rx="10" fill="#141011" stroke="#443438" stroke-width="2"/>
165
+ <text x="860" y="394" font-size="20" letter-spacing="1" fill="#B9AAAE">JSON</text>
166
+ <rect class="save" x="860" y="406" width="84" height="36" rx="8" fill="#21191B" stroke="#B9AAAE" stroke-width="2"/>
167
+ <text class="mono" x="902" y="431" text-anchor="middle" font-size="20" fill="#F3EDEE">save</text>
168
+ <text x="960" y="431" font-size="20" fill="#B9AAAE">from rev 3</text>
169
+ <g class="b409">
170
+ <rect x="860" y="456" width="180" height="36" rx="8" fill="#3A1D20" stroke="#FF5252" stroke-width="2"/>
171
+ <text x="950" y="481" text-anchor="middle" font-size="22" font-weight="600" fill="#F3EDEE">409 conflict</text>
172
+ </g>
173
+ <text class="note" x="860" y="520" font-size="20" fill="#B9AAAE">reload, then save</text>
174
+
175
+ <text x="48" y="610" font-size="22" fill="#B9AAAE">One JSON document per device.</text>
176
+ <text x="48" y="640" font-size="22" fill="#B9AAAE">Agents change it one path at a time; a stale full-document save gets 409.</text>
177
+ </svg>
@@ -0,0 +1,141 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 700" width="1200" height="700" role="img" aria-labelledby="title desc" font-family="Inter, 'Segoe UI', Helvetica, Arial, sans-serif">
2
+ <title id="title">Durable jobs wait for you</title>
3
+ <desc id="desc">The release-check job runs plan, gather, approve, publish and verify on mac-mini, writing one checkpoint per phase; it waits at approve for a person, the wait survives a device restart, and after approval the job finishes.</desc>
4
+ <style>
5
+ .mono { font-family: 'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace; }
6
+ @keyframes prog { 0%, 2.86% { stroke-dashoffset: 939 } 5.71%, 9.29% { stroke-dashoffset: 865 } 12.86%, 16.43% { stroke-dashoffset: 685 } 20%, 49.29% { stroke-dashoffset: 535 } 51.79%, 53.21% { stroke-dashoffset: 325 } 55.71%, 57.14% { stroke-dashoffset: 145 } 59.64%, 96% { stroke-dashoffset: 0 } 100% { stroke-dashoffset: 939 } }
7
+ .prog { animation: prog 14s ease-in-out infinite; }
8
+ @keyframes ck-plan { 0%, 5.71% { opacity: 0; transform: scale(0.55) } 7.11% { opacity: 1; transform: scale(1.12) } 7.86%, 96% { opacity: 1; transform: scale(1) } 100% { opacity: 0; transform: scale(0.55) } }
9
+ .ck-plan { animation: ck-plan 14s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
10
+ @keyframes cp-plan { 0%, 7.14% { opacity: 0 } 9.29%, 96% { opacity: 1 } 100% { opacity: 0 } }
11
+ .cp-plan { animation: cp-plan 14s ease-in-out infinite; }
12
+ @keyframes ck-gather { 0%, 12.86% { opacity: 0; transform: scale(0.55) } 14.25% { opacity: 1; transform: scale(1.12) } 15%, 96% { opacity: 1; transform: scale(1) } 100% { opacity: 0; transform: scale(0.55) } }
13
+ .ck-gather { animation: ck-gather 14s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
14
+ @keyframes cp-gather { 0%, 14.29% { opacity: 0 } 16.43%, 96% { opacity: 1 } 100% { opacity: 0 } }
15
+ .cp-gather { animation: cp-gather 14s ease-in-out infinite; }
16
+ @keyframes ck-publish { 0%, 51.79% { opacity: 0; transform: scale(0.55) } 53.18% { opacity: 1; transform: scale(1.12) } 53.93%, 96% { opacity: 1; transform: scale(1) } 100% { opacity: 0; transform: scale(0.55) } }
17
+ .ck-publish { animation: ck-publish 14s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
18
+ @keyframes cp-publish { 0%, 52.86% { opacity: 0 } 55%, 96% { opacity: 1 } 100% { opacity: 0 } }
19
+ .cp-publish { animation: cp-publish 14s ease-in-out infinite; }
20
+ @keyframes ck-verify { 0%, 55.71% { opacity: 0; transform: scale(0.55) } 57.11% { opacity: 1; transform: scale(1.12) } 57.86%, 96% { opacity: 1; transform: scale(1) } 100% { opacity: 0; transform: scale(0.55) } }
21
+ .ck-verify { animation: ck-verify 14s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
22
+ @keyframes cp-verify { 0%, 56.79% { opacity: 0 } 58.93%, 96% { opacity: 1 } 100% { opacity: 0 } }
23
+ .cp-verify { animation: cp-verify 14s ease-in-out infinite; }
24
+ @keyframes tile { 0%, 20% { stroke: #6B5A5E } 21.43%, 96% { stroke: #FF5252 } 100% { stroke: #6B5A5E } }
25
+ .tile { animation: tile 14s ease-in-out infinite; }
26
+ @keyframes waiting { 0%, 20% { opacity: 0 } 22.14%, 47.14% { opacity: 1 } 48.57%, 100% { opacity: 0 } }
27
+ .waiting { animation: waiting 14s ease-in-out infinite; }
28
+ @keyframes cp-approve { 0%, 21.43% { opacity: 0 } 23.57%, 96% { opacity: 1 } 100% { opacity: 0 } }
29
+ .cp-approve { animation: cp-approve 14s ease-in-out infinite; }
30
+ @keyframes ring { 0%, 21.43% { opacity: 0; transform: scale(.85) } 21.79% { opacity: .9; transform: scale(.85) } 27.14% { opacity: 0; transform: scale(1.3) } 27.5% { opacity: .9; transform: scale(.85) } 32.86% { opacity: 0; transform: scale(1.3) } 41.43% { opacity: 0; transform: scale(.85) } 41.79% { opacity: .9; transform: scale(.85) } 47.14%, 100% { opacity: 0; transform: scale(1.3) } }
31
+ .ring { animation: ring 14s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
32
+ @keyframes restart { 0%, 32.86% { opacity: 0 } 34.29%, 39.29% { opacity: 1 } 40.71%, 100% { opacity: 0 } }
33
+ .restart { animation: restart 14s ease-in-out infinite; }
34
+ @keyframes host { 0%, 32.86% { opacity: 1 } 34.29%, 39.29% { opacity: .25 } 40.71%, 100% { opacity: 1 } }
35
+ .host { animation: host 14s ease-in-out infinite; }
36
+ @keyframes approved { 0%, 47.86% { opacity: 0 } 49.29%, 96% { opacity: 1 } 100% { opacity: 0 } }
37
+ .approved { animation: approved 14s ease-in-out infinite; }
38
+ @keyframes ck-approve { 0%, 47.86% { opacity: 0; transform: scale(0.55) } 49.25% { opacity: 1; transform: scale(1.12) } 50%, 96% { opacity: 1; transform: scale(1) } 100% { opacity: 0; transform: scale(0.55) } }
39
+ .ck-approve { animation: ck-approve 14s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
40
+ @keyframes done { 0%, 59.64% { opacity: .3; transform: scale(.94) } 61.79%, 96% { opacity: 1; transform: scale(1) } 100% { opacity: .3; transform: scale(.94) } }
41
+ .done { animation: done 14s ease-in-out infinite; transform-box: fill-box; transform-origin: center; }
42
+ @media (prefers-reduced-motion: reduce) { * { animation: none !important; } }
43
+ </style>
44
+ <defs>
45
+ <symbol id="g-pi" viewBox="0 0 64 64">
46
+ <rect x="1.5" y="1.5" width="61" height="61" rx="12" fill="#141011" stroke="#FF5252" stroke-width="2.5"/>
47
+ <g fill="#FFFFFF" transform="translate(16 16) scale(8)">
48
+ <path d="M0 0H3V2H2V1H0Z"/>
49
+ <path d="M0 1H1V2H2V3H1V4H0Z"/>
50
+ <path d="M3 2H4V4H3Z"/>
51
+ </g>
52
+ </symbol>
53
+ <symbol id="g-db" viewBox="0 0 48 60">
54
+ <path d="M3 10 V50 A21 7 0 0 0 45 50 V10" fill="#3A1D20" stroke="#FF5252" stroke-width="2.5"/>
55
+ <ellipse cx="24" cy="10" rx="21" ry="7" fill="#5A2328" stroke="#FF5252" stroke-width="2.5"/>
56
+ <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"/>
57
+ </symbol>
58
+ <symbol id="g-server" viewBox="0 0 64 44">
59
+ <rect x="3" y="4" width="58" height="16" rx="4" fill="#21191B" stroke="#F3EDEE" stroke-width="2.5"/>
60
+ <rect x="3" y="24" width="58" height="16" rx="4" fill="#21191B" stroke="#F3EDEE" stroke-width="2.5"/>
61
+ <circle cx="13" cy="12" r="2.6" fill="#FF5252"/><circle cx="13" cy="32" r="2.6" fill="#FF5252"/>
62
+ <path d="M36 12 H53 M36 32 H53" stroke="#B9AAAE" stroke-width="2.5" stroke-linecap="round"/>
63
+ </symbol>
64
+ <symbol id="g-check" viewBox="0 0 32 32">
65
+ <circle cx="16" cy="16" r="14" fill="#FF5252"/>
66
+ <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"/>
67
+ </symbol>
68
+ <symbol id="g-person" viewBox="0 0 40 40">
69
+ <circle cx="20" cy="13" r="7.5" fill="none" stroke="#F3EDEE" stroke-width="2.5"/>
70
+ <path d="M6 36 C7 27 13 23 20 23 C27 23 33 27 34 36" fill="none" stroke="#F3EDEE" stroke-width="2.5" stroke-linecap="round"/>
71
+ </symbol>
72
+ <marker id="ah-red" viewBox="0 0 12 12" refX="4" refY="6" markerWidth="12" markerHeight="12" markerUnits="userSpaceOnUse" orient="auto"><path d="M0 1 L12 6 L0 11 Z" fill="#FF5252"/></marker>
73
+ <marker id="ah-quiet" viewBox="0 0 12 12" refX="4" refY="6" markerWidth="12" markerHeight="12" markerUnits="userSpaceOnUse" orient="auto"><path d="M0 1 L12 6 L0 11 Z" fill="#6B5A5E"/></marker>
74
+ </defs>
75
+
76
+ <rect width="1200" height="700" rx="18" fill="#141011"/>
77
+ <text x="48" y="70" font-size="34" font-weight="600" fill="#F3EDEE">Durable jobs wait for you</text>
78
+
79
+ <rect x="48" y="100" width="1104" height="568" rx="12" fill="#21191B" stroke="#443438" stroke-width="2"/>
80
+
81
+ <!-- Header: the job and the device it runs on -->
82
+ <text class="mono" x="80" y="152" font-size="24" fill="#F3EDEE">release-check</text>
83
+ <g class="host">
84
+ <use href="#g-server" x="936" y="122" width="64" height="44"/>
85
+ <text class="mono" x="1016" y="151" font-size="22" fill="#F3EDEE">mac-mini</text>
86
+ </g>
87
+ <g class="restart" opacity="0">
88
+ <rect x="700" y="126" width="216" height="36" rx="18" fill="#141011" stroke="#6B5A5E" stroke-width="2"/>
89
+ <path d="M726.7 136.5 A8 8 0 1 0 732 144" fill="none" stroke="#B9AAAE" stroke-width="2.2" stroke-linecap="round"/>
90
+ <path d="M728 145 L732 139.5 L736 145 Z" fill="#B9AAAE"/>
91
+ <text x="744" y="151" font-size="20" fill="#B9AAAE">device restart</text>
92
+ </g>
93
+
94
+ <!-- Phase line: the red progress pauses at approve -->
95
+ <path d="M96 292 H1034" stroke="#6B5A5E" stroke-width="3" fill="none"/>
96
+ <path class="prog" d="M96 292 H1034" stroke="#FF5252" stroke-width="3.5" fill="none" stroke-dasharray="939"/>
97
+ <circle cx="170" cy="292" r="13" fill="#21191B" stroke="#6B5A5E" stroke-width="2.5"/>
98
+ <circle cx="350" cy="292" r="13" fill="#21191B" stroke="#6B5A5E" stroke-width="2.5"/>
99
+ <circle cx="710" cy="292" r="13" fill="#21191B" stroke="#6B5A5E" stroke-width="2.5"/>
100
+ <circle cx="890" cy="292" r="13" fill="#21191B" stroke="#6B5A5E" stroke-width="2.5"/>
101
+ <g class="ck-plan"><use href="#g-check" x="154" y="276" width="32" height="32"/></g>
102
+ <g class="ck-gather"><use href="#g-check" x="334" y="276" width="32" height="32"/></g>
103
+ <g class="ck-publish"><use href="#g-check" x="694" y="276" width="32" height="32"/></g>
104
+ <g class="ck-verify"><use href="#g-check" x="874" y="276" width="32" height="32"/></g>
105
+
106
+ <!-- approve: a person gate -->
107
+ <circle class="ring" cx="530" cy="292" r="46" fill="none" stroke="#FF5252" stroke-width="2.5" opacity="0"/>
108
+ <rect class="tile" x="500" y="262" width="60" height="60" rx="12" fill="#141011" stroke="#FF5252" stroke-width="2.5"/>
109
+ <use href="#g-person" x="510" y="272" width="40" height="40"/>
110
+ <g class="ck-approve"><use href="#g-check" x="546" y="306" width="26" height="26"/></g>
111
+ <text class="waiting" x="530" y="240" text-anchor="middle" font-size="22" fill="#FF5252" opacity="0">waiting for you</text>
112
+ <text class="approved" x="530" y="240" text-anchor="middle" font-size="22" fill="#FF5252">approved</text>
113
+
114
+ <!-- Done -->
115
+ <g class="done">
116
+ <use href="#g-pi" x="1034" y="260" width="64" height="64"/>
117
+ <text x="1066" y="354" text-anchor="middle" font-size="22" fill="#F3EDEE">Done</text>
118
+ </g>
119
+
120
+ <text x="170" y="354" text-anchor="middle" font-size="22" fill="#F3EDEE">plan</text>
121
+ <text x="350" y="354" text-anchor="middle" font-size="22" fill="#F3EDEE">gather</text>
122
+ <text x="530" y="354" text-anchor="middle" font-size="22" fill="#F3EDEE">approve</text>
123
+ <text x="710" y="354" text-anchor="middle" font-size="22" fill="#F3EDEE">publish</text>
124
+ <text x="890" y="354" text-anchor="middle" font-size="22" fill="#F3EDEE">verify</text>
125
+ <text x="350" y="380" text-anchor="middle" font-size="20" fill="#B9AAAE">subagent</text>
126
+
127
+ <!-- One checkpoint per phase -->
128
+ <use href="#g-db" x="482" y="490" width="96" height="120"/>
129
+ <path d="M170 396 L492.4 494.9 L492.4 494.9" stroke="#443438" stroke-width="2.5" fill="none" marker-end="url(#ah-quiet)"/>
130
+ <path class="cp-plan" d="M170 396 L492.4 494.9 L492.4 494.9" stroke="#FF5252" stroke-width="2.5" fill="none" marker-end="url(#ah-red)"/>
131
+ <path d="M350 396 L508.1 489.8 L508.1 489.8" stroke="#443438" stroke-width="2.5" fill="none" marker-end="url(#ah-quiet)"/>
132
+ <path class="cp-gather" d="M350 396 L508.1 489.8 L508.1 489.8" stroke="#FF5252" stroke-width="2.5" fill="none" marker-end="url(#ah-red)"/>
133
+ <path d="M530 396 L530 485 L530 485" stroke="#443438" stroke-width="2.5" fill="none" marker-end="url(#ah-quiet)"/>
134
+ <path class="cp-approve" d="M530 396 L530 485 L530 485" stroke="#FF5252" stroke-width="2.5" fill="none" marker-end="url(#ah-red)"/>
135
+ <path d="M710 396 L551.9 489.8 L551.9 489.8" stroke="#443438" stroke-width="2.5" fill="none" marker-end="url(#ah-quiet)"/>
136
+ <path class="cp-publish" d="M710 396 L551.9 489.8 L551.9 489.8" stroke="#FF5252" stroke-width="2.5" fill="none" marker-end="url(#ah-red)"/>
137
+ <path d="M890 396 L567.6 494.9 L567.6 494.9" stroke="#443438" stroke-width="2.5" fill="none" marker-end="url(#ah-quiet)"/>
138
+ <path class="cp-verify" d="M890 396 L567.6 494.9 L567.6 494.9" stroke="#FF5252" stroke-width="2.5" fill="none" marker-end="url(#ah-red)"/>
139
+ <text x="530" y="644" text-anchor="middle" font-size="22" fill="#F3EDEE">one checkpoint per phase</text>
140
+ <text x="620" y="558" font-size="22" fill="#B9AAAE">A restart resumes the current phase.</text>
141
+ </svg>
@@ -0,0 +1,231 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1200" height="752" viewBox="0 0 1200 752" role="img" aria-labelledby="title desc" font-family="Inter, 'Segoe UI', Helvetica, Arial, sans-serif">
2
+ <title id="title">Change the tools mid-run</title>
3
+ <desc id="desc">An agent's fourteen installed tools flow into its tool list, then turning on the Read only switch strikes the eight that write (bash, write, edit, update_state, run_durable_job, subagent, start_session and ping_on_call_engineer), so the agent's next request sees six: read, read_state, list_durable_jobs, check_durable_job, search_history and handoff.</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
+ <marker id="head-red" viewBox="0 0 10 10" refX="7" refY="5" markerWidth="5" markerHeight="5" orient="auto" markerUnits="strokeWidth">
14
+ <path d="M0 0L10 5L0 10Z" fill="#FF5252"/>
15
+ </marker>
16
+ <marker id="head-muted" viewBox="0 0 10 10" refX="7" refY="5" markerWidth="5" markerHeight="5" orient="auto" markerUnits="strokeWidth">
17
+ <path d="M0 0L10 5L0 10Z" fill="#B9AAAE"/>
18
+ </marker>
19
+ </defs>
20
+ <style>
21
+ .mono { font-family: 'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace; }
22
+ .an { animation-duration: 13s; animation-iteration-count: infinite; animation-timing-function: cubic-bezier(.4, 0, .2, 1); }
23
+ .draw { stroke-dasharray: 1 2; }
24
+
25
+ /* 1. all fourteen installed tools flow into AGENT TOOLS */
26
+ .f0 { animation-name: flow0; } .f1 { animation-name: flow1; } .f2 { animation-name: flow2; } .f3 { animation-name: flow3; }
27
+ .f4 { animation-name: flow4; } .f5 { animation-name: flow5; } .f6 { animation-name: flow6; } .f7 { animation-name: flow7; }
28
+ .f8 { animation-name: flow8; } .f9 { animation-name: flow9; } .f10 { animation-name: flow10; } .f11 { animation-name: flow11; }
29
+ .f12 { animation-name: flow12; } .f13 { animation-name: flow13; }
30
+ @keyframes flow0 { 0%, 4% { opacity: 0; transform: translateX(-412px) } 6% { opacity: 1 } 11%, 96% { opacity: 1; transform: translateX(0) } 100% { opacity: 0; transform: translateX(0) } }
31
+ @keyframes flow1 { 0%, 5% { opacity: 0; transform: translateX(-412px) } 7% { opacity: 1 } 12%, 96% { opacity: 1; transform: translateX(0) } 100% { opacity: 0; transform: translateX(0) } }
32
+ @keyframes flow2 { 0%, 6% { opacity: 0; transform: translateX(-412px) } 8% { opacity: 1 } 13%, 96% { opacity: 1; transform: translateX(0) } 100% { opacity: 0; transform: translateX(0) } }
33
+ @keyframes flow3 { 0%, 7% { opacity: 0; transform: translateX(-412px) } 9% { opacity: 1 } 14%, 96% { opacity: 1; transform: translateX(0) } 100% { opacity: 0; transform: translateX(0) } }
34
+ @keyframes flow4 { 0%, 8% { opacity: 0; transform: translateX(-412px) } 10% { opacity: 1 } 15%, 96% { opacity: 1; transform: translateX(0) } 100% { opacity: 0; transform: translateX(0) } }
35
+ @keyframes flow5 { 0%, 9% { opacity: 0; transform: translateX(-412px) } 11% { opacity: 1 } 16%, 96% { opacity: 1; transform: translateX(0) } 100% { opacity: 0; transform: translateX(0) } }
36
+ @keyframes flow6 { 0%, 10% { opacity: 0; transform: translateX(-412px) } 12% { opacity: 1 } 17%, 96% { opacity: 1; transform: translateX(0) } 100% { opacity: 0; transform: translateX(0) } }
37
+ @keyframes flow7 { 0%, 11% { opacity: 0; transform: translateX(-412px) } 13% { opacity: 1 } 18%, 96% { opacity: 1; transform: translateX(0) } 100% { opacity: 0; transform: translateX(0) } }
38
+ @keyframes flow8 { 0%, 12% { opacity: 0; transform: translateX(-412px) } 14% { opacity: 1 } 19%, 96% { opacity: 1; transform: translateX(0) } 100% { opacity: 0; transform: translateX(0) } }
39
+ @keyframes flow9 { 0%, 13% { opacity: 0; transform: translateX(-412px) } 15% { opacity: 1 } 20%, 96% { opacity: 1; transform: translateX(0) } 100% { opacity: 0; transform: translateX(0) } }
40
+ @keyframes flow10 { 0%, 14% { opacity: 0; transform: translateX(-412px) } 16% { opacity: 1 } 21%, 96% { opacity: 1; transform: translateX(0) } 100% { opacity: 0; transform: translateX(0) } }
41
+ @keyframes flow11 { 0%, 15% { opacity: 0; transform: translateX(-412px) } 17% { opacity: 1 } 22%, 96% { opacity: 1; transform: translateX(0) } 100% { opacity: 0; transform: translateX(0) } }
42
+ @keyframes flow12 { 0%, 16% { opacity: 0; transform: translateX(-412px) } 18% { opacity: 1 } 23%, 96% { opacity: 1; transform: translateX(0) } 100% { opacity: 0; transform: translateX(0) } }
43
+ @keyframes flow13 { 0%, 17% { opacity: 0; transform: translateX(-412px) } 19% { opacity: 1 } 24%, 96% { opacity: 1; transform: translateX(0) } 100% { opacity: 0; transform: translateX(0) } }
44
+
45
+ /* 2. the Read only switch turns on */
46
+ .sw-pill { animation-name: sw-pill; }
47
+ .sw-track { animation-name: sw-track; }
48
+ .sw-knob { animation-name: sw-knob; }
49
+ .sw-label { animation-name: sw-label; }
50
+ @keyframes sw-pill { 0%, 28% { stroke: #443438 } 31%, 96% { stroke: #FF5252 } 100% { stroke: #443438 } }
51
+ @keyframes sw-track { 0%, 28% { fill: #443438 } 31%, 96% { fill: #FF5252 } 100% { fill: #443438 } }
52
+ @keyframes sw-knob { 0%, 28% { transform: translateX(-22px); fill: #B9AAAE } 31%, 96% { transform: translateX(0); fill: #F3EDEE } 100% { transform: translateX(-22px); fill: #B9AAAE } }
53
+ @keyframes sw-label { 0%, 28% { fill: #B9AAAE } 31%, 96% { fill: #F3EDEE } 100% { fill: #B9AAAE } }
54
+ .sw-line { animation-name: sw-line; }
55
+ .sw-head { animation-name: sw-head; }
56
+ @keyframes sw-line { 0%, 31% { stroke-dashoffset: 1; opacity: 1 } 35%, 96% { stroke-dashoffset: 0; opacity: 1 } 100% { stroke-dashoffset: 0; opacity: 0 } }
57
+ @keyframes sw-head { 0%, 34.5% { opacity: 0 } 35%, 96% { opacity: 1 } 100% { opacity: 0 } }
58
+
59
+ /* 3. the eight tools that write are struck and fade; the six read tools turn red */
60
+ .s0 { animation-name: strike0; } .s1 { animation-name: strike1; } .s2 { animation-name: strike2; } .s3 { animation-name: strike3; }
61
+ .s4 { animation-name: strike4; } .s5 { animation-name: strike5; } .s6 { animation-name: strike6; } .s7 { animation-name: strike7; }
62
+ @keyframes strike0 { 0%, 35% { stroke-dashoffset: 1; stroke: #FF5252 } 38%, 42% { stroke-dashoffset: 0; stroke: #FF5252 } 46%, 100% { stroke-dashoffset: 0; stroke: #6B5A5E } }
63
+ @keyframes strike1 { 0%, 35.5% { stroke-dashoffset: 1; stroke: #FF5252 } 38.5%, 42% { stroke-dashoffset: 0; stroke: #FF5252 } 46%, 100% { stroke-dashoffset: 0; stroke: #6B5A5E } }
64
+ @keyframes strike2 { 0%, 36% { stroke-dashoffset: 1; stroke: #FF5252 } 39%, 42% { stroke-dashoffset: 0; stroke: #FF5252 } 46%, 100% { stroke-dashoffset: 0; stroke: #6B5A5E } }
65
+ @keyframes strike3 { 0%, 36.5% { stroke-dashoffset: 1; stroke: #FF5252 } 39.5%, 42% { stroke-dashoffset: 0; stroke: #FF5252 } 46%, 100% { stroke-dashoffset: 0; stroke: #6B5A5E } }
66
+ @keyframes strike4 { 0%, 37% { stroke-dashoffset: 1; stroke: #FF5252 } 40%, 42% { stroke-dashoffset: 0; stroke: #FF5252 } 46%, 100% { stroke-dashoffset: 0; stroke: #6B5A5E } }
67
+ @keyframes strike5 { 0%, 37.5% { stroke-dashoffset: 1; stroke: #FF5252 } 40.5%, 42% { stroke-dashoffset: 0; stroke: #FF5252 } 46%, 100% { stroke-dashoffset: 0; stroke: #6B5A5E } }
68
+ @keyframes strike6 { 0%, 38% { stroke-dashoffset: 1; stroke: #FF5252 } 41%, 42% { stroke-dashoffset: 0; stroke: #FF5252 } 46%, 100% { stroke-dashoffset: 0; stroke: #6B5A5E } }
69
+ @keyframes strike7 { 0%, 38.5% { stroke-dashoffset: 1; stroke: #FF5252 } 41.5%, 42% { stroke-dashoffset: 0; stroke: #FF5252 } 46%, 100% { stroke-dashoffset: 0; stroke: #6B5A5E } }
70
+ .drop-rect { animation-name: drop-rect; }
71
+ .drop-text { animation-name: drop-text; }
72
+ .keep { animation-name: keep; }
73
+ @keyframes drop-rect { 0%, 42% { stroke: #443438 } 46%, 100% { stroke: #2E2427 } }
74
+ @keyframes drop-text { 0%, 42% { fill: #F3EDEE } 46%, 100% { fill: #6B5A5E } }
75
+ @keyframes keep { 0%, 42% { stroke: #443438 } 46%, 100% { stroke: #FF5252 } }
76
+
77
+ /* 4. the next request goes out with six tools */
78
+ .nx-line { animation-name: nx-line; }
79
+ .nx-head { animation-name: nx-head; }
80
+ .nx-in { animation-name: nx-in; }
81
+ @keyframes nx-line { 0%, 48% { stroke-dashoffset: 1; opacity: 1 } 53%, 96% { stroke-dashoffset: 0; opacity: 1 } 100% { stroke-dashoffset: 0; opacity: 0 } }
82
+ @keyframes nx-head { 0%, 52.5% { opacity: 0 } 53%, 96% { opacity: 1 } 100% { opacity: 0 } }
83
+ @keyframes nx-in { 0%, 53% { opacity: 0; transform: translateY(8px) } 58%, 96% { opacity: 1; transform: translateY(0) } 100% { opacity: 0; transform: translateY(0) } }
84
+
85
+ @media (prefers-reduced-motion: reduce) { * { animation: none !important; } }
86
+ </style>
87
+
88
+ <rect width="1200" height="752" rx="18" fill="#141011"/>
89
+ <text x="48" y="70" font-size="34" font-weight="600" fill="#F3EDEE">Change the tools mid-run</text>
90
+
91
+ <!-- panels -->
92
+ <g fill="#21191B" stroke="#443438" stroke-width="2">
93
+ <rect x="48" y="112" width="328" height="558" rx="12"/>
94
+ <rect x="460" y="112" width="328" height="558" rx="12"/>
95
+ <rect x="872" y="112" width="280" height="254" rx="12"/>
96
+ </g>
97
+ <g font-size="20" letter-spacing="1" fill="#B9AAAE" text-anchor="middle">
98
+ <text x="212" y="148">INSTALLED TOOLS</text>
99
+ <text x="624" y="148">AGENT TOOLS</text>
100
+ <text x="1012" y="148">NEXT REQUEST</text>
101
+ </g>
102
+
103
+ <!-- installed tools: six that read, eight that write -->
104
+ <g fill="#141011" stroke="#443438" stroke-width="2">
105
+ <rect x="68" y="168" width="288" height="30" rx="7"/>
106
+ <rect x="68" y="203" width="288" height="30" rx="7"/>
107
+ <rect x="68" y="238" width="288" height="30" rx="7"/>
108
+ <rect x="68" y="273" width="288" height="30" rx="7"/>
109
+ <rect x="68" y="308" width="288" height="30" rx="7"/>
110
+ <rect x="68" y="343" width="288" height="30" rx="7"/>
111
+ <rect x="68" y="378" width="288" height="30" rx="7"/>
112
+ <rect x="68" y="413" width="288" height="30" rx="7"/>
113
+ <rect x="68" y="448" width="288" height="30" rx="7"/>
114
+ <rect x="68" y="483" width="288" height="30" rx="7"/>
115
+ <rect x="68" y="518" width="288" height="30" rx="7"/>
116
+ <rect x="68" y="553" width="288" height="30" rx="7"/>
117
+ <rect x="68" y="588" width="288" height="30" rx="7"/>
118
+ <rect x="68" y="623" width="288" height="30" rx="7"/>
119
+ </g>
120
+ <g class="mono" font-size="20" fill="#F3EDEE">
121
+ <text x="84" y="189">read</text>
122
+ <text x="84" y="224">read_state</text>
123
+ <text x="84" y="259">list_durable_jobs</text>
124
+ <text x="84" y="294">check_durable_job</text>
125
+ <text x="84" y="329">search_history</text>
126
+ <text x="84" y="364">handoff</text>
127
+ <text x="84" y="399">bash</text>
128
+ <text x="84" y="434">write</text>
129
+ <text x="84" y="469">edit</text>
130
+ <text x="84" y="504">update_state</text>
131
+ <text x="84" y="539">run_durable_job</text>
132
+ <text x="84" y="574">subagent</text>
133
+ <text x="84" y="609">start_session</text>
134
+ <text x="84" y="644">ping_on_call_engineer</text>
135
+ </g>
136
+
137
+ <!-- installed tools flow to the agent -->
138
+ <path d="M378 391H456" fill="none" stroke="#B9AAAE" stroke-width="2.5" marker-end="url(#head-muted)"/>
139
+
140
+ <!-- the switch acts on the agent's tools that write -->
141
+ <path class="an draw sw-line" pathLength="1" d="M872 516H792" fill="none" stroke="#FF5252" stroke-width="2.5"/>
142
+ <path class="an sw-head" d="M800 516H792" fill="none" stroke="#FF5252" stroke-width="2.5" marker-end="url(#head-red)"/>
143
+
144
+ <!-- the agent's tools go out with its next request -->
145
+ <path class="an draw nx-line" pathLength="1" d="M790 258H868" fill="none" stroke="#FF5252" stroke-width="2.5"/>
146
+ <path class="an nx-head" d="M860 258H868" fill="none" stroke="#FF5252" stroke-width="2.5" marker-end="url(#head-red)"/>
147
+
148
+ <g class="mono" font-size="20">
149
+ <!-- agent tools: kept -->
150
+ <g class="an f0">
151
+ <rect class="an keep" x="480" y="168" width="288" height="30" rx="7" fill="#141011" stroke="#FF5252" stroke-width="2"/>
152
+ <text x="496" y="189" fill="#F3EDEE">read</text>
153
+ </g>
154
+ <g class="an f1">
155
+ <rect class="an keep" x="480" y="203" width="288" height="30" rx="7" fill="#141011" stroke="#FF5252" stroke-width="2"/>
156
+ <text x="496" y="224" fill="#F3EDEE">read_state</text>
157
+ </g>
158
+ <g class="an f2">
159
+ <rect class="an keep" x="480" y="238" width="288" height="30" rx="7" fill="#141011" stroke="#FF5252" stroke-width="2"/>
160
+ <text x="496" y="259" fill="#F3EDEE">list_durable_jobs</text>
161
+ </g>
162
+ <g class="an f3">
163
+ <rect class="an keep" x="480" y="273" width="288" height="30" rx="7" fill="#141011" stroke="#FF5252" stroke-width="2"/>
164
+ <text x="496" y="294" fill="#F3EDEE">check_durable_job</text>
165
+ </g>
166
+ <g class="an f4">
167
+ <rect class="an keep" x="480" y="308" width="288" height="30" rx="7" fill="#141011" stroke="#FF5252" stroke-width="2"/>
168
+ <text x="496" y="329" fill="#F3EDEE">search_history</text>
169
+ </g>
170
+ <g class="an f5">
171
+ <rect class="an keep" x="480" y="343" width="288" height="30" rx="7" fill="#141011" stroke="#FF5252" stroke-width="2"/>
172
+ <text x="496" y="364" fill="#F3EDEE">handoff</text>
173
+ </g>
174
+
175
+ <!-- agent tools: removed by Read only -->
176
+ <g class="an f6">
177
+ <rect class="an drop-rect" x="480" y="378" width="288" height="30" rx="7" fill="#141011" stroke="#2E2427" stroke-width="2"/>
178
+ <text class="an drop-text" x="496" y="399" fill="#6B5A5E">bash</text>
179
+ <path class="an draw s0" pathLength="1" d="M491 393H549" fill="none" stroke="#6B5A5E" stroke-width="2"/>
180
+ </g>
181
+ <g class="an f7">
182
+ <rect class="an drop-rect" x="480" y="413" width="288" height="30" rx="7" fill="#141011" stroke="#2E2427" stroke-width="2"/>
183
+ <text class="an drop-text" x="496" y="434" fill="#6B5A5E">write</text>
184
+ <path class="an draw s1" pathLength="1" d="M491 428H561" fill="none" stroke="#6B5A5E" stroke-width="2"/>
185
+ </g>
186
+ <g class="an f8">
187
+ <rect class="an drop-rect" x="480" y="448" width="288" height="30" rx="7" fill="#141011" stroke="#2E2427" stroke-width="2"/>
188
+ <text class="an drop-text" x="496" y="469" fill="#6B5A5E">edit</text>
189
+ <path class="an draw s2" pathLength="1" d="M491 463H549" fill="none" stroke="#6B5A5E" stroke-width="2"/>
190
+ </g>
191
+ <g class="an f9">
192
+ <rect class="an drop-rect" x="480" y="483" width="288" height="30" rx="7" fill="#141011" stroke="#2E2427" stroke-width="2"/>
193
+ <text class="an drop-text" x="496" y="504" fill="#6B5A5E">update_state</text>
194
+ <path class="an draw s3" pathLength="1" d="M491 498H645" fill="none" stroke="#6B5A5E" stroke-width="2"/>
195
+ </g>
196
+ <g class="an f10">
197
+ <rect class="an drop-rect" x="480" y="518" width="288" height="30" rx="7" fill="#141011" stroke="#2E2427" stroke-width="2"/>
198
+ <text class="an drop-text" x="496" y="539" fill="#6B5A5E">run_durable_job</text>
199
+ <path class="an draw s4" pathLength="1" d="M491 533H681" fill="none" stroke="#6B5A5E" stroke-width="2"/>
200
+ </g>
201
+ <g class="an f11">
202
+ <rect class="an drop-rect" x="480" y="553" width="288" height="30" rx="7" fill="#141011" stroke="#2E2427" stroke-width="2"/>
203
+ <text class="an drop-text" x="496" y="574" fill="#6B5A5E">subagent</text>
204
+ <path class="an draw s5" pathLength="1" d="M491 568H597" fill="none" stroke="#6B5A5E" stroke-width="2"/>
205
+ </g>
206
+ <g class="an f12">
207
+ <rect class="an drop-rect" x="480" y="588" width="288" height="30" rx="7" fill="#141011" stroke="#2E2427" stroke-width="2"/>
208
+ <text class="an drop-text" x="496" y="609" fill="#6B5A5E">start_session</text>
209
+ <path class="an draw s6" pathLength="1" d="M491 603H657" fill="none" stroke="#6B5A5E" stroke-width="2"/>
210
+ </g>
211
+ <g class="an f13">
212
+ <rect class="an drop-rect" x="480" y="623" width="288" height="30" rx="7" fill="#141011" stroke="#2E2427" stroke-width="2"/>
213
+ <text class="an drop-text" x="496" y="644" fill="#6B5A5E">ping_on_call_engineer</text>
214
+ <path class="an draw s7" pathLength="1" d="M491 638H753" fill="none" stroke="#6B5A5E" stroke-width="2"/>
215
+ </g>
216
+ </g>
217
+
218
+ <!-- Read only switch -->
219
+ <rect class="an sw-pill" x="872" y="490" width="226" height="52" rx="26" fill="#21191B" stroke="#FF5252" stroke-width="2"/>
220
+ <rect class="an sw-track" x="890" y="503" width="48" height="26" rx="13" fill="#FF5252"/>
221
+ <circle class="an sw-knob" cx="925" cy="516" r="9" fill="#F3EDEE"/>
222
+ <text class="an sw-label" x="954" y="524" font-size="24" fill="#F3EDEE">Read only</text>
223
+
224
+ <!-- next request -->
225
+ <g class="an nx-in">
226
+ <use href="#g-pi" x="894" y="222" width="72" height="72"/>
227
+ <text x="982" y="266" font-size="22" fill="#B9AAAE">sees 6 tools</text>
228
+ </g>
229
+
230
+ <text x="48" y="720" font-size="22" fill="#B9AAAE">Tools, model, thinking and instructions apply from the agent's next request.</text>
231
+ </svg>