Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
148 commits
Select commit Hold shift + click to select a range
5a1006e
fix(core): keep credential flags after a boolean -u and query keys in…
cemililik Nov 4, 2026
3cb9712
fix(repo): tighten the dependency allowlist and pin the required checks
cemililik Nov 4, 2026
6155c6d
docs(repo): record the PR #96 merge, the D64 round 1 and the triaged …
cemililik Nov 4, 2026
2f7224e
fix(core): read a credential flag in value position as a flag
cemililik Nov 4, 2026
f213d2a
fix(repo): bound dependency requirements and pin every way a required…
cemililik Nov 4, 2026
07f653e
docs(repo): record the D64 round 2 and correct what it found stale
cemililik Nov 4, 2026
4b12fec
fix(core): make the argv and URL-password readings only add masks
cemililik Nov 4, 2026
71b621d
fix(repo): pin the hash-object batch bound, the other dependency fiel…
cemililik Nov 4, 2026
7a12ee6
docs(repo): record the D64 round 3 and correct round 2's oracle claim
cemililik Nov 4, 2026
93a8b03
test(repo): tolerate a child that exits between the liveness check an…
cemililik Nov 4, 2026
10e033b
fix(core): leave nested URLs and escapes to the scheme scan, and keep…
cemililik Nov 4, 2026
6c7bc70
fix(repo): refuse relative candidate roots and pin batch packing and …
cemililik Nov 4, 2026
68eb689
docs(repo): record the D64 round 4 and the facts it found missing
cemililik Nov 4, 2026
bbffecc
fix(core): remove the comma/slash URL password reading and keep the a…
cemililik Nov 4, 2026
18ea426
docs(repo): record the removal of the URL reading and close the PR #9…
cemililik Nov 4, 2026
6dd3f1e
docs(repo): record the MVP-1 plan rulings
cemililik Nov 4, 2026
9458a2b
feat(cli): show the run id in the live run view and its final summary
cemililik Nov 4, 2026
fed29de
test(cli): give the run-id summary case a complete run:completed event
cemililik Nov 4, 2026
9a1d3ef
feat(cli): add list --runs and status <runId>
cemililik Nov 4, 2026
42336ae
feat(core): add a pre-flight for tools whose host arm a path leaves u…
cemililik Nov 4, 2026
97714f9
feat(cli): refuse a run whose workflow grants a tool the run path can…
cemililik Nov 4, 2026
2f5ec10
docs(repo): say where each egress and os tool runs
cemililik Nov 4, 2026
0330635
feat(shared): add [chat].max_tokens
cemililik Nov 4, 2026
51c78d7
feat(cli): give interactive Anthropic chat its catalog output ceiling
cemililik Nov 4, 2026
f01611e
docs(repo): record the interactive chat output default
cemililik Nov 4, 2026
e478336
test(repo): re-pin the run workload count the run-id test moved
cemililik Nov 4, 2026
d5cde86
test(repo): move the run-reader outcome fixture to the 85-case workload
cemililik Nov 5, 2026
fbc9c88
fix(core): refuse a gate decision its gate type does not accept
cemililik Nov 4, 2026
feb7dc6
fix(cli): refuse a gate decision that does not fit the gate before an…
cemililik Nov 4, 2026
4487c03
docs(repo): state which decisions each human gate type accepts
cemililik Nov 4, 2026
8d8fd70
test(cli): assert the gate refusal without an untyped matcher
cemililik Nov 4, 2026
1f67862
test(repo): re-pin the gate workload count the decision-check test moved
cemililik Nov 4, 2026
e8b421d
feat(shared): add RunAlreadyTerminalError
cemililik Nov 4, 2026
f98ec0e
fix(db): refuse a second terminal in the durable run store
cemililik Nov 4, 2026
5e40f87
fix(core): mirror the second-terminal refusal in the in-memory run store
cemililik Nov 4, 2026
480e04c
feat(cli): reconcile interrupted runs at run/gate start and on Home open
cemililik Nov 4, 2026
f4cbabc
docs(repo): record the liveness wiring and the second-terminal refusal
cemililik Nov 4, 2026
37ac6c4
feat(cli): pick the default chat model from a keyed provider and refu…
cemililik Nov 5, 2026
cf1e355
docs(repo): record the key-aware default chat model and the key pre-f…
cemililik Nov 5, 2026
5b49046
feat(cli): /export writes into .relavium/workflows/ and offers the ru…
cemililik Nov 5, 2026
a30bda1
docs(repo): record where /export writes and how it picks the workflow id
cemililik Nov 5, 2026
80f6dc9
feat(cli): print the workflow's outputs on the human run surfaces
cemililik Nov 5, 2026
e3be7dd
docs(repo): record the outputs block on the human run and logs surfaces
cemililik Nov 5, 2026
723a971
docs(repo): record MVP-1 1b's progress in the roadmap
cemililik Nov 5, 2026
9fc2e33
test(repo): count the session key pre-flight in the packaged chat smoke
cemililik Nov 5, 2026
ed953a1
fix(cli): give replayed log rows the one-line floor
cemililik Nov 5, 2026
5f2a0eb
test(repo): give the compiled-CLI MCP orphan probe a synthetic key
cemililik Nov 5, 2026
bcaf362
docs(repo): draft the eight Gate 0 ADRs
cemililik Nov 5, 2026
6113911
fix(shared): refuse an input gate that would approve on timeout
cemililik Nov 5, 2026
19651cf
fix(core): leave a run whose held terminal is unwritten for the next …
cemililik Nov 5, 2026
42d2d34
feat(core): read back the session a workflow file was exported from
cemililik Nov 5, 2026
dc6a9c8
fix(cli): never promise an input gate it will be approved on timeout
cemililik Nov 5, 2026
bc0341d
fix(cli): mask output fields before serializing, and say when a value…
cemililik Nov 5, 2026
f1c8416
fix(cli): find a session's own export from the file, and show /export…
cemililik Nov 5, 2026
2a5dc99
fix(cli): open an interactive resume whose provider lost its key
cemililik Nov 5, 2026
b5c0d66
fix(cli): name the Home among the commands that recover a held terminal
cemililik Nov 5, 2026
60bc972
docs(repo): record the MVP-1 1b round 1 fixes and its deferred lows
cemililik Nov 5, 2026
499d1fd
fix(cli): read an output field with its name, so a header-named key i…
cemililik Nov 5, 2026
8dc9f12
fix(cli): tell an unreadable terminal outbox from an empty one
cemililik Nov 5, 2026
b08fd6a
fix(cli): never call a run already recorded failed "held"
cemililik Nov 5, 2026
08723f0
fix(cli): keep an own export's permission bits, and refuse where it c…
cemililik Nov 5, 2026
2d4354e
fix(cli): refuse /compact like a message while a resumed session has …
cemililik Nov 5, 2026
9734475
test(cli): pin the resume key pre-flight and the Home reconcile orders
cemililik Nov 5, 2026
ef25a7e
test(repo): resume a historical input gate that approves on timeout
cemililik Nov 5, 2026
ac596a3
docs(core): say an input gate's auto-approval fails at its deadline
cemililik Nov 5, 2026
c2afd8b
docs(shared): name the input-gate refusal among the frozen reader's e…
cemililik Nov 5, 2026
662b023
docs(repo): record the MVP-1 1b round 2 fixes and its deferred lows
cemililik Nov 5, 2026
224b8f6
style(cli): collapse the session-host test's shared type import
cemililik Nov 5, 2026
aa4e27c
fix(cli): decide a whole-value output mask by the field's name alone
cemililik Nov 5, 2026
80d935f
fix(cli): strip terminal controls from REPL command output on the pla…
cemililik Nov 5, 2026
e84d7c9
test(cli): pin a refused message out of the view and an own export's …
cemililik Nov 5, 2026
f8dd0d4
docs(cli): say what reconcile settles and what an own export is not c…
cemililik Nov 5, 2026
2668481
docs(core): name the other order of the run:started to acquire race
cemililik Nov 5, 2026
b70f9de
docs(repo): record the MVP-1 1b round 3 fixes and its deferred lows
cemililik Nov 5, 2026
6e7314f
fix(cli): keep the output value under a name that is itself a secret …
cemililik Nov 5, 2026
55fe542
fix(core): name a concurrent reconcile when a fresh run cannot take i…
cemililik Nov 5, 2026
88f79b8
test(cli): say a provider without a model reaches the starter only fr…
cemililik Nov 5, 2026
df685a5
docs(repo): record the MVP-1 1b round 4 fixes and its deferred lows
cemililik Nov 5, 2026
ab5e46e
docs(repo): record the MVP-1 1b round 5 lows
cemililik Nov 5, 2026
e11167e
docs(repo): accept MVP-1 1b and record the security sitting's lows
cemililik Nov 5, 2026
9da0a64
ci(repo): give the Windows headless chat smoke a fake provider key
cemililik Nov 5, 2026
837a57c
test(repo): read GnuPG's own AEAD choice in the custody test
cemililik Nov 5, 2026
158459a
fix(cli): sanitize every catalog field relavium list prints
cemililik Nov 5, 2026
624bb2e
docs(repo): say relavium list sanitizes every catalog field
cemililik Nov 5, 2026
314ad50
fix(core): bound the run-path tool pre-flight and fail closed on new …
cemililik Nov 5, 2026
f969d25
refactor(cli): wire the egress and os arms from their own unwired ent…
cemililik Nov 5, 2026
abe14ca
fix(cli): point a paused run's summary at the command that accepts it
cemililik Nov 5, 2026
199601b
fix(cli): show nothing pending for a finished run in status <runId>
cemililik Nov 5, 2026
272e099
fix(cli): scale a chat's attempt deadline to its output cap
cemililik Nov 5, 2026
52de04b
docs(repo): record the MVP-1 1a milestone review fixes and its deferr…
cemililik Nov 5, 2026
fbcd73e
test(cli): let the deadline wiring guard accept the chat's test timer…
cemililik Nov 5, 2026
d8762a2
style(cli): format the list run row and the seedRun cancel line
cemililik Nov 5, 2026
dc05e20
fix(cli): point a resumed run's restored gate at relavium status
cemililik Nov 6, 2026
faf28ed
test(cli): pin status's history-identifier sanitizers and finished-ru…
cemililik Nov 6, 2026
32d1a8a
docs(repo): record the MVP-1 1a review round 2 fix and its deferred lows
cemililik Nov 6, 2026
84a758e
fix(cli): print the command that continues each pending human gate in…
cemililik Nov 6, 2026
8e7f41f
docs(repo): record the MVP-1 1a review round 3 fix and its deferred lows
cemililik Nov 6, 2026
e1e42a0
fix(cli): show a decided human gate's step as completed in status
cemililik Nov 6, 2026
3354dda
docs(repo): record the MVP-1 1a review round 4 fix and its deferred lows
cemililik Nov 6, 2026
843924a
docs(repo): accept MVP-1 after a clean 1a milestone review round 5
cemililik Nov 6, 2026
a417a57
refactor(cli): clear the SonarCloud findings on the checkpoint PR
cemililik Nov 6, 2026
077650a
docs(repo): withhold Remember for a credential-shaped command and fix…
cemililik Nov 6, 2026
315e76f
fix(core): keep reconcile from relabelling a held or just-started run
cemililik Nov 6, 2026
c496587
fix(db): report when each interrupted run started
cemililik Nov 6, 2026
ce8cb12
test(db): give each media-temporary worker's first stage a cold-start…
cemililik Nov 6, 2026
bf80877
fix(cli): read the effect journal when the Home reconciles crashed runs
cemililik Nov 6, 2026
a0733a0
fix(cli): make a bare Enter reject a gate card, and close a card a de…
cemililik Nov 6, 2026
3f00c4d
fix(cli): replace an own export only if it is still the file that was…
cemililik Nov 6, 2026
bec3b99
fix(cli): print run and step status on one line in status, list and logs
cemililik Nov 6, 2026
d61488d
ci(repo): say what release.yml's dispatch and environment comments ac…
cemililik Nov 6, 2026
e37f911
docs(core): say a run-path pre-flight tool cannot succeed, not that i…
cemililik Nov 6, 2026
126488c
docs(repo): record the PR #97 review, its fixes, rulings and recorded…
cemililik Nov 6, 2026
13979d6
test(repo): pin the usage permanent inventory at 447 cases
cemililik Nov 6, 2026
775fe8d
fix(core): bound reconcile's TTL grace on both sides and pin the own-…
cemililik Nov 6, 2026
c842f01
fix(cli): keep the own-export identity check sound on coarse filesyst…
cemililik Nov 6, 2026
6b32bfe
test(cli): pin the logs run-id floor and keep reconcile tests testing…
cemililik Nov 6, 2026
0bd1814
test(repo): pin the usage permanent inventory at 448 cases
cemililik Nov 6, 2026
7382389
docs(repo): fix ADR-0118's grant label and record D64 round 1 of the …
cemililik Nov 6, 2026
5bf9849
fix(cli): compare the own export's bytes too before replacing it
cemililik Nov 6, 2026
ca84510
docs(repo): say the own-export check compares the file's bytes
cemililik Nov 6, 2026
0208b23
fix(cli): let Ctrl-C at the rejection reason cancel the run again
cemililik Nov 6, 2026
105c75a
docs(repo): say Ctrl-C at the rejection reason cancels the run
cemililik Nov 6, 2026
471a33e
test(core): pin a start just inside reconcile's future-skew bound
cemililik Nov 6, 2026
82db354
docs(repo): keep export-2's re-check inside the changed-file contract
cemililik Nov 6, 2026
aeb7e4c
fix(cli): compare the own export's stat fields before reading it
cemililik Nov 6, 2026
02a64f4
fix(cli): give the logs skipped-row note's seq the one-line floor
cemililik Nov 6, 2026
f23d4ac
test(repo): pin the usage permanent inventory at 449 cases
cemililik Nov 6, 2026
bc55186
fix(cli): say no answer from the terminal was recorded
cemililik Nov 6, 2026
4f25989
docs(repo): fix ADR-0118's label and ADR-0120's escape after D64 round 2
cemililik Nov 6, 2026
cbe3906
fix(cli): prompt no later gate after a card closes under the user
cemililik Nov 6, 2026
3b8e550
test(cli): pin the own-export swap at open and the legacy card's Enter
cemililik Nov 6, 2026
37acc0f
fix(cli): give gate list's ids and status's attempt the one-line floor
cemililik Nov 6, 2026
1570864
test(core): pin reconcile's per-run outbox re-read and its claim release
cemililik Nov 6, 2026
2d7f071
docs(repo): close ADR-0120's approval escape and record D64 round 3
cemililik Nov 6, 2026
cdb41ca
fix(cli): clear a gate's pause when it resumes
cemililik Nov 6, 2026
e979f3d
test(cli): pin that the own-export check refuses what it never opens
cemililik Nov 6, 2026
d538599
fix(cli): give gate's notices and gate list's empty line the one-line…
cemililik Nov 6, 2026
5410bbe
test(core): pin that reconcile leaves a young run before any claim
cemililik Nov 6, 2026
882a2ff
docs(repo): show line-end whitespace and endings in ADR-0120's approvals
cemililik Nov 6, 2026
90bb0d9
test(cli): pin the own export's stat times and gate's resolved-id notice
cemililik Nov 6, 2026
673a5ea
docs(repo): keep ADR-0120's masks from hiding code and state CR LF files
cemililik Nov 6, 2026
c461cd3
test(repo): pin gate.test.ts at 76 cases in the secrets controls
cemililik Nov 6, 2026
2cc865c
docs(repo): state ADR-0120's approval escape as a starting set
cemililik Nov 6, 2026
d20d414
docs(repo): say the secrets controls pin 76 gate cases
cemililik Nov 6, 2026
69e95d7
fix(cli): start a gate card's cleanup notice only when the card is ab…
cemililik Nov 7, 2026
010b21c
test(cli): pin each own-export stat field without the filesystem clock
cemililik Nov 7, 2026
38b7223
docs(core): say the re-read under the claim keeps a repair off a held…
cemililik Nov 7, 2026
72dee66
docs(repo): say a card closed under the user parks the run's later gates
cemililik Nov 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
# Turborepo cache, plus the formatting check and the no-vendor-type-across-the-seam fence.
#
# Branch protection (set in the GitHub repo settings, not here): `ci`, `coverage` and `windows-concurrency`
# are the REQUIRED status checks to merge into `main` (the Windows job since 2026-11-04: ADR-0106's
# acceptance names required CI for the platform-scoped claims it carries). Wire, usage, filesystem, secrets,
# are the REQUIRED status checks to merge into `main` (the Windows job since the maintainer's 2026-11-04
# ruling: it is the CI lane that validates ADR-0106's Windows-scoped claims). Wire, usage, filesystem, secrets,
# packed CLI and product map control jobs feed `ci` through an explicit success-only aggregation; they cannot
# silently skip or fail while `ci` stays green. The other jobs self-label `(advisory)` — `floor-check` and
# `peer-dep-gate`.
Expand Down Expand Up @@ -226,7 +226,7 @@ jobs:
# RUN the artifact this job just built, through the SAME `pnpm smoke:cli` script the root `ci` script
# calls — a check that exists in only one of the two is exactly the #312 divergence this change closes.
# Until now nothing in the required gate executed
# `apps/cli/dist/index.js` — only the advisory Windows leg and the tag-gated release smoke did (#294) —
# `apps/cli/dist/index.js` — only the then-advisory Windows leg and the tag-gated release smoke did (#294) —
# so a bundle that builds but cannot boot merged green. The `run --json` leg additionally proves the
# migrations resolve beside the bundle, which is the failure `apps/cli/drizzle/**` becoming a declared
# turbo output (#315) exists to prevent: a cache-hit replay used to leave `dist/` fresh next to a
Expand Down Expand Up @@ -424,7 +424,8 @@ jobs:
# Node-22 prebuild (ABI 127 — one binary for ALL of 22.x, so 22.13.0 loads the same artifact 22.0.0 would;
# no node-gyp C++ source build). What it does NOT prove is that no RUNTIME dep requires >22.0.0 — that is
# a property of the prod closure, verified at the ADR (see ADR-0067's amendment note) rather than here.
# A SEPARATE job (the required check stays the ubuntu `ci` job on Node 24); promote once confirmed stable.
# A SEPARATE, advisory job (the required checks are `ci`, `coverage` and `windows-concurrency`; see the header);
# promote once confirmed stable.
floor-check:
name: node 22-line floor (22.13.0) · typecheck · test · build (advisory)
runs-on: ubuntu-latest
Expand Down Expand Up @@ -537,8 +538,8 @@ jobs:
# Runs the @relavium/db concurrency suite (the real Windows native-addon + WAL exercise) + the CLI
# concurrency/perf harness there, the native Step 2 filesystem boundaries (ADR-0105), plus a headless
# no-TTY smoke. Native links/containment complement portable Windows lexical vectors; these results are
# evidence only after this job actually runs. A SEPARATE, advisory job (the required check
# stays the ubuntu `ci` job) — promote to required in branch protection once confirmed stable. POSIX 0600/0700
# evidence only after this job actually runs. A SEPARATE job and, since 2026-11-04, a REQUIRED check in
# branch protection beside `ci` and `coverage` (see the header). POSIX 0600/0700
# perm assertions are NOT exercised here (a documented Windows no-op — ADR-0050); nor is ink's raw-mode code,
# which is TTY-gated (the driver-selection gate picks the plain driver without a TTY — see the smoke below).
windows-concurrency:
Expand Down Expand Up @@ -603,8 +604,10 @@ jobs:
# `chat` is TTY-gated on STDOUT (selectChatDriver / io.stdoutIsTty): with stdout captured (non-TTY)
# here, the driver-selection gate picks the PLAIN driver (ink/setRawMode is never entered), and the
# plain driver must exit cleanly on EOF — never crash. A regression routing to ink without a TTY would
# throw "Raw mode is not supported…", which this catches.
if out="$(printf '' | node apps/cli/dist/index.js chat 2>&1)"; then
# throw "Raw mode is not supported…", which this catches. The runner stores no provider key, and since
# MVP-A4 a keyless `chat` refuses with exit 2 before choosing a driver, so the chat gets a fake env key:
# an empty stdin sends nothing, so the key is never sent.
if out="$(printf '' | RELAVIUM_ANTHROPIC_API_KEY=relavium-headless-smoke-not-a-key node apps/cli/dist/index.js chat 2>&1)"; then
chat_status=0
else
chat_status=$?
Expand Down
12 changes: 8 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
# release ADR that publishes the smoke-verified package-test tarball, with a sunset at 1.0 or when Steps
# 9c/9d land. That ADR must explicitly override ADR-0111's "missing custody cannot downgrade to test mode".
# Until it is Accepted and its guard change passes a security sitting, the guard below stays as it is.
# `publish` runs in the `release` deployment environment, so the npm token can be scoped to it.
# `publish` names the `release` deployment environment, so the npm token can be scoped to it. The environment and
# that scoping are MVP-A23's prerequisite (not done on 2026-11-04: the token is still a repository secret).
#
# Flow: `pack` builds the engine-inlined bundle and `pnpm pack`s it (resolving catalog:/workspace: to
# concrete versions) into a tarball artifact → `smoke` installs THAT SAME tarball outside the workspace on ubuntu /
Expand All @@ -30,7 +31,9 @@
# The `allow_off_main` dispatch input is the maintainer escape hatch for building and smoking an unmerged
# BRANCH. It cannot reach a publish: `workflow_dispatch` accepts a tag ref as readily as a branch, so the
# ancestry assertion ignores the override whenever the ref is a `v*` tag, and `publish` additionally requires
# `github.event_name == 'push'` — a dispatched run never publishes, whatever ref or input it was given.
# `github.event_name == 'push'` — a dispatched run of this workflow never publishes, whatever ref or input it
# was given. A dispatch runs the workflow file found at its ref, so an edited copy on another ref is bounded only by
# where `NPM_TOKEN` lives (MVP-A23).
#
# Third-party actions are pinned to a commit SHA (the `# vX.Y.Z` comment tracks the release), matching ci.yml.
name: Release CLI
Expand Down Expand Up @@ -227,8 +230,9 @@ jobs:
# manually dispatched run publish. Every manual run now stops after the cross-OS smoke.
if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }}
runs-on: ubuntu-latest
# The deployment environment that holds `NPM_TOKEN` and its required reviewer (repo settings); a
# repository-level secret is readable by any workflow a writer pushes. It sets no job environment.
# The deployment environment meant to hold `NPM_TOKEN` and its required reviewer (repo settings, MVP-A23); a
# repository-level secret is readable by any workflow a writer pushes. It does not exist yet: GitHub creates it
# unprotected on the first run that names it, so it gates nothing until MVP-A23 sets it up.
environment: release
timeout-minutes: 10
permissions:
Expand Down
3 changes: 2 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ gateway; engine stays local, Phase 2) — split across build phase 5 (managed in
phase 6 (cloud execution + portal); the engine is identical across all three (ADR-0012..0015).
**Status (2026-11-04): the CLI MVP comes first.** Phases 1, 2 and 2.5 are complete (`relavium@0.1.1` is
published); Phase 2.6.5 is complete with approved deferrals (49/51, PR #92). Phase 2.5.5's Waves 0–2 and Wave 3
Steps 1–8 are merged (PR #94, PR #95), and Steps 9a.1–9b.2 and NI are accepted on `development`. On 2026-10-26
Steps 1–8 are merged (PR #94, PR #95), and Steps 9a.1–9b.2 and NI are accepted and on `main` since the
`development`→`main` checkpoint (PR #96, 2026-11-04). On 2026-10-26
the maintainer paused Wave 3 (Steps 9c–19 pending, not declined) and put the CLI MVP first: `relavium` v0.2.0
(milestone M3.5), ordered as MVP-1…MVP-10 under decisions D58–D72 in
[current.md](docs/roadmap/current.md#next-work--the-cli-mvp). Phase 2.6 is in progress (2.6.C and 2.6.F done,
Expand Down
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ and [docs/architecture/managed-inference.md](docs/architecture/managed-inference
complete (M2.5-4, PR #69, 2026-07-08); Phase 2.6.5 (Core reliability) is complete with approved deferrals
(49/51, PR #92, 2026-10-11). Phase 2.5.5 (Hardening and Remediation): Waves 0–2 are merged (Wave 2: PR #94),
Wave 3 Steps 1–8 are merged (PR #95, 2026-10-18), and PR95, 9a.1, 9a.2a, 9a.2b, NI, 9b.1 and 9b.2 are
accepted on `development`. **On 2026-10-26 the maintainer paused Wave 3 — Steps 9c–19 are pending, not
accepted and on `main` since the `development`→`main` checkpoint (PR #96, merged 2026-11-04). **On 2026-10-26 the maintainer paused Wave 3 — Steps 9c–19 are pending, not
declined — and put the CLI MVP first:** `relavium` v0.2.0 on npm (milestone M3.5), ordered as MVP-1…MVP-10 in
[current.md](docs/roadmap/current.md#next-work--the-cli-mvp) under decisions D58–D72 (ruled 2026-11-04).
Phase 2.6 (Conversational Authoring and the First-Class CLI) is in progress: 2.6.C and 2.6.F are done
(2.6.F's v0.2.0 release clause closes with the MVP) and 2.6.Q P1–P5 landed; the MVP takes slices of the rest.

Two rules shape every MVP increment. Step 9a.1's interim release guard on `development` refuses any npm
Two rules shape every MVP increment. Step 9a.1's interim release guard (on `main` since PR #96) refuses any npm
publication until the superseding pre-1.0 release ADR (D59) is Accepted. The acceptance bar is tiered (D64):
an increment touching an approval or consent path, egress, keys or secrets, filesystem writes, a new terminal
sink for untrusted content, the lease or resume paths, or release keeps a rigor pass, one NEW complete
Expand Down
15 changes: 8 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,12 @@ Relavium is under active development. The **CLI is published as v0.1.1**; the pu
agent-session entry point, workflow runtime, inbound MCP client, and CLI management surface
are implemented. **Phase 2.6.5 — Core Reliability Remediation is complete with approved
deferrals**, with W8 merged in PR #92. The joint Phase 2.5.5/2.6 security remediation
Wave 2 merged to `main` on 2026-10-15 as PR #94, and the first eight steps of Wave 3
(“Clear the ground”) followed on 2026-10-18 as PR #95. Since 2026-10-26 the **CLI MVP
comes first**: Wave 3 is paused, not dropped, while the work a CLI user feels — visible
run results, a chat agent that can edit and run commands, readable replies, conversational
authoring, web, the Home hub and MCP management — leads to `relavium` v0.2.0.
Wave 2 merged to `main` on 2026-10-15 as PR #94. The first eight steps of Wave 3
(“Clear the ground”) followed on 2026-10-18 as PR #95, and the hardened release tooling and
the MVP plan on 2026-11-04 as PR #96. Since 2026-10-26 the **CLI MVP comes first**: Wave 3
is paused, not dropped, while the work a CLI user feels — visible run results, a chat agent
that can edit and run commands, readable replies, conversational authoring, web, the Home
hub and MCP management — leads to `relavium` v0.2.0.

Status changes quickly, so this README intentionally stays high-level. The canonical source
for the exact active wave, completed work, and open reliability obligations is
Expand All @@ -178,8 +179,8 @@ for the exact active wave, completed work, and open reliability obligations is
| [`packages/db`](packages/db/) | Local SQLite persistence with a Postgres-compatible schema and migrations |
| [`packages/mcp`](packages/mcp/) | SDK-confined inbound MCP client and schema validation |
| [`apps/cli`](apps/cli/) | Published terminal product and integration harness |
| [`apps/desktop`](apps/desktop/) | Tauri desktop surface under development |
| [`apps/vscode-extension`](apps/vscode-extension/) | VS Code surface under development |
| [`apps/desktop`](apps/desktop/) | Tauri desktop surface — a placeholder, built in Phase 3 |
| [`apps/vscode-extension`](apps/vscode-extension/) | VS Code surface — a placeholder, built in Phase 4 |

The full dependency graph and ownership rules live in
[docs/project-structure.md](docs/project-structure.md).
Expand Down
3 changes: 2 additions & 1 deletion apps/cli/src/authoring/create-prompter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,8 @@ export function createClackPrompter(deps: ClackCreateDeps = defaultDeps): Create

const toolsRaw = await deps.text({
message: 'Tools (comma-separated tool ids, optional)',
placeholder: 'read_file, web_search',
// Tools that also work on `relavium run`, which wires no egress or os arm (2.6.A).
placeholder: 'read_file, list_directory',
});
if (deps.isCancel(toolsRaw)) return null;
const tools = toolsRaw
Expand Down
47 changes: 47 additions & 0 deletions apps/cli/src/chat/agent-source.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { join } from 'node:path';
import { AgentParseError, MAX_SOURCE_CHARS } from '@relavium/core';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';

import { KNOWN_PROVIDERS } from '../engine/providers.js';
import { isCliError } from '../process/errors.js';
import { DEFAULT_CHAT_AGENT_ID, DEFAULT_CHAT_MODEL } from './default-agent.js';
import { resolveChatAgent } from './agent-source.js';
Expand Down Expand Up @@ -72,6 +73,52 @@ describe('resolveChatAgent', () => {
expect(agent.model).toBe(DEFAULT_CHAT_MODEL);
});

it('MVP-A4: with no configured default, the model comes from the first provider that has a key', () => {
const resolve = (keyed: readonly string[]) =>
resolveChatAgent(undefined, {
cwd: dir,
projectConfigDir: undefined,
defaultModel: undefined,
hasKey: (id) => keyed.includes(id),
});
// Anthropic keeps the long-standing default; every other provider gets the wizard's starter model.
expect(resolve(['anthropic', 'openai'])).toMatchObject({
model: DEFAULT_CHAT_MODEL,
provider: 'anthropic',
});
for (const id of ['openai', 'gemini', 'deepseek'] as const) {
expect(resolve([id])).toMatchObject({ model: KNOWN_PROVIDERS[id].testModel, provider: id });
}
// In KNOWN_PROVIDER_IDS order when several are keyed.
expect(resolve(['deepseek', 'gemini'])).toMatchObject({ provider: 'gemini' });
// No key anywhere: the built-in default, so the session pre-flight names the remedy for it.
expect(resolve([])).toMatchObject({ model: DEFAULT_CHAT_MODEL, provider: 'anthropic' });
});

it('MVP-A4: a configured model, or a provider a caller supplies, wins over the keys', () => {
const keyedOpenAi = (id: string) => id === 'openai';
expect(
resolveChatAgent(undefined, {
cwd: dir,
projectConfigDir: undefined,
defaultModel: 'claude-haiku-4-5',
defaultProvider: 'anthropic',
hasKey: keyedOpenAi,
}),
).toMatchObject({ model: 'claude-haiku-4-5', provider: 'anthropic' });
// A provider passed without a model gets that provider's starter, never the Anthropic default. Only a direct
// caller reaches this: config resolution drops a persisted provider that has no model.
expect(
resolveChatAgent(undefined, {
cwd: dir,
projectConfigDir: undefined,
defaultModel: undefined,
defaultProvider: 'gemini',
hasKey: keyedOpenAi,
}),
).toMatchObject({ model: KNOWN_PROVIDERS.gemini.testModel, provider: 'gemini' });
});

it('bakes opts.reasoningEffort onto the DEFAULT agent (ADR-0066)', () => {
const agent = resolveChatAgent(undefined, {
cwd: dir,
Expand Down
42 changes: 37 additions & 5 deletions apps/cli/src/chat/agent-source.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { parseAgent, type AgentDefinition } from '@relavium/core';
import type { LlmProviderId, ReasoningEffort } from '@relavium/shared';

import { KNOWN_PROVIDER_IDS, KNOWN_PROVIDERS } from '../engine/providers.js';
import { sourceLabel } from '../process/source-label.js';
import { resolveYamlSource } from '../workflows/resolve.js';
import { buildDefaultChatAgent, DEFAULT_CHAT_MODEL } from './default-agent.js';
Expand All @@ -16,6 +17,40 @@ export interface ResolveChatAgentOptions {
/** The resolved `[chat].reasoning_effort` (ADR-0066) — baked onto the DEFAULT agent only (an authored `--agent`
* owns its own `reasoning_effort`, never overridden by config). Absent ⇒ no reasoning control. */
readonly reasoningEffort?: ReasoningEffort;
/**
* Whether a provider has a resolvable key — a boolean, never the key (MVP-A4). Consulted only for the DEFAULT
* agent when neither `defaultModel` nor `defaultProvider` is configured, so the zero-config chat binds a model a
* keyed provider serves. Absent ⇒ the built-in default, as before.
*/
readonly hasKey?: (id: LlmProviderId) => boolean;
}

/**
* The default agent's model and provider (MVP-A4).
*
* A configured `defaultModel` wins, with its persisted provider (ADR-0059). Otherwise the provider is a
* `defaultProvider` the caller passed, else the first provider in {@link KNOWN_PROVIDER_IDS} order that has a key,
* else Anthropic. Config resolution never passes a provider without a model (it drops a stray one), so from config
* the choice is always the key-aware one. Anthropic keeps the long-standing zero-config {@link DEFAULT_CHAT_MODEL}; any other provider gets the
* onboarding wizard's starter model (`KNOWN_PROVIDERS[id].testModel`), so a user with only an OpenAI key reaches a
* working chat instead of an Anthropic credential failure.
*/
export function defaultChatModel(opts: ResolveChatAgentOptions): {
readonly model: string;
readonly provider: LlmProviderId | undefined;
} {
if (opts.defaultModel !== undefined) {
return { model: opts.defaultModel, provider: opts.defaultProvider };
}
const hasKey = opts.hasKey;
const provider =
opts.defaultProvider ??
(hasKey === undefined ? undefined : KNOWN_PROVIDER_IDS.find((id) => hasKey(id))) ??
'anthropic';
return {
model: provider === 'anthropic' ? DEFAULT_CHAT_MODEL : KNOWN_PROVIDERS[provider].testModel,
provider,
};
}

/**
Expand Down Expand Up @@ -56,12 +91,9 @@ export function resolveChatAgentSource(
opts: ResolveChatAgentOptions,
): ResolvedChatAgent {
if (agentRef === undefined) {
const { model, provider } = defaultChatModel(opts);
return {
agent: buildDefaultChatAgent(
opts.defaultModel ?? DEFAULT_CHAT_MODEL,
opts.reasoningEffort,
opts.defaultProvider,
),
agent: buildDefaultChatAgent(model, opts.reasoningEffort, provider),
artifact: undefined,
};
}
Expand Down
1 change: 1 addition & 0 deletions apps/cli/src/chat/compaction-persistence.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const chat: ResolvedChatConfig = {
autoCompact: true,
compactThreshold: 0.7,
maxCostMicrocents: undefined,
maxTokens: undefined,
onExceed: undefined,
strictCostCap: false,
allowedCommands: undefined,
Expand Down
Loading
Loading