@cluesmith/codev 3.2.4 → 3.3.1

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 (394) hide show
  1. package/dashboard-dist/assets/index-BZRTEMtH.css +32 -0
  2. package/dashboard-dist/assets/{index-BZ1x7x1X.js → index-D3XaKpZW.js} +46 -44
  3. package/dashboard-dist/assets/index-D3XaKpZW.js.map +1 -0
  4. package/dashboard-dist/index.html +2 -2
  5. package/dist/agent-farm/cli.d.ts.map +1 -1
  6. package/dist/agent-farm/cli.js +154 -0
  7. package/dist/agent-farm/cli.js.map +1 -1
  8. package/dist/agent-farm/commands/cleanup.d.ts.map +1 -1
  9. package/dist/agent-farm/commands/cleanup.js +16 -0
  10. package/dist/agent-farm/commands/cleanup.js.map +1 -1
  11. package/dist/agent-farm/commands/inbox.d.ts +42 -0
  12. package/dist/agent-farm/commands/inbox.d.ts.map +1 -0
  13. package/dist/agent-farm/commands/inbox.js +129 -0
  14. package/dist/agent-farm/commands/inbox.js.map +1 -0
  15. package/dist/agent-farm/commands/interrupt.d.ts +20 -0
  16. package/dist/agent-farm/commands/interrupt.d.ts.map +1 -0
  17. package/dist/agent-farm/commands/interrupt.js +65 -0
  18. package/dist/agent-farm/commands/interrupt.js.map +1 -0
  19. package/dist/agent-farm/commands/reset/constants.d.ts +52 -0
  20. package/dist/agent-farm/commands/reset/constants.d.ts.map +1 -0
  21. package/dist/agent-farm/commands/reset/constants.js +52 -0
  22. package/dist/agent-farm/commands/reset/constants.js.map +1 -0
  23. package/dist/agent-farm/commands/reset/context.d.ts +230 -0
  24. package/dist/agent-farm/commands/reset/context.d.ts.map +1 -0
  25. package/dist/agent-farm/commands/reset/context.js +428 -0
  26. package/dist/agent-farm/commands/reset/context.js.map +1 -0
  27. package/dist/agent-farm/commands/reset/index.d.ts +192 -0
  28. package/dist/agent-farm/commands/reset/index.d.ts.map +1 -0
  29. package/dist/agent-farm/commands/reset/index.js +488 -0
  30. package/dist/agent-farm/commands/reset/index.js.map +1 -0
  31. package/dist/agent-farm/commands/reset/receipt.d.ts +97 -0
  32. package/dist/agent-farm/commands/reset/receipt.d.ts.map +1 -0
  33. package/dist/agent-farm/commands/reset/receipt.js +149 -0
  34. package/dist/agent-farm/commands/reset/receipt.js.map +1 -0
  35. package/dist/agent-farm/commands/reset/reorient.d.ts +117 -0
  36. package/dist/agent-farm/commands/reset/reorient.d.ts.map +1 -0
  37. package/dist/agent-farm/commands/reset/reorient.js +313 -0
  38. package/dist/agent-farm/commands/reset/reorient.js.map +1 -0
  39. package/dist/agent-farm/commands/reset.d.ts +34 -0
  40. package/dist/agent-farm/commands/reset.d.ts.map +1 -0
  41. package/dist/agent-farm/commands/reset.js +309 -0
  42. package/dist/agent-farm/commands/reset.js.map +1 -0
  43. package/dist/agent-farm/commands/send.d.ts.map +1 -1
  44. package/dist/agent-farm/commands/send.js +49 -8
  45. package/dist/agent-farm/commands/send.js.map +1 -1
  46. package/dist/agent-farm/commands/spawn-worktree.d.ts +105 -6
  47. package/dist/agent-farm/commands/spawn-worktree.d.ts.map +1 -1
  48. package/dist/agent-farm/commands/spawn-worktree.js +289 -66
  49. package/dist/agent-farm/commands/spawn-worktree.js.map +1 -1
  50. package/dist/agent-farm/commands/spawn.d.ts.map +1 -1
  51. package/dist/agent-farm/commands/spawn.js +13 -1
  52. package/dist/agent-farm/commands/spawn.js.map +1 -1
  53. package/dist/agent-farm/commands/status.d.ts.map +1 -1
  54. package/dist/agent-farm/commands/status.js +80 -8
  55. package/dist/agent-farm/commands/status.js.map +1 -1
  56. package/dist/agent-farm/commands/tower.d.ts.map +1 -1
  57. package/dist/agent-farm/commands/tower.js +13 -0
  58. package/dist/agent-farm/commands/tower.js.map +1 -1
  59. package/dist/agent-farm/db/index.d.ts +1 -1
  60. package/dist/agent-farm/db/index.d.ts.map +1 -1
  61. package/dist/agent-farm/db/index.js +80 -1
  62. package/dist/agent-farm/db/index.js.map +1 -1
  63. package/dist/agent-farm/db/mailbox.d.ts +222 -0
  64. package/dist/agent-farm/db/mailbox.d.ts.map +1 -0
  65. package/dist/agent-farm/db/mailbox.js +304 -0
  66. package/dist/agent-farm/db/mailbox.js.map +1 -0
  67. package/dist/agent-farm/db/schema.d.ts +1 -1
  68. package/dist/agent-farm/db/schema.d.ts.map +1 -1
  69. package/dist/agent-farm/db/schema.js +35 -0
  70. package/dist/agent-farm/db/schema.js.map +1 -1
  71. package/dist/agent-farm/db/types.d.ts +45 -0
  72. package/dist/agent-farm/db/types.d.ts.map +1 -1
  73. package/dist/agent-farm/db/types.js.map +1 -1
  74. package/dist/agent-farm/lib/builder-lookup.d.ts +1 -1
  75. package/dist/agent-farm/lib/builder-lookup.js +2 -2
  76. package/dist/agent-farm/lib/builder-lookup.js.map +1 -1
  77. package/dist/agent-farm/lib/reconnect-backoff.d.ts +64 -0
  78. package/dist/agent-farm/lib/reconnect-backoff.d.ts.map +1 -0
  79. package/dist/agent-farm/lib/reconnect-backoff.js +57 -0
  80. package/dist/agent-farm/lib/reconnect-backoff.js.map +1 -0
  81. package/dist/agent-farm/lib/tower-client.d.ts +16 -6
  82. package/dist/agent-farm/lib/tower-client.d.ts.map +1 -1
  83. package/dist/agent-farm/lib/tower-client.js +37 -6
  84. package/dist/agent-farm/lib/tower-client.js.map +1 -1
  85. package/dist/agent-farm/lib/tunnel-client.d.ts +69 -1
  86. package/dist/agent-farm/lib/tunnel-client.d.ts.map +1 -1
  87. package/dist/agent-farm/lib/tunnel-client.js +225 -30
  88. package/dist/agent-farm/lib/tunnel-client.js.map +1 -1
  89. package/dist/agent-farm/servers/canvas-relay.d.ts +60 -0
  90. package/dist/agent-farm/servers/canvas-relay.d.ts.map +1 -0
  91. package/dist/agent-farm/servers/canvas-relay.js +376 -0
  92. package/dist/agent-farm/servers/canvas-relay.js.map +1 -0
  93. package/dist/agent-farm/servers/cron-delivery.d.ts +72 -0
  94. package/dist/agent-farm/servers/cron-delivery.d.ts.map +1 -0
  95. package/dist/agent-farm/servers/cron-delivery.js +80 -0
  96. package/dist/agent-farm/servers/cron-delivery.js.map +1 -0
  97. package/dist/agent-farm/servers/delayed-send.d.ts +85 -0
  98. package/dist/agent-farm/servers/delayed-send.d.ts.map +1 -0
  99. package/dist/agent-farm/servers/delayed-send.js +165 -0
  100. package/dist/agent-farm/servers/delayed-send.js.map +1 -0
  101. package/dist/agent-farm/servers/gate-profiles.d.ts +67 -0
  102. package/dist/agent-farm/servers/gate-profiles.d.ts.map +1 -0
  103. package/dist/agent-farm/servers/gate-profiles.js +113 -0
  104. package/dist/agent-farm/servers/gate-profiles.js.map +1 -0
  105. package/dist/agent-farm/servers/mailbox-delivery.d.ts +370 -0
  106. package/dist/agent-farm/servers/mailbox-delivery.d.ts.map +1 -0
  107. package/dist/agent-farm/servers/mailbox-delivery.js +617 -0
  108. package/dist/agent-farm/servers/mailbox-delivery.js.map +1 -0
  109. package/dist/agent-farm/servers/mailbox-wiring.d.ts +125 -0
  110. package/dist/agent-farm/servers/mailbox-wiring.d.ts.map +1 -0
  111. package/dist/agent-farm/servers/mailbox-wiring.js +425 -0
  112. package/dist/agent-farm/servers/mailbox-wiring.js.map +1 -0
  113. package/dist/agent-farm/servers/message-write.d.ts +53 -1
  114. package/dist/agent-farm/servers/message-write.d.ts.map +1 -1
  115. package/dist/agent-farm/servers/message-write.js +63 -0
  116. package/dist/agent-farm/servers/message-write.js.map +1 -1
  117. package/dist/agent-farm/servers/overview.d.ts +19 -0
  118. package/dist/agent-farm/servers/overview.d.ts.map +1 -1
  119. package/dist/agent-farm/servers/overview.js +100 -4
  120. package/dist/agent-farm/servers/overview.js.map +1 -1
  121. package/dist/agent-farm/servers/render-gate.d.ts +141 -0
  122. package/dist/agent-farm/servers/render-gate.d.ts.map +1 -0
  123. package/dist/agent-farm/servers/render-gate.js +251 -0
  124. package/dist/agent-farm/servers/render-gate.js.map +1 -0
  125. package/dist/agent-farm/servers/session-submit.d.ts +90 -0
  126. package/dist/agent-farm/servers/session-submit.d.ts.map +1 -0
  127. package/dist/agent-farm/servers/session-submit.js +127 -0
  128. package/dist/agent-farm/servers/session-submit.js.map +1 -0
  129. package/dist/agent-farm/servers/tower-cron.d.ts +10 -7
  130. package/dist/agent-farm/servers/tower-cron.d.ts.map +1 -1
  131. package/dist/agent-farm/servers/tower-cron.js +58 -53
  132. package/dist/agent-farm/servers/tower-cron.js.map +1 -1
  133. package/dist/agent-farm/servers/tower-instances.d.ts +14 -2
  134. package/dist/agent-farm/servers/tower-instances.d.ts.map +1 -1
  135. package/dist/agent-farm/servers/tower-instances.js +78 -16
  136. package/dist/agent-farm/servers/tower-instances.js.map +1 -1
  137. package/dist/agent-farm/servers/tower-messages.d.ts +38 -1
  138. package/dist/agent-farm/servers/tower-messages.d.ts.map +1 -1
  139. package/dist/agent-farm/servers/tower-messages.js +106 -1
  140. package/dist/agent-farm/servers/tower-messages.js.map +1 -1
  141. package/dist/agent-farm/servers/tower-routes.d.ts +16 -4
  142. package/dist/agent-farm/servers/tower-routes.d.ts.map +1 -1
  143. package/dist/agent-farm/servers/tower-routes.js +826 -145
  144. package/dist/agent-farm/servers/tower-routes.js.map +1 -1
  145. package/dist/agent-farm/servers/tower-server.js +188 -34
  146. package/dist/agent-farm/servers/tower-server.js.map +1 -1
  147. package/dist/agent-farm/servers/tower-terminals.d.ts +23 -2
  148. package/dist/agent-farm/servers/tower-terminals.d.ts.map +1 -1
  149. package/dist/agent-farm/servers/tower-terminals.js +134 -127
  150. package/dist/agent-farm/servers/tower-terminals.js.map +1 -1
  151. package/dist/agent-farm/servers/tower-tunnel.d.ts.map +1 -1
  152. package/dist/agent-farm/servers/tower-tunnel.js +63 -4
  153. package/dist/agent-farm/servers/tower-tunnel.js.map +1 -1
  154. package/dist/agent-farm/servers/tower-types.d.ts +2 -1
  155. package/dist/agent-farm/servers/tower-types.d.ts.map +1 -1
  156. package/dist/agent-farm/servers/tower-utils.d.ts +64 -1
  157. package/dist/agent-farm/servers/tower-utils.d.ts.map +1 -1
  158. package/dist/agent-farm/servers/tower-utils.js +168 -1
  159. package/dist/agent-farm/servers/tower-utils.js.map +1 -1
  160. package/dist/agent-farm/servers/tower-websocket.d.ts +6 -1
  161. package/dist/agent-farm/servers/tower-websocket.d.ts.map +1 -1
  162. package/dist/agent-farm/servers/tower-websocket.js +95 -57
  163. package/dist/agent-farm/servers/tower-websocket.js.map +1 -1
  164. package/dist/agent-farm/servers/write-queue.d.ts +35 -0
  165. package/dist/agent-farm/servers/write-queue.d.ts.map +1 -0
  166. package/dist/agent-farm/servers/write-queue.js +56 -0
  167. package/dist/agent-farm/servers/write-queue.js.map +1 -0
  168. package/dist/agent-farm/types.d.ts +39 -0
  169. package/dist/agent-farm/types.d.ts.map +1 -1
  170. package/dist/agent-farm/utils/agent-names.d.ts +2 -2
  171. package/dist/agent-farm/utils/agent-names.d.ts.map +1 -1
  172. package/dist/agent-farm/utils/agent-names.js +3 -3
  173. package/dist/agent-farm/utils/agent-names.js.map +1 -1
  174. package/dist/agent-farm/utils/architect-name.d.ts +2 -2
  175. package/dist/agent-farm/utils/architect-name.d.ts.map +1 -1
  176. package/dist/agent-farm/utils/architect-name.js +3 -3
  177. package/dist/agent-farm/utils/architect-name.js.map +1 -1
  178. package/dist/agent-farm/utils/config.d.ts +13 -0
  179. package/dist/agent-farm/utils/config.d.ts.map +1 -1
  180. package/dist/agent-farm/utils/config.js +33 -1
  181. package/dist/agent-farm/utils/config.js.map +1 -1
  182. package/dist/agent-farm/utils/harness.d.ts +103 -7
  183. package/dist/agent-farm/utils/harness.d.ts.map +1 -1
  184. package/dist/agent-farm/utils/harness.js +126 -19
  185. package/dist/agent-farm/utils/harness.js.map +1 -1
  186. package/dist/agent-farm/utils/message-format.d.ts +8 -0
  187. package/dist/agent-farm/utils/message-format.d.ts.map +1 -1
  188. package/dist/agent-farm/utils/message-format.js +20 -0
  189. package/dist/agent-farm/utils/message-format.js.map +1 -1
  190. package/dist/agent-farm/utils/server-utils.d.ts +80 -4
  191. package/dist/agent-farm/utils/server-utils.d.ts.map +1 -1
  192. package/dist/agent-farm/utils/server-utils.js +286 -5
  193. package/dist/agent-farm/utils/server-utils.js.map +1 -1
  194. package/dist/cli.d.ts.map +1 -1
  195. package/dist/cli.js +6 -32
  196. package/dist/cli.js.map +1 -1
  197. package/dist/commands/consult/cli-options.d.ts +34 -0
  198. package/dist/commands/consult/cli-options.d.ts.map +1 -0
  199. package/dist/commands/consult/cli-options.js +67 -0
  200. package/dist/commands/consult/cli-options.js.map +1 -0
  201. package/dist/commands/consult/index.d.ts +56 -2
  202. package/dist/commands/consult/index.d.ts.map +1 -1
  203. package/dist/commands/consult/index.js +272 -28
  204. package/dist/commands/consult/index.js.map +1 -1
  205. package/dist/commands/consult/metrics.d.ts +42 -0
  206. package/dist/commands/consult/metrics.d.ts.map +1 -1
  207. package/dist/commands/consult/metrics.js +129 -9
  208. package/dist/commands/consult/metrics.js.map +1 -1
  209. package/dist/commands/doctor.d.ts.map +1 -1
  210. package/dist/commands/doctor.js +71 -19
  211. package/dist/commands/doctor.js.map +1 -1
  212. package/dist/commands/porch/checks.d.ts +23 -0
  213. package/dist/commands/porch/checks.d.ts.map +1 -1
  214. package/dist/commands/porch/checks.js +60 -0
  215. package/dist/commands/porch/checks.js.map +1 -1
  216. package/dist/commands/porch/config.d.ts +20 -0
  217. package/dist/commands/porch/config.d.ts.map +1 -1
  218. package/dist/commands/porch/config.js +20 -0
  219. package/dist/commands/porch/config.js.map +1 -1
  220. package/dist/commands/porch/index.js +21 -28
  221. package/dist/commands/porch/index.js.map +1 -1
  222. package/dist/commands/porch/next.d.ts.map +1 -1
  223. package/dist/commands/porch/next.js +2 -41
  224. package/dist/commands/porch/next.js.map +1 -1
  225. package/dist/lib/config.d.ts +69 -3
  226. package/dist/lib/config.d.ts.map +1 -1
  227. package/dist/lib/config.js +67 -3
  228. package/dist/lib/config.js.map +1 -1
  229. package/dist/lib/consult-lanes.d.ts +149 -0
  230. package/dist/lib/consult-lanes.d.ts.map +1 -0
  231. package/dist/lib/consult-lanes.js +360 -0
  232. package/dist/lib/consult-lanes.js.map +1 -0
  233. package/dist/lib/forge-contracts.d.ts +9 -0
  234. package/dist/lib/forge-contracts.d.ts.map +1 -1
  235. package/dist/lib/forge-contracts.js.map +1 -1
  236. package/dist/lib/github.d.ts +15 -1
  237. package/dist/lib/github.d.ts.map +1 -1
  238. package/dist/lib/github.js +18 -1
  239. package/dist/lib/github.js.map +1 -1
  240. package/dist/lib/prompt-behavior-metrics.d.ts +67 -0
  241. package/dist/lib/prompt-behavior-metrics.d.ts.map +1 -0
  242. package/dist/lib/prompt-behavior-metrics.js +290 -0
  243. package/dist/lib/prompt-behavior-metrics.js.map +1 -0
  244. package/dist/lib/skeleton.d.ts +22 -1
  245. package/dist/lib/skeleton.d.ts.map +1 -1
  246. package/dist/lib/skeleton.js +120 -0
  247. package/dist/lib/skeleton.js.map +1 -1
  248. package/dist/lib/test-env.d.ts +74 -0
  249. package/dist/lib/test-env.d.ts.map +1 -0
  250. package/dist/lib/test-env.js +92 -0
  251. package/dist/lib/test-env.js.map +1 -0
  252. package/dist/terminal/attach-replay.d.ts +39 -0
  253. package/dist/terminal/attach-replay.d.ts.map +1 -0
  254. package/dist/terminal/attach-replay.js +76 -0
  255. package/dist/terminal/attach-replay.js.map +1 -0
  256. package/dist/terminal/pty-manager.d.ts +2 -0
  257. package/dist/terminal/pty-manager.d.ts.map +1 -1
  258. package/dist/terminal/pty-manager.js +51 -23
  259. package/dist/terminal/pty-manager.js.map +1 -1
  260. package/dist/terminal/pty-session.d.ts +201 -1
  261. package/dist/terminal/pty-session.d.ts.map +1 -1
  262. package/dist/terminal/pty-session.js +327 -46
  263. package/dist/terminal/pty-session.js.map +1 -1
  264. package/dist/terminal/ring-buffer.d.ts +39 -6
  265. package/dist/terminal/ring-buffer.d.ts.map +1 -1
  266. package/dist/terminal/ring-buffer.js +74 -6
  267. package/dist/terminal/ring-buffer.js.map +1 -1
  268. package/dist/terminal/session-manager.d.ts +53 -0
  269. package/dist/terminal/session-manager.d.ts.map +1 -1
  270. package/dist/terminal/session-manager.js +94 -9
  271. package/dist/terminal/session-manager.js.map +1 -1
  272. package/dist/terminal/session-screen.d.ts +116 -0
  273. package/dist/terminal/session-screen.d.ts.map +1 -0
  274. package/dist/terminal/session-screen.js +180 -0
  275. package/dist/terminal/session-screen.js.map +1 -0
  276. package/dist/terminal/shellper-main.js +2 -1
  277. package/dist/terminal/shellper-main.js.map +1 -1
  278. package/dist/terminal/shellper-process.d.ts +1 -1
  279. package/dist/terminal/shellper-process.d.ts.map +1 -1
  280. package/dist/terminal/shellper-process.js +17 -8
  281. package/dist/terminal/shellper-process.js.map +1 -1
  282. package/dist/terminal/shellper-replay-buffer.d.ts +69 -7
  283. package/dist/terminal/shellper-replay-buffer.d.ts.map +1 -1
  284. package/dist/terminal/shellper-replay-buffer.js +167 -31
  285. package/dist/terminal/shellper-replay-buffer.js.map +1 -1
  286. package/package.json +13 -8
  287. package/scripts/forge/gitea/pr-view.sh +4 -1
  288. package/scripts/forge/github/pr-view.sh +1 -1
  289. package/scripts/forge/gitlab/pr-view.sh +4 -1
  290. package/skeleton/.claude/skills/afx/SKILL.md +68 -1
  291. package/skeleton/.claude/skills/arch-init/SKILL.md +22 -9
  292. package/skeleton/.claude/skills/arch-save/SKILL.md +183 -0
  293. package/skeleton/.claude/skills/codev/SKILL.md +31 -0
  294. package/skeleton/.claude/skills/runnable-worktrees/SKILL.md +119 -0
  295. package/skeleton/.codex/skills/afx/SKILL.md +68 -1
  296. package/skeleton/.codex/skills/arch-init/SKILL.md +22 -9
  297. package/skeleton/.codex/skills/arch-save/SKILL.md +183 -0
  298. package/skeleton/.codex/skills/codev/SKILL.md +31 -0
  299. package/skeleton/.codex/skills/runnable-worktrees/SKILL.md +119 -0
  300. package/skeleton/protocols/air/builder-prompt.md +28 -47
  301. package/skeleton/protocols/air/consult-types/impl-review.md +17 -34
  302. package/skeleton/protocols/air/consult-types/pr-review.md +14 -37
  303. package/skeleton/protocols/air/prompts/implement.md +20 -73
  304. package/skeleton/protocols/air/prompts/pr.md +22 -54
  305. package/skeleton/protocols/air/protocol.md +40 -71
  306. package/skeleton/protocols/aspir/builder-prompt.md +29 -66
  307. package/skeleton/protocols/aspir/consult-types/impl-review.md +17 -44
  308. package/skeleton/protocols/aspir/consult-types/phase-review.md +17 -44
  309. package/skeleton/protocols/aspir/consult-types/plan-review.md +14 -38
  310. package/skeleton/protocols/aspir/consult-types/pr-review.md +13 -39
  311. package/skeleton/protocols/aspir/consult-types/spec-review.md +13 -33
  312. package/skeleton/protocols/aspir/prompts/implement.md +27 -196
  313. package/skeleton/protocols/aspir/prompts/plan.md +21 -85
  314. package/skeleton/protocols/aspir/prompts/review.md +29 -228
  315. package/skeleton/protocols/aspir/prompts/specify.md +25 -111
  316. package/skeleton/protocols/aspir/protocol.json +10 -0
  317. package/skeleton/protocols/aspir/protocol.md +36 -82
  318. package/skeleton/protocols/bugfix/builder-prompt.md +23 -45
  319. package/skeleton/protocols/bugfix/consult-types/impl-review.md +21 -45
  320. package/skeleton/protocols/bugfix/consult-types/pr-review.md +18 -52
  321. package/skeleton/protocols/bugfix/prompts/fix.md +16 -61
  322. package/skeleton/protocols/bugfix/prompts/investigate.md +18 -62
  323. package/skeleton/protocols/bugfix/prompts/pr.md +22 -57
  324. package/skeleton/protocols/bugfix/protocol.md +44 -50
  325. package/skeleton/protocols/experiment/builder-prompt.md +25 -58
  326. package/skeleton/protocols/experiment/protocol.md +22 -188
  327. package/skeleton/protocols/experiment/templates/notes.md +11 -71
  328. package/skeleton/protocols/maintain/builder-prompt.md +24 -45
  329. package/skeleton/protocols/maintain/consult-types/impl-review.md +17 -44
  330. package/skeleton/protocols/maintain/consult-types/pr-review.md +13 -39
  331. package/skeleton/protocols/maintain/prompts/maintain.md +1 -1
  332. package/skeleton/protocols/maintain/protocol.md +32 -266
  333. package/skeleton/protocols/maintain/templates/maintenance-run.md +11 -0
  334. package/skeleton/protocols/pir/builder-prompt.md +31 -64
  335. package/skeleton/protocols/pir/consult-types/impl-review.md +17 -50
  336. package/skeleton/protocols/pir/consult-types/pr-review.md +11 -40
  337. package/skeleton/protocols/pir/prompts/implement.md +2 -3
  338. package/skeleton/protocols/pir/prompts/plan.md +1 -4
  339. package/skeleton/protocols/pir/prompts/review.md +2 -2
  340. package/skeleton/protocols/pir/protocol.md +54 -177
  341. package/skeleton/protocols/research/builder-prompt.md +27 -58
  342. package/skeleton/protocols/research/protocol.md +28 -153
  343. package/skeleton/protocols/spike/builder-prompt.md +30 -48
  344. package/skeleton/protocols/spike/protocol.md +24 -107
  345. package/skeleton/protocols/spike/templates/findings.md +9 -39
  346. package/skeleton/protocols/spir/builder-prompt.md +33 -62
  347. package/skeleton/protocols/spir/consult-types/impl-review.md +17 -44
  348. package/skeleton/protocols/spir/consult-types/phase-review.md +17 -44
  349. package/skeleton/protocols/spir/consult-types/plan-review.md +14 -38
  350. package/skeleton/protocols/spir/consult-types/pr-review.md +13 -39
  351. package/skeleton/protocols/spir/consult-types/spec-review.md +13 -33
  352. package/skeleton/protocols/spir/prompts/implement.md +26 -195
  353. package/skeleton/protocols/spir/prompts/plan.md +20 -84
  354. package/skeleton/protocols/spir/prompts/review.md +28 -227
  355. package/skeleton/protocols/spir/prompts/specify.md +24 -110
  356. package/skeleton/protocols/spir/protocol.json +10 -0
  357. package/skeleton/protocols/spir/protocol.md +84 -633
  358. package/skeleton/protocols/spir/templates/plan.md +28 -147
  359. package/skeleton/protocols/spir/templates/review.md +21 -80
  360. package/skeleton/protocols/spir/templates/spec.md +24 -118
  361. package/skeleton/resources/commands/agent-farm.md +262 -0
  362. package/skeleton/resources/commands/consult.md +236 -8
  363. package/skeleton/resources/commands/overview.md +1 -0
  364. package/skeleton/roles/architect.md +67 -317
  365. package/skeleton/roles/builder.md +76 -191
  366. package/skeleton/templates/AGENTS.md +2 -0
  367. package/skeleton/templates/CLAUDE.md +2 -0
  368. package/templates/3d-viewer.html +32 -4
  369. package/templates/open.html +58 -12
  370. package/templates/tower.html +65 -9
  371. package/templates/vendor/three-3MFLoader.js +1478 -0
  372. package/templates/vendor/three-STLLoader.js +410 -0
  373. package/templates/vendor/three-TrackballControls.js +828 -0
  374. package/templates/vendor/three-fflate.module.js +2474 -0
  375. package/templates/vendor/three.module.js +53044 -0
  376. package/dashboard-dist/assets/index-BZ1x7x1X.js.map +0 -1
  377. package/dashboard-dist/assets/index-DB1KBSNE.css +0 -32
  378. package/dist/agent-farm/servers/send-buffer.d.ts +0 -59
  379. package/dist/agent-farm/servers/send-buffer.d.ts.map +0 -1
  380. package/dist/agent-farm/servers/send-buffer.js +0 -116
  381. package/dist/agent-farm/servers/send-buffer.js.map +0 -1
  382. package/skeleton/porch/prompts/defend.md +0 -108
  383. package/skeleton/porch/prompts/diagnose.md +0 -70
  384. package/skeleton/porch/prompts/evaluate.md +0 -132
  385. package/skeleton/porch/prompts/fix.md +0 -59
  386. package/skeleton/porch/prompts/implement.md +0 -88
  387. package/skeleton/porch/prompts/plan.md +0 -74
  388. package/skeleton/porch/prompts/pr.md +0 -84
  389. package/skeleton/porch/prompts/review.md +0 -249
  390. package/skeleton/porch/prompts/specify.md +0 -53
  391. package/skeleton/porch/prompts/test.md +0 -63
  392. package/skeleton/protocols/aspir/templates/plan.md +0 -184
  393. package/skeleton/protocols/aspir/templates/review.md +0 -120
  394. package/skeleton/protocols/aspir/templates/spec.md +0 -154
@@ -342,6 +342,41 @@ afx send [builder] [message] [options]
342
342
  - `--interrupt` - Send Ctrl+C first
343
343
  - `--raw` - Skip structured message formatting
344
344
  - `--no-enter` - Do not send Enter after message
345
+ - `--delay <seconds>` - Deliver after N seconds instead of immediately
346
+
347
+ **Delayed delivery (`--delay`):**
348
+
349
+ Tower holds the message and delivers it after the stated delay, so the sending process is
350
+ free to exit in the meantime. That is the point: a session can schedule a message to
351
+ *itself* for after something that destroys it.
352
+
353
+ - **Authorised at request time, delivered later.** Target resolution and the
354
+ builder-spoofing check run when the command is issued, exactly as for an immediate send.
355
+ A delayed send cannot defer a check past the conditions that would fail it.
356
+ - **Bounds:** a whole number of seconds, 1–3600, rejected at both the CLI and server
357
+ boundaries — a bad value silently changes *when* (or whether) a message arrives rather
358
+ than failing loudly.
359
+ - **Persisted and durable (Spec 1313).** The message is written to Tower's durable mailbox at
360
+ request time with a due time (`not_before`), so a pending delayed send **survives a Tower
361
+ restart** — the render gate still guarantees it only lands on a clean, verified-empty prompt
362
+ when it comes due (this reverses Spec 1307's original drop-on-restart behaviour; the gate now
363
+ provides the protection that behaviour wanted). A pre-due delayed send is listable — and
364
+ cancellable — via `afx inbox`.
365
+ - **Ordering:** a delayed message never overtakes one already queued for that session — its
366
+ durable row is created at request time, and the mailbox delivers the oldest *eligible* row
367
+ first, so a pre-due message does not block a later message that is already due, and concurrent
368
+ deliveries to one agent do not interleave. Request order across *differing* delays is **not**
369
+ preserved — `--delay 30` then `--delay 5` delivers the 5-second one first, because that is what
370
+ `--delay` means.
371
+ - **Reporting:** the CLI says "scheduled", not "sent", and returns the mailbox id of the
372
+ persisted row.
373
+ - `--interrupt` is combinable (the Ctrl+C defers *with* the message); the API's `escape`
374
+ option is not (an ESC bypasses buffering precisely so it interrupts the *current* turn).
375
+
376
+ ```bash
377
+ # Deliver in 15 seconds; this shell can exit immediately
378
+ afx send architect:main --delay 15 --raw '/arch-init main'
379
+ ```
345
380
 
346
381
  **Description:**
347
382
 
@@ -350,6 +385,18 @@ Sends text to a builder's terminal. Useful for:
350
385
  - Interrupting long-running processes
351
386
  - Sending instructions or context
352
387
 
388
+ **Outcome (Spec 1313 — mailbox-first delivery):**
389
+
390
+ `afx send` reports the real first outcome instead of an unconditional "delivered":
391
+
392
+ - **delivered** — the message was written to the recipient's prompt after a clean render-gate pass (an empty, render-verified prompt).
393
+ - **held** — the prompt was not clear, so the message is persisted in Tower's durable mailbox and **delivers automatically** the moment the recipient's prompt is clean (after a submit, on output quiescence, or a poll backstop). The response carries a **why-held reason** and a mailbox id:
394
+ - `busy` — a draft, menu, dialog, or wrapper screen occupies the prompt;
395
+ - `no-profile` — the target app has no render-gate classifier profile (only `claude`, `codex`, and `agy` are modeled);
396
+ - `no-live-pty` — the recipient agent has no live terminal right now (it delivers when the agent respawns — rows address agents, not PTYs).
397
+
398
+ A held message is **never force-injected** onto a busy line: a message body is only ever written to a verified-empty prompt, so it cannot fuse with a half-typed draft, and held rows survive Tower restart/shutdown (no shutdown force-flush). See held mail with `afx inbox`, read one (including its body) with `afx inbox show <id>`, and clear one with `afx inbox dismiss <id>`. `--interrupt` is the explicit, deliberate bypass: it interrupts the agent and writes without holding (unchanged semantics).
399
+
353
400
  **Examples:**
354
401
 
355
402
  ```bash
@@ -368,6 +415,167 @@ afx send 42 --file src/api.ts "Review this implementation"
368
415
 
369
416
  ---
370
417
 
418
+ ### afx inbox
419
+
420
+ List, inspect, and dismiss **held** (undelivered) messages — the human-facing visibility surface for Spec 1313's mailbox. `afx send` persists a message it can't deliver immediately as a held row that delivers automatically once the recipient's prompt is clear; `afx inbox` lets a human see what is still waiting, read a specific message body, and clear rows — without reading Tower logs.
421
+
422
+ ```bash
423
+ afx inbox [options]
424
+ afx inbox show <id> [options]
425
+ afx inbox dismiss <id> [options]
426
+ ```
427
+
428
+ **`afx inbox`** — list every currently-held message in the workspace. Metadata only — message bodies are never shown in the list (or in logs); use `afx inbox show <id>` to read one:
429
+
430
+ | Column | Meaning |
431
+ |---|---|
432
+ | `ID` | Mailbox row id (pass to `show` / `dismiss`) |
433
+ | `AGE` | How long the message has been held (`5s`, `3m`, `2h`, `1d`) |
434
+ | `REASON` | Why-held: `busy`, `no-profile`, or `no-live-pty`; a trailing `!` marks a row past the escalation age |
435
+ | `FROM → TO` | Sender → recipient agent |
436
+ | `WORKSPACE` | Owning workspace |
437
+
438
+ **Options:**
439
+ - `-w, --workspace <path>` - Workspace to list (default: current workspace — `afx inbox` is workspace-scoped, not Tower-wide)
440
+ - `-p, --port <port>` - Tower port (default: 4100)
441
+
442
+ **`afx inbox show <id>`** — display a single message by id, **including its body**. This is the one CLI surface that surfaces a body: the redaction rule keeps bodies out of logs, diagnostics, and telemetry — not out of this local operator view, which travels over the same local Tower connection the message already uses. `show` works on a row of **any** status (held / delivered / superseded / dismissed), so a resolved row stays inspectable by id for audit until it is pruned. Prints the metadata (status, why-held reason, from → to, workspace, timestamps) followed by the raw body.
443
+
444
+ **Options:**
445
+ - `-p, --port <port>` - Tower port (default: 4100)
446
+
447
+ **`afx inbox dismiss <id>`** — mark a held message dismissed. A soft, auditable transition (the row is marked `dismissed`, not deleted) that **never delivers** the message. Any workspace operator may dismiss any held row (same local-human trust level as `afx send`).
448
+
449
+ **Options:**
450
+ - `-p, --port <port>` - Tower port (default: 4100)
451
+
452
+ **Examples:**
453
+
454
+ ```bash
455
+ # List held messages in the current workspace
456
+ afx inbox
457
+
458
+ # Show one message including its body (works for any status, held or resolved)
459
+ afx inbox show 5f3c9a2b-1e4d-4c7a-9f21-8b6d0e2a1c33
460
+
461
+ # Dismiss a held message by id (never delivers it)
462
+ afx inbox dismiss 5f3c9a2b-1e4d-4c7a-9f21-8b6d0e2a1c33
463
+ ```
464
+
465
+ Dismissal is CLI-only; the dashboard and VSCode held-count indicators surface the count but are read-only (Spec 1313 decision 8).
466
+
467
+ ---
468
+
469
+ ### afx interrupt
470
+
471
+ Interrupt a builder mid-turn by sending an ESC keystroke to its PTY.
472
+
473
+ ```bash
474
+ afx interrupt <builder> [options]
475
+ ```
476
+
477
+ **Arguments:**
478
+ - `builder` - Target builder. Same addressing as `afx send`.
479
+
480
+ **Options:**
481
+ - `--no-enter` - Send ESC alone, without the trailing Enter
482
+
483
+ **Description:**
484
+
485
+ This is the only recovery that reaches a builder **mid-turn**. When a builder chains foreground waits
486
+ inside a single turn, every `afx send` — including your order to stop — queues unread until that turn
487
+ ends. ESC interrupts the running tool and ends the turn, after which the queued messages process. The
488
+ trailing Enter (default) is what lets them through.
489
+
490
+ Distinct from `afx send --interrupt`, which sends Ctrl+C.
491
+
492
+ **Examples:**
493
+
494
+ ```bash
495
+ # Builder is wedged on a foreground wait and not reading messages
496
+ afx interrupt 0042
497
+
498
+ # Then the queued instruction lands
499
+ afx send 0042 "That producer died — stop waiting and report."
500
+ ```
501
+
502
+ ---
503
+
504
+ ### afx refresh
505
+
506
+ Refresh a builder's context: have it save its working state, clear the conversation, then re-orient it.
507
+
508
+ ```bash
509
+ afx refresh <builder> [options]
510
+ ```
511
+
512
+ **Arguments:**
513
+ - `builder` - Target builder. Same addressing as `afx send`.
514
+
515
+ **Options:**
516
+ - `--note <text>` - Extra context appended to the re-orientation
517
+ - `--file <path>` - Append file content to the re-orientation (48KB max, read from *your* filesystem)
518
+ - `--dry-run` - Print the save request and both re-orientation payloads; write nothing to the builder
519
+ - `--interrupt-first` - Send ESC before the save request, for a builder already wedged mid-turn
520
+ - `--mode <strict|soft>` - Override the builder mode if it cannot be detected
521
+ - `--timeout <seconds>` - How long to wait for the save-state receipt (default 300)
522
+ - `--min-bytes <n>` - Minimum state-file size to accept as substantive (default 1000)
523
+ - `--quiet-window <ms>` - Terminal silence that counts as turn-ended (default 1500)
524
+
525
+ **Deprecated alias:** `afx reset` still runs this command and prints a one-line notice to stderr.
526
+ It will be removed in a future release — use `afx refresh`.
527
+
528
+ **Description:**
529
+
530
+ Long-running builders exhaust their context window. `afx spawn --resume` reattaches the *same*
531
+ conversation, so a deep session resumes deep — it does not give the builder a fresh window. `afx refresh`
532
+ does, without losing what the builder knows.
533
+
534
+ The sequence:
535
+
536
+ 1. Assemble the re-orientation and write it to `.builder-reorient.md` in the worktree.
537
+ 2. Ask the builder to write its complete working state to `.builder-state.md`, stamped with a one-time
538
+ nonce.
539
+ 3. Wait for that file and **verify** it: correct nonce (not a stale file from an earlier refresh),
540
+ substantive size, and stable across two observations (not still being written).
541
+ 4. Wait for the terminal to fall silent, so the clear is not typed mid-turn. If it does not settle, send
542
+ **one** ESC and wait again.
543
+ 5. Send `/clear`.
544
+ 6. Deliver the re-orientation: role, protocol, mode, project, worktree, branch, the porch re-entry
545
+ instruction, and a pointer to the state file.
546
+
547
+ **Every gate fails safe.** If the state file never arrives, carries the wrong nonce, is a stub, is still
548
+ growing, or the builder will not go quiet — the command **aborts without clearing** and exits non-zero,
549
+ naming the gate that failed. A builder whose context was not cleared has lost nothing.
550
+
551
+ Both worktree artifacts use the `.builder-` prefix, so `afx cleanup` still classifies the worktree as
552
+ clean, and both are untracked so `porch done`'s staged-file sweep cannot pick them up.
553
+
554
+ Requires a harness with in-session context reset (Claude Code). Other harnesses abort loudly rather than
555
+ substituting a different mechanism — use the boundary-recycle pattern instead (let the builder finish,
556
+ then `afx spawn <id> --resume`).
557
+
558
+ **Examples:**
559
+
560
+ ```bash
561
+ # See exactly what would be sent, without touching the builder
562
+ afx refresh 0042 --dry-run
563
+
564
+ # Standard refresh
565
+ afx refresh 0042
566
+
567
+ # Add context that post-dates the builder's saved state
568
+ afx refresh 0042 --note "PR #90 merged while you were mid-phase. Rebase before continuing."
569
+
570
+ # The builder is wedged mid-turn and not reading messages
571
+ afx refresh 0042 --interrupt-first
572
+
573
+ # A builder that legitimately needs longer to write its state
574
+ afx refresh 0042 --timeout 600
575
+ ```
576
+
577
+ ---
578
+
371
579
  ### afx open
372
580
 
373
581
  Open file annotation viewer.
@@ -537,6 +745,42 @@ afx tower status [options]
537
745
 
538
746
  ---
539
747
 
748
+ ### afx cron
749
+
750
+ Manage scheduled tasks defined as YAML files in `.af-cron/` at the workspace root. The Tower scheduler loads these every tick, runs due commands, and delivers messages through the normal send pipeline.
751
+
752
+ ```bash
753
+ afx cron list # List all cron tasks
754
+ afx cron status <name> # Check task status
755
+ afx cron run <name> # Run immediately
756
+ afx cron enable <name> # Enable
757
+ afx cron disable <name> # Disable
758
+ ```
759
+
760
+ There is NO `afx cron add` — create YAML files in `.af-cron/` directly.
761
+
762
+ **Task YAML format:**
763
+
764
+ ```yaml
765
+ name: Service Health Check # required, unique per workspace
766
+ schedule: "*/15 * * * *" # required, cron expression (or @hourly/@daily/@startup)
767
+ command: ./health-check.sh # required, run via shell
768
+ message: "Health alert: ${output}" # required, ${output} = trimmed command output
769
+ condition: "exitCode != 0" # optional JS expression, see below
770
+ target: architect # optional, default architect
771
+ timeout: 30 # optional, seconds, default 30
772
+ enabled: true # optional, default true
773
+ ```
774
+
775
+ **Condition environment:** `condition` is a JavaScript expression evaluated with two variables in scope:
776
+
777
+ - `output` (string) — the command's trimmed output
778
+ - `exitCode` (number) — `0` on success, the command's exit code on non-zero exit, `124` on timeout, `-1` on spawn failure
779
+
780
+ With a `condition`, the message is delivered exactly when the expression evaluates truthy — including on failed runs, so `condition: "exitCode != 0"` alerts when the command fails. Without a `condition`, the message is delivered only when the command exits 0.
781
+
782
+ ---
783
+
540
784
  ### afx db
541
785
 
542
786
  Database debugging and maintenance commands.
@@ -645,6 +889,24 @@ afx workspace start --architect-cmd "claude --model opus"
645
889
  afx spawn 42 --protocol spir --builder-cmd "claude --model haiku"
646
890
  ```
647
891
 
892
+ ### Mailbox retention and escalation
893
+
894
+ `afx send`'s mailbox (Spec 1313) has two Tower-global knobs under a `mailbox` key:
895
+
896
+ ```json
897
+ {
898
+ "mailbox": {
899
+ "retentionDays": 30,
900
+ "escalationSeconds": 60
901
+ }
902
+ }
903
+ ```
904
+
905
+ - `mailbox.retentionDays` (default `30`) — how long a **terminal** mailbox row (delivered, superseded, or dismissed) is retained before Tower prunes it. **Held** rows are never pruned — they persist until they deliver, are superseded, or are dismissed via `afx inbox`.
906
+ - `mailbox.escalationSeconds` (default `60`) — how long a row may stay **held** before it crosses the escalation age. At that point the drainer marks the row `escalated`, emits the escalation broadcast, and moves the dashboard / VSCode held-count indicator into its attention state. This is **visibility only** — crossing the escalation age never triggers delivery (there is no force path; a held message still delivers only onto a verified-empty prompt).
907
+
908
+ Both are Tower-global (they apply to the whole Tower, not per-project) and optional — omit them to use the defaults above.
909
+
648
910
  ---
649
911
 
650
912
  ## Files
@@ -15,14 +15,214 @@ consult stats [options]
15
15
  -m, --model <model> Model to use (required for all modes except stats)
16
16
  ```
17
17
 
18
+ ## Model Selection Options
19
+
20
+ ```
21
+ --model-id <id> Override the provider model id for THIS invocation
22
+ ```
23
+
24
+ `-m/--model` picks the **lane** (`claude`, `codex`, `gemini`, `hermes`); `--model-id` picks the
25
+ **model that lane runs**. The two are independent — see [Configuration](#configuration) for setting
26
+ an id persistently instead.
27
+
28
+ ```bash
29
+ consult -m codex --model-id gpt-5.6-sol --prompt "Review this design"
30
+ ```
31
+
32
+ - **Precedence**: `--model-id` > `consult.models.<lane>` > the lane's shipped default.
33
+ - **Supported lanes**: `claude`, `codex`, `gemini`. Using it with `hermes` is an **error**, not a
34
+ silent no-op — `hermes chat -q` has no model selector, so accepting the flag there would mean
35
+ ignoring it.
36
+ - **Validation is syntax-only.** Whether the id exists is the provider's call; a rejection fails
37
+ loudly with no fallback to the default. See
38
+ [the fail-fast contract](#the-fail-fast-contract-and-where-it-stops).
39
+
18
40
  ## Models
19
41
 
20
- | Model | Alias | Backend | Notes |
21
- |-------|-------|---------|-------|
22
- | `gemini` | `pro` | Antigravity CLI (`agy`) | Agentic file access (`--sandbox --add-dir`), OAuth/subscription login. Skips non-blockingly if `agy` is missing/unauthed. |
23
- | `codex` | `gpt` | @openai/codex | Read-only sandbox, thorough |
24
- | `claude` | `opus` | Claude Agent SDK | Balanced analysis with tool use |
25
- | `hermes` | - | hermes CLI (`hermes chat -q`) | Uses Hermes agent as consult backend |
42
+ | Model | Alias | Backend | Shipped default model id | Notes |
43
+ |-------|-------|---------|--------------------------|-------|
44
+ | `gemini` | `pro` | Antigravity CLI (`agy`) | *(agy's own default — no pinned id)* | Agentic file access (`--sandbox --add-dir`), OAuth/subscription login. Skips non-blockingly if `agy` is missing/unauthed. |
45
+ | `codex` | `gpt` | @openai/codex | `gpt-5.6-sol` (medium reasoning effort) | Read-only sandbox, thorough |
46
+ | `claude` | `opus` | Claude Agent SDK | `claude-opus-5` | Balanced analysis with tool use |
47
+ | `hermes` | - | hermes CLI (`hermes chat -q`) | *(hermes' own default)* | Uses Hermes agent as consult backend |
48
+
49
+ > **The codex lane's `-sol` suffix is load-bearing.** Plain `gpt-5.6` and `gpt-5.6-codex` are both
50
+ > rejected by Codex when running on a ChatGPT account (`The '<id>' model is not supported when
51
+ > using Codex with a ChatGPT account.`). Don't "simplify" the id — a unit test pins it.
52
+
53
+ ### Cost reporting
54
+
55
+ Codex consultation cost is computed from OpenAI's published per-1M-token rates for the lane's
56
+ model. If a model has no rates recorded in Codev, the consultation still runs and its token counts
57
+ are still recorded, but `cost_usd` is stored as `null` rather than billed at some other model's
58
+ rates. Only OpenAI's standard pricing tier is modelled — costs for consultations large enough to
59
+ enter the long-context tier are under-reported.
60
+
61
+ Supply rates for a model Codev doesn't know with [`consult.pricing.codex`](#consultpricingcodex).
62
+
63
+ ## Configuration
64
+
65
+ Everything below lives in `.codev/config.json` and flows through the standard five-layer config
66
+ stack, lowest priority to highest:
67
+
68
+ 1. built-in defaults
69
+ 2. `<cache>/config.json` — remote framework base config
70
+ 3. `~/.codev/config.json` — global, per-user, across all projects
71
+ 4. `.codev/config.json` — project, checked in
72
+ 5. `.codev/config.local.json` — project, per-engineer, gitignored
73
+
74
+ So any key can be set globally and narrowed per project, and an individual engineer can override
75
+ either without touching a checked-in file.
76
+
77
+ **Two independent axes**, easy to confuse:
78
+
79
+ | Axis | Key | Answers |
80
+ |------|-----|---------|
81
+ | *Which model* a lane runs | `consult.models` | "run `claude-opus-5` on the claude lane" |
82
+ | *Which lanes* run at all | `porch.consultation.*` | "review PIR with two lanes, not three" |
83
+
84
+ ### `consult.models`
85
+
86
+ Per-lane model id. Absent → the shipped default in the [Models](#models) table. Outranked for a
87
+ single invocation by [`--model-id`](#model-selection-options).
88
+
89
+ ```json
90
+ { "consult": { "models": { "claude": "claude-opus-5", "codex": "gpt-5.6-sol" } } }
91
+ ```
92
+
93
+ Valid lanes: `claude`, `codex`, `gemini`. **`hermes` is rejected** — it is invoked as
94
+ `hermes chat -q` and exposes no model selector, so configuring one would silently do nothing.
95
+ (`hermes` remains valid in `porch.consultation` lane lists; the two key spaces differ on purpose.)
96
+
97
+ The `gemini` lane passes the id to `agy --model`, so the id space is agy's, not Google's API's.
98
+
99
+ ### `consult.reasoningEffort`
100
+
101
+ ```json
102
+ { "consult": { "reasoningEffort": { "codex": "high" } } }
103
+ ```
104
+
105
+ Only `codex` exposes this. Values: `minimal`, `low`, `medium`, `high`, `xhigh` (default `medium`).
106
+ Unlike model ids, this **is** a closed set Codev validates locally — see the asymmetry below.
107
+
108
+ ### `consult.pricing.codex`
109
+
110
+ Per-1M-token rates for the codex lane. Set this when Codev has no rates for the model you run
111
+ (otherwise `cost_usd` is `null`), or to correct rates that have gone stale.
112
+
113
+ **It outranks the shipped rate table for every model, not only unknown ones** — once set, it is
114
+ used for whatever the codex lane runs, so it is worth revisiting if you later change the model.
115
+
116
+ ```json
117
+ { "consult": { "pricing": { "codex": { "inputPer1M": 5.00, "cachedInputPer1M": 0.50, "outputPer1M": 30.00 } } } }
118
+ ```
119
+
120
+ > **Take the numbers from the provider, not from here.** Those are the rates Codev ships for
121
+ > `gpt-5.6-sol` at the time of writing, shown so the shape is concrete — they are not right for
122
+ > whatever model you are configuring, and published rates change. Copying a plausible-looking wrong
123
+ > rate produces a confidently wrong cost, which is the exact failure this key exists to prevent;
124
+ > a `null` cost is the better outcome of the two.
125
+
126
+ - **`codex` is the only accepted lane.** Claude reports its own cost directly and the gemini/agy
127
+ lane reports no usage data at all, so a pricing override for either would be inert. Any other
128
+ lane key is an error.
129
+ - **All three rates are required together**, and each must be a finite, non-negative number. A
130
+ partial object is an error, not a half-priced estimate: defaulting any one rate to a stale
131
+ built-in would reintroduce exactly the wrong-cost problem this override exists to fix.
132
+
133
+ ### `porch.consultation` — which lanes run
134
+
135
+ Lane lists accept a single name (`"codex"`), an array (`["codex", "claude"]`), or a whole-value
136
+ special mode: `"none"` (skip consultation) or `"parent"` (emit a gate for the architect instead).
137
+ An **empty array is rejected** — use `"none"`, so there is exactly one way to say it.
138
+
139
+ `models` is the workspace-wide default, `modelsByType` narrows by review type, and `byProtocol`
140
+ scopes either of those to one protocol:
141
+
142
+ ```json
143
+ {
144
+ "porch": {
145
+ "consultation": {
146
+ "models": ["gemini", "codex", "claude"],
147
+ "modelsByType": { "pr": ["codex", "claude"] },
148
+ "byProtocol": {
149
+ "pir": {
150
+ "models": ["gemini", "codex"],
151
+ "modelsByType": { "impl": ["codex"] }
152
+ }
153
+ }
154
+ }
155
+ }
156
+ }
157
+ ```
158
+
159
+ Review-type keys are the protocol's own `verify.type` values (`spec`, `plan`, `impl`, `pr`, …);
160
+ protocol keys are protocol names, and aliases are canonicalized so `byProtocol.spider` matches a
161
+ project running as `spir`. Unknown keys in either space are **errors, not warnings** — a typo that
162
+ merely warned would silently leave you on the defaults you were trying to override.
163
+
164
+ #### Precedence
165
+
166
+ Highest first. The first level that is present wins outright; levels do not merge.
167
+
168
+ 1. `porch.consultation.byProtocol[<protocol>].modelsByType[<type>]`
169
+ 2. `porch.consultation.byProtocol[<protocol>].models`
170
+ 3. `porch.consultation.modelsByType[<type>]`
171
+ 4. `porch.consultation.models`
172
+ 5. the protocol's own `verify.models` (i.e. no config at all)
173
+
174
+ Both `porch next` and `porch done` resolve through this one ladder, so the lanes porch asks you to
175
+ run are exactly the lanes it will require review files for.
176
+
177
+ #### Worked example: keeping PIR cheap while widening the default
178
+
179
+ PIR is deliberately a 2-lane (CMAP-2) protocol. A workspace-wide 3-lane default silently inflates
180
+ it, because config outranks protocol. Scope PIR back down explicitly:
181
+
182
+ ```json
183
+ {
184
+ "porch": {
185
+ "consultation": {
186
+ "models": ["gemini", "codex", "claude"],
187
+ "byProtocol": { "pir": { "models": ["gemini", "codex"] } }
188
+ }
189
+ }
190
+ }
191
+ ```
192
+
193
+ `["gemini", "codex"]` is PIR's own shipped pair, so this restores exactly what the protocol declares
194
+ rather than substituting a different two. SPIR and ASPIR reviews run three lanes; PIR runs two.
195
+ Without the `byProtocol` entry, PIR would run three and cost 50% more per review with no change to
196
+ the protocol file.
197
+
198
+ ### The fail-fast contract, and where it stops
199
+
200
+ Config errors are raised when config is **loaded** — before any consultation starts — and name the
201
+ offending key and the valid alternatives. Nothing falls back to a default on error.
202
+
203
+ **The asymmetry worth knowing about:** these two are validated very differently.
204
+
205
+ | | Validated by | When you find out |
206
+ |---|---|---|
207
+ | `reasoningEffort` | **Codev**, against a closed enum | Config load, before anything runs |
208
+ | Model ids | **The provider** | When the lane runs |
209
+
210
+ Codev checks a model id's *syntax* only (ASCII alphanumerics plus `. _ : / @ + -`, 1–200 characters,
211
+ no leading punctuation) — never its existence. **There is no allowlist of model ids anywhere in
212
+ Codev, by design**: a new model must work the day the provider ships it, without a Codev release.
213
+
214
+ So a typo'd model id is not caught at config time. It reaches the backend, which rejects it; that
215
+ lane exits non-zero, the provider's error text is surfaced, the config key that supplied the id is
216
+ named, and **no review file is written** — so porch cannot advance on a lane that never ran. What
217
+ you do *not* get is a silent substitution of the default model.
218
+
219
+ One deliberate exception: a `gemini` lane **with no model id resolved** still skips non-blockingly
220
+ when `agy` is missing or unauthenticated (consultation is best-effort there). Once an id *is*
221
+ resolved — from either `consult.models.gemini` **or** `--model-id` — a rejected model becomes a hard
222
+ failure for that lane, because you asked for a specific model and did not get it. What still skips
223
+ rather than fails, even with an id, are causes that are not the model's fault: `agy` absent,
224
+ unauthenticated, timed out, killed by a signal, or exiting **successfully** having produced no
225
+ output at all.
26
226
 
27
227
  ## Modes
28
228
 
@@ -78,10 +278,11 @@ consult -m codex --type integration --issue 42 --base ci
78
278
  - `--base <ref>` — **`--type integration` only.** Anchor the diff on this base branch (e.g. `ci`), computed locally as `git diff origin/<base>...origin/<head>` (three-dot, merge-base anchored). Use in repos with a long-lived integration branch ahead of the default branch so the review sees only the PR's actual change, not the whole integration-over-trunk delta. Unresolvable refs fail loudly with a `git fetch` hint (no silent fallback to the local checkout). Defaults to config `consult.integrationBranch`; with neither set, the integration review uses the PR's host-recorded base (`gh pr diff`), unchanged.
79
279
 
80
280
  **Config (`.codev/config.json`):**
81
- ```jsonc
281
+ `integrationBranch` is the repo-wide default base for `--type integration`, overridden by `--base`.
282
+
283
+ ```json
82
284
  {
83
285
  "consult": {
84
- // Repo-wide default base for `--type integration` (overridden by --base).
85
286
  "integrationBranch": "ci"
86
287
  }
87
288
  }
@@ -196,6 +397,33 @@ through to a normal spawn.
196
397
  | `CODEV_AGY_AUTH_CACHE_DIR` | `~/.cache/codev` | Cache location (mainly for tests). |
197
398
  | `CODEV_AGY_AUTH_CACHE_DISABLE` | unset | `1` restores the always-spawn behaviour. |
198
399
 
400
+ #### Test isolation
401
+
402
+ The cache above protects *production* runs. It did not protect test runs: the
403
+ cache disables itself under `VITEST` unless a cache directory is named, and any
404
+ test that reached the gemini lane without pinning `CODEV_AGY_BIN` resolved the
405
+ real binary — so a suite run could still open a login window per spawn (#1323).
406
+ Consult now treats a test runner as a hard boundary. Under `VITEST` (or
407
+ `CODEV_TEST_ISOLATION`) it refuses to resolve an unpinned `agy` and refuses to open the
408
+ user-global metrics database, failing loudly instead of reaching either. Codev's
409
+ own suites pin a fake `agy`, a sandbox auth cache, and a sandbox metrics DB for
410
+ every test; spawned `codev` / `consult` children inherit the pins through the
411
+ environment.
412
+
413
+ | Variable | Default | Purpose |
414
+ |---|---|---|
415
+ | `CODEV_AGY_BIN` | auto-resolved | Pin the agy binary. The harness sets this to a fake for every test. |
416
+ | `CODEV_ALLOW_REAL_AGY` | unset | `1` opts a test run into the REAL agy binary — the guarded integration smoke and real-AI e2e runs. Expect a browser window if agy's login has lapsed. |
417
+ | `CODEV_METRICS_DB` | `~/.codev/metrics.db` | Redirect the consult metrics database. Required under a test runner; the harness points it at a temp dir so suite runs stop skewing `consult stats`. |
418
+ | `CODEV_TEST_ISOLATION` | unset | `1` applies the same guards to a harness that is not vitest. |
419
+
420
+ **Adopters:** `VITEST` is exported by *any* vitest run, including yours. If your
421
+ project's own suite deliberately shells out to `consult -m gemini`, that call now
422
+ throws until you set `CODEV_ALLOW_REAL_AGY=1` (and `CODEV_METRICS_DB` if you want
423
+ the metrics recorded somewhere). This is intentional — a suite reaching the real
424
+ agy is what #1323 was about — but it is a behaviour change, not a silent one: the
425
+ error names the variable to set.
426
+
199
427
  ### Claude auth: subscription vs. metered API
200
428
 
201
429
  `consult -m claude` runs on the Claude Agent SDK. When `CLAUDE_CODE_OAUTH_TOKEN`
@@ -59,6 +59,7 @@ See [codev.md](codev.md) for full documentation.
59
59
  | `afx status` | Show status of all agents |
60
60
  | `afx cleanup` | Clean up a builder worktree |
61
61
  | `afx send` | Send instructions to a builder |
62
+ | `afx inbox` | List/show/dismiss held (undelivered) messages |
62
63
  | `afx open` | Open file annotation viewer |
63
64
  | `afx shell` | Spawn a utility shell |
64
65
  | `afx tower` | Cross-project dashboard |