docs: plan OpenCode SCV workers

d95e3005e659 · AtlantisPleb · · parent 6d9797158763

docs: plan OpenCode SCV workers

Deploy story

What this commit did to the running system — joined from the forge receipt chain, the part a commit page elsewhere cannot show.

Not deployed through the forge lane

No push, promotion, build, or deploy receipt references this commit (receipts are scanned over a bounded recent window). Changes shipped by full node replacement carry their proof in the release gate receipt instead.

Changed files

  • modified docs/scv-planning.md

Diff

1 file changed, +659 -42

docs/scv-planning.md modified +659 -42

@@ -2,7 +2,9 @@

2 2
3 3
Date: 2026-08-20
4 4
5
Status: Proposed architecture; implementation and autonomous deployment remain disabled
5
Status: Proposed architecture; OpenCode is the designated first execution
6
runtime and qualification workload;
7
implementation and autonomous deployment remain disabled
6 8
7 9
## Outcome
8 10

@@ -34,7 +36,9 @@ must not bypass the repository's current safety contracts:

34 36
  an SCV identity in the existing free-form `promoted_by` field and call that
35 37
  authorization.
36 38
37
The recommended first milestone is a continuously running, propose-only SCV.
39
The recommended first milestone is a continuously running, propose-only SCV
40
that uses OpenCode inside an isolated worker. Qualify the worker against the
41
OpenCode repository before using the same runtime to improve `openagents.com`.
38 42
The recommended first autonomous milestone is staging-only deployment of a
39 43
narrow, low-risk change class. Production autonomy is a later admission, not a
40 44
configuration toggle hidden inside the first release.

@@ -49,8 +53,13 @@ An SCV should:

49 53
- Read and change the exact repository that Forge recognizes as source truth.
50 54
- Use an isolated, secret-free workspace with a complete compiler and test
51 55
  toolchain.
56
- Route work to capability-described workers so an SCV can use Elixir, Bun,
57
  Node.js, Python, Rust, browser, and platform-specific toolchains without
58
  adding those runtimes to the Phoenix release.
52 59
- Preserve every model request, tool decision, command result, commit, gate,
53 60
  promotion, deployment, verification, and rollback as bounded evidence.
61
- Collect host-observed resource use, benchmark samples, and OpenCode usage
62
  statistics with enough provenance to compare equivalent runs.
54 63
- Recover after node, process, provider, and executor failures without repeating
55 64
  an uncertain external effect.
56 65
- Enforce token, cost, time, CPU, memory, disk, command, diff, commit, and

@@ -73,6 +82,8 @@ The first SCV should not:

73 82
- Modify production data, perform destructive migrations, rotate secrets,
74 83
  change billing policy, or widen an authorization boundary.
75 84
- Run several repository-writing SCVs concurrently.
85
- Treat workers with different images, resource classes, operating systems,
86
  toolchain versions, or cache states as interchangeable benchmark hosts.
76 87
- Deploy a structural or unclassified candidate automatically in the first
77 88
  autonomous release.
78 89
- Treat a passing model-authored test as sufficient evidence of correctness.

@@ -136,12 +147,21 @@ sanitized evidence and operator work

136 147
       |                    |
137 148
       | provider events    | typed executor requests
138 149
       v                    v
139
server provider adapter   isolated SCV worker
140
                            |-- exact Forge checkout
141
                            |-- bounded file tools
142
                            |-- bounded command runner
143
                            |-- disposable database and services
144
                            `-- no production secrets
150
server provider adapter   capability scheduler
151
                                   |
152
                 +-----------------+-----------------+
153
                 |                 |                 |
154
                 v                 v                 v
155
          OpenCode core      browser worker      Rust worker
156
          SCV worker         and benchmarks      and native build
157
                 |                 |                 |
158
                 +-----------------+-----------------+
159
                                   |
160
                                   |-- exact Forge checkout
161
                                   |-- bounded file tools
162
                                   |-- bounded command runner
163
                                   |-- disposable database and services
164
                                   `-- no production secrets
145 165
                                   |
146 166
                                   v
147 167
                         SCV candidate commit and push

@@ -169,10 +189,12 @@ Ecto, and supervised tasks. Do not make an external coding CLI the SCV's

169 189
authority or durable state machine.
170 190
171 191
Run candidate code and build commands in a separate SCV worker container or
172
owned worker VM. The worker may also run Elixir, but it must use a separate
173
runtime identity and mounts from the Phoenix release. This preserves the Forge
174
build-lane rule that the web release receives no compiler, Docker socket, or
175
general command-execution authority.
192
owned worker VM. Run an Elixir/OTP worker release there with a separate runtime
193
identity and mounts from the Phoenix release. Start only the worker supervision
194
tree; do not start the Phoenix endpoint, application Repo, Forge control plane,
195
or deployment coordinators. This preserves the Forge build-lane rule that the
196
web release receives no compiler, Docker socket, or general command-execution
197
authority.
176 198
177 199
The worker needs:
178 200

@@ -190,6 +212,407 @@ Candidate code is untrusted during evaluation even though the worker runs in an

190 212
owned environment. Tests and Mix tasks can execute arbitrary repository code.
191 213
Do not mount any credential that candidate code could read or transmit.
192 214
215
## OpenCode as the first execution runtime
216
217
Use OpenCode for the first end-to-end SCV worker implementation. This validates
218
non-Elixir execution, long model-driven runs, structured events, permission
219
handling, a large polyglot repository, and measurable performance work before
220
the SCV targets `openagents.com` itself.
221
222
Keep these milestones separate:
223
224
1. **Runtime qualification:** Build the OpenCode worker image, compile and test
225
   the inspected OpenCode source, exercise one bounded OpenCode session, and
226
   collect resource and benchmark evidence without pushing a candidate.
227
2. **Self-targeting proof:** Use the read-only admitted OpenCode runtime to fix
228
   a seeded OpenCode defect in the separate target checkout. Stop at a
229
   propose-only run ref.
230
3. **Product pilot:** Use the qualified OpenCode runtime to improve
231
   `openagents.com`, pass its Elixir and Forge gates, and keep promotion human
232
   controlled.
233
234
Passing runtime qualification does not admit an OpenCode candidate, and passing
235
the self-targeting proof does not authorize an `openagents.com` deployment.
236
Mirror the inspected OpenCode commit into a dedicated Forge qualification
237
repository and keep its run refs internal. Do not push a self-targeting proof to
238
the upstream OpenCode repository or treat Forge as upstream authority.
239
240
### Inspected baseline
241
242
This plan uses the OpenCode `dev` branch at commit
243
`b155b15694dbcc6768f11d2f25cc2bdd1f738ab4` as its inspected baseline. The
244
repository is a Bun-first TypeScript monorepo, not a generic Node.js project.
245
Its relevant contracts include:
246
247
- Bun `1.3.14` from the root `packageManager` declaration;
248
- Node.js 24 in continuous integration, with Node.js `24.15` used for the
249
  Playwright path because the repository records a Chromium extraction issue
250
  with the next patch release;
251
- Ubuntu 24.04 for the primary Linux test environment;
252
- Python 3 and `setuptools` for dependency compatibility;
253
- native build tools, `pkg-config`, Git, OpenSSH client, `curl`, certificates,
254
  `jq`, `ripgrep`, `unzip`, `xz-utils`, and `zip`;
255
- package-scoped tests and type checks, because the root test configuration
256
  intentionally refuses test execution;
257
- Rust stable for native and desktop work, plus GTK, WebKit, and Tauri system
258
  packages for Linux desktop builds;
259
- Playwright Chromium and its system dependencies for application end-to-end
260
  and performance work;
261
- Windows and macOS runners for complete platform and release coverage.
262
263
OpenCode already publishes Linux container layers for a base toolchain,
264
Bun plus Node.js, Rust, Tauri Linux, and publishing. Reuse their pinned versions
265
as input evidence, but build and sign SCV-owned images. Do not trust a mutable
266
tag or let repository code select the worker image.
267
268
### Trust boundary
269
270
OpenCode is an execution runtime inside a worker. It is not the SCV coordinator,
271
lease authority, policy engine, receipt store, or promotion authority. The
272
Elixir control plane owns those responsibilities even when OpenCode manages the
273
model and tool loop for one run.
274
275
When an SCV works on OpenCode, keep two separate copies:
276
277
- Install the admitted OpenCode runtime under a read-only path such as
278
  `/opt/scv/opencode/bin/opencode`. Bind its version to the worker image digest.
279
- Check out the target OpenCode SHA under the disposable writable workspace.
280
  Treat every file and executable produced there as candidate code.
281
282
The target checkout must not replace the admitted runtime during a run. A gate
283
may build and execute the candidate OpenCode binary as an untrusted test
284
artifact, but that binary cannot control the run, approve permissions, write
285
receipts, or evaluate its own gate.
286
287
### First worker image
288
289
Build `scv-opencode-core` before creating generic language images. The image is
290
the first executable SCV milestone and should contain:
291
292
| Layer | Pinned contents |
293
| --- | --- |
294
| Operating system | Ubuntu 24.04 for parity with OpenCode's primary Linux tests |
295
| JavaScript runtimes | Bun `1.3.14` baseline build, Node.js `24.15`, and Corepack |
296
| Native support | Python 3, `setuptools`, `build-essential`, `pkg-config`, `libgcc`, and `libstdc++` |
297
| Repository tools | Git, OpenSSH client without credentials, `curl`, certificates, `jq`, `ripgrep`, `unzip`, `xz-utils`, and `zip` |
298
| SCV runtime | A self-contained Elixir/OTP worker release with ERTS, a pinned read-only OpenCode binary, and cgroup and process-tree measurement support |
299
| Runtime identity | An unprivileged UID, empty home and XDG roots per execution, a read-only root filesystem, and a bounded writable workspace and cache |
300
301
Do not include Chromium, Rust, a Docker daemon or socket, a cloud CLI,
302
credential helpers, an SSH agent, or production credentials in this first
303
image. Build dependencies while the image build has admitted network access.
304
Run candidate commands without general network access.
305
306
Address the image by its manifest digest. Produce an SBOM and record the source
307
SHA, Dockerfile digest, base image digest, OpenCode version, package-manager
308
lock digest, toolchain versions, and build receipt. Forge should admit that
309
manifest before any worker registers with it.
310
311
Use a multi-stage build. Compile the minimal SCV worker release and the admitted
312
OpenCode binary in build stages, then copy their immutable artifacts into the
313
final toolchain image. Do not copy source credentials, package-manager tokens,
314
Hex state, SSH state, or build-stage homes into the final image. The worker
315
release should spawn OpenCode and language tools as contained OS processes and
316
remain the parent authority for deadlines, cancellation, output bounds, and
317
receipts.
318
319
### Worker image family
320
321
Use additional images only when the work item requires their capabilities:
322
323
| Worker image | Adds | Intended work |
324
| --- | --- | --- |
325
| `scv-opencode-core` | Bun, Node.js, Python, native build tools, and the admitted OpenCode runtime | OpenCode CLI and server changes, unit tests, type checks, source benchmarks, and most TypeScript work |
326
| `scv-opencode-browser` | Playwright Chromium, browser system libraries, and production application assets | Application end-to-end tests, trace capture, and UI performance benchmarks |
327
| `scv-opencode-rust` | A pinned stable minimal Rust toolchain | Rust crates, native helpers, and cross-language changes |
328
| `scv-opencode-tauri-linux` | GTK, WebKit, librsvg, Tauri prerequisites, and packaging utilities | Linux desktop compilation and packaging |
329
| Platform workers | Native Windows or macOS environment with the same SCV protocol | Platform behavior and release evidence that Linux cannot prove |
330
331
Derive later `scv-node`, `scv-python`, and `scv-rust` images from the same worker
332
contract. A new language requires an image and capability manifest, not a new
333
privilege in the Phoenix release.
334
335
Use this initial artifact layout when implementation starts:
336
337
```text
338
ops/scv/images/opencode-core/Dockerfile
339
ops/scv/images/opencode-browser/Dockerfile
340
ops/scv/images/opencode-rust/Dockerfile
341
ops/scv/images/opencode-tauri-linux/Dockerfile
342
ops/scv/images/versions.env
343
ops/scv/worker/entrypoint.sh
344
```
345
346
Keep versions and expected digests in an operator-owned manifest. The
347
entrypoint may start only the compiled worker release. It must not interpret
348
repository input or construct a shell command.
349
350
### OpenCode execution adapter
351
352
Implement `OpenAgents.SCV.Executor.OpenCode` behind the generic executor
353
protocol. Start with one admitted OpenCode process per run:
354
355
1. Create isolated `HOME`, `XDG_CONFIG_HOME`, `XDG_DATA_HOME`,
356
   `XDG_STATE_HOME`, and `XDG_CACHE_HOME` directories.
357
2. Generate operator-owned OpenCode configuration through
358
   `OPENCODE_CONFIG_CONTENT` and record its redacted digest.
359
3. Start `opencode run --format json` with the admitted model, directory, and
360
   bounded prompt.
361
4. Parse JSON events as nested observational records under one outer SCV
362
   execution step.
363
5. Mark the outer step uncertain and discard its workspace if OpenCode exits
364
   without a terminal event. Do not infer which internal tool effects finished.
365
6. Cancel the entire process tree when the lease, generation, deadline, budget,
366
   or operator state changes.
367
7. Reconcile the OpenCode session ID and local database at termination, retain
368
   admitted artifacts, and destroy the run home.
369
370
Do not use `--auto`, `--yolo`, or `--dangerously-skip-permissions`. Those modes
371
bypass the permission boundary that an SCV needs to test. A later adapter may
372
run `opencode serve` inside each worker for durable multi-turn sessions. Bind it
373
to loopback, require a random `OPENCODE_SERVER_PASSWORD`, keep the password in
374
the sidecar, and address sessions by their recorded OpenCode session IDs.
375
376
The native JSON stream provides useful visibility, but it cannot prove that the
377
SCV persisted each tool request before OpenCode executed it. Treat the first
378
compatibility run as one coarse, disposable effect. Before crash-resumable
379
candidate construction, add an SCV-specific OpenCode tool transport that:
380
381
1. Disables OpenCode's direct edit and command execution for SCV sessions.
382
2. Sends each typed tool request, session ID, run generation, and idempotency
383
   key to the sidecar.
384
3. Persists the requested `scv_step` before the sidecar acknowledges it.
385
4. Executes the request in the credential-free candidate compartment after
386
   policy and generation checks pass.
387
5. Returns a signed, digest-addressed result that OpenCode can use as its tool
388
   output.
389
6. Resolves retries from the committed step instead of repeating the effect.
390
391
Implement this transport as a narrow OpenCode integration or admitted patch,
392
not by parsing terminal output and reconstructing tool calls afterward. Keep
393
OpenCode's SDK, server event stream, session API, and permission API available
394
for session control, but do not confuse those APIs with the durable effect
395
barrier.
396
397
OpenCode project configuration, plugins, Model Context Protocol servers,
398
skills, instructions, and language-server downloads are executable or
399
instruction-bearing repository inputs. The first adapter should disable
400
automatic project configuration and downloads with
401
`OPENCODE_DISABLE_PROJECT_CONFIG=1` and
402
`OPENCODE_DISABLE_LSP_DOWNLOAD=1`. Resolve `AGENTS.md` and other required
403
repository instructions separately, admit their exact digests, and pass their
404
bounded content as evidence. Enable a project feature only after the host
405
policy classifies and receipts it.
406
407
Configure OpenCode permissions explicitly. Start from deny and admit only the
408
read, list, search, workspace edit, and structured command operations that the
409
current phase needs. Pass the operator-owned rule set through
410
`OPENCODE_PERMISSION` and record its digest. OpenCode's permission result is one
411
input to enforcement; the outer worker namespace, filesystem mounts, command
412
policy, cgroup, and network policy remain authoritative.
413
414
### Provider credentials
415
416
Give OpenCode a short-lived, run-scoped inference grant for an
417
OpenAI-compatible internal endpoint. Bind it to the SCV ID, run ID, admitted
418
model set, request count, token budget, cost budget, expiry, and worker
419
generation. Never place a reusable provider key in the image or workspace.
420
421
OpenCode normally launches tool processes beneath itself. Assume those child
422
processes can inspect the OpenCode environment until isolation proves
423
otherwise. The first experiment may use only a disposable, tightly budgeted
424
grant with no authority outside inference. It does not satisfy the final
425
credential-isolation requirement.
426
427
Before an SCV receives autonomous write or deployment authority, separate the
428
OpenCode model process from candidate command execution. Route tool requests
429
through the sidecar into a credential-free execution compartment. Keep the
430
inference grant in the model compartment or authenticate to a local inference
431
proxy through an out-of-band worker identity. Prove that candidate code cannot
432
read, reuse, or transmit the grant.
433
434
### First OpenCode validation run
435
436
Use a fixed workload against the inspected baseline before admitting arbitrary
437
OpenCode work:
438
439
1. Build and admit `scv-opencode-core` by digest.
440
2. Import the exact OpenCode baseline into the dedicated Forge qualification
441
   repository and verify its object and WAL receipts.
442
3. Check out the exact OpenCode baseline in a clean disposable workspace.
443
4. Verify the Bun, Node.js, Python, Git, and admitted OpenCode versions.
444
5. Run `bun install --frozen-lockfile` and record cold-cache and warm-cache
445
   receipts.
446
6. Run `bun typecheck` and `bun test --timeout 30000 --only-failures` from
447
   `packages/opencode`.
448
7. Run `bun run test:httpapi` from `packages/opencode` on the core worker.
449
8. Run `bun run bench:test` from `packages/opencode`, first with one measured
450
   run and then with explicit `BENCH_WARMUPS` and `BENCH_RUNS` values.
451
9. Run `bun run profile:test` from `packages/opencode` with explicit
452
   `TEST_PROFILE_GLOB`, `TEST_PROFILE_LIMIT`, `TEST_PROFILE_TIMEOUT`, and
453
   `TEST_PROFILE_TOP` values.
454
10. Start one bounded `opencode run --format json` session, exercise admitted
455
    read and command operations, and prove every permission denial and event
456
    reaches the SCV receipt chain.
457
11. Cancel a second run at each external boundary and prove generation fencing,
458
    process-tree termination, and workspace cleanup.
459
460
Run the browser performance suite only on `scv-opencode-browser`. Run it
461
serially against a production build, preserve the emitted `BENCHMARK` and
462
`BENCHMARK_PAGE` JSON records, and retain optional Chrome trace artifacts by
463
digest. Invoke `bun run test:bench` from `packages/app`. Use
464
`bun run test:e2e:local` from the same package for the normal end-to-end gate.
465
Do not make Rust, Tauri, Windows, or macOS gates mandatory for a change that
466
does not reach those surfaces.
467
468
The first improvement candidate should fix a seeded, reproducible OpenCode
469
defect or performance regression with an existing or independently authored
470
test. Keep the candidate propose-only. This proves the worker and evidence
471
system before any Forge deployment path opens.
472
473
## Worker pool and capability routing
474
475
Run multiple workers under one Elixir scheduler. Each worker registers an
476
operator-admitted capability manifest containing:
477
478
- worker image and SBOM digests;
479
- operating system, architecture, and resource class;
480
- CPU count or admitted CPU class, memory and disk limits, and process limit;
481
- runtime, compiler, package-manager, browser, and OpenCode versions;
482
- supported command and network profiles;
483
- benchmark isolation and tracing capabilities;
484
- current state: `starting`, `ready`, `busy`, `draining`, `unhealthy`, or
485
  `offline`.
486
487
The scheduler matches a work item's required capabilities to an exact manifest.
488
It must not infer compatibility from a worker name. A worker claims one
489
execution lease with the current run generation, heartbeats while active, and
490
rejects stale or duplicate requests. Draining prevents new claims without
491
interrupting an admitted execution.
492
493
Keep one repository writer per integration history. Multiple workers may run
494
read-only investigation, exact-SHA tests, benchmarks, or independent evaluation
495
in parallel against immutable checkouts. Candidate-affecting results must bind
496
to one exact SHA. A parallel result from an older SHA becomes evidence for a
497
later decision; it cannot silently update the active candidate.
498
499
Separate the logical SCV run from its worker executions. One run may dispatch a
500
core type check, browser benchmark, and Rust gate to different workers while
501
the coordinator retains the run lease and joins their immutable receipts.
502
Cancel or supersede each execution independently when its result is no longer
503
needed.
504
505
### Worker protocol
506
507
Use a versioned, language-neutral protocol so Linux containers, owned virtual
508
machines, and native Windows or macOS workers implement the same boundary. Do
509
not require a remote worker to join the BEAM cluster.
510
511
The protocol needs these operations:
512
513
- register an admitted image and capability manifest;
514
- heartbeat, renew an execution claim, and report health;
515
- claim the next compatible execution with its run generation;
516
- acknowledge a requested step only after the control plane persists it;
517
- stream bounded progress and host-observed measurements;
518
- publish a terminal receipt and artifact digests;
519
- cancel one execution or all executions for a run generation;
520
- drain, retire, and reject an image.
521
522
Authenticate workers with an SCV-specific machine identity over mutually
523
authenticated transport. Bind every message to the SCV ID, run ID, execution
524
ID, generation, protocol revision, and idempotency key. Sign or MAC terminal
525
receipts and verify them before the coordinator changes durable state.
526
527
Let workers pull compatible work instead of accepting arbitrary commands on a
528
general remote-execution port. The control plane stores the request before it
529
becomes claimable. Large source bundles, logs, traces, and profiles move through
530
digest-addressed artifact storage; protocol messages carry bounded metadata and
531
artifact refs. Use `Req` for the Elixir HTTP client if the first protocol uses
532
HTTPS. Keep transport selection behind the protocol behavior so an admitted
533
queue can replace HTTPS without changing run semantics.
534
535
## Resource, benchmark, and statistics evidence
536
537
Measure candidate processes from outside their namespace. OpenCode output and
538
repository benchmark scripts provide domain metrics, but only the worker host
539
can provide authoritative resource use.
540
541
### Execution measurements
542
543
Record these values for each structured command and aggregate them for the run:
544
545
- monotonic start and finish times, wall duration, exit status, signal, retry,
546
  and cancellation reason;
547
- user and system CPU time, allocated CPU class, throttled CPU time, and
548
  throttling count;
549
- current and peak memory, swap use, page faults, and out-of-memory events;
550
- filesystem bytes read and written, workspace and cache size, disk peak, and
551
  inode use;
552
- process and thread peak, descendant count, and leaked-process findings;
553
- network bytes, destination classes, and denied connection count;
554
- standard output and error bytes, retained bytes, truncation, and artifact
555
  digests;
556
- cold, warm, or disabled cache state and relevant cache digests.
557
558
Collect cgroup or container-runtime counters before cleanup. Sample long
559
commands at a bounded interval and store a compact time series outside the
560
workspace. Candidate code cannot write or amend these measurements.
561
562
### OpenCode usage measurements
563
564
Normalize OpenCode JSON events into SCV metrics for:
565
566
- session, provider, and model IDs;
567
- model requests, retries, time to first event, and total completion time;
568
- input, output, reasoning, cache-read, and cache-write tokens;
569
- estimated and provider-reconciled cost;
570
- tool calls by type, duration, result, output size, and permission decision;
571
- changed files, added and removed lines, commands, checkpoints, compactions,
572
  and terminal reason.
573
574
OpenCode's `stats` command aggregates sessions, messages, token classes, cost,
575
tool use, model use, date range, cost per day, tokens per session, and median
576
tokens per session from its local SQLite data. Import that result only as
577
reconciliation evidence. SCV step receipts and the inference ledger remain the
578
usage authority because a candidate can influence the local OpenCode store.
579
580
### Benchmark receipts
581
582
Store every benchmark as a definition plus immutable samples. A definition
583
includes the repository SHA, worker image digest, resource class, operating
584
system and architecture, toolchain versions, command profile, dataset or
585
fixture digest, cache policy, warmup count, measured run count, timeout, and
586
environment digest.
587
588
A sample stores its raw metric records and artifacts plus normalized values.
589
Summaries may report minimum, maximum, mean, median, and percentiles only when
590
the sample count supports them. Keep failed and cancelled samples; removing
591
them biases the result.
592
593
For OpenCode, ingest:
594
595
- `METRIC test_suite_seconds`, `test_suite_best_seconds`, and
596
  `test_suite_worst_seconds` from `bench:test`;
597
- per-file timings, `slowest_test_file_seconds`, and `profiled_test_files` from
598
  `profile:test`;
599
- application `BENCHMARK` and `BENCHMARK_PAGE` JSON lines;
600
- Chrome Performance traces and any admitted CPU or visual profiles;
601
- SCV host measurements for the same processes.
602
603
Compare a candidate with its recorded base only when the worker image, resource
604
class, operating system, architecture, toolchains, benchmark definition, cache
605
policy, and isolation level match. Otherwise mark the comparison
606
`not_comparable`. Use medians from repeated runs for performance decisions.
607
Keep correctness gates separate from performance evidence, and do not create
608
machine-dependent pass thresholds for OpenCode's browser benchmarks.
609
610
Reserve the benchmark worker exclusively for a comparison window. Run base and
611
candidate samples on the same worker when possible, alternate their order, and
612
record thermal, throttling, memory-pressure, and background-load invalidation
613
signals. Do not publish an improvement when environmental noise exceeds the
614
definition's admitted envelope.
615
193 616
## Durable execution model
194 617
195 618
An SCV remains logically active while its work occurs in bounded runs. The

@@ -359,7 +782,9 @@ they fit. Add SCV-specific tools for:

359 782
- file creation, deletion, and rename with path and byte bounds;
360 783
- focused test discovery and execution;
361 784
- Mix help and admitted Mix tasks;
362
- JavaScript tests through the repository's pinned package command;
785
- OpenCode runs through the admitted OpenCode adapter;
786
- repository-defined Bun, Node.js, Python, Rust, browser, and Mix commands
787
  through capability-specific profiles;
363 788
- formatting and final diff inspection;
364 789
- checkpoint and candidate submission.
365 790

@@ -372,7 +797,7 @@ work. Use policy profiles instead:

372 797
373 798
- A read profile admits bounded Git and source-inspection commands.
374 799
- A focused-test profile admits exact repository-owned test entry points and
375
  Mix tasks after validating their options.
800
  repository tasks after validating their options.
376 801
- A candidate-gate profile admits only the immutable gate definition.
377 802
- A networked profile remains disabled in the first release.
378 803

@@ -422,6 +847,7 @@ Store one bounded execution episode:

422 847
- SCV, work item, base SHA, integration WAL position, and generation;
423 848
- program, policy, tool-catalog, evaluator, and gate digests;
424 849
- model and provider adapter IDs;
850
- requested worker capabilities, benchmark definitions, and comparison base;
425 851
- phase and terminal status;
426 852
- token, cost, tool, command, time, CPU, memory, disk, and diff usage;
427 853
- structured checkpoint and bounded report;

@@ -442,6 +868,71 @@ Store large input and output only in a bounded, access-controlled artifact

442 868
store when diagnosis requires it. Database rows should contain redacted
443 869
excerpts and digests.
444 870
871
### `scv_worker_images`
872
873
Store admitted immutable worker manifests:
874
875
- image, SBOM, Dockerfile, base image, source, and build receipt digests;
876
- operating system, architecture, toolchains, OpenCode runtime, and supported
877
  capability names;
878
- default resource bounds and permitted command and network profiles;
879
- admission, retirement, and vulnerability-review state;
880
- creation and immutable admission timestamps.
881
882
### `scv_workers`
883
884
Store the current worker registration and lease surface:
885
886
- stable worker ID, admitted image ID, resource class, and capabilities digest;
887
- state, health, drain request, and last heartbeat;
888
- current execution, run generation, claim expiry, and coordinator owner;
889
- boot identity and monotonic registration generation;
890
- bounded health details without hostnames, credentials, or internal addresses
891
  in operator projections.
892
893
### `scv_executions`
894
895
Store one dispatch to one worker:
896
897
- run, step, worker image, required capabilities, and exact repository SHA;
898
- execution generation, idempotency key, claim, start, heartbeat, cancellation,
899
  and terminal timestamps;
900
- command profile and redacted environment digest;
901
- exit, signal, timeout, cancellation, and uncertainty result;
902
- resource summary, output, event stream, and artifact refs.
903
904
### `scv_benchmark_definitions`
905
906
Store the admitted comparison contract:
907
908
- stable name and revision;
909
- repository paths, structured commands, metric parsers, fixture digests, and
910
  required capabilities;
911
- warmup, repetition, serial-execution, cache, timeout, and tracing rules;
912
- normalized metric names, units, direction, and decision policy;
913
- operator admission and immutable definition digest.
914
915
### `scv_benchmark_runs` and `scv_benchmark_samples`
916
917
Store the benchmark execution and its samples:
918
919
- definition, base or candidate SHA, worker image, resource class, toolchain,
920
  cache, and environment digests;
921
- sample ordinal, warmup flag, status, raw metric refs, normalized metrics, and
922
  host resource summary;
923
- aggregate statistics, comparison result, confidence policy, and
924
  `not_comparable` reasons;
925
- retained trace, profile, and diagnostic artifact refs.
926
927
### `scv_resource_samples`
928
929
Store compact host-observed measurements for long executions:
930
931
- execution ID, monotonic offset, and sample interval;
932
- CPU, throttling, memory, swap, filesystem, process, and network counters;
933
- cgroup or runtime source and collection error;
934
- immutable sample and summary digests.
935
445 936
### `scv_candidates`
446 937
447 938
Store the immutable candidate decision:

@@ -543,8 +1034,10 @@ Run checks in increasing order of cost and stop on the first failure:

543 1034
2. Validate changed paths, diff bounds, generated artifacts, and protected
544 1035
   surfaces.
545 1036
3. Run formatting and focused regression tests.
546
4. Run compile with warnings as errors.
547
5. Run `mix precommit`.
1037
4. Run the repository's admitted compile or type-check profile with warnings as
1038
   errors where the toolchain supports it.
1039
5. Run the repository's final precommit profile. Use `mix precommit` for
1040
   `openagents.com` and the exact package-scoped Bun gates for OpenCode.
548 1041
6. Commit and push the exact candidate SHA.
549 1042
7. Run the required exact-SHA release gate in a fresh checkout.
550 1043
8. Verify that the gate definition digest matches the base policy.

@@ -561,7 +1054,8 @@ For a low-risk automatic candidate, require all of these facts:

561 1054
- the candidate descends from the admitted integration head;
562 1055
- focused tests prove the reported defect or improvement;
563 1056
- no protected surface changed;
564
- `mix precommit` passes without retries or modified thresholds;
1057
- the repository's admitted final gate passes without retries or modified
1058
  thresholds;
565 1059
- the exact-SHA gate passes in the trusted evaluator;
566 1060
- Forge independently classifies the complete candidate as `direct_candidate`;
567 1061
- every changed runtime module matches the narrower SCV allowlist and Forge's

@@ -791,9 +1285,13 @@ Add an operator-only SCV surface with stable IDs and bounded projections. Show:

791 1285
  head;
792 1286
- active and recent work items, runs, candidates, and budgets;
793 1287
- current phase, elapsed time, and cancellation state;
1288
- worker pool health, admitted image digests, capabilities, resource classes,
1289
  active executions, queue pressure, and drain state;
794 1290
- changed paths and diff summary after a candidate exists;
795 1291
- focused tests, exact-SHA gate, Forge build, target, deployment, and observation
796 1292
  receipts;
1293
- resource summaries, comparable benchmark results, OpenCode usage totals, and
1294
  retained trace or profile refs;
797 1295
- terminal result, rollback state, and circuit reason;
798 1296
- **Pause**, **Resume**, **Cancel run**, **Reject candidate**, **Require human
799 1297
  review**, and **Open diff** controls.

@@ -808,6 +1306,9 @@ Emit content-free telemetry for:

808 1306
- work discovery and admission;
809 1307
- run, provider, tool, and command duration;
810 1308
- token and cost use;
1309
- worker claims, queue time, utilization, health, resource use, and out-of-memory
1310
  results;
1311
- benchmark samples, comparison eligibility, regressions, and improvements;
811 1312
- candidate refusal reasons;
812 1313
- gate and build outcomes;
813 1314
- promotion, deploy, observation, and rollback results;

@@ -820,14 +1321,25 @@ Add typed, fail-closed settings such as:

820 1321
```text
821 1322
OPENAGENTS_FEATURE_SCV
822 1323
OPENAGENTS_SCV_MODE=observe|propose|staging_auto|production_auto
823
OPENAGENTS_SCV_REPOSITORIES=openagents.com
1324
OPENAGENTS_SCV_REPOSITORIES=anomalyco/opencode
824 1325
OPENAGENTS_SCV_PROGRAM_REVISION=<revision>
825 1326
OPENAGENTS_SCV_POLICY_REVISION=<revision>
1327
OPENAGENTS_SCV_PROCESS_ROLE=coordinator|worker
826 1328
OPENAGENTS_SCV_EXECUTOR=<adapter>
827 1329
OPENAGENTS_SCV_EXECUTOR_QUEUE_DIR=<absolute-path>
828 1330
OPENAGENTS_SCV_WORKSPACE_DIR=<absolute-path>
1331
OPENAGENTS_SCV_WORKER_IMAGES=<admitted-manifest-digests>
1332
OPENAGENTS_SCV_OPENCODE_IMAGE=<admitted-manifest-digest>
1333
OPENAGENTS_SCV_MAX_WORKERS=<bounded-integer>
829 1334
OPENAGENTS_SCV_MAX_ACTIVE_RUNS=1
1335
OPENAGENTS_SCV_MAX_ACTIVE_REPOSITORY_WRITERS=1
1336
OPENAGENTS_SCV_WORKER_CPU=<bounded-resource-class>
1337
OPENAGENTS_SCV_WORKER_MEMORY_BYTES=<bounded-integer>
1338
OPENAGENTS_SCV_WORKER_DISK_BYTES=<bounded-integer>
1339
OPENAGENTS_SCV_RESOURCE_SAMPLE_MS=<bounded-integer>
830 1340
OPENAGENTS_SCV_RUN_TIMEOUT_MS=<bounded-integer>
1341
OPENAGENTS_SCV_BENCHMARK_RETENTION_MS=<bounded-integer>
1342
OPENAGENTS_SCV_ARTIFACT_RETENTION_MS=<bounded-integer>
831 1343
OPENAGENTS_SCV_DAILY_TOKEN_BUDGET=<bounded-integer>
832 1344
OPENAGENTS_SCV_DAILY_COST_MICROUSD=<bounded-integer>
833 1345
OPENAGENTS_SCV_DAILY_DEPLOYMENTS=<bounded-integer>

@@ -838,11 +1350,19 @@ OPENAGENTS_SCV_OBSERVATION_MS=<bounded-integer>

838 1350
The runtime boundary should reject:
839 1351
840 1352
- any enabled mode without admitted program and policy digests;
1353
- a worker whose image, SBOM, capability, or command-profile digest is not
1354
  admitted;
1355
- an OpenCode adapter without an admitted OpenCode image and explicit
1356
  permissions;
1357
- a worker process role that also starts the Phoenix endpoint, application
1358
  Repo, Forge control plane, or deployment coordinators;
841 1359
- an executor path under `/tmp` in staging or production;
842 1360
- an automatic mode before Forge deployment, boot convergence, durable
843 1361
  artifacts, and isolated staging are enabled;
844 1362
- `production_auto` while production deployment remains globally disabled;
845 1363
- multiple active runs in the first policy revision;
1364
- multiple repository writers for one integration history;
1365
- a benchmark comparison across incompatible provenance;
846 1366
- a deployment budget without an observation window and rollback authority;
847 1367
- an SCV repository that is absent from the configured Forge repositories.
848 1368

@@ -861,6 +1381,16 @@ lib/openagents/scv/work_item.ex

861 1381
lib/openagents/scv/run.ex
862 1382
lib/openagents/scv/step.ex
863 1383
lib/openagents/scv/candidate.ex
1384
lib/openagents/scv/worker_image.ex
1385
lib/openagents/scv/worker.ex
1386
lib/openagents/scv/worker_supervisor.ex
1387
lib/openagents/scv/worker_client.ex
1388
lib/openagents/scv/worker_runner.ex
1389
lib/openagents/scv/execution.ex
1390
lib/openagents/scv/benchmark_definition.ex
1391
lib/openagents/scv/benchmark_run.ex
1392
lib/openagents/scv/benchmark_sample.ex
1393
lib/openagents/scv/resource_sample.ex
864 1394
lib/openagents/scv/program.ex
865 1395
lib/openagents/scv/policy.ex
866 1396
lib/openagents/scv/change_classifier.ex

@@ -872,8 +1402,12 @@ lib/openagents/scv/provider_loop.ex

872 1402
lib/openagents/scv/tool_catalog.ex
873 1403
lib/openagents/scv/workspace.ex
874 1404
lib/openagents/scv/executor.ex
1405
lib/openagents/scv/executor/open_code.ex
875 1406
lib/openagents/scv/executor/sidecar.ex
876 1407
lib/openagents/scv/executor_protocol.ex
1408
lib/openagents/scv/worker_scheduler.ex
1409
lib/openagents/scv/resource_collector.ex
1410
lib/openagents/scv/benchmark_parser.ex
877 1411
lib/openagents/scv/gate.ex
878 1412
lib/openagents/scv/promoter.ex
879 1413
lib/openagents/scv/observer.ex

@@ -901,11 +1435,13 @@ candidate, which changes can qualify, and how the operator stops the system.

901 1435
902 1436
### Phase 1: Observe and queue
903 1437
904
1. Add SCV, work-item, run, step, and candidate schemas with database guards.
1438
1. Add SCV, work-item, run, step, candidate, worker, execution, resource, and
1439
   benchmark schemas with database guards.
905 1440
2. Add the coordinator, lease, budgets, recovery, pause, and circuit state.
906 1441
3. Ingest operator work items and sanitized owned-gate failures.
907 1442
4. Run selection and planning without repository writes.
908
5. Add the operator surface and content-free telemetry.
1443
5. Add the capability scheduler, worker registration, operator surface, and
1444
   content-free telemetry without starting candidate commands.
909 1445
910 1446
**Exit criteria:** An SCV runs continuously in `observe` mode, survives process
911 1447
and node loss, deduplicates work, spends within budget, and performs no external

@@ -913,28 +1449,59 @@ effect.

913 1449
914 1450
### Phase 2: Build candidates
915 1451
916
1. Add the isolated executor protocol and worker.
917
2. Add exact Forge checkout, workspace confinement, SCV tools, command profiles,
918
   and candidate-code sandboxing.
919
3. Add focused tests, commit resolution, run-ref push, WAL receipt linking, and
1452
1. Build and admit `scv-opencode-core` by digest before any generic language
1453
   worker.
1454
2. Add the isolated executor protocol, OpenCode adapter, capability scheduler,
1455
   worker leases, and resource collector.
1456
3. Add exact Forge checkout, workspace confinement, the durable OpenCode tool
1457
   transport, SCV tools, OpenCode event receipts, command profiles, and
1458
   candidate-code sandboxing.
1459
4. Register multiple `scv-opencode-core` workers, but retain one repository
1460
   writer for the OpenCode integration history.
1461
5. Run the fixed OpenCode validation workload, ingest its native benchmarks,
1462
   and prove credential, permission, cancellation, and generation boundaries.
1463
6. Add focused tests, commit resolution, run-ref push, WAL receipt linking, and
920 1464
   cleanup.
921
4. Keep every candidate propose-only.
1465
7. Keep every candidate propose-only.
922 1466
923
**Exit criteria:** An SCV can reproduce, test, patch, commit, and push a bounded
924
candidate. Crash tests prove that no uncertain push or command becomes success.
1467
**Exit criteria:** An SCV can use OpenCode internally to reproduce, test, patch,
1468
commit, and push a bounded OpenCode candidate. Multiple workers can execute
1469
exact-SHA read and gate work without creating multiple writers. Resource and
1470
benchmark receipts remain complete across crash tests, and no uncertain push
1471
or command becomes success.
925 1472
926
### Phase 3: Gate and review
1473
### Phase 3: Qualify and review OpenCode
927 1474
928 1475
1. Add the independent change classifier and protected-surface enforcement.
929
2. Add immutable focused-test, `mix precommit`, exact-SHA release-gate, and
930
   evaluator receipts.
1476
2. Add immutable focused-test, repository precommit, exact-SHA release-gate,
1477
   benchmark, and evaluator receipts.
1478
3. Run the OpenCode runtime qualification and self-targeting proof against the
1479
   inspected baseline.
1480
4. Add human review from the SCV candidate surface without a deployment action.
1481
5. Reconstruct the complete chain from work evidence through OpenCode session,
1482
   worker executions, resource samples, candidate push, exact-SHA gate, and
1483
   benchmark comparison.
1484
1485
**Exit criteria:** A human can review a propose-only OpenCode candidate with all
1486
evidence visible. The admitted OpenCode runtime remains separate from the
1487
candidate checkout, and every refused class stops before source admission.
1488
1489
### Phase 4: Pilot `openagents.com`
1490
1491
1. Build and admit an `scv-openagents` capability image with the repository's
1492
   pinned Elixir, Erlang, Mix, asset, database, and test toolchains. Keep the
1493
   admitted OpenCode runtime as the model and tool-loop process.
1494
2. Run the fixed fixture defect through focused tests, `mix precommit`, the
1495
   exact-SHA release gate, and independent policy evaluation.
931 1496
3. Add human promotion from the SCV candidate surface.
932
4. Reconstruct the complete chain from work evidence to Forge deploy receipt.
1497
4. Reconstruct the complete chain from work evidence to the Forge deploy and
1498
   observation receipts.
933 1499
934
**Exit criteria:** A human can review and promote a low-risk SCV candidate with
935
all evidence visible, and every refused class stops before promotion.
1500
**Exit criteria:** A human can review and promote a low-risk
1501
`openagents.com` candidate with all evidence visible, and every refused class
1502
stops before promotion.
936 1503
937
### Phase 4: Automate isolated staging
1504
### Phase 5: Automate isolated staging
938 1505
939 1506
Start only after ADR 0007's Forge-canonical cutover and the isolated staging
940 1507
deployment gates pass.

@@ -951,7 +1518,7 @@ deployment gates pass.

951 1518
failure cases without mixed revisions, lost commits, unreceipted effects, or
952 1519
continued deployment after rollback.
953 1520
954
### Phase 5: Expand admitted scope
1521
### Phase 6: Expand admitted scope
955 1522
956 1523
Expand one independent policy revision at a time. Possible later admissions
957 1524
include broader direct-load modules, source-only integration, relup candidates,

@@ -983,6 +1550,24 @@ successful staging SCV.

983 1550
  cloud, or user credential.
984 1551
- Prove network and environment profiles fail closed.
985 1552
- Prove cancellation terminates descendant processes and cleans the workspace.
1553
- Prove the target checkout cannot change the admitted OpenCode runtime.
1554
- Prove OpenCode home and XDG data never cross run or worker boundaries.
1555
- Prove candidate commands cannot read or reuse the inference grant before
1556
  enabling autonomous authority.
1557
1558
### Workers and scheduling
1559
1560
- Refuse unadmitted image, SBOM, capability, resource, and command-profile
1561
  digests.
1562
- Match every execution to its required operating system, architecture,
1563
  toolchain, browser, and tracing capabilities.
1564
- Prove worker heartbeat expiry and drain behavior cannot duplicate an
1565
  execution.
1566
- Run read-only exact-SHA executions on multiple workers while one writer owns
1567
  the integration history.
1568
- Supersede late results from an older candidate without rewriting their
1569
  immutable receipts.
1570
- Prove a platform-specific gate never runs on an incompatible worker.
986 1571
987 1572
### Model and tools
988 1573

@@ -993,6 +1578,22 @@ successful staging SCV.

993 1578
- Force a bounded report on token, continuation, command, and wall-clock limits.
994 1579
- Run adversarial repository text that asks an SCV to expose secrets, weaken
995 1580
  gates, expand authority, or deploy directly.
1581
- Refuse OpenCode automatic-permission flags, project plugins, unadmitted Model
1582
  Context Protocol servers, and automatic language-server downloads.
1583
- Reconcile OpenCode session statistics against SCV steps and the inference
1584
  ledger without trusting the local SQLite store as authority.
1585
1586
### Resources and benchmarks
1587
1588
- Compare cgroup or runtime CPU, memory, disk, process, and network summaries
1589
  with known fixture workloads.
1590
- Prove candidate code cannot amend host-observed resource samples.
1591
- Parse OpenCode `METRIC`, `BENCHMARK`, and `BENCHMARK_PAGE` records and retain
1592
  raw artifacts by digest.
1593
- Refuse comparisons when image, resource class, platform, toolchain, benchmark
1594
  definition, cache policy, or isolation differs.
1595
- Retain failed, cancelled, timed-out, and out-of-memory samples.
1596
- Prove benchmark processes run serially when the definition requires it.
996 1597
997 1598
### Change policy
998 1599

@@ -1031,7 +1632,7 @@ Create a fixture defect with a stable failing test. An SCV should:

1031 1632
2. Read the relevant code and invariant.
1032 1633
3. Add or select the regression test.
1033 1634
4. Make the smallest patch.
1034
5. Pass focused checks and `mix precommit`.
1635
5. Pass focused checks and the repository's admitted final gate.
1035 1636
6. Commit and push an exact SHA to its run ref.
1036 1637
7. Pass the independent exact-SHA gate and change policy.
1037 1638
8. Produce a policy-bound promotion receipt.

@@ -1046,18 +1647,28 @@ the circuit.

1046 1647
1047 1648
Ship the first SCV with this deliberately narrow posture:
1048 1649
1049
- one repository: `openagents.com`;
1050
- one logical SCV and one active run;
1650
- one repository: OpenCode, initially anchored to the inspected `dev` baseline;
1651
- one logical SCV, one active run, and one repository writer;
1652
- multiple registered `scv-opencode-core` workers for read-only investigation,
1653
  exact-SHA gates, and benchmark execution;
1654
- `scv-opencode-core` as the first admitted image, with browser, Rust, Tauri,
1655
  Windows, and macOS images added only when a required gate needs them;
1051 1656
- `observe` and `propose` modes only;
1052 1657
- operator-created work items plus reproducible owned-gate failures;
1053 1658
- a dedicated SCV program, tool catalog, service principal, and budget ledger;
1054
- a sidecar executor with no production secrets or general network access;
1659
- an OpenCode executor behind a sidecar with no production secrets or general
1660
  candidate-command network access;
1661
- explicit OpenCode permissions, isolated XDG state, and no automatic
1662
  permissions or unadmitted project extensions;
1055 1663
- run branches and complete receipt chains;
1056
- source, diff, focused-test, and `mix precommit` gates;
1664
- source, diff, package-scoped type-check, focused-test, HTTP API, resource, and
1665
  benchmark receipts;
1057 1666
- no automatic promotion, integration-ref advance, or deployment.
1058 1667
1059
This release validates the difficult lifecycle, sandbox, Git, and evidence
1060
contracts without granting deployment authority. The next release can add
1668
This release validates the lifecycle, polyglot worker, OpenCode runtime,
1669
sandbox, Git, resource, benchmark, and evidence contracts without granting
1670
deployment authority. After it succeeds, target `openagents.com` with an Elixir
1671
capability image and the same worker protocol. The next release can add
1061 1672
human-reviewed SCV candidates. Staging autodeploy should follow only after the
1062 1673
Forge-canonical and isolated-fleet prerequisites pass.
1063 1674

@@ -1069,6 +1680,12 @@ Do not describe an SCV as autonomous until all of these conditions hold:

1069 1680
- Every candidate descends from and conditionally advances one linear
1070 1681
  integration history.
1071 1682
- Candidate code runs without production or operator credentials.
1683
- Candidate code cannot read an inference grant or replace the admitted
1684
  OpenCode runtime.
1685
- Every execution binds an admitted worker image, capability manifest, resource
1686
  class, and host-observed resource receipt.
1687
- Performance decisions use comparable benchmark definitions and preserve raw
1688
  samples, including failures.
1072 1689
- Host policy, not model output, determines risk, gates, budgets, and promotion.
1073 1690
- Protected changes cannot approve themselves.
1074 1691
- A push cannot directly create a target.

This page updates live while a promote is in flight · changelog