@vellumai/assistant 0.5.1 → 0.5.3

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 (405) hide show
  1. package/ARCHITECTURE.md +163 -54
  2. package/docs/architecture/integrations.md +62 -67
  3. package/docs/credential-execution-service.md +3 -3
  4. package/docs/skills.md +100 -0
  5. package/package.json +1 -1
  6. package/src/__tests__/agent-loop.test.ts +111 -0
  7. package/src/__tests__/always-loaded-tools-guard.test.ts +3 -4
  8. package/src/__tests__/app-builder-tool-scripts.test.ts +13 -151
  9. package/src/__tests__/app-dir-path-guard.test.ts +78 -0
  10. package/src/__tests__/app-executors.test.ts +1 -291
  11. package/src/__tests__/app-git-history.test.ts +4 -4
  12. package/src/__tests__/app-routes-csp.test.ts +1 -0
  13. package/src/__tests__/app-store-dir-names.test.ts +426 -0
  14. package/src/__tests__/attachments-store.test.ts +169 -21
  15. package/src/__tests__/attachments.test.ts +115 -1
  16. package/src/__tests__/btw-routes.test.ts +1 -0
  17. package/src/__tests__/canonical-guardian-store.test.ts +38 -0
  18. package/src/__tests__/channel-reply-delivery.test.ts +55 -0
  19. package/src/__tests__/checker.test.ts +54 -0
  20. package/src/__tests__/claude-code-skill-regression.test.ts +2 -0
  21. package/src/__tests__/claude-code-tool-profiles.test.ts +2 -0
  22. package/src/__tests__/compaction.benchmark.test.ts +2 -1
  23. package/src/__tests__/config-schema-cmd.test.ts +68 -21
  24. package/src/__tests__/config-schema.test.ts +1 -1
  25. package/src/__tests__/conversation-agent-loop-overflow.test.ts +156 -5
  26. package/src/__tests__/conversation-agent-loop.test.ts +297 -2
  27. package/src/__tests__/conversation-attachments.test.ts +17 -19
  28. package/src/__tests__/conversation-disk-view-integration.test.ts +277 -0
  29. package/src/__tests__/conversation-disk-view.test.ts +810 -0
  30. package/src/__tests__/conversation-error.test.ts +1 -1
  31. package/src/__tests__/conversation-fork-crud.test.ts +551 -0
  32. package/src/__tests__/conversation-fork-route.test.ts +386 -0
  33. package/src/__tests__/conversation-history-web-search.test.ts +1 -1
  34. package/src/__tests__/conversation-key-store-disk-view.test.ts +130 -0
  35. package/src/__tests__/conversation-media-retry.test.ts +8 -2
  36. package/src/__tests__/conversation-memory-dirty-tail.test.ts +150 -0
  37. package/src/__tests__/conversation-provider-retry-repair.test.ts +7 -0
  38. package/src/__tests__/conversation-queue.test.ts +36 -1
  39. package/src/__tests__/conversation-routes-disk-view.test.ts +439 -0
  40. package/src/__tests__/conversation-routes-guardian-reply.test.ts +2 -2
  41. package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -7
  42. package/src/__tests__/conversation-runtime-assembly.test.ts +17 -2
  43. package/src/__tests__/conversation-skill-tools.test.ts +4 -9
  44. package/src/__tests__/conversation-slash-commands.test.ts +149 -0
  45. package/src/__tests__/conversation-store.test.ts +24 -21
  46. package/src/__tests__/conversation-surfaces-state-update.test.ts +246 -0
  47. package/src/__tests__/conversation-surfaces-task-progress.test.ts +1 -0
  48. package/src/__tests__/conversation-title-service.test.ts +137 -0
  49. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +25 -315
  50. package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +1 -0
  51. package/src/__tests__/conversation-tool-setup-side-effect-flag.test.ts +1 -0
  52. package/src/__tests__/conversation-wipe.test.ts +226 -0
  53. package/src/__tests__/conversation-workspace-cache-state.test.ts +44 -2
  54. package/src/__tests__/conversation-workspace-injection.test.ts +11 -0
  55. package/src/__tests__/credential-security-invariants.test.ts +3 -0
  56. package/src/__tests__/credential-vault-unit.test.ts +5 -10
  57. package/src/__tests__/cu-unified-flow.test.ts +1 -0
  58. package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +241 -0
  59. package/src/__tests__/db-llm-request-log-provider-migration.test.ts +214 -0
  60. package/src/__tests__/db-memory-archive-migration.test.ts +372 -0
  61. package/src/__tests__/db-memory-brief-state-migration.test.ts +213 -0
  62. package/src/__tests__/db-memory-reducer-checkpoints.test.ts +273 -0
  63. package/src/__tests__/diagnostics-export.test.ts +70 -1
  64. package/src/__tests__/first-greeting.test.ts +80 -0
  65. package/src/__tests__/gateway-only-guard.test.ts +1 -0
  66. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +3 -7
  67. package/src/__tests__/history-repair.test.ts +32 -10
  68. package/src/__tests__/http-conversation-lineage.test.ts +251 -0
  69. package/src/__tests__/image-source-path-reinject.test.ts +136 -0
  70. package/src/__tests__/inline-command-runner.test.ts +311 -0
  71. package/src/__tests__/inline-skill-authoring-guard.test.ts +220 -0
  72. package/src/__tests__/inline-skill-load-permissions.test.ts +435 -0
  73. package/src/__tests__/list-messages-attachments.test.ts +96 -0
  74. package/src/__tests__/llm-context-normalization.test.ts +1116 -0
  75. package/src/__tests__/llm-context-route-provider.test.ts +217 -0
  76. package/src/__tests__/llm-request-log-turn-query.test.ts +270 -0
  77. package/src/__tests__/media-generate-image.test.ts +47 -94
  78. package/src/__tests__/memory-brief-open-loops.test.ts +530 -0
  79. package/src/__tests__/memory-brief-time.test.ts +285 -0
  80. package/src/__tests__/memory-brief-wrapper.test.ts +311 -0
  81. package/src/__tests__/memory-chunk-archive.test.ts +400 -0
  82. package/src/__tests__/memory-chunk-dual-write.test.ts +453 -0
  83. package/src/__tests__/memory-episode-archive.test.ts +370 -0
  84. package/src/__tests__/memory-episode-dual-write.test.ts +626 -0
  85. package/src/__tests__/memory-lifecycle-e2e.test.ts +3 -1
  86. package/src/__tests__/memory-observation-archive.test.ts +375 -0
  87. package/src/__tests__/memory-observation-dual-write.test.ts +318 -0
  88. package/src/__tests__/memory-recall-quality.test.ts +7 -7
  89. package/src/__tests__/memory-reducer-store.test.ts +728 -0
  90. package/src/__tests__/memory-reducer-types.test.ts +699 -0
  91. package/src/__tests__/memory-reducer.test.ts +698 -0
  92. package/src/__tests__/memory-regressions.test.ts +6 -4
  93. package/src/__tests__/memory-simplified-config.test.ts +281 -0
  94. package/src/__tests__/migration-cross-version-compatibility.test.ts +4 -1
  95. package/src/__tests__/migration-export-http.test.ts +3 -1
  96. package/src/__tests__/migration-import-commit-http.test.ts +18 -4
  97. package/src/__tests__/migration-import-preflight-http.test.ts +1 -3
  98. package/src/__tests__/mime-builder.test.ts +3 -2
  99. package/src/__tests__/non-member-access-request.test.ts +12 -1
  100. package/src/__tests__/notification-decision-identity.test.ts +52 -0
  101. package/src/__tests__/oauth-apps-routes.test.ts +103 -0
  102. package/src/__tests__/oauth-store.test.ts +115 -0
  103. package/src/__tests__/parse-identity-fields.test.ts +129 -0
  104. package/src/__tests__/provider-error-scenarios.test.ts +1 -3
  105. package/src/__tests__/provider-failover-actual-provider.test.ts +66 -0
  106. package/src/__tests__/recording-handler.test.ts +17 -0
  107. package/src/__tests__/registry.test.ts +3 -8
  108. package/src/__tests__/relay-server.test.ts +1 -1
  109. package/src/__tests__/runtime-attachment-metadata.test.ts +7 -3
  110. package/src/__tests__/schema-transforms.test.ts +165 -5
  111. package/src/__tests__/server-history-render.test.ts +2 -2
  112. package/src/__tests__/skill-load-inline-command.test.ts +598 -0
  113. package/src/__tests__/skill-load-inline-includes.test.ts +644 -0
  114. package/src/__tests__/skills-inline-command-expansions.test.ts +301 -0
  115. package/src/__tests__/skills-transitive-hash.test.ts +333 -0
  116. package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
  117. package/src/__tests__/slack-inbound-verification.test.ts +2 -2
  118. package/src/__tests__/starter-task-flow.test.ts +1 -0
  119. package/src/__tests__/suggestion-routes.test.ts +443 -0
  120. package/src/__tests__/swarm-conversation-integration.test.ts +1 -0
  121. package/src/__tests__/swarm-recursion.test.ts +1 -0
  122. package/src/__tests__/swarm-tool.test.ts +1 -0
  123. package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -0
  124. package/src/__tests__/tool-preview-lifecycle.test.ts +32 -5
  125. package/src/__tests__/top-level-renderer.test.ts +22 -0
  126. package/src/__tests__/turn-boundary-resolution.test.ts +243 -0
  127. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +320 -0
  128. package/src/__tests__/web-fetch.test.ts +6 -2
  129. package/src/__tests__/workspace-migration-006-services-config.test.ts +335 -0
  130. package/src/__tests__/workspace-migration-007-web-search-provider-rename.test.ts +312 -0
  131. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +278 -0
  132. package/src/__tests__/workspace-migration-010-app-dir-rename.test.ts +275 -0
  133. package/src/__tests__/workspace-migration-012-rename-conversation-disk-view-dirs.test.ts +77 -0
  134. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +401 -0
  135. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +328 -0
  136. package/src/__tests__/workspace-migration-seed-device-id.test.ts +6 -10
  137. package/src/agent/attachments.ts +27 -1
  138. package/src/agent/loop.ts +29 -1
  139. package/src/avatar/traits-png-sync.ts +80 -25
  140. package/src/bundler/app-bundler.ts +4 -4
  141. package/src/calls/call-domain.ts +1 -0
  142. package/src/calls/voice-session-bridge.ts +1 -0
  143. package/src/cli/commands/auth.ts +92 -0
  144. package/src/cli/commands/avatar.ts +7 -6
  145. package/src/cli/commands/config.ts +2 -0
  146. package/src/cli/commands/oauth/providers.ts +29 -0
  147. package/src/cli/program.ts +12 -0
  148. package/src/cli.ts +15 -48
  149. package/src/config/bundled-skills/app-builder/SKILL.md +103 -28
  150. package/src/config/bundled-skills/app-builder/TOOLS.json +5 -199
  151. package/src/config/bundled-skills/app-builder/tools/{app-query.ts → app-refresh.ts} +2 -2
  152. package/src/config/bundled-skills/contacts/tools/google-contacts.ts +2 -3
  153. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +6 -9
  154. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +4 -6
  155. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +2 -3
  156. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +2 -3
  157. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +2 -3
  158. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +2 -3
  159. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +4 -6
  160. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +2 -3
  161. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +2 -3
  162. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +2 -3
  163. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +2 -3
  164. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -3
  165. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +2 -3
  166. package/src/config/bundled-skills/google-calendar/tools/shared.ts +1 -1
  167. package/src/config/bundled-skills/image-studio/SKILL.md +2 -2
  168. package/src/config/bundled-skills/image-studio/TOOLS.json +2 -2
  169. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +45 -72
  170. package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +2 -2
  171. package/src/config/bundled-skills/messaging/tools/shared.ts +1 -1
  172. package/src/config/bundled-skills/settings/tools/voice-config-update.ts +19 -3
  173. package/src/config/bundled-skills/skill-management/SKILL.md +1 -1
  174. package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
  175. package/src/config/bundled-skills/slack/tools/shared.ts +19 -4
  176. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +2 -3
  177. package/src/config/bundled-skills/transcribe/SKILL.md +1 -1
  178. package/src/config/bundled-skills/transcribe/TOOLS.json +2 -6
  179. package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +19 -83
  180. package/src/config/bundled-tool-registry.ts +2 -14
  181. package/src/config/feature-flag-registry.json +24 -0
  182. package/src/config/loader.ts +65 -0
  183. package/src/config/raw-config-utils.ts +58 -0
  184. package/src/config/schema-utils.ts +28 -7
  185. package/src/config/schema.ts +20 -0
  186. package/src/config/schemas/elevenlabs.ts +18 -0
  187. package/src/config/schemas/memory-lifecycle.ts +4 -2
  188. package/src/config/schemas/memory-simplified.ts +101 -0
  189. package/src/config/schemas/memory-storage.ts +1 -1
  190. package/src/config/schemas/memory.ts +4 -0
  191. package/src/config/schemas/services.ts +8 -6
  192. package/src/config/skills.ts +50 -4
  193. package/src/contacts/contact-store.ts +13 -6
  194. package/src/contacts/contacts-write.ts +0 -1
  195. package/src/context/window-manager.ts +13 -2
  196. package/src/daemon/conversation-agent-loop-handlers.ts +54 -8
  197. package/src/daemon/conversation-agent-loop.ts +127 -20
  198. package/src/daemon/conversation-attachments.ts +18 -36
  199. package/src/daemon/conversation-error.ts +2 -1
  200. package/src/daemon/conversation-history.ts +18 -4
  201. package/src/daemon/conversation-lifecycle.ts +50 -16
  202. package/src/daemon/conversation-messaging.ts +70 -26
  203. package/src/daemon/conversation-process.ts +58 -34
  204. package/src/daemon/conversation-runtime-assembly.ts +22 -38
  205. package/src/daemon/conversation-slash.ts +121 -256
  206. package/src/daemon/conversation-surfaces.ts +170 -24
  207. package/src/daemon/conversation-tool-setup.ts +0 -6
  208. package/src/daemon/conversation-workspace.ts +21 -1
  209. package/src/daemon/conversation.ts +69 -30
  210. package/src/daemon/first-greeting.ts +35 -0
  211. package/src/daemon/handlers/config-embeddings.ts +156 -0
  212. package/src/daemon/handlers/config-model.ts +62 -26
  213. package/src/daemon/handlers/conversations.ts +0 -23
  214. package/src/daemon/handlers/identity.ts +12 -1
  215. package/src/daemon/handlers/recording.ts +26 -21
  216. package/src/daemon/host-cu-proxy.ts +2 -2
  217. package/src/daemon/lifecycle.ts +115 -65
  218. package/src/daemon/message-protocol.ts +3 -0
  219. package/src/daemon/message-types/conversations.ts +18 -0
  220. package/src/daemon/message-types/messages.ts +1 -0
  221. package/src/daemon/message-types/shared.ts +2 -0
  222. package/src/daemon/message-types/surfaces.ts +2 -0
  223. package/src/daemon/message-types/upgrades.ts +23 -0
  224. package/src/daemon/server.ts +83 -12
  225. package/src/daemon/shutdown-handlers.ts +8 -5
  226. package/src/daemon/startup-error.ts +9 -0
  227. package/src/daemon/tool-side-effects.ts +11 -28
  228. package/src/events/tool-permission-telemetry-listener.ts +1 -3
  229. package/src/followups/followup-store.ts +47 -1
  230. package/src/instrument.ts +0 -4
  231. package/src/media/app-icon-generator.ts +2 -2
  232. package/src/memory/app-git-service.ts +28 -16
  233. package/src/memory/app-store.ts +230 -41
  234. package/src/memory/archive-store.ts +400 -0
  235. package/src/memory/attachments-store.ts +558 -130
  236. package/src/memory/brief-formatting.ts +33 -0
  237. package/src/memory/brief-open-loops.ts +266 -0
  238. package/src/memory/brief-time.ts +161 -0
  239. package/src/memory/brief.ts +75 -0
  240. package/src/memory/conversation-attention-store.ts +70 -0
  241. package/src/memory/conversation-crud.ts +591 -8
  242. package/src/memory/conversation-directories.ts +125 -0
  243. package/src/memory/conversation-disk-view.ts +390 -0
  244. package/src/memory/conversation-key-store.ts +17 -5
  245. package/src/memory/conversation-queries.ts +5 -1
  246. package/src/memory/conversation-title-service.ts +21 -49
  247. package/src/memory/db-init.ts +40 -0
  248. package/src/memory/embedding-backend.ts +42 -53
  249. package/src/memory/embedding-gemini.test.ts +4 -4
  250. package/src/memory/embedding-local.ts +1 -3
  251. package/src/memory/embedding-ollama.ts +1 -3
  252. package/src/memory/embedding-openai.ts +1 -3
  253. package/src/memory/indexer.ts +114 -21
  254. package/src/memory/items-extractor.ts +42 -13
  255. package/src/memory/job-handlers/conversation-starters.ts +6 -1
  256. package/src/memory/job-handlers/embedding.test.ts +2 -4
  257. package/src/memory/job-handlers/embedding.ts +83 -0
  258. package/src/memory/job-utils.ts +1 -1
  259. package/src/memory/jobs-store.ts +6 -0
  260. package/src/memory/jobs-worker.ts +12 -0
  261. package/src/memory/llm-request-log-store.ts +100 -1
  262. package/src/memory/migrations/102-alter-table-columns.ts +5 -0
  263. package/src/memory/migrations/146-schedule-oneshot-routing.ts +3 -3
  264. package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +66 -70
  265. package/src/memory/migrations/148-drop-reminders-table.ts +5 -9
  266. package/src/memory/migrations/160-drop-loopback-port-column.ts +1 -3
  267. package/src/memory/migrations/174-rename-thread-starters-table.ts +0 -7
  268. package/src/memory/migrations/178-oauth-providers-managed-service-config-key.ts +15 -0
  269. package/src/memory/migrations/179-llm-request-log-message-id.ts +16 -0
  270. package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +66 -0
  271. package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +46 -0
  272. package/src/memory/migrations/182-oauth-providers-display-metadata.ts +20 -0
  273. package/src/memory/migrations/183-add-conversation-fork-lineage.ts +22 -0
  274. package/src/memory/migrations/184-llm-request-log-provider.ts +12 -0
  275. package/src/memory/migrations/185-memory-brief-state.ts +52 -0
  276. package/src/memory/migrations/186-memory-archive.ts +109 -0
  277. package/src/memory/migrations/187-memory-reducer-checkpoints.ts +19 -0
  278. package/src/memory/migrations/index.ts +10 -0
  279. package/src/memory/migrations/registry.ts +13 -0
  280. package/src/memory/qdrant-client.ts +23 -4
  281. package/src/memory/reducer-store.ts +271 -0
  282. package/src/memory/reducer-types.ts +99 -0
  283. package/src/memory/reducer.ts +453 -0
  284. package/src/memory/retriever.test.ts +601 -2
  285. package/src/memory/retriever.ts +85 -9
  286. package/src/memory/schema/conversations.ts +9 -0
  287. package/src/memory/schema/index.ts +2 -0
  288. package/src/memory/schema/infrastructure.ts +13 -7
  289. package/src/memory/schema/memory-archive.ts +121 -0
  290. package/src/memory/schema/memory-brief.ts +55 -0
  291. package/src/memory/schema/oauth.ts +6 -0
  292. package/src/memory/search/semantic.ts +17 -4
  293. package/src/messaging/providers/gmail/mime-builder.ts +3 -1
  294. package/src/notifications/copy-composer.ts +26 -0
  295. package/src/notifications/decision-engine.ts +14 -1
  296. package/src/notifications/emit-signal.ts +1 -1
  297. package/src/notifications/signal.ts +36 -0
  298. package/src/oauth/byo-connection.test.ts +1 -45
  299. package/src/oauth/byo-connection.ts +2 -8
  300. package/src/oauth/connect-orchestrator.ts +15 -11
  301. package/src/oauth/connection-resolver.test.ts +191 -0
  302. package/src/oauth/connection-resolver.ts +66 -38
  303. package/src/oauth/connection.ts +0 -1
  304. package/src/oauth/oauth-store.ts +99 -47
  305. package/src/oauth/platform-connection.test.ts +0 -1
  306. package/src/oauth/platform-connection.ts +11 -3
  307. package/src/oauth/seed-providers.ts +78 -3
  308. package/src/oauth/token-persistence.ts +16 -10
  309. package/src/permissions/checker.ts +160 -14
  310. package/src/permissions/defaults.ts +14 -0
  311. package/src/prompts/templates/BOOTSTRAP.md +2 -0
  312. package/src/providers/anthropic/client.ts +8 -1
  313. package/src/providers/failover.ts +4 -1
  314. package/src/providers/gemini/client.ts +50 -0
  315. package/src/providers/model-catalog.ts +92 -0
  316. package/src/providers/model-intents.ts +29 -20
  317. package/src/providers/openai/client.ts +49 -0
  318. package/src/providers/types.ts +2 -0
  319. package/src/runtime/access-request-helper.ts +16 -7
  320. package/src/runtime/auth/credential-service.ts +3 -1
  321. package/src/runtime/auth/route-policy.ts +14 -1
  322. package/src/runtime/btw-sidechain.ts +101 -0
  323. package/src/runtime/channel-reply-delivery.ts +17 -1
  324. package/src/runtime/http-router.ts +3 -1
  325. package/src/runtime/http-server.ts +196 -141
  326. package/src/runtime/http-types.ts +1 -0
  327. package/src/runtime/migrations/vbundle-builder.ts +5 -1
  328. package/src/runtime/routes/access-request-decision.ts +41 -0
  329. package/src/runtime/routes/app-management-routes.ts +6 -3
  330. package/src/runtime/routes/app-routes.ts +7 -3
  331. package/src/runtime/routes/approval-routes.ts +1 -0
  332. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +34 -2
  333. package/src/runtime/routes/attachment-routes.ts +45 -15
  334. package/src/runtime/routes/btw-routes.ts +21 -61
  335. package/src/runtime/routes/conversation-management-routes.ts +74 -0
  336. package/src/runtime/routes/conversation-query-routes.ts +187 -10
  337. package/src/runtime/routes/conversation-routes.ts +269 -28
  338. package/src/runtime/routes/conversation-starter-routes.ts +9 -11
  339. package/src/runtime/routes/diagnostics-routes.ts +1 -0
  340. package/src/runtime/routes/identity-routes.ts +2 -35
  341. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -2
  342. package/src/runtime/routes/llm-context-normalization.ts +1212 -0
  343. package/src/runtime/routes/log-export-routes.ts +3 -0
  344. package/src/runtime/routes/memory-item-routes.test.ts +34 -0
  345. package/src/runtime/routes/memory-item-routes.ts +94 -5
  346. package/src/runtime/routes/migration-routes.ts +4 -1
  347. package/src/runtime/routes/oauth-apps.ts +291 -0
  348. package/src/runtime/routes/secret-routes.ts +30 -1
  349. package/src/runtime/routes/settings-routes.ts +14 -0
  350. package/src/runtime/routes/surface-action-routes.ts +68 -1
  351. package/src/runtime/routes/trace-event-routes.ts +4 -1
  352. package/src/schedule/schedule-store.ts +30 -21
  353. package/src/security/secure-keys.ts +21 -0
  354. package/src/signals/bash.ts +1 -1
  355. package/src/skills/inline-command-expansions.ts +204 -0
  356. package/src/skills/inline-command-render.ts +127 -0
  357. package/src/skills/inline-command-runner.ts +242 -0
  358. package/src/skills/transitive-version-hash.ts +88 -0
  359. package/src/swarm/backend-claude-code.ts +3 -6
  360. package/src/tasks/task-store.ts +43 -1
  361. package/src/telemetry/usage-telemetry-reporter.test.ts +3 -2
  362. package/src/telemetry/usage-telemetry-reporter.ts +3 -1
  363. package/src/tools/AGENTS.md +6 -10
  364. package/src/tools/apps/executors.ts +17 -232
  365. package/src/tools/claude-code/claude-code.ts +2 -3
  366. package/src/tools/credentials/vault.ts +7 -12
  367. package/src/tools/host-filesystem/read.ts +13 -10
  368. package/src/tools/network/__tests__/web-search.test.ts +4 -2
  369. package/src/tools/permission-checker.ts +8 -1
  370. package/src/tools/schedule/list.ts +2 -7
  371. package/src/tools/schema-transforms.ts +5 -0
  372. package/src/tools/shared/filesystem/format-diff.ts +2 -7
  373. package/src/tools/skills/execute.ts +1 -1
  374. package/src/tools/skills/load.ts +140 -6
  375. package/src/tools/tool-manifest.ts +0 -6
  376. package/src/tools/ui-surface/definitions.ts +2 -2
  377. package/src/util/device-id.ts +28 -5
  378. package/src/util/platform.ts +24 -0
  379. package/src/util/pricing.ts +1 -0
  380. package/src/util/retry.ts +1 -3
  381. package/src/workspace/migrations/003-seed-device-id.ts +3 -4
  382. package/src/workspace/migrations/006-services-config.ts +5 -0
  383. package/src/workspace/migrations/008-voice-timeout-and-max-steps.ts +12 -0
  384. package/src/workspace/migrations/009-backfill-conversation-disk-view.ts +10 -0
  385. package/src/workspace/migrations/010-app-dir-rename.ts +223 -0
  386. package/src/workspace/migrations/{002-backfill-installation-id.ts → 011-backfill-installation-id.ts} +24 -13
  387. package/src/workspace/migrations/012-rename-conversation-disk-view-dirs.ts +64 -0
  388. package/src/workspace/migrations/013-repair-conversation-disk-view.ts +11 -0
  389. package/src/workspace/migrations/rebuild-conversation-disk-view.ts +186 -0
  390. package/src/workspace/migrations/registry.ts +11 -1
  391. package/src/workspace/top-level-renderer.ts +12 -0
  392. package/src/__tests__/asset-materialize-tool.test.ts +0 -523
  393. package/src/__tests__/asset-search-tool.test.ts +0 -536
  394. package/src/__tests__/fixtures/media-reuse-fixtures.ts +0 -56
  395. package/src/__tests__/media-reuse-story.e2e.test.ts +0 -762
  396. package/src/__tests__/media-visibility-policy.test.ts +0 -190
  397. package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +0 -14
  398. package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +0 -13
  399. package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +0 -21
  400. package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +0 -14
  401. package/src/config/bundled-skills/app-builder/tools/app-list.ts +0 -13
  402. package/src/config/bundled-skills/app-builder/tools/app-update.ts +0 -23
  403. package/src/daemon/media-visibility-policy.ts +0 -59
  404. package/src/tools/assets/materialize.ts +0 -248
  405. package/src/tools/assets/search.ts +0 -400
@@ -0,0 +1,242 @@
1
+ /**
2
+ * Sandbox-only runner for inline command expansions (`!\`command\``).
3
+ *
4
+ * Executes the literal command string in the sandbox without going through the
5
+ * general `bash` tool's permission path. Security constraints:
6
+ *
7
+ * - Network mode forced off (no outbound connections)
8
+ * - Sanitized environment variables only (no API keys, tokens, credentials)
9
+ * - No credential proxy, no CES client, no host fallback
10
+ * - Uses the conversation working directory as `cwd` so repo-local commands
11
+ * remain interoperable with externally authored skills that expect project
12
+ * context.
13
+ *
14
+ * Output handling:
15
+ * - Captures stdout only (stderr is discarded)
16
+ * - Strips ANSI escape sequences
17
+ * - Rejects binary-ish output
18
+ * - Clamps output to a fixed cap
19
+ * - Returns deterministic sanitized error results for timeout, non-zero exit,
20
+ * or spawn failures (no raw stderr dumps)
21
+ */
22
+
23
+ import { spawn } from "node:child_process";
24
+
25
+ import { getConfig } from "../config/loader.js";
26
+ import { buildSanitizedEnv } from "../tools/terminal/safe-env.js";
27
+ import { wrapCommand } from "../tools/terminal/sandbox.js";
28
+ import { getLogger } from "../util/logger.js";
29
+
30
+ const log = getLogger("inline-command-runner");
31
+
32
+ // ─── Constants ───────────────────────────────────────────────────────────────
33
+
34
+ /** Maximum wall-clock time for an inline command before it is killed. */
35
+ const DEFAULT_TIMEOUT_MS = 10_000;
36
+
37
+ /** Maximum output characters before truncation. */
38
+ const MAX_OUTPUT_CHARS = 20_000;
39
+
40
+ /**
41
+ * ANSI escape sequence pattern (covers SGR, cursor movement, erase, etc.).
42
+ * Matches: ESC[ ... final_byte and ESC] ... ST (OSC sequences).
43
+ */
44
+ const ANSI_RE = /\x1b\[[0-9;]*[A-Za-z]|\x1b\][^\x07]*(?:\x07|\x1b\\)/g;
45
+
46
+ /**
47
+ * Heuristic for binary output: if more than 10% of the characters are
48
+ * non-printable (control chars excluding \t, \n, \r) then reject.
49
+ */
50
+ const BINARY_THRESHOLD = 0.1;
51
+
52
+ // ─── Result type ─────────────────────────────────────────────────────────────
53
+
54
+ /** Deterministic result shape returned by the inline command runner. */
55
+ export interface InlineCommandResult {
56
+ /** The sanitized stdout output, or a human-readable error description. */
57
+ output: string;
58
+ /** Whether the command completed successfully. */
59
+ ok: boolean;
60
+ /**
61
+ * Machine-readable failure reason.
62
+ * - `"timeout"` — command exceeded the wall-clock limit
63
+ * - `"non_zero_exit"` — command exited with a non-zero code
64
+ * - `"binary_output"` — stdout contained binary-ish data
65
+ * - `"spawn_failure"` — the subprocess could not be spawned
66
+ * - `undefined` — success
67
+ */
68
+ failureReason?:
69
+ | "timeout"
70
+ | "non_zero_exit"
71
+ | "binary_output"
72
+ | "spawn_failure";
73
+ }
74
+
75
+ // ─── Public API ──────────────────────────────────────────────────────────────
76
+
77
+ export interface InlineCommandRunnerOptions {
78
+ /** Override the default timeout (ms). */
79
+ timeoutMs?: number;
80
+ /** Override the default output cap (chars). */
81
+ maxOutputChars?: number;
82
+ }
83
+
84
+ /**
85
+ * Run an inline command expansion in the sandbox.
86
+ *
87
+ * @param command The literal command string from the `!\`...\`` token.
88
+ * @param workingDir The conversation's working directory (repo root).
89
+ * @param options Optional overrides for timeout and output cap.
90
+ */
91
+ export async function runInlineCommand(
92
+ command: string,
93
+ workingDir: string,
94
+ options?: InlineCommandRunnerOptions,
95
+ ): Promise<InlineCommandResult> {
96
+ const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
97
+ const maxChars = options?.maxOutputChars ?? MAX_OUTPUT_CHARS;
98
+
99
+ // Build sandbox-wrapped command. Always use the sandbox config with
100
+ // network forced off — inline commands never need network access.
101
+ const config = getConfig();
102
+ const sandboxConfig = { ...config.sandbox, enabled: true };
103
+
104
+ const wrapped = wrapCommand(command, workingDir, sandboxConfig, {
105
+ networkMode: "off",
106
+ });
107
+
108
+ // Build a minimal, sanitized environment. Explicitly exclude gateway URL,
109
+ // workspace dir, and data dir since inline commands have no business calling
110
+ // internal APIs, mutating workspace state, or accessing instance-scoped data.
111
+ const env = buildSanitizedEnv();
112
+ delete env.INTERNAL_GATEWAY_BASE_URL;
113
+ delete env.VELLUM_WORKSPACE_DIR;
114
+ delete env.VELLUM_DATA_DIR;
115
+
116
+ return new Promise<InlineCommandResult>((resolve) => {
117
+ let timedOut = false;
118
+ const stdoutChunks: Buffer[] = [];
119
+
120
+ let child: ReturnType<typeof spawn>;
121
+ try {
122
+ child = spawn(wrapped.command, wrapped.args, {
123
+ cwd: workingDir,
124
+ env,
125
+ stdio: ["ignore", "pipe", "ignore"],
126
+ });
127
+ } catch (err) {
128
+ const message = err instanceof Error ? err.message : String(err);
129
+ log.warn({ command, error: message }, "Failed to spawn inline command");
130
+ resolve({
131
+ output: "Inline command could not be started.",
132
+ ok: false,
133
+ failureReason: "spawn_failure",
134
+ });
135
+ return;
136
+ }
137
+
138
+ const timer = setTimeout(() => {
139
+ timedOut = true;
140
+ child.kill("SIGKILL");
141
+ }, timeoutMs);
142
+
143
+ child.stdout!.on("data", (data: Buffer) => stdoutChunks.push(data));
144
+
145
+ child.on("close", (code) => {
146
+ clearTimeout(timer);
147
+
148
+ // ── Timeout ──────────────────────────────────────────────────────
149
+ if (timedOut) {
150
+ log.debug({ command, timeoutMs }, "Inline command timed out");
151
+ resolve({
152
+ output: `Inline command timed out after ${timeoutMs}ms.`,
153
+ ok: false,
154
+ failureReason: "timeout",
155
+ });
156
+ return;
157
+ }
158
+
159
+ // ── Non-zero exit ────────────────────────────────────────────────
160
+ if (code !== 0) {
161
+ log.debug(
162
+ { command, exitCode: code },
163
+ "Inline command exited with non-zero code",
164
+ );
165
+ resolve({
166
+ output: `Inline command failed (exit code ${code}).`,
167
+ ok: false,
168
+ failureReason: "non_zero_exit",
169
+ });
170
+ return;
171
+ }
172
+
173
+ // ── Process stdout ───────────────────────────────────────────────
174
+ const raw = Buffer.concat(stdoutChunks).toString("utf-8");
175
+
176
+ // Strip ANSI sequences first — these are terminal artifacts, not
177
+ // binary data. Stripping before the binary check prevents legitimate
178
+ // color-coded tool output from being rejected.
179
+ let cleaned = raw.replace(ANSI_RE, "");
180
+
181
+ // Reject binary-ish output (after ANSI stripping)
182
+ if (isBinaryish(cleaned)) {
183
+ log.debug({ command }, "Inline command produced binary-ish output");
184
+ resolve({
185
+ output: "Inline command produced binary output.",
186
+ ok: false,
187
+ failureReason: "binary_output",
188
+ });
189
+ return;
190
+ }
191
+
192
+ // Clamp to max output
193
+ if (cleaned.length > maxChars) {
194
+ cleaned = cleaned.slice(0, maxChars) + "\n[output truncated]";
195
+ }
196
+
197
+ // Trim trailing whitespace
198
+ cleaned = cleaned.trimEnd();
199
+
200
+ resolve({
201
+ output: cleaned,
202
+ ok: true,
203
+ });
204
+ });
205
+
206
+ child.on("error", (err) => {
207
+ clearTimeout(timer);
208
+ log.warn({ command, error: err.message }, "Inline command spawn error");
209
+ resolve({
210
+ output: "Inline command could not be started.",
211
+ ok: false,
212
+ failureReason: "spawn_failure",
213
+ });
214
+ });
215
+ });
216
+ }
217
+
218
+ // ─── Helpers ─────────────────────────────────────────────────────────────────
219
+
220
+ /**
221
+ * Heuristic check for binary output. Returns true if more than
222
+ * {@link BINARY_THRESHOLD} of the characters are non-printable control
223
+ * characters (excluding tab, newline, carriage return).
224
+ */
225
+ function isBinaryish(text: string): boolean {
226
+ if (text.length === 0) return false;
227
+
228
+ let controlCount = 0;
229
+ for (let i = 0; i < text.length; i++) {
230
+ const code = text.charCodeAt(i);
231
+ // Control characters: 0x00-0x1F (excluding \t=0x09, \n=0x0A, \r=0x0D)
232
+ // and 0x7F (DEL)
233
+ if (
234
+ (code <= 0x1f && code !== 0x09 && code !== 0x0a && code !== 0x0d) ||
235
+ code === 0x7f
236
+ ) {
237
+ controlCount++;
238
+ }
239
+ }
240
+
241
+ return controlCount / text.length > BINARY_THRESHOLD;
242
+ }
@@ -0,0 +1,88 @@
1
+ import { createHash } from "node:crypto";
2
+
3
+ import type { SkillSummary } from "../config/skills.js";
4
+ import { validateIncludes } from "./include-graph.js";
5
+ import { computeSkillVersionHash } from "./version-hash.js";
6
+
7
+ /**
8
+ * Error thrown when the include graph is invalid (missing nodes or cycles).
9
+ * The permission layer depends on exact approval candidates, so we fail closed
10
+ * rather than returning a partial or potentially misleading hash.
11
+ */
12
+ export class TransitiveHashError extends Error {
13
+ constructor(
14
+ message: string,
15
+ public readonly code: "missing" | "cycle",
16
+ ) {
17
+ super(message);
18
+ this.name = "TransitiveHashError";
19
+ }
20
+ }
21
+
22
+ /**
23
+ * Compute a transitive version hash for a skill and all its included children.
24
+ *
25
+ * The hash covers:
26
+ * 1. The DFS-ordered list of visited skill IDs (so the graph structure matters)
27
+ * 2. Each visited skill's directory hash (via `computeSkillVersionHash`)
28
+ *
29
+ * This means editing any included child skill invalidates the parent's
30
+ * transitive hash, which is required for version-pinned inline-command
31
+ * approval.
32
+ *
33
+ * Fails closed (throws `TransitiveHashError`) when:
34
+ * - A child referenced in `includes` is missing from the catalog index
35
+ * - The include graph contains a cycle
36
+ *
37
+ * @param rootSkillId The skill ID to start traversal from.
38
+ * @param catalogIndex A `Map<skillId, SkillSummary>` built via `indexCatalogById`.
39
+ * @returns A canonical hash string in the format `tv1:<hex-sha256>`.
40
+ */
41
+ export function computeTransitiveSkillVersionHash(
42
+ rootSkillId: string,
43
+ catalogIndex: Map<string, SkillSummary>,
44
+ ): string {
45
+ // Validate the include graph first — fail closed on any issue.
46
+ const validation = validateIncludes(rootSkillId, catalogIndex);
47
+
48
+ if (!validation.ok) {
49
+ if (validation.error === "cycle") {
50
+ throw new TransitiveHashError(
51
+ `Cycle detected in include graph: ${validation.cyclePath.join(" -> ")}`,
52
+ "cycle",
53
+ );
54
+ }
55
+ // validation.error === "missing"
56
+ throw new TransitiveHashError(
57
+ `Missing child skill "${validation.missingChildId}" referenced by "${validation.parentId}" (path: ${validation.path.join(" -> ")})`,
58
+ "missing",
59
+ );
60
+ }
61
+
62
+ // validation.ok === true, so visited contains all skill IDs in DFS pre-order.
63
+ const { visited } = validation;
64
+
65
+ const hash = createHash("sha256");
66
+
67
+ for (const skillId of visited) {
68
+ // Fold the skill ID into the digest so graph structure matters.
69
+ hash.update(skillId);
70
+ hash.update("\0");
71
+
72
+ const skill = catalogIndex.get(skillId);
73
+ if (!skill) {
74
+ // Should be unreachable after validateIncludes succeeds, but fail closed.
75
+ throw new TransitiveHashError(
76
+ `Skill "${skillId}" disappeared from catalog index after validation`,
77
+ "missing",
78
+ );
79
+ }
80
+
81
+ // Fold the per-directory content hash so file changes propagate.
82
+ const dirHash = computeSkillVersionHash(skill.directoryPath);
83
+ hash.update(dirHash);
84
+ hash.update("\n");
85
+ }
86
+
87
+ return `tv1:${hash.digest("hex")}`;
88
+ }
@@ -7,7 +7,7 @@
7
7
 
8
8
  import { resolveModelIntent } from "../providers/model-intents.js";
9
9
  import type { ModelIntent } from "../providers/types.js";
10
- import { getSecureKeyAsync } from "../security/secure-keys.js";
10
+ import { getProviderKeyAsync } from "../security/secure-keys.js";
11
11
  import { getLogger } from "../util/logger.js";
12
12
  import type {
13
13
  SwarmWorkerBackend,
@@ -29,8 +29,7 @@ export function createClaudeCodeBackend(): SwarmWorkerBackend {
29
29
  name: "claude_code",
30
30
 
31
31
  async isAvailable(): Promise<boolean> {
32
- const apiKey =
33
- (await getSecureKeyAsync("anthropic")) ?? process.env.ANTHROPIC_API_KEY;
32
+ const apiKey = await getProviderKeyAsync("anthropic");
34
33
  return !!apiKey;
35
34
  },
36
35
 
@@ -39,9 +38,7 @@ export function createClaudeCodeBackend(): SwarmWorkerBackend {
39
38
  const stderrLines: string[] = [];
40
39
  try {
41
40
  const { query } = await import("@anthropic-ai/claude-agent-sdk");
42
- const apiKey =
43
- (await getSecureKeyAsync("anthropic")) ??
44
- process.env.ANTHROPIC_API_KEY;
41
+ const apiKey = await getProviderKeyAsync("anthropic");
45
42
  if (!apiKey) {
46
43
  return {
47
44
  success: false,
@@ -1,4 +1,4 @@
1
- import { desc, eq, inArray } from "drizzle-orm";
1
+ import { asc, desc, eq, inArray, or } from "drizzle-orm";
2
2
 
3
3
  import { getDb } from "../memory/db.js";
4
4
  import { taskRuns, tasks, workItems } from "../memory/schema.js";
@@ -139,3 +139,45 @@ export function getTaskRun(id: string): TaskRun | undefined {
139
139
  const db = getDb();
140
140
  return db.select().from(taskRuns).where(eq(taskRuns.id, id)).get();
141
141
  }
142
+
143
+ // ── Brief Helpers ─────────────────────────────────────────────────────
144
+
145
+ /**
146
+ * Lightweight read-only projection of a work item used by the brief compiler.
147
+ * Avoids pulling the full WorkItem type with all its tool/approval fields.
148
+ */
149
+ export interface ActionableWorkItem {
150
+ id: string;
151
+ taskId: string;
152
+ title: string;
153
+ status: string;
154
+ priorityTier: number;
155
+ updatedAt: number;
156
+ }
157
+
158
+ /**
159
+ * Return actionable work items — those that are queued, running, or
160
+ * awaiting review. Ordered by priority (high first) then most-recently-updated.
161
+ */
162
+ export function getActionableWorkItems(): ActionableWorkItem[] {
163
+ const db = getDb();
164
+ return db
165
+ .select({
166
+ id: workItems.id,
167
+ taskId: workItems.taskId,
168
+ title: workItems.title,
169
+ status: workItems.status,
170
+ priorityTier: workItems.priorityTier,
171
+ updatedAt: workItems.updatedAt,
172
+ })
173
+ .from(workItems)
174
+ .where(
175
+ or(
176
+ eq(workItems.status, "queued"),
177
+ eq(workItems.status, "running"),
178
+ eq(workItems.status, "awaiting_review"),
179
+ ),
180
+ )
181
+ .orderBy(asc(workItems.priorityTier), desc(workItems.updatedAt))
182
+ .all();
183
+ }
@@ -97,6 +97,7 @@ mock.module("../version.js", () => ({
97
97
  // Production import (after mocks)
98
98
  // ---------------------------------------------------------------------------
99
99
 
100
+ import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
100
101
  import type { UsageEvent } from "../usage/types.js";
101
102
  import { UsageTelemetryReporter } from "./usage-telemetry-reporter.js";
102
103
 
@@ -434,7 +435,7 @@ describe("UsageTelemetryReporter", () => {
434
435
  expect(body.user_id).toBeUndefined();
435
436
  });
436
437
 
437
- test("assistant_id falls back to 'self' when getExternalAssistantId returns undefined", async () => {
438
+ test("assistant_id falls back to DAEMON_INTERNAL_ASSISTANT_ID when getExternalAssistantId returns undefined", async () => {
438
439
  mockGetExternalAssistantId.mockReturnValue(undefined);
439
440
  const events = [makeUsageEvent()];
440
441
  mockQueryUnreportedUsageEvents.mockReturnValue(events);
@@ -450,7 +451,7 @@ describe("UsageTelemetryReporter", () => {
450
451
  (mockFetch.mock.calls[0] as [string, RequestInit])[1].body as string,
451
452
  );
452
453
  expect(body.installation_id).toBe("test-device-id");
453
- expect(body.assistant_id).toBe("self");
454
+ expect(body.assistant_id).toBe(DAEMON_INTERNAL_ASSISTANT_ID);
454
455
  });
455
456
 
456
457
  test("turn events are included in the events array with type discriminator", async () => {
@@ -23,6 +23,7 @@ import { queryUnreportedLifecycleEvents } from "../memory/lifecycle-events-store
23
23
  import { queryUnreportedUsageEvents } from "../memory/llm-usage-store.js";
24
24
  import { queryUnreportedTurnEvents } from "../memory/turn-events-store.js";
25
25
  import { resolveManagedProxyContext } from "../providers/managed-proxy/context.js";
26
+ import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
26
27
  import { getExternalAssistantId } from "../runtime/auth/external-assistant-id.js";
27
28
  import { getDeviceId } from "../util/device-id.js";
28
29
  import { getLogger } from "../util/logger.js";
@@ -187,7 +188,8 @@ export class UsageTelemetryReporter {
187
188
  ),
188
189
  ];
189
190
 
190
- const assistantId = getExternalAssistantId() ?? "self";
191
+ const assistantId =
192
+ getExternalAssistantId() ?? DAEMON_INTERNAL_ASSISTANT_ID;
191
193
  const organizationId = getPlatformOrganizationId() || undefined;
192
194
  const userId = getPlatformUserId() || undefined;
193
195
  const payload = {
@@ -1,18 +1,14 @@
1
1
  # Tools - Agent Instructions
2
2
 
3
- ## No New Tools Policy
3
+ ## New Non-Skill Tools Are Strongly Discouraged
4
4
 
5
- **New tool registrations require approval from Team Jarvis.**
5
+ **Prefer skills over new non-skill tool registrations.** Non-skill tools require approval from Team Jarvis.
6
6
 
7
- The tool registration system (`class ... implements Tool` + `registerTool()`) is being phased out in favor of skill-based approaches. Before adding a new tool, contact Team Jarvis for approval.
7
+ Skills are the preferred approach for adding new capabilities they are progressively disclosed into context, more portable, and can be iterated on independently. New non-skill tool registrations (`class ... implements Tool` + `registerTool()`) carry additional costs:
8
8
 
9
- ## Why This Policy Exists
9
+ 1. **Context overhead** Each registered tool adds to the system prompt and increases token usage for every conversation.
10
10
 
11
- 1. **Skills are preferred** - The project direction is to teach the assistant CLI tools via skills rather than hardcoding tool implementations. Skills are progressively disclosed into context, are more portable, and are often self-contained.
12
-
13
- 2. **Context overhead** - Each registered tool adds to the system prompt and increases token usage for every conversation.
14
-
15
- 3. **Maintenance burden** - Tools require ongoing maintenance, testing, and security review. Skills can be iterated on independently.
11
+ 2. **Maintenance burden** Tools require ongoing maintenance, testing, and security review.
16
12
 
17
13
  ## What To Do Instead
18
14
 
@@ -26,7 +22,7 @@ Instead of creating a new tool, consider:
26
22
 
27
23
  ## Approved Exception: Credential Execution Service (CES) Tools
28
24
 
29
- The following three CES tools are the only approved exception to the no-new-tools policy:
25
+ The following three CES tools are approved exceptions that justify tool registrations over skills:
30
26
 
31
27
  | Tool | Purpose |
32
28
  | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |