@parcha/agentrun-pi 0.1.0-beta.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 (45) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +2 -0
  3. package/README.md +209 -0
  4. package/dist/admission.d.ts +6 -0
  5. package/dist/admission.js +51 -0
  6. package/dist/author.d.ts +21 -0
  7. package/dist/author.js +72 -0
  8. package/dist/cli.d.ts +2 -0
  9. package/dist/cli.js +68 -0
  10. package/dist/demo-data.d.ts +361 -0
  11. package/dist/demo-data.js +386 -0
  12. package/dist/demo.d.ts +13 -0
  13. package/dist/demo.js +44 -0
  14. package/dist/extension-service.d.ts +110 -0
  15. package/dist/extension-service.js +477 -0
  16. package/dist/extension.d.ts +41 -0
  17. package/dist/extension.js +419 -0
  18. package/dist/host-session.d.ts +5 -0
  19. package/dist/host-session.js +80 -0
  20. package/dist/index.d.ts +6 -0
  21. package/dist/index.js +6 -0
  22. package/dist/presentation.d.ts +4 -0
  23. package/dist/presentation.js +34 -0
  24. package/dist/runner.d.ts +12 -0
  25. package/dist/runner.js +256 -0
  26. package/dist/skill-bundle.d.ts +5 -0
  27. package/dist/skill-bundle.js +15 -0
  28. package/dist/tool-input-error.d.ts +10 -0
  29. package/dist/tool-input-error.js +40 -0
  30. package/dist/types.d.ts +119 -0
  31. package/dist/types.js +1 -0
  32. package/package.json +73 -0
  33. package/skills/author/SKILL.md +102 -0
  34. package/skills/author/examples/evidence-gate.input.json +6 -0
  35. package/skills/author/examples/evidence-gate.json +125 -0
  36. package/skills/author/examples/read-file.input.json +1 -0
  37. package/skills/author/examples/read-file.json +44 -0
  38. package/skills/author/examples/read-source-decision.input.json +4 -0
  39. package/skills/author/examples/read-source-decision.json +37 -0
  40. package/skills/author/examples/release-note.txt +10 -0
  41. package/skills/author/examples/review-release-notes.input.json +6 -0
  42. package/skills/author/examples/review-release-notes.json +123 -0
  43. package/skills/author/references/jev-decisions.md +112 -0
  44. package/skills/author/references/sdk-authoring.md +16 -0
  45. package/skills/author/references/workflow-format.md +145 -0
@@ -0,0 +1,125 @@
1
+ {
2
+ "v": 2,
3
+ "name": "fictional-evidence-gate",
4
+ "schemas": {
5
+ "Record": {
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": [
9
+ "claim",
10
+ "evidence"
11
+ ],
12
+ "properties": {
13
+ "claim": {
14
+ "type": "string"
15
+ },
16
+ "evidence": {
17
+ "type": "string"
18
+ }
19
+ }
20
+ },
21
+ "Input": {
22
+ "type": "object",
23
+ "additionalProperties": false,
24
+ "required": [
25
+ "record"
26
+ ],
27
+ "properties": {
28
+ "record": {
29
+ "$ref": "#/definitions/Record"
30
+ }
31
+ }
32
+ },
33
+ "Questions": {
34
+ "type": "object",
35
+ "additionalProperties": false,
36
+ "required": [
37
+ "supported"
38
+ ],
39
+ "properties": {
40
+ "supported": {
41
+ "type": "boolean",
42
+ "description": "Does the supplied evidence explicitly support every factual detail in the claim, without adding assumptions or contradicting it?"
43
+ }
44
+ }
45
+ },
46
+ "Gate": {
47
+ "type": "object",
48
+ "additionalProperties": false,
49
+ "required": [
50
+ "accepted"
51
+ ],
52
+ "properties": {
53
+ "accepted": {
54
+ "type": "boolean"
55
+ }
56
+ }
57
+ },
58
+ "Result": {
59
+ "type": "object",
60
+ "additionalProperties": false,
61
+ "required": [
62
+ "record",
63
+ "accepted"
64
+ ],
65
+ "properties": {
66
+ "record": {
67
+ "$ref": "#/definitions/Record"
68
+ },
69
+ "accepted": {
70
+ "type": "boolean"
71
+ }
72
+ }
73
+ }
74
+ },
75
+ "input": {
76
+ "schemaId": "Input"
77
+ },
78
+ "output": {
79
+ "schemaId": "Result",
80
+ "path": "result"
81
+ },
82
+ "root": {
83
+ "node": "chain",
84
+ "steps": [
85
+ {
86
+ "node": "code",
87
+ "label": "retain-record",
88
+ "code": "(s) => ({ original: s.record })"
89
+ },
90
+ {
91
+ "node": "judge",
92
+ "label": "check-evidence",
93
+ "state": {
94
+ "record": "{original}"
95
+ },
96
+ "out": "Questions",
97
+ "as": "check"
98
+ },
99
+ {
100
+ "node": "code",
101
+ "label": "probability-gate",
102
+ "code": "(s) => { const p = s['check$answers']?.answers?.supported?.noul; return { accepted: typeof p === 'number' && Number.isFinite(p) && p >= 0.90 && p <= 1 }; }",
103
+ "as": "gate"
104
+ },
105
+ {
106
+ "node": "escalate",
107
+ "label": "request-better-evidence",
108
+ "when": {
109
+ "predicate": "field_equals",
110
+ "path": "gate.accepted",
111
+ "value": false
112
+ },
113
+ "kind": "needs_evidence",
114
+ "stage": "verification",
115
+ "summary": "Evidence did not meet the required yes-probability threshold."
116
+ },
117
+ {
118
+ "node": "code",
119
+ "label": "assemble-result",
120
+ "code": "(s) => ({ record: s.original, accepted: s.gate.accepted })",
121
+ "as": "result"
122
+ }
123
+ ]
124
+ }
125
+ }
@@ -0,0 +1 @@
1
+ { "path": "README.md" }
@@ -0,0 +1,44 @@
1
+ {
2
+ "v": 2,
3
+ "name": "read-file",
4
+ "schemas": {
5
+ "Input": {
6
+ "type": "object",
7
+ "properties": { "path": { "type": "string", "minLength": 1 } },
8
+ "required": ["path"],
9
+ "additionalProperties": false
10
+ },
11
+ "ToolResult": {
12
+ "type": "object",
13
+ "properties": {
14
+ "content": {
15
+ "type": "array",
16
+ "items": {
17
+ "type": "object",
18
+ "properties": {
19
+ "type": { "type": "string", "enum": ["text", "image"] },
20
+ "text": { "type": "string" },
21
+ "data": { "type": "string" },
22
+ "mimeType": { "type": "string" }
23
+ },
24
+ "required": ["type"]
25
+ }
26
+ },
27
+ "details": {}
28
+ },
29
+ "required": ["content"]
30
+ }
31
+ },
32
+ "input": { "schemaId": "Input" },
33
+ "output": { "schemaId": "ToolResult", "path": "file" },
34
+ "root": {
35
+ "node": "call",
36
+ "label": "read-file",
37
+ "via": "tool",
38
+ "tool": "read",
39
+ "args": { "path": "{path}" },
40
+ "out": "ToolResult",
41
+ "as": "file",
42
+ "deadline_s": 10
43
+ }
44
+ }
@@ -0,0 +1,4 @@
1
+ {
2
+ "question": "Does the source announce a required client migration for the current release rather than a proposal?",
3
+ "paths": ["release-note.txt"]
4
+ }
@@ -0,0 +1,37 @@
1
+ {
2
+ "v": 2,
3
+ "name": "fictional-read-source-decision",
4
+ "schemas": {
5
+ "Input": { "type": "object", "properties": {
6
+ "question": { "type": "string", "minLength": 1 },
7
+ "paths": { "type": "array", "items": { "type": "string", "minLength": 1 } }
8
+ }, "required": ["question", "paths"], "additionalProperties": false },
9
+ "ToolResult": { "type": "object", "properties": {
10
+ "content": { "type": "array", "items": { "type": "object", "properties": {
11
+ "type": { "const": "text" }, "text": { "type": "string" }
12
+ }, "required": ["type", "text"] } }, "details": {}
13
+ }, "required": ["content"] },
14
+ "Questions": { "type": "object", "properties": {
15
+ "matches": { "type": "boolean", "description": "Does the original source text satisfy the condition asked in question, taking account of its headings, scope and exclusions rather than keyword overlap?" }
16
+ }, "required": ["matches"], "additionalProperties": false },
17
+ "Results": { "type": "array", "items": { "type": "object", "properties": {
18
+ "path": { "type": "string" }, "source": { "$ref": "#/definitions/ToolResult" },
19
+ "probability": { "type": "number", "minimum": 0, "maximum": 1 }
20
+ }, "required": ["path", "source", "probability"], "additionalProperties": false } }
21
+ },
22
+ "input": { "schemaId": "Input" },
23
+ "output": { "schemaId": "Results", "path": "results" },
24
+ "root": {
25
+ "node": "map", "label": "read-and-judge-originals", "itemsPath": "paths", "maxConcurrency": 2,
26
+ "as": "results", "resultPath": "record",
27
+ "body": { "node": "chain", "steps": [
28
+ { "node": "call", "label": "read-original", "via": "tool", "tool": "read",
29
+ "args": { "path": "{item}" }, "out": "ToolResult", "as": "source", "deadline_s": 30 },
30
+ { "node": "judge", "label": "source-membership", "state": {
31
+ "question": "{question}", "source": "{source}"
32
+ }, "out": "Questions", "as": "decision" },
33
+ { "node": "code", "label": "retain-source-and-probability", "as": "record",
34
+ "code": "(s) => ({ path: s.item, source: s.source, probability: s['decision$answers'].answers.matches.noul })" }
35
+ ] }
36
+ }
37
+ }
@@ -0,0 +1,10 @@
1
+ FICTIONAL EXAMPLE — not a real product release
2
+
3
+ # Current release
4
+
5
+ Clients MUST send the X-Workspace header with their workspace slug.
6
+
7
+ # Future proposals — not approved
8
+
9
+ Changing the authentication mechanism remains a proposal. No authentication
10
+ migration is required by this release.
@@ -0,0 +1,6 @@
1
+ {
2
+ "notes": [
3
+ "Requests now require the X-Workspace header. Older clients must send X-Workspace with their workspace slug.",
4
+ "The legacy /events endpoint has been removed. Send event queries to /v2/events instead."
5
+ ]
6
+ }
@@ -0,0 +1,123 @@
1
+ {
2
+ "v": 2,
3
+ "name": "review-release-notes",
4
+ "schemas": {
5
+ "Input": {
6
+ "type": "object",
7
+ "properties": {
8
+ "notes": {
9
+ "type": "array",
10
+ "items": {
11
+ "type": "string",
12
+ "minLength": 1
13
+ },
14
+ "minItems": 1,
15
+ "maxItems": 5
16
+ }
17
+ },
18
+ "required": [
19
+ "notes"
20
+ ],
21
+ "additionalProperties": false
22
+ },
23
+ "Change": {
24
+ "type": "object",
25
+ "properties": {
26
+ "breakingChange": {
27
+ "type": "string",
28
+ "minLength": 1
29
+ },
30
+ "migrationAction": {
31
+ "type": "string",
32
+ "minLength": 1
33
+ }
34
+ },
35
+ "required": [
36
+ "breakingChange",
37
+ "migrationAction"
38
+ ],
39
+ "additionalProperties": false
40
+ },
41
+ "Report": {
42
+ "type": "object",
43
+ "properties": {
44
+ "summary": {
45
+ "type": "string",
46
+ "minLength": 1
47
+ },
48
+ "changes": {
49
+ "type": "array",
50
+ "items": {
51
+ "type": "object",
52
+ "properties": {
53
+ "breakingChange": {
54
+ "type": "string",
55
+ "minLength": 1
56
+ },
57
+ "migrationAction": {
58
+ "type": "string",
59
+ "minLength": 1
60
+ }
61
+ },
62
+ "required": [
63
+ "breakingChange",
64
+ "migrationAction"
65
+ ],
66
+ "additionalProperties": false
67
+ },
68
+ "minItems": 1
69
+ }
70
+ },
71
+ "required": [
72
+ "summary",
73
+ "changes"
74
+ ],
75
+ "additionalProperties": false
76
+ }
77
+ },
78
+ "input": {
79
+ "schemaId": "Input"
80
+ },
81
+ "output": {
82
+ "schemaId": "Report",
83
+ "path": "report"
84
+ },
85
+ "root": {
86
+ "node": "chain",
87
+ "steps": [
88
+ {
89
+ "node": "map",
90
+ "label": "extract-each-release-note",
91
+ "itemsPath": "notes",
92
+ "as": "changes",
93
+ "maxConcurrency": 2,
94
+ "body": {
95
+ "node": "extract",
96
+ "label": "extract-change",
97
+ "instructions": "Extract the breaking change and its migration action from the supplied release note. Preserve the exact header name and required action. Do not invent a migration step.",
98
+ "state": {
99
+ "text": "{item}"
100
+ },
101
+ "requires": [
102
+ "item"
103
+ ],
104
+ "out": "Change",
105
+ "as": "change"
106
+ }
107
+ },
108
+ {
109
+ "node": "extract",
110
+ "label": "summarize-migration",
111
+ "instructions": "Summarize these migration actions for a client maintainer. Return the supplied changes unchanged alongside the summary. Do not invent steps.",
112
+ "state": {
113
+ "changes": "{changes}"
114
+ },
115
+ "requires": [
116
+ "changes"
117
+ ],
118
+ "out": "Report",
119
+ "as": "report"
120
+ }
121
+ ]
122
+ }
123
+ }
@@ -0,0 +1,112 @@
1
+ # Design Jev decisions in AgentRun
2
+
3
+ Jev returns typed judgments and probabilities, not generated prose, tool calls or
4
+ multi-step research. The host supplies its adapter and credentials. Do not write
5
+ HTTP requests or SDK setup into workflow code. This guide maps the TypeSafe
6
+ programming model to the installed DSL; the general TypeSafe skill is optional.
7
+
8
+ ## Choose the boundary
9
+
10
+ Work backward from the action the result controls. Code handles exact lookups,
11
+ parsing, arithmetic, joins, grouping and constraints. An agent handles open-ended
12
+ research or generation. Jev can select relevant evidence, interpret a boundary,
13
+ compare a claim to its source or choose among known actions. It need not be a
14
+ final approval stage, and a workflow without a semantic decision need not use it.
15
+
16
+ Ask one coherent judgment per property. Separate independently useful conditions;
17
+ keep related context together. Avoid asking whether a whole complex answer is
18
+ "correct" when no source supporting that answer is supplied. Question descriptions
19
+ must carry their meaning; property names alone are not instructions.
20
+
21
+ ## Construct the evidence, not another opinion
22
+
23
+ For source-grounded work, a useful pattern is:
24
+
25
+ 1. A tool or agent locates candidate references, retaining their identities.
26
+ 2. Direct tool calls fetch the original text at those references.
27
+ 3. Jev sees the question or full selection rule **and that original text**.
28
+ 4. Code uses the returned values; an agent may repair missing evidence or synthesize.
29
+
30
+ Keep source text separate from a candidate extraction, paraphrase or claim. An
31
+ agent's field named `quote`, `headerContext` or `verified` does not make it original
32
+ evidence. Re-read the cited source through the host tool when independent checking
33
+ matters. Include relevant headings, units, dates, neighboring rows, exclusions and
34
+ section boundaries. An exact quote match checks presence, not interpretation.
35
+
36
+ Judge only what the supplied context can establish. If a source is truncated,
37
+ follow its continuation when relevant; if it is missing, retrieve or surface the
38
+ gap. Do not silently substitute a summary to fit a size limit. Narrow or partition
39
+ large contexts at meaningful boundaries while retaining their qualifiers.
40
+ The adapter has no default byte ceiling. A host may explicitly configure
41
+ `maxStateBytes`; local size errors then report the measured UTF-8 JSON bytes and
42
+ that host's limit before any HTTP request is sent. Provider context limits are
43
+ separate and token-based, not a fixed bytes-to-tokens conversion. Jev 1.13's
44
+ documented contract, checked on 2026-09-22, allows 32k tokens for state plus the
45
+ longest question and 64k for state plus all questions combined; check the selected
46
+ model's current contract. Oversized provider requests remain
47
+ errors, not permission to truncate evidence or silently retry a different graph.
48
+
49
+ `sift` sends **all items together in one request**. Shared `state` is added to
50
+ that batch; it does not replace or narrow each item. `describe` adds an item
51
+ summary, but the full original item is still sent. A tool envelope can contain
52
+ the same text in both `content` and `details`, so character limits on individual
53
+ reads do not establish the final serialized size.
54
+
55
+ When judgments are independent, explicitly use `map` with a `judge` body for one
56
+ request per original. For records that already contain `document`, `page` and
57
+ `text`, a body can use `state: {rule: "{question}", original: "{item}"}`. For tool
58
+ envelopes, select the host's actual original-text and provenance fields instead
59
+ of sending duplicate representations. Retain the full reviewed rule, relevant
60
+ headers, units, dates, exclusions and neighboring rows. If an individual original
61
+ is still too large, retrieve or partition it at meaningful boundaries; do not
62
+ silently truncate it or replace it with an agent's interpretation. This explicit
63
+ graph change changes request count; no automatic batching or truncation occurs.
64
+
65
+ The fictional [read-source decision](../examples/read-source-decision.json) and
66
+ [input](../examples/read-source-decision.input.json) demonstrate direct `read`
67
+ results passed to Jev unchanged, followed by deterministic probability projection.
68
+ Its paths are inputs, not a built-in corpus. Place the bundled fictional
69
+ [release note](../examples/release-note.txt) at `release-note.txt` in the working
70
+ directory (or change the input path to its location) before running that input.
71
+ Adapt the tool and return schema to
72
+ `describe`; an agent locator can produce those paths earlier in the same graph.
73
+
74
+ ## Use the installed primitives
75
+
76
+ - `judge`: a flat output schema describes several independent questions over one
77
+ explicit `state` map. Boolean properties become yes-probabilities (Noul); enums
78
+ become Choice; integer properties with minimum 0, maximum N−1 and N described
79
+ levels in `criteria` (2–10 levels) become Score. Put the complete question in each
80
+ `description`.
81
+ - `sift`: ask questions about each candidate and retain originals. Pass shared task
82
+ context in `state`; each item also needs its own original evidence. Candidate
83
+ coverage matters: no judge can recover a source absent from the candidate set.
84
+ - `pick`: choose from known candidates, with `allowNone` when none may fit.
85
+ - `route`: choose a semantic branch. Its uncertainty gate concerns that new
86
+ decision, not an earlier judge's probability.
87
+
88
+ Batch independent questions over the same state. They cannot read each other's
89
+ answers. Use another step when a decision is needed to retrieve new evidence or
90
+ construct new state. Inspect the assembled state and questions, not just node names.
91
+
92
+ ## Consume uncertainty honestly
93
+
94
+ `judge` stores decoded values at its `as` key and raw answers at `<as>$answers`.
95
+ A boolean is true at yes-probability 0.5; to enforce another threshold, read the
96
+ raw `.answers.<property>.noul` number and compare in code. A Noul near 0.5 means
97
+ uncertainty between yes and no, not medium intensity. Choice/Score confidence is
98
+ distribution concentration, not proof that the workflow is right.
99
+
100
+ Use thresholds appropriate to the task, with an explicit missing/uncertain path.
101
+ An example threshold is not calibrated policy. Low probability can justify
102
+ exclusion, another retrieval, cheap-agent repair or escalation, depending on the
103
+ question. Do not reject an entire result just because an unused condition is
104
+ uncertain. Preserve raw decisions so these policies can be inspected separately.
105
+
106
+ Typed output proves an interface, not truth. Test source coverage, semantics and
107
+ the downstream action independently. A fake-judge fixture proves wiring only.
108
+
109
+ Maintained against TypeSafe's state, primitives/Noul, confidence and citation-check
110
+ documentation, reviewed 2026-09-22. Upstream reference locations:
111
+ `https://docs.typesafe.ai/concepts/state`, `https://docs.typesafe.ai/primitives`,
112
+ `https://docs.typesafe.ai/confidence`, `https://docs.typesafe.ai/cookbooks/citation_check`.
@@ -0,0 +1,16 @@
1
+ # Demo commands and standalone SDK
2
+
3
+ ## Demonstrations
4
+
5
+ `/agentrun demo` runs the interpreter with scripted responses over fictional sources. `/agentrun demo empty` exercises insufficient evidence. Neither makes model calls. `/agentrun demo live` uses real Pi agent calls and Jev system one decisions over the same fictional sources; TypeSafe access is required. It is still not web research.
6
+
7
+
8
+ ## SDK authoring only
9
+
10
+ Use this path when the host invokes `authorWorkflow` rather than the native `agentrun` tool. The SDK supplies a `submit` tool; deliver `{"value": workflow}` through it. Read validation and acceptance feedback, then repair within that session. The host retains each version and rejection. Acceptance does not activate or execute a replacement.
11
+
12
+ With `rubricSections`, every generated LLM node must reference every supplied section, including child workflows. This conservative author policy rejects Jev nodes, semantic `ask` predicates, and `verify` clauses until the host has a separately reviewed question contract. Execution must receive the same authoritative SOP text. A schema field named `node`, `verify`, or `predicate` is ordinary data, not a judgment clause.
13
+
14
+ Host-owned acceptance callbacks and fixtures remain outside generated workflows. Do not edit them to obtain a pass. Structural acceptance alone does not establish behavior. Keep request text, rubric text, candidates, and reviews in storage appropriate for their contents.
15
+
16
+ SDK configuration and file retention are not features the native author must reimplement. The installed Pi package README documents `authorWorkflow`, `createPiHostRunner`, and the separate CLI.
@@ -0,0 +1,145 @@
1
+ # Workflow format
2
+
3
+ AgentRun documents are JSON data: `v: 2`, `name`, `schemas`, optional `input: {schemaId}`, `output: {schemaId, path}`, and `root`. Schema identifiers refer to the document's own catalog. Define the input and expected output before adding nodes. The installed `@parcha/agentrun-dsl/schema` is the complete editor schema; execution performs additional semantic checks.
4
+
5
+ ## Minimal typed answer
6
+
7
+ The complete [inline typed example](../SKILL.md#minimal-typed-example) shows the minimal extraction pattern and its input. The model must extract the stated facts; the example itself is not a passed quality test.
8
+
9
+ Important fields:
10
+
11
+ - `requires` names paths in workflow state, not renamed keys in the prompt map. It is a **nonempty-evidence guard**, not a field-existence check: missing/null values, blank strings, empty arrays and objects without concrete values fail before model construction. `false` and `0` are concrete values. If an empty search result is valid input to a recovery step, handle it explicitly rather than declaring it nonempty.
12
+ - LLM `instructions` are literal prose. They do not substitute `{text}`.
13
+ - `state: {text: "{text}"}` explicitly chooses the JSON user message. Omitted `state` sends accumulated state, excluding legacy reference catalogs.
14
+ - `out` names the node's schema; `as` stores its value in state. For agent/extract/decide nodes, omitting `as` stores under the node's `label`; fields are not merged into top-level state. `output.path` selects the final value to validate.
15
+
16
+ For repository work, an agent can declare `tools: ["read", "grep"]` only if those tools are available. Read the host's tool argument schemas; do not invent parameters. Use `tools: []` for a tool-free agent or extraction. Omitting the list inherits the runner's allowed tools; it does not mean tool-free execution.
17
+
18
+ ## One direct tool operation
19
+
20
+ Read [read-file.json](../examples/read-file.json) and its [input](../examples/read-file.input.json). This performs one active built-in `read` call; it needs no model or Jev system one decision. Replace the input path with the file the user asked to read.
21
+
22
+ A built-in returns a Pi tool result: `content` is an array of text/image blocks and `details` is optional. Give `call.out` a schema for that tool return, rather than the final answer or a plain string. A later extraction can transform it into a different output schema. The bundled fictional `search` tool is the exception: its direct effect result is `{sources}`. A `call` needs its host tool name, typed `args`, result `out`, state key `as`, and positive `deadline_s`.
23
+
24
+ ## Composition and decisions
25
+
26
+ Read the complete [release-note review](../examples/review-release-notes.json) and its [input](../examples/review-release-notes.input.json) before composing nodes. It maps a typed extraction over two notes, collects only each `change`, then summarizes the collected changes. This needs Pi, but no Jev or external tools.
27
+
28
+ Use `chain.steps` for dependencies. Each `parallel.branches` entry receives the same input; branches must write different top-level keys. In `map`, `itemsPath` selects the list and the body sees `item` and `item_index`; set `as` and bound `maxConcurrency`. A body with `as` already returns that value per item. Use `resultPath` to select a different path, or to avoid retaining whole parent states from a chain body without `as`. A `loop` needs `until` and integer `maxIters` from 1 through 20; reaching the bound is not proof of success.
29
+
30
+ A Jev `judge` has a nonempty `state` map, `out`, and `as`. Its schema is flat: descriptions state questions, booleans yield yes-probabilities, enums yield choices, and integers with 2 to 10 explicit level descriptions in `criteria` yield scores. Scores range from 0 to the last level index. Raw answers are retained at `<as>$answers`; confidence is not calibrated accuracy. `sift` applies questions to each item, and `route` chooses a branch. Use an explicit uncertainty gate or escalation rather than inventing evidence. Supply the complete reviewed rubric; Jev question text is not a substitute for an unavailable SOP.
31
+
32
+ For `sift`, add a flat question schema to `schemas`, then a node such as:
33
+
34
+ ```json
35
+ {
36
+ "node": "sift", "label": "select-migration-notes",
37
+ "itemsPath": "notes", "out": "MigrationQuestions", "as": "selected",
38
+ "keep": { "path": "actionable", "gte": 0.8 }
39
+ }
40
+ ```
41
+
42
+ `MigrationQuestions` can declare `actionable` as `{"type":"boolean","description":"Does this release note state a concrete change a client maintainer must make, rather than only announce a feature?"}` inside its object `properties`. Set `required: ["actionable"]`. Read selected originals from `selected.items`, retained decisions from `selected.values`, and evidence sidecars from `selected.answers`. The `gte` value gates the yes-probability; it is an example threshold to review, not a calibrated guarantee. Handle empty results explicitly with an `escalate` node using `when: {predicate: "empty", path: "selected.items"}` before synthesis.
43
+
44
+ A `sift` batches all full items into one Jev request; `state` adds shared context
45
+ and `describe` adds summaries, neither replaces the items. The assembled request
46
+ must fit the selected provider's token context and any explicit host byte guard;
47
+ the adapter does not impose a default byte ceiling. A local `jev_state_too_large`
48
+ report names the node, measured bytes and configured host limit; it means no HTTP
49
+ request was sent. For independent judgments over larger originals,
50
+ use an explicit `map` with a `judge` body and selected original-text/provenance
51
+ fields, preserving the full rubric and necessary headers/qualifiers. See the
52
+ [Jev guide](jev-decisions.md); no automatic splitting or truncation occurs.
53
+
54
+ ### Check the edges before running
55
+
56
+ For each connection, name the actual value produced and the exact path consumed.
57
+ These are different contracts; do not make them all the final answer schema:
58
+
59
+ Inspection displays typed state keys and the final selection. It rejects nested
60
+ paths excluded by known closed producer schemas before execution. Dynamic code,
61
+ open schemas, unions and conditional control flow may leave shapes unknown;
62
+ passing inspection does not prove those paths exist at runtime.
63
+
64
+ | Producer | Value available downstream |
65
+ | --- | --- |
66
+ | Host tool called with `as: "read"` | `read.content` and optional `read.details`; not the fields inside `details` at top level |
67
+ | Agent/extract with `out: "Row", as: "row"` | The schema-valid Row at `row`, not `{row: Row}` inside it |
68
+ | Code with `as: "total"` returning a number | The number at `total`; returning `{total: number}` adds a second wrapper |
69
+ | Map with an agent body using `as: "row"` | An array of Row values; no `row` wrapper on each item |
70
+ | Map with a chain body and `resultPath: "row"` | An array of Row values selected from each completed body state |
71
+
72
+ Without `resultPath`, a chain map body retains the whole item state. That is not
73
+ the same as collecting its last step. After mapping, an array is still an array:
74
+ if the final contract is an object, explicitly assemble that object and point
75
+ `output.path` to it. Preserve the same distinction for tool result schemas and
76
+ final answer schemas. Inspection does not execute transforms or prove these
77
+ runtime shapes; check the reported value and contract when execution fails.
78
+
79
+ An `escalate` node always requires `when`. Inside a route branch, the branch-taken predicate below makes escalation unconditional for that branch; outside a branch, provide a predicate for the actual stopping condition.
80
+
81
+ A `route` needs a nonempty `state` map and at least two named branch objects with `body` nodes. This fragment uses the release review's `changes` state and `Report` schema:
82
+
83
+ ```json
84
+ {
85
+ "node": "route", "label": "check-migration-detail", "as": "routing",
86
+ "state": { "changes": "{changes}" },
87
+ "instructions": "Can a maintainer follow every supplied migration action without guessing missing details?",
88
+ "branches": {
89
+ "ready": {
90
+ "criteria": "Every action specifies the concrete client change needed.",
91
+ "body": {
92
+ "node": "extract", "label": "summarize-ready-changes",
93
+ "instructions": "Summarize the supplied migration actions and return changes unchanged.",
94
+ "state": { "changes": "{changes}" }, "out": "Report", "as": "report"
95
+ }
96
+ },
97
+ "needs_details": {
98
+ "criteria": "Any action lacks a required detail or the supplied changes conflict.",
99
+ "body": {
100
+ "node": "escalate", "label": "request-migration-details",
101
+ "when": { "predicate": "field_equals", "path": "routing.taken", "value": "needs_details" },
102
+ "kind": "needs_input", "stage": "migration", "summary": "Migration details need clarification."
103
+ }
104
+ }
105
+ },
106
+ "unsure": { "branch": "needs_details", "gte": 0.8 }
107
+ }
108
+ ```
109
+
110
+ `unsure` selects the conservative branch below its confidence gate. Preserve the raw decision evidence; reaching `ready` does not prove migration correctness.
111
+
112
+ Mechanical checks belong in predicates; semantic questions belong in agent/Jev nodes. Code is trusted JavaScript, not a sandbox, and requires the user's trusted run in the extension. Do not turn an unavailable tool or missing verifier into generated code that bypasses the host.
113
+
114
+ ## Code transforms and schema references
115
+
116
+ Read the complete fictional [evidence gate](../examples/evidence-gate.json) and its [input](../examples/evidence-gate.input.json). It preserves a supplied claim and evidence, asks one Jev question, and gates the raw yes-probability in code before returning a typed record. It uses no agent or tool; running it with a real judge still needs Jev. The repository test uses a fake judge and proves interface behavior, not semantic quality.
117
+
118
+ A code node permits **only** `node`, `label`, `code`, and optional `as`. Its `code` is a single synchronous function expression, such as `(s) => ({ count: s.items.length })`, not a bare statement body. The function receives the **full accumulated workflow state** as its first argument; it does not receive a scoped prompt map. Do not add `state`, `requires`, `out`, or `instructions` to a code node.
119
+
120
+ Native inspection uses nonexecuting syntax/mechanical validation, equivalent to SDK `validateWorkflow(workflow, {executeCode: false})`. It neither evaluates code factories nor probes their outputs. The ordinary SDK validation default is for trusted code and may execute factories/probes. Neither mode is a sandbox or a proof that the eventual result will satisfy the output schema.
121
+
122
+ Use synchronous data operations such as `Math`, `JSON`, `Array`, `Object`, `Map`, and `Set`. The current executor shadows `Date`, `Promise`, timers, host/network globals, and `Function`; they are unavailable even in a trusted run. For example, derive calendar-month sequences from integer year/month pairs rather than `new Date(...)`. This catches accidental host dependencies; it is not an isolation or security boundary.
123
+
124
+ - With `as: "result"`, the returned value is stored at `state.result`; do not also wrap it in `{result: ...}`.
125
+ - Without `as`, return an object patch: its top-level fields shallow-merge into state. Other state keys remain; returning a nested object replaces that entire top-level value. A non-object or array return is stored under the node's label instead, so use an object for patch semantics.
126
+ - Do not mutate the input state. Return new values; do not return a Promise. Code remains trusted host JavaScript, not a sandbox.
127
+
128
+ A node's `out: "Record"` names a sibling catalog schema directly. Inside a schema, the same sibling is referenced as `{"$ref":"#/definitions/Record"}`, **not** `{"$ref":"Record"}`. The example's input and result schemas both use this form. A `judge` has no `instructions` field: put each complete question in its output schema property's `description` (and its decision criteria in `criteria`, when needed).
129
+
130
+ ### Gate the raw probability, not the decoded boolean
131
+
132
+ For a judge with `as: "check"` and boolean question `supported`, read:
133
+
134
+ ```js
135
+ (s) => {
136
+ const p = s['check$answers']?.answers?.supported?.noul;
137
+ return {
138
+ accepted: typeof p === 'number' && Number.isFinite(p) && p >= 0.90 && p <= 1
139
+ };
140
+ }
141
+ ```
142
+
143
+ With `as: "gate"`, this stores `gate.accepted`. Missing, malformed, nonfinite, or out-of-range probabilities fail closed. Follow it with an `escalate` whose `when` is `{predicate: "field_equals", path: "gate.accepted", value: false}`, as in the example. The threshold is illustrative policy, not a calibrated accuracy guarantee.
144
+
145
+ `check.supported` is only the decoded boolean (yes at probability 0.5); it does **not** prove a 0.90 threshold. Likewise, `route.unsure.gte` gates the route's **own new choice confidence**, not an upstream judge's yes-probability. Giving a route the earlier boolean or asking it to enforce a number is not this deterministic gate.