approval-md 0.1.0 → 0.3.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 (416) hide show
  1. package/README.md +629 -559
  2. package/SPEC.md +99 -24
  3. package/dist/src/adapters/agentmail.d.ts +426 -0
  4. package/dist/src/adapters/agentmail.js +2 -2
  5. package/dist/src/adapters/conformance.d.ts +149 -0
  6. package/dist/src/adapters/contract.d.ts +628 -0
  7. package/dist/src/adapters/contract.js +110 -16
  8. package/dist/src/adapters/contract.js.map +1 -1
  9. package/dist/src/adapters/email.d.ts +324 -0
  10. package/dist/src/adapters/env-passphrase.d.ts +93 -0
  11. package/dist/src/adapters/public.d.ts +11 -0
  12. package/dist/src/adapters/public.js +11 -0
  13. package/dist/src/adapters/public.js.map +1 -0
  14. package/dist/src/adapters/registry.d.ts +59 -0
  15. package/dist/src/adapters/registry.js +2 -1
  16. package/dist/src/adapters/registry.js.map +1 -1
  17. package/dist/src/adapters/smtp.d.ts +213 -0
  18. package/dist/src/adapters/vault-provider.d.ts +114 -0
  19. package/dist/src/adapters/vault-provider.js +3 -3
  20. package/dist/src/adapters/zzz.d.ts +66 -0
  21. package/dist/src/adapters/zzz.js +299 -0
  22. package/dist/src/adapters/zzz.js.map +1 -0
  23. package/dist/src/channels/batch.d.ts +109 -0
  24. package/dist/src/channels/cli.d.ts +193 -0
  25. package/dist/src/channels/conformance.d.ts +92 -0
  26. package/dist/src/channels/contract.d.ts +656 -0
  27. package/dist/src/channels/contract.js +200 -7
  28. package/dist/src/channels/contract.js.map +1 -1
  29. package/dist/src/channels/payload-view.d.ts +35 -0
  30. package/dist/src/channels/render-queue.d.ts +149 -0
  31. package/dist/src/channels/tagging.d.ts +196 -0
  32. package/dist/src/channels/telegram.d.ts +1944 -0
  33. package/dist/src/channels/telegram.js +218 -23
  34. package/dist/src/channels/telegram.js.map +1 -1
  35. package/dist/src/channels/web.d.ts +350 -0
  36. package/dist/src/channels/web.js +17 -0
  37. package/dist/src/channels/web.js.map +1 -1
  38. package/dist/src/cli/adapter.d.ts +90 -0
  39. package/dist/src/cli/adapter.js +25 -15
  40. package/dist/src/cli/adapter.js.map +1 -1
  41. package/dist/src/cli/amend.d.ts +59 -0
  42. package/dist/src/cli/amend.js +214 -30
  43. package/dist/src/cli/amend.js.map +1 -1
  44. package/dist/src/cli/args.d.ts +43 -0
  45. package/dist/src/cli/attest.d.ts +50 -0
  46. package/dist/src/cli/attest.js +134 -7
  47. package/dist/src/cli/attest.js.map +1 -1
  48. package/dist/src/cli/audit-card.d.ts +62 -0
  49. package/dist/src/cli/audit.d.ts +59 -0
  50. package/dist/src/cli/channel-telegram.d.ts +879 -0
  51. package/dist/src/cli/channel-telegram.js +311 -13
  52. package/dist/src/cli/channel-telegram.js.map +1 -1
  53. package/dist/src/cli/channel-web.d.ts +131 -0
  54. package/dist/src/cli/channel.d.ts +80 -0
  55. package/dist/src/cli/channel.js +9 -0
  56. package/dist/src/cli/channel.js.map +1 -1
  57. package/dist/src/cli/checkpoint-tap.d.ts +169 -0
  58. package/dist/src/cli/codex-bridge.d.ts +819 -0
  59. package/dist/src/cli/codex-bridge.js +1607 -0
  60. package/dist/src/cli/codex-bridge.js.map +1 -0
  61. package/dist/src/cli/codex.d.ts +2 -0
  62. package/dist/src/cli/codex.js +469 -0
  63. package/dist/src/cli/codex.js.map +1 -0
  64. package/dist/src/cli/coverage.d.ts +61 -0
  65. package/dist/src/cli/daemon.d.ts +120 -0
  66. package/dist/src/cli/daemon.js +4 -1
  67. package/dist/src/cli/daemon.js.map +1 -1
  68. package/dist/src/cli/doctor.d.ts +129 -0
  69. package/dist/src/cli/doctor.js +586 -17
  70. package/dist/src/cli/doctor.js.map +1 -1
  71. package/dist/src/cli/env.d.ts +65 -0
  72. package/dist/src/cli/execute.d.ts +202 -0
  73. package/dist/src/cli/execute.js +25 -2
  74. package/dist/src/cli/execute.js.map +1 -1
  75. package/dist/src/cli/exit-codes.d.ts +73 -0
  76. package/dist/src/cli/feedback.d.ts +60 -0
  77. package/dist/src/cli/gate-window.d.ts +40 -0
  78. package/dist/src/cli/gate.d.ts +68 -0
  79. package/dist/src/cli/git-scope.d.ts +190 -0
  80. package/dist/src/cli/gloss-attach.d.ts +85 -0
  81. package/dist/src/cli/gloss-codex-child.d.ts +9 -0
  82. package/dist/src/cli/gloss-codex.d.ts +24 -0
  83. package/dist/src/cli/gloss-options.d.ts +42 -0
  84. package/dist/src/cli/gloss.d.ts +265 -0
  85. package/dist/src/cli/help.d.ts +107 -0
  86. package/dist/src/cli/help.js +320 -93
  87. package/dist/src/cli/help.js.map +1 -1
  88. package/dist/src/cli/hook-codex.d.ts +126 -0
  89. package/dist/src/cli/hook-codex.js +226 -0
  90. package/dist/src/cli/hook-codex.js.map +1 -0
  91. package/dist/src/cli/hook.d.ts +787 -0
  92. package/dist/src/cli/hook.js +1235 -181
  93. package/dist/src/cli/hook.js.map +1 -1
  94. package/dist/src/cli/import.d.ts +35 -0
  95. package/dist/src/cli/import.js +1 -1
  96. package/dist/src/cli/import.js.map +1 -1
  97. package/dist/src/cli/init.d.ts +84 -0
  98. package/dist/src/cli/init.js +2 -2
  99. package/dist/src/cli/init.js.map +1 -1
  100. package/dist/src/cli/instructions.d.ts +23 -0
  101. package/dist/src/cli/journal.d.ts +41 -0
  102. package/dist/src/cli/log-advance.d.ts +287 -0
  103. package/dist/src/cli/log-advance.js +102 -11
  104. package/dist/src/cli/log-advance.js.map +1 -1
  105. package/dist/src/cli/log-anchor.d.ts +176 -0
  106. package/dist/src/cli/log-checkpoint.d.ts +22 -0
  107. package/dist/src/cli/log-sync.d.ts +243 -0
  108. package/dist/src/cli/log-verbs.d.ts +16 -0
  109. package/dist/src/cli/log-verbs.js +7 -1
  110. package/dist/src/cli/log-verbs.js.map +1 -1
  111. package/dist/src/cli/long-help.d.ts +70 -0
  112. package/dist/src/cli/main.d.ts +77 -0
  113. package/dist/src/cli/main.js +159 -7
  114. package/dist/src/cli/main.js.map +1 -1
  115. package/dist/src/cli/mcp.d.ts +52 -0
  116. package/dist/src/cli/paths.d.ts +56 -0
  117. package/dist/src/cli/payload.d.ts +58 -0
  118. package/dist/src/cli/policy-apply.d.ts +195 -0
  119. package/dist/src/cli/policy-apply.js +573 -0
  120. package/dist/src/cli/policy-apply.js.map +1 -0
  121. package/dist/src/cli/policy.d.ts +43 -0
  122. package/dist/src/cli/policy.js +14 -1
  123. package/dist/src/cli/policy.js.map +1 -1
  124. package/dist/src/cli/preflight.d.ts +501 -0
  125. package/dist/src/cli/preflight.js +689 -45
  126. package/dist/src/cli/preflight.js.map +1 -1
  127. package/dist/src/cli/progress.d.ts +78 -0
  128. package/dist/src/cli/prompt.d.ts +209 -0
  129. package/dist/src/cli/quickstart.d.ts +46 -0
  130. package/dist/src/cli/quickstart.js +297 -0
  131. package/dist/src/cli/quickstart.js.map +1 -0
  132. package/dist/src/cli/records.d.ts +34 -0
  133. package/dist/src/cli/render.d.ts +22 -0
  134. package/dist/src/cli/sandbox.d.ts +51 -0
  135. package/dist/src/cli/sandbox.js +17 -1
  136. package/dist/src/cli/sandbox.js.map +1 -1
  137. package/dist/src/cli/scaffold.d.ts +79 -0
  138. package/dist/src/cli/scaffold.js +1 -1
  139. package/dist/src/cli/setup-adapter.d.ts +137 -0
  140. package/dist/src/cli/setup-adapter.js +38 -4
  141. package/dist/src/cli/setup-adapter.js.map +1 -1
  142. package/dist/src/cli/setup-channel.d.ts +126 -0
  143. package/dist/src/cli/setup-channel.js +28 -1
  144. package/dist/src/cli/setup-channel.js.map +1 -1
  145. package/dist/src/cli/setup-checkpoint.d.ts +57 -0
  146. package/dist/src/cli/setup-common.d.ts +277 -0
  147. package/dist/src/cli/setup-common.js +3 -2
  148. package/dist/src/cli/setup-common.js.map +1 -1
  149. package/dist/src/cli/setup-flow.d.ts +287 -0
  150. package/dist/src/cli/setup-service.d.ts +96 -0
  151. package/dist/src/cli/setup.d.ts +204 -0
  152. package/dist/src/cli/setup.js +94 -2
  153. package/dist/src/cli/setup.js.map +1 -1
  154. package/dist/src/cli/style.d.ts +320 -0
  155. package/dist/src/cli/token.d.ts +39 -0
  156. package/dist/src/cli/up.d.ts +155 -0
  157. package/dist/src/cli/up.js +119 -53
  158. package/dist/src/cli/up.js.map +1 -1
  159. package/dist/src/cli/usage.d.ts +37 -0
  160. package/dist/src/cli/values.d.ts +40 -0
  161. package/dist/src/cli/values.js +3 -4
  162. package/dist/src/cli/values.js.map +1 -1
  163. package/dist/src/cli/vault.d.ts +59 -0
  164. package/dist/src/cli/vault.js +2 -2
  165. package/dist/src/cli/vault.js.map +1 -1
  166. package/dist/src/cli/verb-registry.d.ts +76 -0
  167. package/dist/src/cli/verb-registry.js +344 -11
  168. package/dist/src/cli/verb-registry.js.map +1 -1
  169. package/dist/src/cli/wordmark.d.ts +31 -0
  170. package/dist/src/cli/wordmark.js +2 -2
  171. package/dist/src/codex/broker.d.ts +229 -0
  172. package/dist/src/codex/broker.js +548 -0
  173. package/dist/src/codex/broker.js.map +1 -0
  174. package/dist/src/codex/doctor.d.ts +13 -0
  175. package/dist/src/codex/doctor.js +41 -0
  176. package/dist/src/codex/doctor.js.map +1 -0
  177. package/dist/src/codex/manifest.d.ts +49 -0
  178. package/dist/src/codex/manifest.js +103 -0
  179. package/dist/src/codex/manifest.js.map +1 -0
  180. package/dist/src/codex/runner.d.ts +178 -0
  181. package/dist/src/codex/runner.js +231 -0
  182. package/dist/src/codex/runner.js.map +1 -0
  183. package/dist/src/codex/serve.d.ts +56 -0
  184. package/dist/src/codex/serve.js +98 -0
  185. package/dist/src/codex/serve.js.map +1 -0
  186. package/dist/src/codex/templates.d.ts +41 -0
  187. package/dist/src/codex/templates.js +319 -0
  188. package/dist/src/codex/templates.js.map +1 -0
  189. package/dist/src/codex/trust.d.ts +19 -0
  190. package/dist/src/codex/trust.js +183 -0
  191. package/dist/src/codex/trust.js.map +1 -0
  192. package/dist/src/codex/workspace-commit.d.ts +219 -0
  193. package/dist/src/codex/workspace-commit.js +549 -0
  194. package/dist/src/codex/workspace-commit.js.map +1 -0
  195. package/dist/src/codex/workspace-plan.d.ts +131 -0
  196. package/dist/src/codex/workspace-plan.js +561 -0
  197. package/dist/src/codex/workspace-plan.js.map +1 -0
  198. package/dist/src/core/actor.d.ts +2 -0
  199. package/dist/src/core/actor.js +5 -0
  200. package/dist/src/core/actor.js.map +1 -0
  201. package/dist/src/core/advance-cycle.d.ts +221 -0
  202. package/dist/src/core/advance-cycle.js +66 -2
  203. package/dist/src/core/advance-cycle.js.map +1 -1
  204. package/dist/src/core/agents-md.d.ts +278 -0
  205. package/dist/src/core/agents-md.js +33 -31
  206. package/dist/src/core/agents-md.js.map +1 -1
  207. package/dist/src/core/apply-patch.d.ts +49 -0
  208. package/dist/src/core/apply-patch.js +266 -0
  209. package/dist/src/core/apply-patch.js.map +1 -0
  210. package/dist/src/core/attest.d.ts +635 -0
  211. package/dist/src/core/attest.js +326 -4
  212. package/dist/src/core/attest.js.map +1 -1
  213. package/dist/src/core/audit.d.ts +510 -0
  214. package/dist/src/core/audit.js +13 -0
  215. package/dist/src/core/audit.js.map +1 -1
  216. package/dist/src/core/budgets.d.ts +238 -0
  217. package/dist/src/core/channel-owner.d.ts +213 -0
  218. package/dist/src/core/channel-owner.js +358 -0
  219. package/dist/src/core/channel-owner.js.map +1 -0
  220. package/dist/src/core/checkpoint.d.ts +500 -0
  221. package/dist/src/core/child-env.d.ts +88 -0
  222. package/dist/src/core/clock.d.ts +52 -0
  223. package/dist/src/core/command-class.d.ts +697 -0
  224. package/dist/src/core/command-class.js +713 -25
  225. package/dist/src/core/command-class.js.map +1 -1
  226. package/dist/src/core/commit-guard.d.ts +272 -0
  227. package/dist/src/core/commit-guard.js +424 -0
  228. package/dist/src/core/commit-guard.js.map +1 -0
  229. package/dist/src/core/coverage-sources/adapter.d.ts +40 -0
  230. package/dist/src/core/coverage-sources/gh.d.ts +48 -0
  231. package/dist/src/core/coverage-sources/git.d.ts +101 -0
  232. package/dist/src/core/coverage.d.ts +217 -0
  233. package/dist/src/core/credential-spec.d.ts +72 -0
  234. package/dist/src/core/daemon-actor.d.ts +45 -0
  235. package/dist/src/core/daemon-actor.js +54 -0
  236. package/dist/src/core/daemon-actor.js.map +1 -0
  237. package/dist/src/core/dark-session.d.ts +432 -0
  238. package/dist/src/core/dark-session.js +266 -82
  239. package/dist/src/core/dark-session.js.map +1 -1
  240. package/dist/src/core/decision-refusal.d.ts +206 -0
  241. package/dist/src/core/decision-refusal.js +24 -2
  242. package/dist/src/core/decision-refusal.js.map +1 -1
  243. package/dist/src/core/env-file.d.ts +455 -0
  244. package/dist/src/core/env-file.js +60 -1
  245. package/dist/src/core/env-file.js.map +1 -1
  246. package/dist/src/core/execute.d.ts +871 -0
  247. package/dist/src/core/execute.js +59 -8
  248. package/dist/src/core/execute.js.map +1 -1
  249. package/dist/src/core/frontmatter.d.ts +78 -0
  250. package/dist/src/core/gate-window.d.ts +312 -0
  251. package/dist/src/core/gate.d.ts +1449 -0
  252. package/dist/src/core/gate.js +149 -14
  253. package/dist/src/core/gate.js.map +1 -1
  254. package/dist/src/core/gesture-refusal.d.ts +166 -0
  255. package/dist/src/core/gesture-refusal.js +188 -0
  256. package/dist/src/core/gesture-refusal.js.map +1 -0
  257. package/dist/src/core/git-run.d.ts +73 -0
  258. package/dist/src/core/harness-version.d.ts +157 -0
  259. package/dist/src/core/harness-version.js +4 -1
  260. package/dist/src/core/harness-version.js.map +1 -1
  261. package/dist/src/core/harness-wait.d.ts +55 -0
  262. package/dist/src/core/head-retry.d.ts +107 -0
  263. package/dist/src/core/instance.d.ts +310 -0
  264. package/dist/src/core/instance.js +113 -0
  265. package/dist/src/core/instance.js.map +1 -1
  266. package/dist/src/core/intake-limits.d.ts +247 -0
  267. package/dist/src/core/jcs.d.ts +52 -0
  268. package/dist/src/core/journal.d.ts +144 -0
  269. package/dist/src/core/live-draw.d.ts +436 -0
  270. package/dist/src/core/log-reconcile.d.ts +89 -0
  271. package/dist/src/core/log-subscribe.d.ts +36 -0
  272. package/dist/src/core/log-subscribe.js +162 -0
  273. package/dist/src/core/log-subscribe.js.map +1 -0
  274. package/dist/src/core/log.d.ts +316 -0
  275. package/dist/src/core/log.js.map +1 -1
  276. package/dist/src/core/loop.d.ts +274 -0
  277. package/dist/src/core/loop.js +11 -0
  278. package/dist/src/core/loop.js.map +1 -1
  279. package/dist/src/core/md-fence.d.ts +41 -0
  280. package/dist/src/core/money.d.ts +147 -0
  281. package/dist/src/core/payload-census.d.ts +74 -0
  282. package/dist/src/core/payload-store.d.ts +175 -0
  283. package/dist/src/core/payload.d.ts +71 -0
  284. package/dist/src/core/policy-diff.d.ts +292 -0
  285. package/dist/src/core/policy-diff.js +27 -4
  286. package/dist/src/core/policy-diff.js.map +1 -1
  287. package/dist/src/core/policy-expectations.d.ts +199 -0
  288. package/dist/src/core/policy-explain.d.ts +160 -0
  289. package/dist/src/core/policy-explain.js +63 -3
  290. package/dist/src/core/policy-explain.js.map +1 -1
  291. package/dist/src/core/policy-load.d.ts +567 -0
  292. package/dist/src/core/policy-load.js +36 -6
  293. package/dist/src/core/policy-load.js.map +1 -1
  294. package/dist/src/core/policy-match.d.ts +324 -0
  295. package/dist/src/core/policy-match.js +72 -9
  296. package/dist/src/core/policy-match.js.map +1 -1
  297. package/dist/src/core/policy-proposal.d.ts +317 -0
  298. package/dist/src/core/policy-proposal.js +102 -2
  299. package/dist/src/core/policy-proposal.js.map +1 -1
  300. package/dist/src/core/prompt-layout.d.ts +221 -0
  301. package/dist/src/core/protected-path-guard.d.ts +566 -0
  302. package/dist/src/core/protected-path-guard.js +848 -55
  303. package/dist/src/core/protected-path-guard.js.map +1 -1
  304. package/dist/src/core/question-preempted.d.ts +141 -0
  305. package/dist/src/core/question-preempted.js +152 -0
  306. package/dist/src/core/question-preempted.js.map +1 -0
  307. package/dist/src/core/read-scope.d.ts +172 -0
  308. package/dist/src/core/read-scope.js +252 -0
  309. package/dist/src/core/read-scope.js.map +1 -0
  310. package/dist/src/core/registration.d.ts +25 -0
  311. package/dist/src/core/reindex.d.ts +99 -0
  312. package/dist/src/core/sampler.d.ts +313 -0
  313. package/dist/src/core/sandbox.d.ts +371 -0
  314. package/dist/src/core/sandbox.js +190 -1
  315. package/dist/src/core/sandbox.js.map +1 -1
  316. package/dist/src/core/seal.d.ts +165 -0
  317. package/dist/src/core/sender-identity.d.ts +476 -0
  318. package/dist/src/core/sender-identity.js +572 -0
  319. package/dist/src/core/sender-identity.js.map +1 -0
  320. package/dist/src/core/shlex.d.ts +102 -0
  321. package/dist/src/core/shlex.js +159 -0
  322. package/dist/src/core/shlex.js.map +1 -0
  323. package/dist/src/core/state.d.ts +505 -0
  324. package/dist/src/core/task-file.d.ts +185 -0
  325. package/dist/src/core/telegram-config.d.ts +93 -0
  326. package/dist/src/core/token.d.ts +409 -0
  327. package/dist/src/core/token.js +21 -38
  328. package/dist/src/core/token.js.map +1 -1
  329. package/dist/src/core/validate.d.ts +138 -0
  330. package/dist/src/core/values.d.ts +147 -0
  331. package/dist/src/core/values.js +36 -1
  332. package/dist/src/core/values.js.map +1 -1
  333. package/dist/src/core/vault.d.ts +291 -0
  334. package/dist/src/core/verified-snapshot.d.ts +204 -0
  335. package/dist/src/core/verify.d.ts +336 -0
  336. package/dist/src/core/version.d.ts +8 -0
  337. package/dist/src/core/wysiwys.d.ts +370 -0
  338. package/dist/src/daemon/advance-child.d.ts +39 -0
  339. package/dist/src/daemon/advance.d.ts +476 -0
  340. package/dist/src/daemon/advance.js +25 -4
  341. package/dist/src/daemon/advance.js.map +1 -1
  342. package/dist/src/daemon/audit.d.ts +87 -0
  343. package/dist/src/daemon/daemon.d.ts +1180 -0
  344. package/dist/src/daemon/daemon.js +9 -0
  345. package/dist/src/daemon/daemon.js.map +1 -1
  346. package/dist/src/daemon/dark-session.d.ts +64 -0
  347. package/dist/src/daemon/draw-child.d.ts +36 -0
  348. package/dist/src/daemon/draw.d.ts +154 -0
  349. package/dist/src/daemon/git-evidence.d.ts +173 -0
  350. package/dist/src/daemon/git-evidence.js +1 -1
  351. package/dist/src/daemon/projection.d.ts +180 -0
  352. package/dist/src/daemon/prune.d.ts +207 -0
  353. package/dist/src/mcp/http.d.ts +113 -0
  354. package/dist/src/mcp/server.d.ts +265 -0
  355. package/dist/src/mcp/server.js +17 -1
  356. package/dist/src/mcp/server.js.map +1 -1
  357. package/docs/adapter-api.md +106 -0
  358. package/docs/cli-reference.md +1316 -63
  359. package/docs/codex-enforced-session.md +103 -0
  360. package/docs/codex-workspace-broker.md +118 -0
  361. package/package.json +14 -2
  362. package/schema/codex-instance.schema.json +82 -0
  363. package/schema/event.schema.json +539 -9
  364. package/schema/fixtures/codex-instance/invalid/unpinned-codex-version.json +40 -0
  365. package/schema/fixtures/codex-instance/valid/canonical.json +40 -0
  366. package/schema/fixtures/event/invalid/approval-granted-sender-hashed-false.json +20 -0
  367. package/schema/fixtures/event/invalid/approval-granted-sender-hashed-raw-id.json +20 -0
  368. package/schema/fixtures/event/invalid/audit-gesture-refused-human-actor.json +16 -0
  369. package/schema/fixtures/event/invalid/audit-gesture-refused-no-actor-no-sender.json +15 -0
  370. package/schema/fixtures/event/invalid/audit-gesture-refused-unknown-gesture.json +16 -0
  371. package/schema/fixtures/event/invalid/audit-question-preempted-agent-actor.json +16 -0
  372. package/schema/fixtures/event/invalid/audit-question-preempted-no-question-id.json +16 -0
  373. package/schema/fixtures/event/invalid/audit-question-preempted-unknown-source.json +15 -0
  374. package/schema/fixtures/event/invalid/gate-path-signed-off-absolute-path.json +14 -0
  375. package/schema/fixtures/event/invalid/gate-path-signed-off-agent-actor.json +14 -0
  376. package/schema/fixtures/event/invalid/gate-path-signed-off-missing-path.json +13 -0
  377. package/schema/fixtures/event/valid/approval-granted-sender-hashed.json +20 -0
  378. package/schema/fixtures/event/valid/audit-gesture-refused-review-note.json +21 -0
  379. package/schema/fixtures/event/valid/audit-gesture-refused-sender-key-unavailable.json +19 -0
  380. package/schema/fixtures/event/valid/audit-gesture-refused.json +19 -0
  381. package/schema/fixtures/event/valid/audit-question-preempted-no-verdict.json +16 -0
  382. package/schema/fixtures/event/valid/audit-question-preempted.json +20 -0
  383. package/schema/fixtures/event/valid/gate-path-signed-off.json +14 -0
  384. package/schema/fixtures/event/valid/harness-kind-claude-code.json +23 -0
  385. package/schema/fixtures/event/valid/harness-kind-codex.json +23 -0
  386. package/schema/fixtures/event/valid/harness-kind-cursor.json +23 -0
  387. package/schema/fixtures/event/valid/harness-kind-grok.json +23 -0
  388. package/schema/fixtures/event/valid/harness-kind-muse.json +23 -0
  389. package/schema/fixtures/policy/invalid/senders-half-keyed.json +20 -0
  390. package/schema/fixtures/policy/valid/canonical.json +1 -1
  391. package/schema/fixtures/policy/valid/senders-keyed.json +24 -0
  392. package/schema/fixtures/policy-md/valid/canonical.md +1 -1
  393. package/schema/fixtures/policy-md/valid/with-values.md +5 -7
  394. package/schema/fixtures/values/invalid/class-shaped.json +1 -1
  395. package/schema/fixtures/values/invalid/duplicate-entry.json +1 -1
  396. package/schema/fixtures/values/invalid/non-string-item.json +1 -1
  397. package/schema/fixtures/values/invalid/over-cap.json +1 -1
  398. package/schema/fixtures/values/invalid/unknown-key.json +1 -1
  399. package/schema/fixtures/values/invalid/version-float.json +1 -0
  400. package/schema/fixtures/values/invalid/version-integer.json +1 -0
  401. package/schema/fixtures/values/invalid/version-wrong-string.json +1 -0
  402. package/schema/fixtures/values/valid/empty-lists.json +2 -3
  403. package/schema/fixtures/values/valid/full.json +5 -7
  404. package/schema/fixtures/values/valid/minimal.json +1 -1
  405. package/schema/fixtures/values-md/invalid/schema-invalid.md +5 -3
  406. package/schema/fixtures/values-md/invalid/two-blocks.md +3 -3
  407. package/schema/fixtures/values-md/invalid/unterminated.md +2 -2
  408. package/schema/fixtures/values-md/invalid/version-1.md +69 -0
  409. package/schema/fixtures/values-md/invalid/version-unquoted.md +64 -0
  410. package/schema/fixtures/values-md/invalid/yaml-error.md +2 -2
  411. package/schema/fixtures/values-md/valid/absent.md +1 -1
  412. package/schema/fixtures/values-md/valid/with-values.md +5 -7
  413. package/schema/policy.schema.json +75 -3
  414. package/schema/values.schema.json +7 -11
  415. package/templates/codex/README.md +9 -0
  416. package/schema/fixtures/values/invalid/version-string.json +0 -1
@@ -217,7 +217,16 @@ const POLICY_RESOLUTION_OUTPUT = object({
217
217
  liveRate: nullable(NUMBER),
218
218
  approvers: nullable(arrayOf(STRING)),
219
219
  limits: nullable(OPEN_OBJECT),
220
- }, ["autonomy", "declaredAutonomy", "supervision", "liveRate", "approvers", "limits"]),
220
+ allowIrreversible: BOOLEAN,
221
+ }, [
222
+ "autonomy",
223
+ "declaredAutonomy",
224
+ "supervision",
225
+ "liveRate",
226
+ "approvers",
227
+ "limits",
228
+ "allowIrreversible",
229
+ ]),
221
230
  // `inherited` since APRV-266: a `policy.edit` sub-class the policy declares
222
231
  // no rule for, decided by the `policy.edit` line it is a sub-class of.
223
232
  provenance: { enum: ["rule", "default", "inherited", "fail-closed", "floor"] },
@@ -227,6 +236,16 @@ const POLICY_RESOLUTION_OUTPUT = object({
227
236
  loadFailure: nullable(object({ code: STRING, message: STRING }, ["code", "message"])),
228
237
  matched: nullable(object({ pattern: STRING, rule: OPEN_OBJECT }, ["pattern", "rule"])),
229
238
  overridden: nullable(object({ pattern: nullable(STRING), autonomy: STRING }, ["pattern", "autonomy"])),
239
+ irreversibility: {
240
+ enum: [
241
+ "not-applicable",
242
+ "policy-allowed",
243
+ "floor-applied",
244
+ "already-manual",
245
+ "human-only",
246
+ ],
247
+ },
248
+ irreversiblePatterns: arrayOf(STRING),
230
249
  candidates: arrayOf(object({
231
250
  pattern: STRING,
232
251
  specificity: { type: "array", items: INTEGER, minItems: 3, maxItems: 3 },
@@ -244,6 +263,8 @@ const POLICY_RESOLUTION_OUTPUT = object({
244
263
  "loadFailure",
245
264
  "matched",
246
265
  "overridden",
266
+ "irreversibility",
267
+ "irreversiblePatterns",
247
268
  "candidates",
248
269
  "decisionPath",
249
270
  ]);
@@ -279,6 +300,16 @@ const VERBS = [
279
300
  error: ERROR_SCHEMA,
280
301
  exit_codes: BASE_EXIT_CODES,
281
302
  },
303
+ {
304
+ name: "quickstart",
305
+ purpose: "Interactive solo setup: asks for a human id, terminal or Telegram, and five manual class families; writes a new policy and identity configuration, shows the exact bytes, requires typed understood, then attests. It classifies policy.core, refuses non-terminal input and --json, and never overwrites an existing policy.",
306
+ human_only: true,
307
+ human_only_note: "This command authors and attests APPROVAL.md and declares APPROVAL_HUMAN. It is reserved to a person at a terminal and is never exposed through MCP.",
308
+ input: input({ flags: { "--dir": "string", "--api-base": "string", ...HELP_FLAGS } }),
309
+ output: null,
310
+ error: ERROR_SCHEMA,
311
+ exit_codes: BASE_EXIT_CODES,
312
+ },
282
313
  {
283
314
  name: "log",
284
315
  subcommand: "verify",
@@ -333,6 +364,32 @@ const VERBS = [
333
364
  error: ERROR_SCHEMA,
334
365
  exit_codes: [OK, { code: 1, meaning: "the log is corrupt; nothing was printed" }, USAGE, TORN, IO],
335
366
  },
367
+ {
368
+ name: "log",
369
+ subcommand: "follow",
370
+ purpose: "Emit one JSON event per line after an exclusive sequence cursor, then follow appends. Every batch is verified from genesis before emission; filesystem notifications only prompt another read. The optional cursor hash binds a resume to the retained prefix. This foreground stream is intentionally excluded from MCP's finite call queue.",
371
+ human_only: false,
372
+ input: input({
373
+ flags: {
374
+ ...LOG_FLAG,
375
+ "--from": "string",
376
+ "--cursor-hash": "string",
377
+ ...JSON_FLAG,
378
+ ...HELP_FLAGS,
379
+ },
380
+ }),
381
+ // A stream has no single finite output object for registry/MCP purposes.
382
+ // Each stdout line is a RECORD, pinned by the CLI end-to-end test.
383
+ output: null,
384
+ error: ERROR_SCHEMA,
385
+ exit_codes: [
386
+ { code: 0, meaning: "cancelled by a signal or downstream pipe closure" },
387
+ { code: 1, meaning: "corrupt log or cursor mismatch" },
388
+ USAGE,
389
+ TORN,
390
+ IO,
391
+ ],
392
+ },
336
393
  // APRV-125. The two verbs that move the log FILE. `human_only` is false on
337
394
  // both: an agent may run them, and the policy decides whether it may — they
338
395
  // classify as `log.sync` and `log.advance` rather than as the gate's own
@@ -396,6 +453,7 @@ const VERBS = [
396
453
  "--remote": "string",
397
454
  "--branch": "string",
398
455
  "--pr": "boolean",
456
+ "--co-author": "string",
399
457
  "--dry-run": "boolean",
400
458
  ...JSON_FLAG,
401
459
  ...HELP_FLAGS,
@@ -441,7 +499,7 @@ const VERBS = [
441
499
  {
442
500
  name: "policy",
443
501
  subcommand: "check",
444
- purpose: "Explain what APPROVAL.md does with one action class: the resolved autonomy, the rule that matched, every candidate with its specificity, and the decision path that produced the answer. Nothing is executed, requested or logged. A policy that fails to load is not an error here: a broken policy IS a manual-everything policy, and that answer is delivered on stdout at exit 0, so branch on manualBecause and provenance rather than on the exit code.",
502
+ purpose: "Explain what APPROVAL.md does with one action class: the resolved autonomy, the rule that matched, every candidate with its specificity, the unanimous max-specificity allow_irreversible decision, and the decision path that produced the answer. Nothing is executed, requested or logged. A policy that fails to load is not an error here: a broken policy IS a manual-everything policy, and that answer is delivered on stdout at exit 0, so branch on manualBecause and provenance rather than on the exit code.",
445
503
  human_only: false,
446
504
  input: input({
447
505
  positionals: positionals([{ name: "class", description: "a concrete action class, e.g. vcs.push.main" }], 1),
@@ -475,12 +533,13 @@ const VERBS = [
475
533
  {
476
534
  name: "policy",
477
535
  subcommand: "attest",
478
- purpose: "Record a human's sign-off on the policy file's exact bytes, as one policy.updated event carrying their SHA-256. Gate operations refuse while the live file is unattested or has changed since the last attestation, so an edited policy is inoperative until a human re-attests it. With --organ <path> it attests one of the gate's ORGANS instead — the harness files that install the hook — as one gate.organ.attested event no gate operation reads: those paths are human-only, so no grant for a hand edit to one can exist and this record is the only evidence the protected-path guard can accept (APRV-272).",
536
+ purpose: "Record a human's sign-off on the policy file's exact bytes, as one policy.updated event carrying their SHA-256. Gate operations refuse while the live file is unattested or has changed since the last attestation, so an edited policy is inoperative until a human re-attests it. With --organ <path> it attests one of the gate's ORGANS instead — the harness files that install the hook — as one gate.organ.attested event no gate operation reads: those paths are human-only, so no grant for a hand edit to one can exist and this record is the only evidence the protected-path guard can accept (APRV-272). With --path <path> it signs off an ordinary PROTECTED path (policy.edit or a policy.edit.* sub-class) as one gate.path.signed_off event, which is what resolves SPEC.md's `(Amended APRV-n, pending sign-off.)` suffix: whole-file evidence that a human read those bytes, weaker than the hunk a grant binds, and read by the protected-path guard only after its grant search has failed (APRV-338). All three routes are human-only, refuse an agent actor with a machine-readable code, and compute their digest in the runtime.",
479
537
  human_only: true,
480
538
  input: input({
481
539
  flags: {
482
540
  ...POLICY_FLAGS,
483
541
  "--organ": "string",
542
+ "--path": "string",
484
543
  ...AS_FLAG,
485
544
  ...LOG_FLAG,
486
545
  ...JSON_FLAG,
@@ -496,6 +555,10 @@ const VERBS = [
496
555
  // repository-relative spelling the record carries, which is the
497
556
  // identity the guard matches on and is not derivable from `path`.
498
557
  organ_path: STRING,
558
+ // The same fact for the --path route, under its own name so that a
559
+ // reader of one object can never take a sign-off for an organ
560
+ // attestation: the two records are different claims (APRV-338).
561
+ signed_path: STRING,
499
562
  }, ["ok", "seq", "sha256", "path"]),
500
563
  error: ERROR_SCHEMA,
501
564
  exit_codes: BASE_EXIT_CODES,
@@ -548,6 +611,37 @@ const VERBS = [
548
611
  error: ERROR_SCHEMA,
549
612
  exit_codes: BASE_EXIT_CODES,
550
613
  },
614
+ {
615
+ name: "policy",
616
+ subcommand: "apply",
617
+ purpose: "Apply a proposal document's quoted Current/Replace-with pairs to APPROVAL.md and then run the amendment, so the edit and its attestation stay one act. It PUBLISHES by default (APRV-360): the amendment runs with --pr, so the branch is created on the remote by refspec, the pull request is opened and auto-merge is armed, and the checkout never moves; --no-publish stops at the commit and --pr is accepted as a no-op. HUMAN-ONLY twice over: an agent identity refuses `apply-agent-actor`, and the verb classifies `policy.core`, which the reference policy holds human-only. Every pair is resolved against an in-memory copy before a byte is written, so a stale proposal writes nothing at all; a whole-file replacement is not accepted, because every byte written is anchored to a byte proved present in the live file. Fences are read by their backtick run, so a wrapper fence around a block is the wrapper it is (APRV-273).",
618
+ human_only: true,
619
+ input: input({
620
+ positionals: positionals([{ name: "proposal", description: "the proposal document to apply" }], 1),
621
+ flags: {
622
+ ...POLICY_FLAGS,
623
+ ...LOG_FLAG,
624
+ ...AS_FLAG,
625
+ "--dry-run": "boolean",
626
+ "--no-amend": "boolean",
627
+ "--pr": "boolean",
628
+ "--no-publish": "boolean",
629
+ "--yes": "boolean",
630
+ ...JSON_FLAG,
631
+ ...HELP_FLAGS,
632
+ },
633
+ }),
634
+ output: object({
635
+ ok: { const: true },
636
+ policy: STRING,
637
+ proposal: STRING,
638
+ pairs: INTEGER,
639
+ noop: BOOLEAN,
640
+ dryRun: BOOLEAN,
641
+ }, ["ok", "policy", "proposal", "pairs", "noop", "dryRun"]),
642
+ error: ERROR_SCHEMA,
643
+ exit_codes: BASE_EXIT_CODES,
644
+ },
551
645
  {
552
646
  name: "register",
553
647
  purpose: "Validate a task file's `approval:` envelope against envelope.schema.json and append one task.registered event carrying the declared actions. FAIL CLOSED: an invalid envelope appends nothing. The file is read only. Registration is a proposal rather than a decision, so an agent may perform it, and it is the step that makes every later question about an action ('what class is this key?') answerable from the log.",
@@ -823,11 +917,12 @@ const VERBS = [
823
917
  },
824
918
  {
825
919
  name: "sandbox",
826
- purpose: "Run a command with outbound network denied by the operating system (macOS sandbox-exec), with the credential-bearing variables scrubbed out of its environment and the credential material beside the log unreadable to it. It exits with the child's own exit code and appends NOTHING: it removes a capability rather than authorizing anything, so there is no record to write and the gate stays reachable because its IPC is a file rather than a socket. This is what the hook cannot do for the commands it merely ALLOWS: `npm test` runs whatever an agent wrote a minute ago, so the command's name stopped describing its effect, and this is how such a command runs where its effects cannot leave. The classifier reads `approval sandbox -- <cmd>` as the class of <cmd>, so wrapping a command neither hides it from the gate nor is punished by it. Refuses with 127 on a machine with no sandbox primitive: it makes one promise and will not run a command it cannot keep that promise for. An agent HARNESS cannot run under this, because a harness needs the model API and that is exactly what is denied.",
920
+ purpose: "Run a command with outbound network denied by the operating system (macOS sandbox-exec), with the credential-bearing variables scrubbed out of its environment and the credential material beside the log unreadable to it. It exits with the child's own exit code and appends NOTHING: it removes a capability rather than authorizing anything, so there is no record to write and the gate stays reachable because its IPC is a file rather than a socket. This is what the hook cannot do for the commands it merely ALLOWS: `npm test` runs whatever an agent wrote a minute ago, so the command's name stopped describing its effect, and this is how such a command runs where its effects cannot leave. The classifier reads `approval sandbox -- <cmd>` as the class of <cmd>, so wrapping a command neither hides it from the gate nor is punished by it. Refuses with 127 on a machine with no sandbox primitive: it makes one promise and will not run a command it cannot keep that promise for. An agent HARNESS cannot run under this, because a harness needs the model API and that is exactly what is denied. Since APRV-347 it also confines what the child may READ: a policy declaring a `read_scope` block turns the profile deny-default for file reads and opens the gate root and whatever that block adds, and `--read-jail` applies the same confinement to one command whether the policy declares a block or not. There is no flag that turns the jail off where a policy asked for it.",
827
921
  human_only: false,
828
922
  input: input({
829
923
  flags: {
830
924
  "--allow-loopback": "boolean",
925
+ "--read-jail": "boolean",
831
926
  ...LOG_FLAG,
832
927
  ...HELP_FLAGS,
833
928
  },
@@ -1672,7 +1767,7 @@ const VERBS = [
1672
1767
  },
1673
1768
  {
1674
1769
  name: "values",
1675
- purpose: "Print the OPTIONAL values block of APPROVAL.md: what the operator loves, likes and dislikes, what they want from an agent as behaviour, and how they read and answer. It is HUMAN-AUTHORED GUIDANCE and it is never policy: it grants nothing, forbids nothing and changes no verdict, and no routing, class match, sampling draw, budget, token or execution decision reads it. Read it at the start of a session and weigh it in HOW you work; what you MAY do is the policy block, answered by `policy check`. A file with no values block exits 0 and says in words that the operator declared no values, which keeps a declared absence distinguishable from not having looked. A block that is present and unreadable exits 1 with its load code and is to be treated as absent. Resolves no policy rule, reads no log, writes nothing.",
1770
+ purpose: "Print the OPTIONAL values block of APPROVAL.md: what the operator loves, likes (which is also where what they ask of an agent as behaviour lives) and dislikes, and how they read and answer. It is HUMAN-AUTHORED GUIDANCE and it is never policy: it grants nothing, forbids nothing and changes no verdict, and no routing, class match, sampling draw, budget, token or execution decision reads it. Read it at the start of a session and weigh it in HOW you work; what you MAY do is the policy block, answered by `policy check`. A file with no values block exits 0 and says in words that the operator declared no values, which keeps a declared absence distinguishable from not having looked. A block that is present and unreadable exits 1 with its load code and is to be treated as absent. Resolves no policy rule, reads no log, writes nothing.",
1676
1771
  human_only: false,
1677
1772
  human_only_note: "Human-AUTHORED and agent-FACING, which is the whole point: the block is the operator writing to the agent, so a surface that withheld it from agents would leave the words with no reader. It carries no authority in either direction. Nothing in it can widen what an agent may do, because no enforcement path reads it (SPEC.md §11.1 invariant 10), and an agent cannot write it: the block lives inside APPROVAL.md, which is `policy.core` and rides the whole-file attestation.",
1678
1773
  input: input({
@@ -1752,6 +1847,19 @@ const VERBS = [
1752
1847
  error: ERROR_SCHEMA,
1753
1848
  exit_codes: BASE_EXIT_CODES,
1754
1849
  },
1850
+ {
1851
+ name: "setup",
1852
+ subcommand: "sender-key",
1853
+ purpose: "Mint the operator-held key that turns a channel account id into the value an `approvers[id].senders` mapping carries (APRV-370), store it, and record where it lives. A published policy and a published log disclose the account otherwise, and a plain unkeyed digest would not fix that: a Telegram id is a short decimal number and the whole space is enumerable. It does not edit an attested policy. INTERACTIVE ONLY — except `--id <account-id>`, which mints and stores nothing and prints the `hmac-sha256:<hex>` mapping line for one account under the key already in the environment, so it runs anywhere.",
1854
+ human_only: true,
1855
+ human_only_note: "Minting it is minting the value every sender mapping is then written against, and an agent that could mint one could re-key the mapping and make every account in the policy unresolvable. The verb classifies policy.core. `--id` is a computation over a key the caller already holds and prints a value designed to be published, so it is not the human-only half.",
1856
+ input: input({
1857
+ flags: { "--id": "string", ...AS_FLAG, ...LOG_FLAG, ...POLICY_FLAGS, ...HELP_FLAGS },
1858
+ }),
1859
+ output: null,
1860
+ error: ERROR_SCHEMA,
1861
+ exit_codes: BASE_EXIT_CODES,
1862
+ },
1755
1863
  {
1756
1864
  name: "setup",
1757
1865
  subcommand: "checkpoint",
@@ -1898,9 +2006,9 @@ const VERBS = [
1898
2006
  {
1899
2007
  name: "adapter",
1900
2008
  subcommand: "email",
1901
- purpose: "Execute one approved action through the email adapter: send a single RFC 5322 message over SMTP for a communicate.email.external action. The runtime — not the adapter — recomputes the payload hash, spends the token, and writes both execution events around the send, and the credentials leave the vault only inside that verified-token window. This is the hard boundary of SPEC.md §10.4.",
2009
+ purpose: "Execute one action through the email adapter: send a single RFC 5322 message over SMTP for a communicate.email.external action. The runtime recomputes the payload hash, applies attested policy, and writes both execution events around the send. Manual and selected-live paths spend a grant token; an explicitly policy-authorized supervised or autonomous path has no token. Credentials leave the vault only inside the execution window. This is the hard boundary of SPEC.md §10.4.",
1902
2010
  human_only: false,
1903
- human_only_note: "Agent-facing on purpose. It executes inside the token window with a token a human granted for these exact bytes, which is the authority an executing agent is meant to hold; the adapter refuses everything else. Making it human-only would move the send back to a human and leave the token doing nothing.",
2011
+ human_only_note: "Agent-facing on purpose. Manual and selected-live execution uses a token a human granted for these exact bytes. Explicitly opted-in supervised and autonomous execution follows attested policy without minting a token. The adapter refuses every path the core does not admit.",
1904
2012
  input: input({
1905
2013
  positionals: positionals([{ name: "action-key", description: "the action's idempotency_key" }], 1),
1906
2014
  flags: {
@@ -1949,15 +2057,15 @@ const VERBS = [
1949
2057
  USAGE,
1950
2058
  TORN,
1951
2059
  IO,
1952
- { code: 5, meaning: "no valid execution token; nothing was appended and nothing was sent" },
2060
+ { code: 5, meaning: "the effective manual path needs a valid execution token; nothing was appended and nothing was sent" },
1953
2061
  ],
1954
2062
  },
1955
2063
  {
1956
2064
  name: "adapter",
1957
2065
  subcommand: "agentmail",
1958
- purpose: "Execute one approved action through the AgentMail adapter: a direct send over the AgentMail API, or the send of a draft the agent already composed. The draft mode re-reads the draft and refuses `agentmail-draft-drifted` when any approved field changed, because a grant is over a snapshot of the words and not over a mutable draft id. AgentMail has no per-message From — the inbox is the sender — so the approved `from` is checked against the inbox's own address before anything is sent. The runtime, not the adapter, recomputes the payload hash, spends the token and writes both execution events, and the vault's sending key leaves it only inside that window.",
2066
+ purpose: "Execute one action through the AgentMail adapter: a direct send over the AgentMail API, or the send of a draft the agent already composed. The draft mode re-reads the draft and refuses `agentmail-draft-drifted` when any bound field changed, because authority covers a snapshot of the words and not a mutable draft id. AgentMail has no per-message From — the inbox is the sender — so the bound `from` is checked against the inbox's own address before anything is sent. The runtime recomputes the payload hash, applies attested policy and writes both execution events. Manual and selected-live paths spend a grant token; explicitly opted-in supervised and autonomous paths do not mint one.",
1959
2067
  human_only: false,
1960
- human_only_note: "Agent-facing for the reason `adapter email` is: it executes inside the token window with a token a human granted for these exact bytes. The split that makes it safe is in the keys, not in the caller — the agent's own AgentMail key cannot send, and the one that can lives in the vault.",
2068
+ human_only_note: "Agent-facing for the reason `adapter email` is. Manual and selected-live paths use a token granted for the exact bytes; explicitly opted-in supervised and autonomous paths follow attested policy without one. The split that makes it safe is in the keys: the agent's own AgentMail key cannot send, and the one that can lives in the vault.",
1961
2069
  input: input({
1962
2070
  positionals: positionals([{ name: "action-key", description: "the action's idempotency_key" }], 1),
1963
2071
  flags: {
@@ -2006,9 +2114,31 @@ const VERBS = [
2006
2114
  USAGE,
2007
2115
  TORN,
2008
2116
  IO,
2009
- { code: 5, meaning: "no valid execution token; nothing was appended and nothing was sent" },
2117
+ { code: 5, meaning: "the effective manual path needs a valid execution token; nothing was appended and nothing was sent" },
2010
2118
  ],
2011
2119
  },
2120
+ {
2121
+ name: "adapter",
2122
+ subcommand: "zzz",
2123
+ purpose: "Execute one zzz.bot create-thread or create-reply action. The tagged payload selects a fixed production or preview origin and binds the destination, body, metadata, tags and references. The runtime applies attested policy before the write-capable Bearer token leaves the vault. Manual and selected-live paths spend a grant token; explicitly opted-in supervised and autonomous paths do not mint one. The provider Idempotency-Key is derived from the action key and payload hash.",
2124
+ human_only: false,
2125
+ human_only_note: "Agent-facing because the shared adapter contract verifies the exact payload and applies attested policy before the vault credential can be used. It spends a token on manual and selected-live paths.",
2126
+ input: input({
2127
+ positionals: positionals([{ name: "action-key", description: "the action's idempotency_key" }], 1),
2128
+ flags: {
2129
+ "--token": "string", "--payload": "string", ...AS_FLAG, "--vault": "string",
2130
+ ...POLICY_FLAGS, ...LOG_FLAG, "--timeout": "string", ...JSON_FLAG, ...HELP_FLAGS,
2131
+ },
2132
+ }),
2133
+ output: object({
2134
+ ok: { const: true }, adapter: { const: "zzz" }, action_key: STRING,
2135
+ task: STRING, class: STRING, autonomy: STRING, payload_hash: SHA256,
2136
+ started_seq: INTEGER, outcome: { enum: ["execution.completed", "execution.failed"] },
2137
+ outcome_seq: INTEGER, exit_code: nullable(INTEGER), detail: OPEN_OBJECT, redactions: INTEGER,
2138
+ }, ["ok", "adapter", "action_key", "task", "class", "autonomy", "payload_hash", "started_seq", "outcome", "outcome_seq", "exit_code"]),
2139
+ error: ERROR_SCHEMA,
2140
+ exit_codes: [OK, INTEGRITY, USAGE, TORN, IO, { code: 5, meaning: "the effective manual path needs a valid execution token; nothing was appended and nothing was sent" }],
2141
+ },
2012
2142
  {
2013
2143
  name: "hook",
2014
2144
  subcommand: "claude-code",
@@ -2055,6 +2185,78 @@ const VERBS = [
2055
2185
  { code: 2, meaning: "the hook is misconfigured; the harness blocks and reads stderr" },
2056
2186
  ],
2057
2187
  },
2188
+ {
2189
+ name: "hook",
2190
+ subcommand: "codex",
2191
+ purpose: "Read one Codex PreToolUse or PostToolUse event on stdin and strictly validate its stable ids, tool, and visible working directory. PreToolUse denies Bash because Codex does not expose its effective per-call workdir; direct apply_patch is an experimental bounded gate surface and receives nested allow or deny JSON. Manual patch classes wait on a log-backed decision. PostToolUse records an outcome only when a native-verified closed reading exists. THE VERDICT IS NEVER 'ask'. Exit 0 carries a pre-tool verdict, while a post-tool diagnostic uses the post-hook status contract.",
2192
+ human_only: false,
2193
+ human_only_note: "The agent harness surface, so agent-facing by construction: Codex invokes it around the agent's own Bash and apply_patch calls. Bash is refused before gate intake; direct patches can record the agent's proposal and wait for a human. It never records a decision.",
2194
+ input: input({
2195
+ flags: {
2196
+ ...AS_FLAG,
2197
+ "--timeout": "string",
2198
+ "--interval": "string",
2199
+ "--retry-grace": "string",
2200
+ ...POLICY_FLAGS,
2201
+ ...LOG_FLAG,
2202
+ ...HELP_FLAGS,
2203
+ },
2204
+ }),
2205
+ output: null,
2206
+ error: ERROR_SCHEMA,
2207
+ exit_codes: [
2208
+ { code: 0, meaning: "the PreToolUse verdict (allow OR deny) is the JSON object on stdout, or a reported PostToolUse counterpart landed" },
2209
+ { code: 2, meaning: "the hook is misconfigured or a PostToolUse outcome was not recorded; the diagnostic is on stderr" },
2210
+ ],
2211
+ },
2212
+ {
2213
+ name: "hook",
2214
+ subcommand: "grok",
2215
+ purpose: "Read one Grok Build PreToolUse event on stdin (camelCase keys), classify its Bash command and its Edit, Write, MultiEdit and NotebookEdit paths, resolve the class against APPROVAL.md, and answer {decision, reason} on stdout — waiting on a real decision when the class is manual. THE VERDICT IS NEVER 'ask'. A DENY IS EXIT 2, not exit 0 with a body: Grok reads the exit code, so the Claude dialect's exit-0 deny would be read as an allow, and Grok states that it reads .claude/settings.json for compatibility, which is how that dialect can fire under a Grok session in the first place. Exit 0 is an allow whatever stdout said.",
2216
+ human_only: false,
2217
+ human_only_note: "The agent harness surface, so agent-facing by construction: Grok Build invokes it around the agent's own tool calls. It records the agent's proposal and waits for a human; it never records a decision.",
2218
+ input: input({
2219
+ flags: {
2220
+ ...AS_FLAG,
2221
+ "--timeout": "string",
2222
+ "--interval": "string",
2223
+ "--retry-grace": "string",
2224
+ ...POLICY_FLAGS,
2225
+ ...LOG_FLAG,
2226
+ ...HELP_FLAGS,
2227
+ },
2228
+ }),
2229
+ output: null,
2230
+ error: ERROR_SCHEMA,
2231
+ exit_codes: [
2232
+ { code: 0, meaning: "the tool call is allowed; the {decision, reason} object is on stdout" },
2233
+ { code: 2, meaning: "the tool call is DENIED, or the hook is misconfigured; either way Grok blocks and reads the reason" },
2234
+ ],
2235
+ },
2236
+ {
2237
+ name: "hook",
2238
+ subcommand: "muse",
2239
+ purpose: "Read one Meta Muse Code PreToolUse or PostToolUse event on stdin (snake_case), classify its bash command or its write_file, read_file and search paths, resolve the class against APPROVAL.md, and answer allow or deny — waiting on a real decision when the class is manual. THE VERDICT IS NEVER 'ask'. It answers in ONE dialect and nothing else, the nested permissionDecision object at exit 0, because Muse treats output carrying any unsupported key as a failed hook and a failed hook FAILS OPEN. A Contributor-tier model is refused for every tool call regardless of policy (hook-muse-contributor-model): Meta trains on that tier's prompts and completions, so every read is a disclosure. Muse fails open on hook crash, timeout and malformed output, so this is enforcement only while the hook is healthy and answers inside the timeout the human commits.",
2240
+ human_only: false,
2241
+ human_only_note: "The agent harness surface, so agent-facing by construction: Muse invokes it around the agent's own tool calls. It proposes and waits; it never records a decision.",
2242
+ input: input({
2243
+ flags: {
2244
+ ...AS_FLAG,
2245
+ "--timeout": "string",
2246
+ "--interval": "string",
2247
+ "--retry-grace": "string",
2248
+ ...POLICY_FLAGS,
2249
+ ...LOG_FLAG,
2250
+ ...HELP_FLAGS,
2251
+ },
2252
+ }),
2253
+ output: null,
2254
+ error: ERROR_SCHEMA,
2255
+ exit_codes: [
2256
+ { code: 0, meaning: "the PreToolUse verdict (allow OR deny) is the JSON object on stdout, or a reported PostToolUse counterpart landed" },
2257
+ { code: 2, meaning: "the hook is misconfigured or a PostToolUse outcome was not recorded; the diagnostic is on stderr" },
2258
+ ],
2259
+ },
2058
2260
  {
2059
2261
  name: "hook",
2060
2262
  subcommand: "classify",
@@ -2099,6 +2301,137 @@ const VERBS = [
2099
2301
  error: ERROR_SCHEMA,
2100
2302
  exit_codes: BASE_EXIT_CODES,
2101
2303
  },
2304
+ {
2305
+ name: "codex",
2306
+ subcommand: "prepare",
2307
+ purpose: "Write a fresh inert review bundle for a constrained Codex host. It writes only --output, activates nothing, and cannot establish enforcement.",
2308
+ human_only: true,
2309
+ human_only_note: "Host preparation is an operator workflow and is excluded with the whole codex family from the broad agent MCP catalog.",
2310
+ input: input({
2311
+ flags: {
2312
+ "--instance": "string", "--workspace": "string", "--primary": "string",
2313
+ "--install-root": "string", "--output": "string", "--codex": "string", "--node": "string",
2314
+ ...JSON_FLAG, ...HELP_FLAGS,
2315
+ },
2316
+ }),
2317
+ output: object({ ok: { const: true }, inert: { const: true }, output: STRING, files: arrayOf(STRING), manifest: OPEN_OBJECT }, ["ok", "inert", "output", "files", "manifest"]),
2318
+ error: ERROR_SCHEMA,
2319
+ exit_codes: [OK, INTEGRITY, USAGE, IO],
2320
+ },
2321
+ {
2322
+ name: "codex",
2323
+ subcommand: "setup",
2324
+ purpose: "Verify a prepared Codex bundle's exact file set, hashes, manifest, and generated bytes. Success means internally consistent and inert, never installed or ready.",
2325
+ human_only: true,
2326
+ human_only_note: "Setup verification belongs to the operator and is absent from the broad agent MCP catalog.",
2327
+ input: input({ flags: { "--check": "string", ...JSON_FLAG, ...HELP_FLAGS } }),
2328
+ output: object({
2329
+ ok: { const: true }, inert: { const: true }, ready: { const: false },
2330
+ bundle: STRING, files: arrayOf(STRING), reason: { const: "broker-and-runner-not-shipped" },
2331
+ }, ["ok", "inert", "ready", "bundle", "files", "reason"]),
2332
+ error: ERROR_SCHEMA,
2333
+ exit_codes: [OK, INTEGRITY, USAGE, IO],
2334
+ },
2335
+ {
2336
+ name: "codex",
2337
+ subcommand: "doctor",
2338
+ purpose: "Fail-closed inspection of the manifest, platform, pinned version declarations, principals, path separation, symlinks, ownership, modes, invocation, broker and runner. It executes no manifest binary and APRV-325.1 always reports runtime versions unchecked and not ready.",
2339
+ human_only: true,
2340
+ human_only_note: "Strict host custody inspection is an operator surface and is absent from the broad agent MCP catalog.",
2341
+ input: input({ flags: { "--manifest": "string", "--strict": "boolean", ...JSON_FLAG, ...HELP_FLAGS } }),
2342
+ output: null,
2343
+ error: ERROR_SCHEMA,
2344
+ exit_codes: [OK, INTEGRITY, USAGE, IO],
2345
+ },
2346
+ {
2347
+ name: "codex",
2348
+ subcommand: "apply",
2349
+ purpose: "Apply one bounded typed workspace proposal through the gate (APRV-325.2). The manifest supplies the actor, workspace root, policy and log, and the proposal file supplies only operations and the policy digest it was built against; an unknown key is refused rather than ignored. One action is registered per distinct path class and never collapsed, every leg is authorized and started before any byte moves, and the change is staged, journaled and applied under a workspace lock. The outcome reported is what reading the workspace back proved: applied, not applied, or honestly unknown.",
2350
+ human_only: true,
2351
+ human_only_note: "The broker is reached by a constrained Codex session through `codex serve`, which publishes exactly one tool. Publishing this verb on the broad agent MCP catalog would put a second door beside that one, and the whole point of the strict server is that there is only the one.",
2352
+ input: input({
2353
+ flags: {
2354
+ "--manifest": "string",
2355
+ "--proposal": "string",
2356
+ "--token": "string",
2357
+ "--require-exclusive-custody": "boolean",
2358
+ ...JSON_FLAG,
2359
+ ...HELP_FLAGS,
2360
+ },
2361
+ }),
2362
+ output: object({
2363
+ ok: { const: true },
2364
+ version: { const: "approval.codex.broker.v1" },
2365
+ task: STRING,
2366
+ payload_hash: SHA256,
2367
+ policy_sha256: SHA256,
2368
+ legs: arrayOf(object({ class: STRING, actionKey: STRING, mode: { enum: ["policy", "token"] } }, ["class", "actionKey", "mode"])),
2369
+ custody: object({ kind: { enum: ["os-exclusive", "advisory"] }, findings: arrayOf(STRING) }, ["kind", "findings"]),
2370
+ state: { const: "after" },
2371
+ }, ["ok", "version", "task", "payload_hash", "policy_sha256", "legs", "custody", "state"]),
2372
+ error: ERROR_SCHEMA,
2373
+ exit_codes: [OK, INTEGRITY, USAGE, IO],
2374
+ },
2375
+ {
2376
+ name: "codex",
2377
+ subcommand: "recover",
2378
+ purpose: "Read a workspace's retained transaction journal and report whether the workspace is in the approved before-state, the approved after-state, or neither. It changes nothing: a mixed workspace is a person's to reconcile, and a recovery that rolled one either way would be guessing which half was approved. Exits 1 on mixed.",
2379
+ human_only: true,
2380
+ human_only_note: "Reading a half-applied workspace is an operator's diagnosis and belongs beside the reconcile verb, which is human-only for the same reason.",
2381
+ input: input({ flags: { "--manifest": "string", ...JSON_FLAG, ...HELP_FLAGS } }),
2382
+ output: null,
2383
+ error: ERROR_SCHEMA,
2384
+ exit_codes: [OK, INTEGRITY, USAGE, IO],
2385
+ },
2386
+ {
2387
+ name: "codex",
2388
+ subcommand: "start",
2389
+ purpose: "Prepare a confined Codex session and, with `-- <command>`, run something inside it (APRV-325.3). The shell gets a disposable workspace that is the ONLY path it may write; the canonical workspace is readable and never writable; reads are jailed to exactly those two roots, so the gate home and everything else the host holds are unreadable; the environment is an allow-list rather than a filtered copy of the operator's; and outbound network is denied with loopback. There is no opt-out flag and no unwrapped fallback: a host with no sandbox mechanism refuses rather than running the shell and calling it confined. With no `-- <command>` it reports the room and runs nothing. Its exit code is the child's.",
2390
+ human_only: true,
2391
+ human_only_note: "Starting a constrained host session is an operator action and is absent from broad MCP.",
2392
+ input: input({
2393
+ flags: { "--manifest": "string", "--timeout": "string", ...JSON_FLAG, ...HELP_FLAGS },
2394
+ trailing: TRAILING,
2395
+ }),
2396
+ output: null,
2397
+ error: ERROR_SCHEMA,
2398
+ exit_codes: [OK, INTEGRITY, USAGE],
2399
+ },
2400
+ {
2401
+ name: "codex",
2402
+ subcommand: "serve",
2403
+ purpose: "Serve the workspace broker over stdio as EXACTLY ONE MCP tool, `codex_workspace_apply`, with a positive server-side allowlist checked at call time as well as at list time. Distinct from `mcp serve`, whose catalog is this whole registry: a constrained session must reach one door and the same door next month. The published input schema carries no identity, path, class, token or sandbox argument, because none exists to remove.",
2404
+ human_only: true,
2405
+ human_only_note: "The strict server is separate from and never published by the broad MCP server; starting one is an operator's act, as `mcp serve` is.",
2406
+ input: input({ flags: { "--manifest": "string", "--require-exclusive-custody": "boolean", ...JSON_FLAG, ...HELP_FLAGS } }),
2407
+ output: null,
2408
+ error: ERROR_SCHEMA,
2409
+ exit_codes: [OK, INTEGRITY, USAGE, IO],
2410
+ },
2411
+ {
2412
+ name: "codex",
2413
+ subcommand: "bridge",
2414
+ purpose: "Start `codex app-server` and answer every approval request it raises through the policy and the log (APRV-361). Each exec request carries `command` and `cwd` on one frame, minted by the harness runtime, which is the pair the native hook lacks and refuses for want of; the request goes through the hook's own decision path — classify, the human-only refusal, the loop floor, register, request, wait on the verified view — and the answer is `{id, result: {decision}}` on the connection. Accept or decline only, in the vocabulary the request advertised, never `acceptForSession`, `cancel` or `abort`. The deadline is the policy's `approval_ttl`, because this transport has no timeout. An ADVISORY checkpoint and never a boundary: see docs/codex-app-server-bridge.md.",
2415
+ human_only: true,
2416
+ human_only_note: "An OPERATOR process, like `codex serve`: it launches a long-lived server, holds the acting identity every answer is recorded under, and decides questions on a connection this transport owns. An agent that could start one would gain a second writer against the log nobody supervises.",
2417
+ input: input({
2418
+ flags: {
2419
+ "--prompt": "string",
2420
+ "--workspace": "string",
2421
+ ...AS_FLAG,
2422
+ ...POLICY_FLAGS,
2423
+ ...LOG_FLAG,
2424
+ "--wait": "string",
2425
+ "--interval": "string",
2426
+ ...JSON_FLAG,
2427
+ ...HELP_FLAGS,
2428
+ },
2429
+ trailing: TRAILING,
2430
+ }),
2431
+ output: null,
2432
+ error: ERROR_SCHEMA,
2433
+ exit_codes: [OK, USAGE, IO],
2434
+ },
2102
2435
  {
2103
2436
  name: "mcp",
2104
2437
  subcommand: "serve",