@archmax-ai/harness 0.6.1 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +2 -2
  2. package/dist/assembly/compose.js +0 -1
  3. package/dist/assembly/compose.js.map +1 -1
  4. package/dist/authoring-skill/archmax-harness/references/backend-integration.md +6 -0
  5. package/dist/authoring-skill/archmax-harness/references/hook-and-test-scripts.md +23 -4
  6. package/dist/authoring-skill/archmax-harness/references/hooks-and-scripts.md +4 -1
  7. package/dist/authoring-skill/archmax-harness/references/workflow-schema.md +51 -21
  8. package/dist/authoring-skill/archmax-harness/references/workflow-yaml.md +11 -7
  9. package/dist/kernel/kernel.d.ts +9 -6
  10. package/dist/kernel/kernel.js +80 -14
  11. package/dist/kernel/kernel.js.map +1 -1
  12. package/dist/lifecycle/runner.d.ts +6 -0
  13. package/dist/lifecycle/runner.js +1 -0
  14. package/dist/lifecycle/runner.js.map +1 -1
  15. package/dist/machine/machine.d.ts +22 -0
  16. package/dist/machine/machine.js +42 -5
  17. package/dist/machine/machine.js.map +1 -1
  18. package/dist/sandbox/executor.d.ts +5 -0
  19. package/dist/sandbox/executor.js +17 -5
  20. package/dist/sandbox/executor.js.map +1 -1
  21. package/dist/sandbox/prelude.js +20 -7
  22. package/dist/sandbox/prelude.js.map +1 -1
  23. package/dist/sandbox/runtime.d.ts +15 -2
  24. package/dist/sandbox/runtime.js +180 -23
  25. package/dist/sandbox/runtime.js.map +1 -1
  26. package/dist/sandbox/tools.js +3 -0
  27. package/dist/sandbox/tools.js.map +1 -1
  28. package/dist/workflow/file-values.d.ts +8 -10
  29. package/dist/workflow/file-values.js +4 -5
  30. package/dist/workflow/file-values.js.map +1 -1
  31. package/dist/workflow/governance.d.ts +1 -1
  32. package/dist/workflow/governance.js +3 -2
  33. package/dist/workflow/governance.js.map +1 -1
  34. package/dist/workflow/middleware.js +1 -2
  35. package/dist/workflow/middleware.js.map +1 -1
  36. package/dist/workflow/parks.js +6 -2
  37. package/dist/workflow/parks.js.map +1 -1
  38. package/dist/workflow/render-prompt.js +12 -4
  39. package/dist/workflow/render-prompt.js.map +1 -1
  40. package/dist/workflow/sub-workflow.js +8 -7
  41. package/dist/workflow/sub-workflow.js.map +1 -1
  42. package/dist/workflow/tool-service.d.ts +1 -1
  43. package/dist/workflow/tool-service.js +7 -1
  44. package/dist/workflow/tool-service.js.map +1 -1
  45. package/dist/workflow/turn-boundary.js +22 -6
  46. package/dist/workflow/turn-boundary.js.map +1 -1
  47. package/dist/workflow/workflow-tools.js +1 -1
  48. package/dist/workflow/workflow-tools.js.map +1 -1
  49. package/package.json +1 -1
  50. package/skills/archmax-harness/references/backend-integration.md +6 -0
  51. package/skills/archmax-harness/references/hook-and-test-scripts.md +23 -4
  52. package/skills/archmax-harness/references/hooks-and-scripts.md +4 -1
  53. package/skills/archmax-harness/references/workflow-schema.md +51 -21
  54. package/skills/archmax-harness/references/workflow-yaml.md +11 -7
@@ -206,7 +206,8 @@ mounts?:
206
206
  # validate ERRORS on a name the table does not mount.
207
207
  forbid_always?: string[] # MOUNT NAMES out of reach of EVERY state, governed or
208
208
  # not, whatever any list grants. Deny beats allow.
209
- # Inherited by every sub-workflow, naming the workflow
209
+ # Binds this workflow's own HOOKS too, and is
210
+ # inherited by every sub-workflow, naming the workflow
210
211
  # that declared it. A NAME only — a denial is total, so
211
212
  # there is no `access` to qualify. (A root `mounts.allow`
212
213
  # is a load error: one mounts model.)
@@ -391,7 +392,11 @@ states:
391
392
  # volatile prompt block, and filtered out of every
392
393
  # ls/glob/grep result, the WORKSPACE ROOT LISTING
393
394
  # included. Lifecycle HOOKS are exempt from this key
394
- # (runtime authority), but not from `forbid_always`.
395
+ # (runtime authority), but not from `forbid_always`
396
+ # nor from the WORKFLOW's grants: a hook reaches a
397
+ # governed mount only if allow_always or SOME state's
398
+ # allow names it, in any state, and writes it only
399
+ # where a grant of the workflow asks `read_write`.
395
400
 
396
401
  model?: string # MODEL ID ONLY — this state's turns run on it (and the
397
402
  # handoff message of a park it holds). Most specific of
@@ -542,12 +547,18 @@ states:
542
547
  - `requires:` / `returns:` are the run's **signature**, and both are enforced. A
543
548
  firing that does not supply every `requires` name does not start. `returns`
544
549
  is checked once as the run finishes, and **nothing is handed back**: a
545
- sub-workflow child with a name unset **completes**, and its caller gets the
546
- returns it set plus `note: "Not all return variables were set by the
547
- sub-workflow: '<name>' was not set."`; a top-level run with a name unset is
548
- **rejected**; a typed one mistyped rejects either way. A run that *parks* is
549
- not checked — it has not finished. `note` is reserved: a `returns` list may
550
- not declare it. Want the model to try again? Check the returns in a terminal
550
+ sub-workflow child with a name unset **completes**, and its caller gets
551
+ every declared return, the unset ones `null`, plus `note: "Not all return
552
+ variables were set by the sub-workflow: '<name>' was not set."`; a top-level
553
+ run with a name unset is **rejected**; a typed one mistyped rejects either
554
+ way. A run that *parks* is not checked — it has not finished. A return is
555
+ owed **only at the finish**: `archmax_advance` checks a state's own
556
+ `requires:`, never the returns, a later write replaces an unlocked earlier
557
+ one, and a seed of one (a name in both lists) lands **unlocked** and does not
558
+ overwrite a value the session already holds. So do not list a return in a
559
+ state's `requires:` unless that state must settle it, and do not tell the
560
+ agent to lock one before its value is final. `note` is reserved: a `returns`
561
+ list may not declare it. Want the model to try again? Check the returns in a terminal
551
562
  `after` hook, which can `correct`. Each entry is a bare
552
563
  run-variable name (**untyped**: any value, `null` included) or a strict object
553
564
  `{ name, type?, description? }` naming one; the spellings mix in one list and
@@ -577,8 +588,10 @@ states:
577
588
  completion and at a delegation call the runtime also requires a **file** (not a
578
589
  folder) at the path that the session may read **on runtime authority** — the
579
590
  rules a hook is bound by: zone rules (`checkpoints/`, `artifacts/`, `_specs/`
580
- never) and every workflow-wide `forbid_always`, inherited ones included; the
581
- state's allow list and mount/skill grants do not narrow it. So tell the agent to
591
+ never), the workflow's mount grants taken across all its states (a governed
592
+ mount no state is granted is out of reach), and every workflow-wide
593
+ `forbid_always`, inherited ones included; the state's allow list and its own
594
+ mount/skill grants do not narrow it. So tell the agent to
582
595
  write the file *before* it sets a `file` return: `archmax_set_variables` refuses
583
596
  a path with nothing there. A host hands a file in with `TurnInput.files` (CLI:
584
597
  `archmax run … --file invoice=./invoice.pdf`), which places it under
@@ -774,7 +787,8 @@ workflow's grant, the state's own `allow` and the always-on surface alike.
774
787
  **Deny beats allow, and no narrower level widens a denial.** A forbid entry may
775
788
  name the tool `*` (every tool); `*` in an allow list is a load error. A lifecycle
776
789
  hook is exempt from the state's `allow` **and** its `forbid` — runtime authority,
777
- outside that surface both ways — but never from `forbid_always`.
790
+ outside that surface both ways — but never from `forbid_always` (the workflow's
791
+ own `tools.`, `skills.` and `mounts.forbid_always`, and every ancestor's).
778
792
 
779
793
  Precedence (highest first):
780
794
 
@@ -873,7 +887,8 @@ capability workflow-wide.
873
887
  Hooks are **exempt**: a `before`/`after` script reads authored data on runtime
874
888
  authority, so a state may enable nothing and still be gated by a hook that reads
875
889
  the very bundle the model cannot. That is the shape to reach for when a capability
876
- should *enforce* something without being *usable*.
890
+ should *enforce* something without being *usable*. A bundle the workflow's
891
+ `skills.forbid_always` denies is refused to its hooks too.
877
892
 
878
893
  **`tools.forbid` on a state denies there**, and `tools.forbid_always` at the
879
894
  root denies everywhere. Both beat every grant. Migrating a workflow off the
@@ -1015,7 +1030,18 @@ so `AGENTS.md.bak` is not captured.
1015
1030
 
1016
1031
  Hooks and rubric graders are bound by `mounts.forbid_always` and **not** by a
1017
1032
  state's `forbid` or its enabled set: they run on runtime authority, exactly as for
1018
- tools, so a `before` hook can read a mount the model in that state cannot.
1033
+ tools, so a `before` hook can read a mount the model in that state cannot. A hook
1034
+ is still held to its **workflow's** grants, taken across every state:
1035
+
1036
+ - it reads a governed mount only if `allow_always` or some state's `allow` names
1037
+ it, else `mount.not-allowed`. The table serves every child too, so it can hold a
1038
+ mount only a child grants, and the caller's hooks cannot reach that;
1039
+ - it writes one only where a grant of the workflow asks `access: read_write`, and an
1040
+ `access: read` in `allow_always` narrows any mount for it (`mount.read-only`).
1041
+
1042
+ So when a hook needs a mount no state's model should see, grant it in a state the
1043
+ hook's workflow has anyway, or in `allow_always` with the model's states
1044
+ forbidding it.
1019
1045
 
1020
1046
  ## Session variables in guards
1021
1047
 
@@ -1083,7 +1109,8 @@ scalar.
1083
1109
  **Authoring rules that matter:**
1084
1110
 
1085
1111
  - **Lock anything a guard reads.** Host seeds are locked automatically (`title`
1086
- excepted, which is never locked); for an agent-established fact pass `lock: true`. An unlocked variable can be
1112
+ and a seed of a trigger's `returns` excepted, which land unlocked); for an
1113
+ agent-established fact pass `lock: true` — on a return, only once it is final. An unlocked variable can be
1087
1114
  overwritten by any later state — that rewrite is permitted, being one writer
1088
1115
  twice, and the later value simply wins — so a guard bound to an unlocked name is
1089
1116
  a weak guard. A lock is the only thing that makes a fact settled.
@@ -1358,7 +1385,7 @@ enrich:
1358
1385
  (`unresolved-param`) and **disabled-target** refusals are blocked calls —
1359
1386
  nothing ran, so correct the call and retry. A child whose returns are
1360
1387
  mistyped (`invalid-return`) is a failure: it ran. One that left returns unset
1361
- is not: the call answers with what it set and a `note`.
1388
+ is not: the call answers with them `null` and a `note`.
1362
1389
  - **A whole-argument reference keeps its type.** `{ quantity: "${{count}}" }`
1363
1390
  seeds the child with the number `count` holds, so it satisfies an `integer`
1364
1391
  parameter; `{ note: "order ${{order_id}}" }` is substituted as text.
@@ -1396,16 +1423,18 @@ enrich:
1396
1423
 
1397
1424
  A dispatch missing a `requires` name is **refused before the child is
1398
1425
  composed**; a child that completes without every `returns` name set
1399
- **completes anyway**, and the call answers with the returns it set plus a
1400
- `note` naming the rest — no second attempt is spent, and the caller decides
1426
+ **completes anyway**, and the call answers with every declared return, the
1427
+ unset ones `null`, plus a `note` naming them — no second attempt is spent, and
1428
+ the caller decides
1401
1429
  (a child that *parks* is not checked — it has not finished; a child that
1402
1430
  raises fails the call `raised`). A typed entry is held to its type at both
1403
1431
  ends: a mistyped argument is refused `invalid-param` before the child runs, and
1404
1432
  a mistyped return fails the call `invalid-return`. What the child must *do* to
1405
1433
  produce a variable belongs in the state `instructions` that set it. The names,
1406
1434
  with type and description where declared, are rendered into the child's prompt
1407
- under its entry state, so it is told what to produce before it can be failed
1408
- for omitting it.
1435
+ in every state, so it is told what to produce before it can be failed for
1436
+ omitting it — and to set each once its final value is known, locking one only
1437
+ when it is final.
1409
1438
  - **The call answers with the returns, by name.** A signed target answers
1410
1439
  `{ message, returns: { enrichment_file, delayed } }`; one declaring no
1411
1440
  `returns:` answers with the closing message alone. The message keeps its own
@@ -1416,7 +1445,7 @@ enrich:
1416
1445
  - **Mocks are held to the same contract.** An `archmax_workflow_<slug>` mock for a
1417
1446
  signed target supplies `returns:`. One that supplies a mistyped typed one
1418
1447
  (`invalid-return`) fails the mocked dispatch, and one that omits a declared
1419
- name answers like a real child that left it unset: what it supplied, plus a
1448
+ name answers like a real child that left it unset: that name `null`, plus a
1420
1449
  `note` — a mock stands in for the sub-run, never for its agreement.
1421
1450
  - **No prose crosses the boundary.** A sub-run gets no instruction from its
1422
1451
  caller — it works from its own state `instructions` (system prompt) plus the
@@ -1499,7 +1528,8 @@ triggers:
1499
1528
  repeated or parallel calls never overwrite each other or the caller's files. A
1500
1529
  return whose file is gone at completion fails the call `invalid-return`.
1501
1530
  - **No laundering.** A `file` value must name a file the session may read on
1502
- runtime authority, and a child inherits every ancestor's `forbid_always`. So a
1531
+ runtime authority (its own workflow's mount grants and `forbid_always`), and a
1532
+ child inherits every ancestor's `forbid_always`. So a
1503
1533
  child cannot hand back a file its caller's workflow denies: its agent's write
1504
1534
  is refused, and a script's write is rejected at completion.
1505
1535
  - **Instructions to write.** Tell the child to write the file *first* and then set
@@ -170,9 +170,9 @@ states:
170
170
  the agent back with the reason, bounded per hook by `max_iterations`
171
171
  (default 0 → a correct is a hard veto). A list runs in order and stops at
172
172
  the first non-ok. Errors and missing files veto (fail-closed). Hooks run
173
- on runtime authority: the state's `allow`/`forbid`/`skills` do not bind
174
- them; `forbid_always` and safety rules do. Human states may not declare
175
- hooks.
173
+ on runtime authority: the state's `allow`/`forbid`/`skills`/`mounts` do not
174
+ bind them; `forbid_always`, safety rules and the workflow's mount grants
175
+ (any state's) do. Human states may not declare hooks.
176
176
  - **Budgets and `on_error`.** `budget.maxTurns`/`timeoutMs`/`maxParks` bound
177
177
  a state's segment. A terminal failure (hook execution error, exhausted
178
178
  corrections, exhausted budget, exhausted parks) routes to `on_error`
@@ -188,8 +188,11 @@ states:
188
188
  mistyped argument is refused `invalid-param`, and `"${{count}}"` alone
189
189
  passes the value with its own type), its `returns` the result
190
190
  (`{ message, returns }`; a child finishing with some unset completes, and
191
- `returns` holds what it set plus a `note` naming the rest; a mistyped typed
192
- return fails `invalid-return`). Each failed call is the
191
+ `returns` holds every declared one, the unset ones `null`, plus a `note`
192
+ naming them; a mistyped typed return fails `invalid-return`). Returns are
193
+ owed only at the finish: no state needs them to be left, a later write
194
+ replaces an unlocked earlier one, and a seed of one lands unlocked; lock one
195
+ only once it is final. Each failed call is the
193
196
  calling state's failure, recorded with its arguments and routed through
194
197
  `on_error` when the agent finishes unless a later successful call of the
195
198
  same workflow from the same state recovers it first. One success recovers
@@ -276,5 +279,6 @@ Closed by default; **deny beats allow, and no narrower level widens a denial.**
276
279
  A state enabling no skill can run no script at all.
277
280
  - **Scripts' `tools.*` calls** are governed per call: an `archmax_run` script
278
281
  is bound like the model (grant every tool it calls); a hook is exempt from
279
- the state's lists. Neither may read `workflows/**` or write a mount. A
280
- refused call throws inside the script.
282
+ the state's lists but held to its workflow's mount grants. Neither may read
283
+ `workflows/**` or write a read-only mount. A refused call throws inside the
284
+ script.