@archmax-ai/harness 0.0.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 (351) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +219 -0
  3. package/dist/agent.d.ts +174 -0
  4. package/dist/agent.js +140 -0
  5. package/dist/agent.js.map +1 -0
  6. package/dist/assembly/compose.d.ts +170 -0
  7. package/dist/assembly/compose.js +391 -0
  8. package/dist/assembly/compose.js.map +1 -0
  9. package/dist/assembly/delegation-registry.d.ts +5 -0
  10. package/dist/assembly/delegation-registry.js +118 -0
  11. package/dist/assembly/delegation-registry.js.map +1 -0
  12. package/dist/assembly/index.d.ts +192 -0
  13. package/dist/assembly/index.js +265 -0
  14. package/dist/assembly/index.js.map +1 -0
  15. package/dist/assembly/plain.d.ts +7 -0
  16. package/dist/assembly/plain.js +41 -0
  17. package/dist/assembly/plain.js.map +1 -0
  18. package/dist/authoring-skill/archmax-harness/README.md +76 -0
  19. package/dist/authoring-skill/archmax-harness/SKILL.md +241 -0
  20. package/dist/authoring-skill/archmax-harness/references/backend-integration.md +626 -0
  21. package/dist/authoring-skill/archmax-harness/references/cases.md +41 -0
  22. package/dist/authoring-skill/archmax-harness/references/diagnostics.md +51 -0
  23. package/dist/authoring-skill/archmax-harness/references/hook-and-test-scripts.md +1070 -0
  24. package/dist/authoring-skill/archmax-harness/references/hooks-and-scripts.md +82 -0
  25. package/dist/authoring-skill/archmax-harness/references/wiring.md +101 -0
  26. package/dist/authoring-skill/archmax-harness/references/workflow-schema.md +1631 -0
  27. package/dist/authoring-skill/archmax-harness/references/workflow-yaml.md +241 -0
  28. package/dist/behaviour/support.d.ts +232 -0
  29. package/dist/behaviour/support.js +339 -0
  30. package/dist/behaviour/support.js.map +1 -0
  31. package/dist/cli/banner.d.ts +11 -0
  32. package/dist/cli/banner.js +29 -0
  33. package/dist/cli/banner.js.map +1 -0
  34. package/dist/cli/bootstrap.d.ts +33 -0
  35. package/dist/cli/bootstrap.js +153 -0
  36. package/dist/cli/bootstrap.js.map +1 -0
  37. package/dist/cli/command.d.ts +39 -0
  38. package/dist/cli/command.js +97 -0
  39. package/dist/cli/command.js.map +1 -0
  40. package/dist/cli/state-flow.d.ts +46 -0
  41. package/dist/cli/state-flow.js +268 -0
  42. package/dist/cli/state-flow.js.map +1 -0
  43. package/dist/cli/style.d.ts +41 -0
  44. package/dist/cli/style.js +64 -0
  45. package/dist/cli/style.js.map +1 -0
  46. package/dist/cli/turn.d.ts +41 -0
  47. package/dist/cli/turn.js +161 -0
  48. package/dist/cli/turn.js.map +1 -0
  49. package/dist/cli.d.ts +10 -0
  50. package/dist/cli.js +426 -0
  51. package/dist/cli.js.map +1 -0
  52. package/dist/core/code-description.d.ts +22 -0
  53. package/dist/core/code-description.js +38 -0
  54. package/dist/core/code-description.js.map +1 -0
  55. package/dist/core/deepagents.d.ts +183 -0
  56. package/dist/core/deepagents.js +128 -0
  57. package/dist/core/deepagents.js.map +1 -0
  58. package/dist/core/events.d.ts +350 -0
  59. package/dist/core/events.js +205 -0
  60. package/dist/core/events.js.map +1 -0
  61. package/dist/core/frontmatter.d.ts +15 -0
  62. package/dist/core/frontmatter.js +32 -0
  63. package/dist/core/frontmatter.js.map +1 -0
  64. package/dist/core/listing-redact.d.ts +37 -0
  65. package/dist/core/listing-redact.js +88 -0
  66. package/dist/core/listing-redact.js.map +1 -0
  67. package/dist/core/match.d.ts +26 -0
  68. package/dist/core/match.js +75 -0
  69. package/dist/core/match.js.map +1 -0
  70. package/dist/core/message-readers.d.ts +84 -0
  71. package/dist/core/message-readers.js +159 -0
  72. package/dist/core/message-readers.js.map +1 -0
  73. package/dist/core/messages.d.ts +49 -0
  74. package/dist/core/messages.js +85 -0
  75. package/dist/core/messages.js.map +1 -0
  76. package/dist/core/mount-prompt.d.ts +28 -0
  77. package/dist/core/mount-prompt.js +55 -0
  78. package/dist/core/mount-prompt.js.map +1 -0
  79. package/dist/core/mount-redact.d.ts +28 -0
  80. package/dist/core/mount-redact.js +32 -0
  81. package/dist/core/mount-redact.js.map +1 -0
  82. package/dist/core/mounts.d.ts +88 -0
  83. package/dist/core/mounts.js +147 -0
  84. package/dist/core/mounts.js.map +1 -0
  85. package/dist/core/path-mapping.d.ts +52 -0
  86. package/dist/core/path-mapping.js +113 -0
  87. package/dist/core/path-mapping.js.map +1 -0
  88. package/dist/core/platform-prompt.generated.d.ts +2 -0
  89. package/dist/core/platform-prompt.generated.js +4 -0
  90. package/dist/core/platform-prompt.generated.js.map +1 -0
  91. package/dist/core/prompt.d.ts +42 -0
  92. package/dist/core/prompt.js +75 -0
  93. package/dist/core/prompt.js.map +1 -0
  94. package/dist/core/session-id.d.ts +38 -0
  95. package/dist/core/session-id.js +61 -0
  96. package/dist/core/session-id.js.map +1 -0
  97. package/dist/core/session-store.d.ts +85 -0
  98. package/dist/core/session-store.js +149 -0
  99. package/dist/core/session-store.js.map +1 -0
  100. package/dist/core/session-zone.d.ts +54 -0
  101. package/dist/core/session-zone.js +82 -0
  102. package/dist/core/session-zone.js.map +1 -0
  103. package/dist/core/skill-prompt.d.ts +31 -0
  104. package/dist/core/skill-prompt.js +54 -0
  105. package/dist/core/skill-prompt.js.map +1 -0
  106. package/dist/core/skill-redact.d.ts +15 -0
  107. package/dist/core/skill-redact.js +27 -0
  108. package/dist/core/skill-redact.js.map +1 -0
  109. package/dist/core/skills.d.ts +172 -0
  110. package/dist/core/skills.js +214 -0
  111. package/dist/core/skills.js.map +1 -0
  112. package/dist/core/tool-mocks.d.ts +23 -0
  113. package/dist/core/tool-mocks.js +39 -0
  114. package/dist/core/tool-mocks.js.map +1 -0
  115. package/dist/core/tool-telemetry.d.ts +16 -0
  116. package/dist/core/tool-telemetry.js +40 -0
  117. package/dist/core/tool-telemetry.js.map +1 -0
  118. package/dist/core/usage.d.ts +114 -0
  119. package/dist/core/usage.js +226 -0
  120. package/dist/core/usage.js.map +1 -0
  121. package/dist/core/workspace-context.d.ts +136 -0
  122. package/dist/core/workspace-context.js +178 -0
  123. package/dist/core/workspace-context.js.map +1 -0
  124. package/dist/core/workspace-prompt.d.ts +7 -0
  125. package/dist/core/workspace-prompt.js +102 -0
  126. package/dist/core/workspace-prompt.js.map +1 -0
  127. package/dist/core/workspace-router.d.ts +61 -0
  128. package/dist/core/workspace-router.js +145 -0
  129. package/dist/core/workspace-router.js.map +1 -0
  130. package/dist/core/workspace.d.ts +85 -0
  131. package/dist/core/workspace.js +193 -0
  132. package/dist/core/workspace.js.map +1 -0
  133. package/dist/core/zones.d.ts +181 -0
  134. package/dist/core/zones.js +202 -0
  135. package/dist/core/zones.js.map +1 -0
  136. package/dist/env.d.ts +99 -0
  137. package/dist/env.js +271 -0
  138. package/dist/env.js.map +1 -0
  139. package/dist/index.d.ts +265 -0
  140. package/dist/index.js +197 -0
  141. package/dist/index.js.map +1 -0
  142. package/dist/kernel/kernel.d.ts +192 -0
  143. package/dist/kernel/kernel.js +751 -0
  144. package/dist/kernel/kernel.js.map +1 -0
  145. package/dist/lifecycle/hook-shape.d.ts +44 -0
  146. package/dist/lifecycle/hook-shape.js +66 -0
  147. package/dist/lifecycle/hook-shape.js.map +1 -0
  148. package/dist/lifecycle/runner.d.ts +177 -0
  149. package/dist/lifecycle/runner.js +372 -0
  150. package/dist/lifecycle/runner.js.map +1 -0
  151. package/dist/lifecycle/transcript.d.ts +27 -0
  152. package/dist/lifecycle/transcript.js +43 -0
  153. package/dist/lifecycle/transcript.js.map +1 -0
  154. package/dist/machine/allow.d.ts +65 -0
  155. package/dist/machine/allow.js +107 -0
  156. package/dist/machine/allow.js.map +1 -0
  157. package/dist/machine/delegation.d.ts +9 -0
  158. package/dist/machine/delegation.js +10 -0
  159. package/dist/machine/delegation.js.map +1 -0
  160. package/dist/machine/diagnostic.d.ts +14 -0
  161. package/dist/machine/diagnostic.js +2 -0
  162. package/dist/machine/diagnostic.js.map +1 -0
  163. package/dist/machine/lint-spec.d.ts +4 -0
  164. package/dist/machine/lint-spec.js +266 -0
  165. package/dist/machine/lint-spec.js.map +1 -0
  166. package/dist/machine/load-spec.d.ts +90 -0
  167. package/dist/machine/load-spec.js +120 -0
  168. package/dist/machine/load-spec.js.map +1 -0
  169. package/dist/machine/machine.d.ts +273 -0
  170. package/dist/machine/machine.js +551 -0
  171. package/dist/machine/machine.js.map +1 -0
  172. package/dist/machine/mount-grants.d.ts +25 -0
  173. package/dist/machine/mount-grants.js +24 -0
  174. package/dist/machine/mount-grants.js.map +1 -0
  175. package/dist/machine/slug.d.ts +14 -0
  176. package/dist/machine/slug.js +17 -0
  177. package/dist/machine/slug.js.map +1 -0
  178. package/dist/machine/spec-schema.d.ts +662 -0
  179. package/dist/machine/spec-schema.js +717 -0
  180. package/dist/machine/spec-schema.js.map +1 -0
  181. package/dist/machine/tool-names.d.ts +98 -0
  182. package/dist/machine/tool-names.js +144 -0
  183. package/dist/machine/tool-names.js.map +1 -0
  184. package/dist/machine/triggers.d.ts +114 -0
  185. package/dist/machine/triggers.js +165 -0
  186. package/dist/machine/triggers.js.map +1 -0
  187. package/dist/machine/types.d.ts +186 -0
  188. package/dist/machine/types.js +12 -0
  189. package/dist/machine/types.js.map +1 -0
  190. package/dist/machine/validate-spec.d.ts +42 -0
  191. package/dist/machine/validate-spec.js +29 -0
  192. package/dist/machine/validate-spec.js.map +1 -0
  193. package/dist/machine/variables.d.ts +196 -0
  194. package/dist/machine/variables.js +415 -0
  195. package/dist/machine/variables.js.map +1 -0
  196. package/dist/public/cli.d.ts +15 -0
  197. package/dist/public/cli.js +14 -0
  198. package/dist/public/cli.js.map +1 -0
  199. package/dist/public/messages.d.ts +33 -0
  200. package/dist/public/messages.js +33 -0
  201. package/dist/public/messages.js.map +1 -0
  202. package/dist/public/sandbox.d.ts +99 -0
  203. package/dist/public/sandbox.js +32 -0
  204. package/dist/public/sandbox.js.map +1 -0
  205. package/dist/public/spec.d.ts +147 -0
  206. package/dist/public/spec.js +149 -0
  207. package/dist/public/spec.js.map +1 -0
  208. package/dist/public/testing.d.ts +71 -0
  209. package/dist/public/testing.js +39 -0
  210. package/dist/public/testing.js.map +1 -0
  211. package/dist/rubrics/rubrics.d.ts +135 -0
  212. package/dist/rubrics/rubrics.js +145 -0
  213. package/dist/rubrics/rubrics.js.map +1 -0
  214. package/dist/runtime/contract.d.ts +73 -0
  215. package/dist/runtime/contract.js +96 -0
  216. package/dist/runtime/contract.js.map +1 -0
  217. package/dist/sandbox/assets/parts/core.js +22 -0
  218. package/dist/sandbox/assets/parts/lifecycle-hook.js +47 -0
  219. package/dist/sandbox/bridge.d.ts +16 -0
  220. package/dist/sandbox/bridge.js +95 -0
  221. package/dist/sandbox/bridge.js.map +1 -0
  222. package/dist/sandbox/executor.d.ts +46 -0
  223. package/dist/sandbox/executor.js +119 -0
  224. package/dist/sandbox/executor.js.map +1 -0
  225. package/dist/sandbox/imports.d.ts +33 -0
  226. package/dist/sandbox/imports.js +67 -0
  227. package/dist/sandbox/imports.js.map +1 -0
  228. package/dist/sandbox/prelude.d.ts +12 -0
  229. package/dist/sandbox/prelude.js +51 -0
  230. package/dist/sandbox/prelude.js.map +1 -0
  231. package/dist/sandbox/ptc-gateway.d.ts +104 -0
  232. package/dist/sandbox/ptc-gateway.js +167 -0
  233. package/dist/sandbox/ptc-gateway.js.map +1 -0
  234. package/dist/sandbox/runtime.d.ts +59 -0
  235. package/dist/sandbox/runtime.js +51 -0
  236. package/dist/sandbox/runtime.js.map +1 -0
  237. package/dist/sandbox/tools.d.ts +34 -0
  238. package/dist/sandbox/tools.js +147 -0
  239. package/dist/sandbox/tools.js.map +1 -0
  240. package/dist/sessions/operations.d.ts +79 -0
  241. package/dist/sessions/operations.js +121 -0
  242. package/dist/sessions/operations.js.map +1 -0
  243. package/dist/sessions/resolve.d.ts +97 -0
  244. package/dist/sessions/resolve.js +145 -0
  245. package/dist/sessions/resolve.js.map +1 -0
  246. package/dist/sessions/resume.d.ts +242 -0
  247. package/dist/sessions/resume.js +288 -0
  248. package/dist/sessions/resume.js.map +1 -0
  249. package/dist/sessions/scope.d.ts +99 -0
  250. package/dist/sessions/scope.js +145 -0
  251. package/dist/sessions/scope.js.map +1 -0
  252. package/dist/sessions/summary.d.ts +65 -0
  253. package/dist/sessions/summary.js +56 -0
  254. package/dist/sessions/summary.js.map +1 -0
  255. package/dist/testing/assertions.d.ts +30 -0
  256. package/dist/testing/assertions.js +231 -0
  257. package/dist/testing/assertions.js.map +1 -0
  258. package/dist/testing/case-document.d.ts +141 -0
  259. package/dist/testing/case-document.js +51 -0
  260. package/dist/testing/case-document.js.map +1 -0
  261. package/dist/testing/case-schema.d.ts +29 -0
  262. package/dist/testing/case-schema.js +519 -0
  263. package/dist/testing/case-schema.js.map +1 -0
  264. package/dist/testing/discovery.d.ts +10 -0
  265. package/dist/testing/discovery.js +24 -0
  266. package/dist/testing/discovery.js.map +1 -0
  267. package/dist/testing/driver.d.ts +78 -0
  268. package/dist/testing/driver.js +117 -0
  269. package/dist/testing/driver.js.map +1 -0
  270. package/dist/testing/grade.d.ts +116 -0
  271. package/dist/testing/grade.js +261 -0
  272. package/dist/testing/grade.js.map +1 -0
  273. package/dist/testing/interpreter.d.ts +55 -0
  274. package/dist/testing/interpreter.js +103 -0
  275. package/dist/testing/interpreter.js.map +1 -0
  276. package/dist/testing/mock-middleware.d.ts +5 -0
  277. package/dist/testing/mock-middleware.js +33 -0
  278. package/dist/testing/mock-middleware.js.map +1 -0
  279. package/dist/testing/runner.d.ts +205 -0
  280. package/dist/testing/runner.js +266 -0
  281. package/dist/testing/runner.js.map +1 -0
  282. package/dist/testing/target.d.ts +27 -0
  283. package/dist/testing/target.js +21 -0
  284. package/dist/testing/target.js.map +1 -0
  285. package/dist/validate/validate.d.ts +41 -0
  286. package/dist/validate/validate.js +669 -0
  287. package/dist/validate/validate.js.map +1 -0
  288. package/dist/workflow/agent-tools.d.ts +10 -0
  289. package/dist/workflow/agent-tools.js +10 -0
  290. package/dist/workflow/agent-tools.js.map +1 -0
  291. package/dist/workflow/checkpointer.d.ts +52 -0
  292. package/dist/workflow/checkpointer.js +200 -0
  293. package/dist/workflow/checkpointer.js.map +1 -0
  294. package/dist/workflow/control-tools.d.ts +174 -0
  295. package/dist/workflow/control-tools.js +468 -0
  296. package/dist/workflow/control-tools.js.map +1 -0
  297. package/dist/workflow/governance.d.ts +104 -0
  298. package/dist/workflow/governance.js +546 -0
  299. package/dist/workflow/governance.js.map +1 -0
  300. package/dist/workflow/middleware.d.ts +85 -0
  301. package/dist/workflow/middleware.js +283 -0
  302. package/dist/workflow/middleware.js.map +1 -0
  303. package/dist/workflow/on-error.d.ts +25 -0
  304. package/dist/workflow/on-error.js +58 -0
  305. package/dist/workflow/on-error.js.map +1 -0
  306. package/dist/workflow/parks.d.ts +46 -0
  307. package/dist/workflow/parks.js +513 -0
  308. package/dist/workflow/parks.js.map +1 -0
  309. package/dist/workflow/paths.d.ts +67 -0
  310. package/dist/workflow/paths.js +108 -0
  311. package/dist/workflow/paths.js.map +1 -0
  312. package/dist/workflow/prompt-cache.d.ts +70 -0
  313. package/dist/workflow/prompt-cache.js +103 -0
  314. package/dist/workflow/prompt-cache.js.map +1 -0
  315. package/dist/workflow/prompt-pruning.d.ts +20 -0
  316. package/dist/workflow/prompt-pruning.js +83 -0
  317. package/dist/workflow/prompt-pruning.js.map +1 -0
  318. package/dist/workflow/render-prompt.d.ts +45 -0
  319. package/dist/workflow/render-prompt.js +140 -0
  320. package/dist/workflow/render-prompt.js.map +1 -0
  321. package/dist/workflow/runtime-config.d.ts +7 -0
  322. package/dist/workflow/runtime-config.js +9 -0
  323. package/dist/workflow/runtime-config.js.map +1 -0
  324. package/dist/workflow/session-artifacts.d.ts +90 -0
  325. package/dist/workflow/session-artifacts.js +134 -0
  326. package/dist/workflow/session-artifacts.js.map +1 -0
  327. package/dist/workflow/session-view.d.ts +31 -0
  328. package/dist/workflow/session-view.js +94 -0
  329. package/dist/workflow/session-view.js.map +1 -0
  330. package/dist/workflow/snapshot.d.ts +14 -0
  331. package/dist/workflow/snapshot.js +97 -0
  332. package/dist/workflow/snapshot.js.map +1 -0
  333. package/dist/workflow/state.d.ts +347 -0
  334. package/dist/workflow/state.js +322 -0
  335. package/dist/workflow/state.js.map +1 -0
  336. package/dist/workflow/sub-workflow.d.ts +174 -0
  337. package/dist/workflow/sub-workflow.js +392 -0
  338. package/dist/workflow/sub-workflow.js.map +1 -0
  339. package/dist/workflow/tool-service.d.ts +48 -0
  340. package/dist/workflow/tool-service.js +291 -0
  341. package/dist/workflow/tool-service.js.map +1 -0
  342. package/dist/workflow/turn-boundary.d.ts +39 -0
  343. package/dist/workflow/turn-boundary.js +128 -0
  344. package/dist/workflow/turn-boundary.js.map +1 -0
  345. package/dist/workflow/turn-runner.d.ts +40 -0
  346. package/dist/workflow/turn-runner.js +122 -0
  347. package/dist/workflow/turn-runner.js.map +1 -0
  348. package/dist/workflow/workflow-tools.d.ts +46 -0
  349. package/dist/workflow/workflow-tools.js +90 -0
  350. package/dist/workflow/workflow-tools.js.map +1 -0
  351. package/package.json +119 -0
@@ -0,0 +1,241 @@
1
+ # `workflow.yaml` — keys, machine rules, governance
2
+
3
+ Load this when writing or editing a `workflow.yaml`. Field-level detail and
4
+ precedence edge cases: [`workflow-schema.md`](workflow-schema.md).
5
+
6
+ ## Every key
7
+
8
+ The schema is strict: an unknown key anywhere is a load error naming it. This
9
+ skeleton is the complete vocabulary; omit what you do not need.
10
+
11
+ ```yaml
12
+ title: Triage example # label only; identity is the directory slug
13
+ instructions: |- # standing direction for the whole run (warning if absent)
14
+ Records live in skills/order-data/assets/orders.json; write artifacts under scratchpad/.
15
+
16
+ Answer only from records you have read; never fabricate.
17
+ runtime: { engine: archmax-harness, version: "2" }
18
+ disabled: false # true = out of service: no new turns; parked runs still drain
19
+ settings: # sandbox limits: timeoutMs, memoryLimitBytes, maxPtcCalls,
20
+ timeoutMs: 15000 # maxResultChars, prompt_cache: { enabled, ttl }
21
+ model: gpt-5-mini # MODEL ID ONLY — every state runs on it; overrides ARCHMAX_MODEL
22
+ tests: # case suite config (no tests.config.js exists)
23
+ maxConcurrency: 1 # only 1 accepted
24
+ caseTimeoutMs: 120000 # per-case wall clock, distinct from settings.timeoutMs
25
+ judge: {} # required for grade:; {} = env default model, or { model, modelOptions }
26
+ metadata: { canvas: {} } # host data, never read; accepted at root, state, rubric — leave as found
27
+ extensions: { hooks: [] } # host-registered hook kinds; rarely authored
28
+
29
+ tools: # tool governance, workflow level
30
+ allow_always: [] # granted in EVERY state; a state's allow adds to it
31
+ forbid_always: [archmax_reset] # denied in EVERY state; beats every grant; "*" = every tool
32
+ skills: # skill governance, workflow level — SLUGS, never paths
33
+ allow_always: [order-data] # enabled in every state; [] = every capability is state-specific
34
+ forbid_always: [] # out of reach everywhere
35
+
36
+ states:
37
+ triage: # key = slug = identity (^[a-z0-9]+(-[a-z0-9]+)*$)
38
+ type: agent # agent (default) | human
39
+ title: Triage request # label for people/hosts; reaches no model call
40
+ summary: Record the refund decision for review. # ditto: an authoring/host label, NOT in the prompt
41
+ triggers: # a trigger is declared on the state it ENTERS; key = id
42
+ manual: # CLI / caller / host entry; the prompt is its input
43
+ email_reply: # any other id = host event; the payload arrives as locked variables
44
+ session: conversation_id # dotted path over variables: which conversation a firing joins
45
+ message: false # or a dotted path to the message text; false = firings carry none
46
+ connection: mail # host access connection; other keys preserved with a warning
47
+ requires: [order_id] # variables a firing must supply (a caller's required params)
48
+ returns: [result_file] # variables the run guarantees on completion (a caller's result)
49
+ instructions: >-
50
+ Record the decision in scratchpad/refund.json, then archmax_advance to
51
+ review; never close the case yourself.
52
+ before: # gates entry: ok/veto only; a veto here rejects the run
53
+ - script: hooks/check-requester.js
54
+ after: # gates the archmax_advance out (or completion, when terminal)
55
+ - script: hooks/check-policy.js
56
+ max_iterations: 2 # how many `correct`s before a hard veto (per hook; default 0)
57
+ - rubric: # LLM grader, inline; the agent never sees it
58
+ instructions: |- # the only required key: criteria + verdict (ok/correct/veto + reason)
59
+ Judge the tone of the last assistant message …
60
+ max_iterations: 1
61
+ model: gpt-4.1-mini # optional override
62
+ tools:
63
+ allow: # adds to allow_always; entry = name | { tool, args: {<arg>: [globs]} } | { tool, paths }
64
+ - lookup_customer
65
+ - { tool: archmax_run, paths: ["skills/refund-policy/scripts/**"] } # narrows an always-on tool, within an enabled skill
66
+ - { tool: write_file, args: { file_path: ["reports/${{case_id}}/*.json"] } } # variable-bound guard
67
+ - archmax_workflow_enrich-order # runs a sibling workflow
68
+ forbid: [archmax_wait] # denies here; beats every grant incl. the always-on surface
69
+ skills:
70
+ allow: [refund-policy] # adds to allow_always (bundle readable + scripts runnable, no path entries)
71
+ forbid: [order-data] # subtracts, even from allow_always ([] never denies)
72
+ requires: [case_id] # variables that must be set before this state may be left
73
+ model: claude-opus-5 # MODEL ID ONLY — this state's turns; beats settings.model
74
+ budget: { maxTurns: 12, timeoutMs: 60000, maxParks: 5 } # bounds the state's segment
75
+ on_error: closed # where a terminal failure of this segment routes
76
+ metadata: { x: 40, y: 180 }
77
+ transitions: # none => terminal state
78
+ - to: review # slug; must exist
79
+ description: The decision is recorded and needs a person's approval. # REQUIRED, non-empty:
80
+ # the ONLY thing the agent knows about this edge (on a human
81
+ # state, also the button label). Say WHEN, never where.
82
+ type: none # approve | reject | refine | none — semantic on human states
83
+
84
+ review: # human state: parks with a decision record; a PERSON picks the edge
85
+ type: human
86
+ title: Review refund
87
+ summary: A person approves the recorded decision or sends it back. # label only
88
+ instructions: >- # required on human states: the decision to present
89
+ Confirm scratchpad/refund.json matches policy.
90
+ approvers: [finance@acme.com]
91
+ evidence: [scratchpad/refund.json] # plus whatever archmax_advance attached via `evidence:`
92
+ transitions: # required; no self-edge; one target per labeled type
93
+ - { to: closed, type: approve, description: Approve and close. }
94
+ - { to: triage, type: refine, description: Send back with a comment. }
95
+
96
+ closed: # bare key = terminal state with no declarations
97
+ ```
98
+
99
+ ## Machine rules
100
+
101
+ - **Movement.** The agent moves only by `archmax_advance({ to, reason, evidence? })`
102
+ — one per message, edge validated, then the leaving state's `after` hooks,
103
+ the target's `before` hooks, then the target's tools unlock. A state with no
104
+ transitions is terminal; the run ends when the agent finishes there. Human
105
+ decisions and `on_error` are the other two movers. `archmax_reset({ reason })`
106
+ returns to the entry state (forbid it via `forbid_always` when a run must
107
+ never restart). No fan-out: sequence states; concurrency lives in
108
+ sub-workflow calls.
109
+ - **Entry.** At least one state declares `triggers`; one state per trigger id;
110
+ `manual` is the entry the CLI, a host firing and a caller all use. A
111
+ re-invoked finished session is a **new turn in the state it ended in**, not
112
+ at the entry — give a state re-entry transitions if a conversation must move
113
+ on, or park instead of finishing.
114
+ - **Variables.** One flat checkpointed `name → value` store, never declared.
115
+ Host seeds (`--variables`, `createAgent({ variables })`, a delivery) are
116
+ **locked**; the agent uses `archmax_get_variables`/`archmax_set_variables`
117
+ (`lock: true` to freeze). Reserved: `trigger` (current trigger id, always
118
+ locked) and `title` (the run's one-line task label, agent-owned). A
119
+ `${{name}}` / `${{a.b.-1.c}}` reference works in `tools.allow` globs
120
+ (guard) and inside any text tool argument the model writes (exact
121
+ substitution, no retyping) — but not in scripts, which read
122
+ `args.variables`. Name a guarded variable in an earlier state's `requires`
123
+ or seed it; an unresolvable guard reference fails the run, an unresolvable
124
+ argument reference is refused and retried. An `archmax_set_variables` typo
125
+ creates a new variable; `requires` is what surfaces it.
126
+ - **Models.** `settings.model` names the id every state runs on and a state's
127
+ `model` names its own — an **id only**, over the endpoint the assembly is
128
+ already configured with (a block with `temperature` is a load error;
129
+ sampling is env/host configuration). Precedence: state → workflow →
130
+ `ARCHMAX_MODEL`. Author it where the work differs in kind: small models for
131
+ classification, extraction and other mechanical states; leave drafting,
132
+ judgement and any state with a big tool surface or several transitions on
133
+ the default, since a small model that routes badly costs more in retries
134
+ than it saves. Repeating the workflow's id on a state is a validate warning.
135
+ A rubric keeps its own `model`, a sub-workflow uses its own spec's, and a
136
+ host that passes an explicit `model` instance to `createAgent` outranks
137
+ every declared id (it must pass `modelFactory` to honour them).
138
+ - **Parking.** A state that needs an event or a time calls
139
+ `archmax_wait({ reason, until? })` (`until`: `30m`/`2h`/`1d` or ISO instant →
140
+ `resumeAt` for the host's scheduler; the runtime holds no timer). Any
141
+ delivered trigger resumes **that same state** with the payload as locked
142
+ variables and an `[event]` runtime note; the state then picks its own edge.
143
+ Bound a polling loop with `budget.maxParks` + `on_error`. `archmax_wait` is
144
+ in every state, terminal ones included. Use a **human state** when a person
145
+ picks the edge, `archmax_wait` when an event or time resumes the work.
146
+ - **Human states** park with a record built from `instructions`, `evidence`
147
+ and transition `type`s. The handoff spends one reply-only model call so the
148
+ park carries a message — do **not** instruct the agent to announce the
149
+ handoff (two messages). While parked, `archmax reply` is answered on a
150
+ tool-free turn and re-parks unchanged; only `decide` moves the run. A
151
+ `refine` edge delivers the reviewer's comment as correction.
152
+ - **Hooks.** `before`: ok/veto (veto rejects entry; on a start state, the
153
+ run; routed through `on_error` if declared). `after`: ok/correct/veto on
154
+ the outgoing advance or on completion of a terminal state; `correct` sends
155
+ the agent back with the reason, bounded per hook by `max_iterations`
156
+ (default 0 → a correct is a hard veto). A list runs in order and stops at
157
+ the first non-ok. Errors and missing files veto (fail-closed). Hooks run
158
+ on runtime authority: the state's `allow`/`forbid`/`skills` do not bind
159
+ them; `forbid_always` and safety rules do. Human states may not declare
160
+ hooks.
161
+ - **Budgets and `on_error`.** `budget.maxTurns`/`timeoutMs`/`maxParks` bound
162
+ a state's segment. A terminal failure (hook execution error, exhausted
163
+ corrections, exhausted budget, exhausted parks) routes to `on_error`
164
+ instead of failing the run; recoverable rejections (invalid edge, veto,
165
+ in-budget correct) keep the agent in place. Declare `on_error` on states
166
+ with strict `after` hooks or bounded loops.
167
+ - **Sub-workflows are tools.** Allow `archmax_workflow_<slug>` (slug verbatim)
168
+ and the sibling `workflows/<slug>/` is callable: its `manual` trigger's
169
+ `requires` are the parameters, its `returns` the result
170
+ (`{ message, returns }`). Nothing captures the result — the caller records
171
+ what it needs with `archmax_set_variables`, made mandatory by `requires`.
172
+ The child is a separate session with a fresh transcript, sees only its
173
+ arguments (as locked variables), and shares no prose. One call = one
174
+ sub-run; fan out with parallel tool calls or `Promise.all` in a script
175
+ (bounds: depth 3, 4 concurrent). A child's human state parks the child;
176
+ a script's delegation cannot park and fails closed.
177
+ - **Choosing a mechanism.** Deterministic work with no model → an `archmax_run`
178
+ script. Delegated work that is itself a process or reused across workflows
179
+ → a sub-workflow. Judging work already done → a rubric hook (never
180
+ callable by the agent; `task` is disclosed nowhere and not grantable).
181
+ - **Prompt economy.** The static prompt + tool schemas are re-sent every
182
+ model call. The static part carries the workflow's `title` + `instructions`
183
+ and **no state of the graph**; a state's `instructions` and its **own**
184
+ outgoing edges are sent only while it is active. So: workflow-wide
185
+ conventions go in the root `instructions` (paid once, cached); everything
186
+ else goes in the state that needs it, and splitting a broad state into
187
+ several narrow ones costs nothing in the prefix. `title` and `summary` are
188
+ free — neither reaches a model call. `WORKFLOW.md` carries only what the spec
189
+ cannot say; reader diagrams go inside an HTML comment (stripped from the
190
+ prompt).
191
+
192
+ ## What the agent sees of the graph
193
+
194
+ Only the state it is in. Every model call is handed that state's outgoing edges
195
+ and nothing else of the machine — no other state's slug, `title`, `summary`,
196
+ hooks or transitions, and no count of the states:
197
+
198
+ ```
199
+ Transitions — choose one with `archmax_advance` when this state's work is done:
200
+ - to `review` (human decision node) — The decision is recorded and needs a person's approval.
201
+ - to `closed` (terminal) — Nothing to refund; the case is answered.
202
+ ```
203
+
204
+ Two rules follow, and they are the ones authors get wrong:
205
+
206
+ 1. **Write the `description` for the source state, not the target.** The agent
207
+ reading it knows nothing about where it is going. Say *when* the edge applies:
208
+ `The refund is over $50, or the customer has asked twice.` Not `Go to
209
+ refund-review.` — that tells a reader who already knows the graph something
210
+ they cannot use, and tells this reader nothing.
211
+ 2. **Routing conditions cannot live downstream.** A target's `summary` or
212
+ `instructions` is never disclosed to the state routing into it. If the
213
+ condition is "when the order is over 30 days old", it belongs on the edge.
214
+
215
+ A missing or blank `description` is a **load error**. There is no fallback, and
216
+ no way to see more of the graph.
217
+
218
+ ## Governance
219
+
220
+ Closed by default; **deny beats allow, and no narrower level widens a denial.**
221
+
222
+ - **Always on, never declared**: `ls`, `read_file`, `write_file`,
223
+ `edit_file`, `glob`, `grep`, `write_todos`, `archmax_eval`, `archmax_run`,
224
+ and the controls `archmax_advance`, `archmax_reset`, `archmax_wait`,
225
+ `archmax_get_variables`, `archmax_set_variables`. Any other tool needs an
226
+ `allow`/`allow_always` entry. An entry naming an always-on tool **narrows**
227
+ it. `task` is ungrantable (error).
228
+ - **Entries**: bare name; `{ tool, args: { <arg>: ["glob", …] } }` (matches
229
+ if any glob matches; `${{var}}` allowed); `{ tool, paths: [...] }`
230
+ (shorthand for `args.file_path`). `"*"` as the tool is legal only in a
231
+ forbid list. Globs match dot-segments (`secrets/**` covers `secrets/.env`).
232
+ - **Skills** are governed by **slug**, never path. Enabling a bundle makes
233
+ `skills/<slug>/**` readable and its scripts runnable with no `tools.allow`
234
+ entry; a disabled bundle is unreachable **and invisible** (not listed, not
235
+ in the prompt). `allow` adds, `forbid` subtracts, `allow: []` denies
236
+ nothing. A `tools.allow` entry may still narrow *within* an enabled bundle.
237
+ A state enabling no skill can run no script at all.
238
+ - **Scripts' `tools.*` calls** are governed per call: an `archmax_run` script
239
+ is bound like the model (grant every tool it calls); a hook is exempt from
240
+ the state's lists. Neither may read `workflows/**` or write a mount. A
241
+ refused call throws inside the script.
@@ -0,0 +1,232 @@
1
+ import type { BaseMessage } from "@langchain/core/messages";
2
+ import { BaseChatModel } from "@langchain/core/language_models/chat_models";
3
+ import type { BaseChatModelCallOptions } from "@langchain/core/language_models/chat_models";
4
+ import type { ChatResult } from "@langchain/core/outputs";
5
+ import { type Agent, type CreateAgentParams, type GovernedAgent, type SessionStore, type WorkflowLifecycleEvent } from "../index.js";
6
+ /** Token usage a scripted reply may report, so `model-usage` events are testable. */
7
+ export interface ScriptedUsage {
8
+ input: number;
9
+ output: number;
10
+ }
11
+ /**
12
+ * The model id a scripted response echoes back in `response_metadata`. Omitted,
13
+ * the response names no model — which is the ordinary case behind an
14
+ * OpenAI-compatible proxy, and the one that used to cost a call its price.
15
+ */
16
+ export type ScriptedModelName = string;
17
+ /** One scripted model turn. */
18
+ export type ScriptedTurn =
19
+ /** A single tool call. */
20
+ {
21
+ tool: string;
22
+ args: Record<string, unknown>;
23
+ usage?: ScriptedUsage;
24
+ reports?: ScriptedModelName;
25
+ }
26
+ /** Several tool calls issued in one assistant message (a tool batch). */
27
+ | {
28
+ batch: Array<{
29
+ tool: string;
30
+ args: Record<string, unknown>;
31
+ }>;
32
+ usage?: ScriptedUsage;
33
+ reports?: ScriptedModelName;
34
+ }
35
+ /** A final text reply, ending the turn. */
36
+ | {
37
+ reply: string;
38
+ usage?: ScriptedUsage;
39
+ reports?: ScriptedModelName;
40
+ };
41
+ /** A tool call the scripted model issued, as recorded. */
42
+ export interface IssuedCall {
43
+ name: string;
44
+ args: Record<string, unknown>;
45
+ }
46
+ /** One model invocation as the fake observed it. */
47
+ export interface ModelCall {
48
+ /** Tool names bound for this call (from the most recent `bindTools`). */
49
+ tools: string[];
50
+ /** The system prompt text, when one was present. */
51
+ systemPrompt: string;
52
+ /** Kinds of the messages the model was shown (`system`, `human`, `ai`, `tool`). */
53
+ messageTypes: string[];
54
+ }
55
+ /**
56
+ * A model that replays a fixed script of turns. `bindTools` returns the same
57
+ * instance so the cursor is shared across every binding the agent performs —
58
+ * the script is the run's plan, not one binding's. When the script runs out the
59
+ * model replies with a final `done`, so every turn terminates.
60
+ */
61
+ export declare class ScriptedModel extends BaseChatModel<BaseChatModelCallOptions> {
62
+ private readonly turns;
63
+ private cursor;
64
+ private lastBound;
65
+ private seq;
66
+ /** Tool calls the script actually issued, in order. */
67
+ readonly issued: IssuedCall[];
68
+ /** Every model invocation, in order. */
69
+ readonly calls: ModelCall[];
70
+ /** What to say when the script is exhausted. */
71
+ readonly fallbackReply: string;
72
+ /**
73
+ * The id this model was configured to run, as a real client exposes it — what
74
+ * `modelIdOf` reads and what the runtime prices against when a response names
75
+ * no model. Left undefined by default so an existing case is unchanged.
76
+ */
77
+ readonly model?: string;
78
+ constructor(turns: ScriptedTurn[], opts?: {
79
+ fallbackReply?: string;
80
+ name?: string;
81
+ model?: string;
82
+ });
83
+ _llmType(): string;
84
+ /** How many scripted turns are still unplayed. */
85
+ get remaining(): number;
86
+ /** Append turns to the script — for a later conversational turn on the same agent. */
87
+ enqueue(...turns: ScriptedTurn[]): void;
88
+ bindTools(tools: unknown[]): BaseChatModel;
89
+ _generate(messages: BaseMessage[]): Promise<ChatResult>;
90
+ }
91
+ /**
92
+ * Write an authored workspace into a fresh temp directory. Values are file
93
+ * contents; a non-string value is serialized as YAML (handy for `workflow.yaml`
94
+ * declared as an object). Returns the root path.
95
+ */
96
+ export declare function makeWorkspace(files: Record<string, string | object>): string;
97
+ /** Remove every workspace {@link makeWorkspace} created. Call from `afterEach`. */
98
+ export declare function cleanupWorkspaces(): void;
99
+ /** A `SKILL.md` body with the frontmatter the skill loader requires. */
100
+ export declare function skillMarkdown(name: string, description?: string): string;
101
+ /**
102
+ * One inline rubric, as the value of a `{ rubric: … }` hook. A rubric is
103
+ * declared on the hook that applies it, so a fixture builds the declaration and
104
+ * drops it straight into a state's `before`/`after`.
105
+ */
106
+ export declare function rubricDeclaration(opts?: {
107
+ maxIterations?: number;
108
+ model?: string;
109
+ instructions?: string;
110
+ metadata?: unknown;
111
+ }): Record<string, unknown>;
112
+ /** The default persona file every workspace here carries. */
113
+ export declare const AGENTS_MD = "# Agent\n\nDo what the workflow says.\n";
114
+ export interface AssembleOptions {
115
+ /** Workflow slug; defaults to `w`. */
116
+ workflow?: string;
117
+ /** The agent model's script. Ignored when `model` is supplied. */
118
+ turns?: ScriptedTurn[];
119
+ /** A prebuilt model (e.g. to share across two assemblies). */
120
+ model?: ScriptedModel;
121
+ /** A second scripted model for the `rubric` role (grading rubrics). */
122
+ rubricModel?: ScriptedModel | JudgeModel;
123
+ /**
124
+ * Supplies the model per role and requested id, for a workflow that declares
125
+ * models. Supplied, it replaces the explicit `model` — which would outrank
126
+ * every declared id — so the ids the spec names actually resolve.
127
+ */
128
+ modelFactory?: CreateAgentParams["modelFactory"];
129
+ /** The session store; defaults to a fresh memory store. */
130
+ store?: SessionStore;
131
+ /** Extra `createAgent` parameters merged in last. */
132
+ params?: Partial<CreateAgentParams>;
133
+ }
134
+ export interface Assembled {
135
+ agent: GovernedAgent;
136
+ model: ScriptedModel;
137
+ events: WorkflowLifecycleEvent[];
138
+ store: SessionStore;
139
+ root: string;
140
+ }
141
+ /** Assemble a governed agent over `root` with an event sink and memory storage. */
142
+ export declare function assemble(root: string, opts?: AssembleOptions): Promise<Assembled>;
143
+ export interface TurnOutcome {
144
+ /** The settled turn result's message list. */
145
+ messages: unknown[];
146
+ /** The last assistant message carrying text, as a person would read it. */
147
+ reply: string;
148
+ }
149
+ /** Drive one conversational turn on `sessionId`. */
150
+ export declare function turn(agent: Agent, sessionId: string, text: string, opts?: {
151
+ trigger?: {
152
+ id: string;
153
+ };
154
+ }): Promise<TurnOutcome>;
155
+ /** The final assistant message carrying text, skipping tool results. */
156
+ export declare function lastAgentText(messages: unknown[]): string;
157
+ /** The type of a message (`ai`, `human`, `tool`, `system`), read across shapes. */
158
+ export declare function messageType(message: unknown): string;
159
+ /** Tool results in a transcript: `{ name, content, status }`. */
160
+ export declare function toolResults(messages: unknown[]): Array<{
161
+ name: string;
162
+ content: string;
163
+ status?: string;
164
+ }>;
165
+ /** Events of one type, narrowed. */
166
+ export declare function eventsOf<T extends WorkflowLifecycleEvent["type"]>(events: WorkflowLifecycleEvent[], type: T): Array<Extract<WorkflowLifecycleEvent, {
167
+ type: T;
168
+ }>>;
169
+ /** The states entered, in order. */
170
+ export declare function statesEntered(events: WorkflowLifecycleEvent[]): string[];
171
+ /** The agent-driven transitions (`from -> to`), in order — the opening arrival excluded. */
172
+ export declare function advances(events: WorkflowLifecycleEvent[]): Array<{
173
+ from: string;
174
+ to: string;
175
+ reason?: string;
176
+ }>;
177
+ /** Names of the tools governance refused, in order. */
178
+ export declare function blockedTools(events: WorkflowLifecycleEvent[]): string[];
179
+ /** Events emitted for one session only. */
180
+ export declare function forSession(events: WorkflowLifecycleEvent[], sessionId: string): WorkflowLifecycleEvent[];
181
+ /**
182
+ * A two-state linear machine: `start` (manual) → `done` (terminal), with the
183
+ * runtime contract pinned. Extra keys are merged into the spec root.
184
+ */
185
+ export declare function linearSpec(extra?: Record<string, unknown>): Record<string, unknown>;
186
+ /** The scripted turn that advances `to` with a reason. */
187
+ export declare function advanceTo(to: string, reason?: string): ScriptedTurn;
188
+ /** A workspace with a persona and one workflow spec under `workflows/w/`. */
189
+ export declare function workspaceWith(spec: Record<string, unknown>, extraFiles?: Record<string, string | object>): string;
190
+ /** A lifecycle judge's answer. */
191
+ export interface JudgeVerdict {
192
+ verdict: "ok" | "correct" | "veto";
193
+ reason: string;
194
+ }
195
+ /**
196
+ * A fake model for the `rubric` role that answers each dispatch with the next
197
+ * scripted verdict. When the framework binds a structured-output tool
198
+ * (`extract-*`) it is called with the verdict; otherwise the verdict is the reply
199
+ * text as JSON — both reach the lifecycle runner as a parseable verdict.
200
+ */
201
+ export declare class JudgeModel extends BaseChatModel<BaseChatModelCallOptions> {
202
+ private readonly verdicts;
203
+ private readonly fallback;
204
+ /**
205
+ * Fail every dispatch instead of answering — how an unusable `model` id
206
+ * surfaces, since a bad id is refused at invocation, not construction.
207
+ */
208
+ private readonly failWith?;
209
+ private cursor;
210
+ private lastBound;
211
+ private seq;
212
+ /** How many times the judge was asked. */
213
+ get dispatches(): number;
214
+ private calls;
215
+ constructor(verdicts: JudgeVerdict[], fallback?: JudgeVerdict,
216
+ /**
217
+ * Fail every dispatch instead of answering — how an unusable `model` id
218
+ * surfaces, since a bad id is refused at invocation, not construction.
219
+ */
220
+ failWith?: string | undefined);
221
+ _llmType(): string;
222
+ bindTools(tools: unknown[]): BaseChatModel;
223
+ _generate(): Promise<ChatResult>;
224
+ }
225
+ /** Read one file from a session store by store-relative path, or `undefined`. */
226
+ export declare function storeFile(store: SessionStore, path: string): Promise<string | undefined>;
227
+ /**
228
+ * A session id no other test in this process has used. Sandbox REPL sessions
229
+ * and other per-session resources are keyed by session id for the life of the
230
+ * process, so tests that run hooks or scripts must not share one.
231
+ */
232
+ export declare function freshSessionId(prefix?: string): string;