@vauban-org/agent-sdk 1.0.0 → 1.2.0

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 (442) hide show
  1. package/CONTRACT.md +6401 -813
  2. package/dist/adapters/llm/anthropic-direct.d.ts +1 -0
  3. package/dist/adapters/llm/anthropic-direct.d.ts.map +1 -1
  4. package/dist/adapters/llm/anthropic-direct.js +43 -0
  5. package/dist/adapters/llm/anthropic-direct.js.map +1 -1
  6. package/dist/adapters/llm/cascade.d.ts.map +1 -1
  7. package/dist/adapters/llm/cascade.js +57 -14
  8. package/dist/adapters/llm/cascade.js.map +1 -1
  9. package/dist/adapters/llm/litellm.d.ts +2 -0
  10. package/dist/adapters/llm/litellm.d.ts.map +1 -1
  11. package/dist/adapters/llm/litellm.js +44 -0
  12. package/dist/adapters/llm/litellm.js.map +1 -1
  13. package/dist/compute/difficulty-estimator.d.ts +53 -0
  14. package/dist/compute/difficulty-estimator.d.ts.map +1 -0
  15. package/dist/compute/difficulty-estimator.js +82 -0
  16. package/dist/compute/difficulty-estimator.js.map +1 -0
  17. package/dist/compute/strategies/mixture-of-agents.d.ts +40 -0
  18. package/dist/compute/strategies/mixture-of-agents.d.ts.map +1 -0
  19. package/dist/compute/strategies/mixture-of-agents.js +110 -0
  20. package/dist/compute/strategies/mixture-of-agents.js.map +1 -0
  21. package/dist/compute/strategies/tree-of-thoughts.d.ts +48 -0
  22. package/dist/compute/strategies/tree-of-thoughts.d.ts.map +1 -0
  23. package/dist/compute/strategies/tree-of-thoughts.js +242 -0
  24. package/dist/compute/strategies/tree-of-thoughts.js.map +1 -0
  25. package/dist/compute/strategies/two-phase-orient.d.ts +72 -0
  26. package/dist/compute/strategies/two-phase-orient.d.ts.map +1 -0
  27. package/dist/compute/strategies/two-phase-orient.js +85 -0
  28. package/dist/compute/strategies/two-phase-orient.js.map +1 -0
  29. package/dist/constitution/types.d.ts +10 -10
  30. package/dist/container/protocol.d.ts +134 -0
  31. package/dist/container/protocol.d.ts.map +1 -0
  32. package/dist/container/protocol.js +157 -0
  33. package/dist/container/protocol.js.map +1 -0
  34. package/dist/container/runtime.d.ts +140 -0
  35. package/dist/container/runtime.d.ts.map +1 -0
  36. package/dist/container/runtime.js +256 -0
  37. package/dist/container/runtime.js.map +1 -0
  38. package/dist/events/catalogue.d.ts +46 -46
  39. package/dist/events/schemas/agent.completed.v1.d.ts +4 -4
  40. package/dist/events/schemas/agent.failed.v1.d.ts +2 -2
  41. package/dist/events/schemas/agent.hitl_resolved.v1.d.ts +2 -2
  42. package/dist/events/schemas/agent.started.v1.d.ts +2 -2
  43. package/dist/events/schemas/brain.skill.extracted.v1.d.ts +4 -4
  44. package/dist/events/schemas/cc.cost.anomaly_detected.v1.d.ts +2 -2
  45. package/dist/events/schemas/cc.cost.recorded.v1.d.ts +4 -4
  46. package/dist/events/schemas/citadel.sprint.analyzed.v1.d.ts +6 -6
  47. package/dist/events/schemas/citadel.sprint.closed.v1.d.ts +2 -2
  48. package/dist/events/schemas/forge.inbox.reply_classified.v1.d.ts +6 -6
  49. package/dist/events/schemas/forge.lead.qualified.v1.d.ts +2 -2
  50. package/dist/events/schemas/forge.outreach.sent.v1.d.ts +4 -4
  51. package/dist/events/schemas/incident.detected.v1.d.ts +2 -2
  52. package/dist/events/schemas/vauban.goal.checked.v1.d.ts +2 -2
  53. package/dist/events/schemas/vauban.rebalancing.checked.v1.d.ts +2 -2
  54. package/dist/events/schemas/vauban.tax.checked.v1.d.ts +2 -2
  55. package/dist/events/schemas/vauban.vault.analyzed.v1.d.ts +6 -6
  56. package/dist/identity/agent-persona.d.ts +73 -0
  57. package/dist/identity/agent-persona.d.ts.map +1 -0
  58. package/dist/identity/agent-persona.js +165 -0
  59. package/dist/identity/agent-persona.js.map +1 -0
  60. package/dist/identity/persona-prompt.d.ts +25 -0
  61. package/dist/identity/persona-prompt.d.ts.map +1 -0
  62. package/dist/identity/persona-prompt.js +71 -0
  63. package/dist/identity/persona-prompt.js.map +1 -0
  64. package/dist/identity/persona-schema.d.ts +120 -0
  65. package/dist/identity/persona-schema.d.ts.map +1 -0
  66. package/dist/identity/persona-schema.js +103 -0
  67. package/dist/identity/persona-schema.js.map +1 -0
  68. package/dist/index.d.ts +37 -2
  69. package/dist/index.d.ts.map +1 -1
  70. package/dist/index.js +29 -1
  71. package/dist/index.js.map +1 -1
  72. package/dist/loop/minimal-loop.js +293 -287
  73. package/dist/memory/episodic-rrf.d.ts +114 -0
  74. package/dist/memory/episodic-rrf.d.ts.map +1 -0
  75. package/dist/memory/episodic-rrf.js +148 -0
  76. package/dist/memory/episodic-rrf.js.map +1 -0
  77. package/dist/mesh/attenuation.d.ts +78 -0
  78. package/dist/mesh/attenuation.d.ts.map +1 -0
  79. package/dist/mesh/attenuation.js +141 -0
  80. package/dist/mesh/attenuation.js.map +1 -0
  81. package/dist/mesh/delegate.d.ts +96 -0
  82. package/dist/mesh/delegate.d.ts.map +1 -0
  83. package/dist/mesh/delegate.js +172 -0
  84. package/dist/mesh/delegate.js.map +1 -0
  85. package/dist/mesh/dispatcher.d.ts +119 -0
  86. package/dist/mesh/dispatcher.d.ts.map +1 -0
  87. package/dist/mesh/dispatcher.js +207 -0
  88. package/dist/mesh/dispatcher.js.map +1 -0
  89. package/dist/mesh/index.d.ts +12 -0
  90. package/dist/mesh/index.d.ts.map +1 -0
  91. package/dist/mesh/index.js +11 -0
  92. package/dist/mesh/index.js.map +1 -0
  93. package/dist/mesh/types.d.ts +30 -0
  94. package/dist/mesh/types.d.ts.map +1 -0
  95. package/dist/mesh/types.js +11 -0
  96. package/dist/mesh/types.js.map +1 -0
  97. package/dist/orchestration/ooda/skills.d.ts +104 -0
  98. package/dist/orchestration/ooda/skills.d.ts.map +1 -1
  99. package/dist/orchestration/ooda/skills.js +106 -0
  100. package/dist/orchestration/ooda/skills.js.map +1 -1
  101. package/dist/ports/bastion-action.contract.test.d.ts +11 -0
  102. package/dist/ports/bastion-action.contract.test.d.ts.map +1 -0
  103. package/dist/ports/bastion-action.contract.test.js +238 -0
  104. package/dist/ports/bastion-action.contract.test.js.map +1 -0
  105. package/dist/ports/bastion-action.d.ts +133 -0
  106. package/dist/ports/bastion-action.d.ts.map +1 -0
  107. package/dist/ports/bastion-action.js +73 -0
  108. package/dist/ports/bastion-action.js.map +1 -0
  109. package/dist/ports/brain.d.ts +31 -0
  110. package/dist/ports/brain.d.ts.map +1 -1
  111. package/dist/ports/brain.js +115 -1
  112. package/dist/ports/brain.js.map +1 -1
  113. package/dist/ports/citadel-action.contract.test.d.ts +11 -0
  114. package/dist/ports/citadel-action.contract.test.d.ts.map +1 -0
  115. package/dist/ports/citadel-action.contract.test.js +317 -0
  116. package/dist/ports/citadel-action.contract.test.js.map +1 -0
  117. package/dist/ports/citadel-action.d.ts +111 -0
  118. package/dist/ports/citadel-action.d.ts.map +1 -0
  119. package/dist/ports/citadel-action.js +62 -0
  120. package/dist/ports/citadel-action.js.map +1 -0
  121. package/dist/ports/compliance-contract.d.ts +123 -0
  122. package/dist/ports/compliance-contract.d.ts.map +1 -0
  123. package/dist/ports/compliance-contract.js +35 -0
  124. package/dist/ports/compliance-contract.js.map +1 -0
  125. package/dist/ports/db.d.ts +38 -0
  126. package/dist/ports/db.d.ts.map +1 -1
  127. package/dist/ports/db.js +88 -1
  128. package/dist/ports/db.js.map +1 -1
  129. package/dist/ports/delegation.contract.test.d.ts +9 -0
  130. package/dist/ports/delegation.contract.test.d.ts.map +1 -0
  131. package/dist/ports/delegation.contract.test.js +337 -0
  132. package/dist/ports/delegation.contract.test.js.map +1 -0
  133. package/dist/ports/delegation.d.ts +134 -0
  134. package/dist/ports/delegation.d.ts.map +1 -0
  135. package/dist/ports/delegation.js +105 -0
  136. package/dist/ports/delegation.js.map +1 -0
  137. package/dist/ports/event-bus.d.ts +29 -0
  138. package/dist/ports/event-bus.d.ts.map +1 -1
  139. package/dist/ports/event-bus.js +106 -1
  140. package/dist/ports/event-bus.js.map +1 -1
  141. package/dist/ports/federation.contract.test.d.ts +9 -0
  142. package/dist/ports/federation.contract.test.d.ts.map +1 -0
  143. package/dist/ports/federation.contract.test.js +279 -0
  144. package/dist/ports/federation.contract.test.js.map +1 -0
  145. package/dist/ports/federation.d.ts +140 -0
  146. package/dist/ports/federation.d.ts.map +1 -0
  147. package/dist/ports/federation.js +57 -0
  148. package/dist/ports/federation.js.map +1 -0
  149. package/dist/ports/index.d.ts +28 -2
  150. package/dist/ports/index.d.ts.map +1 -1
  151. package/dist/ports/index.js +17 -2
  152. package/dist/ports/index.js.map +1 -1
  153. package/dist/ports/llm-provider.d.ts +37 -0
  154. package/dist/ports/llm-provider.d.ts.map +1 -1
  155. package/dist/ports/llm-provider.js +99 -1
  156. package/dist/ports/llm-provider.js.map +1 -1
  157. package/dist/ports/logger.d.ts +27 -0
  158. package/dist/ports/logger.d.ts.map +1 -1
  159. package/dist/ports/logger.js +87 -0
  160. package/dist/ports/logger.js.map +1 -1
  161. package/dist/ports/manifest-registry.contract.test.d.ts +9 -0
  162. package/dist/ports/manifest-registry.contract.test.d.ts.map +1 -0
  163. package/dist/ports/manifest-registry.contract.test.js +246 -0
  164. package/dist/ports/manifest-registry.contract.test.js.map +1 -0
  165. package/dist/ports/manifest-registry.d.ts +116 -0
  166. package/dist/ports/manifest-registry.d.ts.map +1 -0
  167. package/dist/ports/manifest-registry.js +79 -0
  168. package/dist/ports/manifest-registry.js.map +1 -0
  169. package/dist/ports/observability.contract.test.d.ts +12 -0
  170. package/dist/ports/observability.contract.test.d.ts.map +1 -0
  171. package/dist/ports/observability.contract.test.js +260 -0
  172. package/dist/ports/observability.contract.test.js.map +1 -0
  173. package/dist/ports/observability.d.ts +98 -0
  174. package/dist/ports/observability.d.ts.map +1 -0
  175. package/dist/ports/observability.js +59 -0
  176. package/dist/ports/observability.js.map +1 -0
  177. package/dist/ports/outcome.d.ts +26 -0
  178. package/dist/ports/outcome.d.ts.map +1 -1
  179. package/dist/ports/outcome.js +62 -1
  180. package/dist/ports/outcome.js.map +1 -1
  181. package/dist/ports/privacy.contract.test.d.ts +12 -0
  182. package/dist/ports/privacy.contract.test.d.ts.map +1 -0
  183. package/dist/ports/privacy.contract.test.js +325 -0
  184. package/dist/ports/privacy.contract.test.js.map +1 -0
  185. package/dist/ports/privacy.d.ts +132 -0
  186. package/dist/ports/privacy.d.ts.map +1 -0
  187. package/dist/ports/privacy.js +83 -0
  188. package/dist/ports/privacy.js.map +1 -0
  189. package/dist/ports/tenant-context.contract.test.d.ts +14 -0
  190. package/dist/ports/tenant-context.contract.test.d.ts.map +1 -0
  191. package/dist/ports/tenant-context.contract.test.js +352 -0
  192. package/dist/ports/tenant-context.contract.test.js.map +1 -0
  193. package/dist/ports/tenant-context.d.ts +103 -0
  194. package/dist/ports/tenant-context.d.ts.map +1 -0
  195. package/dist/ports/tenant-context.js +48 -0
  196. package/dist/ports/tenant-context.js.map +1 -0
  197. package/dist/ports/vauban-finance-action.contract.test.d.ts +11 -0
  198. package/dist/ports/vauban-finance-action.contract.test.d.ts.map +1 -0
  199. package/dist/ports/vauban-finance-action.contract.test.js +260 -0
  200. package/dist/ports/vauban-finance-action.contract.test.js.map +1 -0
  201. package/dist/ports/vauban-finance-action.d.ts +106 -0
  202. package/dist/ports/vauban-finance-action.d.ts.map +1 -0
  203. package/dist/ports/vauban-finance-action.js +60 -0
  204. package/dist/ports/vauban-finance-action.js.map +1 -0
  205. package/dist/ports/workflow-runtime.d.ts +204 -0
  206. package/dist/ports/workflow-runtime.d.ts.map +1 -0
  207. package/dist/ports/workflow-runtime.js +72 -0
  208. package/dist/ports/workflow-runtime.js.map +1 -0
  209. package/dist/proof/cert-verify.d.ts +80 -0
  210. package/dist/proof/cert-verify.d.ts.map +1 -0
  211. package/dist/proof/cert-verify.js +178 -0
  212. package/dist/proof/cert-verify.js.map +1 -0
  213. package/dist/replay/replay.d.ts.map +1 -1
  214. package/dist/replay/replay.js +5 -1
  215. package/dist/replay/replay.js.map +1 -1
  216. package/dist/retry/index.d.ts +129 -0
  217. package/dist/retry/index.d.ts.map +1 -0
  218. package/dist/retry/index.js +156 -0
  219. package/dist/retry/index.js.map +1 -0
  220. package/dist/retry/presets.d.ts +39 -0
  221. package/dist/retry/presets.d.ts.map +1 -0
  222. package/dist/retry/presets.js +69 -0
  223. package/dist/retry/presets.js.map +1 -0
  224. package/dist/skill-loop/ab-runner.d.ts +67 -0
  225. package/dist/skill-loop/ab-runner.d.ts.map +1 -0
  226. package/dist/skill-loop/ab-runner.js +160 -0
  227. package/dist/skill-loop/ab-runner.js.map +1 -0
  228. package/dist/skill-loop/adoption.d.ts +67 -0
  229. package/dist/skill-loop/adoption.d.ts.map +1 -0
  230. package/dist/skill-loop/adoption.js +126 -0
  231. package/dist/skill-loop/adoption.js.map +1 -0
  232. package/dist/skill-loop/candidate.d.ts +45 -0
  233. package/dist/skill-loop/candidate.d.ts.map +1 -0
  234. package/dist/skill-loop/candidate.js +43 -0
  235. package/dist/skill-loop/candidate.js.map +1 -0
  236. package/dist/skill-loop/evaluator.d.ts +42 -0
  237. package/dist/skill-loop/evaluator.d.ts.map +1 -0
  238. package/dist/skill-loop/evaluator.js +184 -0
  239. package/dist/skill-loop/evaluator.js.map +1 -0
  240. package/dist/skill-loop/index.d.ts +27 -0
  241. package/dist/skill-loop/index.d.ts.map +1 -0
  242. package/dist/skill-loop/index.js +27 -0
  243. package/dist/skill-loop/index.js.map +1 -0
  244. package/dist/skill-loop/reflexion-replay.d.ts +87 -0
  245. package/dist/skill-loop/reflexion-replay.d.ts.map +1 -0
  246. package/dist/skill-loop/reflexion-replay.js +110 -0
  247. package/dist/skill-loop/reflexion-replay.js.map +1 -0
  248. package/dist/skill-loop/sign-off.d.ts +88 -0
  249. package/dist/skill-loop/sign-off.d.ts.map +1 -0
  250. package/dist/skill-loop/sign-off.js +146 -0
  251. package/dist/skill-loop/sign-off.js.map +1 -0
  252. package/dist/skill-loop/value-metric.d.ts +55 -0
  253. package/dist/skill-loop/value-metric.d.ts.map +1 -0
  254. package/dist/skill-loop/value-metric.js +69 -0
  255. package/dist/skill-loop/value-metric.js.map +1 -0
  256. package/dist/skill-loop/versioning.d.ts +36 -0
  257. package/dist/skill-loop/versioning.d.ts.map +1 -0
  258. package/dist/skill-loop/versioning.js +47 -0
  259. package/dist/skill-loop/versioning.js.map +1 -0
  260. package/dist/skill-manifest/anchor.d.ts +91 -0
  261. package/dist/skill-manifest/anchor.d.ts.map +1 -0
  262. package/dist/skill-manifest/anchor.js +331 -0
  263. package/dist/skill-manifest/anchor.js.map +1 -0
  264. package/dist/skill-manifest/builder.d.ts +47 -0
  265. package/dist/skill-manifest/builder.d.ts.map +1 -0
  266. package/dist/skill-manifest/builder.js +93 -0
  267. package/dist/skill-manifest/builder.js.map +1 -0
  268. package/dist/skill-manifest/index.d.ts +13 -0
  269. package/dist/skill-manifest/index.d.ts.map +1 -0
  270. package/dist/skill-manifest/index.js +9 -0
  271. package/dist/skill-manifest/index.js.map +1 -0
  272. package/dist/skill-manifest/types.d.ts +67 -0
  273. package/dist/skill-manifest/types.d.ts.map +1 -0
  274. package/dist/skill-manifest/types.js +16 -0
  275. package/dist/skill-manifest/types.js.map +1 -0
  276. package/dist/skill-manifest/verifier.d.ts +42 -0
  277. package/dist/skill-manifest/verifier.d.ts.map +1 -0
  278. package/dist/skill-manifest/verifier.js +136 -0
  279. package/dist/skill-manifest/verifier.js.map +1 -0
  280. package/dist/skills/brain-query.d.ts +4 -4
  281. package/dist/skills/brain-store.d.ts +6 -6
  282. package/dist/skills/errors.d.ts +15 -0
  283. package/dist/skills/errors.d.ts.map +1 -1
  284. package/dist/skills/errors.js +21 -0
  285. package/dist/skills/errors.js.map +1 -1
  286. package/dist/skills/hitl-request.d.ts +2 -2
  287. package/dist/skills/index.d.ts +3 -1
  288. package/dist/skills/index.d.ts.map +1 -1
  289. package/dist/skills/index.js +4 -1
  290. package/dist/skills/index.js.map +1 -1
  291. package/dist/skills/markdown/loader.d.ts +52 -0
  292. package/dist/skills/markdown/loader.d.ts.map +1 -0
  293. package/dist/skills/markdown/loader.js +93 -0
  294. package/dist/skills/markdown/loader.js.map +1 -0
  295. package/dist/skills/markdown/schema.d.ts +432 -0
  296. package/dist/skills/markdown/schema.d.ts.map +1 -0
  297. package/dist/skills/markdown/schema.js +121 -0
  298. package/dist/skills/markdown/schema.js.map +1 -0
  299. package/dist/skills/poc-md-loader/markdown-loader.d.ts +77 -0
  300. package/dist/skills/poc-md-loader/markdown-loader.d.ts.map +1 -0
  301. package/dist/skills/poc-md-loader/markdown-loader.js +125 -0
  302. package/dist/skills/poc-md-loader/markdown-loader.js.map +1 -0
  303. package/dist/skills/poc-md-loader/runner.d.ts +24 -0
  304. package/dist/skills/poc-md-loader/runner.d.ts.map +1 -0
  305. package/dist/skills/poc-md-loader/runner.js +57 -0
  306. package/dist/skills/poc-md-loader/runner.js.map +1 -0
  307. package/dist/skills/poc-md-loader/vitest.poc.config.d.ts +3 -0
  308. package/dist/skills/poc-md-loader/vitest.poc.config.d.ts.map +1 -0
  309. package/dist/skills/poc-md-loader/vitest.poc.config.js +13 -0
  310. package/dist/skills/poc-md-loader/vitest.poc.config.js.map +1 -0
  311. package/dist/skills/poc-md-loader/web-search/script.d.ts +33 -0
  312. package/dist/skills/poc-md-loader/web-search/script.d.ts.map +1 -0
  313. package/dist/skills/poc-md-loader/web-search/script.js +75 -0
  314. package/dist/skills/poc-md-loader/web-search/script.js.map +1 -0
  315. package/dist/skills/record-outcome.d.ts +4 -4
  316. package/dist/skills/send-email.d.ts.map +1 -1
  317. package/dist/skills/send-email.js +15 -3
  318. package/dist/skills/send-email.js.map +1 -1
  319. package/dist/skills/slack-notify.d.ts +4 -4
  320. package/dist/skills/starknet-balance.d.ts +1 -1
  321. package/dist/skills/telegram-notify.d.ts +4 -4
  322. package/dist/skills/web-search.d.ts +1 -1
  323. package/dist/testing/index.d.ts +3 -0
  324. package/dist/testing/test-brain-port.d.ts +4 -0
  325. package/dist/testing/test-brain-port.d.ts.map +1 -1
  326. package/dist/testing/test-brain-port.js +75 -20
  327. package/dist/testing/test-brain-port.js.map +1 -1
  328. package/dist/testing/test-event-bus.d.ts.map +1 -1
  329. package/dist/testing/test-event-bus.js +89 -36
  330. package/dist/testing/test-event-bus.js.map +1 -1
  331. package/dist/trace/schema.d.ts +1 -1
  332. package/dist/trace/schema.d.ts.map +1 -1
  333. package/dist/trace/schema.js +1 -1
  334. package/dist/trace/schema.js.map +1 -1
  335. package/dist/verify/formal/index.d.ts +44 -0
  336. package/dist/verify/formal/index.d.ts.map +1 -0
  337. package/dist/verify/formal/index.js +98 -0
  338. package/dist/verify/formal/index.js.map +1 -0
  339. package/dist/verify/formal/policy.d.ts +105 -0
  340. package/dist/verify/formal/policy.d.ts.map +1 -0
  341. package/dist/verify/formal/policy.js +159 -0
  342. package/dist/verify/formal/policy.js.map +1 -0
  343. package/dist/verify/formal/result.d.ts +50 -0
  344. package/dist/verify/formal/result.d.ts.map +1 -0
  345. package/dist/verify/formal/result.js +21 -0
  346. package/dist/verify/formal/result.js.map +1 -0
  347. package/dist/verify/formal/solver.d.ts +67 -0
  348. package/dist/verify/formal/solver.d.ts.map +1 -0
  349. package/dist/verify/formal/solver.js +184 -0
  350. package/dist/verify/formal/solver.js.map +1 -0
  351. package/dist/verify/formal/spec-language.d.ts +80 -0
  352. package/dist/verify/formal/spec-language.d.ts.map +1 -0
  353. package/dist/verify/formal/spec-language.js +219 -0
  354. package/dist/verify/formal/spec-language.js.map +1 -0
  355. package/docs/attestation.md +199 -0
  356. package/docs/identity.md +193 -0
  357. package/package.json +34 -17
  358. package/src/adapters/llm/anthropic-direct.ts +51 -0
  359. package/src/adapters/llm/cascade.ts +64 -19
  360. package/src/adapters/llm/litellm.ts +49 -0
  361. package/src/compute/difficulty-estimator.ts +111 -0
  362. package/src/compute/strategies/mixture-of-agents.ts +150 -0
  363. package/src/compute/strategies/tree-of-thoughts.ts +293 -0
  364. package/src/compute/strategies/two-phase-orient.ts +147 -0
  365. package/src/container/protocol.ts +243 -0
  366. package/src/container/runtime.ts +424 -0
  367. package/src/db/migrations/026_formal_verify_results.sql +30 -0
  368. package/src/identity/agent-persona.ts +203 -0
  369. package/src/identity/persona-prompt.ts +84 -0
  370. package/src/identity/persona-schema.ts +127 -0
  371. package/src/index.ts +338 -1
  372. package/src/memory/episodic-rrf.ts +224 -0
  373. package/src/mesh/attenuation.ts +190 -0
  374. package/src/mesh/delegate.ts +254 -0
  375. package/src/mesh/dispatcher.ts +301 -0
  376. package/src/mesh/index.ts +39 -0
  377. package/src/mesh/types.ts +31 -0
  378. package/src/orchestration/ooda/skills.ts +177 -0
  379. package/src/ports/bastion-action.contract.test.ts +355 -0
  380. package/src/ports/bastion-action.ts +198 -0
  381. package/src/ports/brain.ts +177 -15
  382. package/src/ports/citadel-action.contract.test.ts +430 -0
  383. package/src/ports/citadel-action.ts +174 -0
  384. package/src/ports/compliance-contract.ts +191 -0
  385. package/src/ports/db.ts +98 -0
  386. package/src/ports/delegation.contract.test.ts +428 -0
  387. package/src/ports/delegation.ts +211 -0
  388. package/src/ports/event-bus.ts +133 -0
  389. package/src/ports/federation.contract.test.ts +355 -0
  390. package/src/ports/federation.ts +190 -0
  391. package/src/ports/index.ts +186 -1
  392. package/src/ports/llm-provider.ts +123 -0
  393. package/src/ports/logger.ts +104 -0
  394. package/src/ports/manifest-registry.contract.test.ts +324 -0
  395. package/src/ports/manifest-registry.ts +188 -0
  396. package/src/ports/observability.contract.test.ts +315 -0
  397. package/src/ports/observability.ts +150 -0
  398. package/src/ports/outcome.ts +69 -0
  399. package/src/ports/privacy.contract.test.ts +413 -0
  400. package/src/ports/privacy.ts +207 -0
  401. package/src/ports/tenant-context.contract.test.ts +454 -0
  402. package/src/ports/tenant-context.ts +150 -0
  403. package/src/ports/vauban-finance-action.contract.test.ts +335 -0
  404. package/src/ports/vauban-finance-action.ts +166 -0
  405. package/src/ports/workflow-runtime.ts +327 -0
  406. package/src/proof/cert-verify.ts +249 -0
  407. package/src/replay/replay.ts +11 -8
  408. package/src/retry/index.ts +227 -0
  409. package/src/retry/presets.ts +75 -0
  410. package/src/skill-loop/ab-runner.ts +196 -0
  411. package/src/skill-loop/adoption.ts +188 -0
  412. package/src/skill-loop/candidate.ts +75 -0
  413. package/src/skill-loop/evaluator.ts +238 -0
  414. package/src/skill-loop/index.ts +51 -0
  415. package/src/skill-loop/reflexion-replay.ts +173 -0
  416. package/src/skill-loop/sign-off.ts +247 -0
  417. package/src/skill-loop/value-metric.ts +120 -0
  418. package/src/skill-loop/versioning.ts +75 -0
  419. package/src/skill-manifest/anchor.ts +401 -0
  420. package/src/skill-manifest/builder.ts +129 -0
  421. package/src/skill-manifest/index.ts +18 -0
  422. package/src/skill-manifest/types.ts +72 -0
  423. package/src/skill-manifest/verifier.ts +198 -0
  424. package/src/skills/errors.ts +30 -2
  425. package/src/skills/index.ts +19 -0
  426. package/src/skills/markdown/loader.ts +129 -0
  427. package/src/skills/markdown/schema.ts +144 -0
  428. package/src/skills/poc-md-loader/e2e-parity.test.ts +237 -0
  429. package/src/skills/poc-md-loader/markdown-loader.ts +161 -0
  430. package/src/skills/poc-md-loader/runner.ts +82 -0
  431. package/src/skills/poc-md-loader/vitest.poc.config.ts +13 -0
  432. package/src/skills/poc-md-loader/web-search/SKILL.md +42 -0
  433. package/src/skills/poc-md-loader/web-search/script.ts +109 -0
  434. package/src/skills/send-email.ts +15 -3
  435. package/src/testing/test-brain-port.ts +98 -24
  436. package/src/testing/test-event-bus.ts +104 -43
  437. package/src/trace/schema.ts +1 -1
  438. package/src/verify/formal/index.ts +154 -0
  439. package/src/verify/formal/policy.ts +253 -0
  440. package/src/verify/formal/result.ts +52 -0
  441. package/src/verify/formal/solver.ts +235 -0
  442. package/src/verify/formal/spec-language.ts +274 -0
@@ -0,0 +1,198 @@
1
+ /**
2
+ * Skill Lineage Manifest — verifier (sprint-586).
3
+ *
4
+ * Zero external dependency verifier — mirrors vauban-claim-verifier philosophy.
5
+ *
6
+ * Verification checks:
7
+ * 1. replayRootMatches — SHA-256(replaySnapshot) === manifest.trainingReplayRoot
8
+ * 2. poseidonHashValid — computeManifestHash(manifest) === manifest.poseidonHash
9
+ * 3. tsaAnchorValid — verifyTsaAnchor(manifest) (skipped if no tsaToken)
10
+ * 4. starknetAnchorValid — merkle inclusion via AnchorWitness (if provided)
11
+ *
12
+ * A 1-byte tamper in replaySnapshot causes check 1 to fail.
13
+ * All checks run independently; errors array collects all failures.
14
+ *
15
+ * @module skill-manifest/verifier
16
+ */
17
+
18
+ import { createHash } from "node:crypto";
19
+ import { computeManifestHash } from "./builder.js";
20
+ import { verifyTsaAnchor } from "./anchor.js";
21
+ import { verifyProofInclusion } from "../proof/index.js";
22
+ import type { SkillManifest, AnchorWitness } from "./types.js";
23
+
24
+ // ─── ManifestVerifyResult ────────────────────────────────────────────────────
25
+
26
+ export interface ManifestVerifyResult {
27
+ /** Overall validity — true only if all applicable checks pass. */
28
+ valid: boolean;
29
+ /** SHA-256(replaySnapshot) === manifest.trainingReplayRoot */
30
+ replayRootMatches: boolean;
31
+ /** Poseidon commitment over manifest fields matches stored poseidonHash */
32
+ poseidonHashValid: boolean;
33
+ /** RFC 3161 TSA token structurally verifiable (false if no tsaToken) */
34
+ tsaAnchorValid: boolean;
35
+ /** Merkle inclusion proof valid (false if no witness or witness.type='none') */
36
+ starknetAnchorValid: boolean;
37
+ /** Grade propagated from the manifest (informational). */
38
+ grade: SkillManifest["grade"];
39
+ /** Human-readable error messages for every failed check. */
40
+ errors: string[];
41
+ }
42
+
43
+ // ─── helpers ─────────────────────────────────────────────────────────────────
44
+
45
+ function sha256Hex(input: string | Buffer): string {
46
+ const data = typeof input === "string" ? Buffer.from(input, "utf8") : input;
47
+ return createHash("sha256").update(data).digest("hex");
48
+ }
49
+
50
+ /**
51
+ * Normalise hex strings for comparison: strip "0x" prefix, lowercase.
52
+ */
53
+ function normaliseHex(h: string): string {
54
+ return (h.startsWith("0x") ? h.slice(2) : h).toLowerCase();
55
+ }
56
+
57
+ // ─── verifyManifest ───────────────────────────────────────────────────────────
58
+
59
+ /**
60
+ * Verify a SkillManifest against the original training replay snapshot.
61
+ *
62
+ * @param manifest - Manifest to verify.
63
+ * @param replaySnapshot - Original training trace bytes (same input used in buildManifest).
64
+ * @param starknetWitness - Optional Merkle inclusion witness from the Starknet anchor.
65
+ */
66
+ export function verifyManifest(
67
+ manifest: SkillManifest,
68
+ replaySnapshot: string | Buffer,
69
+ starknetWitness?: AnchorWitness
70
+ ): ManifestVerifyResult {
71
+ const errors: string[] = [];
72
+
73
+ // ── Check 1: replay root integrity ──────────────────────────────────────────
74
+ const recomputedRoot = sha256Hex(
75
+ typeof replaySnapshot === "string"
76
+ ? Buffer.from(replaySnapshot, "utf8")
77
+ : replaySnapshot
78
+ );
79
+ const replayRootMatches =
80
+ normaliseHex(recomputedRoot) === normaliseHex(manifest.trainingReplayRoot);
81
+ if (!replayRootMatches) {
82
+ errors.push(
83
+ `replayRoot mismatch: expected ${manifest.trainingReplayRoot}, got ${recomputedRoot}`
84
+ );
85
+ }
86
+
87
+ // ── Check 2: Poseidon hash validity ──────────────────────────────────────────
88
+ let poseidonHashValid = false;
89
+ try {
90
+ const recomputed = computeManifestHash({
91
+ skillId: manifest.skillId,
92
+ version: manifest.version,
93
+ domain: manifest.domain,
94
+ trainingReplayRoot: manifest.trainingReplayRoot,
95
+ });
96
+ poseidonHashValid =
97
+ normaliseHex(recomputed) === normaliseHex(manifest.poseidonHash);
98
+ if (!poseidonHashValid) {
99
+ errors.push(
100
+ `poseidonHash mismatch: expected ${manifest.poseidonHash}, got ${recomputed}`
101
+ );
102
+ }
103
+ } catch (err) {
104
+ errors.push(
105
+ `poseidonHash computation failed: ${
106
+ err instanceof Error ? err.message : String(err)
107
+ }`
108
+ );
109
+ }
110
+
111
+ // ── Check 3: TSA anchor ───────────────────────────────────────────────────────
112
+ const tsaAnchorValid = manifest.tsaToken ? verifyTsaAnchor(manifest) : false;
113
+ if (manifest.tsaToken && !tsaAnchorValid) {
114
+ errors.push("tsaAnchor invalid: token present but verification failed");
115
+ }
116
+
117
+ // ── Check 4: Starknet Merkle inclusion ──────────────────────────────────────
118
+ let starknetAnchorValid = false;
119
+ if (starknetWitness && starknetWitness.type === "starknet") {
120
+ try {
121
+ // proof field: comma-separated Merkle siblings (hex)
122
+ const siblings =
123
+ starknetWitness.proof.length > 0
124
+ ? starknetWitness.proof.split(",").map((s) => s.trim())
125
+ : [];
126
+
127
+ const leafFelt = manifest.poseidonHash.startsWith("0x")
128
+ ? manifest.poseidonHash.slice(2)
129
+ : manifest.poseidonHash;
130
+
131
+ // We need a root to verify against; derive it from the first sibling
132
+ // if the proof is a single-leaf tree (leaf === root).
133
+ if (siblings.length === 0) {
134
+ // Degenerate tree: leaf is the root — valid if leaf is consistent.
135
+ starknetAnchorValid = leafFelt.length > 0;
136
+ } else {
137
+ // verifyProofInclusion: leaf + proof[] → recomputed root must match
138
+ // the last sibling used as root sentinel in single-layer proofs.
139
+ // For multi-layer proofs the root must be provided externally.
140
+ // We use the witness.proof first element as root when siblings.length === 1.
141
+ const root = siblings[siblings.length - 1];
142
+ const proofSiblings = siblings.slice(0, -1);
143
+ starknetAnchorValid = verifyProofInclusion(
144
+ leafFelt,
145
+ proofSiblings,
146
+ root
147
+ );
148
+ }
149
+
150
+ if (!starknetAnchorValid) {
151
+ errors.push("starknetAnchor: Merkle inclusion proof failed");
152
+ }
153
+ } catch (err) {
154
+ errors.push(
155
+ `starknetAnchor verification error: ${
156
+ err instanceof Error ? err.message : String(err)
157
+ }`
158
+ );
159
+ }
160
+ } else if (starknetWitness && starknetWitness.type === "tsa") {
161
+ // TSA witness — treat as tsaAnchorValid supplement (already checked above).
162
+ starknetAnchorValid = false;
163
+ }
164
+ // type === 'none' or no witness → starknetAnchorValid remains false (expected).
165
+
166
+ // ── Grade propagation ─────────────────────────────────────────────────────────
167
+ const grade = manifest.grade;
168
+
169
+ // Warn about unanchored grade in errors (non-fatal, but caller should know).
170
+ if (grade === "unanchored") {
171
+ errors.push(
172
+ "grade=unanchored: manifest has no anchor — development/testing only"
173
+ );
174
+ }
175
+
176
+ // ── Overall validity ──────────────────────────────────────────────────────────
177
+ // An anchored manifest is valid when the integrity checks pass.
178
+ // For unanchored: valid = replayRootMatches && poseidonHashValid only.
179
+ const anchorErrors = errors.filter(
180
+ (e) =>
181
+ e.startsWith("tsa") ||
182
+ e.startsWith("starknet") ||
183
+ e.startsWith("grade=unanchored")
184
+ );
185
+ const integrityErrors = errors.filter((e) => !anchorErrors.includes(e));
186
+
187
+ const valid = integrityErrors.length === 0;
188
+
189
+ return {
190
+ valid,
191
+ replayRootMatches,
192
+ poseidonHashValid,
193
+ tsaAnchorValid,
194
+ starknetAnchorValid,
195
+ grade,
196
+ errors,
197
+ };
198
+ }
@@ -13,7 +13,9 @@ export class SkillNotConfiguredError extends Error {
13
13
  readonly missingEnv: readonly string[];
14
14
  constructor(skillName: string, missingEnv: readonly string[]) {
15
15
  super(
16
- `Skill '${skillName}' not configured: missing env ${missingEnv.join(", ")}`,
16
+ `Skill '${skillName}' not configured: missing env ${missingEnv.join(
17
+ ", "
18
+ )}`
17
19
  );
18
20
  this.name = "SkillNotConfiguredError";
19
21
  this.skillName = skillName;
@@ -28,7 +30,7 @@ export class SkillExecutionError extends Error {
28
30
  constructor(
29
31
  skillName: string,
30
32
  message: string,
31
- opts?: { status?: number; cause?: unknown },
33
+ opts?: { status?: number; cause?: unknown }
32
34
  ) {
33
35
  super(`Skill '${skillName}' failed: ${message}`);
34
36
  this.name = "SkillExecutionError";
@@ -57,3 +59,29 @@ export class HttpFetchAllowlistError extends Error {
57
59
  this.host = host;
58
60
  }
59
61
  }
62
+
63
+ export class SkillMdParseError extends Error {
64
+ readonly filePath: string;
65
+ constructor(filePath: string, reason: string) {
66
+ super(`SKILL.md at ${filePath}: ${reason}`);
67
+ this.name = "SkillMdParseError";
68
+ this.filePath = filePath;
69
+ }
70
+ }
71
+
72
+ export class SkillMdValidationError extends Error {
73
+ readonly filePath: string;
74
+ readonly issues: ReadonlyArray<{ path: string; message: string }>;
75
+ constructor(
76
+ filePath: string,
77
+ issues: ReadonlyArray<{ path: string; message: string }>
78
+ ) {
79
+ const summary = issues
80
+ .map((i) => `${i.path || "(root)"}: ${i.message}`)
81
+ .join("; ");
82
+ super(`SKILL.md at ${filePath}: invalid frontmatter — ${summary}`);
83
+ this.name = "SkillMdValidationError";
84
+ this.filePath = filePath;
85
+ this.issues = issues;
86
+ }
87
+ }
@@ -18,8 +18,27 @@ export {
18
18
  SkillExecutionError,
19
19
  SqlReadOnlyViolation,
20
20
  HttpFetchAllowlistError,
21
+ SkillMdParseError,
22
+ SkillMdValidationError,
21
23
  } from "./errors.js";
22
24
 
25
+ // SKILL.md loader (agentskills.io standard) — ADR-ECO-034
26
+ export {
27
+ loadSkillMd,
28
+ parseSkillMd,
29
+ toDiscoveryEntry,
30
+ type ParsedSkillFile,
31
+ } from "./markdown/loader.js";
32
+ export {
33
+ SkillManifestSchema,
34
+ resolveTier,
35
+ parseAllowedTools,
36
+ type SkillManifest,
37
+ type VaubanSkillTier,
38
+ type VaubanBiscuitScope,
39
+ type VaubanAuditStatus,
40
+ } from "./markdown/schema.js";
41
+
23
42
  export { webSearch } from "./web-search.js";
24
43
  export type { WebSearchOutput, WebSearchResult } from "./web-search.js";
25
44
 
@@ -0,0 +1,129 @@
1
+ /**
2
+ * SKILL.md loader — agentskills.io standard parser.
3
+ *
4
+ * Reads a SKILL.md file, splits frontmatter from body, parses YAML via the
5
+ * `yaml` package (battle-tested), validates against `SkillManifestSchema`,
6
+ * and returns a typed `ParsedSkillFile`.
7
+ *
8
+ * Constraints:
9
+ * - No new npm deps (uses `yaml` already in package.json).
10
+ * - Frontmatter delimiters: `---\n` ... `\n---\n`.
11
+ * - Body returned verbatim (markdown — no rendering).
12
+ * - Validation errors are typed (SkillMdParseError / SkillMdValidationError).
13
+ *
14
+ * Progressive disclosure tiers (per agentskills.io spec):
15
+ * - Discovery (~100 tok) — name + description only
16
+ * - Pre-activate (~500 tok) — full frontmatter + body excerpt
17
+ * - Activate — full body (≤8000 tok recommended)
18
+ *
19
+ * Spec reference: https://agentskills.io/specification
20
+ * @see ADR-ECO-034 — skills TS↔MD coexistence
21
+ * @public
22
+ */
23
+
24
+ import { readFile } from "node:fs/promises";
25
+ import { parse as parseYaml } from "yaml";
26
+ import { SkillMdParseError, SkillMdValidationError } from "../errors.js";
27
+ import {
28
+ type SkillManifest,
29
+ SkillManifestSchema,
30
+ type VaubanSkillTier,
31
+ resolveTier,
32
+ } from "./schema.js";
33
+
34
+ // `---` at line start, then arbitrary content, then `---` at line start. Body follows.
35
+ const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
36
+
37
+ export interface ParsedSkillFile {
38
+ manifest: SkillManifest;
39
+ body: string;
40
+ tier: VaubanSkillTier;
41
+ /** Tokens (rough heuristic ~4 chars/token) for progressive disclosure. */
42
+ bodyTokens: number;
43
+ }
44
+
45
+ /**
46
+ * Load and parse a SKILL.md file from disk.
47
+ *
48
+ * @throws SkillMdParseError when frontmatter delimiters are missing or YAML is invalid
49
+ * @throws SkillMdValidationError when frontmatter fails Zod schema validation
50
+ */
51
+ export async function loadSkillMd(filePath: string): Promise<ParsedSkillFile> {
52
+ const raw = await readFile(filePath, "utf-8");
53
+ return parseSkillMd(raw, filePath);
54
+ }
55
+
56
+ /**
57
+ * Parse SKILL.md content from a string (in-memory). Useful for tests and
58
+ * embedded skills.
59
+ */
60
+ export function parseSkillMd(
61
+ raw: string,
62
+ source = "<inline>"
63
+ ): ParsedSkillFile {
64
+ const match = raw.match(FRONTMATTER_RE);
65
+ if (!match) {
66
+ throw new SkillMdParseError(
67
+ source,
68
+ "missing or malformed frontmatter (expected '---' delimiters on first line)"
69
+ );
70
+ }
71
+ const [, frontmatterText, body] = match;
72
+
73
+ let parsed: unknown;
74
+ try {
75
+ parsed = parseYaml(frontmatterText);
76
+ } catch (err) {
77
+ const message = err instanceof Error ? err.message : String(err);
78
+ throw new SkillMdParseError(source, `YAML parse error — ${message}`);
79
+ }
80
+
81
+ if (parsed == null || typeof parsed !== "object" || Array.isArray(parsed)) {
82
+ throw new SkillMdParseError(
83
+ source,
84
+ "frontmatter must be a YAML object (got " +
85
+ (parsed === null
86
+ ? "null"
87
+ : Array.isArray(parsed)
88
+ ? "array"
89
+ : typeof parsed) +
90
+ ")"
91
+ );
92
+ }
93
+
94
+ const result = SkillManifestSchema.safeParse(parsed);
95
+ if (!result.success) {
96
+ throw new SkillMdValidationError(
97
+ source,
98
+ result.error.issues.map((i) => ({
99
+ path: i.path.join("."),
100
+ message: i.message,
101
+ }))
102
+ );
103
+ }
104
+
105
+ const manifest = result.data;
106
+ const trimmedBody = body.trim();
107
+ return {
108
+ manifest,
109
+ body: trimmedBody,
110
+ tier: resolveTier(manifest),
111
+ bodyTokens: Math.ceil(trimmedBody.length / 4),
112
+ };
113
+ }
114
+
115
+ /**
116
+ * Produce the "discovery" projection (~100 tokens): name + description only.
117
+ * Used by the catalogue / progressive disclosure layer to keep startup cost low.
118
+ */
119
+ export function toDiscoveryEntry(parsed: ParsedSkillFile): {
120
+ name: string;
121
+ description: string;
122
+ tier: VaubanSkillTier;
123
+ } {
124
+ return {
125
+ name: parsed.manifest.name,
126
+ description: parsed.manifest.description,
127
+ tier: parsed.tier,
128
+ };
129
+ }
@@ -0,0 +1,144 @@
1
+ /**
2
+ * SKILL.md frontmatter schema — agentskills.io standard + Vauban extensions.
3
+ *
4
+ * Standard fields (agentskills.io spec):
5
+ * - `name` 1-64 chars, kebab-case
6
+ * - `description` 1-1024 chars
7
+ * - `license` free-text (optional)
8
+ * - `compatibility` free-text (optional, e.g. "Requires STARKNET_RPC_URL")
9
+ * - `allowed-tools` space-separated string, e.g. "Bash(curl:*) Bash(jq:*) Read"
10
+ * - `metadata` arbitrary k/v map (per spec — extension surface)
11
+ *
12
+ * Vauban extensions live UNDER `metadata` (spec-compliant — ignored gracefully
13
+ * by other agentskills.io-conforming tools). Namespaced as `vauban.*` keys
14
+ * for clarity:
15
+ * - `metadata.vauban.tier` "official" | "verified" | "unverified"
16
+ * - `metadata.vauban.subagent` agent id this skill belongs to
17
+ * - `metadata.vauban.model-hint` suggested LLM (forwarded to EconomyRouter)
18
+ * - `metadata.vauban.proof.poseidon_hash` hex
19
+ * - `metadata.vauban.proof.tsa_token` base64 RFC3161
20
+ * - `metadata.vauban.proof.starknet_tx` hex
21
+ * - `metadata.vauban.biscuit.required_caps` array of capability strings
22
+ * - `metadata.vauban.biscuit.max_scope` "project" | "session" | "global"
23
+ * - `metadata.vauban.audit_status` "approved" | "review" | "rejected"
24
+ *
25
+ * Spec reference: https://agentskills.io/specification
26
+ * @see ADR-ECO-034 — skills TS↔MD coexistence
27
+ * @public
28
+ */
29
+
30
+ import { z } from "zod";
31
+
32
+ // ── Vauban metadata extension schemas ────────────────────────────────────────
33
+
34
+ export const VaubanSkillTier = z.enum(["official", "verified", "unverified"]);
35
+ export type VaubanSkillTier = z.infer<typeof VaubanSkillTier>;
36
+
37
+ export const VaubanBiscuitScope = z.enum(["project", "session", "global"]);
38
+ export type VaubanBiscuitScope = z.infer<typeof VaubanBiscuitScope>;
39
+
40
+ export const VaubanAuditStatus = z.enum(["approved", "review", "rejected"]);
41
+ export type VaubanAuditStatus = z.infer<typeof VaubanAuditStatus>;
42
+
43
+ const VaubanProofExtensionSchema = z
44
+ .object({
45
+ poseidon_hash: z
46
+ .string()
47
+ .regex(/^0x[0-9a-fA-F]+$/)
48
+ .optional(),
49
+ tsa_token: z.string().optional(),
50
+ starknet_tx: z
51
+ .string()
52
+ .regex(/^0x[0-9a-fA-F]+$/)
53
+ .optional(),
54
+ anchored_at: z.string().datetime().optional(),
55
+ })
56
+ .strict()
57
+ .partial();
58
+
59
+ const VaubanBiscuitExtensionSchema = z
60
+ .object({
61
+ required_caps: z.array(z.string()).optional(),
62
+ max_scope: VaubanBiscuitScope.optional(),
63
+ })
64
+ .strict()
65
+ .partial();
66
+
67
+ const VaubanExtensionSchema = z
68
+ .object({
69
+ tier: VaubanSkillTier.optional(),
70
+ subagent: z.string().optional(),
71
+ "model-hint": z.string().optional(),
72
+ proof: VaubanProofExtensionSchema.optional(),
73
+ biscuit: VaubanBiscuitExtensionSchema.optional(),
74
+ audit_status: VaubanAuditStatus.optional(),
75
+ observability_metric: z.string().optional(),
76
+ })
77
+ .strict()
78
+ .partial();
79
+
80
+ // ── Generic metadata (per agentskills.io: arbitrary k/v) ─────────────────────
81
+
82
+ const StandardMetadataKnownKeys = z
83
+ .object({
84
+ version: z.string().optional(),
85
+ category: z.string().optional(),
86
+ tags: z.union([z.string(), z.array(z.string())]).optional(),
87
+ author: z.string().optional(),
88
+ "env-required": z.string().optional(),
89
+ "env-mode": z.enum(["all", "at-least-one"]).optional(),
90
+ vauban: VaubanExtensionSchema.optional(),
91
+ })
92
+ .partial();
93
+
94
+ const MetadataSchema = StandardMetadataKnownKeys.passthrough();
95
+
96
+ // ── Top-level SKILL.md frontmatter schema ────────────────────────────────────
97
+
98
+ const KEBAB_CASE = /^[a-z0-9][a-z0-9-]*$/;
99
+
100
+ export const SkillManifestSchema = z
101
+ .object({
102
+ name: z
103
+ .string()
104
+ .min(1, "name must be 1-64 chars")
105
+ .max(64, "name must be 1-64 chars")
106
+ .regex(
107
+ KEBAB_CASE,
108
+ "name must be kebab-case (lowercase, digits, hyphens)"
109
+ ),
110
+ description: z
111
+ .string()
112
+ .min(1, "description must be 1-1024 chars")
113
+ .max(1024, "description must be 1-1024 chars"),
114
+ license: z.string().optional(),
115
+ compatibility: z.string().optional(),
116
+ "allowed-tools": z.string().optional(),
117
+ metadata: MetadataSchema.optional(),
118
+ })
119
+ .strict();
120
+
121
+ export type SkillManifest = z.infer<typeof SkillManifestSchema>;
122
+
123
+ // ── Helpers ───────────────────────────────────────────────────────────────────
124
+
125
+ /**
126
+ * Resolve the Vauban tier from a manifest, defaulting to `unverified` per
127
+ * the trust-stratification rule: any skill without an explicit tier MUST be
128
+ * sandboxed as community-untrusted.
129
+ */
130
+ export function resolveTier(manifest: SkillManifest): VaubanSkillTier {
131
+ return manifest.metadata?.vauban?.tier ?? "unverified";
132
+ }
133
+
134
+ /**
135
+ * Parse the space-separated `allowed-tools` string into an array. Empty string
136
+ * returns []. Whitespace runs collapse. Examples:
137
+ * "Bash(curl:*) Read" → ["Bash(curl:*)", "Read"]
138
+ * "Bash(curl:*) Bash(jq)" → ["Bash(curl:*)", "Bash(jq)"]
139
+ */
140
+ export function parseAllowedTools(manifest: SkillManifest): string[] {
141
+ const raw = manifest["allowed-tools"];
142
+ if (!raw) return [];
143
+ return raw.split(/\s+/).filter((s) => s.length > 0);
144
+ }