@vellumai/assistant 0.10.4-staging.2 → 0.10.5-dev.202607022248.91fa053

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 (864) hide show
  1. package/ARCHITECTURE.md +94 -91
  2. package/Dockerfile +5 -16
  3. package/README.md +7 -10
  4. package/bun.lock +0 -4
  5. package/docs/architecture/security.md +20 -20
  6. package/docs/stt-provider-onboarding.md +4 -5
  7. package/docs/trusted-contact-access.md +7 -7
  8. package/eslint-rules/cli-no-daemon-internals.js +4 -0
  9. package/eslint.config.mjs +7 -1
  10. package/knip.json +0 -1
  11. package/node_modules/@vellumai/gateway-client/src/__tests__/contact-read-contracts.test.ts +36 -0
  12. package/node_modules/@vellumai/gateway-client/src/__tests__/invite-contract.test.ts +233 -0
  13. package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +40 -0
  14. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +20 -8
  15. package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +10 -0
  16. package/node_modules/@vellumai/gateway-client/src/index.ts +33 -0
  17. package/node_modules/@vellumai/gateway-client/src/invite-contract.ts +216 -0
  18. package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +91 -0
  19. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +39 -3
  20. package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +0 -8
  21. package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +1 -5
  22. package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +3 -14
  23. package/openapi.yaml +1073 -225
  24. package/package.json +1 -4
  25. package/scripts/test.sh +35 -13
  26. package/src/__tests__/access-request-seed-content-blocks.test.ts +60 -4
  27. package/src/__tests__/acp-session.test.ts +4 -1
  28. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +0 -6
  29. package/src/__tests__/add-message-preassigned-id.test.ts +56 -0
  30. package/src/__tests__/agent-loop-set-system-prompt.test.ts +139 -0
  31. package/src/__tests__/app-conversation-ids-backfill.test.ts +3 -0
  32. package/src/__tests__/app-source-watcher.test.ts +11 -0
  33. package/src/__tests__/approval-interception-trust-gates.test.ts +148 -3
  34. package/src/__tests__/assistant-attachments.test.ts +62 -4
  35. package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -1
  36. package/src/__tests__/attachments-store-heic-normalize.test.ts +230 -0
  37. package/src/__tests__/attachments-store.test.ts +3 -0
  38. package/src/__tests__/background-shell-bash.test.ts +34 -0
  39. package/src/__tests__/background-shell-host-bash.test.ts +12 -0
  40. package/src/__tests__/background-tool-registry.test.ts +97 -0
  41. package/src/__tests__/background-tool-routes.test.ts +72 -1
  42. package/src/__tests__/background-workers-disk-pressure.test.ts +2 -1
  43. package/src/__tests__/btw-routes.test.ts +57 -3
  44. package/src/__tests__/call-controller.test.ts +474 -84
  45. package/src/__tests__/call-domain.test.ts +48 -1
  46. package/src/__tests__/call-pointer-messages.test.ts +57 -19
  47. package/src/__tests__/call-pointer-no-hardcoded-copy.guard.test.ts +2 -6
  48. package/src/__tests__/call-routes-http.test.ts +15 -14
  49. package/src/__tests__/call-setup-flow-invite.test.ts +568 -0
  50. package/src/__tests__/call-setup-flow-midcall-trust.test.ts +231 -0
  51. package/src/__tests__/call-setup-flow-name-capture.test.ts +754 -0
  52. package/src/__tests__/call-setup-flow-verification.test.ts +925 -0
  53. package/src/__tests__/call-setup-flow.test.ts +311 -0
  54. package/src/__tests__/cancel-resolves-conversation-key.test.ts +0 -1
  55. package/src/__tests__/channel-guardian.test.ts +4 -7
  56. package/src/__tests__/channel-readiness-service.test.ts +0 -6
  57. package/src/__tests__/channel-readiness-slack-remote.test.ts +0 -4
  58. package/src/__tests__/channel-retry-sweep.test.ts +76 -64
  59. package/src/__tests__/channel-setup-panel-ack.test.ts +184 -0
  60. package/src/__tests__/clear-all-lexical.test.ts +90 -0
  61. package/src/__tests__/compactor-media-strip.test.ts +177 -0
  62. package/src/__tests__/config-loader-backfill.test.ts +5 -5
  63. package/src/__tests__/config-schema.test.ts +17 -0
  64. package/src/__tests__/contact-store-interaction-info.test.ts +27 -70
  65. package/src/__tests__/contacts-relay-reads.test.ts +188 -23
  66. package/src/__tests__/contacts-tools.test.ts +42 -1
  67. package/src/__tests__/contacts-write.test.ts +181 -0
  68. package/src/__tests__/context-search-conversations-source.test.ts +220 -81
  69. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -0
  70. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
  71. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
  72. package/src/__tests__/conversation-agent-loop.test.ts +39 -0
  73. package/src/__tests__/conversation-analysis-routes.test.ts +1 -1
  74. package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -0
  75. package/src/__tests__/conversation-clear-safety.test.ts +0 -1
  76. package/src/__tests__/conversation-crud-enabled-plugins.test.ts +60 -0
  77. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -1
  78. package/src/__tests__/conversation-disk-view.test.ts +1 -0
  79. package/src/__tests__/conversation-enabledplugins-route.test.ts +184 -0
  80. package/src/__tests__/conversation-error.test.ts +0 -18
  81. package/src/__tests__/conversation-fork-crud.test.ts +67 -0
  82. package/src/__tests__/conversation-history-web-search.test.ts +7 -137
  83. package/src/__tests__/conversation-initial-prompt.test.ts +110 -0
  84. package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +191 -0
  85. package/src/__tests__/conversation-process-callsite.test.ts +37 -0
  86. package/src/__tests__/conversation-queue.test.ts +149 -0
  87. package/src/__tests__/conversation-routes-enabled-plugins.test.ts +392 -0
  88. package/src/__tests__/conversation-routes-guardian-reply.test.ts +84 -0
  89. package/src/__tests__/conversation-routes-hidden-queue.test.ts +407 -0
  90. package/src/__tests__/conversation-runtime-assembly.test.ts +36 -16
  91. package/src/__tests__/conversation-skill-tools.test.ts +73 -0
  92. package/src/__tests__/conversation-wipe.test.ts +20 -5
  93. package/src/__tests__/credential-prompt-route.test.ts +69 -0
  94. package/src/__tests__/credential-security-invariants.test.ts +1 -3
  95. package/src/__tests__/db-drop-messages-fts.test.ts +115 -0
  96. package/src/__tests__/deterministic-verification-control-plane.test.ts +1 -62
  97. package/src/__tests__/edit-propagation.test.ts +56 -2
  98. package/src/__tests__/empty-state-greeting-cache.test.ts +9 -0
  99. package/src/__tests__/gateway-only-enforcement.test.ts +15 -110
  100. package/src/__tests__/guardian-expiry-notifier.test.ts +1 -0
  101. package/src/__tests__/guardian-question-mode.test.ts +57 -0
  102. package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -1
  103. package/src/__tests__/guardian-wait-controller.test.ts +619 -0
  104. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +33 -2
  105. package/src/__tests__/heic-fixture.ts +55 -0
  106. package/src/__tests__/helpers/seed-contact-channel.ts +0 -2
  107. package/src/__tests__/http-conversation-lineage.test.ts +6 -1
  108. package/src/__tests__/image-conversion.test.ts +170 -0
  109. package/src/__tests__/inbound-invite-redemption.test.ts +72 -341
  110. package/src/__tests__/introduction-card-resolver.test.ts +354 -0
  111. package/src/__tests__/invite-redeemed-ipc.test.ts +97 -0
  112. package/src/__tests__/invite-routes-http.test.ts +246 -420
  113. package/src/__tests__/job-handler-registration-guard.test.ts +104 -0
  114. package/src/__tests__/lexical-index-dual-write.test.ts +426 -0
  115. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +2 -2
  116. package/src/__tests__/list-messages-attachments.test.ts +159 -0
  117. package/src/__tests__/list-messages-background-tool-completion.test.ts +141 -0
  118. package/src/__tests__/list-messages-queued.test.ts +25 -0
  119. package/src/__tests__/managed-store.test.ts +129 -1
  120. package/src/__tests__/media-stream-audio-transcode.test.ts +113 -0
  121. package/src/__tests__/media-stream-output.test.ts +350 -19
  122. package/src/__tests__/media-stream-server-integration.test.ts +943 -169
  123. package/src/__tests__/media-stream-stt-session.test.ts +498 -1
  124. package/src/__tests__/memory-jobs-worker-lanes.test.ts +2 -2
  125. package/src/__tests__/model-intents.test.ts +1 -1
  126. package/src/__tests__/mtime-cache.test.ts +19 -0
  127. package/src/__tests__/non-member-access-request.test.ts +349 -3
  128. package/src/__tests__/notification-decision-fallback.test.ts +104 -8
  129. package/src/__tests__/notification-decision-strategy.test.ts +57 -8
  130. package/src/__tests__/onboarding-template-contract.test.ts +27 -43
  131. package/src/__tests__/openai-provider.test.ts +33 -0
  132. package/src/__tests__/openai-responses-provider.test.ts +40 -0
  133. package/src/__tests__/persistence-layering-guard.test.ts +29 -20
  134. package/src/__tests__/persona-resolver.test.ts +56 -2
  135. package/src/__tests__/personal-memory-auth-bypass.test.ts +62 -0
  136. package/src/__tests__/phone.test.ts +1 -15
  137. package/src/__tests__/plugin-bootstrap.test.ts +25 -196
  138. package/src/__tests__/plugin-disabled-state.test.ts +33 -0
  139. package/src/__tests__/plugin-effective-enabled-set.test.ts +227 -0
  140. package/src/__tests__/plugin-event-hub-facade.test.ts +323 -0
  141. package/src/__tests__/plugin-import-boundary-guard.test.ts +156 -42
  142. package/src/__tests__/plugin-injector-contribution.test.ts +4 -20
  143. package/src/__tests__/plugin-pipeline.test.ts +63 -1
  144. package/src/__tests__/plugin-route-contribution.test.ts +62 -115
  145. package/src/__tests__/plugin-tool-contribution.test.ts +0 -22
  146. package/src/__tests__/plugin-types.test.ts +0 -1
  147. package/src/__tests__/pointer-conversation-trust.test.ts +38 -6
  148. package/src/__tests__/pre-model-call-sanitize.test.ts +1 -1
  149. package/src/__tests__/prune-old-tool-invocations-job.test.ts +97 -0
  150. package/src/__tests__/public-ingress-urls.test.ts +0 -48
  151. package/src/__tests__/qdrant-collection-migration.test.ts +145 -2
  152. package/src/__tests__/reaction-intercept-member-verdict-warm.test.ts +0 -1
  153. package/src/__tests__/resolve-trust-class.test.ts +28 -10
  154. package/src/__tests__/scaffold-managed-skill-tool.test.ts +137 -0
  155. package/src/__tests__/schedule-retry.test.ts +38 -14
  156. package/src/__tests__/schedule-routes-workflow-validation.test.ts +3 -3
  157. package/src/__tests__/schedule-routes.test.ts +14 -6
  158. package/src/__tests__/schedule-store.test.ts +3 -1
  159. package/src/__tests__/scheduler-disk-pressure.test.ts +17 -6
  160. package/src/__tests__/scheduler-recurrence.test.ts +57 -107
  161. package/src/__tests__/scheduler-reuse-conversation.test.ts +51 -46
  162. package/src/__tests__/scheduler-wake.test.ts +13 -23
  163. package/src/__tests__/scheduler-worker-standdown.test.ts +220 -0
  164. package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -1
  165. package/src/__tests__/shell-observability.test.ts +1 -0
  166. package/src/__tests__/skill-boundary-guard.test.ts +3 -4
  167. package/src/__tests__/skill-load-plugin-scope.test.ts +238 -0
  168. package/src/__tests__/skill-projection-feature-flag.test.ts +2 -0
  169. package/src/__tests__/skill-script-runner-host.test.ts +53 -0
  170. package/src/__tests__/skill-script-runner-sandbox.test.ts +5 -2
  171. package/src/__tests__/skill-tool-factory.test.ts +73 -1
  172. package/src/__tests__/slack-app-setup-skill-regression.test.ts +37 -14
  173. package/src/__tests__/slack-inbound-verification.test.ts +36 -0
  174. package/src/__tests__/slack-notification-approval-card.test.ts +89 -2
  175. package/src/__tests__/slack-reaction-canonical-approval.test.ts +51 -1
  176. package/src/__tests__/stt-hints.test.ts +2 -256
  177. package/src/__tests__/subagent-allowlist-validation.test.ts +47 -0
  178. package/src/__tests__/subagent-call-site-routing.test.ts +72 -0
  179. package/src/__tests__/subagent-fork-notifications.test.ts +14 -2
  180. package/src/__tests__/subagent-persistence.test.ts +122 -0
  181. package/src/__tests__/subagent-spawn-and-await.test.ts +1 -0
  182. package/src/__tests__/subagent-terminal-message.test.ts +99 -0
  183. package/src/__tests__/subagent-tool-gate-mode.test.ts +78 -1
  184. package/src/__tests__/system-prompt.test.ts +17 -118
  185. package/src/__tests__/task-scheduler.test.ts +68 -89
  186. package/src/__tests__/telephony-credential-preflight.test.ts +312 -0
  187. package/src/__tests__/telephony-tts-guard.test.ts +538 -0
  188. package/src/__tests__/title-generate-hook.test.ts +16 -0
  189. package/src/__tests__/tool-approval-handler.test.ts +87 -1
  190. package/src/__tests__/tool-approval-seed-content-blocks.test.ts +45 -20
  191. package/src/__tests__/tool-grant-request-escalation.test.ts +39 -0
  192. package/src/__tests__/trust-context-guards.test.ts +21 -10
  193. package/src/__tests__/trusted-contact-multichannel.test.ts +4 -0
  194. package/src/__tests__/twilio-provider.test.ts +17 -17
  195. package/src/__tests__/twilio-routes-twiml.test.ts +6 -543
  196. package/src/__tests__/twilio-routes.test.ts +257 -387
  197. package/src/__tests__/twilio-validation.test.ts +1 -1
  198. package/src/__tests__/unified-turn-context-client-os.test.ts +45 -0
  199. package/src/__tests__/usage-cache-backfill-migration.test.ts +5 -0
  200. package/src/__tests__/voice-approval-resolver-relay.test.ts +150 -0
  201. package/src/__tests__/voice-ingress-preflight.test.ts +61 -0
  202. package/src/__tests__/voice-quality.test.ts +2 -2
  203. package/src/__tests__/voice-scoped-grant-consumer.test.ts +1 -7
  204. package/src/__tests__/voice-session-bridge-processing-wait.test.ts +27 -0
  205. package/src/__tests__/voice-session-bridge.test.ts +1 -10
  206. package/src/__tests__/workspace-git-service.test.ts +1 -1
  207. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +1 -0
  208. package/src/__tests__/workspace-migration-118-seed-now-md.test.ts +120 -0
  209. package/src/__tests__/workspace-migration-120-revise-onboarding-threads.test.ts +175 -0
  210. package/src/__tests__/workspace-migration-121-seed-default-user-guardrails.test.ts +118 -0
  211. package/src/__tests__/workspace-migration-122-relocate-default-user-boundary.test.ts +119 -0
  212. package/src/__tests__/workspace-migration-123-swap-quality-profile-to-fable.test.ts +191 -0
  213. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +235 -241
  214. package/src/acp/__tests__/prepare-agent-env.test.ts +0 -97
  215. package/src/acp/__tests__/session-manager-persistence.test.ts +2 -0
  216. package/src/acp/__tests__/session-manager-resume.test.ts +8 -0
  217. package/src/acp/__tests__/session-manager-usage.test.ts +6 -0
  218. package/src/acp/__tests__/session-manager.test.ts +6 -0
  219. package/src/acp/agent-process.test.ts +116 -0
  220. package/src/acp/agent-process.ts +71 -0
  221. package/src/acp/auto-install.ts +12 -8
  222. package/src/acp/failure-error.test.ts +109 -0
  223. package/src/acp/failure-error.ts +111 -0
  224. package/src/acp/prepare-agent-env.ts +0 -12
  225. package/src/acp/resolve-agent.test.ts +6 -45
  226. package/src/acp/resolve-agent.ts +2 -4
  227. package/src/acp/session-manager.test.ts +312 -0
  228. package/src/acp/session-manager.ts +102 -46
  229. package/src/agent/ax-tree-compaction.test.ts +4 -1
  230. package/src/agent/image-optimize.ts +17 -127
  231. package/src/agent/loop.ts +45 -192
  232. package/src/api/events/background-tool-completed.test.ts +51 -0
  233. package/src/api/events/background-tool-completed.ts +29 -0
  234. package/src/api/events/background-tool-started.test.ts +36 -0
  235. package/src/api/events/background-tool-started.ts +28 -0
  236. package/src/api/events/conversation-error.ts +0 -1
  237. package/src/api/events/open-panel.ts +33 -0
  238. package/src/api/events/subagent-status-changed.ts +4 -1
  239. package/src/api/index.ts +19 -0
  240. package/src/api/responses/conversation-message.ts +34 -0
  241. package/src/approvals/guardian-decision-primitive.ts +74 -24
  242. package/src/approvals/guardian-request-resolvers.ts +450 -122
  243. package/src/apps/app-store.ts +1 -0
  244. package/src/apps/shared-app-links-store.ts +1 -0
  245. package/src/avatar/identity-avatar.ts +3 -7
  246. package/src/background-wake/wake-intent-hooks.test.ts +1 -1
  247. package/src/calls/__tests__/fish-audio-client.test.ts +73 -0
  248. package/src/calls/__tests__/gateway-invite-reader.test.ts +170 -0
  249. package/src/calls/__tests__/relay-setup-router.test.ts +126 -102
  250. package/src/calls/call-controller.ts +134 -48
  251. package/src/calls/call-domain.ts +18 -42
  252. package/src/calls/call-pointer-messages.ts +51 -67
  253. package/src/calls/call-setup-flow-types.ts +76 -0
  254. package/src/calls/call-setup-flow.ts +1743 -0
  255. package/src/calls/call-speech-output.ts +87 -23
  256. package/src/calls/call-store.ts +4 -0
  257. package/src/calls/call-transport.ts +22 -36
  258. package/src/calls/fish-audio-client.ts +3 -0
  259. package/src/calls/gateway-invite-reader.ts +98 -0
  260. package/src/calls/guardian-wait-controller.ts +451 -0
  261. package/src/calls/media-stream-audio-transcode.ts +82 -2
  262. package/src/calls/media-stream-output.ts +142 -36
  263. package/src/calls/media-stream-server.ts +297 -178
  264. package/src/calls/media-stream-stt-session.ts +393 -50
  265. package/src/calls/media-turn-detector.ts +4 -6
  266. package/src/calls/relay-access-wait.ts +3 -4
  267. package/src/calls/relay-setup-router.ts +22 -43
  268. package/src/calls/relay-verification.ts +17 -24
  269. package/src/calls/resolve-call-tts-provider.ts +96 -29
  270. package/src/calls/stt-hints.ts +24 -87
  271. package/src/calls/telephony-credential-preflight.ts +159 -0
  272. package/src/calls/telephony-tts-capability.ts +183 -0
  273. package/src/calls/tts-call-strategy.ts +18 -20
  274. package/src/calls/twilio-provider.ts +3 -2
  275. package/src/calls/twilio-routes.ts +47 -351
  276. package/src/calls/types.ts +5 -3
  277. package/src/calls/voice-ingress-preflight.ts +9 -0
  278. package/src/calls/voice-quality.ts +13 -18
  279. package/src/calls/voice-session-bridge.ts +25 -35
  280. package/src/channels/__tests__/types.test.ts +28 -0
  281. package/src/channels/channel-verification-sessions.ts +7 -2
  282. package/src/channels/config.ts +0 -42
  283. package/src/channels/slack-thread-store.ts +12 -0
  284. package/src/channels/types.ts +23 -0
  285. package/src/cli/commands/__tests__/conversations-slack.test.ts +1 -1
  286. package/src/cli/commands/__tests__/schedules.test.ts +83 -34
  287. package/src/cli/commands/__tests__/status.test.ts +42 -2
  288. package/src/cli/commands/contacts.ts +2 -2
  289. package/src/cli/commands/credentials.ts +17 -0
  290. package/src/cli/commands/monitoring.ts +191 -0
  291. package/src/cli/commands/schedules-worker.ts +175 -0
  292. package/src/cli/commands/schedules.ts +169 -43
  293. package/src/cli/commands/status.ts +12 -1
  294. package/src/cli/commands/tools.ts +5 -1
  295. package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +1 -0
  296. package/src/cli/lib/__tests__/search-plugins.test.ts +29 -1
  297. package/src/cli/lib/__tests__/toggle-plugin.test.ts +7 -0
  298. package/src/cli/lib/search-plugins.ts +6 -0
  299. package/src/cli/lib/toggle-plugin.ts +21 -2
  300. package/src/cli/program.ts +3 -1
  301. package/src/config/__tests__/deployment-context-defaults.test.ts +23 -0
  302. package/src/config/acp-defaults.test.ts +0 -10
  303. package/src/config/acp-defaults.ts +0 -6
  304. package/src/config/bundled-skills/acp/SKILL.md +13 -45
  305. package/src/config/bundled-skills/acp/TOOLS.json +3 -3
  306. package/src/config/bundled-skills/app-builder/SKILL.md +3 -3
  307. package/src/config/bundled-skills/app-builder/references/RESPONSIVE.md +9 -9
  308. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +1 -1
  309. package/src/config/bundled-skills/contacts/tools/contact-search.ts +1 -1
  310. package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
  311. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -9
  312. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +10 -7
  313. package/src/config/bundled-skills/skill-management/TOOLS.json +10 -0
  314. package/src/config/call-site-defaults.ts +0 -2
  315. package/src/config/feature-flag-registry.json +16 -8
  316. package/src/config/loader.ts +11 -0
  317. package/src/config/schema.ts +9 -1
  318. package/src/config/schemas/__tests__/memory-v2.test.ts +2 -2
  319. package/src/config/schemas/__tests__/memory-v3.test.ts +64 -0
  320. package/src/config/schemas/call-site-catalog.ts +0 -12
  321. package/src/config/schemas/calls.ts +8 -0
  322. package/src/config/schemas/elevenlabs.ts +1 -1
  323. package/src/config/schemas/llm.ts +0 -2
  324. package/src/config/schemas/memory-v2.ts +1 -1
  325. package/src/config/schemas/memory-v3.ts +82 -0
  326. package/src/config/schemas/monitoring.ts +61 -0
  327. package/src/config/schemas/schedules.ts +35 -0
  328. package/src/config/seed-inference-profiles.ts +2 -2
  329. package/src/config/skills-plugin-filter.test.ts +96 -0
  330. package/src/config/skills.ts +26 -0
  331. package/src/contacts/__tests__/member-write-relay.test.ts +156 -4
  332. package/src/contacts/canonical-guardian-store.ts +5 -0
  333. package/src/contacts/contact-store.ts +81 -35
  334. package/src/contacts/contacts-write.ts +50 -25
  335. package/src/contacts/member-write-relay.ts +115 -31
  336. package/src/contacts/types.ts +0 -8
  337. package/src/context/compactor.ts +29 -15
  338. package/src/context/outbound-sanitize.ts +202 -0
  339. package/src/daemon/__tests__/abort-null-controller.test.ts +167 -0
  340. package/src/daemon/__tests__/conversation-tool-setup-plugin-scope.test.ts +122 -0
  341. package/src/daemon/__tests__/embedding-reconcile.test.ts +99 -16
  342. package/src/daemon/__tests__/wake-conversation-ops-completion.test.ts +107 -0
  343. package/src/daemon/abort-watchdog.ts +7 -0
  344. package/src/daemon/app-source-watcher.ts +9 -0
  345. package/src/daemon/assistant-attachments.ts +42 -0
  346. package/src/daemon/conversation-agent-loop-handlers.ts +256 -147
  347. package/src/daemon/conversation-agent-loop.ts +61 -68
  348. package/src/daemon/conversation-error.ts +1 -15
  349. package/src/daemon/conversation-history.ts +32 -236
  350. package/src/daemon/conversation-initial-prompt.ts +77 -0
  351. package/src/daemon/conversation-lifecycle.ts +25 -1
  352. package/src/daemon/conversation-messaging.ts +2 -2
  353. package/src/daemon/conversation-plugin-scope.ts +38 -0
  354. package/src/daemon/conversation-process.ts +50 -14
  355. package/src/daemon/conversation-runtime-assembly.ts +36 -6
  356. package/src/daemon/conversation-skill-tools.ts +19 -3
  357. package/src/daemon/conversation-store.ts +3 -3
  358. package/src/daemon/conversation-surfaces.ts +171 -0
  359. package/src/daemon/conversation-tool-setup.test.ts +95 -0
  360. package/src/daemon/conversation-tool-setup.ts +116 -1
  361. package/src/daemon/conversation-turn-finalize.ts +211 -0
  362. package/src/daemon/conversation.ts +92 -1
  363. package/src/daemon/disk-pressure-policy.ts +2 -1
  364. package/src/daemon/event-loop-watchdog.ts +22 -6
  365. package/src/daemon/external-plugins-bootstrap.ts +47 -134
  366. package/src/daemon/handlers/__tests__/config-a2a-accept.test.ts +1 -1
  367. package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +26 -14
  368. package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +27 -14
  369. package/src/daemon/handlers/__tests__/config-channels.test.ts +0 -5
  370. package/src/daemon/handlers/config-a2a.ts +7 -14
  371. package/src/daemon/handlers/config-channels.ts +2 -10
  372. package/src/daemon/handlers/conversation-history.ts +3 -1
  373. package/src/daemon/handlers/conversations.ts +0 -52
  374. package/src/daemon/handlers/shared.ts +4 -24
  375. package/src/daemon/handlers/skills.ts +4 -1
  376. package/src/daemon/host-cu-proxy.ts +1 -1
  377. package/src/daemon/lifecycle.ts +59 -472
  378. package/src/daemon/message-protocol.ts +3 -3
  379. package/src/daemon/message-provenance.ts +12 -14
  380. package/src/daemon/message-types/background-tools.ts +28 -0
  381. package/src/daemon/message-types/contacts.ts +2 -10
  382. package/src/daemon/message-types/conversations.ts +10 -0
  383. package/src/daemon/message-types/integrations.ts +2 -0
  384. package/src/daemon/message-types/surfaces.ts +1 -0
  385. package/src/daemon/message-types/sync.ts +1 -0
  386. package/src/daemon/pointer-conversation-trust.ts +23 -9
  387. package/src/daemon/pointer-turn-runner.ts +174 -0
  388. package/src/daemon/providers-setup.ts +16 -0
  389. package/src/daemon/shutdown-handlers.ts +139 -47
  390. package/src/daemon/skill-memory-refresh.ts +2 -2
  391. package/src/daemon/sqlite-corruption-watchdog.test.ts +217 -0
  392. package/src/daemon/sqlite-corruption-watchdog.ts +155 -0
  393. package/src/daemon/tool-setup-types.ts +8 -0
  394. package/src/daemon/trust-context.ts +21 -6
  395. package/src/daemon/turn-latency-tracker.test.ts +93 -0
  396. package/src/daemon/turn-latency-tracker.ts +38 -0
  397. package/src/daemon/wake-conversation-ops.ts +10 -8
  398. package/src/documents/document-comments-store.test.ts +7 -1
  399. package/src/documents/document-comments-store.ts +8 -0
  400. package/src/documents/document-store.ts +15 -0
  401. package/src/export/__tests__/transcript-formatter.test.ts +11 -0
  402. package/src/export/transcript-formatter.ts +49 -67
  403. package/src/home/__tests__/feed-writer.test.ts +247 -1
  404. package/src/home/conversation-starter-checkpoints.ts +1 -0
  405. package/src/home/feed-writer.ts +61 -0
  406. package/src/home/job-handlers/conversation-starters.ts +1 -0
  407. package/src/hooks/hook-loader.ts +12 -0
  408. package/src/hooks/registry.ts +32 -4
  409. package/src/inbound/public-ingress-urls.ts +0 -17
  410. package/src/ipc/__tests__/contacts-info-ipc.test.ts +285 -0
  411. package/src/ipc/assistant-server.ts +28 -7
  412. package/src/ipc/routes/__tests__/contacts-mirror-apply-atomicity.test.ts +62 -0
  413. package/src/ipc/routes/__tests__/contacts-mirror-apply.test.ts +272 -0
  414. package/src/ipc/routes/__tests__/contacts-mirror-ipc-routes.test.ts +322 -0
  415. package/src/ipc/routes/__tests__/invite-ipc-routes.test.ts +60 -4
  416. package/src/ipc/routes/contacts-info-ipc-routes.ts +239 -0
  417. package/src/ipc/routes/contacts-mirror-ipc-routes.ts +202 -0
  418. package/src/ipc/routes/db-proxy.ts +5 -2
  419. package/src/ipc/routes/invite-ipc-routes.ts +53 -39
  420. package/src/jobs/worker.ts +9 -2
  421. package/src/live-voice/__tests__/live-voice-archive.test.ts +10 -1
  422. package/src/live-voice/live-voice-archive.ts +5 -0
  423. package/src/messaging/providers/__tests__/transport-dispatch.test.ts +22 -6
  424. package/src/messaging/providers/channel-transport.ts +6 -0
  425. package/src/messaging/providers/index.ts +3 -0
  426. package/src/messaging/providers/slack/api.test.ts +49 -1
  427. package/src/messaging/providers/slack/api.ts +110 -0
  428. package/src/messaging/providers/slack/send.test.ts +85 -0
  429. package/src/messaging/providers/slack/send.ts +100 -28
  430. package/src/messaging/providers/slack/transport.ts +7 -13
  431. package/src/messaging/providers/whatsapp/send.ts +29 -9
  432. package/src/monitoring/__tests__/control.test.ts +235 -0
  433. package/src/monitoring/__tests__/sample-ring-buffer.test.ts +96 -0
  434. package/src/monitoring/control.ts +105 -0
  435. package/src/monitoring/resource-sampler.ts +258 -0
  436. package/src/monitoring/sample-ring-buffer.ts +108 -0
  437. package/src/monitoring/worker.ts +94 -0
  438. package/src/notifications/README.md +1 -1
  439. package/src/notifications/access-request-copy.ts +94 -23
  440. package/src/notifications/adapters/slack.ts +89 -21
  441. package/src/notifications/approval-card-builder.ts +33 -18
  442. package/src/notifications/approval-card-data.ts +48 -15
  443. package/src/notifications/broadcaster.ts +25 -16
  444. package/src/notifications/decision-engine.ts +131 -32
  445. package/src/notifications/guardian-question-mode.ts +58 -10
  446. package/src/permissions/approval-policy.ts +8 -1
  447. package/src/permissions/checker.ts +2 -0
  448. package/src/permissions/gateway-threshold-reader.ts +7 -6
  449. package/src/permissions/ipc-risk-types.ts +1 -0
  450. package/src/permissions/secret-prompter.ts +11 -3
  451. package/src/permissions/types.ts +2 -2
  452. package/src/persistence/__tests__/conversation-queries-search.test.ts +397 -0
  453. package/src/persistence/__tests__/conversation-search-lexical.test.ts +103 -0
  454. package/src/persistence/__tests__/jobs-worker-memory-disabled.test.ts +95 -0
  455. package/src/persistence/__tests__/slow-query-log.test.ts +266 -0
  456. package/src/persistence/__tests__/slow-sync-log.test.ts +155 -0
  457. package/src/persistence/a2a-invite-store.ts +205 -0
  458. package/src/persistence/attachments-store.ts +94 -10
  459. package/src/persistence/checkpoints.ts +45 -0
  460. package/src/persistence/conversation-crud.ts +453 -260
  461. package/src/persistence/conversation-display-order-migration.ts +8 -2
  462. package/src/persistence/conversation-group-migration.test.ts +8 -0
  463. package/src/persistence/conversation-group-migration.ts +9 -0
  464. package/src/persistence/conversation-queries.ts +244 -125
  465. package/src/persistence/conversation-row-batch-delete.ts +9 -5
  466. package/src/persistence/conversation-search-lexical.ts +49 -0
  467. package/src/persistence/db-async-query.ts +42 -0
  468. package/src/persistence/db-connection.ts +13 -0
  469. package/src/persistence/delivery-channels.ts +0 -82
  470. package/src/persistence/delivery-crud.ts +27 -6
  471. package/src/persistence/embeddings/__tests__/embedding-identity.test.ts +18 -5
  472. package/src/persistence/embeddings/__tests__/messages-lexical-index.test.ts +334 -0
  473. package/src/persistence/embeddings/embedding-identity.ts +17 -5
  474. package/src/persistence/embeddings/embedding-runtime-manager.ts +31 -0
  475. package/src/persistence/embeddings/messages-lexical-index.ts +396 -0
  476. package/src/persistence/embeddings/qdrant-client.ts +81 -5
  477. package/src/persistence/group-crud.ts +13 -1
  478. package/src/persistence/job-handlers/__tests__/message-lexical-backfill.test.ts +506 -0
  479. package/src/persistence/job-handlers/__tests__/message-lexical-enqueue.test.ts +164 -0
  480. package/src/persistence/job-handlers/__tests__/message-lexical.test.ts +259 -0
  481. package/src/persistence/job-handlers/cleanup.ts +57 -9
  482. package/src/persistence/job-handlers/message-lexical-backfill.ts +187 -0
  483. package/src/persistence/job-handlers/message-lexical.ts +251 -0
  484. package/src/persistence/jobs-store.ts +102 -8
  485. package/src/persistence/jobs-worker.ts +68 -28
  486. package/src/persistence/llm-request-log-store.ts +35 -19
  487. package/src/persistence/llm-usage-store.ts +11 -0
  488. package/src/persistence/memory-lifecycle-hooks.test.ts +65 -0
  489. package/src/persistence/memory-lifecycle-hooks.ts +55 -1
  490. package/src/persistence/migrations/028-call-session-mode.ts +1 -1
  491. package/src/persistence/migrations/116-messages-fts.ts +8 -1
  492. package/src/persistence/migrations/311-create-subagents-table.ts +50 -0
  493. package/src/persistence/migrations/312-drop-inbox-conversation-state-table.ts +15 -0
  494. package/src/persistence/migrations/313-drop-messages-fts.ts +17 -0
  495. package/src/persistence/migrations/314-add-conversation-enabled-plugins.ts +25 -0
  496. package/src/persistence/migrations/315-create-a2a-invites.ts +58 -0
  497. package/src/persistence/migrations/316-drop-contact-channels-invite-id.ts +28 -0
  498. package/src/persistence/migrations/317-canonical-guardian-requester-signals.ts +24 -0
  499. package/src/persistence/migrations/318-drop-contact-channel-telemetry.ts +32 -0
  500. package/src/persistence/migrations/__tests__/315-create-a2a-invites.test.ts +161 -0
  501. package/src/persistence/migrations/__tests__/316-drop-contact-channels-invite-id.test.ts +156 -0
  502. package/src/persistence/migrations/__tests__/318-drop-contact-channel-telemetry.test.ts +134 -0
  503. package/src/persistence/migrations/__tests__/migration-prefix-guard.test.ts +99 -0
  504. package/src/persistence/raw-query.ts +50 -11
  505. package/src/persistence/schema/a2a.ts +14 -0
  506. package/src/persistence/schema/contacts.ts +0 -62
  507. package/src/persistence/schema/conversation-groups.ts +12 -0
  508. package/src/persistence/schema/conversations.ts +2 -0
  509. package/src/persistence/schema/documents.ts +65 -0
  510. package/src/persistence/schema/guardian.ts +4 -0
  511. package/src/persistence/schema/index.ts +4 -0
  512. package/src/persistence/schema/memory-injection.ts +62 -0
  513. package/src/persistence/schema/workflows.ts +55 -0
  514. package/src/persistence/slow-query-log.ts +437 -0
  515. package/src/persistence/slow-sync-log.ts +204 -0
  516. package/src/persistence/steps.ts +16 -0
  517. package/src/persistence/subagent-store.ts +125 -0
  518. package/src/persistence/worker-control.ts +45 -238
  519. package/src/plugin-api/event-hub-facade.ts +172 -0
  520. package/src/plugin-api/index.ts +9 -1
  521. package/src/plugin-api/types.ts +40 -9
  522. package/src/plugins/defaults/default-plugin-names.ts +60 -0
  523. package/src/plugins/defaults/index.ts +19 -29
  524. package/src/plugins/defaults/memory/__tests__/conversation-queries.test.ts +46 -67
  525. package/src/plugins/defaults/memory/__tests__/db-async-query.test.ts +36 -1
  526. package/src/plugins/defaults/memory/__tests__/find-most-recent-retrospective-for.test.ts +2 -4
  527. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +2 -2
  528. package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-schedule.test.ts +9 -0
  529. package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +7 -4
  530. package/src/plugins/defaults/memory/config.ts +11 -0
  531. package/src/plugins/defaults/memory/context-search/agent-runner.ts +1 -1
  532. package/src/plugins/defaults/memory/context-search/sources/conversations.ts +124 -113
  533. package/src/plugins/defaults/memory/embeddings.ts +77 -0
  534. package/src/plugins/defaults/memory/find-most-recent-retrospective-for.ts +66 -0
  535. package/src/plugins/defaults/memory/frontmatter.ts +50 -0
  536. package/src/plugins/defaults/memory/graph/bootstrap.test.ts +36 -10
  537. package/src/plugins/defaults/memory/graph/bootstrap.ts +6 -5
  538. package/src/plugins/defaults/memory/graph/consolidation.ts +3 -5
  539. package/src/plugins/defaults/memory/graph/extraction.ts +3 -6
  540. package/src/plugins/defaults/memory/graph/graph-search.ts +12 -23
  541. package/src/plugins/defaults/memory/graph/narrative.ts +3 -5
  542. package/src/plugins/defaults/memory/graph/pattern-scan.ts +3 -5
  543. package/src/plugins/defaults/memory/graph/retriever.test.ts +1 -6
  544. package/src/plugins/defaults/memory/graph/retriever.ts +5 -10
  545. package/src/plugins/defaults/memory/graph/tools.ts +1 -1
  546. package/src/plugins/defaults/memory/hooks/init.ts +31 -5
  547. package/src/plugins/defaults/memory/indexer.ts +2 -3
  548. package/src/plugins/defaults/memory/injectors.ts +2 -2
  549. package/src/plugins/defaults/memory/job-handler-registration.ts +96 -0
  550. package/src/plugins/defaults/memory/job-handlers/backfill.ts +4 -26
  551. package/src/plugins/defaults/memory/job-handlers/embedding.test.ts +6 -19
  552. package/src/plugins/defaults/memory/job-handlers/embedding.ts +9 -22
  553. package/src/plugins/defaults/memory/job-handlers/index-maintenance.ts +2 -3
  554. package/src/plugins/defaults/memory/job-handlers.ts +13 -12
  555. package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +1 -1
  556. package/src/plugins/defaults/memory/llm-helpers.ts +76 -0
  557. package/src/plugins/defaults/memory/memory-retrospective-job.ts +8 -5
  558. package/src/plugins/defaults/memory/memory-retrospective-startup-cleanup.ts +2 -2
  559. package/src/plugins/defaults/memory/memory-v2-concept-frequency.ts +2 -0
  560. package/src/plugins/defaults/memory/persistence-hooks.ts +46 -1
  561. package/src/plugins/defaults/memory/pkb/pkb-index.ts +1 -5
  562. package/src/plugins/defaults/memory/pkb/pkb-search.ts +2 -2
  563. package/src/plugins/defaults/memory/routes/__tests__/memory-v2-simulate-route.test.ts +4 -6
  564. package/src/plugins/defaults/memory/routes/memory-item-routes.ts +1 -1
  565. package/src/plugins/defaults/memory/search/semantic.ts +2 -2
  566. package/src/plugins/defaults/memory/startup.ts +244 -0
  567. package/src/plugins/defaults/memory/task-memory-cleanup.ts +8 -0
  568. package/src/{daemon → plugins/defaults/memory/v2}/__tests__/memory-v2-startup.test.ts +6 -6
  569. package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +2 -13
  570. package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +4 -5
  571. package/src/plugins/defaults/memory/v2/__tests__/sweep-job.test.ts +1 -8
  572. package/src/plugins/defaults/memory/v2/activation.ts +2 -4
  573. package/src/plugins/defaults/memory/v2/cli-command-store.ts +2 -4
  574. package/src/plugins/defaults/memory/v2/frontmatter-sweep.ts +1 -1
  575. package/src/{daemon → plugins/defaults/memory/v2}/memory-v2-startup.test.ts +8 -8
  576. package/src/{daemon → plugins/defaults/memory/v2}/memory-v2-startup.ts +20 -22
  577. package/src/plugins/defaults/memory/v2/migration.ts +2 -5
  578. package/src/plugins/defaults/memory/v2/page-store.ts +1 -1
  579. package/src/plugins/defaults/memory/v2/qdrant.ts +2 -3
  580. package/src/plugins/defaults/memory/v2/router.ts +5 -5
  581. package/src/plugins/defaults/memory/v2/sim.ts +2 -4
  582. package/src/plugins/defaults/memory/v2/skill-store.ts +2 -4
  583. package/src/plugins/defaults/memory/v2/sweep-job.ts +6 -6
  584. package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +11 -9
  585. package/src/plugins/defaults/memory/v3/__tests__/dense.test.ts +107 -2
  586. package/src/plugins/defaults/memory/v3/__tests__/gate-flag.test.ts +69 -0
  587. package/src/plugins/defaults/memory/v3/__tests__/gate.test.ts +181 -0
  588. package/src/plugins/defaults/memory/v3/__tests__/live-integration.test.ts +7 -3
  589. package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +345 -8
  590. package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +1 -4
  591. package/src/plugins/defaults/memory/v3/__tests__/section-needle.test.ts +64 -0
  592. package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +18 -13
  593. package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +62 -1
  594. package/src/plugins/defaults/memory/v3/card.ts +1 -4
  595. package/src/plugins/defaults/memory/v3/dense.ts +60 -25
  596. package/src/plugins/defaults/memory/v3/edge.ts +1 -1
  597. package/src/plugins/defaults/memory/v3/gate-flag.ts +20 -0
  598. package/src/plugins/defaults/memory/v3/gate.ts +158 -0
  599. package/src/plugins/defaults/memory/v3/maintain-job.ts +2 -4
  600. package/src/plugins/defaults/memory/v3/orchestrate.ts +186 -25
  601. package/src/plugins/defaults/memory/v3/pool-select.test.ts +7 -9
  602. package/src/plugins/defaults/memory/v3/pool-select.ts +6 -6
  603. package/src/plugins/defaults/memory/v3/prune.ts +2 -2
  604. package/src/plugins/defaults/memory/v3/section-dense-store.ts +8 -11
  605. package/src/plugins/defaults/memory/v3/section-needle.ts +27 -7
  606. package/src/plugins/defaults/memory/v3/shadow-plugin.ts +10 -0
  607. package/src/plugins/defaults/memory/v3-eval/eval-packets.ts +1 -4
  608. package/src/plugins/defaults/title-generate/hooks/user-prompt-submit.ts +5 -0
  609. package/src/plugins/defaults/turn-context/injectors.ts +1 -0
  610. package/src/plugins/defaults/turn-context/unified-turn-context.ts +12 -0
  611. package/src/plugins/injector-registry.ts +13 -2
  612. package/src/plugins/mtime-cache.ts +36 -47
  613. package/src/plugins/pipeline.ts +15 -1
  614. package/src/plugins/types.ts +14 -23
  615. package/src/prompts/__tests__/system-prompt.test.ts +170 -32
  616. package/src/prompts/persona-resolver.ts +13 -9
  617. package/src/prompts/system-prompt.ts +30 -9
  618. package/src/prompts/templates/BOOTSTRAP.md +16 -119
  619. package/src/prompts/templates/SOUL.md +43 -13
  620. package/src/prompts/templates/system-sections.ts +32 -27
  621. package/src/prompts/templates/users/default.md +19 -0
  622. package/src/providers/__tests__/placeholder-sentinels.test.ts +56 -0
  623. package/src/providers/inference/__tests__/base-url-route-validation.test.ts +96 -1
  624. package/src/providers/model-intents.ts +2 -2
  625. package/src/providers/openai/chat-completions-provider.ts +14 -1
  626. package/src/providers/openai/responses-provider.ts +18 -0
  627. package/src/providers/placeholder-sentinels.ts +18 -8
  628. package/src/providers/retry.ts +1 -0
  629. package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +0 -64
  630. package/src/providers/speech-to-text/__tests__/resolve.test.ts +92 -79
  631. package/src/providers/speech-to-text/deepgram-realtime.test.ts +98 -0
  632. package/src/providers/speech-to-text/deepgram-realtime.ts +62 -3
  633. package/src/providers/speech-to-text/provider-catalog.ts +0 -89
  634. package/src/providers/speech-to-text/resolve.ts +55 -0
  635. package/src/providers/tool-progress-events.test.ts +50 -0
  636. package/src/providers/tool-progress-events.ts +99 -0
  637. package/src/providers/types.ts +1 -1
  638. package/src/runtime/AGENTS.md +5 -4
  639. package/src/runtime/__tests__/agent-wake.test.ts +158 -1
  640. package/src/runtime/__tests__/channel-verification-service.test.ts +2 -2
  641. package/src/runtime/__tests__/trust-verdict-consumer.test.ts +37 -8
  642. package/src/runtime/access-request-helper.ts +154 -3
  643. package/src/runtime/actor-trust-resolver.ts +7 -21
  644. package/src/runtime/agent-wake.ts +41 -1
  645. package/src/runtime/assistant-event.ts +86 -12
  646. package/src/runtime/auth/__tests__/route-policy.test.ts +31 -0
  647. package/src/runtime/channel-approval-types.ts +52 -2
  648. package/src/runtime/channel-approvals.ts +23 -8
  649. package/src/runtime/channel-invite-transport.ts +2 -2
  650. package/src/runtime/channel-invite-transports/voice.ts +1 -1
  651. package/src/runtime/channel-readiness-service.ts +3 -5
  652. package/src/runtime/channel-retry-sweep.ts +18 -24
  653. package/src/runtime/channel-verification-service.ts +9 -11
  654. package/src/runtime/finalize-event-delivery.ts +30 -16
  655. package/src/runtime/guardian-action-service.ts +10 -11
  656. package/src/runtime/guardian-reply-router.ts +122 -21
  657. package/src/runtime/http-server.ts +44 -101
  658. package/src/runtime/introduction-policy.test.ts +214 -0
  659. package/src/runtime/introduction-policy.ts +284 -0
  660. package/src/runtime/invite-service.ts +104 -361
  661. package/src/runtime/local-actor-identity.test.ts +38 -0
  662. package/src/runtime/local-actor-identity.ts +14 -0
  663. package/src/runtime/middleware/__tests__/rate-limiter.test.ts +22 -0
  664. package/src/runtime/middleware/rate-limiter.ts +30 -0
  665. package/src/runtime/middleware/twilio-validation.ts +5 -7
  666. package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +28 -0
  667. package/src/runtime/migrations/origin-mode.ts +6 -6
  668. package/src/runtime/pre-first-message-gate.ts +1 -0
  669. package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +6 -35
  670. package/src/runtime/routes/__tests__/consolidation-routes.test.ts +24 -3
  671. package/src/runtime/routes/__tests__/contact-routes.test.ts +80 -15
  672. package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +7 -1
  673. package/src/runtime/routes/__tests__/global-search-routes.test.ts +0 -3
  674. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +142 -1
  675. package/src/runtime/routes/__tests__/invite-relay-routes.test.ts +119 -30
  676. package/src/runtime/routes/__tests__/migration-import-allowed-hosts-env.test.ts +70 -0
  677. package/src/runtime/routes/__tests__/monitoring-routes.test.ts +194 -0
  678. package/src/runtime/routes/__tests__/plugins-routes.test.ts +755 -29
  679. package/src/runtime/routes/__tests__/retrospective-routes.test.ts +4 -0
  680. package/src/runtime/routes/__tests__/schedule-routes-create.test.ts +70 -0
  681. package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +161 -0
  682. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +1 -1
  683. package/src/runtime/routes/__tests__/surface-content-routes.test.ts +1 -1
  684. package/src/runtime/routes/acp-routes.ts +15 -3
  685. package/src/runtime/routes/app-management-routes.ts +4 -7
  686. package/src/runtime/routes/approval-routes.ts +4 -0
  687. package/src/runtime/routes/attachment-routes.ts +54 -3
  688. package/src/runtime/routes/avatar-routes.ts +0 -4
  689. package/src/runtime/routes/background-tool-routes.ts +34 -5
  690. package/src/runtime/routes/btw-routes.ts +32 -4
  691. package/src/runtime/routes/channel-route-shared.ts +18 -14
  692. package/src/runtime/routes/channel-verification-routes.ts +0 -3
  693. package/src/runtime/routes/contact-routes.ts +298 -117
  694. package/src/runtime/routes/conversation-list-routes.ts +6 -0
  695. package/src/runtime/routes/conversation-management-routes.ts +74 -37
  696. package/src/runtime/routes/conversation-query-routes.ts +5 -2
  697. package/src/runtime/routes/conversation-routes.ts +222 -82
  698. package/src/runtime/routes/conversations-import-routes.ts +8 -1
  699. package/src/runtime/routes/credential-prompt-routes.ts +20 -5
  700. package/src/runtime/routes/debug-routes.ts +1 -0
  701. package/src/runtime/routes/documents-routes.ts +5 -2
  702. package/src/runtime/routes/empty-state-greeting-cache.ts +37 -10
  703. package/src/runtime/routes/global-search-routes.ts +2 -1
  704. package/src/runtime/routes/guardian-approval-interception.ts +51 -0
  705. package/src/runtime/routes/home-feed-routes.ts +60 -1
  706. package/src/runtime/routes/identity-routes.ts +4 -87
  707. package/src/runtime/routes/inbound-message-handler.ts +82 -41
  708. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +430 -57
  709. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +302 -572
  710. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +76 -270
  711. package/src/runtime/routes/inbound-stages/background-dispatch.ts +21 -116
  712. package/src/runtime/routes/inbound-stages/edit-intercept.ts +9 -1
  713. package/src/runtime/routes/inbound-stages/escalation-intercept.test.ts +158 -0
  714. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +22 -1
  715. package/src/runtime/routes/index.ts +6 -0
  716. package/src/runtime/routes/inference-provider-connection-routes.ts +22 -16
  717. package/src/runtime/routes/internal-twilio-routes.ts +0 -15
  718. package/src/runtime/routes/messages-lexical-routes.ts +75 -0
  719. package/src/runtime/routes/migration-routes.ts +69 -6
  720. package/src/runtime/routes/monitoring-routes.ts +237 -0
  721. package/src/runtime/routes/plugins-routes.ts +329 -8
  722. package/src/runtime/routes/schedule-routes.ts +49 -8
  723. package/src/runtime/routes/schedule-worker-routes.ts +210 -0
  724. package/src/runtime/routes/secret-routes.ts +1 -1
  725. package/src/runtime/routes/surface-conversation-resolver.ts +1 -0
  726. package/src/runtime/services/__tests__/analyze-conversation.test.ts +54 -9
  727. package/src/runtime/services/__tests__/auto-analysis-enqueue.test.ts +30 -6
  728. package/src/runtime/services/__tests__/conversation-analyze-job.test.ts +43 -8
  729. package/src/runtime/services/__tests__/conversation-serializer.test.ts +20 -0
  730. package/src/runtime/services/analyze-conversation.ts +14 -4
  731. package/src/runtime/services/conversation-serializer.ts +5 -0
  732. package/src/runtime/slack-no-response.ts +47 -0
  733. package/src/runtime/slack-reply-session.test.ts +633 -0
  734. package/src/runtime/slack-reply-session.ts +382 -0
  735. package/src/runtime/slack-task-progress.ts +95 -0
  736. package/src/runtime/sync/resource-sync-events.ts +25 -0
  737. package/src/runtime/tool-grant-request-helper.ts +17 -1
  738. package/src/runtime/trust-class.test.ts +141 -0
  739. package/src/runtime/trust-class.ts +121 -0
  740. package/src/runtime/trust-verdict-consumer.ts +7 -6
  741. package/src/schedule/__tests__/run-script.test.ts +21 -0
  742. package/src/schedule/__tests__/worker-control.test.ts +241 -0
  743. package/src/schedule/run-script.ts +13 -6
  744. package/src/schedule/schedule-usage-store.ts +1 -0
  745. package/src/schedule/scheduler.ts +178 -127
  746. package/src/schedule/worker-control.ts +118 -0
  747. package/src/schedule/worker.ts +131 -0
  748. package/src/skills/__tests__/categories-cache.test.ts +38 -0
  749. package/src/skills/categories-cache.ts +40 -5
  750. package/src/skills/managed-store.ts +41 -6
  751. package/src/skills/validate-input.ts +47 -0
  752. package/src/stt/types.ts +5 -9
  753. package/src/subagent/manager.ts +267 -39
  754. package/src/subagent/types.ts +6 -2
  755. package/src/subagent/validate-allowlists.ts +65 -0
  756. package/src/telemetry/watchdog-direct-emit.test.ts +109 -0
  757. package/src/telemetry/watchdog-direct-emit.ts +89 -0
  758. package/src/tools/acp/list-agents.test.ts +0 -6
  759. package/src/tools/background-tool-registry.ts +61 -0
  760. package/src/tools/document/document-comment-tool.test.ts +4 -0
  761. package/src/tools/host-terminal/host-shell.test.ts +397 -0
  762. package/src/tools/host-terminal/host-shell.ts +203 -14
  763. package/src/tools/skills/find-similar-skills.test.ts +152 -1
  764. package/src/tools/skills/find-similar-skills.ts +30 -4
  765. package/src/tools/skills/load.ts +36 -0
  766. package/src/tools/skills/scaffold-managed.ts +66 -34
  767. package/src/tools/skills/skill-script-runner.ts +17 -0
  768. package/src/tools/skills/skill-tool-factory.ts +5 -1
  769. package/src/tools/terminal/safe-env.ts +3 -0
  770. package/src/tools/terminal/shell.test.ts +177 -0
  771. package/src/tools/terminal/shell.ts +98 -4
  772. package/src/tools/tool-approval-handler.ts +106 -29
  773. package/{node_modules/@vellumai/skill-host-contracts/src → src/tools}/tool-types.ts +16 -17
  774. package/src/tools/types.ts +29 -17
  775. package/src/tools/ui-surface/definitions.ts +3 -1
  776. package/src/tts/__tests__/provider-adapters.test.ts +37 -0
  777. package/src/tts/__tests__/provider-catalog.test.ts +21 -0
  778. package/src/tts/provider-catalog.ts +40 -9
  779. package/src/tts/providers/fish-audio-provider.ts +19 -10
  780. package/src/tts/types.ts +3 -4
  781. package/src/util/__tests__/process-tree.test.ts +10 -2
  782. package/src/util/__tests__/text-spacing.test.ts +53 -0
  783. package/src/util/cgroup-memory.ts +142 -0
  784. package/src/util/image-conversion.ts +281 -0
  785. package/src/util/phone.ts +1 -8
  786. package/src/util/platform.ts +33 -0
  787. package/src/util/process-tree.ts +10 -2
  788. package/src/util/text-spacing.ts +53 -0
  789. package/src/util/worker-process.ts +271 -0
  790. package/src/workflows/journal-store.ts +16 -1
  791. package/src/workflows/library.test.ts +35 -20
  792. package/src/workflows/library.ts +105 -66
  793. package/src/workspace/git-service.ts +1 -0
  794. package/src/workspace/migrations/011-backfill-installation-id.ts +83 -31
  795. package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +41 -22
  796. package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +1 -1
  797. package/src/workspace/migrations/118-seed-now-md.ts +64 -0
  798. package/src/workspace/migrations/119-strip-persisted-memory-v3-tuning-defaults.ts +169 -0
  799. package/src/workspace/migrations/120-revise-onboarding-threads.ts +47 -0
  800. package/src/workspace/migrations/121-seed-default-user-guardrails.ts +82 -0
  801. package/src/workspace/migrations/122-relocate-default-user-boundary.ts +111 -0
  802. package/src/workspace/migrations/123-swap-quality-profile-to-fable.ts +85 -0
  803. package/src/workspace/migrations/__tests__/119-strip-persisted-memory-v3-tuning-defaults.test.ts +181 -0
  804. package/src/workspace/migrations/registry.ts +12 -0
  805. package/drizzle/0000_dizzy_maggott.sql +0 -301
  806. package/drizzle/meta/0000_snapshot.json +0 -1933
  807. package/drizzle/meta/_journal.json +0 -13
  808. package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +0 -887
  809. package/node_modules/@vellumai/skill-host-contracts/bun.lock +0 -24
  810. package/node_modules/@vellumai/skill-host-contracts/package.json +0 -18
  811. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -97
  812. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +0 -1349
  813. package/node_modules/@vellumai/skill-host-contracts/src/index.ts +0 -6
  814. package/node_modules/@vellumai/skill-host-contracts/src/runtime-mode.ts +0 -11
  815. package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +0 -32
  816. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +0 -333
  817. package/node_modules/@vellumai/skill-host-contracts/tsconfig.json +0 -20
  818. package/node_modules/@vellumai/skill-host-contracts/tsconfig.test.json +0 -12
  819. package/src/__tests__/invite-redemption-service.test.ts +0 -1180
  820. package/src/__tests__/invite-service-ipc.test.ts +0 -350
  821. package/src/__tests__/job-handler-registry-guard.test.ts +0 -125
  822. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +0 -203
  823. package/src/__tests__/relay-server.test.ts +0 -6153
  824. package/src/__tests__/telephony-stt-routing.test.ts +0 -329
  825. package/src/__tests__/voice-invite-redemption.test.ts +0 -702
  826. package/src/calls/relay-server.ts +0 -2463
  827. package/src/calls/telephony-stt-routing.ts +0 -145
  828. package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +0 -128
  829. package/src/daemon/__tests__/daemon-skill-host.test.ts +0 -273
  830. package/src/daemon/daemon-skill-host.ts +0 -262
  831. package/src/daemon/message-types/meet.ts +0 -143
  832. package/src/daemon/shutdown-registry.ts +0 -40
  833. package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -253
  834. package/src/ipc/__tests__/skill-server.test.ts +0 -182
  835. package/src/ipc/skill-ipc-types.ts +0 -54
  836. package/src/ipc/skill-routes/__tests__/config.test.ts +0 -146
  837. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +0 -448
  838. package/src/ipc/skill-routes/__tests__/identity.test.ts +0 -62
  839. package/src/ipc/skill-routes/__tests__/log.test.ts +0 -133
  840. package/src/ipc/skill-routes/__tests__/memory.test.ts +0 -203
  841. package/src/ipc/skill-routes/__tests__/platform.test.ts +0 -111
  842. package/src/ipc/skill-routes/__tests__/providers.test.ts +0 -265
  843. package/src/ipc/skill-routes/__tests__/registries.test.ts +0 -400
  844. package/src/ipc/skill-routes/config.ts +0 -47
  845. package/src/ipc/skill-routes/events.ts +0 -147
  846. package/src/ipc/skill-routes/identity.ts +0 -21
  847. package/src/ipc/skill-routes/index.ts +0 -37
  848. package/src/ipc/skill-routes/log.ts +0 -40
  849. package/src/ipc/skill-routes/memory.ts +0 -92
  850. package/src/ipc/skill-routes/platform.ts +0 -39
  851. package/src/ipc/skill-routes/providers.ts +0 -162
  852. package/src/ipc/skill-routes/registries.ts +0 -338
  853. package/src/ipc/skill-server.ts +0 -831
  854. package/src/ipc/skill-socket-path.ts +0 -20
  855. package/src/jobs/register-job-handlers.ts +0 -74
  856. package/src/persistence/invite-store.ts +0 -481
  857. package/src/plugins/job-handler-registry.ts +0 -94
  858. package/src/providers/cache-control.ts +0 -26
  859. package/src/runtime/__tests__/runtime-mode.test.ts +0 -62
  860. package/src/runtime/invite-redemption-service.ts +0 -828
  861. package/src/runtime/invite-redemption-templates.ts +0 -46
  862. package/src/runtime/runtime-mode.ts +0 -40
  863. package/src/runtime/slack-dm-text-delivery.ts +0 -177
  864. package/src/util/voice-code.ts +0 -31
package/ARCHITECTURE.md CHANGED
@@ -16,10 +16,10 @@ This document owns assistant-runtime architecture details. The repo-level archit
16
16
  - Guardian/non-guardian/unverified classification is centralized in `assistant/src/runtime/trust-context-resolver.ts`.
17
17
  - The same resolver is used by:
18
18
  - `/channels/inbound` (Telegram/WhatsApp path) before run orchestration.
19
- - Inbound Twilio voice setup (`RelayConnection.handleSetup`) to seed call-time actor context.
19
+ - Inbound Twilio voice setup (media-stream `routeSetup`) to seed call-time actor context.
20
20
  - Runtime channel runs pass this as `trustContext`, and conversation runtime assembly includes actor context in the unified `<turn_context>` block (via `buildUnifiedTurnContextBlock()`) injected into provider-facing prompts.
21
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`.
22
- - Voice-specific behavior (DTMF/speech verification flow, relay state machine) remains voice-local; only actor-role resolution is shared.
22
+ - Voice-specific behavior (DTMF/speech verification flow, call-setup state machine) remains voice-local; only actor-role resolution is shared.
23
23
 
24
24
  ### Safe Storage Limits
25
25
 
@@ -289,17 +289,17 @@ When a voice call's ASK_GUARDIAN consultation times out before the guardian resp
289
289
 
290
290
  **Key source files:**
291
291
 
292
- | File | Purpose |
293
- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
294
- | `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 |
295
- | `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 |
296
- | `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 |
297
- | `src/daemon/guardian-action-generators.ts` | Daemon-injected generator factory: `createGuardianActionCopyGenerator` (latency-optimized text rewriting for guardian-facing copy) |
298
- | `src/calls/call-controller.ts` | Voice timeout handling: marks requests as timed out, sends expiry notices, injects `[GUARDIAN_TIMEOUT]` instruction for generated voice response |
299
- | `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 |
300
- | `src/daemon/conversation-process.ts` | Late reply interception for mac channel: same logic as inbound-message-handler but using conversation-ID-based delivery lookup |
301
- | `src/calls/guardian-action-sweep.ts` | Periodic sweep for stale pending requests; sends expiry notices to guardian destinations |
302
- | `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`) |
292
+ | File | Purpose |
293
+ | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
294
+ | `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 |
295
+ | `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 |
296
+ | `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 |
297
+ | `src/daemon/guardian-action-generators.ts` | Daemon-injected generator factory: `createGuardianActionCopyGenerator` (latency-optimized text rewriting for guardian-facing copy) |
298
+ | `src/calls/call-controller.ts` | Voice timeout handling: marks requests as timed out, sends expiry notices, injects `[GUARDIAN_TIMEOUT]` instruction for generated voice response |
299
+ | `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 |
300
+ | `src/daemon/conversation-process.ts` | Late reply interception for mac channel: same logic as inbound-message-handler but using conversation-ID-based delivery lookup |
301
+ | `src/calls/guardian-action-sweep.ts` | Periodic sweep for stale pending requests; sends expiry notices to guardian destinations |
302
+ | `src/persistence/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`) |
303
303
 
304
304
  ### WhatsApp Channel (Meta Cloud API)
305
305
 
@@ -429,9 +429,8 @@ External users who are not the guardian can gain access to the assistant through
429
429
  | `src/runtime/routes/access-request-decision.ts` | Guardian decision → verification session creation |
430
430
  | `src/runtime/routes/guardian-approval-interception.ts` | Routes guardian decisions (button + conversational) to access request handler |
431
431
  | `src/runtime/channel-verification-service.ts` | Verification session lifecycle, identity binding, rate limiting |
432
- | `src/runtime/routes/contact-routes.ts` | HTTP API handlers for contact and channel management |
433
- | `src/runtime/routes/invite-routes.ts` | HTTP API handlers for invite management |
434
- | `src/runtime/invite-service.ts` | Business logic for invite operations |
432
+ | `src/runtime/routes/contact-routes.ts` | HTTP/IPC handlers for contacts, channels, and invites (invite ops relay to gateway IPC) |
433
+ | `src/runtime/invite-service.ts` | Daemon-owned invite presentation (share link, guardian instruction) over gateway-minted invites |
435
434
  | `src/contacts/contact-store.ts` | Contact read queries — lookup, search, list, and channel operations |
436
435
  | `src/memory/guardian-approvals.ts` | Approval request persistence |
437
436
  | `src/channels/channel-verification-sessions.ts` | Verification challenge persistence |
@@ -455,11 +454,12 @@ A complementary access-granting flow where the guardian proactively creates a sh
455
454
  │ • extractInboundToken(payload) → token | undefined │
456
455
  │ Registered: Telegram │ Deferred: Slack, Voice │
457
456
  ├─────────────────────────────────────────────────────────────┤
458
- │ Core Redemption Engine (invite-redemption-service.ts)
459
- Channel-agnostic token validation, expiry, use-count,
460
- channel-match enforcement, contact activation/reactivation
457
+ │ Core Redemption Engine (gateway-native)
458
+ gateway/src/verification/invite-redemption.ts
459
+ Token/code validation, expiry, use-count, channel-match
460
+ │ enforcement, atomic claim, gateway ACL activation │
461
461
  │ Returns: InviteRedemptionOutcome (discriminated union) │
462
- Reply templates: invite-redemption-templates.ts
462
+ Daemon mirrors contact info via the invite_redeemed event
463
463
  └─────────────────────────────────────────────────────────────┘
464
464
  ```
465
465
 
@@ -467,42 +467,42 @@ A complementary access-granting flow where the guardian proactively creates a sh
467
467
 
468
468
  1. Guardian asks the assistant to create an invite via desktop chat.
469
469
  2. `guardian-invite-intent.ts` detects the intent and rewrites the message to force-load the `contacts` skill.
470
- 3. The skill calls the ingress HTTP API to create an invite token, then calls the Telegram transport adapter to build a deep link: `https://t.me/<bot>?start=iv_<token>`.
470
+ 3. The skill calls the invites HTTP API; the daemon relays the mint to the gateway (`invites_create` IPC), which writes the canonical `ingress_invites` row, then the daemon's Telegram transport adapter builds a deep link: `https://t.me/<bot>?start=iv_<token>`.
471
471
  4. Guardian shares the link with the invitee out-of-band.
472
472
  5. Invitee clicks the link, opening Telegram which sends `/start iv_<token>` to the bot.
473
- 6. The gateway forwards the message to `/channels/inbound`. The inbound handler calls `getInviteAdapterRegistry().get('telegram').extractInboundToken()` to parse the `iv_` token.
474
- 7. The token is redeemed via `invite-redemption-service.ts`, which validates, activates the contact, and returns a `redeemed` outcome.
473
+ 6. The gateway intercepts the `/start iv_<token>` message at ingress (before any daemon forwarding) and redeems the token against its canonical `ingress_invites` row.
474
+ 7. The gateway's redemption engine validates, activates the channel in the gateway ACL, and notifies the daemon (`invite_redeemed`) to mirror the contact info locally.
475
475
  8. A deterministic welcome message is delivered to the invitee (bypasses the LLM pipeline).
476
476
 
477
477
  **Token prefix convention:** The `iv_` prefix distinguishes invite tokens from `gv_` (guardian verification) tokens. Both use the same Telegram `/start` deep-link mechanism but are routed to different handlers.
478
478
 
479
- **Inbound intercept points:** Invite token extraction runs early in the inbound handler, before ACL denial, so valid invites short-circuit the contact check. Two intercept branches handle: (a) unknown contacts — the invite creates their first contact record; (b) inactive contacts (revoked/pending) — the invite reactivates them.
479
+ **Inbound intercept points:** Invite token/code extraction runs at gateway ingress for non-member senders, before ACL denial, so valid invites short-circuit the contact check. The engine handles: (a) unknown contacts — the invite creates their first channel record; (b) inactive contacts (revoked) — the invite reactivates them; blocked channels are never reactivated.
480
480
 
481
481
  **Channel adapter status:**
482
482
 
483
483
  | Channel | Status | Prerequisites |
484
484
  | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
485
485
  | Telegram | Shipped | Bot username resolved from credential metadata or config |
486
- | 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. |
486
+ | Voice | Shipped | Identity-bound voice code redemption via DTMF/speech in the call setup flow. Always-on canonical behavior with personalized friend/guardian name prompts. |
487
487
  | Slack | Deferred | Needs DM-safe ingress — Socket Mode handles channel messages but DM-initiated invite flows need routing |
488
488
 
489
- ### Voice Invite Flow (invite_redemption_pending)
489
+ ### Voice Invite Flow (invite_redemption)
490
490
 
491
- Voice invites use a short numeric code (4-10 digits, default 6) instead of a URL token. The guardian creates an invite bound to the invitee's E.164 phone number; the invitee redeems it by entering the code during an inbound voice call.
491
+ Voice invites use a short numeric code (6 digits) instead of a URL token. The guardian creates an invite bound to the invitee's E.164 phone number; the invitee redeems it by entering the code during an inbound voice call.
492
492
 
493
493
  **Creation flow:**
494
494
 
495
495
  1. Guardian creates a voice invite via `POST /v1/contacts/invites` with `sourceChannel: "phone"` and `expectedExternalUserId` (E.164 phone).
496
- 2. `invite-service.ts` generates a cryptographically random numeric code (`generateVoiceCode`), hashes it with SHA-256 (`hashVoiceCode`), and stores only the hash.
496
+ 2. The daemon relays the mint to the gateway (`invites_create` IPC), which generates a cryptographically random numeric code and stores only its SHA-256 hash on the canonical `ingress_invites` row.
497
497
  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.
498
498
  4. Guardian communicates the code to the invitee out-of-band.
499
499
 
500
- **Call-time redemption subflow (`invite_redemption_pending`):**
500
+ **Call-time redemption subflow (`invite_redemption`):**
501
501
 
502
- 1. Unknown caller dials in. `relay-server.ts` resolves trust via `resolveActorTrust`. Caller is `unknown`, no pending guardian challenge.
503
- 2. The relay checks `findActiveVoiceInvites` for invites bound to the caller's phone number.
504
- 3. If active, non-expired invites exist, the relay enters the `invite_redemption_pending` state (reuses the `verification_pending` connection state) and prompts the caller with personalized copy: `Welcome <friend-name>. Please enter the 6-digit code that <guardian-name> provided you to verify your identity.`
505
- 4. `redeemVoiceInviteCode` validates: identity match, code hash match, expiry, use count. On success, the contact is activated and the call transitions to the normal call flow.
502
+ 1. Unknown caller dials in. The media-stream server resolves trust (gateway trust verdict first, `resolveActorTrust` fallback inside `routeSetup`). Caller is `unknown`, no pending guardian challenge.
503
+ 2. `routeSetup` asks the gateway for the active voice invite bound to the caller's phone number (`get_active_voice_invite` IPC via `calls/gateway-invite-reader.ts`; fail-soft — any gateway failure falls through to the unverified path).
504
+ 3. If an active, non-expired invite exists, the `CallSetupFlow` runs the `invite_redemption` sub-flow (collecting the code via DTMF or spoken digits) and prompts the caller with personalized copy: `Welcome <friend-name>. Please enter the 6-digit code that <guardian-name> provided you to verify your identity.`
505
+ 4. The gateway's `redeem_voice_invite` engine validates: identity match, code hash match, expiry, use count. On success, the phone channel is activated in the gateway ACL and the call transitions to the normal call flow.
506
506
  5. On invalid/expired code, the caller hears deterministic failure copy: `Sorry, the code you provided is incorrect or has since expired. Please ask <guardian-name> for a new code. Goodbye.` and the call ends immediately.
507
507
 
508
508
  **Security invariants:**
@@ -516,22 +516,19 @@ Voice invites use a short numeric code (4-10 digits, default 6) instead of a URL
516
516
 
517
517
  | File | Purpose |
518
518
  | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
519
- | `src/runtime/invite-redemption-service.ts` | Core redemption engine token validation, voice code redemption, contact activation, discriminated-union outcomes |
520
- | `src/runtime/invite-redemption-templates.ts` | Deterministic reply templates for each redemption outcome |
519
+ | `gateway/src/verification/invite-redemption.ts` (gateway) | Core redemption engine + gateway-ingress token/code intercept — validation, atomic claim, ACL activation, discriminated-union outcomes |
521
520
  | `src/runtime/channel-invite-transport.ts` | Transport adapter registry with `buildShareableInvite` / `extractInboundToken` interface |
522
521
  | `src/runtime/channel-invite-transports/telegram.ts` | Telegram adapter — `t.me/<bot>?start=iv_<token>` deep links, `/start iv_<token>` extraction |
523
522
  | `src/runtime/channel-invite-transports/voice.ts` | Voice transport adapter — code-based redemption metadata |
524
523
  | `src/daemon/guardian-invite-intent.ts` | Intent detection — routes create/list/revoke requests into the contacts skill |
525
- | `src/runtime/invite-service.ts` | Shared business logic for invite operations (used by HTTP routes) |
526
- | `src/runtime/routes/invite-routes.ts` | HTTP API handlers for invite management including voice invite creation and redemption |
527
- | `src/runtime/routes/inbound-message-handler.ts` | Invite token intercept in the inbound flow (unknown-contact and inactive-contact branches) |
528
- | `src/calls/relay-server.ts` | Voice relay state machine `invite_redemption_pending` subflow (always-on canonical behavior) |
529
- | `src/util/voice-code.ts` | Cryptographic voice code generation and SHA-256 hashing |
530
- | `src/memory/invite-store.ts` | Invite persistence including `findActiveVoiceInvites` for identity-bound lookup |
524
+ | `src/runtime/invite-service.ts` | Daemon-owned invite presentation (share link, guardian instruction, channel handle) over gateway-minted invites |
525
+ | `src/runtime/routes/contact-routes.ts` | HTTP/IPC invite handlers relay mint/list/revoke/redeem to the gateway's invite IPC routes |
526
+ | `src/calls/call-setup-flow.ts` | Transport-agnostic call setup flow `invite_redemption` sub-flow (always-on canonical behavior) |
527
+ | `src/calls/gateway-invite-reader.ts` | Gateway IPC read of the active voice invite for a caller identity |
531
528
 
532
529
  ### Voice Inbound Security Model (Canonical)
533
530
 
534
- The voice inbound security model determines how unknown callers are handled when they dial in. Three paths exist, evaluated in priority order by `relay-server.ts` during the `handleSetup` phase. All guardian decisions route through `applyCanonicalGuardianDecision` in the canonical guardian request system.
531
+ The voice inbound security model determines how unknown callers are handled when they dial in. Three paths exist, evaluated in priority order by `routeSetup` (`relay-setup-router.ts`) when the media-stream session starts. All guardian decisions route through `applyCanonicalGuardianDecision` in the canonical guardian request system.
535
532
 
536
533
  **Decision tree for inbound unknown callers:**
537
534
 
@@ -550,7 +547,7 @@ resolveActorTrust() → trustClass
550
547
  |
551
548
  ┌────────────────────┼──────────────────────┐
552
549
  | | |
553
- pendingChallenge? activeVoiceInvites? no invite, no challenge
550
+ pendingChallenge? activeVoiceInvite? no invite, no challenge
554
551
  | | |
555
552
  v v v
556
553
  Guardian verification Invite redemption Name capture +
@@ -559,17 +556,17 @@ resolveActorTrust() → trustClass
559
556
 
560
557
  **Path 1: Voice invite code redemption (guardian-initiated)**
561
558
 
562
- The guardian proactively creates a voice invite bound to the caller's E.164 phone number. When the unknown caller dials in and has an active, non-expired invite, the relay enters the `invite_redemption_pending` subflow with personalized prompts using the friend's and guardian's names. This is always-on canonical behavior (no feature flag). See [Voice Invite Flow](#voice-invite-flow-invite_redemption_pending) above.
559
+ The guardian proactively creates a voice invite bound to the caller's E.164 phone number. When the unknown caller dials in and has an active, non-expired invite, the setup flow enters the `invite_redemption` sub-flow with personalized prompts using the friend's and guardian's names. This is always-on canonical behavior (no feature flag). See [Voice Invite Flow](#voice-invite-flow-invite_redemption) above.
563
560
 
564
561
  **Path 2: Live in-call guardian approval (friend-initiated)**
565
562
 
566
- When no invite exists and no pending guardian challenge is active, the relay enters the name capture + guardian approval wait flow:
563
+ When no invite exists and no pending guardian challenge is active, the setup flow enters the name capture + guardian approval wait flow:
567
564
 
568
- 1. The relay transitions to `awaiting_name` state and prompts the caller for their name with a timeout.
565
+ 1. The setup flow transitions to `capturing_name` state and prompts the caller for their name with a timeout.
569
566
  2. On name capture, `notifyGuardianOfAccessRequest` creates a canonical guardian request (`kind: 'access_request'`) and notifies the guardian via the notification pipeline.
570
- 3. The relay transitions to `awaiting_guardian_decision` and plays hold music/messaging while polling the canonical request status.
567
+ 3. The setup flow hands off to a `GuardianWaitController` (`awaiting_guardian_decision`), which speaks hold messaging and heartbeat updates while polling the canonical request status.
571
568
  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`.
572
- 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.
569
+ 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, and the setup flow completes into the normal call flow with the caller's guardian context updated.
573
570
  6. On denial or timeout: the caller hears a denial message and the call ends.
574
571
 
575
572
  **Path 3: Inbound guardian verification (pending challenge)**
@@ -589,7 +586,9 @@ All guardian decisions for voice access requests flow through:
589
586
 
590
587
  | File | Purpose |
591
588
  | ---------------------------------------------- | -------------------------------------------------------------------------------------- |
592
- | `src/calls/relay-server.ts` | Inbound call decision tree, name capture, guardian approval wait polling |
589
+ | `src/calls/relay-setup-router.ts` | Inbound call decision tree (`routeSetup`) |
590
+ | `src/calls/call-setup-flow.ts` | Name capture, verification, and invite sub-flows over the media-stream transport |
591
+ | `src/calls/guardian-wait-controller.ts` | Guardian approval wait — hold messaging, heartbeats, poll/timeout |
593
592
  | `src/runtime/access-request-helper.ts` | Creates canonical access request and notifies guardian |
594
593
  | `src/approvals/guardian-decision-primitive.ts` | `applyCanonicalGuardianDecision` — unified decision primitive |
595
594
  | `src/approvals/guardian-request-resolvers.ts` | `access_request` resolver — voice direct activation, text-channel verification session |
@@ -606,37 +605,41 @@ Audio-to-text conversion occurs in six distinct runtime boundaries, each with it
606
605
 
607
606
  | Boundary | Runtime | Provider (current) | Adapter module | Caller |
608
607
  | -------------------------- | ----------------------------------------------------------------------------- | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
609
- | **Telephony (hybrid)** | Twilio-native ConversationRelay or daemon media-stream (provider-conditional) | Configured STT provider (via `services.stt`) | `src/calls/telephony-stt-routing.ts` | `src/calls/twilio-routes.ts` |
608
+ | **Telephony (media-stream)** | Daemon process (Twilio Media Streams WebSocket) | Configured STT provider (via `services.stt`) | `src/calls/media-stream-stt-session.ts`, `src/providers/speech-to-text/resolve.ts`, streaming provider adapters | `src/calls/media-stream-server.ts` |
610
609
  | **Daemon batch** | Daemon process (REST API to provider) | Configured STT provider (via `services.stt`) | `src/stt/daemon-batch-transcriber.ts` | `src/runtime/routes/inbound-stages/transcribe-audio.ts` |
611
610
  | **Conversation streaming** | Daemon process (WebSocket-based) | Configured STT provider (via `services.stt`) | `src/stt/stt-stream-session.ts`, `src/providers/speech-to-text/deepgram-realtime.ts`, `src/providers/speech-to-text/google-gemini-live-stream.ts`, `src/providers/speech-to-text/openai-whisper-stream.ts`, `src/providers/speech-to-text/xai-realtime.ts` | Web/Electron dictation client via gateway WS proxy |
612
611
  | **Live voice channel** | Assistant process (gateway-authenticated WebSocket) | Configured STT provider (via `services.stt`) | `src/runtime/http-server.ts`, `src/live-voice/live-voice-session-manager.ts`, `src/live-voice/live-voice-session.ts`, `src/providers/speech-to-text/resolve.ts`, streaming provider adapters | Web/Electron live voice client via `/v1/live-voice` |
613
612
  | **Client service-first** | Web/Electron via gateway → daemon | Configured STT provider (via `services.stt`) | `src/runtime/routes/stt-routes.ts` | Web/Electron dictation and voice clients |
614
613
 
615
- **Telephony boundary (hybrid routing):**
614
+ **Telephony boundary (media-stream):**
616
615
 
617
- Telephony STT uses a provider-conditional hybrid model driven by `services.stt.provider`. The routing resolver (`src/calls/telephony-stt-routing.ts`) maps the configured provider to a discriminated strategy at call setup time:
616
+ Every phone call connects over Twilio Media Streams: the voice webhook emits `<Connect><Stream>` TwiML pointing to the gateway's media-stream proxy, and the daemon performs both STT and TTS itself — Twilio only carries mu-law audio frames. The `<Stream url="...">` encodes `callSessionId` and auth `token` as **URL path segments** (e.g. `.../media-stream/<callSessionId>/<token>`) because Twilio Media Streams does not reliably preserve query parameters across the WebSocket upgrade. The gateway extracts metadata from path segments (with query-parameter fallback for backward compatibility) and proxies raw audio frames to the daemon.
618
617
 
619
- - **`conversation-relay-native`** (Deepgram, Google) TwiML emits `<Connect><ConversationRelay>` with `transcriptionProvider` and `speechModel` attributes. Twilio handles audio ingestion and transcription natively; the daemon receives transcribed text via the relay WebSocket. The Twilio-native provider name and default speech model are read from the provider catalog entry's `telephonyRouting.twilioNativeMapping` (e.g. Deepgram maps to `provider: "Deepgram"` with `defaultSpeechModel: "nova-3"`; Google maps to `provider: "Google"` with `defaultSpeechModel: undefined`).
618
+ Transcription mode is selected once per session in `media-stream-stt-session.ts`:
620
619
 
621
- - **`media-stream-custom`** (OpenAI Whisper) — TwiML emits `<Connect><Stream>` pointing to the gateway's media-stream proxy. The `<Stream url="...">` encodes `callSessionId` and auth `token` as **URL path segments** (e.g. `.../media-stream/<callSessionId>/<token>`) because Twilio Media Streams does not reliably preserve query parameters across the WebSocket upgrade. The gateway extracts metadata from path segments (with query-parameter fallback for backward compatibility) and proxies raw audio frames to the daemon, which transcribes server-side via the provider's batch API.
620
+ - **Streaming** (default) — when `calls.voice.telephonyStreaming` is enabled and the configured provider resolves a streaming transcriber (`resolveStreamingTranscriber()`), inbound audio is decoded (mu-law PCM16, resampled 8 kHz 16 kHz) and fed to the provider's realtime adapter. Replies trigger only on utterance-boundary finals (for Deepgram, `speech_final`/`UtteranceEnd`, never mid-sentence `is_final` segments), and barge-in fires from local energy VAD, never from transcriber partials.
621
+ - **Batch fallback** — otherwise the session segments turns with the energy-based `MediaTurnDetector` and transcribes each completed turn via the provider's batch API.
622
+
623
+ A credential preflight (`resolveTelephonyCredentialReadiness()` in `src/calls/telephony-credential-preflight.ts`) gates every call: it requires a credentialed, telephony-capable STT provider **and** a media-stream-playable TTS provider (the configured one or a credentialed playable fallback). Inbound calls that fail the preflight receive `<Say>` setup-required copy plus `<Hangup/>` instead of a doomed stream; outbound placement fails before dialing via `preflightVoiceIngress()` with the same user-facing message.
622
624
 
623
625
  Key modules:
624
626
 
625
- | Module | Purpose |
626
- | --------------------------------------------------- | ---------------------------------------------------------------------- |
627
- | `src/calls/telephony-stt-routing.ts` | Maps `services.stt.provider` to a discriminated `TelephonySttStrategy` |
628
- | `src/calls/twilio-routes.ts` | Voice webhook handler; generates provider-conditional TwiML |
629
- | `src/calls/media-stream-parser.ts` | Twilio Media Streams protocol parser |
630
- | `src/calls/media-turn-detector.ts` | Energy-based VAD turn detector for raw audio |
631
- | `src/calls/media-stream-stt-session.ts` | STT session that transcribes audio turns via `services.stt` |
632
- | `src/calls/call-transport.ts` | Transport interface decoupling CallController from wire protocol |
633
- | `src/calls/media-stream-output.ts` | Output adapter for sending TTS audio back via Media Streams |
634
- | `src/calls/media-stream-server.ts` | WebSocket server binding media-stream lifecycle to call sessions |
635
- | `gateway/src/http/routes/twilio-media-websocket.ts` | Gateway WebSocket proxy for Media Streams frames |
627
+ | Module | Purpose |
628
+ | --------------------------------------------------- | -------------------------------------------------------------------------------- |
629
+ | `src/calls/twilio-routes.ts` | Voice webhook handler; generates `<Connect><Stream>` TwiML, enforces the inbound credential preflight |
630
+ | `src/calls/telephony-credential-preflight.ts` | Combined STT + TTS credential-readiness resolver |
631
+ | `src/calls/media-stream-parser.ts` | Twilio Media Streams protocol parser |
632
+ | `src/calls/media-turn-detector.ts` | Energy-based VAD turn detector for raw audio (batch mode) |
633
+ | `src/calls/media-stream-stt-session.ts` | STT session streaming/batch mode selection and transcription via `services.stt` |
634
+ | `src/calls/media-stream-audio-transcode.ts` | Mu-law PCM16 codecs and resampling |
635
+ | `src/calls/call-transport.ts` | Transport interface decoupling CallController from wire protocol |
636
+ | `src/calls/media-stream-output.ts` | Output adapter for sending TTS audio back via Media Streams |
637
+ | `src/calls/media-stream-server.ts` | WebSocket server binding media-stream lifecycle to call sessions and setup flows |
638
+ | `gateway/src/http/routes/twilio-media-websocket.ts` | Gateway WebSocket proxy for Media Streams frames |
636
639
 
637
- Guard tests in `__tests__/twilio-routes-twiml.test.ts` and `__tests__/twilio-routes.test.ts` assert that TwiML generation matches the provider-conditional strategy for each supported provider.
640
+ Guard tests in `__tests__/twilio-routes-twiml.test.ts` and `__tests__/twilio-routes.test.ts` assert that every supported STT provider yields `<Connect><Stream>` TwiML for both inbound and outbound calls.
638
641
 
639
- To add a new telephony STT provider: add a `telephonyRouting` entry to the provider's catalog entry in `provider-catalog.ts`. Set `strategyKind` to `"conversation-relay-native"` for Twilio-native providers (and include a `twilioNativeMapping` with the Twilio `provider` name and `defaultSpeechModel`), or `"media-stream-custom"` for providers that require daemon-side transcription. The routing resolver reads these fields from the catalog — no hardcoded maps to update.
642
+ To add a new telephony STT provider: declare `telephonyMode` and `supportedBoundaries` on the provider's catalog entry in `provider-catalog.ts`. The telephony capability resolver (`resolveTelephonySttCapability()`) reads these fields plus credential availability from the catalog — no per-provider routing maps exist.
640
643
 
641
644
  **Daemon batch boundary:**
642
645
 
@@ -747,7 +750,7 @@ The web client implements these flows in `clients/web/src/domains/chat/voice/`:
747
750
 
748
751
  **Cross-boundary notes:**
749
752
 
750
- - The `services.stt` config block is the single source of truth for STT provider selection across the daemon batch boundary, the conversation streaming boundary, the client service-first boundary, and the telephony boundary. The batch and streaming resolvers (`resolveBatchTranscriber()`, `resolveStreamingTranscriber()`) both read from `services.stt.provider` and resolve credentials through the same catalog; the telephony boundary uses `resolveTelephonySttRouting()` to determine the Twilio integration strategy. The daemon provider catalog (`src/providers/speech-to-text/provider-catalog.ts`) is the authoritative registry of supported providers. Native clients fetch display metadata via `GET /v1/stt/providers`.
753
+ - The `services.stt` config block is the single source of truth for STT provider selection across the daemon batch boundary, the conversation streaming boundary, the client service-first boundary, and the telephony boundary. The batch and streaming resolvers (`resolveBatchTranscriber()`, `resolveStreamingTranscriber()`) both read from `services.stt.provider` and resolve credentials through the same catalog; the telephony boundary's media-stream STT session uses these same resolvers — it selects streaming vs batch transcription via `resolveStreamingTranscriber()`/`resolveBatchTranscriber()` under the `calls.voice.telephonyStreaming` flag, gated by `resolveTelephonySttCapability()`, while call placement/TwiML is gated by `resolveTelephonyCredentialReadiness()`. The daemon provider catalog (`src/providers/speech-to-text/provider-catalog.ts`) is the authoritative registry of supported providers. Native clients fetch display metadata via `GET /v1/stt/providers`.
751
754
  - Conversation streaming does not replace the client service-first batch path. When streaming is available, it runs concurrently during recording and provides real-time partials and finals. The batch path remains the fallback for providers that do not support streaming, when streaming fails mid-session, or when streaming produces no final transcript.
752
755
  - Credential mapping is catalog-driven: `provider-secret-catalog.ts` derives STT API-key provider names from the daemon catalog via `listCredentialProviderNames()`, deduplicating against the LLM/search provider list. Adding a provider to the catalog automatically includes its credential name in `API_KEY_PROVIDERS`.
753
756
  - Terminology: "STT", "transcription", and "speech recognition" all refer to the same operation (converting audio to text).
@@ -799,14 +802,14 @@ The assistant feature-flag resolver (`src/config/assistant-feature-flags.ts`) is
799
802
 
800
803
  **Skill-gating guarantee:** Skill feature-flag gating is **opt-in**: only skills whose SKILL.md frontmatter contains a `featureFlag` field are gated. Skills without the field are always available regardless of feature flag state. For skills that declare a `featureFlag`, when the corresponding flag is OFF the skill is unavailable everywhere — it cannot appear in client UIs, model context, or runtime tool execution. This is enforced at six independent points:
801
804
 
802
- | Enforcement Point | Module | Effect |
803
- | -------------------------------- | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
804
- | **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. |
805
- | **2. Capability memory seeding** | `seedSkillGraphNodes()` in `memory/graph/capability-seed.ts` | Skills with flag OFF are excluded from capability memory seeding. The model cannot discover them via semantic recall. |
806
- | **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)"`. |
807
- | **4. Runtime tool projection** | `projectSkillTools()` in `daemon/conversation-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. |
808
- | **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. |
809
- | **6. Skill install gate** | `installSkill()` in `daemon/handlers/skills.ts` | When a client requests skill installation, the function checks the skill's feature flag before proceeding. If the flag is OFF, the install is rejected with an error. |
805
+ | Enforcement Point | Module | Effect |
806
+ | -------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
807
+ | **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. |
808
+ | **2. Capability memory seeding** | `seedSkillGraphNodes()` in `plugins/defaults/memory/graph/capability-seed.ts` | Skills with flag OFF are excluded from capability memory seeding. The model cannot discover them via semantic recall. |
809
+ | **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)"`. |
810
+ | **4. Runtime tool projection** | `projectSkillTools()` in `daemon/conversation-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. |
811
+ | **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. |
812
+ | **6. Skill install gate** | `installSkill()` in `daemon/handlers/skills.ts` | When a client requests skill installation, the function checks the skill's feature flag before proceeding. If the flag is OFF, the install is rejected with an error. |
810
813
 
811
814
  All six enforcement points derive the flag key via `skillFlagKey(skill)` — which returns `undefined` for ungated skills, short-circuiting the check — and then call `isAssistantFeatureFlagEnabled(flagKey, config)` for consistency.
812
815
 
@@ -814,17 +817,17 @@ All six enforcement points derive the flag key via `skillFlagKey(skill)` — whi
814
817
 
815
818
  **Key source files:**
816
819
 
817
- | File | Purpose |
818
- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
819
- | `src/config/assistant-feature-flags.ts` | Canonical resolver: `isAssistantFeatureFlagEnabled()`, registry loader |
820
- | `src/config/skill-state.ts` | `skillFlagKey(skill)` — returns canonical flag key for skills with a `featureFlag` frontmatter field, `undefined` otherwise; `resolveSkillStates()` — enforcement point 1 |
821
- | `src/memory/graph/capability-seed.ts` | `seedSkillGraphNodes()` — enforcement point 2 |
822
- | `src/tools/skills/load.ts` | `executeSkillLoad()` — enforcement points 3 and 5 |
823
- | `src/daemon/conversation-skill-tools.ts` | `projectSkillTools()` — enforcement point 4 |
824
- | `src/config/schema.ts` | `AssistantConfig` Zod schema definition (feature flag values are no longer stored here) |
825
- | `src/daemon/handlers/skills.ts` | `listSkills()` — uses `resolveSkillStates()` for client responses; `installSkill()` — enforcement point 6 |
826
- | `meta/feature-flags/feature-flag-registry.json` | Unified feature flag registry (repo root) — all declared flags with scope, label, default values, and descriptions |
827
- | `src/config/feature-flag-registry.json` | Bundled copy of the unified registry for compiled binary resolution |
820
+ | File | Purpose |
821
+ | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
822
+ | `src/config/assistant-feature-flags.ts` | Canonical resolver: `isAssistantFeatureFlagEnabled()`, registry loader |
823
+ | `src/config/skill-state.ts` | `skillFlagKey(skill)` — returns canonical flag key for skills with a `featureFlag` frontmatter field, `undefined` otherwise; `resolveSkillStates()` — enforcement point 1 |
824
+ | `src/plugins/defaults/memory/graph/capability-seed.ts` | `seedSkillGraphNodes()` — enforcement point 2 |
825
+ | `src/tools/skills/load.ts` | `executeSkillLoad()` — enforcement points 3 and 5 |
826
+ | `src/daemon/conversation-skill-tools.ts` | `projectSkillTools()` — enforcement point 4 |
827
+ | `src/config/schema.ts` | `AssistantConfig` Zod schema definition (feature flag values are no longer stored here) |
828
+ | `src/daemon/handlers/skills.ts` | `listSkills()` — uses `resolveSkillStates()` for client responses; `installSkill()` — enforcement point 6 |
829
+ | `meta/feature-flags/feature-flag-registry.json` | Unified feature flag registry (repo root) — all declared flags with scope, label, default values, and descriptions |
830
+ | `src/config/feature-flag-registry.json` | Bundled copy of the unified registry for compiled binary resolution |
828
831
 
829
832
  ---
830
833
 
@@ -2201,12 +2204,12 @@ The `TtsUseCase` discriminator (`"phone-call"` or `"message-playback"`) lets pro
2201
2204
 
2202
2205
  **Synthesis orchestrator (`synthesize-text.ts`):** `synthesizeText()` is the top-level entry point. It resolves the globally configured provider via the config resolver, looks up the adapter in the registry, and delegates synthesis. Provider selection is always global — per-use-case policy only gates capabilities (e.g. format checks), never overrides the chosen provider.
2203
2206
 
2204
- **Call strategy abstraction (`tts-call-strategy.ts`):** The call strategy layer determines how a TTS provider integrates with the Twilio ConversationRelay telephony path. Instead of inferring call behavior from runtime capabilities, `resolveCallStrategy(config)` reads the provider's `callMode` from the canonical catalog and returns a `TtsCallStrategy` with the provider ID and call mode. Two modes exist:
2207
+ **Call strategy abstraction (`tts-call-strategy.ts`):** The call strategy layer determines how a TTS provider integrates with the telephony path. Instead of inferring call behavior from runtime capabilities, `resolveCallStrategy(config)` reads the provider's `callMode` from the canonical catalog and returns a `TtsCallStrategy` with the provider ID and call mode. Two modes exist:
2205
2208
 
2206
- - **`native-twilio`** — Twilio handles TTS natively via ConversationRelay. The profile needs a real `ttsProvider` name (e.g. `"ElevenLabs"`) and a provider-specific voice spec string. New native providers plug in by registering a `NativeTwilioVoiceSpecBuilder` via `registerNativeTwilioVoiceSpec()` no edits to core call routing logic required.
2207
- - **`synthesized-play`** — The assistant synthesises audio via the provider's HTTP API and streams chunks to Twilio via `play` messages. Uses a placeholder TTS provider (`"Google"`) and an empty voice string because Twilio never drives TTS itself on this path.
2209
+ - **`native-twilio`** — the text-token path: spoken text is sent via `sendTextToken()`, which the media-stream transport re-synthesizes through daemon TTS. The profile carries a real `ttsProvider` name (e.g. `"ElevenLabs"`) and a provider-specific voice spec string built by a registered `NativeTwilioVoiceSpecBuilder`. Collapsing this mode is a documented deferred follow-up.
2210
+ - **`synthesized-play`** — The assistant synthesises audio via the provider's HTTP API and streams it through the audio store / `sendPlayUrl()` path. Uses a placeholder TTS provider (`"Google"`) and an empty voice string.
2208
2211
 
2209
- **Phone call integration:** `resolveVoiceQualityProfile()` in `voice-quality.ts` uses `resolveCallStrategy()` to determine the call mode, then dispatches to the appropriate path. For `native-twilio`, it looks up the registered `NativeTwilioVoiceSpec` to build the voice string. For `synthesized-play`, it uses the placeholder profile. This replaces the previous `supportsStreaming`-based branching with explicit catalog-declared modes.
2212
+ **Phone call integration:** Phone calls run on the media-stream transport, where the daemon synthesises speech via the configured TTS provider and transcodes it to mu-law 8 kHz frames (`media-stream-output.ts`). Each catalog entry declares `mediaStreamPlayback.outputFormat` (`pcm`, `wav`, or `none`); `resolveTelephonyTtsCapability()` (`src/calls/telephony-tts-capability.ts`) combines that field with credential availability into a playable / not-playable verdict, and the call TTS resolver falls back to a credentialed playable provider rather than producing silence. `resolveVoiceQualityProfile()` in `voice-quality.ts` uses `resolveCallStrategy()` to determine the call mode and build the voice profile.
2210
2213
 
2211
2214
  **Adding a new TTS provider (catalog-first checklist):**
2212
2215
 
package/Dockerfile CHANGED
@@ -24,7 +24,6 @@ COPY packages/egress-proxy ./packages/egress-proxy
24
24
  COPY packages/environments ./packages/environments
25
25
  COPY packages/gateway-client ./packages/gateway-client
26
26
  COPY packages/ipc-server-utils ./packages/ipc-server-utils
27
- COPY packages/skill-host-contracts ./packages/skill-host-contracts
28
27
  COPY packages/slack-text ./packages/slack-text
29
28
  COPY packages/twilio-client ./packages/twilio-client
30
29
 
@@ -52,17 +51,6 @@ RUN set -eu; for pkg in /app/skills/*/package.json; do \
52
51
  (cd "$dir" && (bun install --frozen-lockfile 2>/dev/null || bun install)); \
53
52
  done
54
53
 
55
- # Copy assistant source so emit-manifest can resolve the skill's remaining
56
- # `../../assistant/src/...` imports while walking the register() module
57
- # graph. Those imports disappear when skill-isolation Phase 1 completes
58
- # (plan PR 18); the collector host short-circuits before any runtime path
59
- # touches them, so the emitted manifest is correct in the meantime.
60
- COPY assistant ./assistant
61
-
62
- # Emit the meet-join manifest consumed by the daemon-side loader to
63
- # register proxy tools/routes without importing the skill in-process.
64
- RUN bun run /app/skills/meet-join/scripts/emit-manifest.ts \
65
- --output /app/skills/meet-join/manifest.json
66
54
 
67
55
  # Final stage
68
56
  FROM debian:trixie-slim@sha256:4ffb3a1511099754cddc70eb1b12e50ffdb67619aa0ab6c13fcd800a78ef7c7a AS runner
@@ -133,6 +121,11 @@ RUN apt-get update && apt-get install -y \
133
121
  COPY --from=builder /root/.bun/bin/bun /usr/local/bin/bun
134
122
  RUN ln -sf /usr/local/bin/bun /usr/local/bin/bunx
135
123
 
124
+ # Copy installed deps, shared packages, and bundled skills from the builder stage.
125
+ COPY --from=builder /app /app
126
+
127
+ COPY assistant /app/assistant
128
+
136
129
  # Install assistant CLI launcher backed by the bundled assistant package
137
130
  RUN printf '#!/usr/bin/env sh\nexec bun run /app/assistant/src/index.ts "$@"\n' > /usr/local/bin/assistant && \
138
131
  chmod +x /usr/local/bin/assistant
@@ -238,10 +231,6 @@ EXPOSE 3001
238
231
  ENV RUNTIME_HTTP_PORT=3001
239
232
  ENV IS_CONTAINERIZED=true
240
233
 
241
- # Copy installed deps, shared packages, bundled skills, assistant source,
242
- # and the generated meet-join manifest from the builder stage.
243
- COPY --from=builder /app /app
244
-
245
234
  COPY packages/block-volume-bootstrap/scripts/*.sh /usr/local/bin/
246
235
 
247
236
  RUN chmod +x \
package/README.md CHANGED
@@ -174,7 +174,7 @@ Guardian actor-role _classification_ (determining whether a sender is guardian,
174
174
 
175
175
  ### Ingress Boundary Guarantees (Gateway-Only Mode)
176
176
 
177
- The runtime operates in **gateway-only mode**: all public-facing webhook paths are blocked at the runtime level. Direct access to Twilio webhook routes (`/webhooks/twilio/voice`, `/webhooks/twilio/status`, `/webhooks/twilio/connect-action`) and their legacy equivalents (`/v1/calls/twilio/*`) returns `410 GATEWAY_ONLY`. This ensures external webhook traffic can only reach the runtime through the gateway, which performs signature validation before forwarding.
177
+ The runtime operates in **gateway-only mode**: all public-facing webhook paths are blocked at the runtime level. Direct access to Twilio webhook routes (`/webhooks/twilio/voice`, `/webhooks/twilio/status`) and their legacy equivalents (`/v1/calls/twilio/*`) returns `410 GATEWAY_ONLY`. This ensures external webhook traffic can only reach the runtime through the gateway, which performs signature validation before forwarding.
178
178
 
179
179
  Internal forwarding routes (`/v1/internal/twilio/*`) are unaffected — these accept pre-validated payloads from the gateway over the private network.
180
180
 
@@ -309,7 +309,6 @@ Guardian verification and ingress contact management are complementary but indep
309
309
  | `src/runtime/trust-context-resolver.ts` | Actor role classification: guardian / non-guardian / unverified_channel |
310
310
  | `src/runtime/routes/inbound-message-handler.ts` | Ingress ACL enforcement, verification-code intercept, escalation creation |
311
311
  | `src/contacts/contact-store.ts` | Contact + channel CRUD: `findContactChannel`, `upsertContact`, `updateChannelStatus`, `searchContacts` |
312
- | `src/memory/invite-store.ts` | Invite lifecycle: `createInvite`, `redeemInvite` (atomically creates member record) |
313
312
  | `src/memory/channel-verification-sessions.ts` | Guardian binding types and verification challenge persistence |
314
313
  | `src/memory/guardian-approvals.ts` | Approval request persistence |
315
314
  | `src/runtime/verification-outbound-actions.ts` | Shared business logic for outbound verification (start/resend/cancel) |
@@ -383,7 +382,7 @@ External users join through **invite tokens**. There are two invite flows:
383
382
  1. **Guardian requests invite** — The guardian asks the assistant (via desktop chat) to create a Telegram invite link. The `guardian-invite-intent.ts` module detects the intent and routes the request into the `contacts` skill.
384
383
  2. **Invite creation** — The skill creates an invite token via the ingress HTTP API, looks up the Telegram bot username from the integration config endpoint, and constructs a shareable deep link: `https://t.me/<bot>?start=iv_<token>`.
385
384
  3. **Guardian shares link** — The guardian copies the deep link and shares it with the invitee through any messaging channel.
386
- 4. **Invitee redeems** — The invitee clicks the link, which opens Telegram and sends `/start iv_<token>` to the bot. The inbound message handler extracts the token via the transport adapter, redeems it through the invite redemption service, and auto-creates an active member record.
385
+ 4. **Invitee redeems** — The invitee clicks the link, which opens Telegram and sends `/start iv_<token>` to the bot. The gateway intercepts the token at ingress, redeems it against its canonical invite row, activates the member channel in the gateway ACL, and notifies the daemon to mirror the contact info.
387
386
  5. **Access granted** — The invitee receives a welcome message and all subsequent messages pass the ingress ACL.
388
387
 
389
388
  The `iv_` prefix distinguishes invite tokens from `gv_` (guardian verification) tokens, which use the same Telegram `/start` deep-link mechanism.
@@ -392,7 +391,7 @@ The `iv_` prefix distinguishes invite tokens from `gv_` (guardian verification)
392
391
 
393
392
  The invite redemption system uses a three-layer architecture:
394
393
 
395
- - **Core redemption engine** (`invite-redemption-service.ts`) — Channel-agnostic business logic that validates tokens, enforces expiry/use-count/channel-match constraints, handles member reactivation, and returns a discriminated-union `InviteRedemptionOutcome`. Deterministic reply templates (`invite-redemption-templates.ts`) map each outcome to a user-facing message without passing through the LLM.
394
+ - **Core redemption engine** (gateway-native, `gateway/src/verification/invite-redemption.ts`) — Channel-agnostic business logic that validates tokens and codes, enforces expiry/use-count/channel-match constraints, handles member reactivation, and returns a discriminated-union `InviteRedemptionOutcome`. Deterministic reply templates map each outcome to a user-facing message without passing through the LLM.
396
395
  - **Channel transport adapters** (`channel-invite-transport.ts` + `channel-invite-transports/`) — A registry of per-channel adapters that know how to build shareable links (`buildShareLink`) and extract inbound tokens (`extractInboundToken`). Adapters are implemented for Telegram, Voice, Email, WhatsApp, and Slack.
397
396
  - **Conversational orchestration** (`guardian-invite-intent.ts`) — Pattern-based intent detection that intercepts guardian invite management requests (create, list, revoke) in the session pipeline and forces immediate entry into the `contacts` skill, bypassing the normal agent loop.
398
397
 
@@ -422,16 +421,14 @@ If no guardian binding exists, escalation fails closed — the message is denied
422
421
 
423
422
  | File | Purpose |
424
423
  | --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
425
- | `src/memory/invite-store.ts` | CRUD for invite tokens with SHA-256 hashing and expiry |
426
424
  | `src/contacts/contact-store.ts` | Contact + channel CRUD with policy enforcement |
427
- | `src/daemon/handlers/config-inbox.ts` | HTTP handlers for invite operations |
428
- | `src/runtime/routes/channel-routes.ts` | ACL enforcement point — member lookup, policy check, escalation creation |
429
- | `src/runtime/invite-redemption-service.ts` | Core redemption engine — token validation, member creation, discriminated-union outcomes |
430
- | `src/runtime/invite-redemption-templates.ts` | Deterministic reply templates for each redemption outcome |
425
+ | `src/runtime/routes/contact-routes.ts` | HTTP/IPC invite handlers relay mint/list/revoke/redeem to the gateway's invite IPC routes |
426
+ | `src/runtime/routes/inbound-message-handler.ts` | ACL enforcement point — member lookup, policy check, escalation creation |
427
+ | `gateway/src/verification/invite-redemption.ts` (gateway) | Core redemption engine — token/code validation, atomic claim, ACL activation, discriminated-union outcomes |
431
428
  | `src/runtime/channel-invite-transport.ts` | Transport adapter registry — `buildShareableInvite` / `extractInboundToken` per channel |
432
429
  | `src/runtime/channel-invite-transports/telegram.ts` | Telegram adapter — builds `t.me/<bot>?start=iv_<token>` deep links, extracts `iv_` tokens from `/start` commands |
433
430
  | `src/daemon/guardian-invite-intent.ts` | Intent detection — routes guardian invite management requests into the `contacts` skill |
434
- | `src/runtime/invite-service.ts` | Shared business logic for invite and contact operations |
431
+ | `src/runtime/invite-service.ts` | Daemon-owned invite presentation (share link, guardian instruction) over gateway-minted invites |
435
432
 
436
433
  ## Database
437
434
 
package/bun.lock CHANGED
@@ -21,7 +21,6 @@
21
21
  "@vellumai/gateway-client": "file:../packages/gateway-client",
22
22
  "@vellumai/ipc-server-utils": "file:../packages/ipc-server-utils",
23
23
  "@vellumai/service-contracts": "file:../packages/service-contracts",
24
- "@vellumai/skill-host-contracts": "file:../packages/skill-host-contracts",
25
24
  "@vellumai/slack-text": "file:../packages/slack-text",
26
25
  "@vellumai/twilio-client": "file:../packages/twilio-client",
27
26
  "commander": "13.1.0",
@@ -38,7 +37,6 @@
38
37
  "pino": "9.14.0",
39
38
  "pino-pretty": "13.1.3",
40
39
  "playwright": "1.58.2",
41
- "postgres": "3.4.8",
42
40
  "quickjs-emscripten": "0.32.0",
43
41
  "re2js": "2.8.3",
44
42
  "remark-gfm": "4.0.1",
@@ -505,8 +503,6 @@
505
503
 
506
504
  "@vellumai/service-contracts": ["@vellumai/service-contracts@file:../packages/service-contracts", { "dependencies": { "zod": "4.3.6" }, "devDependencies": { "@types/bun": "1.2.4", "typescript": "5.7.3" } }],
507
505
 
508
- "@vellumai/skill-host-contracts": ["@vellumai/skill-host-contracts@file:../packages/skill-host-contracts", { "devDependencies": { "@types/bun": "1.3.10", "typescript": "5.9.3" } }],
509
-
510
506
  "@vellumai/slack-text": ["@vellumai/slack-text@file:../packages/slack-text", { "devDependencies": { "@types/bun": "1.3.10", "typescript": "5.9.3" } }],
511
507
 
512
508
  "@vellumai/twilio-client": ["@vellumai/twilio-client@file:../packages/twilio-client", { "devDependencies": { "@types/bun": "1.3.10", "typescript": "5.9.3" } }],