Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
39 changes: 28 additions & 11 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Maintain one plan-first bootstrap adapter for:

The public entry point is `scripts/bootstrap.sh`. Treat
`config/rldyour-contract.json`, the platform installers, verification scripts,
and tests as the executable contract. Current adapter version: `2.2.1`.
and tests as the executable contract. Current adapter version: `2.3.0`.

## Composition Invariants

Expand All @@ -30,13 +30,15 @@ profile; Ubuntu server is always headless.

## Verified Pins

- Active harness set (one owner per harness, RVR-P1-004): `codex` and `zcode`,
each installed by its authoritative NDDev module. Bootstrap installs no AI CLI
inline or through a bun/npm global path.
- Active harness set (one owner per harness, RVR-P1-004): `codex`, installed by
its authoritative NDDev module. Bootstrap installs no AI CLI inline or through a
bun/npm global path.
- `codex`: `nddev-codex-app` via `RLDYOUR_CODEX_MODULE` (safe setup by default;
full-auto only with `RLDYOUR_CODEX_FULL_AUTO=1`; then `install-builder`).
- `zcode`: `nddev-zcode-app` via `RLDYOUR_ZCODE_MODULE` (nddev-builder setup,
module `--plan`/`--apply` lifecycle).
full-auto only with `RLDYOUR_CODEX_FULL_AUTO=1`; then `install-builder`). The
module publishes its CLI only under its own target, so
`${RLDYOUR_CODEX_HOME:-$HOME/.codex}/bin` belongs on the managed PATH.
- `zcode`: delegated out of bootstrap (ADR 0006), owned by `nddev-harnesses`.
Its target cannot be adopted unattended; never reintroduce an install path.
- RTK exact `0.43.0`, hash-pinned native artifact
- CloakBrowser `0.4.12`
- Chrome DevTools MCP `1.6.0`
Expand All @@ -55,6 +57,19 @@ profile; Ubuntu server is always headless.
server profile, which stays `container-execution-only`. gopls `v0.23.0` is
pinned by module version and verified through the Go checksum database, not a
tracked archive hash (ADR 0005).
- Ubuntu Dart SDK `3.12.2`, desktop-only, tracked architecture hashes (ADR 0006).
One archive provides `dart language-server` and `dart mcp-server`; the latter is
the transport the `dart-flutter` MCP server in `rldyour-mcps` executes, so both
verifiers prove the subcommand responds and not merely that `dart` resolves. The
Flutter SDK stays out: its `bin/cache` self-populates at runtime and would
mutate a receipt-verified tree. macOS uses Homebrew's `dart-sdk`.
Two Dart-specific invariants must not regress: the SDK zip stores `0775`
directories, so the staged tree goes through
`rldyour::_managed_tree_permissions normalize` before the receipt is written
(umask cannot fix this — it only clears bits it never adds), and telemetry is
disabled through `rldyour::ensure_dart_telemetry_disabled`, which runs the SDK's
own `--disable-analytics` switch and then reads `reporting=0` back. Never
hand-write the shared Dart/Flutter telemetry config.

Keep the contract, both installers, tests, README, install guide, AGENTS, and
this file synchronized when a pin changes.
Expand Down Expand Up @@ -92,15 +107,17 @@ copy outside the active namespace.

- macOS GUI mode: Ghostty, cmux, ChatGPT, the separate Codex app, Claude Desktop.
- Ubuntu GUI mode: no bootstrap-installed harness apps; the ZCode desktop app is
owned by its `nddev-zcode-app` module.
owned by the `nddev-harnesses` repository. `scripts/ubuntu/desktop.sh` owns
desktop customization: GNOME dock, Russian layout, BrowserOS install, and the
complete snap+apt Firefox removal.
- Server: no GUI layer.

macOS GUI apply installs cmux hooks non-interactively only for Codex. Keep the
targeted `--yes` command; do not use broad interactive `cmux hooks setup`.

The ZCode app and CLI are owned by the `nddev-zcode-app` module and installed
through its own `--plan`/`--apply` lifecycle; bootstrap never installs ZCode via
an apt `.deb` or a `RLDYOUR_ZCODE_SHA256` gate.
The ZCode app and CLI are owned by the `nddev-harnesses` repository; bootstrap
never installs ZCode via an apt `.deb`, a `RLDYOUR_ZCODE_SHA256` gate, or a module
delegation.

Credentials are outside bootstrap ownership. Use:

Expand Down
15 changes: 9 additions & 6 deletions .github/workflows/dependency-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,10 @@ jobs:
]
common = Path("scripts/lib/common.sh")

# The active harness set is codex and zcode; each is installed by its
# authoritative NDDev module, never inline and never through a
# bun/npm global path or a frozen AI-CLI bundle.
# The active harness set is codex, installed by its authoritative NDDev
# module, never inline and never through a bun/npm global path or a
# frozen AI-CLI bundle. zcode is delegated to nddev-harnesses (ADR 0006)
# because its target cannot be adopted unattended.
removed_globals = [
"@anthropic-ai/claude-code",
"opencode-ai",
Expand All @@ -70,20 +71,22 @@ jobs:
for func in (
"rldyour::install_selected_harnesses",
"rldyour::install_codex_harness",
"rldyour::install_zcode_harness",
"RLDYOUR_CODEX_MODULE",
"RLDYOUR_ZCODE_MODULE",
):
if func not in common_data:
raise SystemExit(f"harness delegation symbol missing in {common}: {func}")
# ADR 0006: no zcode install path may return, in any form.
for banned in ("rldyour::install_zcode_harness", "RLDYOUR_ZCODE_MODULE"):
if banned in common_data:
raise SystemExit(f"zcode is delegated out of bootstrap: {banned} must not return")

# A streamed Antigravity installer was always forbidden and stays gone.
streamed_installer = "antigravity.google/cli/install.sh"
for path in installers:
if streamed_installer in path.read_text(encoding="utf-8"):
raise SystemExit(f"streamed installer is forbidden in {path}")

print("harness delegation is one-owner-per-harness: codex + zcode via GDS modules")
print("harness delegation is one-owner-per-harness: codex via its GDS module; zcode delegated to nddev-harnesses")
PY

- name: Validate dependency-check intent
Expand Down
65 changes: 40 additions & 25 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ When prose and implementation disagree, verify the scripts and contract, then
update the affected documentation in the same change. Do not invent a second
policy source.

## Contract `2.2.1`
## Contract `2.3.0`

Ubuntu profile selection is always explicit. Never infer server/rootful Docker
from `uname=Linux`; require `--profile desktop|server`.
Expand All @@ -47,27 +47,32 @@ or configure local project build/runtime execution. `--no-gui` removes only
the GUI overlay; it does not change the desktop execution policy. Server is
Ubuntu-only and always headless.

Desktop profiles additionally install Go and Rust as language-server hosts for
`gopls` and `rust-analyzer`, on the same footing as Node, Python, and LLVM —
present to resolve source, not to authorize project builds (ADR 0005). The
server profile receives no host compiler: `install_compiled_language_hosts`
returns early there.
Desktop profiles additionally install Go, Rust, and the Dart SDK as
language-server hosts for `gopls`, `rust-analyzer`, and the Dart analysis server,
on the same footing as Node, Python, and LLVM — present to resolve source, not to
authorize project builds (ADR 0005, ADR 0006). Dart also provides
`dart mcp-server`, the transport the `dart-flutter` MCP server in `rldyour-mcps`
executes; the Flutter SDK is not installed because its `bin/cache` self-populates
and would mutate a receipt-verified tree. The server profile receives no host
toolchain: `install_compiled_language_hosts` returns early there.

## Managed Versions

These values must match both platform installers, the contract, tests, and
operator documentation:

- Active harness set (one owner per harness, RVR-P1-004): `codex` and `zcode`.
- Active harness set (one owner per harness, RVR-P1-004): `codex`.
Bootstrap installs no AI CLI inline and never through a bun/npm global path.
Each harness is owned by its authoritative NDDev module, whose materialized
The harness is owned by its authoritative NDDev module, whose materialized
checkout GDS device bootstrap passes in an env var:
- `codex`: `nddev-codex-app` (`RLDYOUR_CODEX_MODULE`); `install-cli`, then
`apply --setup safe` (full-auto only via `RLDYOUR_CODEX_FULL_AUTO=1`), then
`install-builder`.
- `zcode`: `nddev-zcode-app` (`RLDYOUR_ZCODE_MODULE`); `bootstrap` then
`install --setup nddev-builder` through the module's `--plan`/`--apply`
lifecycle.
`install-builder`. The module publishes its CLI only under its own target, so
`${RLDYOUR_CODEX_HOME:-$HOME/.codex}/bin` is part of the managed PATH.
- `zcode`: **delegated out of bootstrap** (`harnesses.delegated`, ADR 0006) and
owned by the `nddev-harnesses` repository. Its target cannot be adopted
unattended, and blocking a device apply on it stranded every later layer. Do
not reintroduce a zcode install path, not even a warn-and-continue one.
- RTK: exact `0.43.0`, hash-pinned native artifact
- CloakBrowser: `0.4.12`
- Chrome DevTools MCP: `1.6.0`
Expand All @@ -82,21 +87,28 @@ operator documentation:
`0.45.0`. Adding a tool means adding a row; there is no second install path.
Ubuntu uses markdown-oxide where macOS uses marksman (marksman's formula
depends on `dotnet@9`). ast-grep's deprecated `sg` shim is never published.
- Ubuntu Go `1.26.5` and Rust `1.97.1`, desktop-only language-server hosts,
tracked architecture hashes. One combined Rust archive carries rustc, cargo,
rust-std, clippy, rustfmt, and rust-analyzer. gopls `v0.23.0` is pinned by
module version and verified through the Go checksum database — it publishes
no prebuilt archive, so it carries no tracked archive hash (ADR 0005).
- Ubuntu Go `1.26.5`, Rust `1.97.1`, and Dart SDK `3.12.2`, desktop-only
language-server hosts, tracked architecture hashes. One combined Rust archive
carries rustc, cargo, rust-std, clippy, rustfmt, and rust-analyzer. One Dart SDK
archive carries both `dart language-server` and `dart mcp-server`; both
verifiers gate on the exact/floor version *and* on the mcp-server subcommand
responding, because an SDK that resolves but cannot serve MCP is the defect
ADR 0006 exists to prevent. The Dart tree is permission-normalized before
publication (its zip stores `0775` directories, which umask cannot fix), and its
telemetry is disabled through the SDK's own switch and then proven by reading
`reporting=0` back. gopls `v0.23.0` is pinned by module version and verified
through the Go checksum database — it publishes no prebuilt archive, so it
carries no tracked archive hash (ADR 0005).

Use current, source-backed facts before changing a dependency. Preserve exact
pins and integrity checks unless the change intentionally updates the contract.
Never reintroduce mutable, unauthenticated remote installer execution or
unfrozen dependency resolution. The Node browser providers use
`templates/browser/provider/bun.lock`; CloakBrowser uses its tracked `uv.lock`.
The codex and zcode harnesses own their standalone artifacts inside their
modules; never reintroduce an inline AI-CLI bundle or a bun/npm global install.
The codex harness owns its standalone artifacts inside its module; never
reintroduce an inline AI-CLI bundle or a bun/npm global install.

The codex and zcode harnesses stay update-locked: `DISABLE_AUTOUPDATER=1` and
The codex harness stays update-locked: `DISABLE_AUTOUPDATER=1` and
`DISABLE_UPDATES=1` keep the codex module's standalone binary from drifting.

## Non-Negotiable Browser Boundary
Expand Down Expand Up @@ -128,17 +140,20 @@ be committed.

- macOS GUI: Ghostty, cmux, ChatGPT, and the separate Codex app.
- Ubuntu GUI: no bootstrap-installed harness apps; the ZCode desktop app is
installed by its `nddev-zcode-app` module.
installed by the `nddev-harnesses` repository. Desktop customization
(GNOME dock, Russian layout, BrowserOS install, Firefox removal) is owned by
`scripts/ubuntu/desktop.sh`.
- Ubuntu server: no GUI applications.

macOS GUI apply configures cmux non-interactively only for Codex. Do not replace
that targeted `--yes` install with broad interactive `cmux hooks setup`, which
can create unrelated agent configs.

ZCode is owned by the `nddev-zcode-app` module and installed through its own
`--plan`/`--apply` lifecycle. Bootstrap never installs ZCode via an apt `.deb`
or a `RLDYOUR_ZCODE_SHA256` gate; both were removed in contract `2.0.0`. Do not
reintroduce a silent download, fallback checksum, or integrity bypass.
ZCode is owned by the `nddev-harnesses` repository and installed through its own
lifecycle. Bootstrap never installs ZCode via an apt `.deb` or a
`RLDYOUR_ZCODE_SHA256` gate; both were removed in contract `2.0.0`, and the
remaining module delegation was removed in `2.3.0`. Do not reintroduce a silent
download, fallback checksum, or integrity bypass.

Authentication is a post-install owner handoff. `scripts/auth-handoff.sh` may
show instructions and perform non-secret status probes, but bootstrap code must
Expand Down
75 changes: 75 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,81 @@ All notable changes to this module will be documented in this file.

## [Unreleased]

## [2.3.0] - 2026-08-03

Two declared-but-undelivered capabilities are closed in one contract bump: the
`dart-flutter` MCP server had no Dart on any provisioned device, and the zcode
harness step aborted device applies before the layer that installs
`chrome-devtools-mcp`. Both MCP servers named in the `rldyour-mcps` marketplace
were therefore unstartable on a desktop this adapter had just provisioned.

### Added

- **Dart SDK `3.12.2` as the third desktop language-server host (ADR 0006).**
`rldyour-mcps` declares a `dart-flutter` MCP server whose transport is
`dart mcp-server`, and `rldyour-claudecode` stated that its Dart SDK pin
"matches what the bootstrap installs". No bootstrap path installed Dart on
either platform — the string appeared in this repository only in ADR 0005's
forbidden list and the test enforcing it — so that MCP server could never start
on any provisioned device. Ubuntu now installs the stable-channel
`dartsdk-linux-<arch>-release.zip` into an owned versioned directory with a
runtime receipt and a managed `~/.local/bin` link, exactly like Go and Rust;
macOS uses Homebrew's `dart-sdk`. Both digests were confirmed by downloading the
artifacts (`28e47b44…` x64, `f82c83ec…` arm64). Verification gates on the exact
(Ubuntu) or floor (macOS) version **and** on `dart mcp-server --version`
responding, because an SDK that resolves on `PATH` but cannot serve MCP is the
precise defect this replaces. The Flutter SDK is deliberately excluded: its
`bin/cache` self-populates at runtime and would mutate a hash-verified tree,
which needs its own decision rather than a row in this one.
`dart language-server --protocol=lsp` — the exact invocation `rldyour-lsps`
declares — was proven against a real `initialize` handshake, with a rejected
bogus `--protocol` value as the negative control.

- **Dart telemetry disabled through one shared fail-closed helper.** The SDK
reports by default, which contradicts the boundary that makes the browser
wrapper reject `--usage-statistics`. `rldyour::ensure_dart_telemetry_disabled`
runs the SDK's own `dart --disable-analytics` switch — the shared Dart/Flutter
telemetry config is upstream's to maintain and is never hand-written — then reads
`reporting=0` back and rejects a conflicting `reporting=1`. Both installers call
it; Ubuntu's verifier re-proves it.

### Fixed

- **Group-writable directories in the published Dart tree.** The SDK zip records
directories as `0775`, and umask only clears bits it never adds, so extracting
under `umask 002` published 113 group-writable directories inside a
receipt-verified tree. Because the receipt hashes only the declared executables,
a writable directory beside them was enough to add or swap a snapshot without
invalidating it. Go and Rust never showed this — their archives store `0755`
directories. Rather than add a second permission path, the helper written for
group-writable Bun trees is generalized to
`rldyour::_managed_tree_permissions` and now normalizes the staged Dart tree
before the receipt is written and re-validates a reused one.

- **`${RLDYOUR_CODEX_HOME:-$HOME/.codex}/bin` on the managed PATH.**
`nddev-codex-app` installs its standalone CLI under its own target and publishes
no link into the managed prefix, while both verifiers required `codex` on
`PATH`. `rldyour::ensure_path` and the `zshenv` template omitted that directory,
so strict verification could not pass on a correctly installed device — the
binary was present and unreachable.

### Removed

- **The zcode harness delegation, entirely (ADR 0006).** The ZCode desktop app
creates and owns `~/.zcode` on first launch; its module installer then correctly
refuses to write into an unstamped target without an explicit
`--adopt-unmanaged`, an adoption decision no unattended run may make for the
owner. Because `install_ai_runtimes` sat ahead of every other layer under
`set -euo pipefail`, that refusal aborted whole device applies: an observed
Ubuntu 26.04 desktop was missing 24 of the 46 commands its own `verify.sh`
requires — all the bun language servers, Go, Rust, every pinned scanner, the
entire CloakBrowser stack, and with it `chrome-devtools-mcp`, breaking a second
declared MCP server for the same reason. `rldyour::install_zcode_harness` and
`RLDYOUR_ZCODE_MODULE` are removed rather than softened into warn-and-continue,
which would be exactly the best-effort fallback this repository forbids. zcode is
declared `harnesses.delegated` in the contract, owned by `nddev-harnesses`, and
`dependency-check.yml` now fails if any zcode install path returns.

### Changed

- **Every reusable-workflow caller repinned from `0.12.0` to `0.13.3`.** All
Expand Down
Loading
Loading