@robmclarty/volley 0.6.0 → 0.7.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,32 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.7.0 — 2026-10-16
4
+
5
+ ### Added
6
+ - **Each seat can use its own model server.** `--builder-url` and `--critic-url` (`builder_url` and `critic_url` in a config file) point the builder and the critic at different machines even when both run on the same provider, such as two Ollama servers. A seat without a URL of its own uses the provider's env var (`VOLLEY_OLLAMA_URL` or `VOLLEY_LMSTUDIO_URL`), then the default, never the other seat's. Everything a seat sends goes to its URL: its model calls, the Ollama prewarm and context check, and the `--dry-run` probe and critic canary. Inside the sandbox, a loopback seat URL crosses to `VOLLEY_MODEL_HOST` on its own port. Both URLs carry over to `volley resume` and to every `volley matrix` pairing. A URL on a `claude_cli` seat, or one that isn't plain http(s), is a configuration error (exit 5).
7
+
8
+ ### Changed
9
+ - **Ollama seats need ai-sdk-ollama 4.3.0 or later.** Before 4.3.0 it streams a thinking model's reasoning only when a request sets `think`, which volley never does, so the reasoning vanished from the terminal and the trajectory and the phase's throughput read high. volley now declares the floor as an optional peer: pnpm warns about an older copy, npm refuses it with ERESOLVE, and an install without ai-sdk-ollama is unaffected.
10
+ - **`--dry-run` probes the critic's model endpoint too.** Each local seat's endpoint is probed, once for a server both seats share, so a `claude_cli` builder with a local critic now gets a reachability check before the canary, and an unreachable endpoint is named with its seat.
11
+ - **`ResolvedConfig` has `builder_url` and `critic_url`.** Both are required (`string | null`), so SDK code that builds a `ResolvedConfig` by hand instead of through `resolve_config` needs them. A run saved by an earlier version resumes with both null.
12
+ - **An empty `VOLLEY_OLLAMA_URL` or `VOLLEY_LMSTUDIO_URL` means the default.** It used to fail the run with a configuration error.
13
+
14
+ ### Fixed
15
+ - **An IPv6 loopback model URL reaches the host from inside the sandbox.** `http://[::1]:…` was never crossed to `VOLLEY_MODEL_HOST`, because `URL` keeps the brackets in the hostname.
16
+
17
+ ### Internal
18
+ - **Built on fascicle 0.14.0, TypeScript 7, and tsdown.** tsdown replaces tsup, whose declaration build needed a compiler API TypeScript 7 no longer exports. The published files keep their names and exports, and the bundles now keep their source comments. The dev toolchain moves to checkride 0.14.0, fallow 3.33.1, oxlint 1.88.0, vitest 5.0.4, and @ast-grep/cli 0.50.0, alongside ai 7.0.140, undici 8.12.1, and cac 7.1.0, and `pnpm audit` is clean.
19
+ - **The throughput docs mark the gap that remains on Ollama.** A turn whose only output is a tool call still reports a rate far too high until fascicle times those turns another way (robmclarty/fascicle#12).
20
+ - **An integration test holds each seat to its own server.** It runs real engines against two stand-in Ollama servers, and the local-provider tests no longer reach a developer's own Ollama.
21
+
22
+ ## v0.6.1 — 2026-10-14
23
+
24
+ ### Fixed
25
+ - **`--worktree` now isolates a Claude builder.** The `claude` session started in the workspace instead of the worktree, so under `--worktree` a `claude_cli` builder edited your checkout while the check, the checkpoints, and the change report the critic reads all looked at the untouched worktree. Claude sessions now start in the worktree; `.volley/` run state stays in the workspace as before, and local-model builders, whose tools were already rooted in the worktree, are unaffected.
26
+
27
+ ### Internal
28
+ - An integration test runs the real engine against a stand-in `claude` binary and checks that the builder's write lands on the run branch, not in the workspace.
29
+
3
30
  ## v0.6.0 — 2026-09-27
4
31
 
5
32
  ### Added
package/README.md CHANGED
@@ -157,10 +157,12 @@ volley matrix --builders <models> --critics <models> --config <path>
157
157
  | `--check` | `auto` | `auto` (checkride if detected, else none), `none`, or a shell command. |
158
158
  | `--builder-model` | `opus` | `opus`/`sonnet`/`haiku` or a full model id. |
159
159
  | `--builder-provider` | `claude_cli` | `claude_cli`, `ollama`, or `lmstudio` (see [Local builder](#local-builder)). |
160
+ | `--builder-url` | the provider's env var | The builder's model server base URL, for `ollama` or `lmstudio` only. Lets the builder and critic run on different machines with the same provider (see [Seats on different machines](#seats-on-different-machines)). |
160
161
  | `--builder-max-steps` | `50` | Local builder tool-loop step cap per iteration. Ignored for `claude_cli`. |
161
162
  | `--allow-unsandboxed-builder` | off | Permit a local builder to run without a sandbox (see [Local builder](#local-builder)). |
162
163
  | `--critic-model` | `opus` | Model for the critic. |
163
164
  | `--critic-provider` | `claude_cli` | `claude_cli`, `ollama`, or `lmstudio` (see [Local critic](#local-critic)). |
165
+ | `--critic-url` | the provider's env var | The critic's model server base URL, for `ollama` or `lmstudio` only. |
164
166
  | `--builder-permission-mode` | `acceptEdits` | Or `bypassPermissions` for fully trusted workspaces. |
165
167
  | `--critic` | `reviewer` | `reviewer`, `optimizer`, `researcher`, or a prompt file path. |
166
168
  | `--max-iterations` | `10` | Hard iteration cap. |
@@ -172,7 +174,7 @@ volley matrix --builders <models> --critics <models> --config <path>
172
174
  | `--fail-on-gate-edit` | off | Halt the run (exit 8) if the builder edits a gate path, instead of reporting it. |
173
175
  | `--sandbox-image` | `volley-sandbox:latest` | Container image for the local-builder sandbox. Or `VOLLEY_SANDBOX_IMAGE`. |
174
176
  | `--run-id` | a fresh UUID | The run's id, naming its `.volley/` state and its `volley/<id>` branch, so a harness that owns the id finds it in both. Letters, digits, `-`, and `_`, starting with a letter or digit. |
175
- | `--dry-run` | off | Validate config, run `checkride doctor` and (for a local critic) the critic-seat canary, then exit. |
177
+ | `--dry-run` | off | Validate config, run `checkride doctor`, probe each local seat's model endpoint, run the critic-seat canary (for a local critic), then exit. |
176
178
  | `--config` | — | TypeScript config file (`VolleyConfig` default export). CLI flags override. |
177
179
  | `--json` | off | Machine mode: one summary JSON document on stdout. |
178
180
  | `--verbose` | off | Full tool inputs/outputs (truncated at 4000 chars). |
@@ -244,7 +246,7 @@ volley matrix \
244
246
 
245
247
  | Matrix flag | Description |
246
248
  |---|---|
247
- | `--config` | Base `VolleyConfig` (TS/JS): the task, workspace, providers, and caps held fixed. Required. |
249
+ | `--config` | Base `VolleyConfig` (TS/JS): the task, workspace, providers, seat URLs, and caps held fixed. Required. |
248
250
  | `--builders` | Comma-separated builder models to sweep. |
249
251
  | `--critics` | Comma-separated critic models to sweep. |
250
252
  | `--repeat` | Attempts per seat (default 1). A pass *rate* needs more than one. |
@@ -296,8 +298,8 @@ produced none at all (`status: broke`).
296
298
 
297
299
  ## Local critic
298
300
 
299
- The builder always runs on the Claude Code CLI, but the critic is read-only
300
- and schema-constrained — a good fit for a cheaper local model. Point it at a
301
+ The critic is read-only and schema-constrained, which makes it a good fit for
302
+ a cheaper local model even when the builder stays on Claude. Point it at a
301
303
  local provider with `--critic-provider`:
302
304
 
303
305
  ```sh
@@ -317,19 +319,29 @@ Providers and their setup:
317
319
 
318
320
  | `--critic-provider` | Server | Base-URL env (default) | Required peer dependency |
319
321
  |---|---|---|---|
320
- | `ollama` | [Ollama](https://ollama.com) | `VOLLEY_OLLAMA_URL` (`http://localhost:11434`) | `ai-sdk-ollama@^4` |
322
+ | `ollama` | [Ollama](https://ollama.com) | `VOLLEY_OLLAMA_URL` (`http://localhost:11434`) | `ai-sdk-ollama@^4.3.0` |
321
323
  | `lmstudio` | [LM Studio](https://lmstudio.ai) | `VOLLEY_LMSTUDIO_URL` (`http://localhost:1234/v1`) | `@ai-sdk/openai-compatible` |
322
324
 
323
325
  Install the peer for your provider in the project running volley (e.g.
324
- `pnpm add ai-sdk-ollama@^4`); fascicle loads it lazily only when the local
325
- critic actually runs. The major matters: it must satisfy fascicle's declared
326
- peer range (`^4` for fascicle 0.12.13, which tracks the AI SDK v7 line; a bare
327
- `pnpm add ai-sdk-ollama` installs v4, which is exactly what this major wants).
326
+ `pnpm add ai-sdk-ollama@^4.3.0`); fascicle loads it lazily only when the local
327
+ critic actually runs. The version matters. The major must satisfy fascicle's
328
+ declared peer range (`^4` for fascicle 0.14.0, which tracks the AI SDK v7
329
+ line), and volley declares 4.3.0 as its floor (an optional peer, so your
330
+ package manager flags an older copy at install time). Before 4.3.0,
331
+ ai-sdk-ollama streams a thinking model's reasoning only when the request sets
332
+ `think`, which volley never does: the reasoning disappears from the terminal
333
+ and the trajectory, and the phase's throughput reads high. A bare
334
+ `pnpm add ai-sdk-ollama` installs the latest 4.x, which clears the floor.
328
335
  The Ollama base URL is the **server root** — `ai-sdk-ollama` adds the `/api`
329
336
  prefix itself (volley strips a trailing `/api` from `VOLLEY_OLLAMA_URL` for
330
337
  compatibility). Local providers are free, so the critic's cost is reported as
331
338
  `$0.000` and the run total reflects builder spend only.
332
339
 
340
+ The env var sets a provider's URL for both seats. To give the critic a server
341
+ of its own, pass `--critic-url` (`critic_url` in a config file). A seat uses its
342
+ own URL, then the provider's env var, then the default, and never the other
343
+ seat's URL; see [Seats on different machines](#seats-on-different-machines).
344
+
333
345
  Keeping the builder on Claude while the critic goes local is the low-risk split:
334
346
  the recurring per-iteration critic cost drops to zero and the critic is
335
347
  read-only, so a weaker local model can only mis-judge, never mis-edit. A local
@@ -408,7 +420,8 @@ is discarded wholesale in all three modes: an abandoned phase leaves nothing
408
420
  behind.
409
421
 
410
422
  Provider setup is the same as the [local critic](#local-critic) table
411
- (`VOLLEY_OLLAMA_URL` / `VOLLEY_LMSTUDIO_URL`, same peer dependencies). At
423
+ (`VOLLEY_OLLAMA_URL` / `VOLLEY_LMSTUDIO_URL`, or `--builder-url` for the builder
424
+ alone; same peer dependencies). At
412
425
  builder start (and before a local critic's first verdict) volley pre-loads an
413
426
  Ollama model with a load-only `/api/generate` call, so a cold multi-GB model
414
427
  load doesn't eat the first real request's time-to-first-byte budget — without
@@ -443,6 +456,44 @@ weak local model to drive a tool loop reliably has three sharp edges:
443
456
  Local providers are free, so a local builder's cost is reported as `$0.000` and
444
457
  never trips `--max-cost-usd`.
445
458
 
459
+ ### Seats on different machines
460
+
461
+ Each seat can reach its own model server, so the builder and the critic can run
462
+ on different machines even when they use the same provider. Give each seat a
463
+ URL with `--builder-url` and `--critic-url`, or in a config file:
464
+
465
+ ```ts
466
+ const config: VolleyConfig = {
467
+ // ...the task...
468
+ builder_provider: 'ollama',
469
+ builder_model: 'qwen3-coder:30b',
470
+ builder_url: 'http://localhost:11434', // this machine
471
+ critic_provider: 'ollama',
472
+ critic_model: 'qwen3:8b',
473
+ critic_url: 'http://localhost:11522', // a second machine, forwarded here
474
+ };
475
+ ```
476
+
477
+ - **Fallback.** A seat without a URL of its own uses the provider's env var,
478
+ then the default, never the other seat's URL.
479
+ - **Same rules as the env var.** Ollama's trailing `/api` is dropped. The URL
480
+ must be plain `http(s)`, with no credentials, query, or fragment. Include the
481
+ port: a URL without one goes to 80 or 443, not the provider's default.
482
+ - **`claude_cli` takes no URL.** Setting one on a `claude_cli` seat is a
483
+ configuration error (exit 5).
484
+ - **Everything a seat sends goes to its own URL.** That covers the model calls,
485
+ the Ollama prewarm and context check, and the `--dry-run` endpoint probe and
486
+ critic canary. `volley matrix` holds both URLs fixed across every pairing.
487
+
488
+ Inside the sandbox container, a loopback seat URL crosses to the host at
489
+ `VOLLEY_MODEL_HOST` the way the env var does, keeping its port. So the two seats
490
+ can be two forwarded ports on the host (`localhost:11522`, `localhost:11523`).
491
+ With the allowlist's host rules in place the container reaches only the host
492
+ gateway, so it can reach a seat on another machine only through a port forward
493
+ on the host, for example `ssh -N -L 11522:localhost:11434 gpu-box`. On a Linux
494
+ host, `host-gateway` is the Docker bridge's address, so the forward, like Ollama
495
+ itself, has to listen there rather than on `127.0.0.1` alone.
496
+
446
497
  ## What the builder changed
447
498
 
448
499
  A check that exits 0 proves the check passed. It does not prove the builder did
@@ -520,7 +571,7 @@ pnpm install
520
571
  pnpm test # vitest
521
572
  pnpm typecheck # tsc --noEmit
522
573
  pnpm check # checkride — volley dogfoods its own definition of done
523
- pnpm build # tsup → dist/
574
+ pnpm build # tsdown → dist/
524
575
  pnpm diagram # draw the flow from src/flow.ts with describe.diagram
525
576
  ```
526
577