@vellumai/assistant 0.4.42 → 0.4.44

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 (867) hide show
  1. package/.env.example +1 -6
  2. package/.prettierignore +3 -0
  3. package/ARCHITECTURE.md +140 -403
  4. package/Dockerfile +0 -1
  5. package/README.md +81 -92
  6. package/bun.lock +8 -2
  7. package/docs/architecture/integrations.md +81 -104
  8. package/docs/architecture/memory.md +1 -1
  9. package/docs/architecture/scheduling.md +63 -63
  10. package/docs/architecture/security.md +3 -3
  11. package/docs/runbook-trusted-contacts.md +11 -12
  12. package/docs/trusted-contact-access.md +39 -39
  13. package/package.json +5 -8
  14. package/src/__tests__/access-request-decision.test.ts +4 -4
  15. package/src/__tests__/active-skill-tools.test.ts +49 -34
  16. package/src/__tests__/actor-token-service.test.ts +55 -85
  17. package/src/__tests__/amazon-cdp-integration.test.ts +14 -26
  18. package/src/__tests__/app-bundler.test.ts +14 -368
  19. package/src/__tests__/app-compiler.test.ts +0 -1
  20. package/src/__tests__/app-executors.test.ts +10 -1
  21. package/src/__tests__/approval-hardcoded-copy-guard.test.ts +1 -1
  22. package/src/__tests__/approval-primitive.test.ts +2 -4
  23. package/src/__tests__/approval-routes-http.test.ts +1 -3
  24. package/src/__tests__/asset-materialize-tool.test.ts +1 -4
  25. package/src/__tests__/asset-search-tool.test.ts +1 -4
  26. package/src/__tests__/assistant-attachments.test.ts +23 -0
  27. package/src/__tests__/assistant-feature-flags-integration.test.ts +4 -8
  28. package/src/__tests__/assistant-id-boundary-guard.test.ts +5 -5
  29. package/src/__tests__/attachments-store.test.ts +1 -4
  30. package/src/__tests__/avatar-e2e.test.ts +43 -23
  31. package/src/__tests__/browser-fill-credential.test.ts +1 -1
  32. package/src/__tests__/bundled-asset.test.ts +1 -1
  33. package/src/__tests__/bundled-skill-retrieval-guard.test.ts +2 -9
  34. package/src/__tests__/call-controller.test.ts +4 -8
  35. package/src/__tests__/call-conversation-messages.test.ts +1 -1
  36. package/src/__tests__/call-domain.test.ts +250 -8
  37. package/src/__tests__/call-pointer-message-composer.test.ts +14 -14
  38. package/src/__tests__/call-pointer-messages.test.ts +7 -11
  39. package/src/__tests__/call-recovery.test.ts +47 -0
  40. package/src/__tests__/call-routes-http.test.ts +13 -0
  41. package/src/__tests__/call-start-guardian-guard.test.ts +1 -1
  42. package/src/__tests__/callback-handoff-copy.test.ts +5 -5
  43. package/src/__tests__/canonical-guardian-store.test.ts +3 -3
  44. package/src/__tests__/channel-approval-routes.test.ts +101 -134
  45. package/src/__tests__/channel-approval.test.ts +0 -201
  46. package/src/__tests__/channel-approvals.test.ts +2 -2
  47. package/src/__tests__/channel-delivery-store.test.ts +16 -24
  48. package/src/__tests__/channel-guardian.test.ts +641 -740
  49. package/src/__tests__/channel-invite-transport.test.ts +1 -2
  50. package/src/__tests__/channel-policy.test.ts +9 -12
  51. package/src/__tests__/channel-readiness-service.test.ts +156 -45
  52. package/src/__tests__/channel-reply-delivery.test.ts +3 -3
  53. package/src/__tests__/channel-retry-sweep.test.ts +7 -7
  54. package/src/__tests__/checker.test.ts +41 -35
  55. package/src/__tests__/chrome-cdp.test.ts +57 -17
  56. package/src/__tests__/cli-help-reference-sync.test.ts +26 -0
  57. package/src/__tests__/compaction.benchmark.test.ts +25 -5
  58. package/src/__tests__/computer-use-session-lifecycle.test.ts +1 -1
  59. package/src/__tests__/computer-use-session-working-dir.test.ts +2 -6
  60. package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +1 -1
  61. package/src/__tests__/config-loader-backfill.test.ts +310 -0
  62. package/src/__tests__/config-watcher.test.ts +1 -5
  63. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +3 -5
  64. package/src/__tests__/connection-policy.test.ts +3 -62
  65. package/src/__tests__/contacts-tools.test.ts +0 -2
  66. package/src/__tests__/context-memory-e2e.test.ts +11 -7
  67. package/src/__tests__/context-overflow-policy.test.ts +2 -2
  68. package/src/__tests__/context-window-manager.test.ts +220 -61
  69. package/src/__tests__/conversation-attention-store.test.ts +178 -2
  70. package/src/__tests__/conversation-attention-telegram.test.ts +8 -11
  71. package/src/__tests__/conversation-pairing.test.ts +14 -14
  72. package/src/__tests__/conversation-routes-guardian-reply.test.ts +7 -7
  73. package/src/__tests__/conversation-store.test.ts +2 -2
  74. package/src/__tests__/conversation-unread-route.test.ts +155 -0
  75. package/src/__tests__/credential-metadata-store.test.ts +0 -2
  76. package/src/__tests__/credential-security-invariants.test.ts +10 -16
  77. package/src/__tests__/credentials-cli.test.ts +49 -5
  78. package/src/__tests__/daemon-assistant-events.test.ts +4 -22
  79. package/src/__tests__/db-migration-rollback.test.ts +2 -2
  80. package/src/__tests__/deterministic-verification-control-plane.test.ts +19 -19
  81. package/src/__tests__/dictation-mode-detection.test.ts +1 -1
  82. package/src/__tests__/dynamic-page-surface.test.ts +2 -2
  83. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -6
  84. package/src/__tests__/email-cli.test.ts +12 -12
  85. package/src/__tests__/email-service-config-fallback.test.ts +1 -1
  86. package/src/__tests__/emit-signal-routing-intent.test.ts +3 -18
  87. package/src/__tests__/error-handler-friendly-messages.test.ts +46 -0
  88. package/src/__tests__/event-bus.test.ts +0 -1
  89. package/src/__tests__/followup-tools.test.ts +0 -2
  90. package/src/__tests__/gateway-client-managed-outbound.test.ts +6 -6
  91. package/src/__tests__/gateway-only-enforcement.test.ts +13 -77
  92. package/src/__tests__/gateway-only-guard.test.ts +5 -0
  93. package/src/__tests__/guardian-action-conversation-turn.test.ts +3 -3
  94. package/src/__tests__/guardian-action-followup-executor.test.ts +29 -94
  95. package/src/__tests__/guardian-action-followup-store.test.ts +2 -12
  96. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +48 -194
  97. package/src/__tests__/guardian-action-late-reply.test.ts +12 -12
  98. package/src/__tests__/guardian-action-store.test.ts +2 -2
  99. package/src/__tests__/guardian-action-sweep.test.ts +5 -5
  100. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +1 -3
  101. package/src/__tests__/guardian-dispatch.test.ts +5 -46
  102. package/src/__tests__/guardian-grant-minting.test.ts +5 -44
  103. package/src/__tests__/guardian-outbound-http.test.ts +95 -114
  104. package/src/__tests__/guardian-question-mode.test.ts +1 -4
  105. package/src/__tests__/guardian-routing-invariants.test.ts +5 -13
  106. package/src/__tests__/guardian-routing-state.test.ts +3 -3
  107. package/src/__tests__/guardian-verification-voice-binding.test.ts +64 -7
  108. package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +2 -2
  109. package/src/__tests__/handle-user-message-secret-resume.test.ts +3 -5
  110. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +16 -34
  111. package/src/__tests__/headless-browser-interactions.test.ts +1 -1
  112. package/src/__tests__/headless-browser-navigate.test.ts +1 -1
  113. package/src/__tests__/headless-browser-read-tools.test.ts +1 -1
  114. package/src/__tests__/headless-browser-snapshot.test.ts +1 -1
  115. package/src/__tests__/heartbeat-service.test.ts +1 -1
  116. package/src/__tests__/host-shell-tool.test.ts +3 -12
  117. package/src/__tests__/inbound-invite-redemption.test.ts +2 -2
  118. package/src/__tests__/ingress-url-consistency.test.ts +0 -64
  119. package/src/__tests__/integration-status.test.ts +8 -8
  120. package/src/__tests__/intent-routing.test.ts +9 -13
  121. package/src/__tests__/invite-redemption-service.test.ts +4 -4
  122. package/src/__tests__/invite-routes-http.test.ts +10 -10
  123. package/src/__tests__/llm-usage-store.test.ts +45 -9
  124. package/src/__tests__/local-gateway-health.test.ts +209 -0
  125. package/src/__tests__/managed-avatar-client.test.ts +23 -12
  126. package/src/__tests__/managed-skill-lifecycle.test.ts +1 -2
  127. package/src/__tests__/managed-store.test.ts +29 -12
  128. package/src/__tests__/managed-twitter-guardrails.test.ts +357 -0
  129. package/src/__tests__/mcp-cli.test.ts +1 -1
  130. package/src/__tests__/mcp-health-check.test.ts +1 -1
  131. package/src/__tests__/media-generate-image.test.ts +1 -1
  132. package/src/__tests__/media-reuse-story.e2e.test.ts +1 -4
  133. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +9 -6
  134. package/src/__tests__/memory-regressions.test.ts +1 -166
  135. package/src/__tests__/messaging-send-tool.test.ts +8 -4
  136. package/src/__tests__/migration-export-http.test.ts +2 -2
  137. package/src/__tests__/migration-transport.test.ts +44 -0
  138. package/src/__tests__/non-member-access-request.test.ts +49 -36
  139. package/src/__tests__/notification-broadcaster.test.ts +15 -15
  140. package/src/__tests__/notification-decision-fallback.test.ts +2 -2
  141. package/src/__tests__/notification-decision-strategy.test.ts +4 -4
  142. package/src/__tests__/notification-deep-link.test.ts +3 -3
  143. package/src/__tests__/notification-guardian-path.test.ts +6 -44
  144. package/src/__tests__/notification-routing-intent.test.ts +11 -7
  145. package/src/__tests__/oauth-cli.test.ts +1 -1
  146. package/src/__tests__/onboarding-starter-tasks.test.ts +2 -6
  147. package/src/__tests__/onboarding-template-contract.test.ts +2 -12
  148. package/src/__tests__/platform.test.ts +168 -5
  149. package/src/__tests__/playbook-execution.test.ts +0 -2
  150. package/src/__tests__/playbook-tools.test.ts +0 -2
  151. package/src/__tests__/pricing.test.ts +125 -0
  152. package/src/__tests__/provider-error-scenarios.test.ts +9 -3
  153. package/src/__tests__/provider-fail-open-selection.test.ts +12 -2
  154. package/src/__tests__/recording-handler.test.ts +46 -80
  155. package/src/__tests__/recording-state-machine.test.ts +112 -183
  156. package/src/__tests__/registry.test.ts +1 -1
  157. package/src/__tests__/relay-server.test.ts +69 -71
  158. package/src/__tests__/reminder-store.test.ts +3 -3
  159. package/src/__tests__/request-file-tool.test.ts +2 -2
  160. package/src/__tests__/ride-shotgun-handler.test.ts +2 -33
  161. package/src/__tests__/runtime-attachment-metadata.test.ts +3 -3
  162. package/src/__tests__/runtime-events-sse-parity.test.ts +1 -1
  163. package/src/__tests__/scaffold-managed-skill-tool.test.ts +4 -4
  164. package/src/__tests__/schedule-store.test.ts +13 -4
  165. package/src/__tests__/schedule-tools.test.ts +0 -2
  166. package/src/__tests__/scheduler-recurrence.test.ts +3 -4
  167. package/src/__tests__/scoped-approval-grants.test.ts +3 -5
  168. package/src/__tests__/scoped-grant-security-matrix.test.ts +6 -8
  169. package/src/__tests__/secret-prompt-log-hygiene.test.ts +1 -1
  170. package/src/__tests__/secret-response-routing.test.ts +1 -1
  171. package/src/__tests__/send-endpoint-busy.test.ts +1 -4
  172. package/src/__tests__/sequence-store.test.ts +0 -2
  173. package/src/__tests__/server-history-render.test.ts +2 -199
  174. package/src/__tests__/session-abort-tool-results.test.ts +9 -3
  175. package/src/__tests__/session-agent-loop.test.ts +107 -3
  176. package/src/__tests__/session-confirmation-signals.test.ts +17 -49
  177. package/src/__tests__/session-conflict-gate.test.ts +9 -3
  178. package/src/__tests__/session-init.benchmark.test.ts +22 -13
  179. package/src/__tests__/session-load-history-repair.test.ts +6 -3
  180. package/src/__tests__/session-pre-run-repair.test.ts +9 -3
  181. package/src/__tests__/session-profile-injection.test.ts +9 -3
  182. package/src/__tests__/session-provider-retry-repair.test.ts +10 -4
  183. package/src/__tests__/session-queue.test.ts +10 -4
  184. package/src/__tests__/session-runtime-assembly.test.ts +28 -18
  185. package/src/__tests__/session-skill-tools.test.ts +2 -3
  186. package/src/__tests__/session-slash-known.test.ts +11 -4
  187. package/src/__tests__/session-slash-queue.test.ts +11 -4
  188. package/src/__tests__/session-slash-unknown.test.ts +12 -4
  189. package/src/__tests__/session-surfaces-deselection.test.ts +2 -2
  190. package/src/__tests__/session-surfaces-task-progress.test.ts +3 -3
  191. package/src/__tests__/session-tool-setup-app-refresh.test.ts +1 -1
  192. package/src/__tests__/session-tool-setup-memory-scope.test.ts +1 -1
  193. package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +1 -1
  194. package/src/__tests__/session-usage.test.ts +180 -0
  195. package/src/__tests__/session-workspace-cache-state.test.ts +8 -2
  196. package/src/__tests__/session-workspace-injection.test.ts +8 -2
  197. package/src/__tests__/session-workspace-tool-tracking.test.ts +8 -2
  198. package/src/__tests__/skill-feature-flags-integration.test.ts +5 -11
  199. package/src/__tests__/skill-feature-flags.test.ts +1 -0
  200. package/src/__tests__/skill-include-graph.test.ts +1 -0
  201. package/src/__tests__/skill-load-feature-flag.test.ts +3 -9
  202. package/src/__tests__/skill-load-tool.test.ts +90 -12
  203. package/src/__tests__/skill-projection-feature-flag.test.ts +14 -15
  204. package/src/__tests__/skills-uninstall.test.ts +131 -0
  205. package/src/__tests__/skills.test.ts +32 -16
  206. package/src/__tests__/slack-block-formatting.test.ts +1 -1
  207. package/src/__tests__/slack-channel-config.test.ts +71 -12
  208. package/src/__tests__/slack-inbound-verification.test.ts +7 -7
  209. package/src/__tests__/slack-share-routes.test.ts +1 -1
  210. package/src/__tests__/slack-skill.test.ts +2 -2
  211. package/src/__tests__/slash-commands-catalog.test.ts +1 -0
  212. package/src/__tests__/slash-commands-resolver.test.ts +1 -0
  213. package/src/__tests__/starter-task-flow.test.ts +10 -20
  214. package/src/__tests__/subagent-manager-notify.test.ts +1 -1
  215. package/src/__tests__/subagent-tools.test.ts +2 -2
  216. package/src/__tests__/system-prompt.test.ts +7 -12
  217. package/src/__tests__/task-compiler.test.ts +0 -2
  218. package/src/__tests__/task-management-tools.test.ts +0 -2
  219. package/src/__tests__/task-runner.test.ts +0 -2
  220. package/src/__tests__/task-scheduler.test.ts +2 -2
  221. package/src/__tests__/telegram-bot-username-resolution.test.ts +46 -44
  222. package/src/__tests__/terminal-tools.test.ts +1 -11
  223. package/src/__tests__/thread-seed-composer.test.ts +3 -1
  224. package/src/__tests__/tool-approval-handler.test.ts +5 -7
  225. package/src/__tests__/tool-executor.test.ts +2 -2
  226. package/src/__tests__/tool-grant-request-escalation.test.ts +3 -5
  227. package/src/__tests__/tool-notification-listener.test.ts +1 -1
  228. package/src/__tests__/tool-profiling-listener.test.ts +1 -1
  229. package/src/__tests__/tool-trace-listener.test.ts +1 -2
  230. package/src/__tests__/trace-emitter.test.ts +1 -1
  231. package/src/__tests__/trust-context-guards.test.ts +1 -1
  232. package/src/__tests__/trust-store.test.ts +48 -399
  233. package/src/__tests__/trusted-contact-approval-notifier.test.ts +6 -8
  234. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +5 -7
  235. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +6 -6
  236. package/src/__tests__/trusted-contact-multichannel.test.ts +54 -47
  237. package/src/__tests__/trusted-contact-verification.test.ts +12 -12
  238. package/src/__tests__/twilio-config.test.ts +11 -2
  239. package/src/__tests__/twilio-provider.test.ts +6 -4
  240. package/src/__tests__/twilio-routes.test.ts +408 -86
  241. package/src/__tests__/twitter-platform-proxy-client.test.ts +475 -0
  242. package/src/__tests__/update-bulletin-format.test.ts +1 -1
  243. package/src/__tests__/update-bulletin-state.test.ts +1 -1
  244. package/src/__tests__/update-bulletin.test.ts +4 -8
  245. package/src/__tests__/update-template-contract.test.ts +1 -1
  246. package/src/__tests__/usage-cache-backfill-migration.test.ts +406 -0
  247. package/src/__tests__/usage-routes.test.ts +23 -5
  248. package/src/__tests__/user-reference.test.ts +1 -1
  249. package/src/__tests__/{guardian-control-plane-policy.test.ts → verification-control-plane-policy.test.ts} +142 -170
  250. package/src/__tests__/{guardian-verification-intent-routing.test.ts → verification-session-intent-routing.test.ts} +16 -16
  251. package/src/__tests__/view-image-tool.test.ts +0 -2
  252. package/src/__tests__/voice-ingress-preflight.test.ts +36 -0
  253. package/src/__tests__/voice-invite-redemption.test.ts +18 -18
  254. package/src/__tests__/voice-scoped-grant-consumer.test.ts +7 -7
  255. package/src/__tests__/voice-session-bridge.test.ts +14 -16
  256. package/src/__tests__/workspace-policy.test.ts +1 -1
  257. package/src/approvals/AGENTS.md +4 -4
  258. package/src/approvals/approval-primitive.ts +2 -2
  259. package/src/approvals/guardian-decision-primitive.ts +1 -1
  260. package/src/approvals/guardian-request-resolvers.ts +3 -4
  261. package/src/bundler/app-bundler.ts +29 -217
  262. package/src/calls/active-call-lease.ts +207 -0
  263. package/src/calls/call-constants.ts +0 -7
  264. package/src/calls/call-controller.ts +1 -1
  265. package/src/calls/call-conversation-messages.ts +6 -6
  266. package/src/calls/call-domain.ts +73 -38
  267. package/src/calls/call-pointer-message-composer.ts +6 -6
  268. package/src/calls/call-pointer-messages.ts +14 -13
  269. package/src/calls/call-recovery.ts +2 -0
  270. package/src/calls/call-store.ts +21 -28
  271. package/src/calls/guardian-action-sweep.ts +6 -8
  272. package/src/calls/guardian-dispatch.ts +2 -6
  273. package/src/calls/relay-access-wait.ts +4 -4
  274. package/src/calls/relay-server.ts +69 -80
  275. package/src/calls/relay-setup-router.ts +16 -21
  276. package/src/calls/relay-verification.ts +27 -28
  277. package/src/calls/twilio-config.ts +28 -3
  278. package/src/calls/twilio-provider.ts +5 -5
  279. package/src/calls/twilio-rest.ts +26 -27
  280. package/src/calls/twilio-routes.ts +67 -54
  281. package/src/calls/types.ts +8 -8
  282. package/src/calls/voice-ingress-preflight.ts +110 -0
  283. package/src/calls/voice-session-bridge.ts +7 -7
  284. package/src/channels/config.ts +1 -10
  285. package/src/{config/channel-permission-profiles.ts → channels/permission-profiles.ts} +1 -1
  286. package/src/channels/types.ts +2 -13
  287. package/src/cli/__tests__/notifications.test.ts +1 -1
  288. package/src/{amazon → cli/commands/amazon}/client.ts +99 -42
  289. package/src/cli/{amazon.ts → commands/amazon/index.ts} +14 -54
  290. package/src/{amazon → cli/commands/amazon}/request-extractor.ts +39 -3
  291. package/src/cli/commands/amazon/session.ts +108 -0
  292. package/src/cli/{audit.ts → commands/audit.ts} +2 -4
  293. package/src/cli/{autonomy.ts → commands/autonomy.ts} +1 -3
  294. package/src/cli/commands/browser-relay.ts +520 -0
  295. package/src/cli/commands/channel-verification-sessions.ts +442 -0
  296. package/src/cli/{completions.ts → commands/completions.ts} +1 -3
  297. package/src/cli/{config.ts → commands/config.ts} +3 -5
  298. package/src/cli/{contacts.ts → commands/contacts.ts} +15 -17
  299. package/src/cli/{credentials.ts → commands/credentials.ts} +9 -10
  300. package/src/cli/{default-action.ts → commands/default-action.ts} +3 -3
  301. package/src/cli/{dev.ts → commands/dev.ts} +4 -6
  302. package/src/cli/{doctor.ts → commands/doctor.ts} +36 -60
  303. package/src/cli/{email.ts → commands/email.ts} +2 -2
  304. package/src/cli/{keys.ts → commands/keys.ts} +6 -6
  305. package/src/cli/{map.ts → commands/map.ts} +85 -93
  306. package/src/cli/{mcp.ts → commands/mcp.ts} +5 -7
  307. package/src/cli/{memory.ts → commands/memory.ts} +6 -7
  308. package/src/cli/{notifications.ts → commands/notifications.ts} +8 -10
  309. package/src/cli/{oauth.ts → commands/oauth.ts} +2 -2
  310. package/src/cli/commands/platform.ts +176 -0
  311. package/src/cli/{sequence.ts → commands/sequence.ts} +3 -3
  312. package/src/cli/{sessions.ts → commands/sessions.ts} +32 -52
  313. package/src/cli/commands/skills.ts +498 -0
  314. package/src/cli/{trust.ts → commands/trust.ts} +2 -4
  315. package/src/cli/commands/twitter/__tests__/cli-read-routing.test.ts +345 -0
  316. package/src/cli/commands/twitter/__tests__/cli-routing.test.ts +252 -0
  317. package/src/{__tests__/twitter-oauth-client.test.ts → cli/commands/twitter/__tests__/oauth-client.test.ts} +2 -48
  318. package/src/cli/commands/twitter/index.ts +420 -0
  319. package/src/{twitter → cli/commands/twitter}/oauth-client.ts +1 -35
  320. package/src/cli/commands/twitter/router.ts +351 -0
  321. package/src/cli/commands/twitter/types.ts +30 -0
  322. package/src/cli/db.ts +1 -0
  323. package/src/cli/http-client.ts +87 -0
  324. package/src/cli/logger.ts +6 -0
  325. package/src/cli/main-screen.tsx +4 -3
  326. package/src/cli/output.ts +19 -0
  327. package/src/cli/program.ts +29 -27
  328. package/src/cli/reference.ts +27 -37
  329. package/src/cli.ts +452 -240
  330. package/src/config/assistant-feature-flags.ts +3 -15
  331. package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +3 -6
  332. package/src/config/bundled-skills/agentmail/SKILL.md +4 -4
  333. package/src/config/bundled-skills/amazon/SKILL.md +15 -6
  334. package/src/config/bundled-skills/api-mapping/SKILL.md +4 -4
  335. package/src/config/bundled-skills/app-builder/SKILL.md +4 -9
  336. package/src/config/bundled-skills/app-builder/TOOLS.json +0 -4
  337. package/src/config/bundled-skills/browser/SKILL.md +4 -5
  338. package/src/config/bundled-skills/chatgpt-import/SKILL.md +4 -4
  339. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +1 -1
  340. package/src/config/bundled-skills/claude-code/SKILL.md +4 -4
  341. package/src/config/bundled-skills/cli-discover/SKILL.md +4 -4
  342. package/src/config/bundled-skills/computer-use/SKILL.md +4 -4
  343. package/src/config/bundled-skills/contacts/SKILL.md +23 -77
  344. package/src/config/bundled-skills/deploy-fullstack-vercel/SKILL.md +4 -4
  345. package/src/config/bundled-skills/document/SKILL.md +4 -3
  346. package/src/config/bundled-skills/document-writer/SKILL.md +4 -4
  347. package/src/config/bundled-skills/doordash/SKILL.md +4 -12
  348. package/src/config/bundled-skills/doordash/__tests__/doordash-session.test.ts +1 -90
  349. package/src/config/bundled-skills/doordash/doordash-cli.ts +132 -109
  350. package/src/config/bundled-skills/doordash/lib/session.ts +22 -19
  351. package/src/config/bundled-skills/doordash/lib/shared/platform.ts +26 -9
  352. package/src/config/bundled-skills/elevenlabs-voice/SKILL.md +140 -0
  353. package/src/config/bundled-skills/email-setup/SKILL.md +4 -4
  354. package/src/config/bundled-skills/followups/SKILL.md +4 -3
  355. package/src/config/bundled-skills/frontend-design/SKILL.md +2 -0
  356. package/src/config/bundled-skills/google-calendar/SKILL.md +4 -4
  357. package/src/config/bundled-skills/google-oauth-setup/SKILL.md +4 -6
  358. package/src/config/bundled-skills/guardian-verify-setup/SKILL.md +26 -41
  359. package/src/config/bundled-skills/image-studio/SKILL.md +4 -5
  360. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +1 -1
  361. package/src/config/bundled-skills/influencer/SKILL.md +19 -19
  362. package/src/{influencer → config/bundled-skills/influencer/scripts}/client.ts +73 -56
  363. package/src/config/bundled-skills/influencer/scripts/influencer.ts +267 -0
  364. package/src/config/bundled-skills/knowledge-graph/SKILL.md +4 -2
  365. package/src/config/bundled-skills/macos-automation/SKILL.md +4 -5
  366. package/src/config/bundled-skills/mcp-setup/SKILL.md +4 -4
  367. package/src/config/bundled-skills/media-processing/SKILL.md +3 -2
  368. package/src/config/bundled-skills/messaging/SKILL.md +6 -33
  369. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -5
  370. package/src/config/bundled-skills/notifications/SKILL.md +4 -4
  371. package/src/config/bundled-skills/notion/SKILL.md +4 -4
  372. package/src/config/bundled-skills/notion-oauth-setup/SKILL.md +4 -5
  373. package/src/config/bundled-skills/oauth-setup/SKILL.md +4 -5
  374. package/src/config/bundled-skills/phone-calls/SKILL.md +24 -458
  375. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +83 -0
  376. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +57 -0
  377. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +67 -0
  378. package/src/config/bundled-skills/playbooks/SKILL.md +4 -3
  379. package/src/config/bundled-skills/public-ingress/SKILL.md +65 -14
  380. package/src/config/bundled-skills/reminder/SKILL.md +4 -3
  381. package/src/config/bundled-skills/restaurant-reservation/SKILL.md +4 -6
  382. package/src/config/bundled-skills/schedule/SKILL.md +4 -3
  383. package/src/config/bundled-skills/screen-recording/SKILL.md +4 -3
  384. package/src/config/bundled-skills/self-upgrade/SKILL.md +4 -4
  385. package/src/config/bundled-skills/skills-catalog/SKILL.md +4 -4
  386. package/src/config/bundled-skills/slack/SKILL.md +4 -8
  387. package/src/config/bundled-skills/slack/tools/slack-channel-permissions.ts +1 -1
  388. package/src/config/bundled-skills/slack-app-setup/SKILL.md +66 -88
  389. package/src/config/bundled-skills/slack-digest-setup/SKILL.md +4 -5
  390. package/src/config/bundled-skills/slack-oauth-setup/SKILL.md +4 -5
  391. package/src/config/bundled-skills/start-the-day/SKILL.md +4 -4
  392. package/src/config/bundled-skills/subagent/SKILL.md +4 -3
  393. package/src/config/bundled-skills/tasks/SKILL.md +4 -3
  394. package/src/config/bundled-skills/telegram-setup/SKILL.md +63 -112
  395. package/src/config/bundled-skills/time-based-actions/SKILL.md +4 -3
  396. package/src/config/bundled-skills/transcribe/SKILL.md +4 -3
  397. package/src/config/bundled-skills/twilio-setup/SKILL.md +23 -50
  398. package/src/config/bundled-skills/twitter/SKILL.md +73 -144
  399. package/src/config/bundled-skills/typescript-eval/SKILL.md +4 -4
  400. package/src/config/bundled-skills/vercel-token-setup/SKILL.md +4 -5
  401. package/src/config/bundled-skills/voice-setup/SKILL.md +19 -45
  402. package/src/config/bundled-skills/watcher/SKILL.md +4 -3
  403. package/src/config/env-registry.ts +1 -10
  404. package/src/config/feature-flag-registry.json +8 -16
  405. package/src/config/loader.ts +78 -38
  406. package/src/config/schema.ts +143 -106
  407. package/src/config/schemas/channels.ts +80 -0
  408. package/src/config/schemas/heartbeat.ts +51 -0
  409. package/src/config/schemas/inference.ts +136 -0
  410. package/src/config/schemas/ingress.ts +81 -0
  411. package/src/config/schemas/logging.ts +21 -0
  412. package/src/config/schemas/memory-lifecycle.ts +67 -0
  413. package/src/config/schemas/memory-processing.ts +215 -0
  414. package/src/config/schemas/memory-retrieval.ts +222 -0
  415. package/src/config/schemas/memory-storage.ts +83 -0
  416. package/src/config/schemas/memory.ts +58 -0
  417. package/src/config/schemas/platform.ts +64 -0
  418. package/src/config/schemas/security.ts +54 -0
  419. package/src/config/schemas/swarm.ts +50 -0
  420. package/src/config/schemas/timeouts.ts +47 -0
  421. package/src/config/{agent-schema.ts → schemas/workspace-git.ts} +0 -97
  422. package/src/config/skill-state.ts +3 -13
  423. package/src/config/skills.ts +196 -75
  424. package/src/config/types.ts +1 -20
  425. package/src/contacts/contact-store.ts +12 -49
  426. package/src/contacts/contacts-write.ts +1 -5
  427. package/src/contacts/index.ts +0 -2
  428. package/src/contacts/types.ts +0 -8
  429. package/src/context/window-manager.ts +73 -14
  430. package/src/daemon/assistant-attachments.ts +9 -0
  431. package/src/daemon/computer-use-session.ts +3 -3
  432. package/src/daemon/connection-policy.ts +6 -21
  433. package/src/daemon/context-overflow-policy.ts +1 -1
  434. package/src/daemon/daemon-control.ts +46 -54
  435. package/src/daemon/doordash-steps.ts +1 -1
  436. package/src/daemon/handlers/config-channels.ts +407 -71
  437. package/src/daemon/handlers/config-ingress.ts +17 -85
  438. package/src/daemon/handlers/config-model.ts +145 -123
  439. package/src/daemon/handlers/config-slack-channel.ts +43 -29
  440. package/src/daemon/handlers/config-telegram.ts +32 -27
  441. package/src/daemon/handlers/config-voice.ts +1 -4
  442. package/src/daemon/handlers/dictation.ts +11 -16
  443. package/src/daemon/handlers/identity.ts +5 -6
  444. package/src/daemon/handlers/pairing.ts +5 -13
  445. package/src/daemon/handlers/recording.ts +97 -199
  446. package/src/daemon/handlers/session-history.ts +151 -105
  447. package/src/daemon/handlers/session-user-message.ts +29 -57
  448. package/src/daemon/handlers/sessions.ts +240 -137
  449. package/src/daemon/handlers/shared.ts +62 -95
  450. package/src/daemon/handlers/skills.ts +492 -543
  451. package/src/daemon/lifecycle.ts +155 -55
  452. package/src/daemon/{ipc-contract.ts → message-protocol.ts} +49 -49
  453. package/src/daemon/{ipc-contract → message-types}/apps.ts +0 -25
  454. package/src/daemon/{ipc-contract → message-types}/computer-use.ts +0 -3
  455. package/src/daemon/{ipc-contract → message-types}/diagnostics.ts +0 -16
  456. package/src/daemon/{ipc-contract → message-types}/integrations.ts +30 -20
  457. package/src/daemon/{ipc-contract → message-types}/memory.ts +8 -0
  458. package/src/daemon/{ipc-contract → message-types}/notifications.ts +15 -1
  459. package/src/daemon/{ipc-contract → message-types}/sessions.ts +7 -1
  460. package/src/daemon/{ipc-contract → message-types}/shared.ts +0 -8
  461. package/src/daemon/{ipc-contract → message-types}/surfaces.ts +2 -0
  462. package/src/daemon/{ipc-contract → message-types}/workspace.ts +2 -2
  463. package/src/daemon/providers-setup.ts +0 -5
  464. package/src/daemon/recording-executor.ts +0 -7
  465. package/src/daemon/ride-shotgun-handler.ts +42 -14
  466. package/src/daemon/seed-files.ts +3 -27
  467. package/src/daemon/server.ts +134 -524
  468. package/src/daemon/session-agent-loop-handlers.ts +46 -9
  469. package/src/daemon/session-agent-loop.ts +86 -24
  470. package/src/daemon/session-attachments.ts +1 -1
  471. package/src/daemon/session-error.ts +1 -1
  472. package/src/daemon/session-history.ts +20 -15
  473. package/src/daemon/session-lifecycle.ts +9 -7
  474. package/src/daemon/session-memory.ts +15 -1
  475. package/src/daemon/session-messaging.ts +10 -6
  476. package/src/daemon/session-notifiers.ts +10 -8
  477. package/src/daemon/session-process.ts +34 -25
  478. package/src/daemon/session-queue-manager.ts +1 -1
  479. package/src/daemon/session-runtime-assembly.ts +6 -32
  480. package/src/daemon/session-surfaces.ts +187 -35
  481. package/src/daemon/session-tool-setup.ts +1 -1
  482. package/src/daemon/session-usage.ts +119 -18
  483. package/src/daemon/session.ts +11 -33
  484. package/src/daemon/tool-side-effects.ts +6 -5
  485. package/src/daemon/trace-emitter.ts +1 -1
  486. package/src/daemon/{guardian-verification-intent.ts → verification-session-intent.ts} +16 -16
  487. package/src/daemon/watch-handler.ts +2 -5
  488. package/src/email/service.ts +8 -8
  489. package/src/events/domain-events.ts +0 -1
  490. package/src/events/tool-notification-listener.ts +1 -1
  491. package/src/followups/followup-store.ts +1 -2
  492. package/src/followups/types.ts +0 -6
  493. package/src/heartbeat/heartbeat-service.ts +1 -1
  494. package/src/inbound/platform-callback-registration.ts +1 -1
  495. package/src/inbound/public-ingress-urls.ts +0 -8
  496. package/src/index.ts +12 -0
  497. package/src/mcp/client.ts +1 -1
  498. package/src/mcp/manager.ts +1 -1
  499. package/src/memory/app-store.ts +1 -60
  500. package/src/memory/{guardian-verification.ts → channel-verification-sessions.ts} +110 -93
  501. package/src/memory/conversation-attention-store.ts +154 -0
  502. package/src/memory/conversation-bootstrap.ts +1 -1
  503. package/src/memory/conversation-crud.ts +53 -1
  504. package/src/memory/conversation-display-order-migration.ts +2 -3
  505. package/src/memory/conversation-queries.ts +1 -29
  506. package/src/memory/conversation-title-service.ts +26 -21
  507. package/src/memory/db-connection.ts +1 -8
  508. package/src/memory/db-init.ts +20 -0
  509. package/src/memory/delivery-crud.ts +4 -34
  510. package/src/memory/external-conversation-store.ts +1 -1
  511. package/src/memory/format-recall.ts +47 -0
  512. package/src/memory/guardian-action-store.ts +4 -5
  513. package/src/memory/guardian-rate-limits.ts +0 -3
  514. package/src/memory/invite-store.ts +1 -1
  515. package/src/memory/job-handlers/backfill.ts +9 -2
  516. package/src/memory/job-handlers/extraction.ts +2 -7
  517. package/src/memory/job-handlers/summarization.ts +1 -1
  518. package/src/memory/llm-usage-store.ts +11 -0
  519. package/src/memory/migrations/114-notifications.ts +12 -40
  520. package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +357 -0
  521. package/src/memory/migrations/141-rename-verification-table.ts +55 -0
  522. package/src/memory/migrations/142-rename-verification-session-id-column.ts +32 -0
  523. package/src/memory/migrations/143-rename-guardian-verification-values.ts +48 -0
  524. package/src/memory/migrations/144-rename-voice-to-phone.ts +147 -0
  525. package/src/memory/migrations/index.ts +5 -0
  526. package/src/memory/migrations/registry.ts +30 -0
  527. package/src/memory/qdrant-circuit-breaker.ts +5 -0
  528. package/src/memory/retriever.test.ts +707 -0
  529. package/src/memory/retriever.ts +120 -116
  530. package/src/memory/schema/calls.ts +3 -7
  531. package/src/memory/schema/guardian.ts +2 -2
  532. package/src/memory/schema/infrastructure.ts +0 -8
  533. package/src/memory/search/lexical.ts +4 -1
  534. package/src/memory/search/query-expansion.test.ts +70 -0
  535. package/src/memory/search/query-expansion.ts +118 -0
  536. package/src/memory/search/types.ts +18 -17
  537. package/src/messaging/providers/telegram-bot/adapter.ts +1 -1
  538. package/src/messaging/providers/whatsapp/adapter.ts +1 -4
  539. package/src/messaging/registry.ts +0 -1
  540. package/src/notifications/README.md +13 -22
  541. package/src/notifications/adapters/macos.ts +1 -1
  542. package/src/notifications/conversation-pairing.ts +2 -2
  543. package/src/notifications/copy-composer.ts +2 -2
  544. package/src/notifications/decision-engine.ts +1 -10
  545. package/src/notifications/destination-resolver.ts +2 -3
  546. package/src/notifications/emit-signal.ts +2 -8
  547. package/src/notifications/guardian-question-mode.ts +5 -8
  548. package/src/notifications/signal.ts +1 -2
  549. package/src/notifications/types.ts +1 -1
  550. package/src/oauth/token-persistence.ts +25 -1
  551. package/src/permissions/checker.ts +4 -29
  552. package/src/permissions/defaults.ts +9 -9
  553. package/src/permissions/prompter.ts +1 -1
  554. package/src/permissions/secret-prompter.ts +1 -1
  555. package/src/permissions/shell-identity.ts +1 -1
  556. package/src/permissions/trust-store.ts +13 -76
  557. package/src/permissions/workspace-policy.ts +1 -1
  558. package/src/{config → prompts}/computer-use-prompt.ts +1 -1
  559. package/src/{config → prompts}/system-prompt.ts +44 -26
  560. package/src/{config → prompts}/templates/BOOTSTRAP.md +0 -3
  561. package/src/providers/registry.ts +2 -4
  562. package/src/runtime/AGENTS.md +6 -8
  563. package/src/runtime/access-request-helper.ts +36 -55
  564. package/src/runtime/actor-trust-resolver.ts +1 -24
  565. package/src/runtime/approval-message-composer.ts +6 -2
  566. package/src/runtime/assistant-event.ts +1 -1
  567. package/src/runtime/auth/__tests__/guard-tests.test.ts +1 -0
  568. package/src/runtime/auth/__tests__/ipc-auth-context.test.ts +1 -1
  569. package/src/runtime/auth/__tests__/scopes.test.ts +2 -1
  570. package/src/runtime/auth/__tests__/subject.test.ts +32 -0
  571. package/src/runtime/auth/route-policy.ts +137 -25
  572. package/src/runtime/auth/scopes.ts +1 -0
  573. package/src/runtime/auth/subject.ts +9 -0
  574. package/src/runtime/auth/token-service.ts +12 -1
  575. package/src/runtime/auth/types.ts +1 -1
  576. package/src/runtime/channel-approval-types.ts +1 -1
  577. package/src/runtime/channel-approvals.ts +1 -1
  578. package/src/runtime/channel-invite-transport.ts +0 -2
  579. package/src/runtime/channel-invite-transports/slack.ts +5 -19
  580. package/src/runtime/channel-invite-transports/telegram.ts +17 -34
  581. package/src/runtime/channel-invite-transports/voice.ts +1 -1
  582. package/src/runtime/channel-readiness-service.ts +24 -159
  583. package/src/runtime/channel-readiness-types.ts +5 -1
  584. package/src/runtime/channel-reply-delivery.ts +43 -3
  585. package/src/runtime/channel-retry-sweep.ts +14 -22
  586. package/src/runtime/{channel-guardian-service.ts → channel-verification-service.ts} +50 -53
  587. package/src/runtime/confirmation-request-guardian-bridge.ts +2 -3
  588. package/src/runtime/gateway-client.ts +12 -15
  589. package/src/runtime/guardian-action-followup-executor.ts +8 -73
  590. package/src/runtime/guardian-action-grant-minter.ts +45 -61
  591. package/src/runtime/guardian-action-message-composer.ts +4 -4
  592. package/src/runtime/guardian-reply-router.ts +3 -3
  593. package/src/runtime/http-server.ts +133 -24
  594. package/src/runtime/http-types.ts +44 -1
  595. package/src/runtime/invite-instruction-generator.ts +1 -3
  596. package/src/runtime/invite-redemption-service.ts +5 -5
  597. package/src/runtime/invite-service.ts +7 -7
  598. package/src/runtime/local-actor-identity.ts +28 -2
  599. package/src/runtime/local-gateway-health.ts +275 -0
  600. package/src/runtime/middleware/error-handler.ts +14 -1
  601. package/src/runtime/middleware/twilio-validation.ts +3 -3
  602. package/src/runtime/migrations/migration-transport.ts +18 -3
  603. package/src/runtime/migrations/rebind-secrets-screen.ts +2 -2
  604. package/src/runtime/nl-approval-parser.ts +2 -3
  605. package/src/runtime/routes/access-request-decision.ts +2 -2
  606. package/src/runtime/routes/app-management-routes.ts +918 -0
  607. package/src/runtime/routes/approval-routes.ts +76 -7
  608. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +38 -203
  609. package/src/runtime/routes/brain-graph/brain-graph.html +1845 -0
  610. package/src/runtime/routes/brain-graph-routes.ts +4 -42
  611. package/src/runtime/routes/channel-delivery-routes.ts +5 -4
  612. package/src/runtime/routes/channel-route-shared.ts +1 -3
  613. package/src/runtime/routes/channel-routes.ts +1 -4
  614. package/src/runtime/routes/channel-verification-routes.ts +257 -0
  615. package/src/runtime/routes/computer-use-routes.ts +595 -0
  616. package/src/runtime/routes/contact-routes.ts +1 -317
  617. package/src/runtime/routes/conversation-attention-routes.ts +6 -5
  618. package/src/runtime/routes/conversation-routes.ts +20 -24
  619. package/src/runtime/routes/debug-routes.ts +1 -1
  620. package/src/runtime/routes/diagnostics-routes.ts +890 -0
  621. package/src/runtime/routes/documents-routes.ts +227 -0
  622. package/src/runtime/routes/guardian-approval-interception.ts +25 -48
  623. package/src/runtime/routes/guardian-bootstrap-routes.ts +3 -3
  624. package/src/runtime/routes/guardian-expiry-sweep.ts +2 -2
  625. package/src/runtime/routes/guardian-refresh-routes.ts +11 -6
  626. package/src/runtime/routes/inbound-conversation.ts +3 -10
  627. package/src/runtime/routes/inbound-message-handler.ts +7 -6
  628. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +22 -22
  629. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +44 -0
  630. package/src/runtime/routes/inbound-stages/background-dispatch.ts +140 -22
  631. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +4 -4
  632. package/src/runtime/routes/inbound-stages/edit-intercept.ts +5 -5
  633. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +3 -3
  634. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +4 -4
  635. package/src/runtime/routes/inbound-stages/verification-intercept.ts +13 -14
  636. package/src/runtime/routes/integrations/slack/channel.ts +72 -0
  637. package/src/runtime/routes/{slack-share-routes.ts → integrations/slack/share.ts} +9 -9
  638. package/src/runtime/routes/integrations/telegram.ts +111 -0
  639. package/src/runtime/routes/integrations/twilio.ts +451 -0
  640. package/src/runtime/routes/invite-routes.ts +2 -2
  641. package/src/runtime/routes/pairing-routes.ts +1 -1
  642. package/src/runtime/routes/recording-routes.ts +332 -0
  643. package/src/{daemon/handlers/config-scheduling.ts → runtime/routes/schedule-routes.ts} +91 -106
  644. package/src/runtime/routes/session-management-routes.ts +167 -0
  645. package/src/runtime/routes/session-query-routes.ts +204 -0
  646. package/src/runtime/routes/settings-routes.ts +887 -0
  647. package/src/runtime/routes/skills-routes.ts +266 -0
  648. package/src/runtime/routes/subagents-routes.ts +246 -0
  649. package/src/runtime/routes/surface-action-routes.ts +100 -10
  650. package/src/runtime/routes/surface-content-routes.ts +1 -1
  651. package/src/runtime/routes/work-items-routes.ts +809 -0
  652. package/src/runtime/routes/workspace-routes.test.ts +778 -0
  653. package/src/runtime/routes/workspace-routes.ts +410 -0
  654. package/src/runtime/routes/workspace-utils.ts +88 -0
  655. package/src/runtime/telegram-streaming-delivery.test.ts +597 -0
  656. package/src/runtime/telegram-streaming-delivery.ts +380 -0
  657. package/src/runtime/tool-grant-request-helper.ts +1 -2
  658. package/src/runtime/trust-context-resolver.ts +0 -1
  659. package/src/runtime/{guardian-outbound-actions.ts → verification-outbound-actions.ts} +23 -188
  660. package/src/runtime/verification-rate-limiter.ts +2 -2
  661. package/src/runtime/{guardian-verification-templates.ts → verification-templates.ts} +2 -28
  662. package/src/schedule/integration-status.ts +2 -2
  663. package/src/schedule/schedule-store.ts +7 -9
  664. package/src/sequence/engine.ts +1 -1
  665. package/src/skills/active-skill-tools.ts +0 -8
  666. package/src/skills/clawhub.ts +1 -10
  667. package/src/skills/managed-store.ts +14 -4
  668. package/src/skills/slash-commands.ts +1 -1
  669. package/src/subagent/manager.ts +1 -1
  670. package/src/subagent/types.ts +1 -1
  671. package/src/tasks/SPEC.md +10 -10
  672. package/src/tasks/task-scheduler.ts +1 -1
  673. package/src/telegram/bot-username.ts +13 -0
  674. package/src/tools/AGENTS.md +38 -0
  675. package/src/tools/apps/executors.ts +0 -6
  676. package/src/tools/assets/materialize.ts +1 -1
  677. package/src/tools/assets/search.ts +1 -1
  678. package/src/tools/browser/browser-execution.ts +2 -2
  679. package/src/tools/browser/browser-manager.ts +88 -11
  680. package/src/tools/browser/browser-screencast.ts +1 -1
  681. package/src/tools/browser/headless-browser.ts +0 -17
  682. package/src/tools/browser/jit-auth.ts +1 -1
  683. package/src/tools/browser/recording-store.ts +19 -1
  684. package/src/tools/browser/runtime-check.ts +4 -2
  685. package/src/tools/calls/call-start.ts +3 -3
  686. package/src/tools/credentials/metadata-store.ts +0 -13
  687. package/src/tools/credentials/vault.ts +7 -31
  688. package/src/tools/document/editor-template.ts +10 -8
  689. package/src/tools/followups/followup_create.ts +0 -8
  690. package/src/tools/mcp/mcp-tool-factory.ts +1 -1
  691. package/src/tools/memory/definitions.ts +32 -10
  692. package/src/tools/memory/handlers.test.ts +573 -0
  693. package/src/tools/memory/handlers.ts +222 -65
  694. package/src/tools/memory/register.ts +53 -24
  695. package/src/tools/network/script-proxy/session-manager.ts +1 -12
  696. package/src/tools/schedule/update.ts +0 -8
  697. package/src/tools/skills/load.ts +3 -3
  698. package/src/tools/subagent/read.ts +1 -1
  699. package/src/tools/system/voice-config.ts +2 -14
  700. package/src/tools/terminal/safe-env.ts +5 -18
  701. package/src/tools/tool-approval-handler.ts +4 -4
  702. package/src/tools/tool-manifest.ts +4 -2
  703. package/src/tools/types.ts +1 -1
  704. package/src/tools/{guardian-control-plane-policy.ts → verification-control-plane-policy.ts} +37 -39
  705. package/src/twitter/platform-proxy-client.ts +408 -0
  706. package/src/usage/types.ts +21 -0
  707. package/src/util/canonicalize-identity.ts +2 -6
  708. package/src/util/errors.ts +12 -0
  709. package/src/util/platform.ts +93 -86
  710. package/src/util/pricing.ts +180 -43
  711. package/src/work-items/work-item-runner.ts +1 -1
  712. package/scripts/ipc/check-contract-inventory.ts +0 -107
  713. package/scripts/ipc/check-swift-decoder-drift.ts +0 -184
  714. package/scripts/ipc/generate-swift.ts +0 -528
  715. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +0 -3043
  716. package/src/__tests__/app-migration.test.ts +0 -148
  717. package/src/__tests__/config-loader-migration.test.ts +0 -85
  718. package/src/__tests__/daemon-lifecycle.test.ts +0 -715
  719. package/src/__tests__/daemon-server-session-init.test.ts +0 -864
  720. package/src/__tests__/guardian-actions-endpoint.test.ts +0 -1452
  721. package/src/__tests__/handlers-add-trust-rule-metadata.test.ts +0 -228
  722. package/src/__tests__/handlers-cu-observation-blob.test.ts +0 -397
  723. package/src/__tests__/handlers-ipc-blob-probe.test.ts +0 -218
  724. package/src/__tests__/handlers-slack-config.test.ts +0 -140
  725. package/src/__tests__/handlers-telegram-config.test.ts +0 -1317
  726. package/src/__tests__/handlers-twitter-config.test.ts +0 -1145
  727. package/src/__tests__/home-base-bootstrap.test.ts +0 -86
  728. package/src/__tests__/ingress-reconcile.test.ts +0 -606
  729. package/src/__tests__/integrations-cli.test.ts +0 -232
  730. package/src/__tests__/ipc-blob-store.test.ts +0 -329
  731. package/src/__tests__/ipc-contract-inventory.test.ts +0 -69
  732. package/src/__tests__/ipc-contract.test.ts +0 -76
  733. package/src/__tests__/ipc-protocol.test.ts +0 -120
  734. package/src/__tests__/ipc-roundtrip.benchmark.test.ts +0 -250
  735. package/src/__tests__/ipc-snapshot.test.ts +0 -2197
  736. package/src/__tests__/ipc-validate.test.ts +0 -471
  737. package/src/__tests__/migration-cli-flows.test.ts +0 -186
  738. package/src/__tests__/migration-ordering.test.ts +0 -267
  739. package/src/__tests__/oauth-connect-handler.test.ts +0 -361
  740. package/src/__tests__/platform-move-helper.test.ts +0 -108
  741. package/src/__tests__/platform-socket-path.test.ts +0 -52
  742. package/src/__tests__/platform-workspace-migration.test.ts +0 -1051
  743. package/src/__tests__/prebuilt-home-base-seed.test.ts +0 -79
  744. package/src/__tests__/recording-intent-handler.test.ts +0 -1155
  745. package/src/__tests__/script-proxy-profile-template-fallback.test.ts +0 -127
  746. package/src/__tests__/sms-messaging-provider.test.ts +0 -156
  747. package/src/__tests__/tool-permission-simulate-handler.test.ts +0 -367
  748. package/src/__tests__/twitter-auth-handler.test.ts +0 -561
  749. package/src/__tests__/twitter-cli-error-shaping.test.ts +0 -224
  750. package/src/__tests__/twitter-cli-routing.test.ts +0 -286
  751. package/src/__tests__/work-item-output.test.ts +0 -150
  752. package/src/amazon/session.ts +0 -58
  753. package/src/cli/channels.ts +0 -51
  754. package/src/cli/influencer.ts +0 -319
  755. package/src/cli/integrations.ts +0 -372
  756. package/src/cli/ipc-client.ts +0 -88
  757. package/src/cli/twitter.ts +0 -1111
  758. package/src/config/bundled-skills/configure-settings/SKILL.md +0 -86
  759. package/src/config/bundled-skills/doordash/lib/shared/ipc.ts +0 -32
  760. package/src/config/bundled-skills/sms-setup/SKILL.md +0 -210
  761. package/src/config/core-schema.ts +0 -434
  762. package/src/config/memory-schema.ts +0 -617
  763. package/src/daemon/auth-manager.ts +0 -106
  764. package/src/daemon/handlers/apps.ts +0 -783
  765. package/src/daemon/handlers/avatar.ts +0 -73
  766. package/src/daemon/handlers/browser.ts +0 -3
  767. package/src/daemon/handlers/computer-use.ts +0 -231
  768. package/src/daemon/handlers/config-dispatch.ts +0 -29
  769. package/src/daemon/handlers/config-heartbeat.ts +0 -299
  770. package/src/daemon/handlers/config-inbox.ts +0 -457
  771. package/src/daemon/handlers/config-integrations.ts +0 -409
  772. package/src/daemon/handlers/config-platform.ts +0 -77
  773. package/src/daemon/handlers/config-slack.ts +0 -41
  774. package/src/daemon/handlers/config-tools.ts +0 -226
  775. package/src/daemon/handlers/config-trust.ts +0 -135
  776. package/src/daemon/handlers/config.ts +0 -64
  777. package/src/daemon/handlers/contacts.ts +0 -193
  778. package/src/daemon/handlers/diagnostics.ts +0 -382
  779. package/src/daemon/handlers/documents.ts +0 -188
  780. package/src/daemon/handlers/guardian-actions.ts +0 -82
  781. package/src/daemon/handlers/home-base.ts +0 -82
  782. package/src/daemon/handlers/index.ts +0 -222
  783. package/src/daemon/handlers/misc.ts +0 -1139
  784. package/src/daemon/handlers/navigate-settings.ts +0 -29
  785. package/src/daemon/handlers/oauth-connect.ts +0 -202
  786. package/src/daemon/handlers/open-bundle-handler.ts +0 -88
  787. package/src/daemon/handlers/publish.ts +0 -176
  788. package/src/daemon/handlers/signing.ts +0 -56
  789. package/src/daemon/handlers/subagents.ts +0 -286
  790. package/src/daemon/handlers/twitter-auth.ts +0 -220
  791. package/src/daemon/handlers/work-items.ts +0 -796
  792. package/src/daemon/handlers/workspace-files.ts +0 -84
  793. package/src/daemon/handlers.ts +0 -16
  794. package/src/daemon/ipc-blob-store.ts +0 -246
  795. package/src/daemon/ipc-contract-inventory.json +0 -348
  796. package/src/daemon/ipc-contract-inventory.ts +0 -202
  797. package/src/daemon/ipc-handler.ts +0 -120
  798. package/src/daemon/ipc-protocol.ts +0 -85
  799. package/src/daemon/ipc-validate.ts +0 -254
  800. package/src/home-base/app-link-store.ts +0 -78
  801. package/src/home-base/bootstrap.ts +0 -74
  802. package/src/home-base/prebuilt/brain-graph.html +0 -1483
  803. package/src/home-base/prebuilt/index.html +0 -702
  804. package/src/home-base/prebuilt/seed-metadata.json +0 -21
  805. package/src/home-base/prebuilt/seed.ts +0 -122
  806. package/src/home-base/prebuilt-home-base-updater.ts +0 -36
  807. package/src/memory/app-migration.ts +0 -114
  808. package/src/memory/channel-delivery-store.ts +0 -40
  809. package/src/memory/channel-guardian-store.ts +0 -83
  810. package/src/memory/conversation-store.ts +0 -102
  811. package/src/memory/schema-migration.ts +0 -38
  812. package/src/messaging/providers/sms/adapter.ts +0 -232
  813. package/src/messaging/providers/sms/client.ts +0 -93
  814. package/src/messaging/providers/sms/types.ts +0 -7
  815. package/src/migrations/config-merge.ts +0 -62
  816. package/src/migrations/data-layout.ts +0 -89
  817. package/src/migrations/data-merge.ts +0 -44
  818. package/src/migrations/hooks-merge.ts +0 -118
  819. package/src/migrations/index.ts +0 -6
  820. package/src/migrations/log.ts +0 -28
  821. package/src/migrations/skills-merge.ts +0 -44
  822. package/src/migrations/workspace-layout.ts +0 -94
  823. package/src/notifications/adapters/sms.ts +0 -94
  824. package/src/runtime/channel-approval-parser.ts +0 -123
  825. package/src/runtime/channel-invite-transports/sms.ts +0 -53
  826. package/src/runtime/routes/approval-strategies/guardian-legacy-fallback-strategy.ts +0 -82
  827. package/src/runtime/routes/integration-routes.ts +0 -381
  828. package/src/runtime/routes/twilio-routes.ts +0 -1251
  829. package/src/twitter/client.ts +0 -979
  830. package/src/twitter/router.ts +0 -131
  831. package/src/twitter/session.ts +0 -54
  832. package/src/util/cookie-session.ts +0 -114
  833. package/src/watcher/providers/slack.ts +0 -282
  834. /package/src/{amazon → cli/commands/amazon}/cart.ts +0 -0
  835. /package/src/{amazon → cli/commands/amazon}/checkout.ts +0 -0
  836. /package/src/{amazon → cli/commands/amazon}/product-details.ts +0 -0
  837. /package/src/{amazon → cli/commands/amazon}/search.ts +0 -0
  838. /package/src/config/{calls-schema.ts → schemas/calls.ts} +0 -0
  839. /package/src/config/{elevenlabs-schema.ts → schemas/elevenlabs.ts} +0 -0
  840. /package/src/config/{mcp-schema.ts → schemas/mcp.ts} +0 -0
  841. /package/src/config/{notifications-schema.ts → schemas/notifications.ts} +0 -0
  842. /package/src/config/{sandbox-schema.ts → schemas/sandbox.ts} +0 -0
  843. /package/src/config/{skills-schema.ts → schemas/skills.ts} +0 -0
  844. /package/src/daemon/{ipc-contract → message-types}/browser.ts +0 -0
  845. /package/src/daemon/{ipc-contract → message-types}/contacts.ts +0 -0
  846. /package/src/daemon/{ipc-contract → message-types}/documents.ts +0 -0
  847. /package/src/daemon/{ipc-contract → message-types}/guardian-actions.ts +0 -0
  848. /package/src/daemon/{ipc-contract → message-types}/inbox.ts +0 -0
  849. /package/src/daemon/{ipc-contract → message-types}/messages.ts +0 -0
  850. /package/src/daemon/{ipc-contract → message-types}/pairing.ts +0 -0
  851. /package/src/daemon/{ipc-contract → message-types}/schedules.ts +0 -0
  852. /package/src/daemon/{ipc-contract → message-types}/settings.ts +0 -0
  853. /package/src/daemon/{ipc-contract → message-types}/skills.ts +0 -0
  854. /package/src/daemon/{ipc-contract → message-types}/subagents.ts +0 -0
  855. /package/src/daemon/{ipc-contract → message-types}/trust.ts +0 -0
  856. /package/src/daemon/{ipc-contract → message-types}/work-items.ts +0 -0
  857. /package/src/{cli/email-guardrails.ts → email/guardrails.ts} +0 -0
  858. /package/src/{config → prompts}/__tests__/build-cli-reference-section.test.ts +0 -0
  859. /package/src/{config → prompts}/templates/IDENTITY.md +0 -0
  860. /package/src/{config → prompts}/templates/SOUL.md +0 -0
  861. /package/src/{config → prompts}/templates/UPDATES.md +0 -0
  862. /package/src/{config → prompts}/templates/USER.md +0 -0
  863. /package/src/{config → prompts}/update-bulletin-format.ts +0 -0
  864. /package/src/{config → prompts}/update-bulletin-state.ts +0 -0
  865. /package/src/{config → prompts}/update-bulletin-template-path.ts +0 -0
  866. /package/src/{config → prompts}/update-bulletin.ts +0 -0
  867. /package/src/{config → prompts}/user-reference.ts +0 -0
package/ARCHITECTURE.md CHANGED
@@ -4,19 +4,18 @@ This document owns assistant-runtime architecture details. The repo-level archit
4
4
 
5
5
  ### Channel Onboarding Playbook Bootstrap
6
6
 
7
- - Transport metadata arrives via `session_create.transport` (IPC) or `/channels/inbound` (`channelId`, optional `hints`, optional `uxBrief`).
8
- - Telegram webhook ingress now injects deterministic channel-safe transport metadata (`hints` + `uxBrief`) so non-dashboard channels defer Home Base-only UI tasks cleanly.
7
+ - Transport metadata arrives via `session_create.transport` (HTTP) or `/channels/inbound` (`channelId`, optional `hints`, optional `uxBrief`).
8
+ - Telegram webhook ingress injects deterministic channel-safe transport metadata (`hints` + `uxBrief`) so non-dashboard channels defer dashboard-only UI tasks cleanly.
9
9
  - `OnboardingPlaybookManager` resolves `<channel>_onboarding.md`, checks `onboarding/playbooks/registry.json`, and applies per-channel first-time fast-path onboarding.
10
- - `OnboardingOrchestrator` derives onboarding-mode guidance (post-hatch sequence, USER.md capture, Home Base handoff) from playbook + transport context.
10
+ - `OnboardingOrchestrator` derives onboarding-mode guidance (post-hatch sequence, USER.md capture) from playbook + transport context.
11
11
  - Session runtime assembly injects both `<channel_onboarding_playbook>` and `<onboarding_mode>` context before provider calls, then strips both from persisted conversation history.
12
- - Daemon startup runs `ensurePrebuiltHomeBaseSeeded()` to provision one idempotent prebuilt Home Base app in `~/.vellum/workspace/data/apps`.
13
- - Home Base onboarding buttons relay prefilled natural-language prompts to the main assistant; permission setup remains user-initiated and hatch + first-conversation flows avoid proactive permission asks.
12
+ - Permission setup remains user-initiated and hatch + first-conversation flows avoid proactive permission asks.
14
13
 
15
14
  ### Guardian Actor Context (Unified Across Channels)
16
15
 
17
16
  - Guardian/non-guardian/unverified classification is centralized in `assistant/src/runtime/trust-context-resolver.ts`.
18
17
  - The same resolver is used by:
19
- - `/channels/inbound` (Telegram/SMS/WhatsApp path) before run orchestration.
18
+ - `/channels/inbound` (Telegram/WhatsApp path) before run orchestration.
20
19
  - Inbound Twilio voice setup (`RelayConnection.handleSetup`) to seed call-time actor context.
21
20
  - Runtime channel runs pass this as `trustContext`, and session runtime assembly injects `<inbound_actor_context>` (via `inboundActorContextFromTrustContext()`) into provider-facing prompts.
22
21
  - Voice calls mirror the same prompt contract: `CallController` receives guardian context on setup and refreshes it immediately after successful voice challenge verification, so the first post-verification turn is grounded as `actor_role: guardian`.
@@ -41,12 +40,12 @@ All HTTP API requests use a single `Authorization: Bearer <jwt>` header for auth
41
40
 
42
41
  **Subject patterns:**
43
42
 
44
- | Pattern | Principal Type | Description |
45
- | ---------------------------------------- | -------------- | --------------------------------------------- |
46
- | `actor:<assistantId>:<actorPrincipalId>` | `actor` | Desktop, iOS, or CLI client |
47
- | `svc:gateway:<assistantId>` | `svc_gateway` | Gateway service (ingress, webhooks) |
48
- | `ipc:<assistantId>:<sessionId>` | `ipc` | Internal IPC connections |
49
- | `svc:daemon:self` | n/a | Daemon self-identification (for internal use) |
43
+ | Pattern | Principal Type | Description |
44
+ | ---------------------------------------- | -------------- | ------------------------------------------- |
45
+ | `actor:<assistantId>:<actorPrincipalId>` | `actor` | Desktop, iOS, or CLI client |
46
+ | `svc:gateway:<assistantId>` | `svc_gateway` | Gateway service (ingress, webhooks) |
47
+ | `svc:internal:<assistantId>:<sessionId>` | `svc_internal` | Internal service connections |
48
+ | `svc:daemon:<identifier>` | `svc_daemon` | Daemon service token (local) |
50
49
 
51
50
  **Scope profiles:**
52
51
 
@@ -55,17 +54,17 @@ All HTTP API requests use a single `Authorization: Bearer <jwt>` header for auth
55
54
  | `actor_client_v1` | `chat.{read,write}`, `approval.{read,write}`, `settings.{read,write}`, `attachments.{read,write}`, `calls.{read,write}`, `feature_flags.{read,write}` | Desktop, iOS, CLI clients |
56
55
  | `gateway_ingress_v1` | `ingress.write`, `internal.write` | Gateway channel inbound + webhook forwarding |
57
56
  | `gateway_service_v1` | `settings.read`, `settings.write`, `internal.write` | Gateway service-to-daemon calls |
58
- | `ipc_v1` | `ipc.all` | Internal IPC connections |
57
+ | `internal_v1` | `internal.all` | Internal service connections |
59
58
 
60
59
  **Identity lifecycle:**
61
60
 
62
- 1. **Bootstrap (loopback-only, macOS/CLI)** — On first launch, the client calls `POST /v1/integrations/guardian/vellum/bootstrap` with `{ platform, deviceId }`. The endpoint is loopback-only and mints a JWT access token + refresh token pair. Returns `{ guardianPrincipalId, accessToken, accessTokenExpiresAt, refreshToken, refreshTokenExpiresAt, refreshAfter, isNew }`.
61
+ 1. **Bootstrap (loopback-only, macOS)** — On first launch, the macOS client calls `POST /v1/guardian/init` with `{ platform, deviceId }`. The endpoint is loopback-only and mints a JWT access token + refresh token pair. Returns `{ guardianPrincipalId, accessToken, accessTokenExpiresAt, refreshToken, refreshTokenExpiresAt, refreshAfter, isNew }`. The CLI obtains its bearer token during `hatch` and does not perform a separate bootstrap step.
63
62
 
64
63
  2. **iOS pairing** — iOS devices obtain JWTs through the QR pairing flow. The pairing response includes `accessToken` and `refreshToken` credentials.
65
64
 
66
- 3. **Refresh** — `POST /v1/integrations/guardian/vellum/refresh` accepts `{ refreshToken }` and returns a new access/refresh token pair. Single-use rotation with replay detection and family-based revocation.
65
+ 3. **Refresh** — `POST /v1/guardian/refresh` accepts `{ refreshToken }` and returns a new access/refresh token pair. Single-use rotation with replay detection and family-based revocation.
67
66
 
68
- 4. **IPC identity** — Local IPC connections use `resolveLocalIpcGuardianContext()` for deterministic identity without tokens.
67
+ 4. **Local identity** — Local connections use deterministic identity resolution without tokens.
69
68
 
70
69
  **Route policy enforcement:** Every protected endpoint declares required scopes and allowed principal types in `src/runtime/auth/route-policy.ts`. The `enforcePolicy()` function checks the AuthContext against these requirements and returns 403 when access is denied. A guard test ensures every dispatched endpoint has a corresponding policy entry.
71
70
 
@@ -85,11 +84,11 @@ All HTTP API requests use a single `Authorization: Bearer <jwt>` header for auth
85
84
  | `src/runtime/auth/subject.ts` | Subject string parser (`parseSub`) |
86
85
  | `src/runtime/auth/middleware.ts` | JWT bearer auth middleware (`authenticateRequest`) |
87
86
  | `src/runtime/auth/route-policy.ts` | Route-level scope/principal enforcement |
88
- | `src/runtime/routes/guardian-bootstrap-routes.ts` | `POST /v1/integrations/guardian/vellum/bootstrap` (initial JWT issuance) |
89
- | `src/runtime/routes/guardian-refresh-routes.ts` | `POST /v1/integrations/guardian/vellum/refresh` (token rotation) |
87
+ | `src/runtime/routes/guardian-bootstrap-routes.ts` | `POST /v1/guardian/init` (initial JWT issuance) |
88
+ | `src/runtime/routes/guardian-refresh-routes.ts` | `POST /v1/guardian/refresh` (token rotation) |
90
89
  | `src/runtime/routes/pairing-routes.ts` | JWT credential issuance in pairing flow |
91
- | `src/runtime/local-actor-identity.ts` | `resolveLocalIpcGuardianContext` — deterministic IPC identity |
92
- | `src/memory/channel-guardian-store.ts` | Guardian binding types and re-exports |
90
+ | `src/runtime/local-actor-identity.ts` | `resolveLocalGuardianContext` — deterministic local identity |
91
+ | `src/memory/channel-verification-sessions.ts` | Guardian binding types, verification session management |
93
92
 
94
93
  ### Channel-Agnostic Scoped Approval Grants
95
94
 
@@ -97,7 +96,7 @@ Scoped approval grants allow a guardian's approval decision on one channel (e.g.
97
96
 
98
97
  ### Guardian Decision Primitive (Dual-Mode Approval)
99
98
 
100
- All guardian approval decisions — regardless of how they arrive — route through a single unified primitive in `src/approvals/guardian-decision-primitive.ts`. This centralizes decision logic that was previously duplicated across callback button handlers, the conversational approval engine, the legacy text parser, and the requester self-cancel path.
99
+ All guardian approval decisions — regardless of how they arrive — route through a single unified primitive in `src/approvals/guardian-decision-primitive.ts`. This centralizes decision logic that was previously duplicated across callback button handlers, the conversational approval engine, and the requester self-cancel path.
101
100
 
102
101
  **Core API:**
103
102
 
@@ -113,12 +112,12 @@ All guardian approval decisions — regardless of how they arrive — route thro
113
112
  - `approve_always` is downgraded to `approve_once` for guardian-on-behalf requests (guardians cannot permanently allowlist tools for requesters).
114
113
  - Scoped grant minting only fires on explicit approve for requests with tool metadata.
115
114
 
116
- **Unified interaction model — buttons first, text fallback:** All guardian approval prompts follow a canonical "buttons first, text fallback" pattern. Structured button UIs are the primary interaction surface, but every prompt also carries deterministic text fallback instructions so guardians can always act even when buttons are unavailable or not used. This applies uniformly across all request kinds (`tool_approval`, `pending_question`, `access_request`) and all channels (macOS desktop, Telegram, SMS, WhatsApp).
115
+ **Unified interaction model — buttons first, text fallback:** All guardian approval prompts follow a canonical "buttons first, text fallback" pattern. Structured button UIs are the primary interaction surface, but every prompt also carries deterministic text fallback instructions so guardians can always act even when buttons are unavailable or not used. This applies uniformly across all request kinds (`tool_approval`, `pending_question`, `access_request`) and all channels (macOS desktop, Telegram, WhatsApp).
117
116
 
118
117
  **Button-first path (deterministic):**
119
118
 
120
119
  - Desktop clients (macOS/iOS) render `GuardianDecisionPrompt` objects as tappable card UIs with kind-aware headers and action buttons. The `GuardianDecisionBubble` renders distinct headers for each kind: "Tool Approval Required", "Question Pending", or "Access Request".
121
- - Desktop clients submit decisions via HTTP (`POST /v1/guardian-actions/decision`) or IPC (`guardian_action_decision`). Both route through `applyCanonicalGuardianDecision`.
120
+ - Desktop clients submit decisions via HTTP (`POST /v1/guardian-actions/decision`), routed through `applyCanonicalGuardianDecision`.
122
121
  - Channel adapters (Telegram inline keyboards, WhatsApp) encode actions as callback data (`apr:<requestId>:<action>`).
123
122
 
124
123
  **Text fallback path (always available):**
@@ -137,8 +136,6 @@ All guardian approval decisions — regardless of how they arrive — route thro
137
136
  | `src/approvals/guardian-decision-primitive.ts` | Unified decision application: downgrade, approval info capture, `handleChannelDecision`, record update, grant minting |
138
137
  | `src/runtime/guardian-decision-types.ts` | Shared types: `GuardianDecisionPrompt`, `GuardianDecisionAction`, `buildDecisionActions`, `buildPlainTextFallback`, `ApplyGuardianDecisionResult` |
139
138
  | `src/runtime/routes/guardian-action-routes.ts` | HTTP route handlers for `GET /v1/guardian-actions/pending` and `POST /v1/guardian-actions/decision` |
140
- | `src/daemon/handlers/guardian-actions.ts` | IPC handlers wrapping the same logic for desktop socket clients |
141
- | `src/daemon/ipc-contract/guardian-actions.ts` | IPC message type definitions for guardian action requests/responses |
142
139
  | `src/runtime/channel-approval-types.ts` | Channel-facing approval action types and `toApprovalActionOptions` bridge |
143
140
 
144
141
  ### Temporary Approval Modes (Session-Scoped Overrides)
@@ -167,17 +164,17 @@ In addition to persistent trust rules (`always_allow` / `always_deny`), the appr
167
164
 
168
165
  ### Canonical Guardian Request System
169
166
 
170
- The canonical guardian request system provides a channel-agnostic, unified domain for all guardian approval and question flows. It replaces the fragmented per-channel storage with a single source of truth that works identically for voice calls, Telegram/SMS/WhatsApp, and desktop UI.
167
+ The canonical guardian request system provides a channel-agnostic, unified domain for all guardian approval and question flows. It replaces the fragmented per-channel storage with a single source of truth that works identically for voice calls, Telegram/WhatsApp, and desktop UI.
171
168
 
172
169
  **Architecture layers:**
173
170
 
174
171
  1. **Canonical domain (single source of truth):** All guardian requests — tool approvals, pending questions, access requests — are persisted in the `canonical_guardian_requests` table (`src/memory/canonical-guardian-store.js`). Each request has a unique ID, a short human-readable request code, and a status that follows a CAS (compare-and-swap) lifecycle: `pending` -> `approved` | `denied` | `expired` | `cancelled`. Deliveries (notifications sent to guardians) are tracked in `canonical_guardian_deliveries`.
175
172
 
176
- 2. **Unified apply primitive (single write path):** `applyCanonicalGuardianDecision()` in `src/approvals/guardian-decision-primitive.ts` is the single write path for all guardian decisions. It enforces identity validation, expiry checks, CAS resolution, `approve_always` downgrade (guardian-on-behalf invariant), kind-specific resolver dispatch via the resolver registry, and scoped grant minting. All callers — HTTP API, IPC handlers, inbound channel router, desktop session — route decisions through this function.
173
+ 2. **Unified apply primitive (single write path):** `applyCanonicalGuardianDecision()` in `src/approvals/guardian-decision-primitive.ts` is the single write path for all guardian decisions. It enforces identity validation, expiry checks, CAS resolution, `approve_always` downgrade (guardian-on-behalf invariant), kind-specific resolver dispatch via the resolver registry, and scoped grant minting. All callers — HTTP API, inbound channel router, desktop session — route decisions through this function.
177
174
 
178
175
  3. **Shared reply router (priority-ordered routing):** `routeGuardianReply()` in `src/runtime/guardian-reply-router.ts` provides a single entry point for all inbound guardian reply processing across channels. It routes through a priority-ordered pipeline: (a) deterministic callback parsing (button presses with `apr:<requestId>:<action>`), (b) request code parsing (6-char alphanumeric prefix), (c) NL classification via the conversational approval engine. All decisions flow through `applyCanonicalGuardianDecision`.
179
176
 
180
- 4. **Deterministic API (prompt listing and decision endpoints):** Desktop clients and API consumers use `GET /v1/guardian-actions/pending` and `POST /v1/guardian-actions/decision` (HTTP) or the equivalent IPC messages. These endpoints surface canonical requests alongside legacy pending interactions and channel approval records, with deduplication to avoid double-rendering.
177
+ 4. **Deterministic API (prompt listing and decision endpoints):** Desktop clients and API consumers use `GET /v1/guardian-actions/pending` and `POST /v1/guardian-actions/decision` (HTTP). These endpoints surface canonical requests alongside legacy pending interactions and channel approval records, with deduplication to avoid double-rendering.
181
178
 
182
179
  5. **Buttons first, text fallback:** All request kinds (`tool_approval`, `pending_question`, `access_request`) are rendered as structured button cards when displayed in macOS/iOS guardian threads. Each prompt also embeds deterministic text fallback instructions (request-code-based approve/reject directives, and for `access_request` the "open invite flow" phrase) so text-based channels and manual fallback always work. Code-only messages (just a request code without decision text) return clarification instead of auto-approving. Disambiguation with multiple pending requests stays fail-closed — no auto-resolve when the target is ambiguous.
183
180
 
@@ -198,51 +195,51 @@ The canonical guardian request system provides a channel-agnostic, unified domai
198
195
  | `src/approvals/guardian-request-resolvers.ts` | Resolver registry: kind-specific side-effect dispatch after CAS resolution |
199
196
  | `src/runtime/guardian-reply-router.ts` | Shared inbound router: callback -> code -> NL classification pipeline |
200
197
  | `src/runtime/routes/guardian-action-routes.ts` | HTTP endpoints for prompt listing and decision submission |
201
- | `src/daemon/handlers/guardian-actions.ts` | IPC handlers for desktop socket clients |
202
198
  | `src/runtime/routes/canonical-guardian-expiry-sweep.ts` | Canonical request expiry sweep |
203
199
 
204
- ### Outbound Guardian Verification (HTTP Endpoints)
200
+ ### Outbound Channel Verification (HTTP Endpoints)
205
201
 
206
- Guardian verification can be initiated through gateway HTTP endpoints (which forward to runtime handlers) as an alternative to the legacy IPC-only flow. This enables chat-first verification where the assistant guides the user through guardian setup via normal conversation.
202
+ Channel verification is initiated through gateway HTTP endpoints (which forward to runtime handlers). This enables chat-first verification where the assistant guides the user through channel verification setup via normal conversation.
207
203
 
208
204
  **HTTP Endpoints:**
209
205
 
210
- | Endpoint | Method | Description |
211
- | ------------------------------------------- | ------ | --------------------------------------------------------------------------------------------------- |
212
- | `/v1/integrations/guardian/outbound/start` | POST | Start a new outbound verification session. Body: `{ channel, destination?, assistantId?, rebind? }` |
213
- | `/v1/integrations/guardian/outbound/resend` | POST | Resend the verification code for an active session. Body: `{ channel, assistantId? }` |
214
- | `/v1/integrations/guardian/outbound/cancel` | POST | Cancel an active outbound verification session. Body: `{ channel, assistantId? }` |
206
+ | Endpoint | Method | Description |
207
+ | ------------------------------------------ | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
208
+ | `/v1/channel-verification-sessions` | POST | Create a verification session. If `destination` is provided, starts outbound verification; if `purpose: "trusted_contact"` with `contactChannelId`, starts trusted contact verification; otherwise creates an inbound challenge. Body: `{ channel?, destination?, rebind?, purpose?, contactChannelId? }` |
209
+ | `/v1/channel-verification-sessions/resend` | POST | Resend the verification code for an active outbound session. Body: `{ channel }` |
210
+ | `/v1/channel-verification-sessions` | DELETE | Cancel all active sessions (inbound + outbound) for a channel. Body: `{ channel }` |
211
+ | `/v1/channel-verification-sessions/revoke` | POST | Cancel all active sessions and revoke the guardian binding. Body: `{ channel? }` |
212
+ | `/v1/channel-verification-sessions/status` | GET | Check guardian binding status. Query: `?channel=<channel>` |
215
213
 
216
214
  All endpoints are JWT-authenticated via `Authorization: Bearer <jwt>`. Skills and user-facing tooling should target the gateway URL (default `http://localhost:7830`), not the runtime port.
217
215
 
218
216
  **Shared Business Logic:**
219
217
 
220
- The HTTP route handlers (`integration-routes.ts`) and the legacy IPC handlers (`config-channels.ts`) both delegate to the same action functions in `guardian-outbound-actions.ts`. This module contains transport-agnostic business logic for starting, resending, and cancelling outbound verification flows across SMS, Telegram, and voice channels. It returns `OutboundActionResult` objects that the transport layer (gateway-forwarded HTTP or IPC) maps to its respective response format.
218
+ The HTTP route handlers (`channel-verification-routes.ts`) delegate to action functions in `verification-outbound-actions.ts`. This module contains transport-agnostic business logic for starting, resending, and cancelling outbound verification flows across Telegram and voice channels. It returns `OutboundActionResult` objects that the transport layer maps to the HTTP response format.
221
219
 
222
220
  **Chat-First Orchestration Flow:**
223
221
 
224
- 1. The user asks the assistant (via desktop chat) to set up guardian verification for a channel.
225
- 2. The conversational routing layer detects the guardian-setup intent and loads the `guardian-verify-setup` skill via `skill_load`.
222
+ 1. The user asks the assistant (via desktop chat) to set up channel verification.
223
+ 2. The conversational routing layer detects the verification-setup intent and loads the `guardian-verify-setup` skill via `skill_load`.
226
224
  3. The skill guides the assistant through collecting the channel and destination, then calls the outbound HTTP endpoints using `curl`.
227
225
  4. The assistant relays verification status (code sent, resend available, expiry) back to the user conversationally.
228
- 5. On the channel side, the verification code arrives (SMS text, Telegram message, or voice call) and the recipient enters it to complete the binding.
226
+ 5. On the channel side, the verification code arrives (Telegram message or voice call) and the recipient enters it to complete the binding.
229
227
 
230
228
  **Key Source Files:**
231
229
 
232
- | File | Purpose |
233
- | ---------------------------------------------------------- | ---------------------------------------------------------------------------------- |
234
- | `src/runtime/guardian-outbound-actions.ts` | Shared business logic for start/resend/cancel outbound verification |
235
- | `src/runtime/routes/integration-routes.ts` | HTTP route handlers for `/v1/integrations/guardian/outbound/*` |
236
- | `src/daemon/handlers/config-channels.ts` | IPC handler that delegates to the same shared actions |
237
- | `src/config/bundled-skills/guardian-verify-setup/SKILL.md` | Skill that teaches the assistant how to orchestrate guardian verification via chat |
230
+ | File | Purpose |
231
+ | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
232
+ | `src/runtime/verification-outbound-actions.ts` | Shared business logic for start/resend/cancel outbound verification |
233
+ | `src/runtime/routes/channel-verification-routes.ts` | HTTP route handlers for unified verification session API (`/v1/channel-verification-sessions`, `/revoke`, `/status`) |
234
+ | `src/config/bundled-skills/guardian-verify-setup/SKILL.md` | Skill that teaches the assistant how to orchestrate channel verification via chat |
238
235
 
239
236
  **Guardian-Only Tool Invocation Gate:**
240
237
 
241
- Guardian verification control-plane endpoints (`/v1/integrations/guardian/*`) are protected by a deterministic gate in the tool executor (`src/tools/executor.ts`). Before any tool invocation proceeds, the executor checks whether the invocation targets a guardian control-plane endpoint and whether the actor role is allowed. The policy uses an allowlist: only `guardian` and `undefined` (desktop/trusted) actor roles can invoke these endpoints. Non-guardian and unverified-channel actors receive a denial message explaining the restriction.
238
+ Channel verification control-plane endpoints (`/v1/channel-verification-sessions/*`) are protected by a deterministic gate in the tool executor (`src/tools/executor.ts`). Before any tool invocation proceeds, the executor checks whether the invocation targets a guardian control-plane endpoint and whether the actor role is allowed. The policy uses an allowlist: only `guardian` and `undefined` (desktop/trusted) actor roles can invoke these endpoints. Non-guardian and unverified-channel actors receive a denial message explaining the restriction.
242
239
 
243
- The policy is implemented in `src/tools/guardian-control-plane-policy.ts`, which inspects tool inputs (bash commands, URLs) for guardian endpoint paths. This is a defense-in-depth measure — even if the LLM attempts to call guardian endpoints on behalf of a non-guardian actor, the tool executor blocks it deterministically.
240
+ The policy is implemented in `src/tools/verification-control-plane-policy.ts`, which inspects tool inputs (bash commands, URLs) for verification endpoint paths. This is a defense-in-depth measure — even if the LLM attempts to call verification endpoints on behalf of a non-guardian actor, the tool executor blocks it deterministically.
244
241
 
245
- The `guardian-verify-setup` skill is the exclusive handler for guardian verification intents in the system prompt. Other skills (e.g., `phone-calls`) hand off to `guardian-verify-setup` rather than orchestrating verification directly.
242
+ The `guardian-verify-setup` skill is the exclusive handler for channel verification intents in the system prompt. Other skills (e.g., `phone-calls`) hand off to `guardian-verify-setup` rather than orchestrating verification directly.
246
243
 
247
244
  ### Guardian Action Timeout-to-Follow-Up Lifecycle
248
245
 
@@ -278,7 +275,7 @@ When a voice call's ASK_GUARDIAN consultation times out before the guardian resp
278
275
 
279
276
  **Generated messaging requirement:** All user-facing copy in the guardian timeout/follow-up path is generated through the `guardian-action-message-composer.ts` composition system, which uses a 2-tier priority chain: (1) daemon-injected LLM generator for natural, varied text; (2) deterministic fallback templates for reliability. No hardcoded user-facing strings exist in the flow files (call-controller, inbound-message-handler, session-process) outside of internal log messages and LLM-instruction prompts. A guard test (`guardian-action-no-hardcoded-copy.test.ts`) enforces this invariant.
280
277
 
281
- **Callback/message-back branch:** When the conversation engine classifies the guardian's intent as `call_back`, the executor starts an outbound call to the counterparty with context about the guardian's answer. When classified as `message_back`, the executor sends an SMS to the counterparty via the gateway's `/deliver/sms` endpoint. The counterparty phone number is resolved from the original call session by call direction (inbound: `fromNumber`; outbound: `toNumber`).
278
+ **Callback branch:** When the conversation engine classifies the guardian's intent as `call_back`, the executor starts an outbound call to the counterparty with context about the guardian's answer. The counterparty phone number is resolved from the original call session by call direction (inbound: `fromNumber`; outbound: `toNumber`).
282
279
 
283
280
  **Key source files:**
284
281
 
@@ -286,55 +283,18 @@ When a voice call's ASK_GUARDIAN consultation times out before the guardian resp
286
283
  | ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
287
284
  | `src/memory/guardian-action-store.ts` | Follow-up state machine with atomic transitions (`startFollowupFromExpiredRequest`, `progressFollowupState`, `finalizeFollowup`) and query helpers for pending/expired/follow-up deliveries |
288
285
  | `src/runtime/guardian-action-message-composer.ts` | 2-tier text generation: daemon-injected LLM generator with deterministic fallback templates. Covers all scenarios from timeout acknowledgment through follow-up completion |
289
- | `src/runtime/guardian-action-conversation-turn.ts` | Follow-up decision engine: classifies guardian replies into `call_back`, `message_back`, `decline`, or `keep_pending` dispositions using LLM tool calling |
290
- | `src/runtime/guardian-action-followup-executor.ts` | Action dispatch: resolves counterparty from call session, executes `message_back` (SMS via gateway) or `call_back` (outbound call via `startCall`), finalizes follow-up state |
286
+ | `src/runtime/guardian-action-conversation-turn.ts` | Follow-up decision engine: classifies guardian replies into `call_back`, `decline`, or `keep_pending` dispositions using LLM tool calling |
287
+ | `src/runtime/guardian-action-followup-executor.ts` | Action dispatch: resolves counterparty from call session, executes `call_back` (outbound call via `startCall`), finalizes follow-up state |
291
288
  | `src/daemon/guardian-action-generators.ts` | Daemon-injected generator factories: `createGuardianActionCopyGenerator` (latency-optimized text rewriting) and `createGuardianFollowUpConversationGenerator` (tool-calling intent classification) |
292
289
  | `src/calls/call-controller.ts` | Voice timeout handling: marks requests as timed out, sends expiry notices, injects `[GUARDIAN_TIMEOUT]` instruction for generated voice response |
293
- | `src/runtime/routes/inbound-message-handler.ts` | Late reply interception for Telegram/SMS channels: matches late answers to expired requests, routes follow-up conversation turns, dispatches actions |
294
- | `src/daemon/session-process.ts` | Late reply interception for mac/IPC channel: same logic as inbound-message-handler but using conversation-ID-based delivery lookup |
290
+ | `src/runtime/routes/inbound-message-handler.ts` | Late reply interception for Telegram channels: matches late answers to expired requests, routes follow-up conversation turns, dispatches actions |
291
+ | `src/daemon/session-process.ts` | Late reply interception for mac channel: same logic as inbound-message-handler but using conversation-ID-based delivery lookup |
295
292
  | `src/calls/guardian-action-sweep.ts` | Periodic sweep for stale pending requests; sends expiry notices to guardian destinations |
296
293
  | `src/memory/migrations/030-guardian-action-followup.ts` | Schema migration adding follow-up columns (`followup_state`, `late_answer_text`, `late_answered_at`, `followup_action`, `followup_completed_at`) |
297
294
 
298
- ### SMS Channel (Twilio)
299
-
300
- The SMS channel provides text-only messaging via Twilio, sharing the same telephony provider as voice calls. It follows the same ingress/egress pattern as Telegram but uses Twilio's HMAC-SHA1 signature validation instead of a secret header.
301
-
302
- **Ingress** (`POST /webhooks/twilio/sms`):
303
-
304
- 1. Twilio delivers an inbound SMS as a form-encoded POST to the gateway.
305
- 2. The gateway validates the `X-Twilio-Signature` header using HMAC-SHA1 with the Twilio Auth Token against the canonical request URL (reconstructed from `INGRESS_PUBLIC_BASE_URL` when behind a tunnel).
306
- 3. `MessageSid` deduplication prevents reprocessing retried webhooks.
307
- 4. **MMS detection**: The gateway treats a message as MMS when any of: `NumMedia > 0`, any `MediaUrl<N>` key has a non-empty value, or any `MediaContentType<N>` key has a non-empty value. This catches media attachments even when Twilio omits `NumMedia`. The gateway replies with an unsupported notice and does not forward the payload. MMS payloads are explicitly rejected rather than silently dropped.
308
- 5. **`/new` command**: When the message body is exactly `/new` (case-insensitive, trimmed), the gateway resolves routing first. If routing is rejected, a rejection notice SMS is sent to the sender (matching Telegram `/new` rejection semantics — "This message could not be routed to an assistant"). If routing succeeds, the gateway calls `resetConversation(...)` on the runtime and sends a confirmation SMS. The message is never forwarded to the runtime.
309
- 6. The payload is normalized into a `GatewayInboundEvent` with `sourceChannel: "sms"` and `conversationExternalId` set to the sender's phone number (E.164).
310
- 7. **Routing** — Phone-number-based routing is checked first: the inbound `To` number is reverse-looked-up in `assistantPhoneNumbers` (a `Record<string, string>` mapping assistant IDs to E.164 numbers, propagated from the assistant config file). If a match is found, that assistant handles the message. Otherwise, the standard routing chain (conversation_id -> actor_id -> default/reject) is used. This allows multiple assistants to have dedicated phone numbers. The resolved route is passed as a `routingOverride` to `handleInbound()` so the already-resolved routing is used directly instead of re-running `resolveAssistant()` inside the handler.
311
- 8. The event is forwarded to the runtime via `POST /channels/inbound`, including SMS-specific transport hints (`chat-first-medium`, `sms-character-limits`, etc.) and a `replyCallbackUrl` pointing to `/deliver/sms`.
312
-
313
- **Egress** (`POST /deliver/sms`):
314
-
315
- 1. The runtime calls the gateway's `/deliver/sms` endpoint with `{ to, text }` or `{ chatId, text }`. The `chatId` field is an alias for `to`, allowing the runtime channel callback (which sends `{ chatId, text }`) to work without translation. When both `to` and `chatId` are provided, `to` takes precedence.
316
- 2. The gateway authenticates the request via bearer token (same fail-closed model as `/deliver/telegram`).
317
- 3. The gateway sends the SMS via the Twilio Messages API using the configured `TWILIO_PHONE_NUMBER` as the `From` number.
318
-
319
- **Setup**: Twilio credentials (Account SID, Auth Token) and phone number are managed via HTTP control-plane endpoints (`/v1/integrations/twilio/*`) exposed by the runtime and proxied by the gateway (see `src/runtime/routes/twilio-routes.ts`). A single phone number is shared across voice and SMS for each assistant. Both `provision` and `assign` endpoints auto-persist the number to config and secure storage, and auto-configure Twilio webhooks (voice URL, status callback, SMS URL) via the Twilio IncomingPhoneNumber API when a public ingress URL is available. When `assistantId` is provided, the number is persisted into the per-assistant mapping at `sms.assistantPhoneNumbers[assistantId]`, and the legacy `sms.phoneNumber` field is only set if it was previously empty/unset (acting as a fallback for single-assistant installs). This prevents multi-assistant assignments from clobbering each other's global outbound number. Without `assistantId`, the legacy field is always updated. Webhook configuration is best-effort — if ingress is not yet set up, the number is still assigned and webhooks can be configured later. Non-fatal webhook failures are surfaced as a `warning` field in the response.
320
-
321
- **Phone Number Resolution**: At runtime, `getTwilioConfig()` resolves the phone number using this priority chain: (1) `TWILIO_PHONE_NUMBER` env var — highest priority, explicit override; (2) `sms.phoneNumber` in config — primary source of truth written by `provision_number`/`assign_number`; (3) `credential:twilio:phone_number` secure key — backward-compatible fallback. An error is thrown if no number is found after all sources are checked.
322
-
323
- **Credential Clearing Semantics**: `clear_credentials` removes only the authentication credentials (Account SID and Auth Token) from secure storage. The phone number is preserved in both the config file (`sms.phoneNumber`) and the secure key (`credential:twilio:phone_number`) so that re-entering credentials resumes working without needing to reassign the number.
324
-
325
- **Webhook Lifecycle**: Twilio webhook URLs are managed through a shared `syncTwilioWebhooks` helper in `config.ts` that computes voice, status-callback, and SMS URLs from the ingress config and pushes them to Twilio. Webhooks are synchronized at three points:
326
-
327
- 1. **Number provisioning** (`provision_number`) — immediately after purchasing a number.
328
- 2. **Number assignment** (`assign_number`) — when an existing number is assigned to the assistant.
329
- 3. **Ingress URL change** (`ingress_config` set) — when the public ingress URL is updated or enabled, the daemon automatically re-synchronizes Twilio webhooks (fire-and-forget) if credentials and an assigned number are present. This ensures tunnel URL changes (e.g., ngrok restart) propagate without manual re-assignment.
330
-
331
- All three paths are best-effort: webhook sync failures do not prevent the primary operation from succeeding.
332
-
333
- **Limitations (v1)**: Text-only — MMS payloads are explicitly rejected with a user-facing notice rather than silently dropped.
334
-
335
295
  ### WhatsApp Channel (Meta Cloud API)
336
296
 
337
- The WhatsApp channel enables inbound and outbound messaging via the Meta WhatsApp Business Cloud API. It follows the same ingress/egress pattern as SMS but uses Meta's HMAC-SHA256 signature validation (`X-Hub-Signature-256`) instead of Twilio's HMAC-SHA1.
297
+ The WhatsApp channel enables inbound and outbound messaging via the Meta WhatsApp Business Cloud API. It follows the standard ingress/egress pattern with Meta's HMAC-SHA256 signature validation (`X-Hub-Signature-256`).
338
298
 
339
299
  **Ingress** (`GET /webhooks/whatsapp` — verification, `POST /webhooks/whatsapp` — messages):
340
300
 
@@ -365,9 +325,7 @@ These can be set via environment variables or stored in the credential vault (ke
365
325
 
366
326
  **Limitations (v1)**: Rich approval UI (inline buttons) is not supported. Contacts and location message types are acknowledged but not forwarded.
367
327
 
368
- **Channel Readiness**: The channel readiness HTTP endpoints (`GET /v1/channels/readiness`, `POST /v1/channels/readiness/refresh`) backed by `ChannelReadinessService` in `src/runtime/channel-readiness-service.ts` provide a unified readiness subsystem for all channels. Each channel registers a `ChannelProbe` that runs synchronous local checks (credential presence, phone number, ingress config) and optional async remote checks with a 5-minute TTL cache. Built-in probes: SMS (Twilio credentials, phone number, ingress; remote checks query Twilio toll-free verification status for toll-free numbers) and Telegram (bot token, webhook secret, ingress). The GET endpoint returns cached snapshots; the refresh endpoint invalidates the cache first. Unknown channels return `unsupported_channel`. Route handlers live in `src/runtime/routes/channel-readiness-routes.ts`.
369
-
370
- **SMS Compliance & Admin**: The Twilio HTTP control-plane endpoints extend beyond credential and number management with compliance and admin routes: `GET /v1/integrations/twilio/sms/compliance` detects toll-free vs local number type and fetches verification status; `POST/PATCH/DELETE /v1/integrations/twilio/sms/compliance/tollfree` manage the Twilio toll-free verification lifecycle; `POST /v1/integrations/twilio/numbers/release` removes a phone number from the Twilio account and clears all local references. All compliance actions validate required fields and Twilio enum values before calling the API.
328
+ **Channel Readiness**: The channel readiness HTTP endpoints (`GET /v1/channels/readiness`, `POST /v1/channels/readiness/refresh`) backed by `ChannelReadinessService` in `src/runtime/channel-readiness-service.ts` provide a unified readiness subsystem for all channels. Each channel registers a `ChannelProbe` that runs synchronous local checks (credential presence, ingress config) and optional async remote checks with a 5-minute TTL cache. Built-in probes: Telegram (bot token, webhook secret, ingress). The GET endpoint returns cached snapshots; the refresh endpoint invalidates the cache first. Unknown channels return `unsupported_channel`. Route handlers live in `src/runtime/routes/channel-readiness-routes.ts`.
371
329
 
372
330
  ### Slack Channel (Socket Mode)
373
331
 
@@ -406,14 +364,14 @@ Both `GET` and `POST` endpoints report `connected: true` only when both `hasBotT
406
364
 
407
365
  **Key source files:**
408
366
 
409
- | File | Purpose |
410
- | --------------------------------------------- | --------------------------------------------------------------- |
411
- | `src/daemon/handlers/config-slack-channel.ts` | Business logic for get/set/clear Slack channel config |
412
- | `src/runtime/routes/integration-routes.ts` | HTTP route handlers for `/v1/integrations/slack/channel/config` |
367
+ | File | Purpose |
368
+ | -------------------------------------------------- | --------------------------------------------------------------- |
369
+ | `src/daemon/handlers/config-slack-channel.ts` | Business logic for get/set/clear Slack channel config |
370
+ | `src/runtime/routes/integrations/slack/channel.ts` | HTTP route handlers for `/v1/integrations/slack/channel/config` |
413
371
 
414
372
  ### Trusted Contact Access (Channel-Agnostic)
415
373
 
416
- External users who are not the guardian can gain access to the assistant through a guardian-mediated verification flow. The flow is channel-agnostic — it works identically on Telegram, SMS, voice, and any future channel.
374
+ External users who are not the guardian can gain access to the assistant through a guardian-mediated verification flow. The flow is channel-agnostic — it works identically on Telegram, voice, and any future channel.
417
375
 
418
376
  **Full design doc:** [`docs/trusted-contact-access.md`](docs/trusted-contact-access.md)
419
377
 
@@ -422,12 +380,12 @@ External users who are not the guardian can gain access to the assistant through
422
380
  1. Unknown user messages the assistant on any channel.
423
381
  2. Ingress ACL (`inbound-message-handler.ts`) rejects the message and emits an `ingress.access_request` notification signal to the guardian.
424
382
  3. Guardian approves or denies via callback button or conversational intent (routed through `guardian-approval-interception.ts`).
425
- 4. On approval, an identity-bound verification session with a 6-digit code is created (`access-request-decision.ts` → `channel-guardian-service.ts`).
383
+ 4. On approval, an identity-bound verification session with a 6-digit code is created (`access-request-decision.ts` → `channel-verification-service.ts`).
426
384
  5. Guardian gives the code to the requester out-of-band.
427
385
  6. Requester enters the code; identity binding is verified, the challenge is consumed, and an active contact channel is created in the contacts table.
428
386
  7. All subsequent messages are accepted through the ingress ACL.
429
387
 
430
- **Channel-agnostic design:** The entire flow operates on abstract `ChannelId` and `actorExternalId`/`conversationExternalId` fields (DB column names `externalUserId`/`externalChatId` are unchanged). Identity binding adapts per channel: Telegram uses chat IDs, SMS/voice use E.164 phone numbers, HTTP API uses caller-provided identity. No channel-specific branching exists in the trusted contact code paths.
388
+ **Channel-agnostic design:** The entire flow operates on abstract `ChannelId` and `actorExternalId`/`conversationExternalId` fields (DB column names `externalUserId`/`externalChatId` are unchanged). Identity binding adapts per channel: Telegram uses chat IDs, voice uses E.164 phone numbers, HTTP API uses caller-provided identity. No channel-specific branching exists in the trusted contact code paths.
431
389
 
432
390
  **Lifecycle states:** `requested → pending_guardian → verification_pending → active | denied | expired`
433
391
 
@@ -456,12 +414,13 @@ External users who are not the guardian can gain access to the assistant through
456
414
  | `src/runtime/routes/inbound-message-handler.ts` | Ingress ACL, unknown-contact rejection, verification code interception |
457
415
  | `src/runtime/routes/access-request-decision.ts` | Guardian decision → verification session creation |
458
416
  | `src/runtime/routes/guardian-approval-interception.ts` | Routes guardian decisions (button + conversational) to access request handler |
459
- | `src/runtime/channel-guardian-service.ts` | Verification challenge lifecycle, identity binding, rate limiting |
417
+ | `src/runtime/channel-verification-service.ts` | Verification session lifecycle, identity binding, rate limiting |
460
418
  | `src/runtime/routes/contact-routes.ts` | HTTP API handlers for contact and channel management |
461
419
  | `src/runtime/routes/invite-routes.ts` | HTTP API handlers for invite management |
462
420
  | `src/runtime/invite-service.ts` | Business logic for invite operations |
463
421
  | `src/contacts/contact-store.ts` | Contact read queries — lookup, search, list, and channel operations |
464
- | `src/memory/channel-guardian-store.ts` | Approval request and verification challenge persistence |
422
+ | `src/memory/guardian-approvals.ts` | Approval request persistence |
423
+ | `src/memory/channel-verification-sessions.ts` | Verification challenge persistence |
465
424
  | `src/config/bundled-skills/contacts/SKILL.md` | Unified skill for contact management, access control, and invite links |
466
425
 
467
426
  ### Guardian-Initiated Invite Links
@@ -480,7 +439,7 @@ A complementary access-granting flow where the guardian proactively creates a sh
480
439
  │ Registry of per-channel adapters: │
481
440
  │ • buildShareableInvite(token) → { url, displayText } │
482
441
  │ • extractInboundToken(payload) → token | undefined │
483
- │ Registered: Telegram │ Deferred: SMS, Slack, Voice
442
+ │ Registered: Telegram │ Deferred: Slack, Voice
484
443
  ├─────────────────────────────────────────────────────────────┤
485
444
  │ Core Redemption Engine (invite-redemption-service.ts) │
486
445
  │ Channel-agnostic token validation, expiry, use-count, │
@@ -511,7 +470,6 @@ A complementary access-granting flow where the guardian proactively creates a sh
511
470
  | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
512
471
  | Telegram | Shipped | Bot username resolved from credential metadata or `TELEGRAM_BOT_USERNAME` env |
513
472
  | Voice | Shipped | Identity-bound voice code redemption via DTMF/speech in the relay state machine. Always-on canonical behavior with personalized friend/guardian name prompts. |
514
- | SMS | Deferred | Needs a deep-link strategy compatible with SMS (short URL or web redemption page) |
515
473
  | Slack | Deferred | Needs DM-safe ingress — Socket Mode handles channel messages but DM-initiated invite flows need routing |
516
474
 
517
475
  ### Voice Invite Flow (invite_redemption_pending)
@@ -520,7 +478,7 @@ Voice invites use a short numeric code (4-10 digits, default 6) instead of a URL
520
478
 
521
479
  **Creation flow:**
522
480
 
523
- 1. Guardian creates a voice invite via `POST /v1/contacts/invites` with `sourceChannel: "voice"` and `expectedExternalUserId` (E.164 phone).
481
+ 1. Guardian creates a voice invite via `POST /v1/contacts/invites` with `sourceChannel: "phone"` and `expectedExternalUserId` (E.164 phone).
524
482
  2. `invite-service.ts` generates a cryptographically random numeric code (`generateVoiceCode`), hashes it with SHA-256 (`hashVoiceCode`), and stores only the hash.
525
483
  3. The one-time plaintext `voiceCode` is returned in the creation response. The raw token is NOT returned for voice invites — redemption uses the identity-bound code flow exclusively.
526
484
  4. Guardian communicates the code to the invitee out-of-band.
@@ -550,7 +508,7 @@ Voice invites use a short numeric code (4-10 digits, default 6) instead of a URL
550
508
  | `src/runtime/channel-invite-transports/telegram.ts` | Telegram adapter — `t.me/<bot>?start=iv_<token>` deep links, `/start iv_<token>` extraction |
551
509
  | `src/runtime/channel-invite-transports/voice.ts` | Voice transport adapter — code-based redemption metadata |
552
510
  | `src/daemon/guardian-invite-intent.ts` | Intent detection — routes create/list/revoke requests into the contacts skill |
553
- | `src/runtime/invite-service.ts` | Shared business logic for invite operations (used by both HTTP routes and IPC) |
511
+ | `src/runtime/invite-service.ts` | Shared business logic for invite operations (used by HTTP routes) |
554
512
  | `src/runtime/routes/invite-routes.ts` | HTTP API handlers for invite management including voice invite creation and redemption |
555
513
  | `src/runtime/routes/inbound-message-handler.ts` | Invite token intercept in the inbound flow (unknown-contact and inactive-contact branches) |
556
514
  | `src/calls/relay-server.ts` | Voice relay state machine — `invite_redemption_pending` subflow (always-on canonical behavior) |
@@ -596,13 +554,13 @@ When no invite exists and no pending guardian challenge is active, the relay ent
596
554
  1. The relay transitions to `awaiting_name` state and prompts the caller for their name with a timeout.
597
555
  2. On name capture, `notifyGuardianOfAccessRequest` creates a canonical guardian request (`kind: 'access_request'`) and notifies the guardian via the notification pipeline.
598
556
  3. The relay transitions to `awaiting_guardian_decision` and plays hold music/messaging while polling the canonical request status.
599
- 4. The guardian approves or denies via any channel (Telegram, SMS, desktop). All decisions route through `applyCanonicalGuardianDecision`, which dispatches to the `access_request` resolver in `guardian-request-resolvers.ts`.
557
+ 4. The guardian approves or denies via any channel (Telegram, desktop). All decisions route through `applyCanonicalGuardianDecision`, which dispatches to the `access_request` resolver in `guardian-request-resolvers.ts`.
600
558
  5. On approval: the resolver directly activates the caller as a trusted contact (sets channel `status: 'active'`, `policy: 'allow'`), the poll detects the approved status, the relay transitions to the normal call flow with the caller's guardian context updated.
601
559
  6. On denial or timeout: the caller hears a denial message and the call ends.
602
560
 
603
561
  **Path 3: Inbound guardian verification (pending challenge)**
604
562
 
605
- When a pending voice guardian challenge exists (`getPendingChallenge`), the caller enters the DTMF/speech verification flow to complete an outbound-initiated guardian binding. This path is for guardian identity verification, not trusted-contact access.
563
+ When a pending voice guardian challenge exists (`getPendingSession`), the caller enters the DTMF/speech verification flow to complete an outbound-initiated guardian binding. This path is for guardian identity verification, not trusted-contact access.
606
564
 
607
565
  **Canonical decision routing:**
608
566
 
@@ -630,7 +588,7 @@ Release-driven update notification system that surfaces release notes to the ass
630
588
 
631
589
  **Data flow:**
632
590
 
633
- 1. **Bundled template** (`src/config/templates/UPDATES.md`) — source of release notes, maintained per-release in the repo.
591
+ 1. **Bundled template** (`src/prompts/templates/UPDATES.md`) — source of release notes, maintained per-release in the repo.
634
592
  2. **Startup sync** (`syncUpdateBulletinOnStartup()` in `src/config/update-bulletin.ts`) — materializes the bundled template into the workspace `UPDATES.md` on daemon boot. Uses atomic write (temp + rename) for crash safety.
635
593
  3. **System prompt injection** — `buildSystemPrompt()` reads workspace `UPDATES.md` and injects it as a `## Recent Updates` section with judgment-based handling instructions.
636
594
  4. **Completion by deletion** — the assistant deletes `UPDATES.md` when it has actioned all updates. Next startup detects the deletion and marks those releases as completed in checkpoint state.
@@ -645,11 +603,11 @@ Release-driven update notification system that surfaces release notes to the ass
645
603
 
646
604
  | File | Purpose |
647
605
  | -------------------------------------- | --------------------------------------------------------- |
648
- | `src/config/templates/UPDATES.md` | Bundled release-note template |
606
+ | `src/prompts/templates/UPDATES.md` | Bundled release-note template |
649
607
  | `src/config/update-bulletin.ts` | Startup sync logic (materialize, delete-complete, merge) |
650
608
  | `src/config/update-bulletin-format.ts` | Release block formatter/parser helpers |
651
609
  | `src/config/update-bulletin-state.ts` | Checkpoint state helpers for active/completed releases |
652
- | `src/config/system-prompt.ts` | Prompt injection of updates section |
610
+ | `src/prompts/system-prompt.ts` | Prompt injection of updates section |
653
611
  | `src/daemon/config-watcher.ts` | File watcher — evicts sessions on UPDATES.md changes |
654
612
  | `src/permissions/defaults.ts` | Auto-allow rules for file_read/write/edit + rm UPDATES.md |
655
613
 
@@ -667,7 +625,7 @@ The assistant feature-flag resolver (`src/config/assistant-feature-flags.ts`) is
667
625
  2. Defaults registry `defaultEnabled` — from the unified registry (`meta/feature-flags/feature-flag-registry.json`, filtered to `scope: "assistant"`)
668
626
  3. `true` — unknown/undeclared flags with no persisted override default to enabled
669
627
 
670
- **Storage:** Flags are persisted in `~/.vellum/workspace/config.json`. New writes go to the `assistantFeatureFlagValues` section (managed by the gateway's `/v1/feature-flags` API — see [`gateway/ARCHITECTURE.md`](../gateway/ARCHITECTURE.md)). The legacy `featureFlags` section is still read for backward compatibility. The daemon's config watcher hot-reloads this file, so flag changes take effect on the next tool resolution or session.
628
+ **Storage:** Flags are persisted in `~/.vellum/workspace/config.json` in the `assistantFeatureFlagValues` section (managed by the gateway's `/v1/feature-flags` API — see [`gateway/ARCHITECTURE.md`](../gateway/ARCHITECTURE.md)). The daemon's config watcher hot-reloads this file, so flag changes take effect on the next tool resolution or session.
671
629
 
672
630
  **Public API:**
673
631
 
@@ -678,8 +636,8 @@ The assistant feature-flag resolver (`src/config/assistant-feature-flags.ts`) is
678
636
 
679
637
  | Enforcement Point | Module | Effect |
680
638
  | ---------------------------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
681
- | **1. Client skill list** | `resolveSkillStates()` in `config/skill-state.ts` | Skills with flag OFF are excluded from the resolved list returned to IPC clients (macOS skill list, settings UI). The skill never appears in the client. |
682
- | **2. System prompt skill catalog** | `appendSkillsCatalog()` in `config/system-prompt.ts` | The model-visible `## Skills Catalog` section in the system prompt filters out flagged-off skills. The model cannot see or reference them. |
639
+ | **1. Client skill list** | `resolveSkillStates()` in `config/skill-state.ts` | Skills with flag OFF are excluded from the resolved list returned to clients (macOS skill list, settings UI). The skill never appears in the client. |
640
+ | **2. System prompt skill catalog** | `appendSkillsCatalog()` in `prompts/system-prompt.ts` | The model-visible `## Skills Catalog` section in the system prompt filters out flagged-off skills. The model cannot see or reference them. |
683
641
  | **3. `skill_load` tool** | `executeSkillLoad()` in `tools/skills/load.ts` | If the model attempts to load a flagged-off skill by name, the tool returns an error: `"skill is currently unavailable (disabled by feature flag)"`. |
684
642
  | **4. Runtime tool projection** | `projectSkillTools()` in `daemon/session-skill-tools.ts` | Even if a skill was previously active in a session (has `<loaded_skill>` markers in history), the per-turn projection drops it when the flag is OFF. Already-registered tools are unregistered. |
685
643
  | **5. Included child skills** | `executeSkillLoad()` in `tools/skills/load.ts` | When a parent skill includes children via the `includes` directive, each child is independently checked against its feature flag. Flagged-off children are silently excluded from the loaded skill content. |
@@ -694,12 +652,11 @@ All five enforcement points use `isAssistantFeatureFlagEnabled(skillFlagKey(skil
694
652
  | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
695
653
  | `src/config/assistant-feature-flags.ts` | Canonical resolver: `isAssistantFeatureFlagEnabled()`, `getAssistantFeatureFlagDefaults()`, registry loader |
696
654
  | `src/config/skill-state.ts` | `skillFlagKey()` — derives canonical flag key for skills; `resolveSkillStates()` — enforcement point 1 |
697
- | `src/config/system-prompt.ts` | `appendSkillsCatalog()` — enforcement point 2 |
655
+ | `src/prompts/system-prompt.ts` | `appendSkillsCatalog()` — enforcement point 2 |
698
656
  | `src/tools/skills/load.ts` | `executeSkillLoad()` — enforcement points 3 and 5 |
699
657
  | `src/daemon/session-skill-tools.ts` | `projectSkillTools()` — enforcement point 4 |
700
- | `src/config/schema.ts` | `featureFlags` and `assistantFeatureFlagValues` field definitions in `AssistantConfig` (Zod schema) |
701
- | `src/config/types.ts` | Type definitions for `FeatureFlags` (legacy) and `AssistantFeatureFlagValues` (canonical) |
702
- | `src/daemon/handlers/skills.ts` | `handleSkillsList()` — uses `resolveSkillStates()` for IPC client responses |
658
+ | `src/config/schema.ts` | `assistantFeatureFlagValues` field definition in `AssistantConfig` (Zod schema) |
659
+ | `src/daemon/handlers/skills.ts` | `handleSkillsList()` uses `resolveSkillStates()` for client responses |
703
660
  | `meta/feature-flags/feature-flag-registry.json` | Unified feature flag registry (repo root) — all declared flags with scope, label, default values, and descriptions |
704
661
  | `src/config/feature-flag-registry.json` | Bundled copy of the unified registry for compiled binary resolution |
705
662
 
@@ -752,21 +709,16 @@ graph LR
752
709
  WORK_ITEMS["work_items<br/>───────────────<br/>Task Queue entries<br/>taskId (FK → tasks)<br/>title, notes, status<br/>priority_tier (0-3), sort_index<br/>last_run_id, last_run_status<br/>source_type, source_id"]
753
710
  end
754
711
 
755
- subgraph "~/.vellum/workspace/data/ipc-blobs/"
756
- BLOBS["*.blob<br/>───────────────<br/>Ephemeral blob files<br/>UUID filenames<br/>Atomic temp+rename writes<br/>Consumed after daemon hydration<br/>Stale sweep every 5min (30min max age)"]
757
- end
758
-
759
712
  subgraph "~/.vellum/ (Root Files)"
760
- SOCK["vellum.sock<br/>Unix domain socket"]
761
713
  TRUST["protected/trust.json<br/>Tool permission rules"]
762
714
  FF_TOKEN["feature-flag-token<br/>Client token for feature-flag API"]
763
715
  end
764
716
 
765
717
  subgraph "~/.vellum/workspace/ (Workspace Files)"
766
- CONFIG["config files<br/>Hot-reloaded by daemon<br/>(includes featureFlags)"]
718
+ CONFIG["config files<br/>Hot-reloaded by daemon<br/>(includes assistantFeatureFlagValues)"]
767
719
  ONBOARD_PLAYBOOKS["onboarding/playbooks/<br/>[channel]_onboarding.md<br/>assistant-updatable checklists"]
768
720
  ONBOARD_REGISTRY["onboarding/playbooks/registry.json<br/>channel-start index for fast-path + reconciliation"]
769
- APPS_STORE["data/apps/<br/><app-id>.json + pages/*.html<br/>prebuilt Home Base seeded here"]
721
+ APPS_STORE["data/apps/<br/><app-id>.json + pages/*.html<br/>User-created apps stored here"]
770
722
  SKILLS_DIR["skills/<br/>managed skill directories<br/>SKILL.md + TOOLS.json + tools/"]
771
723
  end
772
724
 
@@ -791,8 +743,8 @@ graph TB
791
743
  end
792
744
 
793
745
  subgraph "Local Mode"
794
- LOCAL_CLIENT["LocalDaemonClient"]
795
- LOCAL_SOCK["Unix Socket<br/>~/.vellum/vellum.sock"]
746
+ LOCAL_CLIENT["RuntimeClient"]
747
+ LOCAL_HTTP["HTTP API<br/>localhost:RUNTIME_HTTP_PORT"]
796
748
  LOCAL_DAEMON["Local Daemon<br/>(same machine)"]
797
749
  LOCAL_DB["~/.vellum/workspace/data/db/assistant.db"]
798
750
  end
@@ -809,8 +761,8 @@ graph TB
809
761
  AUTH --> PG
810
762
 
811
763
  ROUTES -->|"ASSISTANT_CONNECTION_MODE=local"| LOCAL_CLIENT
812
- LOCAL_CLIENT --> LOCAL_SOCK
813
- LOCAL_SOCK --> LOCAL_DAEMON
764
+ LOCAL_CLIENT --> LOCAL_HTTP
765
+ LOCAL_HTTP --> LOCAL_DAEMON
814
766
  LOCAL_DAEMON --> LOCAL_DB
815
767
 
816
768
  ROUTES -->|"ASSISTANT_CONNECTION_MODE=cloud"| RUNTIME_CLIENT
@@ -821,228 +773,19 @@ graph TB
821
773
 
822
774
  ---
823
775
 
824
- ## IPC ContractSource of Truth and Code Generation
825
-
826
- The TypeScript file `assistant/src/daemon/ipc-contract.ts` is the **single source of truth** for all IPC message types. Swift client models are auto-generated from it.
827
-
828
- ```mermaid
829
- graph LR
830
- subgraph "Source of Truth"
831
- CONTRACT["ipc-contract.ts<br/>───────────────<br/>All message interfaces<br/>ClientMessage union<br/>ServerMessage union"]
832
- end
833
-
834
- subgraph "Generation Pipeline"
835
- TJS["typescript-json-schema<br/>───────────────<br/>TS → JSON Schema"]
836
- GEN["generate-swift.ts<br/>───────────────<br/>JSON Schema → Swift<br/>Codable structs"]
837
- end
838
-
839
- subgraph "Generated Output"
840
- SWIFT["IPCContractGenerated.swift<br/>───────────────<br/>clients/shared/IPC/Generated/<br/>IPC-prefixed Codable structs"]
841
- end
842
-
843
- subgraph "Hand-Written Swift"
844
- ENUMS["IPCMessages.swift<br/>───────────────<br/>ClientMessage / ServerMessage<br/>discriminated union enums<br/>(custom Decodable init)"]
845
- end
846
-
847
- subgraph "Inventory Tracking"
848
- INV_SRC["ipc-contract-inventory.ts<br/>───────────────<br/>AST parser for union members"]
849
- INV_SNAP["ipc-contract-inventory.json<br/>───────────────<br/>Checked-in snapshot"]
850
- end
851
-
852
- subgraph "Enforcement"
853
- CI["CI (GitHub Actions)<br/>bun run check:ipc-generated<br/>bun run ipc:inventory<br/>bun run ipc:check-swift-drift"]
854
- HOOK["Pre-commit hook<br/>same 3 checks on staged<br/>IPC files"]
855
- end
856
-
857
- CONTRACT --> TJS
858
- TJS --> GEN
859
- GEN --> SWIFT
860
- SWIFT --> ENUMS
861
-
862
- CONTRACT --> INV_SRC
863
- INV_SRC --> INV_SNAP
864
-
865
- CONTRACT --> CI
866
- CONTRACT --> HOOK
867
- ```
868
-
869
- ---
870
-
871
- ## IPC Protocol — Message Types
872
-
873
- ```mermaid
874
- graph LR
875
- subgraph "Client → Server"
876
- direction TB
877
- C0["task_submit<br/>task, screenWidth, screenHeight,<br/>attachments, source?:'voice'|'text'"]
878
- C1["cu_session_create<br/>task, attachments"]
879
- C2["cu_observation<br/>axTree, axDiff, screenshot,<br/>secondaryWindows, result/error,<br/>axTreeBlob?, screenshotBlob?"]
880
- C3["ambient_observation<br/>screenContent, requestId"]
881
- C4["session_create<br/>title, threadType?"]
882
- C5["user_message<br/>text, attachments"]
883
- C6["confirmation_response<br/>decision"]
884
- C7["cancel / undo"]
885
- C8["model_get / model_set"]
886
- C9["ping"]
887
- C10["ipc_blob_probe<br/>probeId, nonceSha256"]
888
- C11["work_items_list / work_item_get<br/>work_item_create / work_item_update<br/>work_item_complete / work_item_run_task<br/>(planned)"]
889
- C12["tool_permission_simulate<br/>toolName, input, workingDir?,<br/>isInteractive?, forcePromptSideEffects?,<br/>executionTarget?"]
890
- C13["conversation_search<br/>query, limit?,<br/>maxMessagesPerConversation?"]
891
- C14["ingress_invite<br/>create / list / revoke / redeem"]
892
- C15["contacts<br/>list / get / update_channel"]
893
- end
894
-
895
- SOCKET["Unix Socket<br/>~/.vellum/vellum.sock<br/>───────────────<br/>Newline-delimited JSON<br/>Max 96MB per message<br/>Ping/pong every 30s<br/>Auto-reconnect<br/>1s → 30s backoff"]
896
-
897
- subgraph "Server → Client"
898
- direction TB
899
- S0["task_routed<br/>interactionType, sessionId"]
900
- S1["cu_action<br/>tool, input dict"]
901
- S2["cu_complete<br/>summary"]
902
- S3["cu_error<br/>message"]
903
- S4["assistant_text_delta<br/>streaming text"]
904
- S5["assistant_thinking_delta<br/>streaming thinking"]
905
- S6["message_complete<br/>usage stats, attachments?"]
906
- S7["ambient_result<br/>decision, summary/suggestion"]
907
- S8["confirmation_request<br/>tool, risk_level,<br/>executionTarget"]
908
- S9["memory_recalled<br/>source hits + relation counters<br/>ranking/debug telemetry"]
909
- S10["usage_update / error"]
910
- S11["generation_cancelled"]
911
- S12["message_queued<br/>position in queue"]
912
- S13["message_dequeued<br/>queue drained"]
913
- S14["generation_handoff<br/>sessionId, requestId?,<br/>queuedCount, attachments?"]
914
- S15["trace_event<br/>eventId, sessionId, requestId?,<br/>timestampMs, sequence, kind,<br/>status?, summary, attributes?"]
915
- S16["session_error<br/>sessionId, code,<br/>userMessage, retryable,<br/>debugDetails?"]
916
- S17["ipc_blob_probe_result<br/>probeId, ok,<br/>observedNonceSha256?, reason?"]
917
- S18["session_info<br/>sessionId, title,<br/>correlationId?, threadType?"]
918
- S19["session_title_updated<br/>sessionId, title"]
919
- S20["session_list_response<br/>sessions[]: id, title,<br/>updatedAt, threadType?"]
920
- S21["work_item_status_changed<br/>workItemId, newStatus<br/>(planned push)"]
921
- S22["tool_permission_simulate_response<br/>decision, riskLevel, reason?,<br/>promptPayload?, matchedRuleId?"]
922
- S23["conversation_search_response<br/>query, results[]: conversationId,<br/>title, updatedAt, matchingMessages[]"]
923
- S24["ingress_invite_response<br/>invite / invites"]
924
- S25["contacts_response<br/>contact / contacts"]
925
- end
926
-
927
- C0 --> SOCKET
928
- C1 --> SOCKET
929
- C2 --> SOCKET
930
- C3 --> SOCKET
931
- C4 --> SOCKET
932
- C5 --> SOCKET
933
- C6 --> SOCKET
934
- C7 --> SOCKET
935
- C8 --> SOCKET
936
- C9 --> SOCKET
937
- C10 --> SOCKET
938
- C11 --> SOCKET
939
- C12 --> SOCKET
940
- C13 --> SOCKET
941
- C14 --> SOCKET
942
- C15 --> SOCKET
943
-
944
- SOCKET --> S0
945
- SOCKET --> S1
946
- SOCKET --> S2
947
- SOCKET --> S3
948
- SOCKET --> S4
949
- SOCKET --> S5
950
- SOCKET --> S6
951
- SOCKET --> S7
952
- SOCKET --> S8
953
- SOCKET --> S9
954
- SOCKET --> S10
955
- SOCKET --> S11
956
- SOCKET --> S12
957
- SOCKET --> S13
958
- SOCKET --> S14
959
- SOCKET --> S15
960
- SOCKET --> S16
961
- SOCKET --> S17
962
- SOCKET --> S18
963
- SOCKET --> S19
964
- SOCKET --> S20
965
- SOCKET --> S21
966
- SOCKET --> S22
967
- SOCKET --> S24
968
- SOCKET --> S25
969
- ```
970
-
971
- ---
972
-
973
- ## Blob Transport — Large Payload Side-Channel
974
-
975
- CU observations can carry large payloads (screenshots as JPEG, AX trees as UTF-8 text). Instead of embedding these inline as base64/text in newline-delimited JSON IPC messages, the blob transport offloads them to local files and sends only lightweight references over the socket.
976
-
977
- ### Probe Mechanism
978
-
979
- Blob transport is opt-in per connection. On every macOS socket connect, the client writes a random nonce file to the blob directory and sends an `ipc_blob_probe` message with the SHA-256 of the nonce. The daemon reads the file, computes the hash, and responds with `ipc_blob_probe_result`. If hashes match, the client sets `isBlobTransportAvailable = true` for that connection. The flag resets to `false` on disconnect or reconnect.
980
-
981
- On iOS (HTTP+SSE connections via the gateway), blob transport is not applicable — `isBlobTransportAvailable` stays `false` and inline payloads are always used. Over SSH-forwarded Unix sockets on macOS, the probe runs but fails because the client and daemon don't share a filesystem, so blob transport stays disabled and inline payloads are used transparently.
982
-
983
- ### Blob Directory
984
-
985
- All blobs live at `~/.vellum/workspace/data/ipc-blobs/`. Filenames are `${uuid}.blob`. The daemon ensures this directory exists on startup. Both client and daemon use atomic writes (temp file + rename) to prevent partial reads.
986
-
987
- ### Blob Reference
988
-
989
- ```
990
- IpcBlobRef {
991
- id: string // UUID v4
992
- kind: "ax_tree" | "screenshot_jpeg"
993
- encoding: "utf8" | "binary"
994
- byteLength: number
995
- sha256?: string // SHA-256 hex digest for integrity check
996
- }
997
- ```
998
-
999
- ### Transport Decision Flow
1000
-
1001
- ```mermaid
1002
- graph TB
1003
- HAS_DATA{"Has large payload?"}
1004
- BLOB_AVAIL{"isBlobTransportAvailable?"}
1005
- THRESHOLD{"Above threshold?<br/>(screenshots: always,<br/>AX trees: >8KB)"}
1006
- WRITE_BLOB["Write blob file<br/>atomic temp+rename"]
1007
- WRITE_OK{"Write succeeded?"}
1008
- SEND_REF["Send IpcBlobRef<br/>(inline field = nil)"]
1009
- SEND_INLINE["Send inline<br/>(base64 / text)"]
1010
-
1011
- HAS_DATA -->|Yes| BLOB_AVAIL
1012
- HAS_DATA -->|No| SEND_INLINE
1013
- BLOB_AVAIL -->|Yes| THRESHOLD
1014
- BLOB_AVAIL -->|No| SEND_INLINE
1015
- THRESHOLD -->|Yes| WRITE_BLOB
1016
- THRESHOLD -->|No| SEND_INLINE
1017
- WRITE_BLOB --> WRITE_OK
1018
- WRITE_OK -->|Yes| SEND_REF
1019
- WRITE_OK -->|No| SEND_INLINE
1020
- ```
1021
-
1022
- ### Daemon Hydration
1023
-
1024
- When the daemon receives a CU observation with blob refs, it attempts blob-first hydration before the CU session processes the observation:
1025
-
1026
- 1. Validate the blob ref's `kind` and `encoding` match the expected field (`axTreeBlob` must be `kind=ax_tree, encoding=utf8`; `screenshotBlob` must be `kind=screenshot_jpeg, encoding=binary`).
1027
- 2. Verify the blob file is a regular file (not a symlink) and its realpath stays within the blob directory.
1028
- 3. Read the blob file, verify actual size matches `byteLength`, and check optional `sha256`.
1029
- 4. For screenshots: base64-encode the bytes into the `screenshot` field.
1030
- 5. For AX trees: decode UTF-8 bytes into the `axTree` field.
1031
- 6. Delete the consumed blob file.
776
+ ## Client-Server CommunicationHTTP + SSE
1032
777
 
1033
- **Fallback behavior**: If both a blob ref and an inline field are present and blob hydration succeeds, the blob value takes precedence. If blob hydration fails and an inline fallback exists, the inline value is used. If blob hydration fails and no inline fallback exists, the daemon sends a `cu_error` and does not forward the observation to the session.
778
+ All client-server communication uses HTTP for request/response operations and Server-Sent Events (SSE) for streaming server-to-client events. The runtime HTTP server (`RUNTIME_HTTP_PORT`, default 7821) is the sole transport.
1034
779
 
1035
- ### Cleanup
780
+ **Client → Server (HTTP POST):** Clients send messages, session operations, configuration changes, and approval decisions via HTTP endpoints (e.g., `POST /v1/messages`, `POST /v1/confirm`, `POST /v1/sessions`).
1036
781
 
1037
- - **Consumed blobs**: Deleted immediately after successful hydration.
1038
- - **Stale sweep**: The daemon runs a periodic sweep (every 5 minutes) to delete blob files older than 30 minutes, catching orphans from failed sends or crashes.
1039
- - **Size limits**: Screenshot blobs are capped at 10MB, AX tree blobs at 2MB. Oversized blobs are rejected.
782
+ **Server Client (SSE):** The daemon streams events to clients via `GET /v1/events`. All agent events (text deltas, tool execution, confirmations, session state changes) are published through the `assistantEventHub` and delivered as SSE events.
1040
783
 
1041
784
  ---
1042
785
 
1043
786
  ## Session Errors vs Global Errors
1044
787
 
1045
- The daemon emits two distinct error message types over IPC:
788
+ The daemon emits two distinct error message types via SSE:
1046
789
 
1047
790
  | Message type | Scope | Purpose | Payload |
1048
791
  | --------------- | -------------- | -------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
@@ -1072,7 +815,7 @@ Classification uses a two-tier strategy:
1072
815
  1. **Structured provider errors**: If the error is a `ProviderError` with a `statusCode`, the status code determines the category deterministically — `429` maps to `PROVIDER_RATE_LIMIT` (retryable), `5xx` to `PROVIDER_API` (retryable), other `4xx` to `PROVIDER_API` (not retryable).
1073
816
  2. **Regex fallback**: For non-provider errors or `ProviderError` without a status code, regex pattern matching against the error message detects network failures, rate limits, and API errors. Phase-specific overrides handle queue and regeneration contexts.
1074
817
 
1075
- Debug details are capped at 4,000 characters to prevent oversized IPC payloads.
818
+ Debug details are capped at 4,000 characters to prevent oversized payloads.
1076
819
 
1077
820
  ### Error → Toast → Recovery Flow
1078
821
 
@@ -1097,14 +840,14 @@ sequenceDiagram
1097
840
  UI->>VM: retryAfterSessionError()
1098
841
  VM->>VM: dismissSessionError()<br/>+ regenerateLastMessage()
1099
842
  VM->>DC: regenerate {sessionId}
1100
- DC->>Daemon: IPC
843
+ DC->>Daemon: HTTP POST /v1/messages
1101
844
  else User taps Dismiss
1102
845
  UI->>VM: dismissSessionError()
1103
846
  VM->>VM: clear sessionError + errorText
1104
847
  end
1105
848
  ```
1106
849
 
1107
- 1. **Daemon** encounters a session-scoped failure, classifies it via `classifySessionError()`, and sends a `session_error` IPC message with the session ID, typed error code, user-facing message, retryable flag, and optional debug details. Session-scoped failures emit _only_ `session_error` (never the generic `error` type) to prevent cross-session bleed.
850
+ 1. **Daemon** encounters a session-scoped failure, classifies it via `classifySessionError()`, and sends a `session_error` SSE event with the session ID, typed error code, user-facing message, retryable flag, and optional debug details. Session-scoped failures emit _only_ `session_error` (never the generic `error` type) to prevent cross-session bleed.
1108
851
  2. **ChatViewModel** receives the error via DaemonClient's `subscribe()` stream (each view model gets an independent stream), sets the `sessionError` property, and transitions out of the streaming/loading state so the UI is interactive. If the error arrives during an active cancel (`wasCancelling == true`), it is suppressed — cancel only shows `generation_cancelled` behavior.
1109
852
  3. **ChatView** observes the published `sessionError` and displays an actionable toast with a category-specific icon and accent color:
1110
853
  - **Retry** (shown when `retryable` is true): calls `retryAfterSessionError()`, which clears the error and sends a `regenerate` message to the daemon.
@@ -1363,9 +1106,9 @@ graph TB
1363
1106
  - macOS UI shows Inspect and Delete controls for managed skills only (source = "managed").
1364
1107
  - `skill_load` validates the recursive include graph (via `include-graph.ts`) before emitting output. Missing children and cycles produce `isError: true` with no `<loaded_skill>` marker. Valid includes produce an "Included Skills (immediate)" metadata section showing child ID, name, description, and path.
1365
1108
 
1366
- ### Skills Authoring via IPC
1109
+ ### Skills Authoring via HTTP
1367
1110
 
1368
- The Skills page in the macOS client can author managed skills through daemon IPC without going through the agent loop:
1111
+ The Skills page in the macOS client can author managed skills through the daemon HTTP API without going through the agent loop:
1369
1112
 
1370
1113
  1. **Draft** (`skills_draft`): The client sends source text (with optional YAML frontmatter). The daemon parses frontmatter for metadata fields (skillId, name, description, emoji), fills missing fields via a latency-optimized LLM call, and falls back to deterministic heuristics if the provider is unavailable. Returns `skills_draft_response` with the complete draft.
1371
1114
  2. **Create** (`skills_create`): The client sends finalized skill metadata and body. The daemon calls `createManagedSkill()` from `managed-store.ts`, auto-enables the skill in config, and broadcasts `skills_state_changed`.
@@ -1463,7 +1206,7 @@ graph TB
1463
1206
  end
1464
1207
 
1465
1208
  subgraph "Per-Turn Projection (session-skill-tools.ts)"
1466
- DERIVE["deriveActiveSkillIds(history)<br/>scan all messages for markers"]
1209
+ DERIVE["deriveActiveSkills(history)<br/>scan all messages for markers"]
1467
1210
  UNION["Union: context-derived ∪ preactivated"]
1468
1211
  DIFF["Diff vs previous turn"]
1469
1212
  UNREGISTER["unregisterSkillTools(removedId)<br/>tear down stale tools"]
@@ -1535,7 +1278,7 @@ graph TB
1535
1278
  | `assistant/src/config/skills.ts` | Skill catalog loading: bundled, managed, workspace, extra directories |
1536
1279
  | `assistant/src/config/bundled-skills/` | Bundled skill directories (browser, gmail, claude-code, computer-use, weather, etc.) |
1537
1280
  | `assistant/src/skills/tool-manifest.ts` | `TOOLS.json` parser and validator |
1538
- | `assistant/src/skills/active-skill-tools.ts` | `deriveActiveSkillIds()` — scans history for `<loaded_skill>` markers |
1281
+ | `assistant/src/skills/active-skill-tools.ts` | `deriveActiveSkills()` — scans history for `<loaded_skill>` markers |
1539
1282
  | `assistant/src/skills/include-graph.ts` | Include graph builder: `indexCatalogById()`, `validateIncludes()`, cycle/missing detection |
1540
1283
  | `assistant/src/daemon/session-skill-tools.ts` | `projectSkillTools()` — per-turn projection, register/unregister lifecycle |
1541
1284
  | `assistant/src/tools/skills/skill-tool-factory.ts` | `createSkillToolsFromManifest()` — manifest entries to Tool objects |
@@ -1698,7 +1441,7 @@ For `bash` and `host_bash` tool invocations, the permission system uses parser-d
1698
1441
 
1699
1442
  ### Prompt UX
1700
1443
 
1701
- When a permission prompt is sent to the client (via `confirmation_request` IPC message), it includes:
1444
+ When a permission prompt is sent to the client (via `confirmation_request` SSE event), it includes:
1702
1445
 
1703
1446
  | Field | Content |
1704
1447
  | ------------------ | --------------------------------------------------- |
@@ -1723,7 +1466,7 @@ File tool candidates include canonical (symlink-resolved) absolute paths via `no
1723
1466
  | `assistant/src/permissions/checker.ts` | `classifyRisk()`, `check()`, `buildCommandCandidates()`, allowlist/scope generation |
1724
1467
  | `assistant/src/permissions/shell-identity.ts` | `analyzeShellCommand()`, `deriveShellActionKeys()`, `buildShellCommandCandidates()`, `buildShellAllowlistOptions()` — parser-based shell command identity and action key derivation |
1725
1468
  | `assistant/src/permissions/trust-store.ts` | Rule persistence, `findHighestPriorityRule()`, execution-target matching, starter bundle |
1726
- | `assistant/src/permissions/prompter.ts` | IPC prompt flow: `confirmation_request` → `confirmation_response` |
1469
+ | `assistant/src/permissions/prompter.ts` | Prompt flow: `confirmation_request` (SSE) → `confirmation_response` (HTTP POST) |
1727
1470
  | `assistant/src/permissions/defaults.ts` | Default rule templates (system ask rules for host tools, CU, etc.) |
1728
1471
  | `assistant/src/skills/version-hash.ts` | `computeSkillVersionHash()` — deterministic SHA-256 of skill source files |
1729
1472
  | `assistant/src/skills/path-classifier.ts` | `isSkillSourcePath()`, `normalizeFilePath()`, skill root detection |
@@ -1733,7 +1476,7 @@ File tool candidates include canonical (symlink-resolved) absolute paths via `no
1733
1476
 
1734
1477
  ### Permission Simulation (Tool Permission Tester)
1735
1478
 
1736
- The `tool_permission_simulate` IPC message lets clients dry-run a tool invocation through the full permission evaluation pipeline without actually executing the tool or mutating daemon state. The macOS Settings panel exposes this as a "Tool Permission Tester" UI.
1479
+ The `tool_permission_simulate` HTTP endpoint lets clients dry-run a tool invocation through the full permission evaluation pipeline without actually executing the tool or mutating daemon state. The macOS Settings panel exposes this as a "Tool Permission Tester" UI.
1737
1480
 
1738
1481
  **Simulation semantics:**
1739
1482
 
@@ -1829,7 +1572,7 @@ sequenceDiagram
1829
1572
  User->>Chat: send message while busy
1830
1573
  Chat->>VM: enqueue message
1831
1574
  VM->>DC: user_message
1832
- DC->>Daemon: IPC
1575
+ DC->>Daemon: HTTP
1833
1576
  Daemon-->>DC: message_queued (position)
1834
1577
  DC-->>VM: show queue status
1835
1578
 
@@ -1852,7 +1595,7 @@ sequenceDiagram
1852
1595
 
1853
1596
  ## Trace System — Debug Panel Data Flow
1854
1597
 
1855
- The trace system provides real-time observability of daemon session internals. Each session creates a `TraceEmitter` that emits structured `trace_event` IPC messages as the session processes requests, makes LLM calls, and executes tools.
1598
+ The trace system provides real-time observability of daemon session internals. Each session creates a `TraceEmitter` that emits structured `trace_event` SSE events as the session processes requests, makes LLM calls, and executes tools.
1856
1599
 
1857
1600
  ```mermaid
1858
1601
  sequenceDiagram
@@ -1869,7 +1612,7 @@ sequenceDiagram
1869
1612
 
1870
1613
  User->>Chat: send message
1871
1614
  Chat->>DC: user_message
1872
- DC->>Daemon: IPC
1615
+ DC->>Daemon: HTTP
1873
1616
 
1874
1617
  Daemon->>TE: emit(request_received)
1875
1618
  TE-->>DC: trace_event (request_received)
@@ -1934,9 +1677,9 @@ Events emitted during a session lifecycle:
1934
1677
 
1935
1678
  ### Architecture
1936
1679
 
1937
- - **TraceEmitter** (daemon, per-session): Constructed with a `sessionId` and a `sendToClient` callback. Maintains a monotonic sequence counter for stable ordering. Truncates summaries to 200 chars and attribute values to 500 chars. Each call to `emit()` sends a `trace_event` IPC message to the connected client.
1680
+ - **TraceEmitter** (daemon, per-session): Constructed with a `sessionId` and a `sendToClient` callback. Maintains a monotonic sequence counter for stable ordering. Truncates summaries to 200 chars and attribute values to 500 chars. Each call to `emit()` sends a `trace_event` SSE event to connected clients.
1938
1681
  - **ToolTraceListener** (daemon): Subscribes to the session's `EventBus` via `onAny()` and translates tool domain events (`tool.execution.started`, `tool.execution.finished`, `tool.execution.failed`, `tool.permission.requested`, `tool.permission.decided`, `tool.secret.detected`) into trace events through the `TraceEmitter`.
1939
- - **DaemonClient** (Swift, shared): Decodes `trace_event` IPC messages into `TraceEventMessage` structs and invokes the `onTraceEvent` callback.
1682
+ - **DaemonClient** (Swift, shared): Decodes `trace_event` SSE events into `TraceEventMessage` structs and invokes the `onTraceEvent` callback.
1940
1683
  - **TraceStore** (Swift, macOS): `@MainActor ObservableObject` that ingests `TraceEventMessage` structs. Deduplicates by `eventId`, maintains stable sort order (sequence, then timestampMs, then insertion order), groups events by session and requestId, and enforces a retention cap of 5,000 events per session. Each request group is classified with a terminal status: `completed` (via `message_complete`), `cancelled` (via `generation_cancelled`), `handedOff` (via `generation_handoff`), `error` (via `request_error` or any event with `status == "error"`), or `active` (no terminal event yet).
1941
1684
  - **DebugPanel** (Swift, macOS): SwiftUI view that observes `TraceStore`. Displays a metrics strip (request count, LLM calls, total tokens, average latency, tool failures) and a `TraceTimelineView` showing events grouped by requestId with color-coded status indicators. The timeline auto-scrolls to new events while the user is at the bottom; scrolling up pauses auto-scroll and shows a "Jump to bottom" button that resumes it.
1942
1685
 
@@ -1946,7 +1689,7 @@ Events emitted during a session lifecycle:
1946
1689
 
1947
1690
  ## Assistant Events — SSE Transport Layer
1948
1691
 
1949
- The assistant-events system provides a single, shared publish path that fans out to both the Unix socket IPC layer (native clients) and an HTTP SSE endpoint (web/remote clients). There is no separate message schema for SSE — the `ServerMessage` payload is wrapped in an `AssistantEvent` envelope and serialised as JSON.
1692
+ The assistant-events system provides a single, shared publish path that fans out to all connected clients via HTTP SSE. The `ServerMessage` payload is wrapped in an `AssistantEvent` envelope and serialised as JSON.
1950
1693
 
1951
1694
  ### Data Flow
1952
1695
 
@@ -1954,7 +1697,7 @@ The assistant-events system provides a single, shared publish path that fans out
1954
1697
  graph TB
1955
1698
  subgraph "Event Sources"
1956
1699
  direction TB
1957
- IPC_DAEMON["Daemon IPC send paths<br/>(daemon/server.ts)"]
1700
+ SESSION["Session process<br/>(session-process.ts)"]
1958
1701
  HTTP_RUN["HTTP Run path<br/>(run-orchestrator.ts)"]
1959
1702
  end
1960
1703
 
@@ -1962,9 +1705,8 @@ graph TB
1962
1705
  HUB["AssistantEventHub<br/>(assistant-event-hub.ts)<br/>──────────────────────<br/>maxSubscribers: 100<br/>FIFO eviction on overflow<br/>Synchronous fan-out"]
1963
1706
  end
1964
1707
 
1965
- subgraph "Transports"
1708
+ subgraph "SSE Transport"
1966
1709
  SSE_ROUTE["SSE Route<br/>GET /v1/events?conversationKey=...<br/>(events-routes.ts)<br/>──────────────────────<br/>ReadableStream + CountQueuingStrategy(16)<br/>Heartbeat every 30 s<br/>Slow-consumer shed"]
1967
- SOCK["Unix Socket<br/>(daemon/session-surfaces.ts)"]
1968
1710
  end
1969
1711
 
1970
1712
  subgraph "Clients"
@@ -1973,13 +1715,12 @@ graph TB
1973
1715
  WEB["Web / Remote clients<br/>(EventSource / fetch)"]
1974
1716
  end
1975
1717
 
1976
- IPC_DAEMON -->|"buildAssistantEvent()"| HUB
1718
+ SESSION -->|"buildAssistantEvent()"| HUB
1977
1719
  HTTP_RUN -->|"buildAssistantEvent()"| HUB
1978
- IPC_DAEMON --> SOCK
1979
1720
 
1980
1721
  HUB -->|"subscriber callback"| SSE_ROUTE
1981
1722
 
1982
- SOCK --> MACOS
1723
+ SSE_ROUTE --> MACOS
1983
1724
  SSE_ROUTE --> IOS
1984
1725
  SSE_ROUTE --> WEB
1985
1726
  ```
@@ -1994,7 +1735,7 @@ Every event published through the hub is wrapped in an `AssistantEvent` (defined
1994
1735
  | `assistantId` | `string` | Logical assistant identifier (`"self"` for HTTP runs) |
1995
1736
  | `sessionId` | `string?` | Resolved conversation ID when available |
1996
1737
  | `emittedAt` | `string` (ISO-8601) | Server-side timestamp |
1997
- | `message` | `ServerMessage` | Unchanged IPC outbound message — no schema fork |
1738
+ | `message` | `ServerMessage` | The outbound message payload |
1998
1739
 
1999
1740
  ### SSE Frame Format
2000
1741
 
@@ -2024,12 +1765,12 @@ Keep-alive heartbeats (every 30 s by default):
2024
1765
 
2025
1766
  ### Key Source Files
2026
1767
 
2027
- | File | Role |
2028
- | ----------------------------------------------- | ----------------------------------------------------------------------------------- |
2029
- | `assistant/src/runtime/assistant-event.ts` | `AssistantEvent` type, `buildAssistantEvent()` factory, SSE framing helpers |
2030
- | `assistant/src/runtime/assistant-event-hub.ts` | `AssistantEventHub` class and process-level singleton |
2031
- | `assistant/src/runtime/routes/events-routes.ts` | `handleSubscribeAssistantEvents()` — SSE route handler |
2032
- | `assistant/src/daemon/server.ts` | IPC send/broadcast paths that publish to the hub (`send` → `publishAssistantEvent`) |
1768
+ | File | Role |
1769
+ | ----------------------------------------------- | ------------------------------------------------------------------------------ |
1770
+ | `assistant/src/runtime/assistant-event.ts` | `AssistantEvent` type, `buildAssistantEvent()` factory, SSE framing helpers |
1771
+ | `assistant/src/runtime/assistant-event-hub.ts` | `AssistantEventHub` class and process-level singleton |
1772
+ | `assistant/src/runtime/routes/events-routes.ts` | `handleSubscribeAssistantEvents()` — SSE route handler |
1773
+ | `assistant/src/daemon/server.ts` | Session event paths that publish to the hub (`send` → `publishAssistantEvent`) |
2033
1774
 
2034
1775
  ---
2035
1776
 
@@ -2040,7 +1781,7 @@ The notification module (`assistant/src/notifications/`) uses a signal-based arc
2040
1781
  ```
2041
1782
  Producer → NotificationSignal → Candidate Generation → Decision Engine (LLM) → Deterministic Checks → Broadcaster → Conversation Pairing → Adapters → Delivery
2042
1783
  ↑ ↓
2043
- Preference Summary notification_thread_created IPC
1784
+ Preference Summary notification_thread_created SSE event
2044
1785
  Thread Candidates (creation-only — not emitted on reuse)
2045
1786
  ```
2046
1787
 
@@ -2052,7 +1793,7 @@ Producer → NotificationSignal → Candidate Generation → Decision Engine (LL
2052
1793
  - **`conversationStrategy`** — how the notification pipeline materializes conversations for the channel:
2053
1794
  - `start_new_conversation` — creates a fresh conversation per delivery (e.g. vellum desktop/mobile threads)
2054
1795
  - `continue_existing_conversation` — intended to append to an existing channel-scoped conversation; currently materializes a background audit conversation per delivery (e.g. Telegram)
2055
- - `not_deliverable` — channel cannot receive notifications (e.g. voice)
1796
+ - `not_deliverable` — channel cannot receive notifications (e.g. phone)
2056
1797
 
2057
1798
  Helper functions: `getDeliverableChannels()`, `getChannelPolicy()`, `isNotificationDeliverable()`, `getConversationStrategy()`.
2058
1799
 
@@ -2075,23 +1816,23 @@ The pairing function (`pairDeliveryWithConversation`) is resilient — errors ar
2075
1816
 
2076
1817
  The notification pipeline uses a single conversation materialization path across producers:
2077
1818
 
2078
- 1. **Canonical pipeline** (`emitNotificationSignal` → decision engine → broadcaster → conversation pairing → adapters): The broadcaster pairs each delivery with a conversation, then dispatches a `notification_intent` IPC event via the Vellum adapter. The IPC payload includes `deepLinkMetadata` (e.g. `{ conversationId, messageId }`) so the macOS/iOS client can deep-link to the relevant context when the user taps the notification. When `messageId` is present, the client scrolls to that specific message within the thread (message-level anchoring).
1819
+ 1. **Canonical pipeline** (`emitNotificationSignal` → decision engine → broadcaster → conversation pairing → adapters): The broadcaster pairs each delivery with a conversation, then dispatches a `notification_intent` SSE event via the Vellum adapter. The payload includes `deepLinkMetadata` (e.g. `{ conversationId, messageId }`) so the macOS/iOS client can deep-link to the relevant context when the user taps the notification. When `messageId` is present, the client scrolls to that specific message within the thread (message-level anchoring).
2079
1820
  2. **Guardian bookkeeping** (`dispatchGuardianQuestion`): Guardian dispatch creates `guardian_action_request` / `guardian_action_delivery` audit rows derived from pipeline delivery results and the per-dispatch `onThreadCreated` callback — there is no separate thread-creation path.
2080
1821
 
2081
- ### Thread Surfacing via `notification_thread_created` IPC (Creation-Only)
1822
+ ### Thread Surfacing via `notification_thread_created` (Creation-Only)
2082
1823
 
2083
- The `notification_thread_created` IPC event is emitted **only when a brand-new conversation is created** by the broadcaster. Reusing an existing thread does not trigger this event — the macOS/iOS client already knows about the conversation from the original creation. This is enforced in `broadcaster.ts` by gating on `pairing.createdNewConversation === true`.
1824
+ The `notification_thread_created` SSE event is emitted **only when a brand-new conversation is created** by the broadcaster. Reusing an existing thread does not trigger this event — the macOS/iOS client already knows about the conversation from the original creation. This is enforced in `broadcaster.ts` by gating on `pairing.createdNewConversation === true`.
2084
1825
 
2085
- When a new vellum notification thread is created (strategy `start_new_conversation`), the broadcaster emits the IPC event **immediately** (before waiting for slower channel deliveries like Telegram). This pushes the thread to the macOS/iOS client so it can display the notification thread in the sidebar and deep-link to it.
1826
+ When a new vellum notification thread is created (strategy `start_new_conversation`), the broadcaster emits the event **immediately** (before waiting for slower channel deliveries like Telegram). This pushes the thread to the macOS/iOS client so it can display the notification thread in the sidebar and deep-link to it.
2086
1827
 
2087
- ### IPC Thread-Created Events
1828
+ ### Thread-Created Events
2088
1829
 
2089
- Two IPC push events surface new threads in the macOS/iOS client sidebar:
1830
+ Two SSE push events surface new threads in the macOS/iOS client sidebar:
2090
1831
 
2091
1832
  - **`notification_thread_created`** — Emitted by `broadcaster.ts` when a notification delivery **creates** a new vellum conversation (strategy `start_new_conversation`, `createdNewConversation: true`). **Not** emitted when a thread is reused. Payload: `{ conversationId, title, sourceEventName }`.
2092
1833
  - **`task_run_thread_created`** — Emitted by `work-item-runner.ts` when a task run creates a conversation. Payload: `{ conversationId, workItemId, title }`.
2093
1834
 
2094
- All events follow the same pattern: the daemon creates a server-side conversation, persists an initial message, and broadcasts the IPC event so the macOS `ThreadManager` can create a visible thread in the sidebar.
1835
+ All events follow the same pattern: the daemon creates a server-side conversation, persists an initial message, and broadcasts the SSE event so the macOS `ThreadManager` can create a visible thread in the sidebar.
2095
1836
 
2096
1837
  ### Thread Routing Decision Flow
2097
1838
 
@@ -2101,7 +1842,7 @@ The decision engine produces per-channel thread actions using a candidate-driven
2101
1842
  2. **LLM decision**: The candidate set is serialized into the system prompt. The LLM chooses `start_new` or `reuse_existing` (with a candidate `conversationId`) per channel.
2102
1843
  3. **Strict validation** (`validateThreadActions`): Reuse targets must exist in the candidate set. Invalid targets are downgraded to `start_new`.
2103
1844
  4. **Pairing execution**: `pairDeliveryWithConversation` executes the thread action — appending to an existing conversation on reuse, creating a new one otherwise.
2104
- 5. **IPC gating**: `notification_thread_created` fires only on actual creation, not on reuse.
1845
+ 5. **Creation-only gating**: `notification_thread_created` fires only on actual creation, not on reuse.
2105
1846
  6. **Audit trail**: Thread actions are persisted in both `notification_decisions.validation_results` and `notification_deliveries` columns (`thread_action`, `thread_target_conversation_id`, `thread_decision_fallback_used`).
2106
1847
 
2107
1848
  ### Guardian Call Thread Affinity
@@ -2121,7 +1862,7 @@ When the decision engine routes multiple guardian questions to the same conversa
2121
1862
  - **Multiple pending deliveries**: The guardian must prefix their reply with the 6-char hex request code (e.g. `A1B2C3 yes, allow it`). Case-insensitive matching.
2122
1863
  - **No match**: A disambiguation message is sent listing all active request codes.
2123
1864
 
2124
- This invariant is enforced identically on mac/vellum (`session-process.ts`), Telegram, and SMS (`inbound-message-handler.ts`). All disambiguation messages are generated through the guardian action message composer (LLM with deterministic fallback).
1865
+ This invariant is enforced identically on mac/vellum (`session-process.ts`) and Telegram (`inbound-message-handler.ts`). All disambiguation messages are generated through the guardian action message composer (LLM with deterministic fallback).
2125
1866
 
2126
1867
  ### Reminder Routing Metadata
2127
1868
 
@@ -2131,11 +1872,10 @@ Reminders carry optional `routingIntent` (`single_channel` | `multi_channel` | `
2131
1872
 
2132
1873
  Notifications are delivered to three channel types:
2133
1874
 
2134
- - **Vellum (always connected)**: Local IPC via the daemon's broadcast mechanism. The `VellumAdapter` emits a `notification_intent` message with rendered copy and optional `deepLinkMetadata` (includes `conversationId` for thread navigation and `messageId` for message-level scroll anchoring).
1875
+ - **Vellum (always connected)**: SSE via the daemon's broadcast mechanism. The `VellumAdapter` emits a `notification_intent` message with rendered copy and optional `deepLinkMetadata` (includes `conversationId` for thread navigation and `messageId` for message-level scroll anchoring).
2135
1876
  - **Telegram (when guardian binding exists)**: HTTP POST to the gateway's `/deliver/telegram` endpoint. Requires an active guardian binding for the assistant.
2136
- - **SMS (when guardian binding exists)**: HTTP POST to the gateway's `/deliver/sms` endpoint. Follows the same pattern as Telegram; the `SmsAdapter` sends text-only messages via the Twilio Messages API. The `assistantId` is threaded through the delivery payload for multi-assistant phone number resolution.
2137
1877
 
2138
- Connected channels are resolved at signal emission time: vellum is always included, and binding-based channels (Telegram, SMS) are included only when an active guardian binding exists for the assistant.
1878
+ Connected channels are resolved at signal emission time: vellum is always included, and binding-based channels (Telegram) are included only when an active guardian binding exists for the assistant.
2139
1879
 
2140
1880
  **Key modules:**
2141
1881
 
@@ -2145,13 +1885,12 @@ Connected channels are resolved at signal emission time: vellum is always includ
2145
1885
  | `assistant/src/notifications/emit-signal.ts` | Single entry point for all producers; orchestrates the full pipeline |
2146
1886
  | `assistant/src/notifications/decision-engine.ts` | LLM-based routing decisions with deterministic fallback |
2147
1887
  | `assistant/src/notifications/deterministic-checks.ts` | Hard invariant checks (dedupe, source-active suppression, channel availability) |
2148
- | `assistant/src/notifications/broadcaster.ts` | Dispatches decisions to channel adapters; emits `notification_thread_created` IPC (creation-only) |
1888
+ | `assistant/src/notifications/broadcaster.ts` | Dispatches decisions to channel adapters; emits `notification_thread_created` SSE event (creation-only) |
2149
1889
  | `assistant/src/notifications/conversation-pairing.ts` | Materializes conversation + message per delivery; executes thread reuse decisions |
2150
1890
  | `assistant/src/notifications/thread-candidates.ts` | Builds per-channel candidate set of recent conversations for the decision engine |
2151
- | `assistant/src/notifications/adapters/macos.ts` | Vellum adapter — broadcasts `notification_intent` via IPC with deep-link metadata |
1891
+ | `assistant/src/notifications/adapters/macos.ts` | Vellum adapter — broadcasts `notification_intent` via SSE with deep-link metadata |
2152
1892
  | `assistant/src/notifications/adapters/telegram.ts` | Telegram adapter — POSTs to gateway `/deliver/telegram` |
2153
- | `assistant/src/notifications/adapters/sms.ts` | SMS adapter POSTs to gateway `/deliver/sms` via Twilio Messages API |
2154
- | `assistant/src/notifications/destination-resolver.ts` | Resolves per-channel endpoints (vellum IPC, Telegram chat ID from guardian binding) |
1893
+ | `assistant/src/notifications/destination-resolver.ts` | Resolves per-channel endpoints (vellum SSE, Telegram chat ID from guardian binding) |
2155
1894
  | `assistant/src/notifications/copy-composer.ts` | Template-based fallback copy when LLM copy is unavailable |
2156
1895
  | `assistant/src/notifications/preference-extractor.ts` | Detects preference statements in conversation messages |
2157
1896
  | `assistant/src/notifications/preferences-store.ts` | CRUD for user notification preferences |
@@ -2188,7 +1927,6 @@ Connected channels are resolved at signal emission time: vellum is always includ
2188
1927
  | Trace events | In-memory (TraceStore) | Structured events | Swift ObservableObject | Max 5,000 per session, ephemeral |
2189
1928
  | Media embed settings | `~/.vellum/workspace/config.json` (`ui.mediaEmbeds`) | JSON | `WorkspaceConfigIO` (atomic merge) | Permanent |
2190
1929
  | Media embed MIME cache | In-memory (`ImageMIMEProbe`) | `NSCache` (500 entries) | HTTP HEAD | Ephemeral; cleared on app restart |
2191
- | IPC blob payloads | `~/.vellum/workspace/data/ipc-blobs/` | Binary files (UUID names) | File I/O (atomic write) | Ephemeral; consumed on hydration, stale sweep every 5min |
2192
1930
  | Tasks & task runs | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent |
2193
1931
  | Work items (Task Queue) | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; archived items retained |
2194
1932
  | Recurrence schedules & runs | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; supports cron and RRULE syntax |
@@ -2199,7 +1937,7 @@ Connected channels are resolved at signal emission time: vellum is always includ
2199
1937
  | Call sessions, events, pending questions | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent, cascade on session delete |
2200
1938
  | Active call controllers | In-memory (CallState) | Map<callSessionId, CallController> | Manual lifecycle | Ephemeral; cleared on call end or destroy |
2201
1939
  | Guardian bindings | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; revoked bindings retained |
2202
- | Guardian verification challenges | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; consumed/expired challenges retained |
1940
+ | Channel verification sessions | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; consumed/expired sessions retained |
2203
1941
  | Guardian approval requests | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; decision outcome retained |
2204
1942
  | Contact invites | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; token hash stored, raw token never persisted |
2205
1943
  | Contacts & channels | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; revoked/blocked contacts retained |
@@ -2207,7 +1945,6 @@ Connected channels are resolved at signal emission time: vellum is always includ
2207
1945
  | Notification decisions | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; FK to notification_events |
2208
1946
  | Notification deliveries | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; FK to notification_decisions |
2209
1947
  | Notification preferences | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; per-assistant conversational preferences |
2210
- | IPC transport | `~/.vellum/vellum.sock` | Unix domain socket | NWConnection (Swift) / Bun net | Ephemeral |
2211
1948
 
2212
1949
  ### Sensitive Tool Output Placeholder Substitution
2213
1950
 
@@ -2246,7 +1983,7 @@ The guardian trust system uses a three-valued `TrustClass` — `'guardian'`, `'t
2246
1983
 
2247
1984
  **Explicit trust gates:** `trustClass` is a **required** field in `ToolContext` (in `src/tools/types.ts`). Every tool execution must carry a trust classification — the field is not optional. This ensures trust-gated tool policies (guardian control-plane restrictions, host-tool blocking for untrusted actors) cannot be bypassed by omitting the classification.
2248
1985
 
2249
- **Guardian bindings** (in `src/memory/channel-guardian-store.ts`) always carry `guardianPrincipalId: string` as a required, non-null field. A binding without a principal ID is invalid and cannot be created.
1986
+ **Guardian bindings** (in `src/memory/channel-verification-sessions.ts`) always carry `guardianPrincipalId: string` as a required, non-null field. A binding without a principal ID is invalid and cannot be created.
2250
1987
 
2251
1988
  **Strict retry sweep parsing:** The channel retry sweep (`src/runtime/channel-retry-sweep.ts`) uses `parseTrustRuntimeContext()` which validates `trustClass` against the canonical three-value set. There is no fallback to a legacy `actorRole` field — stored payloads that lack a valid `trustClass` are rejected deterministically to prevent silent privilege escalation. When `trustCtx` is entirely absent from a stored payload (pre-guardian events), the sweep synthesizes an explicit `trustClass: 'unknown'` context so that replay never proceeds without a trust classification.
2252
1989
 
@@ -2254,10 +1991,10 @@ The guardian trust system uses a three-valued `TrustClass` — `'guardian'`, `'t
2254
1991
 
2255
1992
  **Key files:**
2256
1993
 
2257
- | File | Purpose |
2258
- | -------------------------------------------- | ----------------------------------------------------- |
2259
- | `src/daemon/session-runtime-assembly.ts` | `TrustContext` type definition |
2260
- | `src/tools/types.ts` | `ToolContext.trustClass` (required trust gate) |
2261
- | `src/runtime/channel-retry-sweep.ts` | Strict `trustClass` parser for retry sweep |
2262
- | `src/memory/channel-guardian-store.ts` | `GuardianBinding` with required `guardianPrincipalId` |
2263
- | `src/__tests__/trust-context-guards.test.ts` | Guard tests enforcing trust-context type invariants |
1994
+ | File | Purpose |
1995
+ | --------------------------------------------- | ----------------------------------------------------- |
1996
+ | `src/daemon/session-runtime-assembly.ts` | `TrustContext` type definition |
1997
+ | `src/tools/types.ts` | `ToolContext.trustClass` (required trust gate) |
1998
+ | `src/runtime/channel-retry-sweep.ts` | Strict `trustClass` parser for retry sweep |
1999
+ | `src/memory/channel-verification-sessions.ts` | `GuardianBinding` with required `guardianPrincipalId` |
2000
+ | `src/__tests__/trust-context-guards.test.ts` | Guard tests enforcing trust-context type invariants |