@vellumai/assistant 0.5.10 → 0.5.12

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 (395) hide show
  1. package/AGENTS.md +8 -0
  2. package/ARCHITECTURE.md +43 -43
  3. package/Dockerfile +3 -0
  4. package/docs/architecture/integrations.md +37 -42
  5. package/docs/architecture/memory.md +7 -12
  6. package/docs/credential-execution-service.md +9 -9
  7. package/docs/skills.md +1 -1
  8. package/node_modules/@vellumai/ces-contracts/src/__tests__/grants.test.ts +7 -7
  9. package/node_modules/@vellumai/ces-contracts/src/handles.ts +5 -4
  10. package/node_modules/@vellumai/credential-storage/src/index.ts +3 -3
  11. package/node_modules/@vellumai/credential-storage/src/static-credentials.ts +1 -1
  12. package/openapi.yaml +7208 -0
  13. package/package.json +2 -1
  14. package/scripts/generate-openapi.ts +562 -0
  15. package/src/__tests__/acp-session.test.ts +239 -44
  16. package/src/__tests__/assistant-feature-flag-guard.test.ts +8 -8
  17. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +5 -86
  18. package/src/__tests__/assistant-feature-flags-integration.test.ts +7 -14
  19. package/src/__tests__/browser-skill-endstate.test.ts +1 -1
  20. package/src/__tests__/btw-routes.test.ts +8 -0
  21. package/src/__tests__/bundled-skill-retrieval-guard.test.ts +10 -10
  22. package/src/__tests__/catalog-cache.test.ts +164 -0
  23. package/src/__tests__/catalog-search.test.ts +61 -0
  24. package/src/__tests__/channel-approvals.test.ts +7 -7
  25. package/src/__tests__/channel-readiness-service.test.ts +41 -0
  26. package/src/__tests__/cli-command-risk-guard.test.ts +181 -6
  27. package/src/__tests__/config-schema.test.ts +10 -2
  28. package/src/__tests__/context-memory-e2e.test.ts +2 -6
  29. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +396 -0
  30. package/src/__tests__/conversation-error.test.ts +3 -2
  31. package/src/__tests__/conversation-skill-tools.test.ts +1 -3
  32. package/src/__tests__/conversation-title-service.test.ts +2 -15
  33. package/src/__tests__/credential-execution-feature-gates.test.ts +4 -8
  34. package/src/__tests__/credential-execution-managed-contract.test.ts +8 -8
  35. package/src/__tests__/credential-security-e2e.test.ts +4 -4
  36. package/src/__tests__/credential-security-invariants.test.ts +12 -18
  37. package/src/__tests__/credential-vault-unit.test.ts +32 -34
  38. package/src/__tests__/credential-vault.test.ts +25 -33
  39. package/src/__tests__/credentials-cli.test.ts +3 -3
  40. package/src/__tests__/daemon-credential-client.test.ts +2 -2
  41. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -1
  42. package/src/__tests__/gateway-only-guard.test.ts +3 -0
  43. package/src/__tests__/heartbeat-service.test.ts +35 -0
  44. package/src/__tests__/host-bash-proxy.test.ts +79 -0
  45. package/src/__tests__/host-cu-proxy.test.ts +90 -0
  46. package/src/__tests__/host-file-proxy.test.ts +89 -0
  47. package/src/__tests__/host-shell-tool.test.ts +1 -1
  48. package/src/__tests__/inline-skill-load-permissions.test.ts +3 -3
  49. package/src/__tests__/integration-status.test.ts +5 -5
  50. package/src/__tests__/list-messages-attachments.test.ts +171 -0
  51. package/src/__tests__/llm-request-log-turn-query.test.ts +64 -0
  52. package/src/__tests__/log-export-workspace.test.ts +1 -1
  53. package/src/__tests__/mcp-abort-signal.test.ts +205 -0
  54. package/src/__tests__/mcp-client-auth.test.ts +1 -1
  55. package/src/__tests__/memory-lifecycle-e2e.test.ts +2 -2
  56. package/src/__tests__/memory-recall-log-store.test.ts +182 -0
  57. package/src/__tests__/memory-recall-quality.test.ts +6 -8
  58. package/src/__tests__/memory-regressions.test.ts +53 -42
  59. package/src/__tests__/memory-retrieval.benchmark.test.ts +5 -9
  60. package/src/__tests__/messaging-send-tool.test.ts +5 -5
  61. package/src/__tests__/messaging-skill-split.test.ts +2 -17
  62. package/src/__tests__/notification-telegram-adapter.test.ts +125 -0
  63. package/src/__tests__/oauth-cli.test.ts +203 -649
  64. package/src/__tests__/oauth-provider-profiles.test.ts +55 -20
  65. package/src/__tests__/oauth-scope-policy.test.ts +4 -6
  66. package/src/__tests__/onboarding-template-contract.test.ts +2 -2
  67. package/src/__tests__/platform-callback-registration.test.ts +119 -0
  68. package/src/__tests__/secret-ingress-channel.test.ts +261 -0
  69. package/src/__tests__/secret-ingress-cli.test.ts +201 -0
  70. package/src/__tests__/secret-ingress-http.test.ts +312 -0
  71. package/src/__tests__/secret-ingress.test.ts +283 -0
  72. package/src/__tests__/secret-onetime-send.test.ts +4 -4
  73. package/src/__tests__/secret-routes-managed-proxy.test.ts +78 -0
  74. package/src/__tests__/secure-keys-managed-failover.test.ts +73 -0
  75. package/src/__tests__/skill-feature-flags-integration.test.ts +4 -4
  76. package/src/__tests__/skill-feature-flags.test.ts +11 -19
  77. package/src/__tests__/skill-load-feature-flag.test.ts +1 -1
  78. package/src/__tests__/skill-load-inline-command.test.ts +3 -3
  79. package/src/__tests__/skill-load-inline-includes.test.ts +2 -2
  80. package/src/__tests__/skill-memory.test.ts +2 -4
  81. package/src/__tests__/skill-projection-feature-flag.test.ts +2 -4
  82. package/src/__tests__/skill-projection.benchmark.test.ts +1 -3
  83. package/src/__tests__/skills-uninstall.test.ts +2 -2
  84. package/src/__tests__/skills.test.ts +16 -2
  85. package/src/__tests__/slack-channel-config.test.ts +1 -1
  86. package/src/__tests__/slack-messaging-token-resolution.test.ts +22 -24
  87. package/src/__tests__/slack-share-routes.test.ts +5 -5
  88. package/src/__tests__/slack-skill.test.ts +5 -69
  89. package/src/__tests__/system-prompt.test.ts +39 -0
  90. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -1
  91. package/src/__tests__/workspace-migration-018-rekey-compound-credential-keys.test.ts +181 -0
  92. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +5 -4
  93. package/src/acp/client-handler.ts +113 -31
  94. package/src/acp/session-manager.ts +29 -27
  95. package/src/approvals/guardian-request-resolvers.ts +1 -1
  96. package/src/cli/AGENTS.md +113 -0
  97. package/src/cli/commands/autonomy.ts +3 -5
  98. package/src/cli/commands/browser-relay.ts +2 -17
  99. package/src/cli/commands/contacts.ts +6 -4
  100. package/src/cli/commands/conversations.ts +13 -1
  101. package/src/cli/commands/credential-execution.ts +17 -3
  102. package/src/cli/commands/credentials.ts +2 -8
  103. package/src/cli/commands/memory.ts +2 -3
  104. package/src/cli/commands/oauth/__tests__/connect.test.ts +706 -0
  105. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +686 -0
  106. package/src/cli/commands/oauth/__tests__/mode.test.ts +625 -0
  107. package/src/cli/commands/oauth/__tests__/ping.test.ts +631 -0
  108. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +574 -0
  109. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +416 -0
  110. package/src/cli/commands/oauth/__tests__/status.test.ts +551 -0
  111. package/src/cli/commands/oauth/__tests__/token.test.ts +420 -0
  112. package/src/cli/commands/oauth/apps.ts +87 -50
  113. package/src/cli/commands/oauth/connect.ts +405 -0
  114. package/src/cli/commands/oauth/disconnect.ts +285 -0
  115. package/src/cli/commands/oauth/index.ts +62 -20
  116. package/src/cli/commands/oauth/mode.ts +251 -0
  117. package/src/cli/commands/oauth/ping.ts +196 -0
  118. package/src/cli/commands/oauth/providers.ts +589 -55
  119. package/src/cli/commands/oauth/request.ts +564 -0
  120. package/src/cli/commands/oauth/shared.ts +114 -0
  121. package/src/cli/commands/oauth/status.ts +191 -0
  122. package/src/cli/commands/oauth/token.ts +150 -0
  123. package/src/cli/commands/platform/connect.ts +104 -0
  124. package/src/cli/commands/platform/disconnect.ts +118 -0
  125. package/src/cli/commands/platform/index.ts +252 -0
  126. package/src/cli/commands/sequence.ts +5 -4
  127. package/src/cli/commands/shotgun.ts +16 -0
  128. package/src/cli/commands/skills.ts +173 -41
  129. package/src/cli/commands/usage.ts +5 -11
  130. package/src/cli/lib/daemon-credential-client.ts +22 -38
  131. package/src/cli/program.ts +1 -1
  132. package/src/cli.ts +82 -17
  133. package/src/config/assistant-feature-flags.ts +77 -18
  134. package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +1 -1
  135. package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -1
  136. package/src/config/bundled-skills/contacts/tools/google-contacts.ts +1 -1
  137. package/src/config/bundled-skills/conversations/SKILL.md +20 -0
  138. package/src/config/bundled-skills/conversations/TOOLS.json +23 -0
  139. package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +66 -0
  140. package/src/config/bundled-skills/gmail/SKILL.md +13 -13
  141. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +3 -3
  142. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +2 -2
  143. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +1 -1
  144. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +1 -1
  145. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +1 -1
  146. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +1 -1
  147. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +2 -2
  148. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +1 -1
  149. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +1 -1
  150. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +1 -1
  151. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +1 -1
  152. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +1 -1
  153. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +1 -1
  154. package/src/config/bundled-skills/google-calendar/SKILL.md +10 -4
  155. package/src/config/bundled-skills/google-calendar/tools/shared.ts +1 -1
  156. package/src/config/bundled-skills/messaging/SKILL.md +19 -42
  157. package/src/config/bundled-skills/messaging/TOOLS.json +9 -9
  158. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +1 -1
  159. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +5 -2
  160. package/src/config/bundled-skills/messaging/tools/shared.ts +5 -6
  161. package/src/config/bundled-skills/notifications/SKILL.md +1 -1
  162. package/src/config/bundled-skills/schedule/SKILL.md +2 -2
  163. package/src/config/bundled-skills/settings/SKILL.md +5 -3
  164. package/src/config/bundled-skills/settings/TOOLS.json +17 -0
  165. package/src/config/bundled-skills/settings/tools/avatar-get.ts +50 -0
  166. package/src/config/bundled-skills/settings/tools/avatar-remove.ts +7 -0
  167. package/src/config/bundled-skills/settings/tools/avatar-update.ts +6 -1
  168. package/src/config/bundled-skills/settings/tools/identity-avatar.ts +55 -0
  169. package/src/config/bundled-skills/skills-catalog/SKILL.md +3 -3
  170. package/src/config/bundled-skills/slack/SKILL.md +58 -44
  171. package/src/config/bundled-tool-registry.ts +7 -19
  172. package/src/config/env.ts +5 -1
  173. package/src/config/feature-flag-registry.json +58 -42
  174. package/src/config/loader.ts +4 -0
  175. package/src/config/schemas/platform.ts +0 -8
  176. package/src/config/schemas/security.ts +9 -1
  177. package/src/config/schemas/services.ts +1 -1
  178. package/src/config/skill-state.ts +1 -3
  179. package/src/config/skills.ts +2 -4
  180. package/src/credential-execution/client.ts +1 -1
  181. package/src/credential-execution/feature-gates.ts +9 -16
  182. package/src/credential-execution/process-manager.ts +12 -0
  183. package/src/daemon/config-watcher.ts +4 -0
  184. package/src/daemon/conversation-agent-loop-handlers.ts +10 -0
  185. package/src/daemon/conversation-agent-loop.ts +51 -2
  186. package/src/daemon/conversation-error.ts +36 -6
  187. package/src/daemon/conversation-memory.ts +0 -1
  188. package/src/daemon/conversation-messaging.ts +9 -0
  189. package/src/daemon/conversation-runtime-assembly.ts +33 -0
  190. package/src/daemon/conversation-surfaces.ts +120 -14
  191. package/src/daemon/conversation.ts +5 -0
  192. package/src/daemon/handlers/config-slack-channel.ts +43 -1
  193. package/src/daemon/handlers/conversations.ts +41 -33
  194. package/src/daemon/handlers/skills.ts +148 -3
  195. package/src/daemon/host-bash-proxy.ts +16 -0
  196. package/src/daemon/host-cu-proxy.ts +16 -0
  197. package/src/daemon/host-file-proxy.ts +16 -0
  198. package/src/daemon/lifecycle.ts +73 -3
  199. package/src/daemon/message-types/acp.ts +0 -15
  200. package/src/daemon/message-types/conversations.ts +1 -0
  201. package/src/daemon/message-types/guardian-actions.ts +2 -0
  202. package/src/daemon/message-types/host-bash.ts +6 -1
  203. package/src/daemon/message-types/host-cu.ts +6 -1
  204. package/src/daemon/message-types/host-file.ts +6 -1
  205. package/src/daemon/message-types/integrations.ts +0 -1
  206. package/src/daemon/message-types/memory.ts +0 -1
  207. package/src/daemon/message-types/messages.ts +9 -1
  208. package/src/daemon/message-types/schedules.ts +9 -0
  209. package/src/daemon/server.ts +48 -9
  210. package/src/email/feature-gate.ts +3 -3
  211. package/src/heartbeat/heartbeat-service.ts +48 -0
  212. package/src/hooks/cli.ts +74 -0
  213. package/src/inbound/platform-callback-registration.ts +68 -19
  214. package/src/mcp/client.ts +6 -1
  215. package/src/mcp/manager.ts +2 -1
  216. package/src/mcp/mcp-oauth-provider.ts +3 -3
  217. package/src/memory/app-store.ts +3 -3
  218. package/src/memory/conversation-crud.ts +213 -0
  219. package/src/memory/conversation-key-store.ts +26 -0
  220. package/src/memory/conversation-title-service.ts +7 -17
  221. package/src/memory/db-init.ts +24 -0
  222. package/src/memory/embedding-local.ts +47 -2
  223. package/src/memory/indexer.ts +13 -10
  224. package/src/memory/items-extractor.ts +12 -4
  225. package/src/memory/job-utils.ts +5 -0
  226. package/src/memory/jobs-store.ts +10 -2
  227. package/src/memory/journal-memory.ts +6 -2
  228. package/src/memory/llm-request-log-store.ts +88 -21
  229. package/src/memory/memory-recall-log-store.ts +128 -0
  230. package/src/memory/migrations/194-memory-recall-logs.ts +50 -0
  231. package/src/memory/migrations/195-oauth-providers-ping-config.ts +23 -0
  232. package/src/memory/migrations/196-messages-conversation-created-at-index.ts +9 -0
  233. package/src/memory/migrations/196-strip-integration-prefix-from-provider-keys.ts +186 -0
  234. package/src/memory/migrations/197-oauth-providers-behavior-columns.ts +29 -0
  235. package/src/memory/migrations/198-drop-setup-skill-id-column.ts +11 -0
  236. package/src/memory/migrations/index.ts +6 -0
  237. package/src/memory/migrations/registry.ts +8 -0
  238. package/src/memory/retriever.test.ts +4 -5
  239. package/src/memory/schema/infrastructure.ts +31 -0
  240. package/src/memory/schema/oauth.ts +14 -0
  241. package/src/messaging/provider.ts +13 -12
  242. package/src/messaging/providers/gmail/adapter.ts +44 -35
  243. package/src/messaging/providers/slack/adapter.ts +63 -33
  244. package/src/messaging/providers/telegram-bot/adapter.ts +7 -9
  245. package/src/messaging/providers/whatsapp/adapter.ts +6 -8
  246. package/src/notifications/adapters/telegram.ts +78 -2
  247. package/src/oauth/__tests__/identity-verifier.test.ts +464 -0
  248. package/src/oauth/byo-connection.test.ts +22 -24
  249. package/src/oauth/connect-orchestrator.ts +79 -64
  250. package/src/oauth/connect-types.ts +7 -65
  251. package/src/oauth/connection-resolver.test.ts +13 -13
  252. package/src/oauth/connection-resolver.ts +3 -4
  253. package/src/oauth/identity-verifier.ts +177 -0
  254. package/src/oauth/manual-token-connection.ts +5 -5
  255. package/src/oauth/oauth-store.ts +251 -5
  256. package/src/oauth/platform-connection.test.ts +56 -6
  257. package/src/oauth/platform-connection.ts +8 -1
  258. package/src/oauth/seed-providers.ts +256 -34
  259. package/src/permissions/checker.ts +129 -3
  260. package/src/permissions/trust-client.ts +2 -2
  261. package/src/platform/client.ts +2 -2
  262. package/src/prompts/journal-context.ts +6 -1
  263. package/src/prompts/system-prompt.ts +43 -9
  264. package/src/prompts/templates/BOOTSTRAP.md +16 -5
  265. package/src/providers/anthropic/client.ts +139 -28
  266. package/src/runtime/auth/__tests__/middleware.test.ts +19 -0
  267. package/src/runtime/auth/route-policy.ts +0 -1
  268. package/src/runtime/btw-sidechain.ts +7 -1
  269. package/src/runtime/channel-approvals.ts +2 -2
  270. package/src/runtime/channel-readiness-service.ts +30 -7
  271. package/src/runtime/guardian-action-service.ts +7 -2
  272. package/src/runtime/http-router.ts +31 -0
  273. package/src/runtime/http-server.ts +26 -7
  274. package/src/runtime/http-types.ts +9 -0
  275. package/src/runtime/pending-interactions.ts +21 -3
  276. package/src/runtime/routes/acp-routes.ts +46 -28
  277. package/src/runtime/routes/app-management-routes.ts +123 -0
  278. package/src/runtime/routes/app-routes.ts +31 -0
  279. package/src/runtime/routes/approval-routes.ts +108 -3
  280. package/src/runtime/routes/attachment-routes.ts +45 -0
  281. package/src/runtime/routes/avatar-routes.ts +16 -0
  282. package/src/runtime/routes/brain-graph-routes.ts +18 -0
  283. package/src/runtime/routes/btw-routes.ts +20 -0
  284. package/src/runtime/routes/call-routes.ts +81 -0
  285. package/src/runtime/routes/channel-readiness-routes.ts +48 -7
  286. package/src/runtime/routes/channel-routes.ts +18 -0
  287. package/src/runtime/routes/channel-verification-routes.ts +49 -1
  288. package/src/runtime/routes/contact-routes.ts +77 -0
  289. package/src/runtime/routes/conversation-attention-routes.ts +37 -0
  290. package/src/runtime/routes/conversation-management-routes.ts +125 -0
  291. package/src/runtime/routes/conversation-query-routes.ts +78 -0
  292. package/src/runtime/routes/conversation-routes.ts +191 -39
  293. package/src/runtime/routes/conversation-starter-routes.ts +29 -0
  294. package/src/runtime/routes/debug-routes.ts +23 -0
  295. package/src/runtime/routes/diagnostics-routes.ts +30 -0
  296. package/src/runtime/routes/documents-routes.ts +42 -0
  297. package/src/runtime/routes/events-routes.ts +10 -0
  298. package/src/runtime/routes/global-search-routes.ts +35 -0
  299. package/src/runtime/routes/guardian-action-routes.ts +61 -3
  300. package/src/runtime/routes/guardian-approval-prompt.ts +77 -2
  301. package/src/runtime/routes/heartbeat-routes.ts +278 -0
  302. package/src/runtime/routes/host-bash-routes.ts +16 -1
  303. package/src/runtime/routes/host-cu-routes.ts +23 -1
  304. package/src/runtime/routes/host-file-routes.ts +18 -1
  305. package/src/runtime/routes/identity-routes.ts +35 -0
  306. package/src/runtime/routes/inbound-message-handler.ts +46 -25
  307. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -8
  308. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +30 -2
  309. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +1 -2
  310. package/src/runtime/routes/integrations/slack/share.ts +1 -1
  311. package/src/runtime/routes/integrations/twilio.ts +32 -22
  312. package/src/runtime/routes/invite-routes.ts +83 -0
  313. package/src/runtime/routes/log-export-routes.ts +14 -0
  314. package/src/runtime/routes/memory-item-routes.ts +99 -1
  315. package/src/runtime/routes/migration-rollback-routes.ts +25 -0
  316. package/src/runtime/routes/migration-routes.ts +40 -0
  317. package/src/runtime/routes/notification-routes.ts +20 -0
  318. package/src/runtime/routes/oauth-apps.ts +13 -4
  319. package/src/runtime/routes/pairing-routes.ts +15 -0
  320. package/src/runtime/routes/recording-routes.ts +72 -0
  321. package/src/runtime/routes/schedule-routes.ts +77 -5
  322. package/src/runtime/routes/secret-routes.ts +99 -14
  323. package/src/runtime/routes/settings-routes.ts +102 -19
  324. package/src/runtime/routes/skills-routes.ts +141 -18
  325. package/src/runtime/routes/subagents-routes.ts +38 -3
  326. package/src/runtime/routes/surface-action-routes.ts +66 -24
  327. package/src/runtime/routes/surface-content-routes.ts +20 -0
  328. package/src/runtime/routes/telemetry-routes.ts +12 -0
  329. package/src/runtime/routes/trace-event-routes.ts +25 -0
  330. package/src/runtime/routes/trust-rules-routes.ts +46 -0
  331. package/src/runtime/routes/tts-routes.ts +15 -4
  332. package/src/runtime/routes/upgrade-broadcast-routes.ts +38 -0
  333. package/src/runtime/routes/usage-routes.ts +59 -0
  334. package/src/runtime/routes/watch-routes.ts +28 -0
  335. package/src/runtime/routes/work-items-routes.ts +59 -0
  336. package/src/runtime/routes/workspace-commit-routes.ts +12 -0
  337. package/src/runtime/routes/workspace-routes.ts +102 -0
  338. package/src/schedule/integration-status.ts +2 -2
  339. package/src/schedule/scheduler.ts +7 -1
  340. package/src/security/AGENTS.md +7 -0
  341. package/src/security/ces-rpc-credential-backend.ts +19 -16
  342. package/src/security/credential-backend.ts +1 -1
  343. package/src/security/encrypted-store.ts +3 -3
  344. package/src/security/oauth-completion-page.ts +153 -0
  345. package/src/security/oauth2.ts +58 -17
  346. package/src/security/secret-ingress.ts +174 -0
  347. package/src/security/secret-patterns.ts +133 -0
  348. package/src/security/secret-scanner.ts +28 -117
  349. package/src/security/secure-keys.ts +207 -7
  350. package/src/security/token-manager.ts +3 -6
  351. package/src/signals/bash.ts +6 -1
  352. package/src/signals/confirm.ts +12 -8
  353. package/src/signals/user-message.ts +18 -3
  354. package/src/skills/catalog-cache.ts +44 -0
  355. package/src/skills/catalog-search.ts +18 -0
  356. package/src/skills/skill-memory.ts +1 -2
  357. package/src/tasks/task-runner.ts +7 -1
  358. package/src/tools/credentials/broker.ts +1 -1
  359. package/src/tools/credentials/metadata-store.ts +1 -1
  360. package/src/tools/credentials/post-connect-hooks.ts +1 -1
  361. package/src/tools/credentials/vault.ts +36 -48
  362. package/src/tools/host-terminal/host-shell.ts +16 -3
  363. package/src/tools/mcp/mcp-tool-factory.ts +2 -1
  364. package/src/tools/memory/definitions.ts +1 -1
  365. package/src/tools/memory/handlers.test.ts +2 -4
  366. package/src/tools/skills/load.ts +1 -1
  367. package/src/tools/skills/sandbox-runner.ts +16 -3
  368. package/src/tools/terminal/safe-env.ts +7 -0
  369. package/src/tools/terminal/shell.ts +16 -3
  370. package/src/tools/tool-manifest.ts +1 -1
  371. package/src/util/log-redact.ts +9 -34
  372. package/src/util/logger.ts +11 -1
  373. package/src/util/sentry-log-stream.ts +51 -0
  374. package/src/watcher/providers/github.ts +2 -2
  375. package/src/watcher/providers/gmail.ts +1 -1
  376. package/src/watcher/providers/google-calendar.ts +1 -1
  377. package/src/watcher/providers/linear.ts +2 -2
  378. package/src/workspace/migrations/011-backfill-installation-id.ts +5 -3
  379. package/src/workspace/migrations/020-rename-oauth-skill-dirs.ts +119 -0
  380. package/src/workspace/migrations/registry.ts +2 -0
  381. package/docs/architecture/keychain-broker.md +0 -68
  382. package/src/cli/commands/oauth/connections.ts +0 -734
  383. package/src/cli/commands/oauth/platform.ts +0 -525
  384. package/src/cli/commands/platform.ts +0 -176
  385. package/src/config/bundled-skills/slack/TOOLS.json +0 -272
  386. package/src/config/bundled-skills/slack/tools/shared.ts +0 -34
  387. package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +0 -27
  388. package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +0 -38
  389. package/src/config/bundled-skills/slack/tools/slack-channel-permissions.ts +0 -146
  390. package/src/config/bundled-skills/slack/tools/slack-configure-channels.ts +0 -105
  391. package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +0 -26
  392. package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +0 -27
  393. package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +0 -25
  394. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +0 -372
  395. package/src/oauth/provider-behaviors.ts +0 -634
package/AGENTS.md CHANGED
@@ -3,3 +3,11 @@
3
3
  For error handling conventions (throw vs result objects vs null), see [docs/error-handling.md](docs/error-handling.md).
4
4
 
5
5
  Subdirectory-scoped rules live in local AGENTS.md files: `src/cli/`, `src/runtime/`, `src/approvals/`, `src/notifications/`, `src/workspace/migrations/`.
6
+
7
+ ## Adding new environment variables
8
+
9
+ When you introduce a new env var that the assistant process needs to read at runtime, **update `src/tools/terminal/safe-env.ts`** as well.
10
+
11
+ `safe-env.ts` maintains the allowlist of env vars that are forwarded to agent-spawned child processes (bash tool, skill sandbox, etc.). Anything not on the list is stripped to prevent credential leakage. If your new var is needed by commands the agent runs, it must be added.
12
+
13
+ **Default to including it.** If the var doesn't contain secrets (e.g. a URL, a feature flag, a path, a mode string), add it. Only omit it if it carries credential material (tokens, passwords, private keys) — those must stay isolated to CES.
package/ARCHITECTURE.md CHANGED
@@ -617,7 +617,7 @@ Release-driven update notification system that surfaces release notes to the ass
617
617
 
618
618
  The assistant feature-flag resolver (`src/config/assistant-feature-flags.ts`) is the canonical module for determining whether an assistant feature flag is enabled. It loads default values from the unified registry at `meta/feature-flags/feature-flag-registry.json` (bundled copy at `src/config/feature-flag-registry.json`) and resolves the effective state for each declared assistant-scope flag. Assistant feature flags are declaration-driven assistant-scoped booleans that can gate any assistant behavior; skill availability is one consumer.
619
619
 
620
- **Canonical key format:** `feature_flags.<flag_id>.enabled` (e.g., `feature_flags.contacts.enabled`).
620
+ **Canonical key format:** Simple kebab-case (e.g., `contacts`, `ces-tools`).
621
621
 
622
622
  **Resolution priority** (highest wins):
623
623
 
@@ -645,7 +645,7 @@ The assistant feature-flag resolver (`src/config/assistant-feature-flags.ts`) is
645
645
 
646
646
  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.
647
647
 
648
- **Migration path:** The legacy `skills.<id>.enabled` key format is no longer supported. All code must use the canonical `feature_flags.<id>.enabled` format. Guard tests enforce canonical key usage and declaration coverage for literal key references in the unified registry.
648
+ **Migration path:** The legacy `skills.<id>.enabled` and `feature_flags.<id>.enabled` key formats are no longer supported. All code must use simple kebab-case keys (e.g., `contacts`, `ces-tools`). Guard tests enforce canonical key usage and declaration coverage for literal key references in the unified registry.
649
649
 
650
650
  **Key source files:**
651
651
 
@@ -1142,7 +1142,7 @@ Skills can expose custom tools via a `TOOLS.json` manifest alongside their `SKIL
1142
1142
 
1143
1143
  ### Bundled Skill Retrieval Contract (CLI-First)
1144
1144
 
1145
- Config/status retrieval instructions in bundled `SKILL.md` files are CLI-first. Retrieval should flow through canonical `vellum` CLI surfaces (`assistant config get` for generic settings, secure credential surfaces for secrets, and domain reads where available) instead of direct gateway curl snippets or keychain lookups.
1145
+ Config/status retrieval instructions in bundled `SKILL.md` files are CLI-first. Retrieval should flow through canonical `vellum` CLI surfaces (`assistant config get` for generic settings, secure credential surfaces for secrets, and domain reads where available) instead of direct gateway curl snippets or credential store lookups.
1146
1146
 
1147
1147
  ```mermaid
1148
1148
  graph LR
@@ -1156,7 +1156,7 @@ Rules enforced by guard tests:
1156
1156
 
1157
1157
  - Retrieval reads use `bash` + canonical CLI surfaces (`assistant config get` and domain read commands where available).
1158
1158
  - Direct gateway `curl` + manual bearer headers are for control-plane writes/actions, not retrieval reads.
1159
- - Bundled skill docs must not instruct direct keychain lookups (`security find-generic-password`, `secret-tool`) for retrieval.
1159
+ - Bundled skill docs must not instruct direct credential store lookups (`security find-generic-password`, `secret-tool`) for retrieval.
1160
1160
  - `host_bash` is not used for Vellum CLI retrieval commands unless intentionally allowlisted.
1161
1161
  - Outbound credentialed API calls use CES tools (`make_authenticated_request`, `run_authenticated_command`) so credential materialization happens in a separate process. Command output (stdout/stderr) is forwarded back to the assistant and may contain credential values if the command echoes them, so the isolation covers injection, not output. `host_bash` is available as a user-approved escape hatch but is outside the strong secrecy guarantee.
1162
1162
 
@@ -1264,7 +1264,7 @@ graph TB
1264
1264
 
1265
1265
  Skills can embed dynamic shell output in their SKILL.md body using `!`command``tokens. When`skill_load` processes a skill containing these tokens, the commands are executed at load time through a sandboxed runner and their output is substituted inline. This enables externally authored skills to include project-specific context (e.g., directory listings, config values) without requiring manual edits.
1266
1266
 
1267
- **Feature flag:** `feature_flags.inline-skill-commands.enabled` (default: enabled). When disabled, loading a skill that contains `!`command`` tokens fails closed with an error rather than leaving raw tokens in the prompt.
1267
+ **Feature flag:** `inline-skill-commands` (default: enabled). When disabled, loading a skill that contains `!`command`` tokens fails closed with an error rather than leaving raw tokens in the prompt.
1268
1268
 
1269
1269
  #### Syntax and Parsing
1270
1270
 
@@ -1935,44 +1935,44 @@ Connected channels are resolved at signal emission time: vellum is always includ
1935
1935
 
1936
1936
  ## Storage Summary
1937
1937
 
1938
- | What | Where | Format | ORM/Driver | Retention |
1939
- | ---------------------------------------- | ----------------------------------------------------------------- | ----------------------------------- | ---------------------------------- | ------------------------------------------------------- |
1940
- | API key | CES / encrypted file store | Encrypted binary | CES API / `secure-keys.ts` | Permanent |
1941
- | Credential secrets | CES / encrypted file store | Encrypted binary | `secure-keys.ts` wrapper | Permanent (until deleted via tool) |
1942
- | Credential metadata | `~/.vellum/workspace/data/credentials/metadata.json` | JSON | Atomic file write | Permanent (until deleted via tool) |
1943
- | Integration OAuth tokens | CES / encrypted file store (via `secure-keys.ts`) | Encrypted binary | `TokenManager` auto-refresh | Until disconnected or revoked |
1944
- | User preferences | UserDefaults | plist | Foundation | Permanent |
1945
- | Session logs | `~/Library/.../logs/session-*.json` | JSON per session | Swift Codable | Unbounded |
1946
- | Conversations & messages | `~/.vellum/workspace/data/db/assistant.db` | SQLite + WAL | Drizzle ORM (Bun) | Permanent |
1947
- | Memory segments | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent |
1948
- | Extracted facts | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent, deduped |
1949
- | Embeddings | `~/.vellum/workspace/data/db/assistant.db` | JSON float arrays | Drizzle ORM | Permanent |
1950
- | Async job queue | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Completed jobs persist |
1951
- | Attachments | `~/.vellum/workspace/data/db/assistant.db` | Base64 in SQLite | Drizzle ORM | Permanent |
1952
- | Sandbox filesystem | `~/.vellum/workspace` | Real filesystem tree | Node FS APIs | Persistent across sessions |
1953
- | Tool permission rules | `~/.vellum/protected/trust.json` | JSON | File I/O | Permanent |
1954
- | Web users & assistants | PostgreSQL | Relational | Drizzle ORM (pg) | Permanent |
1955
- | Trace events | In-memory (TraceStore) | Structured events | Swift ObservableObject | Max 5,000 per session, ephemeral |
1956
- | Media embed settings | `~/.vellum/workspace/config.json` (`ui.mediaEmbeds`) | JSON | `WorkspaceConfigIO` (atomic merge) | Permanent |
1957
- | Media embed MIME cache | In-memory (`ImageMIMEProbe`) | `NSCache` (500 entries) | HTTP HEAD | Ephemeral; cleared on app restart |
1958
- | Tasks & task runs | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent |
1959
- | Work items (Task Queue) | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; archived items retained |
1960
- | Recurrence schedules & runs | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; supports cron and RRULE syntax |
1961
- | Watchers & events | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent, cascade on watcher delete |
1962
- | Proxy CA cert + key | `{dataDir}/proxy-ca/` | PEM files (ca.pem, ca-key.pem) | openssl CLI | Permanent (10-year validity) |
1963
- | Proxy leaf certs | `{dataDir}/proxy-ca/issued/` | PEM files per hostname | openssl CLI, cached | 1-year validity, re-issued on CA change |
1964
- | Proxy sessions | In-memory (SessionManager) | Map<ProxySessionId, ManagedSession> | Manual lifecycle | Ephemeral; 5min idle timeout, cleared on shutdown |
1965
- | Call sessions, events, pending questions | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent, cascade on session delete |
1966
- | Active call controllers | In-memory (CallState) | Map<callSessionId, CallController> | Manual lifecycle | Ephemeral; cleared on call end or destroy |
1967
- | Guardian bindings | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; revoked bindings retained |
1968
- | Channel verification sessions | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; consumed/expired sessions retained |
1969
- | Guardian approval requests | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; decision outcome retained |
1970
- | Contact invites | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; token hash stored, raw token never persisted |
1971
- | Contacts & channels | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; revoked/blocked contacts retained |
1972
- | Notification events | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; deduplicated by dedupeKey |
1973
- | Notification decisions | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; FK to notification_events |
1974
- | Notification deliveries | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; FK to notification_decisions |
1975
- | Notification preferences | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; per-assistant conversational preferences |
1938
+ | What | Where | Format | ORM/Driver | Retention |
1939
+ | ---------------------------------------- | ---------------------------------------------------- | ----------------------------------- | ---------------------------------- | ------------------------------------------------------- |
1940
+ | API key | CES / encrypted file store | Encrypted binary | CES API / `secure-keys.ts` | Permanent |
1941
+ | Credential secrets | CES / encrypted file store | Encrypted binary | `secure-keys.ts` wrapper | Permanent (until deleted via tool) |
1942
+ | Credential metadata | `~/.vellum/workspace/data/credentials/metadata.json` | JSON | Atomic file write | Permanent (until deleted via tool) |
1943
+ | Integration OAuth tokens | CES / encrypted file store (via `secure-keys.ts`) | Encrypted binary | `TokenManager` auto-refresh | Until disconnected or revoked |
1944
+ | User preferences | UserDefaults | plist | Foundation | Permanent |
1945
+ | Session logs | `~/Library/.../logs/session-*.json` | JSON per session | Swift Codable | Unbounded |
1946
+ | Conversations & messages | `~/.vellum/workspace/data/db/assistant.db` | SQLite + WAL | Drizzle ORM (Bun) | Permanent |
1947
+ | Memory segments | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent |
1948
+ | Extracted facts | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent, deduped |
1949
+ | Embeddings | `~/.vellum/workspace/data/db/assistant.db` | JSON float arrays | Drizzle ORM | Permanent |
1950
+ | Async job queue | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Completed jobs persist |
1951
+ | Attachments | `~/.vellum/workspace/data/db/assistant.db` | Base64 in SQLite | Drizzle ORM | Permanent |
1952
+ | Sandbox filesystem | `~/.vellum/workspace` | Real filesystem tree | Node FS APIs | Persistent across sessions |
1953
+ | Tool permission rules | `~/.vellum/protected/trust.json` | JSON | File I/O | Permanent |
1954
+ | Web users & assistants | PostgreSQL | Relational | Drizzle ORM (pg) | Permanent |
1955
+ | Trace events | In-memory (TraceStore) | Structured events | Swift ObservableObject | Max 5,000 per session, ephemeral |
1956
+ | Media embed settings | `~/.vellum/workspace/config.json` (`ui.mediaEmbeds`) | JSON | `WorkspaceConfigIO` (atomic merge) | Permanent |
1957
+ | Media embed MIME cache | In-memory (`ImageMIMEProbe`) | `NSCache` (500 entries) | HTTP HEAD | Ephemeral; cleared on app restart |
1958
+ | Tasks & task runs | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent |
1959
+ | Work items (Task Queue) | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; archived items retained |
1960
+ | Recurrence schedules & runs | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; supports cron and RRULE syntax |
1961
+ | Watchers & events | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent, cascade on watcher delete |
1962
+ | Proxy CA cert + key | `{dataDir}/proxy-ca/` | PEM files (ca.pem, ca-key.pem) | openssl CLI | Permanent (10-year validity) |
1963
+ | Proxy leaf certs | `{dataDir}/proxy-ca/issued/` | PEM files per hostname | openssl CLI, cached | 1-year validity, re-issued on CA change |
1964
+ | Proxy sessions | In-memory (SessionManager) | Map<ProxySessionId, ManagedSession> | Manual lifecycle | Ephemeral; 5min idle timeout, cleared on shutdown |
1965
+ | Call sessions, events, pending questions | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent, cascade on session delete |
1966
+ | Active call controllers | In-memory (CallState) | Map<callSessionId, CallController> | Manual lifecycle | Ephemeral; cleared on call end or destroy |
1967
+ | Guardian bindings | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; revoked bindings retained |
1968
+ | Channel verification sessions | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; consumed/expired sessions retained |
1969
+ | Guardian approval requests | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; decision outcome retained |
1970
+ | Contact invites | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; token hash stored, raw token never persisted |
1971
+ | Contacts & channels | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; revoked/blocked contacts retained |
1972
+ | Notification events | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; deduplicated by dedupeKey |
1973
+ | Notification decisions | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; FK to notification_events |
1974
+ | Notification deliveries | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; FK to notification_decisions |
1975
+ | Notification preferences | `~/.vellum/workspace/data/db/assistant.db` | SQLite | Drizzle ORM | Permanent; per-assistant conversational preferences |
1976
1976
 
1977
1977
  ### Sensitive Tool Output Placeholder Substitution
1978
1978
 
package/Dockerfile CHANGED
@@ -52,6 +52,9 @@ RUN apt-get update && apt-get install -y \
52
52
  sudo \
53
53
  htop \
54
54
  procps \
55
+ jq \
56
+ uuid-runtime \
57
+ vim \
55
58
  && rm -rf /var/lib/apt/lists/*
56
59
 
57
60
  # Copy bun binary from builder instead of re-installing
@@ -50,14 +50,7 @@ graph TB
50
50
 
51
51
  subgraph "Slack Skill (bundled-skills/slack/)"
52
52
  SLACK_SKILL_MD["SKILL.md<br/>agent instructions"]
53
- SLACK_SCAN["slack_scan_digest"]
54
- SLACK_DETAILS["slack_channel_details"]
55
- SLACK_CONFIGURE["slack_configure_channels"]
56
- SLACK_REACT["slack_add_reaction"]
57
- SLACK_DELETE["slack_delete_message"]
58
- SLACK_EDIT["slack_edit_message"]
59
- SLACK_LEAVE["slack_leave_channel"]
60
- SLACK_PERMS["slack_channel_permissions"]
53
+ SLACK_WEB_API["Web API via bash<br/>(network_mode: proxied)"]
61
54
  end
62
55
 
63
56
  subgraph "Sequences Skill (bundled-skills/sequences/)"
@@ -107,7 +100,7 @@ graph TB
107
100
  SEND --> SHARED
108
101
  STYLE --> STYLE_ANALYZER
109
102
  GMAIL_ARCHIVE --> GMAIL_ADAPTER
110
- SLACK_REACT --> SLACK_ADAPTER
103
+ SLACK_WEB_API --> SLACK_API
111
104
  ```
112
105
 
113
106
  ### Data Flow
@@ -151,7 +144,7 @@ sequenceDiagram
151
144
 
152
145
  Note over UI,API: Tool Execution Flow
153
146
  Tool->>TokenMgr: withValidToken("gmail", callback)
154
- TokenMgr->>Store: getConnectionByProvider("integration:google")
147
+ TokenMgr->>Store: getConnectionByProvider("google")
155
148
  TokenMgr->>Vault: getSecureKeyAsync("oauth_connection/{conn.id}/access_token")
156
149
  TokenMgr->>Store: check oauth_connections.expires_at
157
150
  alt Token expired
@@ -173,7 +166,7 @@ sequenceDiagram
173
166
 
174
167
  | Decision | Rationale |
175
168
  | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
176
- | PKCE by default, optional client_secret | Desktop apps prefer PKCE; some providers (Slack) require a secret, which is stored in the credential store (`oauth_app/{id}/client_secret`) for autonomous refresh |
169
+ | PKCE by default, optional client_secret | Desktop apps prefer PKCE; some providers (Slack) require a secret, which is stored in the credential store (`oauth_app/{id}/client_secret`) for autonomous refresh |
177
170
  | Shared connect orchestrator | All OAuth providers route through `orchestrateOAuthConnect()`, which resolves profiles, enforces scope policy, runs the flow, stores tokens, and verifies identity. Adding a provider is a declarative profile entry, not new orchestration code |
178
171
  | Canonical credential naming | All reads and writes use `client_id`/`client_secret` as canonical field names |
179
172
  | Gateway callback transport | OAuth callbacks are now routed through the gateway at `${ingress.publicBaseUrl}/webhooks/oauth/callback` instead of a loopback redirect URI. This enables OAuth flows to work in remote and tunneled deployments. |
@@ -203,32 +196,33 @@ sequenceDiagram
203
196
  | `assistant/src/watcher/providers/gmail.ts` | Gmail watcher using History API |
204
197
  | `assistant/src/watcher/providers/github.ts` | GitHub watcher for PRs, issues, review requests, and mentions |
205
198
  | `assistant/src/watcher/providers/linear.ts` | Linear watcher for assigned issues, status changes, and @mentions |
206
- | `assistant/src/oauth/provider-behaviors.ts` | Provider behavior registry: identity verifiers, setup metadata, injection templates |
199
+ | `assistant/src/oauth/seed-providers.ts` | Provider seed data: injection templates, identity config, setup metadata (seeded to DB on startup) |
207
200
  | `assistant/src/oauth/connect-orchestrator.ts` | Shared OAuth connect orchestrator: profile resolution, scope policy, flow execution, token storage |
208
201
  | `assistant/src/oauth/scope-policy.ts` | Deterministic scope resolution and policy enforcement |
209
- | `assistant/src/oauth/connect-types.ts` | Shared types: `OAuthProviderBehavior`, `OAuthScopePolicy`, `OAuthConnectResult` |
202
+ | `assistant/src/oauth/connect-types.ts` | Shared types: `OAuthScopePolicy`, `OAuthConnectResult` |
210
203
  | `assistant/src/oauth/token-persistence.ts` | Token storage helper: persists tokens, metadata, and runs post-connect hooks |
211
204
  | `assistant/src/daemon/handlers/oauth-connect.ts` | Generic OAuth connect handler (`oauth_connect_start` / `oauth_connect_result`) |
212
205
 
213
206
  ---
214
207
 
215
- ## OAuth Extensibility — Provider Behaviors, Scope Policy, and Connect Orchestrator
208
+ ## OAuth Extensibility — DB-Driven Provider Config, Scope Policy, and Connect Orchestrator
216
209
 
217
- The OAuth extensibility layer makes adding a new OAuth provider a declarative operation. Protocol fields (auth URLs, token URLs, scopes, scope policy) are stored in the `oauth_providers` database table, while behavioral fields (identity verifiers, setup metadata, injection templates) live in the **provider behavior registry**. The shared **connect orchestrator** handles the full flow from provider resolution through token storage.
210
+ The OAuth extensibility layer makes adding a new OAuth provider a fully declarative operation. All provider configuration — protocol fields (auth URLs, token URLs, scopes, scope policy), behavioral fields (identity verification, injection templates, setup metadata), and display metadata — is stored in the `oauth_providers` SQLite table and seeded on startup via `seed-providers.ts`. The shared **connect orchestrator** handles the full flow from provider resolution through token storage.
218
211
 
219
- ### Provider Behavior Registry
212
+ ### Provider Configuration (DB-Driven)
220
213
 
221
- `assistant/src/oauth/provider-behaviors.ts` contains the `PROVIDER_BEHAVIORS` map a registry of behavioral aspects for well-known OAuth providers. Each behavior (`OAuthProviderBehavior`) declares:
214
+ All provider config lives in the `oauth_providers` table. Built-in providers are seeded on every startup by `assistant/src/oauth/seed-providers.ts`, which upserts rows from the `PROVIDER_SEED_DATA` constant. Custom providers can be registered via the CLI (`assistant oauth providers register`).
222
215
 
223
- | Field | Purpose |
224
- | -------------------- | ------------------------------------------------------------------------------------------------------ |
225
- | `identityVerifier` | Async function that fetches human-readable account info (e.g. `@username`, email) after token exchange |
226
- | `setup` | Optional metadata for the generic OAuth setup skill (display name, dashboard URL, app type) |
227
- | `injectionTemplates` | Auto-applied credential injection rules for the script proxy |
216
+ Each provider row includes:
228
217
 
229
- Protocol fields (`authUrl`, `tokenUrl`, `defaultScopes`, `scopePolicy`, `callbackTransport`) are stored in the `oauth_providers` database table rather than in code.
230
-
231
- Registered providers: `integration:google`, `integration:slack`, `integration:notion`. Short aliases (e.g. `gmail`, `slack`) are resolved via `resolveService()`.
218
+ | Column group | Fields | Purpose |
219
+ | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
220
+ | **Protocol** | `authUrl`, `tokenUrl`, `tokenEndpointAuthMethod`, `callbackTransport`, `extraParams`, `loopbackPort` | OAuth2 flow parameters |
221
+ | **Scopes** | `defaultScopes`, `scopePolicy` | Deterministic scope resolution (user-customizable, preserved across seed restarts) |
222
+ | **Identity verification** | `identityUrl`, `identityMethod`, `identityHeaders`, `identityBody`, `identityResponsePaths`, `identityFormat`, `identityOkField` | Data-driven identity verifier fetches human-readable account info after token exchange |
223
+ | **Injection templates** | `injectionTemplates` | Auto-applied credential injection rules for the script proxy |
224
+ | **Setup metadata** | `displayName`, `description`, `dashboardUrl`, `appType`, `setupNotes`, `requiresClientSecret` | Metadata for the generic OAuth setup skill |
225
+ | **Ping config** | `pingUrl`, `pingMethod`, `pingHeaders`, `pingBody` | Health-check endpoint for `assistant oauth ping` |
232
226
 
233
227
  ### Scope Policy Engine
234
228
 
@@ -247,12 +241,12 @@ Returns `{ ok: true, scopes }` or `{ ok: false, error, allowedScopes }`.
247
241
 
248
242
  `assistant/src/oauth/connect-orchestrator.ts` exports `orchestrateOAuthConnect(options)`, which runs the full OAuth2 flow:
249
243
 
250
- 1. **Resolve service** — alias expansion via `resolveService()`.
251
- 2. **Load behavior** — `getProviderBehavior()` from the registry; load protocol fields from the `oauth_providers` DB table.
244
+ 1. **Receive canonical provider name** — the orchestrator receives the canonical provider name directly (e.g. `google`, `slack`).
245
+ 2. **Load provider row** — reads all config from the `oauth_providers` DB table.
252
246
  3. **Compute scopes** — `resolveScopes()` with scope policy enforcement.
253
247
  4. **Build OAuth config** — assemble protocol-level config from the DB provider row.
254
248
  5. **Run flow** — interactive (opens browser, blocks until completion) or deferred (returns auth URL for the caller to deliver).
255
- 6. **Verify identity** — runs the profile's `identityVerifier` if defined.
249
+ 6. **Verify identity** — runs the generic data-driven identity verifier using the provider row's identity columns.
256
250
  7. **Store tokens** — `storeOAuth2Tokens()` persists access/refresh tokens, client credentials, and metadata.
257
251
 
258
252
  Result is a discriminated union: `{ success, deferred, grantedScopes, accountInfo }` or `{ success: false, error }`.
@@ -270,24 +264,25 @@ This replaces provider-specific handlers — any provider in the registry can be
270
264
 
271
265
  ### Adding a New OAuth Provider
272
266
 
273
- 1. **Register protocol fields** in the `oauth_providers` database table (via CLI or migration):
274
- - Set `authUrl`, `tokenUrl`, `defaultScopes`, `scopePolicy`, and `callbackTransport`.
275
- 2. **Optional: declare behavioral fields** in `PROVIDER_BEHAVIORS` (`oauth/provider-behaviors.ts`):
276
- - Add an `identityVerifier` an async function that fetches the user's account info from the provider's API.
277
- - Add `setup` metadata `displayName`, `dashboardUrl`, `appType` enable the generic OAuth setup skill to guide users through app creation.
278
- - Add `injectionTemplates` for providers whose tokens should be auto-injected by the script proxy.
267
+ 1. **Add seed data** to `PROVIDER_SEED_DATA` in `assistant/src/oauth/seed-providers.ts`:
268
+ - Set protocol fields: `authUrl`, `tokenUrl`, `defaultScopes`, `scopePolicy`, `callbackTransport`.
269
+ - Set identity verification: `identityUrl`, `identityMethod`, `identityHeaders`, `identityResponsePaths`, `identityFormat`.
270
+ - Set injection templates: `injectionTemplates` for providers whose tokens should be auto-injected by the script proxy.
271
+ - Set setup metadata: `displayName`, `dashboardUrl`, `appType` enable the generic OAuth setup skill to guide users through app creation.
272
+ 2. **Alternatively, register dynamically** via the CLI: `assistant oauth providers register <key> --auth-url ... --token-url ...`.
279
273
  3. **No handler code needed** — the generic `oauth_connect_start` handler and the connect orchestrator handle the flow automatically.
280
274
 
281
275
  ### Key Source Files
282
276
 
283
- | File | Role |
284
- | ------------------------------------------------ | -------------------------------------------------------------------------------- |
285
- | `assistant/src/oauth/provider-behaviors.ts` | Provider behavior registry and alias resolution |
286
- | `assistant/src/oauth/scope-policy.ts` | Scope resolution and policy enforcement (pure, no I/O) |
287
- | `assistant/src/oauth/connect-orchestrator.ts` | Shared connect orchestrator (profile → scopes → flow → tokens) |
288
- | `assistant/src/oauth/connect-types.ts` | Shared types (`OAuthProviderBehavior`, `OAuthScopePolicy`, `OAuthConnectResult`) |
289
- | `assistant/src/oauth/token-persistence.ts` | Token storage: credential store writes, metadata upsert, post-connect hooks |
290
- | `assistant/src/daemon/handlers/oauth-connect.ts` | Generic `oauth_connect_start` / `oauth_connect_result` handler |
277
+ | File | Role |
278
+ | ------------------------------------------------ | --------------------------------------------------------------------------- |
279
+ | `assistant/src/oauth/seed-providers.ts` | Provider seed data and startup seeding |
280
+ | `assistant/src/oauth/scope-policy.ts` | Scope resolution and policy enforcement (pure, no I/O) |
281
+ | `assistant/src/oauth/connect-orchestrator.ts` | Shared connect orchestrator (profile → scopes → flow → tokens) |
282
+ | `assistant/src/oauth/connect-types.ts` | Shared types (`OAuthScopePolicy`, `OAuthConnectResult`) |
283
+ | `assistant/src/oauth/token-persistence.ts` | Token storage: credential store writes, metadata upsert, post-connect hooks |
284
+ | `assistant/src/oauth/identity-verifier.ts` | Generic data-driven identity verifier (reads config from provider DB row) |
285
+ | `assistant/src/daemon/handlers/oauth-connect.ts` | Generic `oauth_connect_start` / `oauth_connect_result` handler |
291
286
 
292
287
  ---
293
288
 
@@ -154,7 +154,6 @@ graph TB
154
154
  BUDGET["Dynamic Recall Budget<br/>computeRecallBudget()<br/>from prompt headroom"]
155
155
  EMBED_Q["Generate dense + sparse<br/>query embeddings"]
156
156
  HYBRID["Hybrid Search<br/>dense + sparse RRF on Qdrant"]
157
- RECENCY["Recency Search<br/>conversation-scoped, DB only"]
158
157
  MERGE["Merge + Deduplicate<br/>weighted score combination"]
159
158
  SCOPE["Scope Filter<br/>scope_id filtering<br/>(strict | global_fallback)<br/>Private conversations: own scope + 'default'"]
160
159
  TIER["Tier Classification<br/>score > 0.8 → tier 1<br/>score > 0.6 → tier 2<br/>below → dropped"]
@@ -218,9 +217,7 @@ graph TB
218
217
  EMBED_Q --> SPARSE_GEN
219
218
  EMBED_Q --> HYBRID
220
219
  HYBRID --> RRF
221
- QUERY --> RECENCY
222
220
  HYBRID --> SCOPE
223
- RECENCY --> SCOPE
224
221
  SCOPE --> MERGE
225
222
  MERGE --> TIER
226
223
  TIER --> STALE
@@ -337,24 +334,22 @@ The recall pipeline runs on every turn that passes the `needsMemory` gate (skips
337
334
 
338
335
  3. **Hybrid search on Qdrant**: When both dense and sparse vectors are available, the pipeline uses Qdrant's query API with two prefetch stages (dense and sparse, each fetching up to 40 candidates) fused via Reciprocal Rank Fusion (RRF). Falls back to dense-only search when sparse vectors are unavailable.
339
336
 
340
- 4. **Recency supplement**: A DB-only recency search fetches the 5 most recent segments from the current conversation, providing conversation-local context even when vector search misses.
337
+ 4. **Merge and deduplicate**: Hybrid candidates are deduplicated by key. A weighted final score is computed: `0.4 + importance * 0.25 + confidence * 0.15 + recency * 0.2`, where `recency` is a logarithmic time-decay score (ACT-R inspired) based on when the item was last seen.
341
338
 
342
- 5. **Merge and deduplicate**: Hybrid and recency candidates are merged by key. Duplicate entries keep the highest scores from each source. A weighted final score is computed: `semantic * 0.7 + recency * 0.2 + confidence * 0.1`.
343
-
344
- 6. **Tier classification** (`tier-classifier.ts`): Score-based, deterministic classification:
339
+ 5. **Tier classification** (`tier-classifier.ts`): Score-based, deterministic classification:
345
340
  - `finalScore > 0.8` → **tier 1** (high relevance)
346
341
  - `finalScore > 0.6` → **tier 2** (possibly relevant)
347
342
  - Below 0.6 → dropped
348
343
 
349
- 7. **Staleness computation** (`staleness.ts`): Each item candidate is annotated with a staleness level based on its age relative to a kind-specific base lifetime (see table above). The effective lifetime is extended by a reinforcement factor: `baseLifetime * (1 + 0.3 * (sourceConversationCount - 1))`, so items mentioned across multiple conversations age more slowly. Staleness levels:
344
+ 6. **Staleness computation** (`staleness.ts`): Each item candidate is annotated with a staleness level based on its age relative to a kind-specific base lifetime (see table above). The effective lifetime is extended by a reinforcement factor: `baseLifetime * (1 + 0.3 * (sourceConversationCount - 1))`, so items mentioned across multiple conversations age more slowly. Staleness levels:
350
345
  - `ratio < 0.5` → `fresh`
351
346
  - `ratio <= 1.0` → `aging`
352
347
  - `ratio <= 2.0` → `stale`
353
348
  - `ratio > 2.0` → `very_stale`
354
349
 
355
- 8. **Stale demotion**: `very_stale` tier 1 candidates are demoted to tier 2, preventing old information from occupying prime injection space.
350
+ 7. **Stale demotion**: `very_stale` tier 1 candidates are demoted to tier 2, preventing old information from occupying prime injection space.
356
351
 
357
- 9. **Two-layer XML injection** (`formatting.ts`): Budget-aware rendering into four XML sections:
352
+ 8. **Two-layer XML injection** (`formatting.ts`): Budget-aware rendering into four XML sections:
358
353
 
359
354
  ```xml
360
355
  <memory_context __injected>
@@ -380,7 +375,7 @@ The recall pipeline runs on every turn that passes the `needsMemory` gate (skips
380
375
 
381
376
  Empty sections are omitted. Each section has a per-item token budget (150 tokens for tier 1, 100 for tier 2). Tier 1 sections consume budget first; tier 2 uses the remainder.
382
377
 
383
- 10. **Injection strategy**: The rendered `<memory_context __injected>` block is prepended as a text content block to the last user message (`injectMemoryRecallAsUserBlock`), following the same pattern as workspace, temporal, and other runtime injections. Stripping is handled by the generic `stripUserTextBlocksByPrefix` mechanism matching the `<memory_context __injected>` prefix (with a backward-compat entry for the legacy `<memory_context>` prefix from older history). This avoids synthetic message pairs and preserves prompt prefix caching between turns.
378
+ 9. **Injection strategy**: The rendered `<memory_context __injected>` block is prepended as a text content block to the last user message (`injectMemoryRecallAsUserBlock`), following the same pattern as workspace, temporal, and other runtime injections. Stripping is handled by the generic `stripUserTextBlocksByPrefix` mechanism matching the `<memory_context __injected>` prefix (with a backward-compat entry for the legacy `<memory_context>` prefix from older history). This avoids synthetic message pairs and preserves prompt prefix caching between turns.
384
379
 
385
380
  ### Internal-Only Trust Gating
386
381
 
@@ -412,7 +407,7 @@ When the embedding backend or Qdrant is unavailable:
412
407
 
413
408
  - A **circuit breaker** on Qdrant (`qdrant-circuit-breaker.ts`) tracks consecutive failures and short-circuits search calls when the breaker is open.
414
409
  - If embedding generation fails and `memory.embeddings.required` is `true`, recall returns an empty result with a degradation status (`embedding_generation_failed` or `embedding_provider_down`).
415
- - If embeddings are optional (default), the pipeline falls back to recency-only search.
410
+ - If embeddings are optional (default), the pipeline returns empty results (no fallback search path exists without Qdrant).
416
411
  - Degradation status is reported to clients via `memory_status` events.
417
412
 
418
413
  ---
@@ -56,7 +56,7 @@ CES tools use the standard `class ... implements Tool` registration pattern. The
56
56
 
57
57
  ### 1. `host_bash` is outside the strong secrecy guarantee
58
58
 
59
- The existing `host_bash` tool executes commands on the host machine without any credential isolation. When an agent uses `host_bash`, it has full access to the host environment, including any credentials stored in environment variables, config files, or keychains accessible to the user. CES does not attempt to intercept or sandbox `host_bash` invocations.
59
+ The existing `host_bash` tool executes commands on the host machine without any credential isolation. When an agent uses `host_bash`, it has full access to the host environment, including any credentials stored in environment variables, config files, or credential stores accessible to the user. CES does not attempt to intercept or sandbox `host_bash` invocations.
60
60
 
61
61
  **Implication**: `host_bash` represents a weaker security tier. Agents that require the strong secrecy guarantee must use `run_authenticated_command` instead. Trust rules and permission policies should reflect this distinction — managed deployments may deny `host_bash` entirely for untrusted agents while allowing `run_authenticated_command`.
62
62
 
@@ -237,13 +237,13 @@ CES is rolled out incrementally via feature flags, all defaulting to `false` (of
237
237
 
238
238
  Enable flags in this order. Each flag is safe to enable independently, but later flags depend on earlier ones being on for meaningful behavior.
239
239
 
240
- | Order | Flag | Gate | Safe to enable alone? |
241
- | ----- | ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
242
- | 1 | `feature_flags.ces-tools.enabled` | Register CES tools (`run_authenticated_command`, `make_authenticated_request`, `manage_secure_command_tool`) in the agent loop | Yes — tools register but are not invoked unless the agent discovers credentials that require CES |
243
- | 2 | `feature_flags.ces-shell-lockdown.enabled` | Enforce shell lockdown for untrusted agents with CES-active credentials; direct shell access to credentialed services is denied | Yes — only activates when CES credentials are present |
244
- | 3 | `feature_flags.ces-secure-install.enabled` | Route tool/command installation through CES secure bundle pipeline instead of direct shell | Yes — falls back to standard install if CES is unavailable |
245
- | 4 | `feature_flags.ces-grant-audit.enabled` | Gate CLI execution of grant listing, grant revocation, and audit inspection commands (commands are always registered but check the flag at runtime) | Yes — read-only inspection surfaces |
246
- | 5 | `feature_flags.ces-managed-sidecar.enabled` | Use managed sidecar transport (Unix socket) instead of local child-process transport | **No** — requires the CES sidecar container to be present in the pod template. Only enable after the sidecar image is deployed. |
240
+ | Order | Flag | Gate | Safe to enable alone? |
241
+ | ----- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
242
+ | 1 | `ces-tools` | Register CES tools (`run_authenticated_command`, `make_authenticated_request`, `manage_secure_command_tool`) in the agent loop | Yes — tools register but are not invoked unless the agent discovers credentials that require CES |
243
+ | 2 | `ces-shell-lockdown` | Enforce shell lockdown for untrusted agents with CES-active credentials; direct shell access to credentialed services is denied | Yes — only activates when CES credentials are present |
244
+ | 3 | `ces-secure-install` | Route tool/command installation through CES secure bundle pipeline instead of direct shell | Yes — falls back to standard install if CES is unavailable |
245
+ | 4 | `ces-grant-audit` | Gate CLI execution of grant listing, grant revocation, and audit inspection commands (commands are always registered but check the flag at runtime) | Yes — read-only inspection surfaces |
246
+ | 5 | `ces-managed-sidecar` | Use managed sidecar transport (Unix socket) instead of local child-process transport | **No** — requires the CES sidecar container to be present in the pod template. Only enable after the sidecar image is deployed. |
247
247
 
248
248
  ### Dark-launching the managed sidecar
249
249
 
@@ -325,7 +325,7 @@ Risks that are acknowledged and accepted for v1, documented here so they are exp
325
325
 
326
326
  ### 1. `host_bash` is a weaker security tier
327
327
 
328
- `host_bash` executes commands on the host machine with full access to the host environment. CES does not intercept or sandbox `host_bash` invocations. An untrusted agent with `host_bash` access can read credentials from environment variables, config files, or keychains.
328
+ `host_bash` executes commands on the host machine with full access to the host environment. CES does not intercept or sandbox `host_bash` invocations. An untrusted agent with `host_bash` access can read credentials from environment variables, config files, or credential stores.
329
329
 
330
330
  **Mitigation**: Trust rules and permission policies should deny `host_bash` for untrusted agents in managed deployments. This is a policy enforcement, not a technical guarantee. The CES process-boundary isolation only protects operations routed through CES tools.
331
331
 
package/docs/skills.md CHANGED
@@ -198,7 +198,7 @@ Malformed tokens do not silently pass through — they are collected as errors a
198
198
 
199
199
  ### Feature flag
200
200
 
201
- Inline command expansion is gated by the `inline-skill-commands` feature flag (key: `feature_flags.inline-skill-commands.enabled`). The flag defaults to **enabled**.
201
+ Inline command expansion is gated by the `inline-skill-commands` feature flag (key: `inline-skill-commands`). The flag defaults to **enabled**.
202
202
 
203
203
  When the flag is disabled and a skill contains inline command expansion tokens, `skill_load` returns an error rather than delivering unexpanded tokens to the model. This fail-closed behavior prevents the LLM from seeing raw expansion tokens and attempting to interpret them.
204
204
 
@@ -71,19 +71,19 @@ describe("handles", () => {
71
71
 
72
72
  describe("localOAuthHandle", () => {
73
73
  test("constructs the expected format", () => {
74
- expect(localOAuthHandle("integration:google", "conn-123")).toBe(
75
- "local_oauth:integration:google/conn-123",
74
+ expect(localOAuthHandle("google", "conn-123")).toBe(
75
+ "local_oauth:google/conn-123",
76
76
  );
77
77
  });
78
78
 
79
- test("roundtrips with integration: prefix in providerKey", () => {
80
- const raw = localOAuthHandle("integration:slack", "conn-abc");
79
+ test("roundtrips through parseHandle", () => {
80
+ const raw = localOAuthHandle("slack", "conn-abc");
81
81
  const result = parseHandle(raw);
82
82
  expect(result.ok).toBe(true);
83
83
  if (!result.ok) return;
84
84
  expect(result.handle.type).toBe(HandleType.LocalOAuth);
85
85
  if (result.handle.type !== HandleType.LocalOAuth) return;
86
- expect(result.handle.providerKey).toBe("integration:slack");
86
+ expect(result.handle.providerKey).toBe("slack");
87
87
  expect(result.handle.connectionId).toBe("conn-abc");
88
88
  });
89
89
  });
@@ -133,7 +133,7 @@ describe("handles", () => {
133
133
  });
134
134
 
135
135
  test("rejects local_oauth with no slash", () => {
136
- const result = parseHandle("local_oauth:integration:google");
136
+ const result = parseHandle("local_oauth:google");
137
137
  expect(result.ok).toBe(false);
138
138
  });
139
139
 
@@ -150,7 +150,7 @@ describe("handles", () => {
150
150
  ).not.toThrow();
151
151
  expect(() =>
152
152
  CredentialHandleSchema.parse(
153
- "local_oauth:integration:google/conn-1",
153
+ "local_oauth:google/conn-1",
154
154
  ),
155
155
  ).not.toThrow();
156
156
  expect(() =>
@@ -13,7 +13,7 @@
13
13
  *
14
14
  * 2. **Local OAuth** — references a locally persisted OAuth connection.
15
15
  * Format: `local_oauth:<providerKey>/<connectionId>` where providerKey
16
- * uses the existing `integration:*` keys (e.g. `integration:google`).
16
+ * is the bare provider name (e.g. `google`).
17
17
  *
18
18
  * 3. **Managed OAuth** — references an OAuth connection managed by the
19
19
  * platform. Format: `platform_oauth:<connectionId>` where connectionId
@@ -50,7 +50,7 @@ export interface LocalStaticHandle {
50
50
 
51
51
  export interface LocalOAuthHandle {
52
52
  type: typeof HandleType.LocalOAuth;
53
- /** Provider key (e.g. "integration:google", "integration:slack"). */
53
+ /** Provider key (e.g. "google", "slack"). */
54
54
  providerKey: string;
55
55
  /** Connection identifier. */
56
56
  connectionId: string;
@@ -146,8 +146,9 @@ export function parseHandle(raw: string): ParseHandleResult {
146
146
  }
147
147
 
148
148
  case HandleType.LocalOAuth: {
149
- // providerKey may itself contain a colon (e.g. "integration:google"),
150
- // so we split on the *last* "/" to separate providerKey from connectionId.
149
+ // providerKey is typically a bare name (e.g. "google"), but legacy handles
150
+ // may contain a colon (e.g. "integration:google"), so we split on the
151
+ // *last* "/" to separate providerKey from connectionId.
151
152
  const lastSlashIdx = rest.lastIndexOf("/");
152
153
  if (
153
154
  lastSlashIdx === -1 ||
@@ -73,8 +73,8 @@ export interface InjectionTemplate {
73
73
  export type SecureKeyDeleteResult = "deleted" | "not-found" | "error";
74
74
 
75
75
  /**
76
- * Abstraction over the underlying secure-key backend (e.g. macOS Keychain,
77
- * encrypted file store). Implementations handle platform-specific details.
76
+ * Abstraction over the underlying secure-key backend (e.g. encrypted file
77
+ * store). Implementations handle platform-specific details.
78
78
  */
79
79
  export interface SecureKeyBackend {
80
80
  /** Retrieve a secret value by key. Returns undefined if not found. */
@@ -98,7 +98,7 @@ export interface SecureKeyBackend {
98
98
  export interface OAuthConnectionRecord {
99
99
  /** Unique identifier for this connection. */
100
100
  id: string;
101
- /** Provider key (e.g. "integration:google", "integration:slack"). */
101
+ /** Provider key (e.g. "google", "slack"). */
102
102
  providerKey: string;
103
103
  /** Account identifier (e.g. email address). */
104
104
  accountInfo: string | null;
@@ -233,7 +233,7 @@ export class StaticCredentialMetadataStore {
233
233
 
234
234
  /**
235
235
  * Throws if the metadata file has an unrecognized version.
236
- * Call this before performing irreversible keychain operations
236
+ * Call this before performing irreversible credential store operations
237
237
  * so the operation fails cleanly before any side effects.
238
238
  */
239
239
  assertWritable(): void {