@robmclarty/volley 0.9.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 +22 -0
- package/README.md +57 -16
- package/dist/cli.js +562 -270
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +31 -4
- package/dist/index.js +441 -242
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/builder/presets/harness_append_acp.md +4 -3
- package/src/builder/presets/harness_append_local.md +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v0.10.0 — 2026-10-27
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- **A builder sees what the last check said (#6).** When the previous iteration's check failed, the builder's prompt carries a `PREVIOUS CHECK RESULT` section: the exit code, the failing slots, and an excerpt capped at 6,000 characters, taken from checkride's digest (volley now runs `pnpm exec checkride --json --digest` and archives `check/digest.md`), else the start of each failing slot's raw output, else the end of a command's output. A resume rebuilds it from the archive, and a check the user rejected under `volley acp` reads as never having run, not as failed.
|
|
7
|
+
- **A tool-loop builder's last steps count down (#6).** The last five steps of a session, or a tenth of a longer budget, end with a note of how many are left and the command that runs the check, and the last says that only `finish` runs on it. When a session hits its step limit, the next prompt says so and asks for the check first.
|
|
8
|
+
- **`--builder-max-output-tokens <n>` caps a tool-loop builder's output per turn (#6).** Or `VOLLEY_BUILDER_MAX_OUTPUT_TOKENS`. Reasoning counts, and Ollama gets it as `num_predict`. An ollama or lmstudio builder is capped at 16,384 by default, an openrouter one only when you set a cap. A turn cut off before it calls a tool costs that step instead of ending the session, and each iteration's summary counts those turns as `builder.truncated_turns`.
|
|
9
|
+
- **`builder_max_steps_hits` counts the builder sessions that ran out of steps (#6).** It's on `RunResult`, so `--json` and `summary.json` carry it, since the warning each one prints goes to stderr, which `--json` silences.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- **Reads don't count against `--builder-max-tool-calls` (#6).** `read_file`, `search_files`, and `list_files` are read-only, so a builder that batches them gets them all, and past the cap the next request names the calls that were dropped. Above a cap of one, step 2 of the builder's prompt no longer names the cap.
|
|
13
|
+
- **The builder is asked to check as it goes (#6).** In a checkride workspace it's told to run `pnpm exec checkride --digest` after each batch of edits and to read `.check/digest.md` before any slot's raw output, and both harness prompts say to verify after each batch of edits, not only before finishing.
|
|
14
|
+
- **`RunResult` has `builder_max_steps_hits` and `ResolvedConfig` has `builder_max_output_tokens`.** Both are required, so SDK code that builds either by hand needs them.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- **A contained `--worktree` run keeps its work.** The sandbox image has no git identity, so volley's own commits failed inside it: the salvage commit that keeps a converged run's work on `volley/<run id>`, the `--git` checkpoints, and the squash merge. They now fall back to `volley <volley@volley.invalid>` for whatever git lacks, and an identity you configured still wins.
|
|
18
|
+
- **A failing slot's raw output is read only from inside the check directory.** Slot names and output files come from a summary the builder could have written, and a `../` in one could put a file from outside it in front of the critic or the next builder.
|
|
19
|
+
|
|
20
|
+
### Internal
|
|
21
|
+
- **Built on fascicle 0.17.1**, which names a turn's dropped tool calls to the model and can go on past a turn cut off at its output cap.
|
|
22
|
+
- **The publish workflow keeps its OIDC identity out of the job that runs dependencies.** A `build` job verifies the tag, installs, runs the gate, builds, and packs with read-only permissions, and a separate `publish` job holds `id-token: write` behind the `npm-publish` approval and publishes that tarball with `--ignore-scripts`.
|
|
23
|
+
- **The tests drive the step countdown, the per-turn cap's read-only reads, and the output cap through fascicle's real tool loop**, against a stand-in OpenAI server that now takes several calls a turn and can end one on `length`.
|
|
24
|
+
|
|
3
25
|
## v0.9.0 — 2026-10-20
|
|
4
26
|
|
|
5
27
|
### Added
|
package/README.md
CHANGED
|
@@ -73,11 +73,20 @@ prompt ──> builder (full agentic session in your workspace)
|
|
|
73
73
|
```
|
|
74
74
|
|
|
75
75
|
- **Builder** gets the task, the acceptance criteria, and the previous
|
|
76
|
-
iteration's critic feedback.
|
|
77
|
-
|
|
76
|
+
iteration's critic feedback. When the previous iteration's check failed, it
|
|
77
|
+
also gets what the check said: checkride's digest of the failing slots, else
|
|
78
|
+
the start of each failing slot's raw output, else the end of a command's
|
|
79
|
+
output, capped at 6,000 characters. If the previous session hit its step
|
|
80
|
+
limit, the prompt says so and asks it to run the check first. In a
|
|
81
|
+
checkride workspace it's asked to run `pnpm exec checkride --digest` after
|
|
82
|
+
each batch of edits and to read `.check/digest.md` when that fails, one
|
|
83
|
+
capped file for every failing slot, before any slot's raw output. It has full tools
|
|
84
|
+
(Read/Write/Edit/Bash) and runs with `--permission-mode acceptEdits` by
|
|
85
|
+
default.
|
|
78
86
|
- **Check** is auto-detected: if the workspace uses checkride, volley runs
|
|
79
|
-
`pnpm exec checkride --json` and gates on the summary. Any shell
|
|
80
|
-
works too (`--check "npm test"`), or `--check none` for critic-only
|
|
87
|
+
`pnpm exec checkride --json --digest` and gates on the summary. Any shell
|
|
88
|
+
command works too (`--check "npm test"`), or `--check none` for critic-only
|
|
89
|
+
runs.
|
|
81
90
|
- **Critic** is read-only (`Read`, `Grep`, `Glob` — no write path at all) and
|
|
82
91
|
returns a schema-validated `{ verdict, feedback, unmet_criteria }`. It is told
|
|
83
92
|
which files the builder changed, so it reviews a change rather than a tree.
|
|
@@ -85,7 +94,7 @@ prompt ──> builder (full agentic session in your workspace)
|
|
|
85
94
|
cannot get them wrong.
|
|
86
95
|
|
|
87
96
|
Each iteration is a fresh session — no context carries over except through the
|
|
88
|
-
workspace filesystem
|
|
97
|
+
workspace filesystem, the critic's feedback, and a failed check's output. Swap the critic to change what
|
|
89
98
|
the loop optimizes for: `--critic reviewer` (default), `optimizer`,
|
|
90
99
|
`researcher`, or a path to your own system prompt.
|
|
91
100
|
|
|
@@ -164,8 +173,9 @@ volley acp --builder-provider <name> --builder-model <model> \
|
|
|
164
173
|
| `--builder-model` | `opus` | `opus`/`sonnet`/`haiku` or a full model id. |
|
|
165
174
|
| `--builder-provider` | `claude_cli` | `claude_cli`, `ollama`, `lmstudio`, or `openrouter` (see [Local builder](#local-builder) and [OpenRouter](#openrouter)). |
|
|
166
175
|
| `--builder-url` | the provider's env var | The builder's model server base URL, for `ollama`, `lmstudio`, or `openrouter` only. Lets the builder and critic run on different machines with the same provider (see [Seats on different machines](#seats-on-different-machines)). |
|
|
167
|
-
| `--builder-max-steps` | `50` | Tool-loop builder step cap per iteration. Or `VOLLEY_BUILDER_MAX_STEPS`. Ignored for `claude_cli`. |
|
|
168
|
-
| `--builder-max-tool-calls` | `1` | Tool calls a tool-loop builder may make per turn; past it, fascicle runs the first
|
|
176
|
+
| `--builder-max-steps` | `50` | Tool-loop builder step cap per iteration. Or `VOLLEY_BUILDER_MAX_STEPS`. Ignored for `claude_cli`. `--json` and `summary.json` count the sessions that hit it as `builder_max_steps_hits`. |
|
|
177
|
+
| `--builder-max-tool-calls` | `1` | Tool calls a tool-loop builder may make per turn, not counting reads (`read_file`, `search_files`, `list_files`); past it, fascicle runs the calls before the first one over, drops the rest, and tells the model which it dropped. Raise it for a model and runtime that return parallel calls well. Or `VOLLEY_BUILDER_MAX_TOOL_CALLS`. Ignored for `claude_cli`. |
|
|
178
|
+
| `--builder-max-output-tokens` | `16384` (ollama, lmstudio), the provider's (openrouter) | Output tokens a tool-loop builder may generate per turn, reasoning included (`num_predict` on Ollama). A turn cut off at it before it calls a tool costs that step, not the session. Or `VOLLEY_BUILDER_MAX_OUTPUT_TOKENS`. Ignored for `claude_cli`. |
|
|
169
179
|
| `--allow-unsandboxed-builder` | off | Permit a builder other than `claude_cli` to run without a sandbox (see [Local builder](#local-builder)). |
|
|
170
180
|
| `--critic-model` | `opus` | Model for the critic. |
|
|
171
181
|
| `--critic-provider` | `claude_cli` | `claude_cli`, `ollama`, `lmstudio`, or `openrouter` (see [Local critic](#local-critic) and [OpenRouter](#openrouter)). |
|
|
@@ -241,7 +251,9 @@ default root, from any directory, since the run's recorded config names its
|
|
|
241
251
|
workspace. A run an older volley started keeps its state in the workspace's
|
|
242
252
|
`.volley/`, and resumes there: point `--workspace` at it, or run `resume` from
|
|
243
253
|
inside it. A run directory with a symbolic link in it is refused, since volley
|
|
244
|
-
never writes one.
|
|
254
|
+
never writes one. The resumed run's first builder gets what the last completed
|
|
255
|
+
iteration left it, as it would have without the stop: the critic's feedback,
|
|
256
|
+
the check's output if it failed, and the step-limit note.
|
|
245
257
|
|
|
246
258
|
**A resume on the host runs only a config this machine signed.** A resume runs
|
|
247
259
|
what the run's `config.json` says, its check command and its seats included.
|
|
@@ -401,7 +413,7 @@ Providers and their setup:
|
|
|
401
413
|
Install the peer for your provider in the project running volley (e.g.
|
|
402
414
|
`pnpm add ai-sdk-ollama@^4.3.0`); fascicle loads it lazily only when the local
|
|
403
415
|
critic actually runs. The version matters. The major must satisfy fascicle's
|
|
404
|
-
declared peer range (`^4` for fascicle 0.
|
|
416
|
+
declared peer range (`^4` for fascicle 0.17.1, which tracks the AI SDK v7
|
|
405
417
|
line), and volley declares 4.3.0 as its floor (an optional peer, so your
|
|
406
418
|
package manager flags an older copy at install time). Before 4.3.0,
|
|
407
419
|
ai-sdk-ollama streams a thinking model's reasoning only when the request sets
|
|
@@ -452,16 +464,41 @@ surface itself — `read_file`, `search_files`, `list_files`, `write_file`,
|
|
|
452
464
|
`edit_file`, `bash`, `fetch`, and an explicit `finish` — and runs one bounded
|
|
453
465
|
tool loop per iteration (capped by `--builder-max-steps`, default 50; hitting
|
|
454
466
|
the cap is treated as partial work, not an error). The produced workspace goes
|
|
455
|
-
to check + critic exactly like a `claude_cli` build.
|
|
467
|
+
to check + critic exactly like a `claude_cli` build. Each hit prints a warning,
|
|
468
|
+
and `--json`, which silences warnings, and `summary.json` count them as
|
|
469
|
+
`builder_max_steps_hits`.
|
|
470
|
+
|
|
471
|
+
So that a model that explores first still verifies, the last few steps of each
|
|
472
|
+
session count down: five, or a tenth of a longer budget. Each of those turns
|
|
473
|
+
ends with a note of how many steps are left and the command that runs the
|
|
474
|
+
check, and the last says that only `finish` runs on it, as fascicle refuses
|
|
475
|
+
any other call there. The note is added to what that one turn sends, never to
|
|
476
|
+
the transcript, so it never piles up and a local runtime's cached prefix holds.
|
|
456
477
|
|
|
457
478
|
A local builder makes one tool call per turn by default, since some model and
|
|
458
|
-
runtime pairs return parallel calls badly.
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
479
|
+
runtime pairs return parallel calls badly. Reads don't count: `read_file`,
|
|
480
|
+
`search_files`, and `list_files` are read-only, so a model that batches them,
|
|
481
|
+
as qwen3.8 on Ollama's MLX runner does, gets them all. A turn's calls run in
|
|
482
|
+
order, so a read can't race an edit. Past the cap, fascicle drops the
|
|
483
|
+
remaining calls and the next request names them, so the model can make them
|
|
484
|
+
again. For a pair that handles parallel calls, `--builder-max-tool-calls <n>`
|
|
485
|
+
lets each turn make up to `n` changes or commands, and the builder's prompt
|
|
462
486
|
then asks it to batch independent reads but make one change or command per
|
|
463
487
|
turn.
|
|
464
488
|
|
|
489
|
+
A thinking model can spend one turn reasoning for a long time: on Ollama's MLX
|
|
490
|
+
runner, with nothing capping a turn, one qwen3.8 turn ran to 30,847 tokens and
|
|
491
|
+
19 minutes before a single `read_file`, since the runner lets an unset
|
|
492
|
+
`num_predict` run to the model's trained context less the prompt. So a local
|
|
493
|
+
builder's turns are capped at 16,384 output tokens, reasoning included, and
|
|
494
|
+
`--builder-max-output-tokens <n>` sets another cap. A turn cut off there
|
|
495
|
+
before it makes a tool call costs that one step: fascicle tells the model it
|
|
496
|
+
hit the limit and the session goes on. Each iteration's `summary.json` counts
|
|
497
|
+
those turns as `builder.truncated_turns`. An OpenRouter builder is capped only
|
|
498
|
+
when you set one, since a hosted model has its own output limit and can refuse
|
|
499
|
+
a request for more; uncapped, a turn cut off at the provider's limit still ends
|
|
500
|
+
the session.
|
|
501
|
+
|
|
465
502
|
```sh
|
|
466
503
|
volley \
|
|
467
504
|
--prompt "@task.md" --workspace ./my-project --criteria "@criteria.md" \
|
|
@@ -526,6 +563,10 @@ surprise at teardown:
|
|
|
526
563
|
| `--worktree` | Committed onto `volley/<run id>` and left there. Recover it with `git switch volley/<run id>` or `git cherry-pick`; the branch is named in the final summary and in `--json` as `salvaged_branch`. |
|
|
527
564
|
| `--worktree --discard-worktree` | Thrown away with the branch — verdicts only, nothing kept. |
|
|
528
565
|
|
|
566
|
+
volley's own commits (`--git` checkpoints, the squash merge, and the salvage
|
|
567
|
+
commit) use your git identity. Where git has none, as in the sandbox image,
|
|
568
|
+
they fall back to `volley <volley@volley.invalid>` rather than fail.
|
|
569
|
+
|
|
529
570
|
Any run that does *not* converge (cost cap, budget exhausted, interrupt, error)
|
|
530
571
|
is discarded wholesale in all three modes: an abandoned phase leaves nothing
|
|
531
572
|
behind.
|
|
@@ -697,7 +738,7 @@ for you ([below](#zed-setup)).
|
|
|
697
738
|
`--builder-provider`, `--builder-model`, `--critic-provider`, and
|
|
698
739
|
`--critic-model`. A missing one is refused with every missing flag named. The
|
|
699
740
|
rest are optional: `--builder-url`, `--critic-url`, `--builder-max-steps`,
|
|
700
|
-
`--builder-max-tool-calls`, `--allow-unsandboxed-builder`, `--critic`, `--check`, `--max-iterations`,
|
|
741
|
+
`--builder-max-tool-calls`, `--builder-max-output-tokens`, `--allow-unsandboxed-builder`, `--critic`, `--check`, `--max-iterations`,
|
|
701
742
|
`--max-cost-usd`, and `--state-dir`.
|
|
702
743
|
|
|
703
744
|
It refuses these before serving, each with exit 5:
|
|
@@ -882,7 +923,7 @@ the workspace: `<root>/<run id>/`, where the root is `--state-dir` (or
|
|
|
882
923
|
trajectory.jsonl # every fascicle trajectory event (replayable, below)
|
|
883
924
|
feedback.md # current critic feedback (harness-written)
|
|
884
925
|
verdict # approved | changes_requested (harness-written)
|
|
885
|
-
iterations/NNN/ # per-iteration archive: feedback, verdict, check artifacts, summary
|
|
926
|
+
iterations/NNN/ # per-iteration archive: feedback, verdict, check artifacts and digest, summary
|
|
886
927
|
```
|
|
887
928
|
|
|
888
929
|
- **Why outside.** Some checks read every file in the tree, dot-directories
|