@intentic/sandbox-contract 1.248.0 → 1.249.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 (877) hide show
  1. package/README.md +18 -15
  2. package/dist/chores/chores.d.ts.map +1 -1
  3. package/dist/chores/chores.js.map +1 -1
  4. package/dist/chores/digest.d.ts.map +1 -1
  5. package/dist/chores/digest.js.map +1 -1
  6. package/dist/chores/extension-update.d.ts.map +1 -1
  7. package/dist/chores/extension-update.js.map +1 -1
  8. package/dist/chores/fix-deps.d.ts.map +1 -1
  9. package/dist/chores/fix-deps.js.map +1 -1
  10. package/dist/chores/index.d.ts +2 -2
  11. package/dist/chores/index.d.ts.map +1 -1
  12. package/dist/chores/index.js +1 -1
  13. package/dist/chores/index.js.map +1 -1
  14. package/dist/chores/probes.d.ts.map +1 -1
  15. package/dist/chores/probes.js.map +1 -1
  16. package/dist/chores/prompt.d.ts.map +1 -1
  17. package/dist/chores/prompt.js.map +1 -1
  18. package/dist/chores/stack.d.ts.map +1 -1
  19. package/dist/chores/stack.js.map +1 -1
  20. package/dist/chores/verdict.d.ts +7 -1
  21. package/dist/chores/verdict.d.ts.map +1 -1
  22. package/dist/chores/verdict.js +8 -0
  23. package/dist/chores/verdict.js.map +1 -1
  24. package/dist/contracts/accounts.contract.d.ts.map +1 -1
  25. package/dist/contracts/accounts.contract.js.map +1 -1
  26. package/dist/contracts/activity.contract.d.ts +1 -0
  27. package/dist/contracts/activity.contract.d.ts.map +1 -1
  28. package/dist/contracts/agent.contract.d.ts +12 -205
  29. package/dist/contracts/agent.contract.d.ts.map +1 -1
  30. package/dist/contracts/agent.contract.js +2 -1
  31. package/dist/contracts/agent.contract.js.map +1 -1
  32. package/dist/contracts/agents.contract.d.ts +228 -54
  33. package/dist/contracts/agents.contract.d.ts.map +1 -1
  34. package/dist/contracts/agents.contract.js +11 -2
  35. package/dist/contracts/agents.contract.js.map +1 -1
  36. package/dist/contracts/automations.contract.d.ts +35 -17
  37. package/dist/contracts/automations.contract.d.ts.map +1 -1
  38. package/dist/contracts/automations.contract.js +10 -1
  39. package/dist/contracts/automations.contract.js.map +1 -1
  40. package/dist/contracts/capabilities.contract.d.ts +0 -12
  41. package/dist/contracts/capabilities.contract.d.ts.map +1 -1
  42. package/dist/contracts/capabilities.contract.js +1 -1
  43. package/dist/contracts/capabilities.contract.js.map +1 -1
  44. package/dist/contracts/chores.contract.d.ts.map +1 -1
  45. package/dist/contracts/chores.contract.js.map +1 -1
  46. package/dist/contracts/ci.contract.d.ts +9 -0
  47. package/dist/contracts/ci.contract.d.ts.map +1 -1
  48. package/dist/contracts/endpoints.contract.d.ts.map +1 -1
  49. package/dist/contracts/endpoints.contract.js.map +1 -1
  50. package/dist/contracts/exit.contract.d.ts.map +1 -1
  51. package/dist/contracts/exit.contract.js +1 -1
  52. package/dist/contracts/exit.contract.js.map +1 -1
  53. package/dist/contracts/extensions.contract.d.ts.map +1 -1
  54. package/dist/contracts/extensions.contract.js.map +1 -1
  55. package/dist/contracts/git.contract.d.ts +45 -6
  56. package/dist/contracts/git.contract.d.ts.map +1 -1
  57. package/dist/contracts/git.contract.js +9 -9
  58. package/dist/contracts/git.contract.js.map +1 -1
  59. package/dist/contracts/host.contract.d.ts +2 -0
  60. package/dist/contracts/host.contract.d.ts.map +1 -1
  61. package/dist/contracts/host.contract.js.map +1 -1
  62. package/dist/contracts/intentic.contract.js +1 -1
  63. package/dist/contracts/intentic.contract.js.map +1 -1
  64. package/dist/contracts/logs.contract.d.ts.map +1 -1
  65. package/dist/contracts/logs.contract.js.map +1 -1
  66. package/dist/contracts/loops.contract.d.ts.map +1 -1
  67. package/dist/contracts/loops.contract.js.map +1 -1
  68. package/dist/contracts/personas.contract.d.ts +1 -0
  69. package/dist/contracts/personas.contract.d.ts.map +1 -1
  70. package/dist/contracts/personas.contract.js +1 -1
  71. package/dist/contracts/personas.contract.js.map +1 -1
  72. package/dist/contracts/providers.contract.d.ts.map +1 -1
  73. package/dist/contracts/providers.contract.js.map +1 -1
  74. package/dist/contracts/runner.contract.d.ts +97 -171
  75. package/dist/contracts/runner.contract.d.ts.map +1 -1
  76. package/dist/contracts/runner.contract.js +2 -2
  77. package/dist/contracts/runner.contract.js.map +1 -1
  78. package/dist/contracts/safety.contract.d.ts.map +1 -1
  79. package/dist/contracts/safety.contract.js +1 -1
  80. package/dist/contracts/safety.contract.js.map +1 -1
  81. package/dist/contracts/secrets.contract.d.ts.map +1 -1
  82. package/dist/contracts/secrets.contract.js.map +1 -1
  83. package/dist/contracts/sessions.contract.d.ts +2 -41
  84. package/dist/contracts/sessions.contract.d.ts.map +1 -1
  85. package/dist/contracts/sessions.contract.js +1 -1
  86. package/dist/contracts/sessions.contract.js.map +1 -1
  87. package/dist/contracts/settings.contract.d.ts +8 -18
  88. package/dist/contracts/settings.contract.d.ts.map +1 -1
  89. package/dist/contracts/settings.contract.js.map +1 -1
  90. package/dist/contracts/share.contract.d.ts.map +1 -1
  91. package/dist/contracts/share.contract.js.map +1 -1
  92. package/dist/contracts/skills.contract.d.ts.map +1 -1
  93. package/dist/contracts/skills.contract.js.map +1 -1
  94. package/dist/contracts/system.contract.d.ts +49 -73
  95. package/dist/contracts/system.contract.d.ts.map +1 -1
  96. package/dist/contracts/system.contract.js +12 -2
  97. package/dist/contracts/system.contract.js.map +1 -1
  98. package/dist/contracts/usage.contract.d.ts.map +1 -1
  99. package/dist/contracts/usage.contract.js.map +1 -1
  100. package/dist/contracts/vpn.contract.d.ts.map +1 -1
  101. package/dist/contracts/vpn.contract.js +1 -1
  102. package/dist/contracts/vpn.contract.js.map +1 -1
  103. package/dist/contracts/webext.contract.d.ts.map +1 -1
  104. package/dist/contracts/webext.contract.js.map +1 -1
  105. package/dist/contracts/workflows.contract.d.ts +7 -6
  106. package/dist/contracts/workflows.contract.d.ts.map +1 -1
  107. package/dist/contracts/workflows.contract.js +12 -3
  108. package/dist/contracts/workflows.contract.js.map +1 -1
  109. package/dist/contracts/workspace.contract.d.ts.map +1 -1
  110. package/dist/contracts/workspace.contract.js.map +1 -1
  111. package/dist/events/agent-events.d.ts +1237 -0
  112. package/dist/events/agent-events.d.ts.map +1 -0
  113. package/dist/events/agent-events.js +226 -0
  114. package/dist/events/agent-events.js.map +1 -0
  115. package/dist/events/cards.d.ts +404 -0
  116. package/dist/events/cards.d.ts.map +1 -0
  117. package/dist/events/cards.js +179 -0
  118. package/dist/events/cards.js.map +1 -0
  119. package/dist/events/resume.d.ts +23 -0
  120. package/dist/events/resume.d.ts.map +1 -0
  121. package/dist/events/resume.js +31 -0
  122. package/dist/events/resume.js.map +1 -0
  123. package/dist/events/system-events.d.ts +615 -0
  124. package/dist/events/system-events.d.ts.map +1 -0
  125. package/dist/events/system-events.js +64 -0
  126. package/dist/events/system-events.js.map +1 -0
  127. package/dist/events/transcript.d.ts +1755 -0
  128. package/dist/events/transcript.d.ts.map +1 -0
  129. package/dist/events/transcript.js +205 -0
  130. package/dist/events/transcript.js.map +1 -0
  131. package/dist/ids/conversation-ids.d.ts +8 -0
  132. package/dist/ids/conversation-ids.d.ts.map +1 -0
  133. package/dist/{conversation-ids.js → ids/conversation-ids.js} +13 -0
  134. package/dist/ids/conversation-ids.js.map +1 -0
  135. package/dist/ids/hostnames.d.ts.map +1 -0
  136. package/dist/ids/hostnames.js.map +1 -0
  137. package/dist/ids/session-names.d.ts.map +1 -0
  138. package/dist/ids/session-names.js.map +1 -0
  139. package/dist/ids/share-paths.d.ts.map +1 -0
  140. package/dist/ids/share-paths.js.map +1 -0
  141. package/dist/{tunnel-ids.d.ts → ids/tunnel-ids.d.ts} +1 -0
  142. package/dist/ids/tunnel-ids.d.ts.map +1 -0
  143. package/dist/{tunnel-ids.js → ids/tunnel-ids.js} +1 -0
  144. package/dist/ids/tunnel-ids.js.map +1 -0
  145. package/dist/index.d.ts +423 -450
  146. package/dist/index.d.ts.map +1 -1
  147. package/dist/index.js +54 -46
  148. package/dist/index.js.map +1 -1
  149. package/dist/{agent-catalog.d.ts → models/agent-catalog.d.ts} +2 -2
  150. package/dist/models/agent-catalog.d.ts.map +1 -0
  151. package/dist/models/agent-catalog.js.map +1 -0
  152. package/dist/models/agent-runtimes.d.ts.map +1 -0
  153. package/dist/models/agent-runtimes.js.map +1 -0
  154. package/dist/{fast-tier.d.ts → models/fast-tier.d.ts} +1 -1
  155. package/dist/models/fast-tier.d.ts.map +1 -0
  156. package/dist/models/fast-tier.js.map +1 -0
  157. package/dist/models/model-order.d.ts.map +1 -0
  158. package/dist/models/model-order.js.map +1 -0
  159. package/dist/{model-pins.d.ts → models/model-pins.d.ts} +1 -1
  160. package/dist/models/model-pins.d.ts.map +1 -0
  161. package/dist/models/model-pins.js.map +1 -0
  162. package/dist/{model-roles.d.ts → models/model-roles.d.ts} +0 -33
  163. package/dist/models/model-roles.d.ts.map +1 -0
  164. package/dist/{model-roles.js → models/model-roles.js} +0 -35
  165. package/dist/models/model-roles.js.map +1 -0
  166. package/dist/{plan-pools.d.ts → models/plan-pools.d.ts} +1 -1
  167. package/dist/models/plan-pools.d.ts.map +1 -0
  168. package/dist/models/plan-pools.js.map +1 -0
  169. package/dist/models/prompt-complexity.d.ts.map +1 -0
  170. package/dist/models/prompt-complexity.js.map +1 -0
  171. package/dist/models/provider-specs.d.ts.map +1 -0
  172. package/dist/models/provider-specs.js.map +1 -0
  173. package/dist/policy/approvals-execution.d.ts.map +1 -0
  174. package/dist/policy/approvals-execution.js.map +1 -0
  175. package/dist/{batch-runs.d.ts → policy/batch-runs.d.ts} +5 -1
  176. package/dist/policy/batch-runs.d.ts.map +1 -0
  177. package/dist/{batch-runs.js → policy/batch-runs.js} +10 -7
  178. package/dist/policy/batch-runs.js.map +1 -0
  179. package/dist/policy/capability-env.d.ts.map +1 -0
  180. package/dist/policy/capability-env.js.map +1 -0
  181. package/dist/policy/capability-secrets.d.ts.map +1 -0
  182. package/dist/policy/capability-secrets.js.map +1 -0
  183. package/dist/{card-status.d.ts → policy/card-status.d.ts} +2 -2
  184. package/dist/policy/card-status.d.ts.map +1 -0
  185. package/dist/{card-status.js → policy/card-status.js} +1 -5
  186. package/dist/policy/card-status.js.map +1 -0
  187. package/dist/{command-classes.d.ts → policy/command-classes.d.ts} +6 -2
  188. package/dist/policy/command-classes.d.ts.map +1 -0
  189. package/dist/{command-classes.js → policy/command-classes.js} +48 -11
  190. package/dist/policy/command-classes.js.map +1 -0
  191. package/dist/{command-run.d.ts → policy/command-run.d.ts} +1 -1
  192. package/dist/policy/command-run.d.ts.map +1 -0
  193. package/dist/policy/command-run.js.map +1 -0
  194. package/dist/policy/control-scopes.d.ts +16 -0
  195. package/dist/policy/control-scopes.d.ts.map +1 -0
  196. package/dist/policy/control-scopes.js +26 -0
  197. package/dist/policy/control-scopes.js.map +1 -0
  198. package/dist/policy/credential-material.d.ts.map +1 -0
  199. package/dist/policy/credential-material.js.map +1 -0
  200. package/dist/policy/needs-action.d.ts.map +1 -0
  201. package/dist/policy/needs-action.js.map +1 -0
  202. package/dist/policy/output-fields.d.ts.map +1 -0
  203. package/dist/policy/output-fields.js.map +1 -0
  204. package/dist/policy/overlay-lint.d.ts.map +1 -0
  205. package/dist/policy/overlay-lint.js.map +1 -0
  206. package/dist/policy/owner-ticket.d.ts.map +1 -0
  207. package/dist/{owner-ticket.js → policy/owner-ticket.js} +1 -1
  208. package/dist/policy/owner-ticket.js.map +1 -0
  209. package/dist/{safety-policy.d.ts → policy/safety-policy.d.ts} +6 -5
  210. package/dist/policy/safety-policy.d.ts.map +1 -0
  211. package/dist/{safety-policy.js → policy/safety-policy.js} +12 -12
  212. package/dist/policy/safety-policy.js.map +1 -0
  213. package/dist/policy/search-globs.d.ts.map +1 -0
  214. package/dist/policy/search-globs.js.map +1 -0
  215. package/dist/protocol/container-requirements.d.ts +20 -0
  216. package/dist/protocol/container-requirements.d.ts.map +1 -0
  217. package/dist/protocol/container-requirements.js +23 -0
  218. package/dist/protocol/container-requirements.js.map +1 -0
  219. package/dist/{host-protocol.d.ts → protocol/host-protocol.d.ts} +1 -0
  220. package/dist/protocol/host-protocol.d.ts.map +1 -0
  221. package/dist/{host-protocol.js → protocol/host-protocol.js} +1 -0
  222. package/dist/protocol/host-protocol.js.map +1 -0
  223. package/dist/protocol/ingress-contract.d.ts.map +1 -0
  224. package/dist/{ingress-contract.js → protocol/ingress-contract.js} +1 -1
  225. package/dist/protocol/ingress-contract.js.map +1 -0
  226. package/dist/protocol/ingress-protocol.d.ts.map +1 -0
  227. package/dist/protocol/ingress-protocol.js.map +1 -0
  228. package/dist/protocol/listener-protocol.d.ts.map +1 -0
  229. package/dist/{listener-protocol.js → protocol/listener-protocol.js} +1 -1
  230. package/dist/protocol/listener-protocol.js.map +1 -0
  231. package/dist/{peer-dial.d.ts → protocol/peer-dial.d.ts} +4 -1
  232. package/dist/protocol/peer-dial.d.ts.map +1 -0
  233. package/dist/{peer-dial.js → protocol/peer-dial.js} +51 -10
  234. package/dist/protocol/peer-dial.js.map +1 -0
  235. package/dist/protocol/peer-mcp-server.d.ts.map +1 -0
  236. package/dist/protocol/peer-mcp-server.js.map +1 -0
  237. package/dist/protocol/request-id.d.ts.map +1 -0
  238. package/dist/protocol/request-id.js.map +1 -0
  239. package/dist/protocol/routes.d.ts.map +1 -0
  240. package/dist/protocol/routes.js.map +1 -0
  241. package/dist/{runner-protocol.d.ts → protocol/runner-protocol.d.ts} +1 -0
  242. package/dist/protocol/runner-protocol.d.ts.map +1 -0
  243. package/dist/{runner-protocol.js → protocol/runner-protocol.js} +2 -1
  244. package/dist/protocol/runner-protocol.js.map +1 -0
  245. package/dist/protocol/sse.d.ts.map +1 -0
  246. package/dist/protocol/sse.js.map +1 -0
  247. package/dist/{terminal-protocol.d.ts → protocol/terminal-protocol.d.ts} +1 -3
  248. package/dist/protocol/terminal-protocol.d.ts.map +1 -0
  249. package/dist/protocol/terminal-protocol.js.map +1 -0
  250. package/dist/protocol/webext-links.d.ts.map +1 -0
  251. package/dist/protocol/webext-links.js.map +1 -0
  252. package/dist/{webext-protocol.d.ts → protocol/webext-protocol.d.ts} +1 -0
  253. package/dist/protocol/webext-protocol.d.ts.map +1 -0
  254. package/dist/{webext-protocol.js → protocol/webext-protocol.js} +1 -0
  255. package/dist/protocol/webext-protocol.js.map +1 -0
  256. package/dist/schemas/activity.d.ts +2 -0
  257. package/dist/schemas/activity.d.ts.map +1 -1
  258. package/dist/schemas/activity.js +4 -0
  259. package/dist/schemas/activity.js.map +1 -1
  260. package/dist/schemas/agent.d.ts +16 -4
  261. package/dist/schemas/agent.d.ts.map +1 -1
  262. package/dist/schemas/agent.js +21 -4
  263. package/dist/schemas/agent.js.map +1 -1
  264. package/dist/schemas/agents.d.ts +17 -4
  265. package/dist/schemas/agents.d.ts.map +1 -1
  266. package/dist/schemas/agents.js +15 -4
  267. package/dist/schemas/agents.js.map +1 -1
  268. package/dist/schemas/approvals.d.ts.map +1 -1
  269. package/dist/schemas/approvals.js.map +1 -1
  270. package/dist/schemas/automations.d.ts +54 -28
  271. package/dist/schemas/automations.d.ts.map +1 -1
  272. package/dist/schemas/automations.js +26 -8
  273. package/dist/schemas/automations.js.map +1 -1
  274. package/dist/schemas/capabilities.d.ts +0 -8
  275. package/dist/schemas/capabilities.d.ts.map +1 -1
  276. package/dist/schemas/capabilities.js +0 -4
  277. package/dist/schemas/capabilities.js.map +1 -1
  278. package/dist/schemas/ci.d.ts +10 -0
  279. package/dist/schemas/ci.d.ts.map +1 -1
  280. package/dist/schemas/ci.js +9 -1
  281. package/dist/schemas/ci.js.map +1 -1
  282. package/dist/schemas/codebase-health.d.ts.map +1 -1
  283. package/dist/schemas/codebase-health.js.map +1 -1
  284. package/dist/schemas/devices.d.ts +90 -0
  285. package/dist/schemas/devices.d.ts.map +1 -1
  286. package/dist/schemas/devices.js +10 -1
  287. package/dist/schemas/devices.js.map +1 -1
  288. package/dist/schemas/engines.d.ts.map +1 -1
  289. package/dist/schemas/engines.js.map +1 -1
  290. package/dist/schemas/environment.d.ts.map +1 -1
  291. package/dist/schemas/environment.js.map +1 -1
  292. package/dist/schemas/exit.d.ts.map +1 -1
  293. package/dist/schemas/exit.js.map +1 -1
  294. package/dist/schemas/extension-updates.d.ts.map +1 -1
  295. package/dist/schemas/extension-updates.js.map +1 -1
  296. package/dist/schemas/git-history.d.ts.map +1 -1
  297. package/dist/schemas/git-history.js.map +1 -1
  298. package/dist/schemas/git.d.ts +80 -16
  299. package/dist/schemas/git.d.ts.map +1 -1
  300. package/dist/schemas/git.js +37 -25
  301. package/dist/schemas/git.js.map +1 -1
  302. package/dist/schemas/history.d.ts.map +1 -1
  303. package/dist/schemas/history.js.map +1 -1
  304. package/dist/schemas/hosts.d.ts.map +1 -1
  305. package/dist/schemas/hosts.js.map +1 -1
  306. package/dist/schemas/inventory.d.ts.map +1 -1
  307. package/dist/schemas/inventory.js.map +1 -1
  308. package/dist/schemas/issues.d.ts +0 -1
  309. package/dist/schemas/issues.d.ts.map +1 -1
  310. package/dist/schemas/issues.js +0 -1
  311. package/dist/schemas/issues.js.map +1 -1
  312. package/dist/schemas/logs.d.ts.map +1 -1
  313. package/dist/schemas/logs.js.map +1 -1
  314. package/dist/schemas/loops.d.ts.map +1 -1
  315. package/dist/schemas/loops.js +1 -1
  316. package/dist/schemas/loops.js.map +1 -1
  317. package/dist/schemas/maintenance.d.ts.map +1 -1
  318. package/dist/schemas/maintenance.js.map +1 -1
  319. package/dist/schemas/marketplace.d.ts +0 -4
  320. package/dist/schemas/marketplace.d.ts.map +1 -1
  321. package/dist/schemas/panels.d.ts.map +1 -1
  322. package/dist/schemas/panels.js.map +1 -1
  323. package/dist/schemas/personas.d.ts +2 -1
  324. package/dist/schemas/personas.d.ts.map +1 -1
  325. package/dist/schemas/personas.js +6 -2
  326. package/dist/schemas/personas.js.map +1 -1
  327. package/dist/schemas/plan-limits.d.ts +2 -4
  328. package/dist/schemas/plan-limits.d.ts.map +1 -1
  329. package/dist/schemas/plan-limits.js +5 -8
  330. package/dist/schemas/plan-limits.js.map +1 -1
  331. package/dist/schemas/ports.d.ts.map +1 -1
  332. package/dist/schemas/ports.js.map +1 -1
  333. package/dist/schemas/provider-oauth.d.ts.map +1 -1
  334. package/dist/schemas/provider-oauth.js.map +1 -1
  335. package/dist/schemas/provider-subscriptions.d.ts +1 -1
  336. package/dist/schemas/provider-subscriptions.d.ts.map +1 -1
  337. package/dist/schemas/provider-subscriptions.js +1 -1
  338. package/dist/schemas/provider-subscriptions.js.map +1 -1
  339. package/dist/schemas/public.d.ts.map +1 -1
  340. package/dist/schemas/public.js.map +1 -1
  341. package/dist/schemas/push.d.ts.map +1 -1
  342. package/dist/schemas/push.js.map +1 -1
  343. package/dist/schemas/secrets.d.ts.map +1 -1
  344. package/dist/schemas/secrets.js.map +1 -1
  345. package/dist/schemas/settings.d.ts +6 -9
  346. package/dist/schemas/settings.d.ts.map +1 -1
  347. package/dist/schemas/settings.js +16 -5
  348. package/dist/schemas/settings.js.map +1 -1
  349. package/dist/schemas/share.d.ts.map +1 -1
  350. package/dist/schemas/share.js.map +1 -1
  351. package/dist/schemas/shared.d.ts +4 -0
  352. package/dist/schemas/shared.d.ts.map +1 -1
  353. package/dist/schemas/shared.js +3 -0
  354. package/dist/schemas/shared.js.map +1 -1
  355. package/dist/schemas/system.d.ts +6 -0
  356. package/dist/schemas/system.d.ts.map +1 -1
  357. package/dist/schemas/system.js +10 -0
  358. package/dist/schemas/system.js.map +1 -1
  359. package/dist/schemas/terminal.d.ts.map +1 -1
  360. package/dist/schemas/terminal.js.map +1 -1
  361. package/dist/schemas/usage.d.ts.map +1 -1
  362. package/dist/schemas/usage.js.map +1 -1
  363. package/dist/schemas/vpn.d.ts.map +1 -1
  364. package/dist/schemas/vpn.js.map +1 -1
  365. package/dist/schemas/webext.d.ts.map +1 -1
  366. package/dist/schemas/webext.js.map +1 -1
  367. package/dist/schemas/workflows.d.ts +66 -9
  368. package/dist/schemas/workflows.d.ts.map +1 -1
  369. package/dist/schemas/workflows.js +6 -5
  370. package/dist/schemas/workflows.js.map +1 -1
  371. package/dist/schemas/workspace-repos.d.ts.map +1 -1
  372. package/dist/schemas/workspace-repos.js.map +1 -1
  373. package/dist/schemas/workspace-search.d.ts.map +1 -1
  374. package/dist/schemas/workspace-search.js.map +1 -1
  375. package/dist/schemas/workspace-setup.d.ts.map +1 -1
  376. package/dist/schemas/workspace-setup.js.map +1 -1
  377. package/dist/schemas/workspace-tree.d.ts.map +1 -1
  378. package/dist/schemas/workspace-tree.js.map +1 -1
  379. package/dist/state/arrival.d.ts.map +1 -0
  380. package/dist/{arrival.js → state/arrival.js} +1 -1
  381. package/dist/state/arrival.js.map +1 -0
  382. package/dist/state/contract-lock.d.ts.map +1 -0
  383. package/dist/{contract-lock.js → state/contract-lock.js} +1 -1
  384. package/dist/state/contract-lock.js.map +1 -0
  385. package/dist/{definition.d.ts → state/definition.d.ts} +21 -17
  386. package/dist/state/definition.d.ts.map +1 -0
  387. package/dist/{definition.js → state/definition.js} +4 -4
  388. package/dist/state/definition.js.map +1 -0
  389. package/dist/state/history-state.d.ts.map +1 -0
  390. package/dist/{history-state.js → state/history-state.js} +1 -0
  391. package/dist/state/history-state.js.map +1 -0
  392. package/dist/state/runtime-state.d.ts.map +1 -0
  393. package/dist/state/runtime-state.js.map +1 -0
  394. package/dist/state/starter.d.ts.map +1 -0
  395. package/dist/state/starter.js.map +1 -0
  396. package/dist/state/state-portability.d.ts.map +1 -0
  397. package/dist/state/state-portability.js.map +1 -0
  398. package/dist/state/versions.d.ts.map +1 -0
  399. package/dist/state/versions.js.map +1 -0
  400. package/dist/{workspace-state.d.ts → state/workspace-state.d.ts} +8 -0
  401. package/dist/state/workspace-state.d.ts.map +1 -0
  402. package/dist/{workspace-state.js → state/workspace-state.js} +25 -0
  403. package/dist/state/workspace-state.js.map +1 -0
  404. package/dist/{documents.d.ts → text/documents.d.ts} +1 -1
  405. package/dist/text/documents.d.ts.map +1 -0
  406. package/dist/{documents.js → text/documents.js} +1 -1
  407. package/dist/text/documents.js.map +1 -0
  408. package/dist/text/embed.d.ts.map +1 -0
  409. package/dist/text/embed.js.map +1 -0
  410. package/dist/text/mentions.d.ts.map +1 -0
  411. package/dist/text/mentions.js.map +1 -0
  412. package/dist/text/model-answer.d.ts +3 -0
  413. package/dist/text/model-answer.d.ts.map +1 -0
  414. package/dist/text/model-answer.js +3 -0
  415. package/dist/text/model-answer.js.map +1 -0
  416. package/dist/text/path-refs.d.ts.map +1 -0
  417. package/dist/text/path-refs.js.map +1 -0
  418. package/dist/{shell-regions.d.ts → text/shell-regions.d.ts} +1 -1
  419. package/dist/text/shell-regions.d.ts.map +1 -0
  420. package/dist/text/shell-regions.js.map +1 -0
  421. package/dist/text/title.d.ts.map +1 -0
  422. package/dist/text/title.js.map +1 -0
  423. package/dist/{transcript-fold.d.ts → text/transcript-fold.d.ts} +2 -1
  424. package/dist/text/transcript-fold.d.ts.map +1 -0
  425. package/dist/{transcript-fold.js → text/transcript-fold.js} +2 -16
  426. package/dist/text/transcript-fold.js.map +1 -0
  427. package/dist/text/whisper.d.ts +3 -0
  428. package/dist/text/whisper.d.ts.map +1 -0
  429. package/dist/text/whisper.js +11 -0
  430. package/dist/text/whisper.js.map +1 -0
  431. package/dist/{workflow-faults.d.ts → text/workflow-faults.d.ts} +1 -1
  432. package/dist/text/workflow-faults.d.ts.map +1 -0
  433. package/dist/{workflow-faults.js → text/workflow-faults.js} +1 -1
  434. package/dist/text/workflow-faults.js.map +1 -0
  435. package/package.json +70 -70
  436. package/src/chores/chores.test.ts +4 -10
  437. package/src/chores/chores.ts +148 -392
  438. package/src/chores/digest.ts +8 -28
  439. package/src/chores/extension-update.ts +3 -8
  440. package/src/chores/fix-deps.ts +4 -18
  441. package/src/chores/index.ts +2 -2
  442. package/src/chores/probes.test.ts +7 -43
  443. package/src/chores/probes.ts +62 -167
  444. package/src/chores/prompt.ts +10 -34
  445. package/src/chores/stack.test.ts +6 -45
  446. package/src/chores/stack.ts +27 -118
  447. package/src/chores/verdict.test.ts +101 -80
  448. package/src/chores/verdict.ts +54 -99
  449. package/src/contracts/accounts.contract.ts +4 -19
  450. package/src/contracts/agent.contract.ts +7 -22
  451. package/src/contracts/agents.contract.ts +25 -71
  452. package/src/contracts/automations.contract.ts +14 -30
  453. package/src/contracts/capabilities.contract.ts +8 -35
  454. package/src/contracts/chores.contract.ts +4 -15
  455. package/src/contracts/endpoints.contract.ts +5 -22
  456. package/src/contracts/exit.contract.ts +7 -30
  457. package/src/contracts/extensions.contract.ts +8 -30
  458. package/src/contracts/git.contract.ts +25 -49
  459. package/src/contracts/host.contract.ts +9 -44
  460. package/src/contracts/intentic.contract.ts +1 -1
  461. package/src/contracts/logs.contract.ts +3 -13
  462. package/src/contracts/loops.contract.ts +9 -40
  463. package/src/contracts/personas.contract.ts +10 -35
  464. package/src/contracts/providers.contract.ts +4 -17
  465. package/src/contracts/runner.contract.ts +12 -39
  466. package/src/contracts/safety.contract.ts +5 -14
  467. package/src/contracts/secrets.contract.ts +4 -22
  468. package/src/contracts/sessions.contract.ts +1 -1
  469. package/src/contracts/settings.contract.ts +4 -10
  470. package/src/contracts/share.contract.ts +3 -9
  471. package/src/contracts/skills.contract.ts +4 -15
  472. package/src/contracts/system.contract.ts +26 -52
  473. package/src/contracts/usage.contract.ts +7 -21
  474. package/src/contracts/vpn.contract.ts +9 -16
  475. package/src/contracts/webext.contract.ts +9 -25
  476. package/src/contracts/workflows.contract.ts +34 -58
  477. package/src/contracts/workspace.contract.ts +19 -50
  478. package/src/events/agent-events.ts +345 -0
  479. package/src/events/cards.ts +286 -0
  480. package/src/{events.test.ts → events/resume.test.ts} +4 -19
  481. package/src/events/resume.ts +60 -0
  482. package/src/events/system-events.ts +139 -0
  483. package/src/events/transcript.ts +320 -0
  484. package/src/{conversation-ids.test.ts → ids/conversation-ids.test.ts} +25 -13
  485. package/src/ids/conversation-ids.ts +178 -0
  486. package/src/ids/hostnames.ts +129 -0
  487. package/src/ids/session-names.ts +29 -0
  488. package/src/ids/share-paths.ts +43 -0
  489. package/src/{tunnel-ids.test.ts → ids/tunnel-ids.test.ts} +1 -14
  490. package/src/ids/tunnel-ids.ts +29 -0
  491. package/src/index.ts +71 -87
  492. package/src/{agent-catalog.test.ts → models/agent-catalog.test.ts} +19 -93
  493. package/src/models/agent-catalog.ts +174 -0
  494. package/src/models/agent-runtimes.ts +201 -0
  495. package/src/models/capability-ledger.test.ts +84 -0
  496. package/src/{fast-tier.test.ts → models/fast-tier.test.ts} +7 -18
  497. package/src/models/fast-tier.ts +36 -0
  498. package/src/{model-order.test.ts → models/model-order.test.ts} +19 -40
  499. package/src/models/model-order.ts +163 -0
  500. package/src/{model-pins.test.ts → models/model-pins.test.ts} +12 -46
  501. package/src/models/model-pins.ts +57 -0
  502. package/src/models/model-roles.test.ts +38 -0
  503. package/src/models/model-roles.ts +180 -0
  504. package/src/{plan-pools.test.ts → models/plan-pools.test.ts} +6 -11
  505. package/src/models/plan-pools.ts +65 -0
  506. package/src/{prompt-complexity.test.ts → models/prompt-complexity.test.ts} +8 -60
  507. package/src/models/prompt-complexity.ts +215 -0
  508. package/src/{provider-specs.test.ts → models/provider-specs.test.ts} +18 -47
  509. package/src/models/provider-specs.ts +272 -0
  510. package/src/policy/approvals-execution.ts +58 -0
  511. package/src/{batch-runs.test.ts → policy/batch-runs.test.ts} +4 -20
  512. package/src/policy/batch-runs.ts +137 -0
  513. package/src/policy/capability-secrets.ts +5 -0
  514. package/src/{card-status.ts → policy/card-status.ts} +11 -26
  515. package/src/{command-classes.test.ts → policy/command-classes.test.ts} +11 -118
  516. package/src/policy/command-classes.ts +395 -0
  517. package/src/policy/command-run.ts +65 -0
  518. package/src/policy/control-scopes.ts +38 -0
  519. package/src/{credential-material.test.ts → policy/credential-material.test.ts} +4 -26
  520. package/src/policy/credential-material.ts +91 -0
  521. package/src/policy/needs-action.ts +5 -0
  522. package/src/policy/output-fields.ts +86 -0
  523. package/src/policy/overlay-lint.ts +100 -0
  524. package/src/{owner-ticket.test.ts → policy/owner-ticket.test.ts} +1 -1
  525. package/src/{owner-ticket.ts → policy/owner-ticket.ts} +9 -31
  526. package/src/policy/safety-policy.test.ts +84 -0
  527. package/src/policy/safety-policy.ts +142 -0
  528. package/src/policy/search-globs.ts +60 -0
  529. package/src/protocol/container-requirements.test.ts +72 -0
  530. package/src/protocol/container-requirements.ts +58 -0
  531. package/src/protocol/host-protocol.ts +29 -0
  532. package/src/protocol/ingress-contract.ts +103 -0
  533. package/src/{ingress-protocol.test.ts → protocol/ingress-protocol.test.ts} +25 -90
  534. package/src/protocol/ingress-protocol.ts +441 -0
  535. package/src/protocol/listener-protocol.ts +75 -0
  536. package/src/{peer-dial.test.ts → protocol/peer-dial.test.ts} +52 -1
  537. package/src/protocol/peer-dial.ts +207 -0
  538. package/src/{peer-mcp-server.ts → protocol/peer-mcp-server.ts} +16 -41
  539. package/src/protocol/request-id.ts +5 -0
  540. package/src/{routes.test.ts → protocol/routes.test.ts} +14 -22
  541. package/src/protocol/routes.ts +159 -0
  542. package/src/protocol/runner-protocol.ts +197 -0
  543. package/src/protocol/terminal-protocol.ts +13 -0
  544. package/src/protocol/webext-links.ts +50 -0
  545. package/src/protocol/webext-protocol.ts +24 -0
  546. package/src/schemas/activity.ts +22 -30
  547. package/src/schemas/agent.ts +130 -238
  548. package/src/schemas/agents.ts +165 -483
  549. package/src/schemas/approvals.ts +23 -71
  550. package/src/schemas/automations.ts +142 -250
  551. package/src/schemas/capabilities.ts +127 -414
  552. package/src/schemas/ci.ts +56 -108
  553. package/src/schemas/codebase-health.ts +7 -11
  554. package/src/schemas/devices.ts +98 -321
  555. package/src/schemas/engines.ts +16 -44
  556. package/src/schemas/environment.ts +41 -91
  557. package/src/schemas/exit.ts +24 -81
  558. package/src/schemas/extension-updates.ts +42 -87
  559. package/src/schemas/git-history.ts +30 -84
  560. package/src/schemas/git.ts +141 -256
  561. package/src/schemas/history.ts +14 -40
  562. package/src/schemas/hosts.ts +9 -15
  563. package/src/schemas/inventory.ts +8 -10
  564. package/src/schemas/issues.ts +66 -134
  565. package/src/schemas/logs.ts +15 -34
  566. package/src/schemas/loops.ts +46 -163
  567. package/src/schemas/maintenance.ts +47 -172
  568. package/src/schemas/panels.ts +20 -45
  569. package/src/schemas/personas.ts +50 -200
  570. package/src/schemas/plan-limits.ts +58 -197
  571. package/src/schemas/ports.ts +14 -32
  572. package/src/schemas/provider-oauth.ts +23 -76
  573. package/src/schemas/provider-subscriptions.ts +4 -13
  574. package/src/schemas/public.ts +4 -15
  575. package/src/schemas/push.ts +8 -36
  576. package/src/schemas/secrets.ts +20 -64
  577. package/src/schemas/settings.ts +175 -600
  578. package/src/schemas/share.ts +14 -32
  579. package/src/schemas/shared.ts +14 -13
  580. package/src/schemas/system.ts +46 -78
  581. package/src/schemas/terminal.ts +41 -120
  582. package/src/schemas/usage.ts +44 -233
  583. package/src/schemas/version-seam.test.ts +9 -26
  584. package/src/schemas/vpn.ts +27 -64
  585. package/src/schemas/webext.ts +22 -53
  586. package/src/schemas/workflows.ts +57 -183
  587. package/src/schemas/workspace-repos.ts +12 -24
  588. package/src/schemas/workspace-search.ts +17 -35
  589. package/src/schemas/workspace-setup.ts +4 -11
  590. package/src/schemas/workspace-tree.ts +32 -91
  591. package/src/state/arrival.ts +109 -0
  592. package/src/state/contract-lock.test.ts +17 -0
  593. package/src/state/contract-lock.ts +49 -0
  594. package/src/state/definition.ts +143 -0
  595. package/src/state/history-state.ts +103 -0
  596. package/src/{runtime-state.test.ts → state/runtime-state.test.ts} +3 -10
  597. package/src/state/runtime-state.ts +62 -0
  598. package/src/state/starter.ts +5 -0
  599. package/src/state/state-portability.ts +27 -0
  600. package/src/state/versions.ts +26 -0
  601. package/src/{workspace-state.test.ts → state/workspace-state.test.ts} +65 -172
  602. package/src/state/workspace-state.ts +669 -0
  603. package/src/{documents.test.ts → text/documents.test.ts} +1 -1
  604. package/src/text/documents.ts +42 -0
  605. package/src/text/embed.ts +132 -0
  606. package/src/text/mentions.ts +21 -0
  607. package/src/text/model-answer.ts +9 -0
  608. package/src/text/path-refs.ts +39 -0
  609. package/src/text/shell-regions.ts +224 -0
  610. package/src/{title.test.ts → text/title.test.ts} +13 -32
  611. package/src/text/title.ts +202 -0
  612. package/src/{transcript-fold.test.ts → text/transcript-fold.test.ts} +5 -83
  613. package/src/{transcript-fold.ts → text/transcript-fold.ts} +65 -170
  614. package/src/text/whisper.test.ts +19 -0
  615. package/src/text/whisper.ts +17 -0
  616. package/src/{workflow-faults.test.ts → text/workflow-faults.test.ts} +6 -24
  617. package/src/{workflow-faults.ts → text/workflow-faults.ts} +20 -60
  618. package/dist/agent-catalog.d.ts.map +0 -1
  619. package/dist/agent-catalog.js.map +0 -1
  620. package/dist/agent-runtimes.d.ts.map +0 -1
  621. package/dist/agent-runtimes.js.map +0 -1
  622. package/dist/approvals-execution.d.ts.map +0 -1
  623. package/dist/approvals-execution.js.map +0 -1
  624. package/dist/arrival.d.ts.map +0 -1
  625. package/dist/arrival.js.map +0 -1
  626. package/dist/batch-runs.d.ts.map +0 -1
  627. package/dist/batch-runs.js.map +0 -1
  628. package/dist/capability-env.d.ts.map +0 -1
  629. package/dist/capability-env.js.map +0 -1
  630. package/dist/capability-secrets.d.ts.map +0 -1
  631. package/dist/capability-secrets.js.map +0 -1
  632. package/dist/card-status.d.ts.map +0 -1
  633. package/dist/card-status.js.map +0 -1
  634. package/dist/command-classes.d.ts.map +0 -1
  635. package/dist/command-classes.js.map +0 -1
  636. package/dist/command-run.d.ts.map +0 -1
  637. package/dist/command-run.js.map +0 -1
  638. package/dist/contract-lock.d.ts.map +0 -1
  639. package/dist/contract-lock.js.map +0 -1
  640. package/dist/conversation-ids.d.ts +0 -4
  641. package/dist/conversation-ids.d.ts.map +0 -1
  642. package/dist/conversation-ids.js.map +0 -1
  643. package/dist/credential-material.d.ts.map +0 -1
  644. package/dist/credential-material.js.map +0 -1
  645. package/dist/definition.d.ts.map +0 -1
  646. package/dist/definition.js.map +0 -1
  647. package/dist/documents.d.ts.map +0 -1
  648. package/dist/documents.js.map +0 -1
  649. package/dist/embed.d.ts.map +0 -1
  650. package/dist/embed.js.map +0 -1
  651. package/dist/events.d.ts +0 -4336
  652. package/dist/events.d.ts.map +0 -1
  653. package/dist/events.js +0 -725
  654. package/dist/events.js.map +0 -1
  655. package/dist/fast-tier.d.ts.map +0 -1
  656. package/dist/fast-tier.js.map +0 -1
  657. package/dist/history-state.d.ts.map +0 -1
  658. package/dist/history-state.js.map +0 -1
  659. package/dist/host-protocol.d.ts.map +0 -1
  660. package/dist/host-protocol.js.map +0 -1
  661. package/dist/hostnames.d.ts.map +0 -1
  662. package/dist/hostnames.js.map +0 -1
  663. package/dist/ingress-contract.d.ts.map +0 -1
  664. package/dist/ingress-contract.js.map +0 -1
  665. package/dist/ingress-protocol.d.ts.map +0 -1
  666. package/dist/ingress-protocol.js.map +0 -1
  667. package/dist/listener-protocol.d.ts.map +0 -1
  668. package/dist/listener-protocol.js.map +0 -1
  669. package/dist/mentions.d.ts.map +0 -1
  670. package/dist/mentions.js.map +0 -1
  671. package/dist/model-order.d.ts.map +0 -1
  672. package/dist/model-order.js.map +0 -1
  673. package/dist/model-pins.d.ts.map +0 -1
  674. package/dist/model-pins.js.map +0 -1
  675. package/dist/model-roles.d.ts.map +0 -1
  676. package/dist/model-roles.js.map +0 -1
  677. package/dist/needs-action.d.ts.map +0 -1
  678. package/dist/needs-action.js.map +0 -1
  679. package/dist/output-fields.d.ts.map +0 -1
  680. package/dist/output-fields.js.map +0 -1
  681. package/dist/overlay-lint.d.ts.map +0 -1
  682. package/dist/overlay-lint.js.map +0 -1
  683. package/dist/owner-ticket.d.ts.map +0 -1
  684. package/dist/owner-ticket.js.map +0 -1
  685. package/dist/path-refs.d.ts.map +0 -1
  686. package/dist/path-refs.js.map +0 -1
  687. package/dist/peer-dial.d.ts.map +0 -1
  688. package/dist/peer-dial.js.map +0 -1
  689. package/dist/peer-mcp-server.d.ts.map +0 -1
  690. package/dist/peer-mcp-server.js.map +0 -1
  691. package/dist/plan-pools.d.ts.map +0 -1
  692. package/dist/plan-pools.js.map +0 -1
  693. package/dist/prompt-complexity.d.ts.map +0 -1
  694. package/dist/prompt-complexity.js.map +0 -1
  695. package/dist/provider-specs.d.ts.map +0 -1
  696. package/dist/provider-specs.js.map +0 -1
  697. package/dist/request-id.d.ts.map +0 -1
  698. package/dist/request-id.js.map +0 -1
  699. package/dist/routes.d.ts.map +0 -1
  700. package/dist/routes.js.map +0 -1
  701. package/dist/runner-protocol.d.ts.map +0 -1
  702. package/dist/runner-protocol.js.map +0 -1
  703. package/dist/runtime-state.d.ts.map +0 -1
  704. package/dist/runtime-state.js.map +0 -1
  705. package/dist/safety-policy.d.ts.map +0 -1
  706. package/dist/safety-policy.js.map +0 -1
  707. package/dist/search-globs.d.ts.map +0 -1
  708. package/dist/search-globs.js.map +0 -1
  709. package/dist/session-names.d.ts.map +0 -1
  710. package/dist/session-names.js.map +0 -1
  711. package/dist/share-paths.d.ts.map +0 -1
  712. package/dist/share-paths.js.map +0 -1
  713. package/dist/shell-regions.d.ts.map +0 -1
  714. package/dist/shell-regions.js.map +0 -1
  715. package/dist/sse.d.ts.map +0 -1
  716. package/dist/sse.js.map +0 -1
  717. package/dist/starter.d.ts.map +0 -1
  718. package/dist/starter.js.map +0 -1
  719. package/dist/state-portability.d.ts.map +0 -1
  720. package/dist/state-portability.js.map +0 -1
  721. package/dist/terminal-protocol.d.ts.map +0 -1
  722. package/dist/terminal-protocol.js.map +0 -1
  723. package/dist/title.d.ts.map +0 -1
  724. package/dist/title.js.map +0 -1
  725. package/dist/transcript-fold.d.ts.map +0 -1
  726. package/dist/transcript-fold.js.map +0 -1
  727. package/dist/tunnel-ids.d.ts.map +0 -1
  728. package/dist/tunnel-ids.js.map +0 -1
  729. package/dist/versions.d.ts.map +0 -1
  730. package/dist/versions.js.map +0 -1
  731. package/dist/webext-links.d.ts.map +0 -1
  732. package/dist/webext-links.js.map +0 -1
  733. package/dist/webext-protocol.d.ts.map +0 -1
  734. package/dist/webext-protocol.js.map +0 -1
  735. package/dist/workflow-faults.d.ts.map +0 -1
  736. package/dist/workflow-faults.js.map +0 -1
  737. package/dist/workspace-state.d.ts.map +0 -1
  738. package/dist/workspace-state.js.map +0 -1
  739. package/src/agent-catalog.ts +0 -316
  740. package/src/agent-runtimes.ts +0 -419
  741. package/src/approvals-execution.ts +0 -96
  742. package/src/arrival.ts +0 -160
  743. package/src/batch-runs.ts +0 -188
  744. package/src/capability-ledger.test.ts +0 -140
  745. package/src/capability-secrets.ts +0 -20
  746. package/src/command-classes.ts +0 -617
  747. package/src/command-run.ts +0 -78
  748. package/src/contract-lock.test.ts +0 -23
  749. package/src/contract-lock.ts +0 -66
  750. package/src/conversation-ids.ts +0 -207
  751. package/src/credential-material.ts +0 -181
  752. package/src/definition.ts +0 -207
  753. package/src/documents.ts +0 -67
  754. package/src/embed.ts +0 -164
  755. package/src/events.ts +0 -1870
  756. package/src/fast-tier.ts +0 -72
  757. package/src/history-state.ts +0 -174
  758. package/src/host-protocol.ts +0 -36
  759. package/src/hostnames.ts +0 -180
  760. package/src/ingress-contract.ts +0 -157
  761. package/src/ingress-protocol.ts +0 -625
  762. package/src/listener-protocol.ts +0 -96
  763. package/src/mentions.ts +0 -25
  764. package/src/model-order.ts +0 -262
  765. package/src/model-pins.ts +0 -132
  766. package/src/model-roles.test.ts +0 -52
  767. package/src/model-roles.ts +0 -320
  768. package/src/needs-action.ts +0 -14
  769. package/src/output-fields.ts +0 -111
  770. package/src/overlay-lint.ts +0 -116
  771. package/src/path-refs.ts +0 -59
  772. package/src/peer-dial.ts +0 -163
  773. package/src/plan-pools.ts +0 -92
  774. package/src/prompt-complexity.ts +0 -334
  775. package/src/provider-specs.ts +0 -432
  776. package/src/request-id.ts +0 -41
  777. package/src/routes.ts +0 -219
  778. package/src/runner-protocol.ts +0 -239
  779. package/src/runtime-state.ts +0 -140
  780. package/src/safety-policy.test.ts +0 -88
  781. package/src/safety-policy.ts +0 -258
  782. package/src/search-globs.ts +0 -76
  783. package/src/session-names.ts +0 -44
  784. package/src/share-paths.ts +0 -68
  785. package/src/shell-regions.ts +0 -289
  786. package/src/starter.ts +0 -13
  787. package/src/state-portability.ts +0 -56
  788. package/src/terminal-protocol.ts +0 -16
  789. package/src/title.ts +0 -267
  790. package/src/tunnel-ids.ts +0 -57
  791. package/src/versions.ts +0 -48
  792. package/src/webext-links.ts +0 -90
  793. package/src/webext-protocol.ts +0 -27
  794. package/src/workspace-state.ts +0 -1090
  795. /package/dist/{hostnames.d.ts → ids/hostnames.d.ts} +0 -0
  796. /package/dist/{hostnames.js → ids/hostnames.js} +0 -0
  797. /package/dist/{session-names.d.ts → ids/session-names.d.ts} +0 -0
  798. /package/dist/{session-names.js → ids/session-names.js} +0 -0
  799. /package/dist/{share-paths.d.ts → ids/share-paths.d.ts} +0 -0
  800. /package/dist/{share-paths.js → ids/share-paths.js} +0 -0
  801. /package/dist/{agent-catalog.js → models/agent-catalog.js} +0 -0
  802. /package/dist/{agent-runtimes.d.ts → models/agent-runtimes.d.ts} +0 -0
  803. /package/dist/{agent-runtimes.js → models/agent-runtimes.js} +0 -0
  804. /package/dist/{fast-tier.js → models/fast-tier.js} +0 -0
  805. /package/dist/{model-order.d.ts → models/model-order.d.ts} +0 -0
  806. /package/dist/{model-order.js → models/model-order.js} +0 -0
  807. /package/dist/{model-pins.js → models/model-pins.js} +0 -0
  808. /package/dist/{plan-pools.js → models/plan-pools.js} +0 -0
  809. /package/dist/{prompt-complexity.d.ts → models/prompt-complexity.d.ts} +0 -0
  810. /package/dist/{prompt-complexity.js → models/prompt-complexity.js} +0 -0
  811. /package/dist/{provider-specs.d.ts → models/provider-specs.d.ts} +0 -0
  812. /package/dist/{provider-specs.js → models/provider-specs.js} +0 -0
  813. /package/dist/{approvals-execution.d.ts → policy/approvals-execution.d.ts} +0 -0
  814. /package/dist/{approvals-execution.js → policy/approvals-execution.js} +0 -0
  815. /package/dist/{capability-env.d.ts → policy/capability-env.d.ts} +0 -0
  816. /package/dist/{capability-env.js → policy/capability-env.js} +0 -0
  817. /package/dist/{capability-secrets.d.ts → policy/capability-secrets.d.ts} +0 -0
  818. /package/dist/{capability-secrets.js → policy/capability-secrets.js} +0 -0
  819. /package/dist/{command-run.js → policy/command-run.js} +0 -0
  820. /package/dist/{credential-material.d.ts → policy/credential-material.d.ts} +0 -0
  821. /package/dist/{credential-material.js → policy/credential-material.js} +0 -0
  822. /package/dist/{needs-action.d.ts → policy/needs-action.d.ts} +0 -0
  823. /package/dist/{needs-action.js → policy/needs-action.js} +0 -0
  824. /package/dist/{output-fields.d.ts → policy/output-fields.d.ts} +0 -0
  825. /package/dist/{output-fields.js → policy/output-fields.js} +0 -0
  826. /package/dist/{overlay-lint.d.ts → policy/overlay-lint.d.ts} +0 -0
  827. /package/dist/{overlay-lint.js → policy/overlay-lint.js} +0 -0
  828. /package/dist/{owner-ticket.d.ts → policy/owner-ticket.d.ts} +0 -0
  829. /package/dist/{search-globs.d.ts → policy/search-globs.d.ts} +0 -0
  830. /package/dist/{search-globs.js → policy/search-globs.js} +0 -0
  831. /package/dist/{ingress-contract.d.ts → protocol/ingress-contract.d.ts} +0 -0
  832. /package/dist/{ingress-protocol.d.ts → protocol/ingress-protocol.d.ts} +0 -0
  833. /package/dist/{ingress-protocol.js → protocol/ingress-protocol.js} +0 -0
  834. /package/dist/{listener-protocol.d.ts → protocol/listener-protocol.d.ts} +0 -0
  835. /package/dist/{peer-mcp-server.d.ts → protocol/peer-mcp-server.d.ts} +0 -0
  836. /package/dist/{peer-mcp-server.js → protocol/peer-mcp-server.js} +0 -0
  837. /package/dist/{request-id.d.ts → protocol/request-id.d.ts} +0 -0
  838. /package/dist/{request-id.js → protocol/request-id.js} +0 -0
  839. /package/dist/{routes.d.ts → protocol/routes.d.ts} +0 -0
  840. /package/dist/{routes.js → protocol/routes.js} +0 -0
  841. /package/dist/{sse.d.ts → protocol/sse.d.ts} +0 -0
  842. /package/dist/{sse.js → protocol/sse.js} +0 -0
  843. /package/dist/{terminal-protocol.js → protocol/terminal-protocol.js} +0 -0
  844. /package/dist/{webext-links.d.ts → protocol/webext-links.d.ts} +0 -0
  845. /package/dist/{webext-links.js → protocol/webext-links.js} +0 -0
  846. /package/dist/{arrival.d.ts → state/arrival.d.ts} +0 -0
  847. /package/dist/{contract-lock.d.ts → state/contract-lock.d.ts} +0 -0
  848. /package/dist/{history-state.d.ts → state/history-state.d.ts} +0 -0
  849. /package/dist/{runtime-state.d.ts → state/runtime-state.d.ts} +0 -0
  850. /package/dist/{runtime-state.js → state/runtime-state.js} +0 -0
  851. /package/dist/{starter.d.ts → state/starter.d.ts} +0 -0
  852. /package/dist/{starter.js → state/starter.js} +0 -0
  853. /package/dist/{state-portability.d.ts → state/state-portability.d.ts} +0 -0
  854. /package/dist/{state-portability.js → state/state-portability.js} +0 -0
  855. /package/dist/{versions.d.ts → state/versions.d.ts} +0 -0
  856. /package/dist/{versions.js → state/versions.js} +0 -0
  857. /package/dist/{embed.d.ts → text/embed.d.ts} +0 -0
  858. /package/dist/{embed.js → text/embed.js} +0 -0
  859. /package/dist/{mentions.d.ts → text/mentions.d.ts} +0 -0
  860. /package/dist/{mentions.js → text/mentions.js} +0 -0
  861. /package/dist/{path-refs.d.ts → text/path-refs.d.ts} +0 -0
  862. /package/dist/{path-refs.js → text/path-refs.js} +0 -0
  863. /package/dist/{shell-regions.js → text/shell-regions.js} +0 -0
  864. /package/dist/{title.d.ts → text/title.d.ts} +0 -0
  865. /package/dist/{title.js → text/title.js} +0 -0
  866. /package/src/{hostnames.test.ts → ids/hostnames.test.ts} +0 -0
  867. /package/src/{share-paths.test.ts → ids/share-paths.test.ts} +0 -0
  868. /package/src/{capability-env.ts → policy/capability-env.ts} +0 -0
  869. /package/src/{overlay-lint.test.ts → policy/overlay-lint.test.ts} +0 -0
  870. /package/src/{search-globs.test.ts → policy/search-globs.test.ts} +0 -0
  871. /package/src/{ingress-contract.test.ts → protocol/ingress-contract.test.ts} +0 -0
  872. /package/src/{peer-mcp-server.test.ts → protocol/peer-mcp-server.test.ts} +0 -0
  873. /package/src/{sse.ts → protocol/sse.ts} +0 -0
  874. /package/src/{versions.test.ts → state/versions.test.ts} +0 -0
  875. /package/src/{embed.test.ts → text/embed.test.ts} +0 -0
  876. /package/src/{mentions.test.ts → text/mentions.test.ts} +0 -0
  877. /package/src/{path-refs.test.ts → text/path-refs.test.ts} +0 -0
@@ -1,41 +1,25 @@
1
1
  // settings: per-sandbox agent settings (.intentic/config/settings.json)
2
2
  import { z } from "zod";
3
- import { CommandJudgeModeSchema } from "../safety-policy.js";
4
- import { ModelRoleSchema } from "../model-roles.js";
3
+ import { CommandJudgeModeSchema } from "../policy/safety-policy.js";
4
+ import { ModelRoleSchema } from "../models/model-roles.js";
5
5
  import { AdmissionPolicySchema, AdmissionRuleSchema, ModelPinSchema } from "./agent.js";
6
- // Which prompt the agent is, before this turn composes anything on top. Two built-in bases and an escape
7
- // hatch: Intentic's own (the default), Claude Code's preset, or the owner's text. Declared out here rather
8
- // than inline in the settings object because both sides of the wire branch on it, the daemon to build the
9
- // turn, the browser to decide which base it can show you.
6
+ // Which prompt base the agent runs before this turn composes anything on top: Intentic's own (default), Claude Code's
7
+ // preset, or the owner's text. Declared out here since both the daemon and the browser branch on it.
10
8
  export const SystemPromptModeSchema = z.enum(["intentic", "claude", "custom"]);
11
9
  export type SystemPromptMode = z.infer<typeof SystemPromptModeSchema>;
12
- // The two bases a user can READ and fork, "custom" is excluded because there is nothing to fetch: it is
13
- // whatever they have already typed into the settings field.
10
+ // Excludes "custom": there is nothing to fetch, it's whatever the owner already typed into the settings field.
14
11
  export const BuiltinPromptSchema = z.object({ base: z.enum(["intentic", "claude"]) });
15
- // How far the dependency-freshness check may go, see the settings field of the same name for why the middle
16
- // state exists. Declared out here because the daemon branches on it in three places (whether to wire the hook,
17
- // whether to consult the successor list, what the notice may say) and the browser branches on it to draw the
18
- // row: a bare inline enum would have each of those spelling the literals for itself.
12
+ // Declared out here because the daemon branches on it in three places (whether to wire the hook, consult the successor
13
+ // list, what the notice says) and the browser branches on it too.
19
14
  export const DependencyFreshnessSchema = z.enum(["off", "versions", "full"]);
20
15
  export type DependencyFreshness = z.infer<typeof DependencyFreshnessSchema>;
21
- /* ---- rules: "at this moment, if this is true, do this" ------------------------------------------------------
22
- *
23
- * The one table behind every standing instruction the owner gives the sandbox about its own work. It replaces
24
- * three settings that were the same idea built three ways, ask for proof before a turn ends, run a command
25
- * before a push, hold or release finished work, and the point of replacing them is that a FOURTH is now a row
26
- * in this table rather than a release.
27
- *
28
- * The moments are named to sit in one family with WorkspaceEventKind (`turn.settled`, `agent.landed`), because
29
- * chores already wake on those and folding them into this table later must not mean renaming what users wrote.
30
- */
16
+ // Rules: "at this moment, if this is true, do this" — one table replacing three settings that were the same idea built
17
+ // three ways; a fourth is now a row here, not a release. Moments are named to match `WorkspaceEventKind`, so folding
18
+ // chores in later won't rename what users wrote.
31
19
 
32
- // WHERE a rule can stand. Four, and each is a place the daemon already stopped to make a decision, this
33
- // names those decisions rather than inventing new ones.
20
+ // Four places the daemon already stops to decide something; this names those decisions rather than inventing new ones.
34
21
  export const RuleMomentSchema = z.enum([
35
- // The assistant has just written a file, with an edit tool or with a shell command; the tree says which. A
36
- // command here runs on that one file (`{file}` in the command is its path) and what it prints on a non-zero
37
- // exit rides back with the edit's own result, while the file is still in mind. The cheapest moment a defect
38
- // can be caught at, and the one the per-edit linter and byte scan stand at.
22
+ // A command here runs on the just-written file (`{file}` is its path); the cheapest moment to catch a defect.
39
23
  "file.edited",
40
24
  // The assistant is about to stop. A rule here can send it back to work, which is the only moment that can.
41
25
  "turn.ending",
@@ -45,36 +29,24 @@ export const RuleMomentSchema = z.enum([
45
29
  "agent.finished",
46
30
  ]);
47
31
  export type RuleMoment = z.infer<typeof RuleMomentSchema>;
48
- /* WHAT A RULE DOES. Four shapes, and the split is functional rather than tidy: the three settings this table
49
- * replaces need three DIFFERENT ones, which is the evidence that a single "run this command" table would have
50
- * mangled at least two of them.
51
- *
52
- * command, run a shell command; its exit code is the verdict. What the pre-push check always was.
53
- * instruct, say something to the assistant, so it acts before it finishes.
54
- * verdict, allow or hold the thing that is about to happen. The vocabulary the permission rules already
55
- * speak, and the honest shape of "land finished work automatically": nothing extra RUNS at that
56
- * moment, a pass that always runs is told which way to go.
57
- * builtin, invoke a named daemon behaviour. The escape hatch that keeps this table from having to express
58
- * machinery it has no business expressing: the proof ledger behind "verify before finishing"
59
- * tracks what a turn edited against what it ran, which is not a shell command and never will be.
60
- */
61
- /* The named behaviours a rule can invoke. Each reads a record only the daemon keeps, which is what makes them
62
- * built-ins rather than commands: `verify-edits` weighs what a turn edited against what it ran,
63
- * `verify-removals` weighs what a turn DELETED against what the repository's history says about those lines,
64
- * which is a question `git log` answers and no shell one-liner an owner could type would, and
65
- * `verify-ui-edits` weighs the rendered surfaces a turn changed against whether it ever looked at one, the one
66
- * question a passing suite is structurally unable to answer, and `verify-tests` weighs the test files a turn
67
- * touched against two things a green suite cannot say: whether their assertions got weaker than the same files
68
- * at HEAD, and whether a test the turn wrote would have passed before the change it covers. */
32
+ // What a rule does; the split is functional since the three settings this table replaces each needed a different shape.
33
+ // command: runs a shell command; its exit code is the verdict.
34
+ // instruct: says something to the assistant before it finishes.
35
+ // verdict: allows or holds what is about to happen (a pass with nothing to run, told which way to go).
36
+ // builtin: invokes a named daemon behaviour the table has no business expressing itself.
37
+ // Each reads a record only the daemon keeps, which is what makes it a built-in rather than a command.
38
+ // verify-edits: what a turn edited, against what it ran.
39
+ // verify-removals: what a turn deleted, against the repo's own history (a `git log` question, not a shell one-liner).
40
+ // verify-ui-edits: rendered surfaces a turn changed, against whether it ever looked at one.
41
+ // verify-tests: whether a touched test's assertions got weaker than at HEAD, or would have passed before its own
42
+ // change.
69
43
  export const RuleBuiltinSchema = z.enum(["verify-edits", "verify-removals", "verify-ui-edits", "verify-tests"]);
70
44
  export type RuleBuiltin = z.infer<typeof RuleBuiltinSchema>;
71
45
  export const RuleActionSchema = z.discriminatedUnion("kind", [
72
46
  z.object({
73
47
  kind: z.literal("command"),
74
48
  command: z.string().max(500),
75
- // Ceiling on one run, after which the child's whole process group is killed and the run is `failed`.
76
- // Never a pass: a command that did not finish has said nothing, and a green light nobody earned is the
77
- // one outcome a check exists to prevent.
49
+ // Past this, the process group is killed and the run is `failed`, never a silent pass.
78
50
  timeoutMs: z.number().min(60_000).max(3_600_000).default(900_000),
79
51
  }),
80
52
  z.object({ kind: z.literal("instruct"), text: z.string().min(1).max(4000) }),
@@ -82,16 +54,12 @@ export const RuleActionSchema = z.discriminatedUnion("kind", [
82
54
  z.object({ kind: z.literal("builtin"), name: RuleBuiltinSchema }),
83
55
  ]);
84
56
  export type RuleAction = z.infer<typeof RuleActionSchema>;
85
- /* HOW A TURN ENDED, as the `agent.finished` moment sees it. `clean`, `error` and `conflict` are the turn's own
86
- * fate. `checks-failed` is a clean turn whose `turn.ending` command check went red on the tree it is about to
87
- * land: the model was told, answered, and the last run still failed. It is named separately because a landing
88
- * rule has to be able to speak about it, and because its default is not the others': work in that state is HELD
89
- * unless a rule names `checks-failed` and says allow (rules/rules.ts landingVerdict). */
57
+ // `checks-failed` is a clean turn whose `turn.ending` check went red on the tree about to land; unlike the others, it
58
+ // defaults to HELD unless a rule explicitly allows it.
90
59
  export const RuleOutcomeSchema = z.enum(["clean", "error", "conflict", "checks-failed"]);
91
60
  export type RuleOutcome = z.infer<typeof RuleOutcomeSchema>;
92
- // WHEN a rule narrows. Three keys, chosen because they cover the two things people reach for on day one,
93
- // "only this repo" and "don't bother for a docs-only change", without opening a query language. Every key
94
- // absent ⇒ the rule always matches at its moment, which is what the three replaced settings each did.
61
+ // Three keys covering "only this repo" and "skip docs-only changes" without a query language; every key absent means
62
+ // the rule always matches.
95
63
  export const RuleConditionSchema = z.object({
96
64
  // A workspace repo id, or "root". Absent ⇒ any.
97
65
  repo: z.string().min(1).optional(),
@@ -99,16 +67,12 @@ export const RuleConditionSchema = z.object({
99
67
  paths: z.array(z.string().min(1)).max(20).optional(),
100
68
  // How the turn ended. Absent/empty ⇒ any, except that `checks-failed` never lands by omission.
101
69
  outcome: z.array(RuleOutcomeSchema).optional(),
70
+ // The fraction of occasions a rule fires on, at moments that draw one (turn.ending); absent ⇒ every occasion.
71
+ sample: z.number().gt(0).lt(1).optional(),
102
72
  });
103
73
  export type RuleCondition = z.infer<typeof RuleConditionSchema>;
104
- /* ONE RULE. `id` is stable and owner-visible: it is what the activity feed names when the rule fires and what
105
- * the last-fired store is keyed by, so it survives a relabel.
106
- *
107
- * WHICH ACTIONS FIT WHICH MOMENT is checked here rather than left to the consumer, because the alternative is
108
- * a rule that saves cleanly and then quietly does nothing, the failure mode a settings screen can least
109
- * afford. A verdict at `turn.ending` has nothing to decide; a command at `agent.finished` has no defined place
110
- * in the landing pass and would be a promise this stage cannot keep; an instruction at `file.edited` would be
111
- * repeated on every save, which is noise by the third one. */
74
+ // `id` is stable and owner-visible, so a rename doesn't orphan the firing history. Which actions fit which moment is
75
+ // validated here, not left to the consumer — the alternative is a rule that saves cleanly and silently does nothing.
112
76
  const MOMENT_ACTIONS: Record<RuleMoment, readonly RuleAction["kind"][]> = {
113
77
  "file.edited": ["command"],
114
78
  "turn.ending": ["builtin", "instruct", "command"],
@@ -129,95 +93,64 @@ export const RuleSchema = z
129
93
  path: ["action"],
130
94
  });
131
95
  export type Rule = z.infer<typeof RuleSchema>;
132
- // When a rule last did something, keyed by rule id, read by the settings list so a rule nobody has seen fire
133
- // in three weeks is visible as such. Kept out of the settings object on purpose: a firing is not an edit, and
134
- // writing the owner's config on every push would make every run a settings save.
96
+ // Kept out of the settings object on purpose: a firing is not an edit, and writing config on every push would make
97
+ // every run a settings save.
135
98
  export const RuleFiringsSchema = z.record(z.string(), z.number());
136
99
  export type RuleFirings = z.infer<typeof RuleFiringsSchema>;
137
- /* WHERE A SKILL CAME FROM, the fact that decides everything else about its row.
138
- *
139
- * A skill is inert text the agent reads, and this sandbox grows them from seven directions at once: the daemon
140
- * writes one per baked tool and one per core feature that has a cheatsheet, connecting a tool or a machine
141
- * writes one for that connection, the owner writes their own, a persona carries its own in its kit, an
142
- * installed extension ships some inside its checkout, and a plugin capability clones a repo full of them.
143
- * Nothing used to LIST the result, which is the whole gap this vocabulary closes, "what does my agent know
144
- * right now" had no answer on screen, and a skill spends the agent's attention whether or not anyone remembers
145
- * adding it.
146
- *
147
- * builtin this image ships it, a baked tool's cheatsheet, or a core feature's
148
- * own the owner wrote it (.intentic/config/skills/), and only these are editable here
149
- * capability something connected brought it: a CLI tool, a machine, a browser account, a VPN
150
- * extension an installed extension ships it inside its checkout
151
- * plugin a plugin capability cloned a repo that holds it
152
- * persona one card's own kit carries it, and only turns wearing that card ever see it
153
- * dropped it is simply sitting in the loaded folder, put there by hand, or by the agent itself
154
- *
155
- * `persona` is the one origin that is not on for everybody, which is why it needs its own word rather than
156
- * being filed under `own`: it says "the agent knows this when it is wearing that card", and a list that showed
157
- * it as an ordinary skill of the owner's would be claiming it applies to every chat.
158
- *
159
- * `dropped` is the honest bottom of the list rather than a category anything creates on purpose: the promise
160
- * this surface makes is that it shows EVERYTHING the agent knows, so a file nothing else claims has to list as
161
- * the loose file it is instead of being quietly left out.
162
- *
163
- * Deliberately NOT a capability kind. A capability holds a credential, can be broken right now, and wants a
164
- * status light; a skill either exists or it does not. See _sandbox/sandbox/src/settings/skill-inventory.ts. */
100
+ // Where a skill came from, the fact that decides everything else about its row.
101
+ // builtin: this image ships it.
102
+ // own: the owner wrote it (.intentic/config/skills/); only these are editable here.
103
+ // capability: something connected brought it (a CLI tool, a machine, a browser account, a VPN).
104
+ // extension: an installed extension ships it inside its checkout.
105
+ // plugin: a plugin capability cloned a repo that holds it.
106
+ // persona: one card's own kit carries it; only turns wearing that card see it.
107
+ // dropped: sitting in the loaded folder by hand or by the agent, claimed by nothing else.
108
+ // Not a capability kind: a capability can be broken and wants a status light, a skill either exists or it doesn't.
165
109
  export const SkillOriginSchema = z.enum(["builtin", "own", "capability", "extension", "plugin", "persona", "dropped"]);
166
110
  export type SkillOrigin = z.infer<typeof SkillOriginSchema>;
167
- /* A skill's own name, the directory it lives in and the word the agent invokes it by. Same slug shape the SDK's
168
- * loader accepts, checked here so a bad name is a refused save rather than a skill that silently never loads. */
111
+ // Same slug shape the SDK's loader accepts, checked here so a bad name is a refused save, not a skill that silently
112
+ // never loads.
169
113
  export const SkillNameSchema = z.string().regex(/^[a-z0-9][a-z0-9-]*$/, "a skill name is lowercase letters, digits and dashes");
170
114
  export const SkillSummarySchema = z.object({
171
- /* The handle the read/remove routes take. An `own` or `builtin` skill IS its name (they share one directory,
172
- * so names there are already unique); one that belongs to something else is `<origin>:<owner>:<name>`,
173
- * because two plugins may each ship a `review` and the list has to be able to tell them apart. */
115
+ // Qualified as `<origin>:<owner>:<name>` for anything not `own`/`builtin`.
174
116
  id: z
175
117
  .string()
176
118
  .describe(
177
119
  "Its handle, which reading and deleting take. A skill of your own is simply its name; one belonging to something else is qualified, because two packages may each ship a review.",
178
120
  ),
179
121
  name: z.string().describe("Its name."),
180
- // The frontmatter line the agent routes on, empty when a shipped skill declares none, which is worth
181
- // showing as the blank it is rather than papering over: a skill with no description is rarely picked.
182
122
  description: z
183
123
  .string()
184
124
  .describe(
185
125
  "What it is for, which is the line the agent reads to decide whether to reach for it. Empty when the skill declares none, which is worth showing as the blank it is: a skill with no description is rarely picked.",
186
126
  ),
187
127
  origin: SkillOriginSchema.describe("Where it came from."),
188
- // Who ships it, as the row names it, an extension's title, a plugin capability's id, a setting's name.
128
+ // e.g. an extension's title, a plugin capability's id, a setting's name.
189
129
  owner: z.string().optional().describe("Who ships it, as the row would name them."),
190
130
  enabled: z.boolean().describe("Whether the agent can reach it."),
191
- /* Whether THIS surface can switch it. True only for the skills the settings `skills` list governs (baked
192
- * tools and the owner's own): everything else is on because its extension, its plugin or another setting is,
193
- * and a switch here that silently did nothing would be worse than no switch at all, the row names its
194
- * owner instead. */
131
+ // True only for the skills the settings `skills` list itself governs (baked tools, the owner's own).
195
132
  switchable: z
196
133
  .boolean()
197
134
  .describe(
198
135
  "Whether this surface can switch it. Everything else is on because its extension or its plugin is, and a switch here that silently did nothing would be worse than none, so the row names its owner instead.",
199
136
  ),
200
- // Whether the owner may rewrite the text here. Their own skills only, a shipped one is its author's, and
201
- // editing it in place would be undone the next time the thing that ships it reconciles.
202
137
  editable: z
203
138
  .boolean()
204
139
  .describe(
205
140
  "Whether it can be rewritten here. Your own only: editing somebody else's in place would be undone the next time the thing that ships it catches up.",
206
141
  ),
207
- /* Whether it can be deleted from this surface. Wider than `editable` by exactly one case: a skill someone
208
- * dropped into the loaded folder is not the owner's to edit (its home is that folder, not their store) but is
209
- * absolutely theirs to clear out, and with no switch and no owning extension there would otherwise be no way
210
- * to get rid of it short of the file tree. */
142
+ // Wider than `editable` by one case: a dropped skill isn't the owner's to edit, but is theirs to remove, with no
143
+ // other way to short of the file tree.
211
144
  removable: z.boolean(),
212
145
  });
213
146
  export type SkillSummary = z.infer<typeof SkillSummarySchema>;
214
147
  export const SkillsListSchema = z.array(SkillSummarySchema);
215
- // One skill's full text, for reading it on screen. Its own route rather than a field on the summary: bodies run
216
- // to thousands of words and a list of twenty would cost a hundred kilobytes to draw a group of one-line rows.
148
+ // Its own route, not a field on the summary: bodies run to thousands of words, too costly to include in a list of
149
+ // one-line rows.
217
150
  export const SkillBodySchema = z.object({
218
151
  id: z.string().describe("The skill's id, which can carry the owner it came from."),
219
152
  name: z.string().describe("Its name."),
220
- // Everything after the frontmatter, the instructions themselves, as written.
153
+ // Everything after the frontmatter.
221
154
  body: z.string().describe("The instructions themselves, as written."),
222
155
  });
223
156
  export type SkillBody = z.infer<typeof SkillBodySchema>;
@@ -229,10 +162,8 @@ export const SkillIdSchema = z.object({
229
162
  "Which skill. It travels in the query rather than the address, because an id can name the owner it came from and that will not fit in a path.",
230
163
  ),
231
164
  });
232
- /* A skill the owner writes. Three fields because a skill IS three things, what it is called, when to reach for
233
- * it, and what to do, and the daemon assembles the frontmatter from the first two so a saved skill can never
234
- * be one the loader skips over. `description` is required for the reason above: it is the only part the model
235
- * reads before deciding whether to open the rest. */
165
+ // Three fields because a skill is three things: name, when to reach for it, what to do. The daemon assembles
166
+ // frontmatter from the first two, so a saved skill can never be one the loader skips.
236
167
  export const SkillDraftSchema = z.object({
237
168
  name: SkillNameSchema.describe("What to call it. Saving over an existing name rewrites it, which is also how one is renamed."),
238
169
  description: z.string().min(1).max(1024).describe("What it is for, which is what the agent reads to decide whether to reach for it."),
@@ -242,62 +173,10 @@ export type SkillDraft = z.infer<typeof SkillDraftSchema>;
242
173
  export const SkillRemoveSchema = z.object({
243
174
  name: SkillNameSchema.describe("Which skill to delete. The text and the enabled list are both updated, so nothing is left half done."),
244
175
  });
245
- // Small user-owned config the /settings routes edit and streamAgent reads, all opt-in booleans the owner
246
- // toggles in the UI (so each can be A/B benchmarked):
247
- // stableSystemPrompt, keeps the system prompt byte-stable across turns (the delegation note rides the user
248
- // message instead of the preset `append`) so the provider prompt cache survives.
249
- // skills , names of baked-tool skills to load into .agents/skills so the agent reaches for them
250
- // (e.g. "lsp". TS rename + diagnostics over the language service); a name absent ⇒ its
251
- // skill file isn't written, so the agent doesn't reach for it. Data-driven: a new baked
252
- // tool is one daemon-side registry entry, not a new settings field.
253
- // hashlineEdits , swaps the native Read/Edit/Write for hash-anchored edits on the Claude path (stale-file
254
- // guard + fewer output tokens); off ⇒ the native file tools.
255
- // systemPromptMode , which base the agent's prompt is: "intentic" (default), "claude", or "custom".
256
- // systemPrompt , the owner's own prompt text, used only by "custom" mode, where it is the ENTIRE system
257
- // prompt and nothing the daemon would otherwise append rides with it, see its own note.
258
- // iqSearch , loads the image-baked iq Claude Code plugin (skill + SessionStart nudge) so the agent
259
- // prefers the iq CLI over grep/find/Glob; off ⇒ plugin not loaded, native search tools
260
- // only. Opt-in (default off); the browser Search box uses iq regardless.
261
- // iqSearchHoldout , conversation-level measurement control for iqSearch (UsageTurn.iqSearchArm). The arm
262
- // stays fixed because teaching already loaded into a session cannot be removed next turn.
263
- // workspaceMap , computes an AREA index of the project a run starts in and prepends it to the
264
- // conversation's opening message, so the turn does not have to buy its own orientation
265
- // with a directory listing. Generated from the filesystem every time, never stored.
266
- // workspaceMapHoldout, conversation-level measurement control for workspaceMap (UsageTurn.mapArm), judged on
267
- // the directory listings the opening turn ran rather than on its searches.
268
- // sidecars , the background pass converging a markdown shadow of every binary workspace file
269
- // (docx/pdf/images/audio → .intentic/local/cache/derived/) the moment it lands, via
270
- // the baked fileq CLI, so reasoning-time reads are pre-derived. The CLI itself is
271
- // always available; this gates only the eager watcher-driven derivation.
272
- // dependencyFreshness, whether a version the agent is about to pin is checked against the package's own
273
- // registry before it lands, and what the check is allowed to say: "off" (no hook is
274
- // wired at all), "versions" (registry-derivable facts only), "full" (also names a
275
- // maintained successor, where one is known and the registry corroborates it).
276
- // outputCleaners , the Bash output-cleaner spec (agent-output-filter): "off" = filter disabled,
277
- // "" = all cleaners on (default), else an iq-style allow-list / default-minus
278
- // spec ("git,pnpm" = only those; "-cap" = all except). Threaded to the filter via env.
279
- // outputHoldout , measurement control: a fraction [0,1] of Bash commands whose output bypasses cleaning
280
- // (recorded raw as `heldOut`), so the savings report compares a real cleaned-vs-raw
281
- // population instead of an estimate. 0 = no holdout (default).
282
- // rules , the standing "at this moment, if this is true, do this" table (RuleSchema): what proves
283
- // a turn's work, what runs before a push, whether finished work lands by itself. Empty
284
- // (the default) means none of those happen, which is the shape a fresh sandbox has.
285
- // automationFailureLimit, consecutive `error` runs after which an automation is disabled rather than left
286
- // firing forever; 0 (default) ⇒ never.
287
- // subagentsAtOnce / subagentsPerTurn / subagentDepth, the harness's own ceilings on delegation, raised or
288
- // lowered from one place; each defaults to what the CLI enforces on its own.
289
- // The booleans default off, outputCleaners defaults "" (cleaning on) and outputHoldout 0; iqSearch stays off
290
- // until the owner enables it. `skills` is the exception and defaults to the
291
- // baked tools worth having on: a skill file is the ONLY thing that tells the agent a baked binary exists, and
292
- // with the list empty `lsp` went used once in 866 sessions, not declined, never learned about.
293
- //
294
- // Every field carries that default IN THE SCHEMA, so a settings object written before a field existed still
295
- // parses, the absent key reads as its default. That is not a compatibility layer, it is the seam this shape
296
- // spans: the browser ships with the platform while the daemon ships inside the user's sandbox image, so a web
297
- // build is routinely NEWER than the daemon answering it. Requiring the key instead makes the whole settings
298
- // surface fail to parse the moment a toggle is added, which reaches the user as a page of switches that are
299
- // silently dead, not as an error. It also means an older on-disk manifest keeps the owner's other picks rather
300
- // than being discarded whole.
176
+ // Opt-in settings the /settings routes edit and streamAgent reads, defaulting off so each can be A/B tested (`skills`
177
+ // defaults on for the baked tools worth having, since a skill file is the only thing that tells the agent a baked
178
+ // binary exists). Every default lives in the schema, so an older settings file still parses and keeps the owner's other
179
+ // picks rather than failing whole.
301
180
 
302
181
  export const SandboxSettingsSchema = z.object({
303
182
  stableSystemPrompt: z
@@ -307,21 +186,14 @@ export const SandboxSettingsSchema = z.object({
307
186
  "Keep the instructions identical between turns so the provider can cache them, moving anything that varies into the message instead. Cheaper, at the cost of some flexibility.",
308
187
  ),
309
188
  skills: z.array(z.string()).default(["lsp", "fileq"]).describe("Which skills are switched on."),
310
- /* WHETHER A NEW CHAT IS ROUTED ONTO A PERSONA, and how far the answer goes without a press. The router is
311
- * the `persona-router` helper role (model-roles.ts): it reads the first message and one line per card and
312
- * names one card or none, once per chat, before the first turn (the sandbox's agent/persona-router.ts).
313
- * off — never asked. A chat wears the persona the user picked, or none.
314
- * suggest — asked, and the answer is a chip on the composer that the user presses to apply. The default:
315
- * a persona takes accounts and repositories AWAY from a chat, and the first time that happens
316
- * it should happen because somebody pressed it.
317
- * auto — the answer is applied when the message is sent, unless the chip was dismissed first.
318
- * Attended chats only, whatever this says: a wake nobody is watching names its persona on its own form,
319
- * and routing one onto a card would GRANT it accounts the owner never named for it. */
189
+ // Router reads the sent message and one line per card, once per chat, between send and the first turn
190
+ // (persona-router.ts / model-roles.ts). Never asked of a draft: only a sent message is a finished one.
191
+ // Attended chats only: routing onto a card would grant an unwatched wake accounts nobody named for it.
320
192
  personaRouting: z
321
- .enum(["off", "suggest", "auto"])
322
- .default("suggest")
193
+ .boolean()
194
+ .default(true)
323
195
  .describe(
324
- "Whether a new chat is matched to one of your personas from its first message. Suggest shows the match on the composer for you to press; auto applies it when you send unless you dismiss it first. Never applies to unwatched runs, which name their persona themselves.",
196
+ "Whether a new chat is matched to one of your personas from its first message. The message is read once it is sent, by the model on the persona-routing list, and the chat says in its own transcript what was asked and which persona it landed on. Never applies to unwatched runs, which name their persona themselves.",
325
197
  ),
326
198
  hashlineEdits: z
327
199
  .boolean()
@@ -329,27 +201,15 @@ export const SandboxSettingsSchema = z.object({
329
201
  .describe(
330
202
  "Have the agent edit files by line number rather than by quoting the text it wants replaced. Cheaper on large files, and less forgiving of a stale read.",
331
203
  ),
332
- /* WHICH SYSTEM PROMPT THE AGENT RUNS ON, the base, before anything this turn composes.
333
- *
334
- * intentic. Intentic's own prompt, tuned for this harness (intentic-prompt.ts). The default.
335
- * claude . Claude Code's preset, as shipped in the CLI this sandbox runs. Not a copy stored here, so
336
- * picking it tracks whatever the installed CLI's prompt is rather than freezing at a snapshot.
337
- * custom , `systemPrompt` below, and nothing else at all.
338
- *
339
- * The first two are peers: both get the harness's own guidance appended (the AskUserQuestion/plan blocks
340
- * the chat's cards need, the checklist guidance behind the todo panel, the browser-tool guidance), plus the
341
- * delegation note. `custom` is the one that does not, by the owner's explicit choice, see the field below. */
204
+ // intentic: this product's own prompt (intentic-prompt.ts), tuned for this harness. Default.
205
+ // claude: Claude Code's preset, read live from the installed CLI, not a stored copy — tracks whatever prompt ships
206
+ // with it.
207
+ // custom: `systemPrompt` below, and nothing else.
342
208
  systemPromptMode: SystemPromptModeSchema.default("intentic").describe(
343
209
  "Which instructions the agent starts from: intentic's own, the ones the installed Claude Code carries, or your own. The first two both get this product's own guidance added on top; your own gets nothing added, which is the point of it.",
344
210
  ),
345
- /* The owner's own prompt, used only when `systemPromptMode` is "custom". Then it is the ENTIRE system
346
- * prompt: both built-in bases are gone and so is everything the daemon would otherwise append, including
347
- * the widget guidance the chat's cards are driven by. That is the price of total control, and the UI states
348
- * it at the moment of the edit rather than letting the
349
- * widgets go quietly dark. Only the cross-provider delegation note survives, because it has a home outside
350
- * the system prompt already (the user-message preamble stableSystemPrompt puts it in).
351
- *
352
- * Cap is roomy, the bases it stands in for are ~6.8k characters, but finite, because every turn pays it. */
211
+ // The delegation note still survives (it lives in the user-message preamble, not here). Cap is roomy but finite —
212
+ // every turn pays for it.
353
213
  systemPrompt: z
354
214
  .string()
355
215
  .max(20000)
@@ -361,10 +221,6 @@ export const SandboxSettingsSchema = z.object({
361
221
  .boolean()
362
222
  .default(false)
363
223
  .describe("Teach the agent how to use this workspace's own search tool, rather than leaving it to grep around."),
364
- /* Measurement control for the iq search teaching, at CONVERSATION level. A fraction [0,1] of conversations
365
- * run without the plugin/instruction and stamp that stable arm on every turn. Per-turn randomization is not
366
- * a valid control here: once the teaching enters a provider session, withholding it from the next request
367
- * does not make the model forget it. 0 ⇒ no measurement and every conversation receives the teaching. */
368
224
  iqSearchHoldout: z
369
225
  .number()
370
226
  .min(0)
@@ -373,35 +229,16 @@ export const SandboxSettingsSchema = z.object({
373
229
  .describe(
374
230
  "What share of conversations to run without that teaching, so the two can be compared. Whole conversations rather than individual turns, because once the teaching is in a session, withholding it from the next request does not make the model forget it.",
375
231
  ),
376
- /* THE MAP THE TURN OPENS WITH, which areas the project a run starts in has, one derived line on what each
377
- * is for, and where the run is standing among them (agent/workspace-map.ts).
378
- *
379
- * It answers the question every first turn has whatever it was asked, "what is this and where am I in
380
- * it", which across a hundred sessions of this workspace was being bought with a directory listing in two
381
- * turns out of five, and with ~5.3k tokens of tool results before the job was touched.
382
- *
383
- * ROOTED AT THE RUN'S STARTING FOLDER rather than at the workspace: a persona's start folder, an isolated
384
- * conversation's worktree, or wherever the turn's cwd is. It maps the project containing that folder and
385
- * names the rest of the workspace on one line, because a run three levels inside one project is not asking
386
- * about the others.
387
- *
388
- * REGENERATED, NEVER STORED, which is the whole reason it is a mechanism rather than a paragraph in the
389
- * system prompt or a hand-written CLAUDE.md: in the ten days that motivated it this repo's two busiest
390
- * top-level directories stopped existing, and every written-down copy of the layout was wrong by the end of
391
- * the window. Off by default, it spends its tokens on the opening message of every conversation. */
232
+ // Rooted at the run's own starting folder (a persona's, an isolated conversation's worktree), not the workspace
233
+ // root — it maps the project containing that folder.
392
234
  workspaceMap: z
393
235
  .boolean()
394
236
  .default(false)
395
237
  .describe(
396
238
  "Open every conversation with a map of the project it starts in: what is in it, what each part is for, and where the agent is standing. Worked out fresh each time rather than written down anywhere, because a written layout is wrong within a fortnight. Off by default, since it spends tokens on the first message of every conversation.",
397
239
  ),
398
- /* Measurement control for the map, at CONVERSATION level for the plainest of reasons: the note is sent on
399
- * the opening message, so every later turn of a mapped conversation has a map in its transcript and a
400
- * per-turn flip would call eleven treated turns controls.
401
- *
402
- * Judged on `UsageTurn.openingListings` and read on each conversation's opening turn (usage/turn-experiments.ts),
403
- * because that is the turn the note was sent to and averaging it across a long conversation divides the
404
- * effect by the conversation's length. 0 ⇒ no measurement and every conversation receives the map. */
240
+ // Judged on the opening turn's own directory listings, not averaged across the conversation, or a twelve-turn
241
+ // conversation would divide the effect by twelve.
405
242
  workspaceMapHoldout: z
406
243
  .number()
407
244
  .min(0)
@@ -410,46 +247,18 @@ export const SandboxSettingsSchema = z.object({
410
247
  .describe(
411
248
  "What share of conversations to open without the map, so the two can be compared. Whole conversations rather than individual turns, because the map is sent once and stays in the conversation's history afterwards.",
412
249
  ),
413
- /* THE MARKDOWN SHADOWS OF BINARY FILES, the eager half of fileq (_sandbox/fileq). The lazy half — the
414
- * `fileq` CLI an agent runs mid-task — is always on PATH and gated only by its skill; this switch is
415
- * about the BACKGROUND pass: the daemon watching /work and converging a sidecar under
416
- * .intentic/local/cache/derived/ for every docx/xlsx/pptx/pdf/image/audio file the moment it lands or
417
- * changes, so reasoning-time reads hit a shadow that already exists. Off by default like every boolean
418
- * here: it spends CPU unasked, on every file that lands, which is the owner's call to make. */
250
+ // Only the eager background pass; the `fileq` CLI itself is always on PATH regardless, gated only by its own skill.
419
251
  sidecars: z
420
252
  .boolean()
421
253
  .default(false)
422
254
  .describe(
423
255
  "Keep an up-to-date markdown rendering of every document, image and audio file in the workspace, made in the background as files land, so the agent reads a pre-derived text instead of paying to parse the file mid-task. Costs background CPU on a document-heavy workspace, so it is a switch rather than a default.",
424
256
  ),
425
- /* IS THE VERSION ABOUT TO BE PINNED THE ONE THE REGISTRY ACTUALLY HAS?
426
- *
427
- * A model writes a version from memory, and memory has a publication date. Across this workspace's own
428
- * session history the failure is small, steady, and never self-correcting: of the version literals an
429
- * agent typed into a manifest or an install command, more than half were already behind the newest
430
- * release at the moment they were typed, and a third were written without any registry ever being asked.
431
- * Nothing downstream catches it either — a stale pin installs cleanly, type-checks, and passes the suite,
432
- * so every gate this sandbox already has says yes to it.
433
- *
434
- * THREE STATES, and the middle one is the whole feature. The two halves of "this dependency choice is
435
- * behind" are different KINDS of claim:
436
- * versions, a measurement. The registry publishes what the newest release is and when; comparing is
437
- * arithmetic, it works for any package, and there is nothing to keep current.
438
- * full , a measurement plus an opinion. Naming `date-fns` as what to reach for instead of `moment`
439
- * is a judgement somebody made, and judgements rot. An owner is entitled to take the facts
440
- * and decline the opinions, which is exactly what the two settings are.
441
- * The successor list never asserts staleness on its own: an entry surfaces only where the registry
442
- * corroborates it (deprecated, or nothing published in eighteen months), so the curation supplies the
443
- * NAME of the replacement and the measurement supplies the reason. That split is what stops it decaying
444
- * into a list of last year's preferences.
445
- *
446
- * IT INFORMS, IT NEVER BLOCKS, and that is not timidity. Matching a version the workspace already pins is
447
- * the common case and it is CORRECT: a new package inside a monorepo should take the catalog's
448
- * `typescript`, not the newest one on the registry. A gate that refused would fight legitimate work
449
- * several times for every mistake it caught, so the fact rides back as context and the model decides.
450
- *
451
- * Off by default like every other flag here, and off means genuinely nothing: no hook is wired, and the
452
- * sandbox makes no network call it would not otherwise have made. */
257
+ // versions: a measurement only (the registry's own newest release).
258
+ // full: also the name of a successor, but only where the registry itself corroborates it (deprecated, or nothing
259
+ // published in 18 months) — curation supplies the name, measurement supplies the reason.
260
+ // Informs, never blocks: matching a version the workspace already pins is usually correct, and a gate would fight
261
+ // legitimate work more than it caught mistakes.
453
262
  dependencyFreshness: DependencyFreshnessSchema.default("off").describe(
454
263
  "Whether a version the agent is about to pin is checked against the package's own registry first. Facts only, or facts plus the name of a maintained replacement where the registry agrees the current choice has been abandoned. It tells the agent and lets it decide rather than refusing, because matching a version your project already uses is usually the right answer and a gate would fight it.",
455
264
  ),
@@ -463,54 +272,18 @@ export const SandboxSettingsSchema = z.object({
463
272
  .max(1)
464
273
  .default(0)
465
274
  .describe("What share of commands to leave untrimmed, so the saving can be measured against a real comparison rather than estimated."),
466
- /* WHICH MODEL DOES WHICH JOB, one ordered list per ROLE (model-roles.ts declares them all).
467
- *
468
- * ONE KEY RATHER THAN SEVENTEEN, and the record is keyed by the role catalog rather than by free strings: a
469
- * job that starts choosing a model tomorrow becomes configurable by adding a row to that table, and the
470
- * settings page, the resolver and the daemon's lookup all follow without a schema change. Seventeen named
471
- * fields here would be the same table written a fourth time, in the one place where getting it out of step
472
- * spends somebody's money.
473
- *
474
- * IT REPLACED THREE BUNDLED KEYS — `quickModel`, `agentRunModels` and `commandJudgeModels` — and the reason
475
- * is worth keeping: the first two were grouped by assumed INTENSITY, not by job. "Quick" covered commit
476
- * messages, session titles and loop verdicts at once, so an owner who wanted better commit subjects could
477
- * not ask for them without also moving every session title onto the same model; "agent runs" covered a
478
- * production incident and a documentation sweep with one tier. An intensity is a guess about work its owner
479
- * knows better, and neither the configuration nor the UI was actually saving anyone anything by making it.
480
- *
481
- * EACH LIST IS AN ORDERED LADDER of pins, tried top to bottom, because the interesting failure is a model
482
- * that is connected and will not answer today: the account's allowance went on the chat, and one spent
483
- * provider takes that job down for hours while the others sit idle.
484
- *
485
- * AN ABSENT OR EMPTY LIST IS THE JOB SWITCHED OFF, and nothing is derived to fill it. A one-shot helper
486
- * used to fall to an "Auto ladder" worked out from whatever was connected, which meant a sandbox nobody
487
- * had configured still spent an account on every commit subject, every session title and every safety
488
- * verdict, on a ranking this repo invented and re-ranked whenever an account was added. Not set now means
489
- * not set: no auto-selection and no recommendation. A one-shot with no list does not run; a whole session
490
- * with no list opens on the model the owner picked for their own chat, which is a choice they made rather
491
- * than one this schema guessed. */
492
- // `partialRecord`, not `record`: an exhaustive one would make every role a required key, so a settings file
493
- // that has never been touched would have to spell out seventeen empty arrays to be valid, and adding a role
494
- // would invalidate every settings file in existence. An absent key IS the answer "this role has no list".
275
+ // One key, not one field per role: a role catalog entry (`model-roles.ts`) makes a new job configurable without a
276
+ // schema change here.
277
+ // `partialRecord`, not `record`: an exhaustive one would force every settings file to list every role, and adding
278
+ // one would invalidate them all. Absent IS "no list".
495
279
  modelRoles: z
496
280
  .partialRecord(ModelRoleSchema, z.array(ModelPinSchema).max(10))
497
281
  .default({})
498
282
  .describe(
499
283
  "Which models do which job, one ordered list per job: commit messages, session titles, the safety judge, pipeline fixes, and every other place this sandbox picks a model for you. Tried in order, so one spent account does not take a job down. Nothing is chosen for you: a one-shot job with no list does not run, and a whole session with no list opens on whatever your own chat is set to.",
500
284
  ),
501
- /* WHICH REPOS KEEP A CHANGELOG, the repos whose commits carry a `Release-Note:` trailer, written by the
502
- * same quick model that drafts the subject (git/commit-message.ts) and harvested at release time.
503
- *
504
- * A LIST OF REPOS RATHER THAN A FLAG, and EMPTY BY DEFAULT, because this daemon runs on the user's repos
505
- * rather than on ours. The commit drafter's one standing rule is that house style is INFERRED, never
506
- * prescribed, it reads the last handful of subjects and matches them, so a repo that spells its commits
507
- * some other way is never argued with. A note trailer is the one thing that cannot be inferred that way: a
508
- * repo which has never written one gives the model nothing to copy, so asking for it has to be somebody's
509
- * explicit decision. Empty means every repo behaves exactly as it did before this existed.
510
- *
511
- * Named by repo id ("root", or the root-relative dir discoverRepos reports), because a workspace holds
512
- * several repos and a commit can span them: the trailer is written when the commit touches a repo that
513
- * asked for one, and a repo that did not ask never gets a line it has to explain to its reviewers. */
285
+ // Named by repo id ("root" or discoverRepos's dir); a commit spanning repos gets the trailer only where one was
286
+ // asked for.
514
287
  changelogRepos: z
515
288
  .array(z.string())
516
289
  .max(50)
@@ -518,60 +291,24 @@ export const SandboxSettingsSchema = z.object({
518
291
  .describe(
519
292
  "Which repositories keep a changelog, and so get a user-facing note written alongside each merge. A list rather than a switch, and empty by default, because the commit writer's standing rule is to copy the house style rather than impose one, and a repository that has never written such a note gives it nothing to copy.",
520
293
  ),
521
- /* AUTOMATIC TIER SELECTION: may the daemon run an easy-looking turn on a cheaper rung of the provider the
522
- * user is already on, instead of on the model they picked?
523
- *
524
- * THREE STATES RATHER THAN A TOGGLE, because the middle one is the only honest way to reach the third.
525
- * Nobody, this repo included, can name a sensible cutoff for "easy enough" without traffic to fit it
526
- * against, and a routing threshold guessed in advance is how a cost feature quietly becomes a quality
527
- * regression. So:
528
- * off — the judge never runs. Nothing is scored, nothing is recorded, turns run on the user's pick.
529
- * shadow — the judge runs and its verdict is written to the spend ledger beside what the turn actually
530
- * cost, and NOTHING IS ROUTED. This is the default: it spends no tokens, changes no behaviour,
531
- * and is the only thing that can turn the weights in prompt-complexity.ts from a hypothesis
532
- * into a measurement.
533
- * on — a turn judged fast runs on the cheap rung (fast-tier.ts), when the provider publishes one.
534
- *
535
- * IT CAN ONLY EVER ROUTE DOWN. There is no "which model is the standard tier" setting because the standard
536
- * tier is the model the user already chose, so the worst case of a wrong verdict is one turn's quality on a
537
- * model they can see on the card and correct, never a bill they did not ask for. That asymmetry is why this
538
- * can default to shadow rather than to off: shadow costs nothing and `on` cannot overspend. */
294
+ // off: the judge never runs.
295
+ // shadow (default): the judge scores every turn to the ledger; nothing is routed.
296
+ // on: a turn judged fast runs on the cheap rung, where the provider publishes one.
539
297
  autoTier: z
540
298
  .enum(["off", "shadow", "on"])
541
299
  .default("shadow")
542
300
  .describe(
543
301
  "Whether an easy-looking turn may run on a cheaper model from the same provider. Three states rather than a switch, because the middle one is the only honest road to the third: it scores every turn and routes nothing, so the guess can become a measurement before it changes anything. It can only ever route down, so the worst case is one turn's quality rather than a bill nobody asked for.",
544
302
  ),
545
- /* HOW EAGER THE JUDGE IS, the one dial this feature exposes and the answer to what the Measure mode is for:
546
- * the numbers say how many turns were called simple, and this is the control that acts on them.
547
- *
548
- * Three named stops rather than a number, because the number means nothing to anyone who has not read the
549
- * weights, while "only the unmistakable" / "the default" / "an easy question about real code too" are three
550
- * sentences an owner can actually hold an opinion about (FAST_CEILINGS spells out each). It moves the
551
- * cutoff and nothing else: the rule that a downgrade needs something POSITIVE to have been said holds at
552
- * every stop, so no setting of this can start downgrading short vague requests.
553
- *
554
- * `balanced` is the default and is what every verdict recorded before this existed was judged against, so
555
- * the shadow history stays comparable across the change rather than silently becoming two populations. */
303
+ // `balanced` is what every verdict recorded before this setting existed was judged against, so shadow history stays
304
+ // comparable.
556
305
  autoTierEagerness: z
557
306
  .enum(["cautious", "balanced", "eager"])
558
307
  .default("balanced")
559
308
  .describe(
560
309
  "How readily a turn counts as simple enough for the cheaper model. It moves only the cutoff: at every setting a turn still has to say something positively easy, so nothing here can downgrade a short vague request.",
561
310
  ),
562
- /* WHICH CHEAP MODEL A DOWNGRADED TURN LANDS ON, an ordered list of `${provider}:${model}` keys
563
- * (modelPinKey), or EMPTY for Auto.
564
- *
565
- * Empty is the default and the interesting case, exactly as a one-shot role's is: Auto is the cheapest row the
566
- * turn's own provider publishes, read through the same cheap-end order (compareCheapestFirst), so the two
567
- * features can never disagree about which rung is the cheap one, and connecting an account tomorrow
568
- * improves the answer by itself.
569
- *
570
- * A LIST, so a sandbox working across several providers can name the rung it wants on each. But unlike the
571
- * two lists above this one is NOT a failure ladder: entries naming a provider other than the turn's own are
572
- * dropped rather than tried, because switching provider retires the conversation's session (turnRequest.ts
573
- * `resumes`), and starting the conversation over to save a fraction of a cent is not a saving. The first
574
- * entry that names this provider AND is genuinely cheaper than the pick wins; if none does, Auto answers. */
311
+ // Auto uses the same cheap-end order as this list (`compareCheapestFirst`), so the two can never disagree.
575
312
  autoFastModels: z
576
313
  .array(z.string())
577
314
  .max(10)
@@ -579,10 +316,6 @@ export const SandboxSettingsSchema = z.object({
579
316
  .describe(
580
317
  "Which cheaper model a downgraded turn lands on. A list so a sandbox spanning providers can name a rung on each, but not a fallback ladder: an entry naming a different provider than the turn is on is skipped rather than tried, because switching provider retires the conversation and starting over to save a fraction of a penny is not a saving. Empty picks the cheapest the turn's own provider publishes.",
581
318
  ),
582
- // How long a finished agent stays on the board before it is archived automatically (days; 0 ⇒ never).
583
- // Unlike every other flag here this one defaults ON, because the lane it governs is the board's only
584
- // terminal state: without a sweep the Finished lane grows for the life of the sandbox, and each card it
585
- // holds is a live worktree checkout, not just a row.
586
319
  agentRetentionDays: z
587
320
  .number()
588
321
  .min(0)
@@ -591,77 +324,48 @@ export const SandboxSettingsSchema = z.object({
591
324
  .describe(
592
325
  "How many days a finished conversation stays on the board before being put away. Zero means never. The one setting here that defaults on, because each card left behind is a real working copy on disk, not just a row.",
593
326
  ),
594
- /* THE SANDBOX-WIDE DEFAULT for "when a turn dies because the MODEL PROVIDER was failing (500/502/503, a
595
- * 529 at capacity, a dropped socket), re-run it on an escalating backoff until it goes through or the
596
- * attempts are spent".
597
- *
598
- * A DEFAULT, not the whole answer: any one conversation may override it (AgentSummarySchema
599
- * .resumeAfterOutage), and the chat's own offer at the moment of failure writes THAT rather than this.
600
- * This toggle is the standing policy for every agent that has not said otherwise, which is why it lives in
601
- * settings and is not reachable by a single press from inside one chat, flipping how the whole board
602
- * behaves should be a thing somebody went to do.
603
- *
604
- * OFF by default, on the same reasoning that keeps a spent usage limit out of this pair entirely: a resume
605
- * re-runs a turn the user sent once, on their own allowance, and only they can say whether the turn was
606
- * worth paying for twice. Starting off costs nothing, because the failed turn is remembered whatever the
607
- * toggle says (recordOutageFailure), the failure frame reports an "available" resume and the chat's offer
608
- * arms that very turn the moment it is armed for that conversation. Worth turning ON for a sandbox whose
609
- * turns mostly have nobody in the room (automation wakes, Discord, webhooks), which is the case no browser
610
- * could rescue and the case a per-conversation press cannot reach. */
327
+ // Off still records the failure, so the per-conversation resume offer arms normally; nothing is lost, just not
328
+ // automatic.
611
329
  resumeAfterOutage: z
612
330
  .boolean()
613
331
  .default(false)
614
332
  .describe(
615
333
  "Whether a turn killed by the model provider failing is re-run automatically, backing off between attempts. The sandbox-wide default; any one conversation can say otherwise. Off to begin with, because a retry spends your allowance on a turn you sent once and only you can say whether it was worth paying for twice. Worth turning on for a sandbox whose work mostly happens with nobody in the room.",
616
334
  ),
617
- /* THE SANDBOX-WIDE DEFAULT for the blocker that is not a failure: "when a spent usage limit refuses a turn,
618
- * send that turn again the moment the allowance comes back".
619
- *
620
- * The one automatic resume here that WAITS FOR A PUBLISHED INSTANT rather than guessing. Its neighbour above
621
- * escalates a backoff at a provider nobody can predict; this one sleeps until the hour the provider itself
622
- * named and fires once, at it. A limit that publishes no instant (Grok, Cursor) is never fired for at all,
623
- * because there is nothing to wait for and a guess would be spending the user's money on arithmetic.
624
- *
625
- * OFF by default, and this is the setting the default matters most for. Every other blocker in this pair
626
- * clears at nobody's expense, while this one clears into an allowance the user may have been holding back
627
- * deliberately, so the shipped behaviour is to say when it reopens and let them decide. What arming it buys
628
- * is the case a press cannot reach: the 2am wall on a board nobody is watching, where the alternative is a
629
- * card that sat waiting eight hours for a press that was always going to come. */
335
+ // The one resume that waits for a published instant rather than guessing; a limit with no published reset (Grok,
336
+ // Cursor) never fires this way at all.
630
337
  resumeAfterLimit: z
631
338
  .boolean()
632
339
  .default(false)
633
340
  .describe(
634
341
  "Whether a turn a spent usage limit refused is sent again by itself once the allowance reopens. The sandbox-wide default; any one conversation can say otherwise. Off to begin with, because the allowance is your budget and a turn that spends it the second it comes back is not a decision to make for you. Worth turning on for a sandbox whose work mostly happens with nobody in the room.",
635
342
  ),
636
- /* When the daemon dies under a running turn, re-run that turn once it is back (agent/turn-journal.ts records
637
- * every in-flight turn; the boot pass in agent/turn-resume.ts re-runs what survived). OFF by default, like
638
- * the outage resume above and for the same reason: a boot that re-runs turns spends the user's allowance on
639
- * work they are not watching, and edits the workspace while they are still waiting for the sandbox to come
640
- * back. Worth turning on for the case it was built for, the container is recreated on every update, every
641
- * environment approval and every dev-sandbox.sh swap, so approving the Dockerfile change an agent asked for
642
- * otherwise costs the run that asked for it.
643
- *
644
- * OFF still records the interruption: the fleet card reads `interrupted` (see AgentStatusSchema) and an
645
- * automation's row shows an `interrupted` run, nothing is re-run, but nothing is silently lost either. */
343
+ // Same provider only; a different provider would retire the session for a saving that isn't one. Composes with
344
+ // `resumeAfterLimit` into four postures: hold, wait for reset, move-or-hold, move-or-wait.
345
+ moveAfterLimit: z
346
+ .boolean()
347
+ .default(false)
348
+ .describe(
349
+ "Whether a turn a spent usage limit refused is moved to another connected account of the same provider that still has room, as soon as the refusal lands. The sandbox-wide default; any one conversation can say otherwise. Off to begin with, because it spends a second account on your behalf. With no account that has room the turn waits as the setting above says.",
350
+ ),
351
+ limitMoveCarryUnder: z
352
+ .number()
353
+ .int()
354
+ .min(0)
355
+ .default(100_000)
356
+ .describe(
357
+ "When a spent usage limit moves a turn to another account, carry the provider session (the model keeps everything, and re-reads all of it once on the other account) while the conversation's context is under this many tokens; at or above it, start a fresh session with the sandbox's measured brief instead. Zero always starts fresh.",
358
+ ),
359
+ // Worth it since the container is recreated on every update or environment approval — otherwise approving a
360
+ // Dockerfile change costs the run that asked for it.
646
361
  autoResumeOnRestart: z
647
362
  .boolean()
648
363
  .default(false)
649
364
  .describe(
650
365
  "Whether a turn killed by the sandbox restarting is re-run once it comes back. Off to begin with, for the same reason: it would spend your allowance on work you are not watching and edit files while you are still waiting for the sandbox to return. Either way the interruption is recorded rather than silently lost.",
651
366
  ),
652
- /* THE RULE TABLE, every standing instruction the owner gives the sandbox about its own work: ask for
653
- * proof before a turn ends, run a command before a push, hold or release finished work, and whatever they
654
- * add next. See RuleSchema for the shape and for why the four action kinds are four.
655
- *
656
- * EMPTY IS THE DEFAULT, and it is exactly the behaviour a fresh sandbox had when these were three separate
657
- * flags: no proof is asked for, no command runs at a push, and finished work waits on its branch. That is
658
- * not a coincidence to preserve by hand, each of those defaults is what "no rule matched" means at its
659
- * moment, so the empty table IS the old default rather than a reconstruction of it.
660
- *
661
- * Rules live here, in the owner's own settings, rather than in the workspace: a rule can hold work back and
662
- * gate a push, so the first version answers to the person whose sandbox it is and to nobody else. Repo-
663
- * committed and extension-contributed rules are worth having and are deliberately not here yet, they need
664
- * the question of what a rule from somewhere else may WIDEN answered first. */
367
+ // Lives in the owner's own settings, not the workspace: a rule can hold work and gate a push, so it answers to the
368
+ // sandbox owner alone. Repo- or extension-contributed rules aren't supported yet.
665
369
  rules: z
666
370
  .array(RuleSchema)
667
371
  .max(50)
@@ -669,19 +373,6 @@ export const SandboxSettingsSchema = z.object({
669
373
  .describe(
670
374
  "Standing instructions you give the sandbox about its own work: ask for proof before a turn ends, run something before a push, hold or release finished work. Empty is the default and is exactly the behaviour of a fresh sandbox, because each of those defaults is what no rule matched means at its own moment.",
671
375
  ),
672
- /* STOP AN AUTOMATION THAT ONLY EVER FAILS. After this many consecutive `error` runs the scheduler disables
673
- * it and says so on the row, instead of firing a job that has proven it cannot succeed every minute until
674
- * someone notices. 0 ⇒ never, which is the default.
675
- *
676
- * Off by default because quarantining edits the USER'S OWN configuration, and the failure it reacts to is
677
- * not always the automation's fault: an hourly poll against an API having a bad afternoon is broken for
678
- * three fires and fine on the fourth, and a job disabled at 3 a.m. is one nobody re-enables until they
679
- * notice it stopped. So the mechanism exists for the case it is unambiguously right for, a misconfigured
680
- * job burning a turn's worth of tokens on every tick, and the owner is the one who decides their
681
- * automations are the kind that should be stopped rather than retried.
682
- *
683
- * Only `error` counts. A `skipped` run is a guard doing its job, and an `interrupted` one means the daemon
684
- * died mid-fire, which says nothing about the automation, counting either would quarantine healthy jobs. */
685
376
  automationFailureLimit: z
686
377
  .number()
687
378
  .min(0)
@@ -690,70 +381,30 @@ export const SandboxSettingsSchema = z.object({
690
381
  .describe(
691
382
  "How many failures in a row before an automation switches itself off. Zero means never, which is the default, because the failure is not always the automation's fault and a job disabled at three in the morning is one nobody re-enables. Only real errors count: a guard deciding there was nothing to do, or the sandbox dying mid-run, say nothing about the automation.",
692
383
  ),
693
- /* WHO MAY START A SESSION WITHOUT YOU, the admission floor, per wake source (see AdmissionPolicySchema).
694
- * Defaults all-allow, so a fresh sandbox behaves exactly as before the floor existed and the per-automation
695
- * `requireApproval` stays the way most owners meet holds. */
384
+ // Defaults all-allow, so a fresh sandbox behaves as it did before this floor existed.
696
385
  admission: AdmissionPolicySchema.prefault({}).describe(
697
386
  "Whether work started from outside may run, per kind of trigger: let it, hold it for approval, or refuse it. Composes with each automation's own setting, and the stricter of the two wins, so holding every visitor's message needs no edit to each automation.",
698
387
  ),
699
- /* THE SNIFFER'S RULEBOOK, verdicts for in-turn actions the outbound gate classifies, keyed by
700
- * `<provider>.<type>` ("discord.message.send") with `<provider>.*` as the per-provider wildcard; exact key
701
- * wins. An action with no rule is allowed, the empty default wires no hook at all, so an unconfigured
702
- * workspace pays nothing. "hold" cannot park a running turn (nobody may be there to answer); it refuses the
703
- * live call and points the agent at the approvals queue, which IS the held form of a send.
704
- *
705
- * The CHILD-AGENT surface reads the same book: `agents.spawn` covers starting, steering and answering
706
- * child agents on every provider, `agents.spawn.<provider>` singles one out (the specific key wins), and
707
- * the daemon's own taint floor holds a spawn from a turn that has taken in outside content unless the
708
- * owner wrote an explicit allow (guard/actions.ts childSpawn). "hold" refuses with the owner named, the
709
- * same translation a send gets. */
388
+ // Keyed by `<provider>.<type>` ("discord.message.send"), or `<provider>.*` as a wildcard — exact key wins;
389
+ // unconfigured is allowed. "hold" can't park a live call: it refuses and points to the approvals queue. The
390
+ // child-agent surface (`agents.spawn`/`agents.spawn.<provider>`) reads the same book, plus its own taint floor for
391
+ // spawns from tainted turns.
710
392
  actionRules: z
711
393
  .record(z.string(), AdmissionRuleSchema)
712
394
  .default({})
713
395
  .describe("What an agent may do out in the world, per kind of action: go ahead, ask first, or never."),
714
- /* NO VERDICT FOR THE COMMAND GATE LIVES HERE, and the two settings that do are about the JUDGE rather than
715
- * about what it should decide. `commandRules` used to be a verdict per CommandClass and `explainCommands`
716
- * decided whether a card carried a sentence; both are gone, and the reason is the whole safety redesign
717
- * (safety-policy.ts argues it). A regex verdict per class asked about `echo "rm -rf /"` and an actual delete
718
- * in the same words, and no setting of six switches fixes that, because telling the two apart is an act of
719
- * understanding rather than a threshold. What replaced them is the owner's written policy at
720
- * .intentic/config/safety.md, read by a judge that also sees what the daemon knows about the turn, plus one
721
- * typed hard rule the judge cannot waive. The Safety page edits that document; what a command may DO is
722
- * settled there and nowhere in this object.
723
- *
724
- * WHETHER THE JUDGE RUNS AT ALL is a different question, and one this object has to answer, because it is
725
- * the only tier of the design that spends money and interrupts people. An owner who does not want either is
726
- * entitled to say so, and before this they could not: the old rulebook could be set to allow everything, and
727
- * the redesign quietly made itself the one part of the sandbox you could only opt further into.
728
- *
729
- * WHICH MODEL judges is not answered here: it is the `safety-judge` role in `modelRoles`, like every other
730
- * job in this sandbox that picks one. It used to need its own key, on the argument that a verdict is worth a
731
- * different model than a commit message — true, and the fact that it had to be argued for one job at a time
732
- * is exactly what the role catalog replaced. */
396
+ // Command policy itself lives at .intentic/config/safety.md (edited by the Safety page), not here; this only says
397
+ // whether the judge runs at all. Which model judges is the `safety-judge` role in `modelRoles`, not a field here.
733
398
  commandJudge: CommandJudgeModeSchema.default("on").describe(
734
399
  "Whether a model reads your safety policy before a flagged command runs. Off judges nothing and asks about nothing; Watch judges everything and records it without ever interrupting you, which is how you find out what your policy actually does before you let it stop anything; On lets the verdict decide. Wiping a disk or deleting under /history asks at every setting — that rule is typed rather than judged, and cannot be turned off.",
735
400
  ),
736
- /* HOW MUCH AN AGENT MAY DELEGATE, the three ceilings the Claude Code harness enforces on its own Agent
737
- * tool, surfaced here because their defaults are tuned for a laptop and this is a container the owner sized.
738
- *
739
- * They are three settings rather than one because they stop different things, and a fan-out that clears one
740
- * lands on the next: `subagentsAtOnce` is the parallel width of a single fan-out, `subagentsPerTurn` is the
741
- * lifetime budget of one conversation, and `subagentDepth` is how far a child may itself delegate. Raising
742
- * the width alone is what makes a wide sweep hit the lifetime cap two rounds later, which reads to the user
743
- * as the same wall in a new place.
744
- *
745
- * Each default is what the CLI does with no env set, so a sandbox that has never opened this group behaves
746
- * exactly as it always did, these are not our numbers, they are the harness's, restated so they can move.
747
- * The ceilings are ours: an agent is told to stop and NOT retry when it hits one, so the cost of a number
748
- * set too high is a real fleet of models running at once, and the cost of one set too low is a wall.
749
- *
750
- * The refusal an agent sees names the env var (`ask them to raise CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS`),
751
- * which is why these three exist as settings at all: without them the only answer to that ask is editing
752
- * the container's environment and restarting the daemon. */
401
+ // Three separate ceilings since they stop different things: width (parallel fan-out), lifetime (per conversation),
402
+ // depth (how far a child may delegate) — raising width alone just hits the lifetime cap sooner. Defaults mirror the
403
+ // CLI's own unset behavior; hitting one stops the agent rather than retrying.
753
404
  subagentsAtOnce: z.number().min(1).max(200).default(20).describe("How many subagents may work at the same time."),
754
405
  subagentsPerTurn: z.number().min(1).max(2000).default(200).describe("How many a single turn may start in total."),
755
- // Depth 1 = an agent may delegate, but its children may not. The CLI's own default is 3, and it is the one
756
- // of the three whose runaway case is unbounded rather than merely wide, each level multiplies the last.
406
+ // Depth 1 means an agent may delegate but its children may not; unlike the other two, a runaway here is
407
+ // multiplicative, not merely wide.
757
408
  subagentDepth: z
758
409
  .number()
759
410
  .min(1)
@@ -762,34 +413,20 @@ export const SandboxSettingsSchema = z.object({
762
413
  .describe("How many levels deep the delegation may go, since a subagent can start subagents of its own."),
763
414
  });
764
415
  export type SandboxSettings = z.infer<typeof SandboxSettingsSchema>;
765
- // One of the two built-in bases, as text: Intentic's own prompt, or Claude Code's preset read out of the CLI
766
- // this sandbox runs (preset-prompt.ts captures it rather than storing a transcription). What the settings page
767
- // shows behind "View" and drops into the editor behind "Edit a copy".
768
- //
769
- // `version` is the CLI build a captured preset came from, so the UI can say WHICH text the user is looking at:
770
- // a custom prompt forked from an older build is a snapshot, and the version is the only honest way to tell.
771
- // Empty for Intentic's prompt, which ships with the app and has no version of its own to report.
416
+ // Read live from the installed CLI (preset-prompt.ts), not a stored transcription. `version` is the CLI build it came
417
+ // from, so a fork from an older build reads as a snapshot; empty for Intentic's own prompt.
772
418
  export const BuiltinPromptTextSchema = z.object({ text: z.string(), version: z.string() });
773
419
  export type BuiltinPromptText = z.infer<typeof BuiltinPromptTextSchema>;
774
- /* ---- savings report: what each token-reduction mechanism actually saved ----
775
- *
776
- * Input-side savings: shell output the cleaners trimmed before the model ever saw it. Both sides of the
777
- * comparison come off the SAME command (raw in, emitted out), so the counterfactual is observed rather than
778
- * estimated: exact, per command, no sample size to argue about.
779
- */
420
+ // What each token-reduction mechanism actually saved. Input-side: both sides of the comparison come off the same
421
+ // command (raw in, emitted out), so the counterfactual is observed, not estimated — exact, per command.
780
422
 
781
- // One mechanism's realized saving, biggest first. `savedTokens` is what THIS stage removed from what reached
782
- // it in pipeline order, sequential attribution, which is why the stages sum exactly to raw − emitted and can
783
- // be drawn as one stacked bar. It is NOT "what turning this cleaner off would cost you": the cap downstream
784
- // would have eaten some of the same lines. `commands` is how many commands the stage ran on. Negative for the
785
- // `footer` stage, which adds the retrieval pointer back, a cost on the same ledger as what it bought.
423
+ // Sequential attribution (sums exactly to raw − emitted, drawable as a stacked bar); not what disabling this stage
424
+ // would save, since downstream would eat some of the same lines. Negative for `footer`, which adds cost back.
786
425
  export const SavingsStageSchema = z.object({ id: z.string(), commands: z.number(), savedTokens: z.number() });
787
- // What the cleaners saved on the way in, aggregated from historyRoot/logs/filter-stats.jsonl, one row per
788
- // agent Bash command, written by agent-output-filter. Every number here is windowed on the ledger's own
789
- // calendar (the UTC day each command ran), so the reader's date range and the figures above it agree.
426
+ // Aggregated from historyRoot/logs/filter-stats.jsonl (one row per Bash command). Windowed on the ledger's own UTC-day
427
+ // calendar, so the reader's date range and these figures agree.
790
428
  export const InputSavingsSchema = z.object({
791
- // When the ledger last recorded a command (epoch ms), so the card can show its age instead of implying
792
- // freshness it doesn't have. Absent when the ledger has never been written.
429
+ // Epoch ms of the ledger's last command, so the card can show its age rather than implying freshness.
793
430
  updatedAt: z.number().optional(),
794
431
  commands: z.number(),
795
432
  rawTokens: z.number(),
@@ -797,133 +434,73 @@ export const InputSavingsSchema = z.object({
797
434
  savedPct: z.number(),
798
435
  // Per-stage attribution, biggest first.
799
436
  perCleaner: z.array(SavingsStageSchema),
800
- // The measured control, commands the holdout left raw, against the cleaned population. A real saved-%
801
- // for the pipeline as a whole rather than an estimate, and the only whole-pipeline counterfactual there is.
437
+ // The measured control (raw vs. cleaned); the only real whole-pipeline counterfactual, not an estimate.
802
438
  holdout: z.object({ cleaned: z.number(), heldOut: z.number(), measuredSavedPct: z.number().optional() }),
803
- /* High-volume commands that matched no cleaner: where the next handler is worth writing. GROUPED by the
804
- * command text, `commands` is how many times it ran and `tokens` their total, because the question this
805
- * list is read for is "what is worth a handler", and a handler is worth writing for a command that costs
806
- * 5k twenty times over, not for the single 60k outlier that happened to sort first. */
439
+ // Grouped by command text: worth a handler is judged by total tokens across runs, not one outlier's size.
807
440
  gaps: z.array(z.object({ command: z.string(), commands: z.number(), tokens: z.number() })),
808
441
  });
809
442
  export type InputSavings = z.infer<typeof InputSavingsSchema>;
810
- // One arm of a turn-level experiment: the turns that ran with the mechanism, and the turns the holdout ran
811
- // without it. A mean PER TURN, because the arms never hold the same number of turns.
443
+ // One arm of a turn-level experiment; mean is per turn, since the two arms never hold the same count.
812
444
  export const SavingsArmSchema = z.object({ turns: z.number(), mean: z.number() });
813
- /* ONE METRIC'S READING of a turn-level experiment: the two arms, and whatever the arithmetic over them will
814
- * stand behind. An experiment can carry several, see TurnExperimentSchema.
815
- *
816
- * `metric` says what `mean` counts and what `deltaPct` is a delta in, and choosing it is most of the work.
817
- * searchCalls , the search teaching: the searches a turn ran, which the teaching directly changes.
818
- * openingSearches, the same, narrower: the searches before the turn first touched a file.
819
- * openingListings , the project map: the directory listings a turn ran to work out where it was, which is
820
- * what the map hands over and what its note tells the turn not to go and fetch.
821
- * callsBeforeTarget, the map again, on value rather than compliance: how far the turn walked before
822
- * touching a file it went on to edit.
823
- * Neither mechanism may be judged on COST. Cost is a whole turn's work, both of these move one part of it, and
824
- * the part sits inside the noise of the rest. The map's whole payload is about 200 tokens, so a cost reading
825
- * would be measuring a quantity two orders of magnitude under its own error bar. */
445
+ // One metric's reading of a turn-level experiment (the two arms, plus the arithmetic over them). `metric` says what
446
+ // `mean`/`deltaPct` count:
447
+ // searchCalls: searches a turn ran (the search teaching).
448
+ // openingSearches: same, narrowed to before the turn first touched a file.
449
+ // openingListings: directory listings a turn ran to orient itself (the project map).
450
+ // callsBeforeTarget: how far a turn walked before touching a file it went on to edit.
451
+ // Never cost: each mechanism moves one small part of a turn's work, inside the noise of the rest.
826
452
  export const TurnMetricReadingSchema = z.object({
827
453
  metric: z.enum(["searchCalls", "openingSearches", "openingListings", "callsBeforeTarget"]),
828
454
  on: SavingsArmSchema,
829
455
  off: SavingsArmSchema,
830
- /* HOW MUCH LONGER, when the margin spans zero and the honest answer is "keep collecting": the additional
831
- * CONTROL turns at which the resolution would reach a width worth acting on (turn-experiments.ts sets it),
832
- * holding the spread where it sits today.
833
- *
834
- * It is aimed at a FIXED resolution rather than at today's delta on purpose. Sized against the observed
835
- * effect it reported fourteen more turns for an experiment that had gone nine days without resolving, an
836
- * estimate divided by noise inherits the noise and promises an answer next week indefinitely. Against a
837
- * fixed target the same ledger asks for a few hundred, which is the fact the reader needs: this holdout is
838
- * not close, and waiting is not the move.
839
- *
840
- * An order-of-magnitude figure, and it reads as one, the point is telling "a few more days" apart from
841
- * "not at this holdout", which is a decision, where "measuring…" forever is not.
842
- *
843
- * Absent ⇒ nothing to wait for: the arms are under `minTurns`, the delta is published, or the resolution is
844
- * already good enough and the effect is simply smaller than it. */
456
+ // Additional control turns to reach a fixed target resolution, not today's delta (which inherits noise and always
457
+ // promises "next week"). Absent means nothing to wait for: under `minTurns`, already published, or already resolved
458
+ // enough.
845
459
  controlTurnsNeeded: z.number().optional(),
846
- /* THE RESOLUTION, present as soon as both arms clear `minTurns`: ± percentage points at 95% (Welch,
847
- * unequal variances and unequal arms). Present even when the delta below is withheld, because "whatever
848
- * this mechanism does, it is smaller than ±35 points" is a true and useful thing to be told, it is the
849
- * reading that says to keep collecting rather than to act. */
460
+ // ± percentage points at 95% (Welch); present once both arms clear `minTurns`, even when `deltaPct` is withheld —
461
+ // "smaller than ±35 points" is still a useful, true answer.
850
462
  marginPct: z.number().optional(),
851
- /* THE CLAIM, present only once there is one. Both together, and only when the margin does NOT span zero.
852
- *
853
- * A schema that can't express a half-measured experiment is how a 34%-that-becomes-8%-tomorrow never
854
- * reaches the screen, and clearing `minTurns` turned out not to be enough to buy that. An early search
855
- * teaching run crossed its thirtieth control turn and immediately reported +31.2% ± 35.1pp: a confidence interval
856
- * running from −3.4% to +66.7%, which is to say no effect was measured at all, rendered as an alarming
857
- * number pointing the wrong way. Thirty turns is where the normal approximation starts to hold, not where
858
- * this much per-turn spread resolves an effect; requiring the interval to exclude zero is the same
859
- * withhold-until-it-means-something rule applied to the thing that actually decides whether it does.
860
- * deltaPct, change in the metric's mean per turn under the mechanism; negative is a saving.
861
- * saved , what the delta is worth over the turns that actually ran with it, in this window, in the
862
- * metric's own unit (searches). */
463
+ // Present only once the margin excludes zero — clearing `minTurns` alone isn't enough, or a wide, unresolved swing
464
+ // reads as a real number.
465
+ // deltaPct: change in the metric's mean per turn; negative is a saving.
466
+ // saved: what that delta was worth over the turns that ran with it, in the metric's own unit.
863
467
  deltaPct: z.number().optional(),
864
468
  saved: z.number().optional(),
865
469
  });
866
470
  export type TurnMetricReading = z.infer<typeof TurnMetricReadingSchema>;
867
- /* A turn-level A/B, the shape the iq search teaching experiment reports in.
868
- *
869
- * ONE COIN FLIP, SEVERAL READINGS. `metrics` is a list because the search teaching is judged on two, the
870
- * searches a turn ran, and the ones it ran before touching a file, and they are two readings of the SAME
871
- * experiment, not two experiments. Splitting them into separate entries would duplicate the arm assignment and
872
- * let a screen show a turn count on one that disagrees with the other. Headline first: the screens read
873
- * `metrics[0]` for the big number and the rest as supporting lines. */
471
+ // One coin flip, several readings: `metrics` is a list since splitting readings into separate entries would duplicate
472
+ // the arm assignment. Screens read `metrics[0]` as the headline, the rest as supporting lines.
874
473
  export const TurnExperimentSchema = z.object({
875
- // A head and a tail rather than a plain array, because an experiment judged on nothing is not an experiment:
876
- // the screens take the first reading for their headline and stack the rest under it, and this is what makes
877
- // "there is always a headline" a fact the type carries instead of a check every screen repeats. (`.nonempty()`
878
- // would not do it, in zod 4 it adds a min-length rule and leaves the inferred type a plain array.)
474
+ // A head and a tail, not a plain array, so "always a headline" is a type fact, not a check every screen repeats.
475
+ // `.nonempty()` doesn't do this in zod 4 (a runtime check, still typed as a plain array).
879
476
  metrics: z.tuple([TurnMetricReadingSchema], TurnMetricReadingSchema),
880
- // Turns per arm before a delta is reported at all. Carried on the wire so the screen's "measuring…" state
881
- // counts toward the daemon's real threshold instead of a number the browser guessed. Shared by every
882
- // reading: they are the same turns counted differently, so they clear it together.
477
+ // Carried on the wire so "measuring…" reflects the daemon's real threshold, not a guess; shared across every
478
+ // reading, since they're the same turns.
883
479
  minTurns: z.number(),
884
- /* The randomized unit behind the arm counts. Turn mechanisms default to turns. Teaching loaded into a
885
- * provider session randomizes and analyzes whole conversations, so repeated turns are not false replicas.
886
- *
887
- * "opening turns" is the third case and belongs to a treatment sent ONCE: the project map rides the first
888
- * message and nothing after it, so the sample is one turn per conversation rather than an average over
889
- * the conversation's turns. The distinction is not cosmetic. Averaging a first-turn treatment across a
890
- * twelve-turn conversation divides its effect by twelve and reports the remainder as noise. */
480
+ // Turn mechanisms randomize by turn; session-loaded teaching randomizes whole conversations; a once-sent treatment
481
+ // (the map) samples one turn per conversation, not an average, or its effect divides by the conversation's length.
891
482
  sampleUnit: z.enum(["turns", "conversations", "opening turns"]).optional(),
892
- // Content-addressed treatment version. Present where mixing rows from two instruction revisions would turn
893
- // one experiment into two unnamed ones; the reader filters to this (latest) cohort.
483
+ // Content-addressed treatment version; the reader filters to the latest so two instruction revisions don't blur
484
+ // into one experiment.
894
485
  cohort: z.string().optional(),
895
486
  });
896
487
  export type TurnExperiment = z.infer<typeof TurnExperimentSchema>;
897
- // `search` is absent when that experiment isn't running at all (its flag off, or no holdout set), a section
898
- // that isn't there reads as "not measured", which is the truth, while zeros would read as "measured, worth
899
- // nothing".
900
- /* WHAT THE COMPLEXITY JUDGE HAS BEEN SAYING, read back off the spend ledger's tier fields (UsageTurn.tierScore
901
- * and friends) over the requested window. The three numbers docs/model-routing-design.md §4 says the feature
902
- * cannot be defended without, plus the veto count, and nothing else: no counterfactual "you would have saved
903
- * $X", because the ledger holds what turns COST, not what they would have cost on a model they never ran.
904
- *
905
- * NOT a TurnExperiment, deliberately. The experiments compare two randomized arms of one population; this is a
906
- * tally of what one mechanism observed and did. Dressing it in arms and margins would claim a control group that
907
- * does not exist (routing follows the settings mode, which follows time, not a coin flip).
908
- *
909
- * The whole section is absent when no turn in the window was judged at all (autoTier "off" throughout), which a
910
- * screen renders as absence: "not measured" is the truth, zeros would read as "measured, found nothing". */
488
+ // Absent when the experiment isn't running (flag off, or no holdout set); absence reads as "not measured", not as zero.
489
+ // Read off the spend ledger's tier fields over the window; no counterfactual $ saved, since the ledger holds only what
490
+ // turns cost. Not a `TurnExperiment`: there's no randomized control, routing follows the settings mode over time, not a
491
+ // coin flip. Absent (no turn judged, autoTier off) reads as "not measured", not "measured, found nothing".
911
492
  export const TierReportSchema = z.object({
912
493
  // Turns the judge ran on in the window, the denominator under everything below.
913
494
  judged: z.number(),
914
495
  // …of which landed at or below FAST_CEILING: the turns that looked simple. fast ÷ judged is the fast share.
915
496
  fast: z.number(),
916
- /* What the fast-judged turns that STAYED on the user's pick actually cost, the money measure mode is
917
- * pointing at. An upper bound on any saving, never an estimate of one: moving those turns to the cheap rung
918
- * would have cost something too, and this schema refuses to guess how much. */
497
+ // Upper bound on any saving, never an estimate: moving these turns to the cheap rung would have cost something too.
919
498
  atStakeUsd: z.number(),
920
499
  // Turns that actually ran the cheap rung, and what they cost there. Realized, not projected.
921
500
  routed: z.number(),
922
501
  routedUsd: z.number(),
923
- /* THE GUARDRAIL: fast-judged turns whose conversation's very next ledger row asked for a dearer model, the
924
- * user reaching for the model picker right after a turn the judge called simple. The strongest negative
925
- * signal the ledger can carry (§4's first calibration row). Past a few percent of `fast`, the judge is
926
- * costing more in retries and trust than it saves in tokens. */
502
+ // The guardrail: fast-judged turns whose very next ledger row asked for a dearer model. Past a few percent of
503
+ // `fast`, the judge costs more in trust than it saves.
927
504
  escalated: z.number(),
928
505
  // Fast-judged turns the user vetoed outright (UsageTurn.tierDenied): the same signal, said even louder.
929
506
  denied: z.number(),
@@ -932,9 +509,7 @@ export type TierReport = z.infer<typeof TierReportSchema>;
932
509
  export const SavingsReportSchema = z.object({
933
510
  input: InputSavingsSchema,
934
511
  search: TurnExperimentSchema.optional(),
935
- /* The project map's arms, read on opening turns (see TurnExperimentSchema.sampleUnit). Absent under the
936
- * same rule as `search`: the switch is off, or no holdout is set, and a section that is not there reads as
937
- * "not measured", which is the truth, where zeros would read as "measured, worth nothing". */
512
+ // Same absence rule as `search`: not measured, never zero.
938
513
  map: TurnExperimentSchema.optional(),
939
514
  // Automatic tier selection's readout, see TierReportSchema. Absent ⇒ nothing was judged in the window.
940
515
  tier: TierReportSchema.optional(),