@ssheleg/agent-stack 0.8.0 → 0.10.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,137 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.10.0] — 2026-08-15
4
+
5
+ ### Added
6
+
7
+ - **`agent-orchestrator/references/graph-engineering.md` — deciding the shape of the work
8
+ before doing it.** The pack could wire a loop, prove it behaved, connect it and tell it
9
+ what to do, and had nothing to say about the question that comes before all four: *does
10
+ this actually have to happen in a line?* Node and edge, the fake-edge test, the diamond,
11
+ the two ways a diamond fails silently, the checker node, static versus dynamic, and the
12
+ cost table that says when a graph is not worth building.
13
+
14
+ Sourced from *Graph Engineering with Claude*
15
+ (`https://x.com/Mahaximus_/status/2082442856417956173`, published 2026-07-29), and the
16
+ link is kept so the original can be re-read rather than remembered through the summary.
17
+ Four sections are **this pack's** and are marked as such in the file: what the host
18
+ actually runs, the barrier distinction, what a checker costs, and auditability as a hard
19
+ rule rather than a preference.
20
+
21
+ - **What Claude Code actually executes, with version evidence.** The source's one
22
+ operational claim aged out six weeks after publication: the `workflow` keyword it names
23
+ was renamed to `ultracode` in **v2.1.160**, and the YAML it shows is a way of describing
24
+ a graph in a prompt rather than a syntax the host parses — the execution contract is a
25
+ script whose primitives are `agent()`, `parallel()` (a barrier) and `pipeline()` (none).
26
+ Every claim in that section carries the `v2.1.x` changelog entry that establishes it,
27
+ which is why the correction reads as a dated fact rather than as an error by the author.
28
+
29
+ - **`agent-harness` — *Static or dynamic, the second question*.** The workflow-versus-agent
30
+ table decided one thing and left the other open. Six rows, and one of them is hard: a run
31
+ that has to be auditable is static, because a graph that picks its own next nodes produces
32
+ a shape nobody drew, and then *"here is the design"* and *"here is what happened"* stop
33
+ being the same document.
34
+
35
+ - **`agent-evals` §5a — the checker node as an evaluator that runs inside the graph.** Its
36
+ five catches split three code checks and two judge calls, so §5's *cheap checks first*
37
+ applies to a position in the graph rather than to a suite. And the part that makes it eval
38
+ work: **a checker that has never rejected anything is a finding, not a reassurance** — its
39
+ verdicts are scores with a source, and its rejection rate belongs on the same dashboard as
40
+ its pass rate.
41
+
42
+ - **A sixth scanner detector, `unguarded-fanout`.** `asyncio.gather` with no
43
+ `return_exceptions=True`, or `Promise.all` with no `allSettled` and no per-branch
44
+ `.catch`: the first sibling to fail cancels the batch, the others' completed work is
45
+ discarded, and the node consuming the results cannot tell a failed branch from an empty
46
+ one. Conservative like the rest — the capturing form anywhere in the file silences it.
47
+
48
+ ### Changed
49
+
50
+ - **The self-test proves silence as well as noise.** `PLANTS` and `CLEAN` replaced the
51
+ single dict, because one detector now reads two languages and needed a plant in each, and
52
+ because a detector that fires on the defect *and* on its fix has no discriminating power.
53
+ A fan-out that **does** capture its branches is now a fixture the pass must stay silent
54
+ on. `self-test: 6/6` → **`9/9`** (seven plants, two clean fixtures), counted by running it.
55
+
56
+ - **`agent-orchestrator` §5 no longer contradicts its own data model.** `PlanStage` declared
57
+ `depends_on` and the executor beside it walked `plan.stages` in list order — a plan that
58
+ went to the trouble of saying it need not be serialised, serialised. It now executes in
59
+ dependency layers (Kahn), gates a layer of more than one on the checker before anything
60
+ consumes it, and `ExecutionPlan` grows the `layers()` that makes the declaration mean
61
+ something. A cycle fails the plan rather than deadlocking the run.
62
+
63
+ ### Removed
64
+
65
+ - **The hardcoded context-window table.** `references/patterns.md` carried nine vendor model
66
+ ids with their windows and a `DEFAULT_CONTEXT_WINDOW` of 16 000. Every number was correct
67
+ when written and none survived: ids were renamed, long-context variants shipped under the
68
+ same family name, and a system reading that table would size its budget for a window an
69
+ order of magnitude smaller than the one it was given. Replaced by the resolution order —
70
+ configuration, then the provider, then a conservative floor **with a loud log line** — and
71
+ the check is mechanical: no vendor model id remains anywhere in the shipped skill text.
72
+ Two illustrative ones in `SKILL.md` and `llm-proxy-billing.md` went with it, because a
73
+ class fixed in one place and left in two others is not fixed.
74
+
75
+ - **Two duplicated homes.** §8's learning tables and §10's prompt-assembly snippet restated
76
+ what `references/patterns.md` and `agent-harness/references/system-prompt.md` already own.
77
+ Both now state the decision and point at the home. `SKILL.md` is **502 lines / 5670
78
+ tokens** against a 4750 working budget — the number is counted, it is over, and the next
79
+ addition to this body should split rather than absorb.
80
+
81
+ ## [0.9.0] — 2026-08-15
82
+
83
+ ### Added
84
+
85
+ - **`agent-harness/references/pi.md` and `pi-sdk.md` — the harness doctrine as a worked
86
+ implementation.** Every other reference in that skill states a rule; **Pi** is small enough
87
+ to read and complete enough to have made each of those decisions in public. So each section
88
+ says what Pi does and then **which rule it is an instance of** — the second half is the
89
+ point, and where Pi disagrees with this pack, that is said rather than smoothed over.
90
+
91
+ Read from `pi.dev/docs/latest` on 2026-08-15: sixteen doc pages plus the package source.
92
+ All sixteen verified reachable (`200`); the only non-resolving URLs in either file are the
93
+ two deliberate placeholders inside custom-provider examples.
94
+
95
+ - **`pi.md`** — the four ways to run it; **sessions as a JSONL tree** (8-hex `id`, `parentId`,
96
+ version 3, `BranchSummaryEntry`) matched to *time travel and forking* in
97
+ `agent-orchestrator/references/runtime.md`; **compaction with the real numbers**
98
+ (`contextTokens > contextWindow - reserveTokens`, defaults 16,384 and 20,000, tool results
99
+ truncated to 2,000 chars while summarizing) matched to the compaction ladder, with what the
100
+ ladder adds that Pi leaves to you; settings precedence that **merges rather than replaces**;
101
+ skills, prompt templates and packages; and the trust model.
102
+
103
+ Its sharpest section is **the deliberate absence of a sandbox**, quoted: *"prompt injection
104
+ from repository files … is expected local-agent risk and cannot be reliably prevented by
105
+ pi."* That is `layers.md`'s delegation thesis stated by the project itself — and for an
106
+ audit it changes the finding, because "no permission model" here is a delegation, not a
107
+ defect. Three containerization patterns are compared by **where credentials end up**, which
108
+ is the question that actually decides between them.
109
+
110
+ - **`pi-sdk.md`** — `createAgentSession()`, `ModelRuntime`, `SessionManager`, `defineTool()`,
111
+ `DefaultResourceLoader`; the RPC protocol with its command groups, its full event lifecycle
112
+ and the **`\n`-only JSONL framing warning**; JSON mode's delta-only records and why;
113
+ the `ExtensionAPI` surface; and **the eight seams** — `tool_call` (can block),
114
+ `tool_result` (a middleware chain), `context`, `before_agent_start`, the three provider
115
+ hooks, and the compaction pair — each matched to the doctrine it lets you implement.
116
+ `tool_call` blocking is called out as the single most important one for an audit: it is
117
+ where a per-tool, per-caller policy can actually live.
118
+
119
+ - Noted with its evidence and its limit: **Pi discovers skills from `~/.agents/skills/`**,
120
+ which on this machine is the ssheleg hub — 72 entries, every family skill carrying the
121
+ `name` and `description` front matter Pi requires. Stated as a fact about the path and the
122
+ front matter, **not** as an observed load: Pi is not installed here. The reference also
123
+ names Pi's documented divergence from the Agent Skills standard (a skill name may differ
124
+ from its directory) and warns that `make-skill`'s validator enforces the strict rule.
125
+
126
+ ### Changed
127
+
128
+ - `references/layers.md` points at the two new files as the worked example of the kernel
129
+ layer it describes abstractly.
130
+ - `agent-harness`'s description gains the embedding triggers (`agent SDK`, `embed an agent`,
131
+ `Pi harness`, `встроить агента`) — 807/1024, inside the family's 970 working budget. The
132
+ repository's own front-matter gate caught a first draft at 1066 and refused the write.
133
+
134
+
3
135
  ## [0.8.0] — 2026-08-14
4
136
 
5
137
  ### Added
package/README.md CHANGED
@@ -11,7 +11,7 @@ Part of the [ssheleg skill family](https://github.com/ssheleg/sshlg-skills).
11
11
 
12
12
  Four skills — `agent-orchestrator` for wiring the loop, `agent-evals` for proving it
13
13
  behaves, `agent-interop` for everything it talks to outside its own process,
14
- `agent-harness` for what it is **told** — and sixteen references they load on demand,
14
+ `agent-harness` for what it is **told** — and nineteen references they load on demand,
15
15
  plus one scanner.
16
16
 
17
17
  **The orchestrator** (`SKILL.md`) — what the agent reads first:
@@ -31,6 +31,10 @@ plus one scanner.
31
31
  decay, plus conflict resolution when a new learning contradicts an old one
32
32
  - context budget allocation by priority
33
33
  - self-learning feedback loops
34
+ - **the shape of the work, decided before the work**: an edge that carries no data is
35
+ no edge, a plan that declares `depends_on` is executed in dependency layers rather
36
+ than in list order, and a parallel layer gets a checker before the node that
37
+ consumes it
34
38
 
35
39
  **The evals skill** (`agent-evals/SKILL.md`) — how you know any of it works. An
36
40
  agent's behaviour is not in its source, so the artifact under test is the
@@ -61,19 +65,29 @@ ACP, AGNTCY, AP2, Agent Skills — so an agent stops guessing.
61
65
  model, and the one where most agent bugs actually live: *the biggest performance
62
66
  improvements often come from clearly explaining tool usage in the system prompt*, and *even
63
67
  small refinements to tool descriptions can yield dramatic improvements*. Before adding a
64
- retry or a sub-agent, it asks four questions about the text. Five references —
68
+ retry or a sub-agent, it asks four questions about the text. Seven references —
65
69
  `system-prompt.md` (right altitude, enumerated vocabulary, and the three things reasoning
66
70
  models changed — starting with **do not add chain-of-thought**), `tools.md` (the
67
71
  agent–computer interface, with a worked before/after and poka-yoke), `techniques.md`
68
72
  (fifteen techniques, a verdict each **for production** rather than a benchmark),
69
73
  `layers.md` (which layer you are building at, and why permission boundaries are usually the
70
- environment's job), `audit.md` (seven tracks, evidence tiers, a plan instead of a score).
74
+ environment's job), `audit.md` (seven tracks, evidence tiers, a plan instead of a score)
75
+ plus **`pi.md` and `pi-sdk.md`, the doctrine as a worked implementation**: Pi read end to
76
+ end, each mechanism matched to the rule it instantiates, its divergences named, and the
77
+ eight extension seams where a permission gate or a context rewrite can actually live.
71
78
 
72
79
  It runs in both directions: **building a harness and auditing somebody else's are one
73
80
  checklist read forwards and backwards.** `scripts/audit_agent.py` is the mechanical half —
74
- five conservative detectors, and it always prints what it *cannot* see plus a denominator,
81
+ six conservative detectors, and it always prints what it *cannot* see plus a denominator,
75
82
  so its silence is never read as a pass.
76
83
 
84
+ **`references/graph-engineering.md`** — deciding the shape of the work before
85
+ doing it: node and edge, the fake-edge test, the diamond and the two ways it
86
+ fails silently, the checker node and what it costs, static versus dynamic with
87
+ auditability as the hard rule, when a graph is not worth building, and what a
88
+ host actually executes when it fans out — with the version evidence, because the
89
+ keyword the source named was renamed six weeks after it was published.
90
+
77
91
  **`references/context-engineering.md`** — what the loop gives up when the window
78
92
  runs out: the five-rung compaction ladder and why to re-measure between rungs,
79
93
  the tool-pair boundary invariant, typed carryover blocks copied across the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ssheleg/agent-stack",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "Production patterns for AI agent orchestrators \u2014 tool-calling loops, multi-stage pipelines with checkpoints, LLM provider routing with fallback, four-layer memory with confidence decay \u2014 plus the wallet side of reselling LLM access. This package is the installer CLI.",
5
5
  "bin": {
6
6
  "agent-stack": "bin/agent-stack.js"
@@ -2,7 +2,7 @@
2
2
  "name": "agent-stack",
3
3
  "displayName": "Agent Stack",
4
4
  "description": "Two skills: agent-orchestrator \u2014 tool-calling loops, multi-stage pipelines with checkpoints, provider routing with fallback, four-layer memory, context engineering, plus the wallet side of reselling LLM access; and agent-evals \u2014 run/trace/thread evals, judges, and fixtures grown from production.",
5
- "version": "0.8.0",
5
+ "version": "0.10.0",
6
6
  "author": {
7
7
  "name": "ssheleg",
8
8
  "url": "https://x.com/sshlg93"
@@ -7,9 +7,10 @@ description: >-
7
7
  evals. Covers the three observability primitives (run, trace, thread) crossed with three
8
8
  eval granularities (single-step, full-turn, multi-turn), the offline/online/ad-hoc
9
9
  timing axis, pass-fail rubrics over scalar scores, cheap code checks before model
10
- judges, simulated users with adversarial personas, annotation queues, and what to
11
- instrument so any of it is possible. Triggers - "agent eval", "eval suite", "LLM judge",
12
- "regression fixture", "trajectory eval", "is the agent getting better", "эвалы агента",
10
+ judges, the checker node as an evaluator running inside the graph, simulated users with
11
+ adversarial personas, annotation queues, and what to instrument so any of it is
12
+ possible. Triggers - "agent eval", "eval suite", "LLM judge", "regression fixture",
13
+ "trajectory eval", "checker node", "is the agent getting better", "эвалы агента",
13
14
  "оценка агента", "LLM-судья", "регрессионный набор", "как проверить агента". Not for
14
15
  unit tests of ordinary code, or for benchmarking a model.
15
16
  license: MIT
@@ -159,6 +160,44 @@ domain expert and accept that this tier stays human.
159
160
 
160
161
  ---
161
162
 
163
+ ## 5a. The checker node — an evaluator that runs inside the graph
164
+
165
+ Everything above evaluates a run *afterwards*. One evaluator runs **during** it, and it is
166
+ the one most systems are missing: a **checker node** sitting between a parallel layer and
167
+ the node that consumes it. Its only job is *usable / not usable*, and the convergence
168
+ depends on **it** rather than on the branches — otherwise the gate has a bypass.
169
+
170
+ It matters here because it is the same machinery as §5, positioned differently:
171
+
172
+ | It catches | Decided by |
173
+ |---|---|
174
+ | an empty or null output | a code check |
175
+ | a confidence signal below the downstream bar | a code check |
176
+ | a shape that will break the consumer's parsing | a code check |
177
+ | two outputs that cannot both be true | a judge |
178
+ | an output answering a different question than the one asked | a judge |
179
+
180
+ Three of five are free. Run them first — §5's *cheap checks first*, applied to a position
181
+ in the graph rather than to a suite.
182
+
183
+ **A checker is a node, so it can be wrong, and its failure mode is silent approval.** A
184
+ model checker that has never been shown a bad input passes everything, and a graph with a
185
+ checker that always says yes is **worse** than one with none: the missing checkpoint has
186
+ been replaced by a false one that everything downstream now trusts. Three consequences,
187
+ and they are eval work rather than orchestration work:
188
+
189
+ - **Watch it refuse a planted bad output** before trusting it, exactly as §5 requires of
190
+ any judge before it scores unattended.
191
+ - **Record every verdict as a score bound to the run**, with `source: code_check` or
192
+ `llm_judge` (§7). A checker whose verdicts are not stored cannot be asked afterwards how
193
+ often it fired, which means it cannot be calibrated.
194
+ - **A checker that has never rejected anything is a finding, not a reassurance.** Put the
195
+ rejection rate on the same dashboard as the pass rate; a rate of zero is either a
196
+ perfect upstream or a broken gate, and only the stored verdicts can tell you which.
197
+
198
+ Where the checker sits in the shape, and why the convergence needs one at all:
199
+ `agent-orchestrator/references/graph-engineering.md`.
200
+
162
201
  ## 6. The corpus grows from production
163
202
 
164
203
  Never author the suite up front. Every production failure and every thumbs-down becomes a
@@ -215,6 +254,8 @@ None of the above runs without these, and they are the part people skip:
215
254
  - [ ] Pass/fail rubrics with enumerated failure conditions, written with behaviour owners
216
255
  - [ ] Code checks before model judges
217
256
  - [ ] Judge calibrated against human labels before it is trusted
257
+ - [ ] Every checker node watched refusing a planted output, its verdicts stored as scores,
258
+ and its rejection rate on the dashboard — a checker at zero rejections is a finding
218
259
  - [ ] Domain-expert review for output a general judge cannot grade
219
260
  - [ ] Every production failure minimised into a permanent fixture
220
261
  - [ ] Annotation queue with filters, and the two reviewer roles kept separate
@@ -2,15 +2,16 @@
2
2
  name: agent-harness
3
3
  description: >-
4
4
  Use when the question is what the agent is TOLD rather than how its loop is wired — writing
5
- or fixing a system prompt, shaping tools so the model actually picks the right one,
6
- deciding whether a job wants a workflow or an agent, or choosing between ReAct, reflection,
7
- planning and voting. Also the audit direction: reviewing an agent system somebody else
8
- built, with tracks, evidence tiers and a prioritized plan instead of a score, plus a
9
- scanner for the defects that are mechanically visible. Triggers - "system prompt", "tool
10
- description", "the agent picks the wrong tool", "agent loops forever", "prompt engineering",
11
- "ReAct", "reflection", "workflow or agent", "audit this agent", "review our agent system",
12
- "системный промпт", "агент не вызывает тул", "аудит агента", "воркфлоу или агент". Not for
13
- the loop's plumbing, its evals, or the protocols it speaks — those are the sibling skills.
5
+ or fixing a system prompt, shaping tools so the model picks the right one, deciding whether
6
+ a job wants a workflow or an agent, or choosing between ReAct, reflection and voting. Also
7
+ auditing an agent system somebody else built: tracks, evidence tiers and a prioritized plan
8
+ instead of a score, plus a scanner. Carries Pi as a worked kernel implementation SDK, RPC
9
+ and extension seams — for embedding or extending a harness. Triggers - "system prompt",
10
+ "tool description", "agent picks the wrong tool", "agent loops forever", "prompt
11
+ engineering", "ReAct", "workflow or agent", "static or dynamic", "audit this agent",
12
+ "embed an agent", "agent SDK", "Pi harness", "системный промпт", "агент не вызывает тул",
13
+ "аудит агента", "встроить агента". Not for the loop's plumbing, its evals, or its
14
+ protocols — those are siblings.
14
15
  ---
15
16
 
16
17
  # Agent harness — what the agent is told, and how to audit what someone else told theirs
@@ -81,6 +82,30 @@ that only where a fixed path genuinely cannot be written.
81
82
  from a known set. Orchestration invents the set per request. If you can enumerate the
82
83
  branches, you wanted routing and it is cheaper.
83
84
 
85
+ ### Static or dynamic — the second question, and it is not the same one
86
+
87
+ Having chosen a workflow, one thing is still open: **is its shape known before it runs?**
88
+ A **static** graph has every node and edge decided up front. A **dynamic** one grows — a
89
+ node finishes, reads what it found, and decides what comes next.
90
+
91
+ | Reach for | When |
92
+ |---|---|
93
+ | **static** | the task repeats and the structure is the same every time |
94
+ | **static** | predictability and speed matter more than flexibility |
95
+ | **static** | **always first** — go dynamic only after the static version hits a wall you can name |
96
+ | dynamic | the scope of the work depends on what is discovered along the way |
97
+ | dynamic | a node must choose its successors from its own output |
98
+ | **never dynamic** | **the run has to be auditable** — see below |
99
+
100
+ **The audit rule is hard, not a preference.** A dynamic graph's executed shape is not the
101
+ shape anybody drew, so *"here is the design"* and *"here is what happened"* stop being the
102
+ same document and every claim about the run becomes unfalsifiable from outside. Most
103
+ workflows that feel like they need a dynamic graph need a better static one.
104
+
105
+ The rest of the model — the fake-edge test, the diamond, the checker node before a
106
+ convergence, and what a host actually executes when it fans out — is
107
+ `agent-orchestrator/references/graph-engineering.md`.
108
+
84
109
  ---
85
110
 
86
111
  ## References
@@ -95,6 +120,8 @@ and `test/validate.py` fails the build on a reference that does not say when it
95
120
  | [`references/techniques.md`](references/techniques.md) | you are choosing between **ReAct, reflection, voting, planning** and the rest — every entry carries a verdict for production, not a benchmark score |
96
121
  | [`references/layers.md`](references/layers.md) | deciding **what your harness owns** — kernel, workbench and product layers, and why permission boundaries are usually somebody else's job |
97
122
  | [`references/audit.md`](references/audit.md) | reviewing **an agent system you did not build** — seven tracks, evidence tiers, and a prioritized plan |
123
+ | [`references/pi.md`](references/pi.md) | you want the doctrine above as a **worked implementation** — Pi's sessions, compaction, config, skills, trust and containerization, each matched to the rule it implements, and the places it deliberately disagrees |
124
+ | [`references/pi-sdk.md`](references/pi-sdk.md) | you are **embedding or extending** a harness — the SDK, the RPC protocol, JSON mode, and the eight extension seams where a permission gate, a context rewrite or a cost hook can actually live |
98
125
 
99
126
  **`scripts/audit_agent.py`** — the mechanical half of the audit. It finds what is visible
100
127
  without understanding intent (an unbounded loop, a tool with no description, a swallowed
@@ -149,6 +176,7 @@ prompt.
149
176
  ## Checklist — a harness worth shipping
150
177
 
151
178
  - [ ] Workflow-versus-agent decided deliberately, and the simpler option was actually tried
179
+ - [ ] Static-versus-dynamic decided too, and a run that must be auditable is static
152
180
  - [ ] System prompt at the **right altitude** — heuristics, not hardcoded branches, not vague hope
153
181
  - [ ] Every status, category and enum the agent must produce is **enumerated in the prompt**
154
182
  - [ ] Today's date, and any other volatile context, injected rather than assumed
@@ -62,6 +62,10 @@ surrounds it. Read as a weakness, it looks like a missing feature. Read as archi
62
62
  is a clear statement: *a harness that also claims to be a sandbox is claiming a guarantee it
63
63
  cannot keep*, because it runs in the same process as the code it would be confining.
64
64
 
65
+ **Worked out in full in `pi.md` and `pi-sdk.md`** — the kernel layer read end to end, with
66
+ each mechanism matched to the rule it implements and its divergences named. Use it as the
67
+ concrete example when this file's abstractions need a body.
68
+
65
69
  Two consequences worth stating plainly:
66
70
 
67
71
  - **A harness advertising "safe tool execution" without an OS-level or container boundary is