Development
April 30, 2026 · View on GitHub
Local validation loop for iterating on reality-check without shipping
changes through upstream. Stands the bundle up inside an isolated DTU,
runs the reality-check-pipeline recipe, and extracts artifacts back
to the host.
Profiles
Two profiles are shipped under .amplifier/digital-twin-universe/profiles/:
-
reality-check-in-incus.yaml-- the heavy profile. Installs the full reality-check stack inside a single Incus container: Incus, Docker, Amplifier + the DTU and Gitea CLIs (for DTU-in-DTU),agent-browser+ Chromium (for the browser validator), the reality-check bundle composed as--app, and the playground fixtures (amplifier-chat source + synthetic spec and conversation) pre-staged at/root/home/viascripts/setup-e2e-playground.sh. Use this for browser-based validation against amplifier-chat. -
reality-check-in-incus-simple.yaml-- the smoke-test profile. Same outer DTU stack, but no Chromium /agent-browseroverhead and an inline "add two numbers" CLI playground instead of amplifier-chat. Use this for fast iteration on the pipeline plumbing (CLI-validated convergence loops, recipe wiring, the report agent) where you don't need a real browser.
Notable profile knobs (both profiles):
--var HOST_PORT=<n> # host port forwarded to the inner Chat UI
# (default 8410 via the wrapper script)
--var GITEA_URL=... # optional: redirect reality-check clones through
--var GITEA_TOKEN=... # a local Gitea for testing uncommitted changes
Wrapper scripts
Two wrappers are shipped under scripts/:
-
run-reality-check-validation.sh-- the inner script. Launches the given profile, polls for readiness, runsamplifier run "<prompt>"inside the DTU with streamed output, then extracts artifacts on exit. Output goes to a timestamped dir under/tmp/reality-check-runs/so the repo working tree is never polluted regardless of invocation CWD. -
run-reality-check-validation-simple.sh-- the outer wrapper for testing local bundle changes. Spins up anamplifier-giteainstance (or reuses the first running one), mirrorsamplifier-bundle-reality-checkfrom GitHub, snapshots the local working tree (committed + staged + untracked) viagit commit-treeagainst a temp index, force-pushes that snapshot to Gitea'smain, then calls the inner script withGITEA_URLandGITEA_TOKENset so the DTU clones your local tree instead of GitHub. Pinned to the simple profile and a 1h exec timeout.
Running
# Smoke-test the pipeline against your local working tree (recommended
# for iterating on recipes / agents / CLI):
./scripts/run-reality-check-validation-simple.sh
# Run the inner script directly against the heavy profile (browser tests
# against amplifier-chat):
./scripts/run-reality-check-validation.sh [flags]
Inner-script flags:
--profile PATH profile YAML (default: reality-check-in-incus.yaml)
--name NAME friendly DTU name
--prompt TEXT override the default recipe-run prompt
--out-dir PATH full output directory (default:
/tmp/reality-check-runs/reality-check-validation-<TS>)
--host-port PORT default 8410; change for concurrent runs
--var KEY=VALUE extra --var entry forwarded to launch (repeatable)
--exec-timeout SEC timeout for the inner `amplifier run` exec call
(default: 1800 = 30 min; pass 'none' to disable)
--destroy-on-finish tear the DTU down after extraction (default: keep)
--help full usage
What the inner script does:
amplifier-digital-twin launchthe profile.- Poll
check-readinessuntil all checks pass. exec --streamamplifier run "<prompt>"inside the DTU. Live output streams to the terminal and torun.log.- On completion (or failure),
file-pull/root/home/and/root/.amplifier/projects/back to the host. Runs in an EXIT trap so partial artifacts are recovered even when the run errors. - Leaves the DTU running so you can
amplifier-digital-twin execin for a closer look; pass--destroy-on-finishto clean up.
The simple wrapper additionally copies the extracted home/ directory
to a flat /tmp/reality-check-home-<TS>/ for easy file-browser access.
Output layout
/tmp/reality-check-runs/reality-check-validation-<UTC-timestamp>/
├── launch-info.json # raw DTU launch JSON
├── run.log # full streamed transcript
├── home/ # /root/home from the DTU
│ ├── reality-check-output/{acceptance-tests,report,screenshots}
│ ├── software/ # the artifact under test
│ └── user/ # spec.md, conversation.md fixtures
└── sessions/ # /root/.amplifier/projects -- per-session events.jsonl etc.
Open home/reality-check-output/report/report.html in a browser for the
rendered gap analysis.
Working on the Python CLI
The bundle ships an amplifier-reality-check CLI under
src/amplifier_bundle_reality_check/. To hack on it:
# Install in editable mode + dev deps
uv sync
# Run the CLI from the working tree
uv run amplifier-reality-check --help
uv run amplifier-reality-check validate-acceptance-tests path/to/tests.yaml
uv run amplifier-reality-check validate-report path/to/raw.yaml \
--acceptance-tests path/to/tests.yaml
uv run amplifier-reality-check schema --type acceptance-tests
# Test suite
uv run pytest
# Lint and type-check
uv run ruff check src/ tests/
uv run pyright src/
When iterating on the CLI alongside the recipe pipeline, the simple
wrapper script (run-reality-check-validation-simple.sh) is the primary
loop -- it pushes your local tree (including untracked CLI changes) to
Gitea, and the DTU profile installs the CLI from there.
Caveats
- Provisioning is slow on first run. The heavy profile pulls
agent-browser install --with-deps(Chromium ~300 MB plus Linux libs). Plan for 10-15 minutes before the DTU reaches readiness. The simple profile is faster (no Chromium). - Port 8410 by default. If another DTU (or anything else on the host)
already holds 8410, use
--host-port 8411(or any free port) so the Incus proxy device can bind. hooks-notifywarnings in the log are non-fatal.amplifier-app-cliinjects ahooks-notifyoverride for root sessions that doesn't carry into recipe sub-sessions; each sub-session logs a "Module not found" error at startup and proceeds. The profile setsnotifications: {}to suppress it at the source.