Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
60 KiB
logos-scaffold dogfooding Scenarios
This document is the canonical dogfooding runbook for logos-scaffold.
Use it to evaluate the latest repository state, not as a dated findings report.
Earlier one-off dogfood notes are historical context only; future runs should start here.
Maintenance note: update this document whenever first-class commands, templates, supported workflows, or major user-facing behaviors are added, removed, or materially changed. If the product surface changes and this runbook does not, the runbook is wrong.
Purpose and Audience
- Dogfooders: use this as a repeatable checklist when validating the latest scaffold DX.
- Contributors: use this document to decide which scenarios must be rerun for a given change.
This guide is intentionally scenario-oriented:
- It defines what to exercise.
- It defines what success looks like.
- It calls out the failures and caveats that are worth recording.
- It does not replace generated project READMEs or CLI help text.
Usage Model
The recommended dogfooding pattern is:
- Build the local scaffold binary from the repository under test.
- Create fresh generated projects in a scratch workspace outside the repo.
- Run project-level scenarios from inside the generated project root.
- Capture command, cwd, exit code, and a short output excerpt for each scenario.
- If the behavior differs from this runbook, update the runbook when the difference is intentional and file a bug when it is not.
For repo dogfooding, prefer the freshly built local binary over an already-installed global binary.
Scaffold now treats LEZ tooling as project-local state. For non-vendored projects, the shared cache layout is <cache_root>/repos/lez/<pin>/...; for vendored projects, LEZ lives under <project>/.scaffold/repos/lez. In both cases, the wallet binary under test is the LEZ-local build artifact at <lez>/target/release/wallet, invoked through logos-scaffold wallet ... rather than a wallet binary on PATH.
export REPO_ROOT=/absolute/path/to/logos-scaffold
export SCRATCH_ROOT=/absolute/path/to/dogfood-runs
cd "$REPO_ROOT"
cargo build
export SCAFFOLD_BIN="$REPO_ROOT/target/debug/logos-scaffold"
mkdir -p "$SCRATCH_ROOT"
You may replace "$SCAFFOLD_BIN" with logos-scaffold when the install path itself is part of what you are validating.
Execution Contexts
| Context | Purpose | Typical commands |
|---|---|---|
| Repo root | Build the latest CLI, inspect docs, validate help/version output, verify out-of-project errors | cargo build, "$SCAFFOLD_BIN" --help, "$SCAFFOLD_BIN" --version, "$SCAFFOLD_BIN" build (expect error) |
| Scratch workspace | Create fresh generated projects without polluting the repo; test advanced creation flags | "$SCAFFOLD_BIN" new dogfood-default, "$SCAFFOLD_BIN" new ... --template ... |
| Generated project root | Execute scaffold workflows and example runners against a fresh project | setup, localnet, build, deploy, wallet, doctor, report, cargo run --bin run_* |
Do not run project-scoped commands from the repository root unless the scenario is explicitly checking the "outside project" error path.
Shared Preconditions
- Unix-like environment with
git,rustc,cargo,lsof,ps, andkill. - Docker or Podman available for guest builds.
- No conflicting listener on the scaffold localnet port before
localnet start. - Network access available for setup/build flows that fetch dependencies.
- No preinstalled
walletbinary is required. If one exists onPATH, do not treat it as the runtime under test for scaffold wallet scenarios. - Optional but supported:
LOGOS_SCAFFOLD_WALLET_PASSWORDwhen validating password override behavior. - For
B-series (basecamp) scenarios: Nix with flakes enabled, plus a module project on disk whoseflake.nixexposes apackages.<system>.lgxoutput (e.g., atictactoe-style project built against thelogos-module-buildertutorial-v1convention).docs/basecamp-module-requirements.md(also reachable via"$SCAFFOLD_BIN" basecamp docs) is the canonical contract.
The lgs binary is a short alias for logos-scaffold produced by the same crate; "$SCAFFOLD_BIN" and lgs are interchangeable in the commands below.
Scenario Index
| ID | Template | Level | Goal | Command surface |
|---|---|---|---|---|
| D1 | default |
Core | Fresh project creation and first-success bootstrap | new, create, setup, localnet start, build, deploy, wallet topup, wallet -- check-health |
| D2 | default |
Core | Localnet lifecycle visibility and doctor checks | localnet status, localnet logs, localnet stop, doctor, JSON variants |
| D3 | default |
Advanced | Deploy path variations and machine-readable single-program submission | deploy [program-name], deploy --program-path, deploy --program-path --json |
| D4 | default |
Core | Wallet management, default-address behavior, and passthrough UX | wallet list, wallet default set, wallet topup --dry-run, wallet topup, wallet -- ... |
| D5 | default |
Advanced | Diagnostics bundle and support artifact hygiene | report, report --out, report --tail |
| D6 | default |
Core | Example runner interaction and account state verification | cargo run --bin run_hello_world, cargo run --bin run_hello_world_with_move_function, wallet -- account get |
| D7 | default |
Core | One-step run pipeline and post-deploy hooks |
run, run --post-deploy, run --no-post-deploy, [run] config |
| L1 | lez-framework |
Core | Fresh LEZ project bootstrap to ready state | new --template lez-framework, setup, localnet start, doctor, build |
| L2 | lez-framework |
Core | LEZ IDL regeneration | build idl |
| L3 | lez-framework |
Advanced | LEZ client generation from current IDL | build client |
| L4 | lez-framework |
Core | LEZ deploy and counter interaction | deploy, cargo run --bin run_lez_counter |
| E1 | N/A | Core | CLI discoverability and error quality | --help, help, --version, unknown commands, out-of-project errors |
| E2 | N/A | Advanced | Project creation with advanced flags and invalid inputs | new --template, new --vendor-deps, new --cache-root |
| E3 | N/A | Core | AI skills materialized into generated and adopted projects | new, new --template lez-framework, init, init re-run |
| B1 | external module project | Core | Basecamp + lgpm setup and idempotent re-run | init, basecamp setup, basecamp doctor, basecamp docs |
| B2 | external module project | Core | Module capture, install, and single-instance launch | basecamp modules, basecamp modules --show, basecamp install, basecamp launch alice |
| B3 | external module project | Core | Two-instance p2p dogfooding | basecamp launch alice, basecamp launch bob (parallel) |
| B4 | external module project | Advanced | Clean-slate scrub semantics on relaunch | basecamp launch alice, basecamp launch alice --no-clean |
| B5 | external module project | Advanced | Portable artefact build for AppImage hand-loading | basecamp build-portable |
Standing Validation Notes
- Project context matters. Many scaffold commands are meant to be run only inside a generated project root. Running them elsewhere should produce a clear error, not silent misbehavior.
- Localnet readiness, listener ownership, and wallet connectivity are high-value validation points. Record contradictions instead of smoothing over them.
- Machine-readable paths matter for tooling. Preserve
--jsonoutputs when a scenario includes them. reportis sanitized on a best-effort basis, not on an absolute guarantee. Always inspect the archive before sharing it.- When wallet behavior depends on an omitted address, verify whether the project default wallet was seeded and persisted as expected.
- Example runner programs (
cargo run --bin run_*) are the final proof that the scaffold pipeline works end-to-end. A successful deploy means nothing if the runner cannot interact with the deployed program.
D1. Default Template Bootstrap and First Success
Goal
Validate that the default template can be scaffolded from the latest repo and reach the documented first-success path.
Preconditions
cargo buildcompleted at the repo root."$SCAFFOLD_BIN"points to the freshly built binary.- Scratch workspace exists and is writable.
Commands / Actions
From the scratch workspace:
cd "$SCRATCH_ROOT"
"$SCAFFOLD_BIN" new dogfood-default
"$SCAFFOLD_BIN" create dogfood-default-create
cd dogfood-default
"$SCAFFOLD_BIN" setup
"$SCAFFOLD_BIN" localnet start
"$SCAFFOLD_BIN" build
"$SCAFFOLD_BIN" deploy
"$SCAFFOLD_BIN" wallet topup
"$SCAFFOLD_BIN" wallet -- check-health
Use new for the main runnable project and create as the lightweight alias-parity check in a separate directory. Both commands also accept --template, --vendor-deps, --lez-path, and --cache-root, but this scenario uses defaults only. See E2 for advanced flag coverage.
Expected Success Signals
- Project creation succeeds and prints the destination path, pinned LEZ commit, and cache root.
setupcompletes after syncing LEZ to the configured pin, building bothsequencer_serviceandwalletinside the project's LEZ tree, and either seeding the default wallet or reporting that a default wallet is already configured.localnet startreports a ready localnet rather than only a spawned PID.buildexits successfully after preparing the project workspace, and — when the project has amethods/Cargo.toml(Risc0 guest crate excluded from the main workspace) — also printsBuilding guest methods...and produces amethods/target/.../releaseartifact.deployprints a submission summary with zero failures when built binaries are present.wallet topupsucceeds without an explicit address because the project default wallet was seeded during setup.wallet -- check-healthsucceeds against the running localnet without requiring a globalwalletinstall or manualPATHchanges.- Generated
scaffold.tomlstores[wallet].home_dirbut does not carry a wallet binary override; wallet location is derived from the pinned LEZ checkout.
Failure Signals / Common Pitfalls
- Running
setup,build,deploy, or wallet commands outside the generated project root should fail with a project-scoped message. - A foreign listener or stale state on the localnet port is a real dogfooding finding; capture
localnet status, not just the final error. - If
wallet topupwithout an address says no destination is configured, record that as a regression in default-wallet seeding or persistence. - If
setupor wallet commands depend onwalletbeing installed globally or onPATH, record that as a regression in the self-contained project model. - If
deployfails due to missing binaries after a successfulbuild, capture the exact missing path.
Evidence to Capture
- Scaffold creation output for both
newandcreate. setup,localnet start,build,deploy, and wallet command excerpts.- The generated project path and the exact binary path used for the run.
Execution Notes
- Use fresh directories per run. Do not reuse an old generated project unless the scenario explicitly targets upgrade or persistence behavior.
- Keep the alias check isolated so a failure in
createdoes not contaminate the primary bootstrap project.
D2. Default Template Operational Health: Localnet and Doctor
Goal
Validate that localnet lifecycle commands and doctor diagnostics provide usable human and machine-readable state.
Preconditions
- A default-template project exists.
setuphas already completed for that project.
Commands / Actions
From the generated project root:
"$SCAFFOLD_BIN" localnet status
"$SCAFFOLD_BIN" localnet status --json
"$SCAFFOLD_BIN" doctor
"$SCAFFOLD_BIN" doctor --json
"$SCAFFOLD_BIN" localnet logs --tail 200
"$SCAFFOLD_BIN" localnet stop
"$SCAFFOLD_BIN" localnet status
If the scenario begins with localnet stopped, run "$SCAFFOLD_BIN" localnet start first and capture both the started and stopped states.
Expected Success Signals
- Human-readable
localnet statusclearly reports tracked PID, listener state, ownership, and readiness. localnet status --jsonreturns parseable JSON with at leasttracked_pid,listener_present,ownership, andready.doctorreturns actionable next steps rather than only raw failures.doctor --jsonreturns parseable JSON with at leaststatus,summary,checks, andnext_steps.localnet logs --tail 200returns useful recent log lines when logs exist.localnet stopsucceeds cleanly and subsequent status reflects the stopped state.
Failure Signals / Common Pitfalls
- Contradictions between tracked PID, listener ownership, and readiness are high-value findings.
- Empty or unhelpful logs after a failed startup are worth recording.
- If
doctoromits next steps or machine-readable output becomes malformed, treat that as a DX regression.
Evidence to Capture
- Human-readable and JSON output for both
localnet statusanddoctor. - A short
localnet logsexcerpt. - Stop behavior and the post-stop status output.
Execution Notes
- Preserve raw JSON output exactly.
- If state is contradictory, do not silently restart localnet before capturing the failing state.
D3. Default Template Deploy Variants and JSON Output
Goal
Validate targeted deployment flows, including the machine-readable single-program submission path via --program-path.
Preconditions
- Default-template project has already completed
build. - Localnet is reachable.
- Guest binaries exist under the generated project's
target/riscv-guest/.../releasedirectory.
Commands / Actions
From the generated project root:
export EXAMPLE_PROGRAMS_BUILD_DIR="$PWD/target/riscv-guest/example_program_deployment_methods/example_program_deployment_programs/riscv32im-risc0-zkvm-elf/release"
"$SCAFFOLD_BIN" deploy hello_world
"$SCAFFOLD_BIN" deploy --program-path "$EXAMPLE_PROGRAMS_BUILD_DIR/hello_world.bin"
"$SCAFFOLD_BIN" deploy --program-path "$EXAMPLE_PROGRAMS_BUILD_DIR/hello_world.bin" --json
"$SCAFFOLD_BIN" deploy nonexistent_program
Use a known default-template program name such as hello_world. If the generated project exposes a different set of programs in methods/guest/src/bin, record the discovered list.
--json only produces structured JSON output when combined with --program-path. On the discovery-based path (deploy or deploy <name>), the --json flag is accepted but silently ignored. This scenario validates that distinction.
Expected Success Signals
deploy hello_worldreportsOK hello_world submittedand ends with a human-readable success summary.deploy --program-path ... --jsonprints a parseable JSON object with at leaststatus,program, andtxfields.deploy --program-path ...without--jsonprints a human-readableOKline with the binary path.deploy nonexistent_programfails with an error listing the available discovered programs.
Failure Signals / Common Pitfalls
- If
deploy hello_world --jsonstarts producing JSON output (instead of the normal human-readable summary), record that as a behavior change worth verifying. - If localnet is unreachable, deploy should fail with a sequencer-unavailable hint instead of a vague wallet error.
- Unknown program names should report the available discovered programs.
- Missing binaries should point back to
logos-scaffold build.
Evidence to Capture
- One successful human-readable deploy excerpt from the discovery path.
- One successful JSON deploy output from the
--program-pathpath. - The error output for an unknown program name.
- Any failure-path excerpt for unreachable sequencer or missing binary when intentionally probed.
Execution Notes
- Keep the
--program-path --jsonexamples separate from discovery-based deploys. Only--program-pathproduces JSON. - When recording a custom
--program-path, preserve the absolute path used in the run log.
D4. Default Template Wallet Workflows and Passthrough
Goal
Validate wallet-focused scaffold behavior beyond the basic bootstrap path.
Preconditions
- Default-template project exists.
- Setup completed successfully.
- Localnet is running if you are validating non-dry-run topup or passthrough health checks.
Commands / Actions
From the generated project root:
"$SCAFFOLD_BIN" wallet list
"$SCAFFOLD_BIN" wallet list --long
"$SCAFFOLD_BIN" wallet default set Public/<account-id>
"$SCAFFOLD_BIN" wallet topup --dry-run
"$SCAFFOLD_BIN" wallet topup
"$SCAFFOLD_BIN" wallet -- account list
"$SCAFFOLD_BIN" wallet -- check-health
Use a real address from wallet list when explicitly validating wallet default set.
Expected Success Signals
wallet listandwallet list --longproxy wallet account enumeration from the project-scoped wallet home using the LEZ-local wallet binary.wallet default setaccepts either positional address or--addressand persists the normalized project default.wallet topup --dry-runrenders the underlying faucet claim command instead of mutating state.wallet topupwithout an explicit address uses the saved default wallet.wallet -- ...preserves the project wallet environment while forwarding the raw wallet command to<lez>/target/release/wallet.
Optional: validate LOGOS_SCAFFOLD_WALLET_PASSWORD override behavior by setting the env var to a non-default value and observing whether wallet commands honor it.
LOGOS_SCAFFOLD_WALLET_PASSWORD="custom-pw" "$SCAFFOLD_BIN" wallet topup --dry-run
Failure Signals / Common Pitfalls
- Invalid addresses should be rejected with an "Accepted formats" hint.
- If both positional address and
--addressare supplied together, that is a user error and should remain clearly reported. - Connectivity failures during topup should mention localnet/sequencer reachability rather than only raw wallet output.
- Passthrough flows require the literal
--; if the CLI starts accepting or mangling passthrough without it, record that change. - If wallet flows only succeed when
walletis separately installed onPATH, or if missing-binary errors point anywhere other than the LEZ-localtarget/release/wallet, record that as a regression.
Evidence to Capture
wallet listoutput with account identifiers redacted only if needed for sharing.wallet topup --dry-runoutput showing the rendered command.- One successful passthrough example, ideally
wallet -- check-healthorwallet -- account list. - If
LOGOS_SCAFFOLD_WALLET_PASSWORDoverride was tested, the dry-run output showing the password was or was not forwarded.
Execution Notes
- Do not let the shell consume the passthrough separator. Record the exact argv form you used.
- If you redact account IDs for public sharing, keep the unredacted originals in a local evidence log so repeated runs stay traceable.
D5. Default Template Diagnostics Bundle
Goal
Validate that scaffold support artifacts can be collected and inspected safely.
Preconditions
- Default-template project exists.
- The project has enough state to make the report meaningful, ideally after setup and at least one localnet or build action.
Commands / Actions
From the generated project root:
"$SCAFFOLD_BIN" report
"$SCAFFOLD_BIN" report --tail 200
"$SCAFFOLD_BIN" report --out "$PWD/artifacts/support-report.tar.gz"
Inspect the produced archive before sharing it:
find .scaffold/reports -maxdepth 1 -name '*.tar.gz' -print | sort
REPORT_ARCHIVE="$(find .scaffold/reports -maxdepth 1 -name '*.tar.gz' | sort | tail -n 1)"
tar -tzf "$REPORT_ARCHIVE" | sort
tar -tzf "$PWD/artifacts/support-report.tar.gz" | sort
Expected Success Signals
reportprints a completion message, archive path, and a warning to inspect files before sharing.- The default output lands under
.scaffold/reports/. - A custom
--outpath is honored. - The archive contains support files such as
README.txt,manifest.json,diagnostics/doctor.json,diagnostics/localnet-status.json, andsummaries/build-evidence.json.
Failure Signals / Common Pitfalls
- If raw wallet files under
.scaffold/wallet/appear in the archive, treat that as a severe regression. - If absolute local paths leak without scrubbing in human-facing report files, record it.
- If the archive is produced but the warning about manual inspection disappears, record it.
Evidence to Capture
- Report completion output.
- Archive path(s).
- A short file listing from the tarball.
Execution Notes
- Never attach the archive to an external system without first listing its contents.
- Keep the tar listing with the run evidence so redaction regressions can be compared across releases.
D6. Default Template Example Runner Interaction
Goal
Validate that deployed programs can actually be invoked via the generated example runner binaries and that account state changes are observable.
D1 validates the scaffold pipeline up to deploy and wallet health. This scenario validates the final step: running programs against the localnet and confirming observable state mutations.
Preconditions
- Default-template project exists with D1 completed (setup, build, deploy done).
- Localnet is running and
wallet -- check-healthsucceeds. - Create a fresh public account for this scenario:
"$SCAFFOLD_BIN" wallet -- account new public
Capture the account ID from the output (format: Public/<base58>). Use the base58 portion as <account-id> below.
Commands / Actions
From the generated project root:
export NSSA_WALLET_HOME_DIR="$PWD/.scaffold/wallet"
cargo run --bin run_hello_world -- <account-id>
"$SCAFFOLD_BIN" wallet -- account get --account-id <account-id>
cargo run --bin run_hello_world_with_move_function -- write-public <account-id> "dogfood-test-message"
"$SCAFFOLD_BIN" wallet -- account get --account-id <account-id>
The first runner (run_hello_world) submits a basic public transaction. The second (run_hello_world_with_move_function write-public) writes a custom greeting string to the account, producing an observable data_b64 field change.
Expected Success Signals
- Both runners print
submitted transaction: status=... tx_hash=...on success. - Both runners print a
verification hint:line pointing towallet account get. - After
run_hello_world_with_move_function write-public,wallet account getshows account data containing the encoded greeting string. - Runner exit code is 0.
Failure Signals / Common Pitfalls
- If a runner exits 0 but the account remains
Uninitialized, the transaction may have been submitted without effect. Record both the runner output and the account state. - Panic output from a runner (e.g.,
unwrap()on wallet/sequencer errors) instead of a structured error is worth recording. - Invalid account ID format (not base58) should produce a clear parse error from the runner, not a panic.
- If localnet is down, runners should fail with a connection-refused error. Capture the exact error text.
Evidence to Capture
- Runner output including
statusandtx_hashfor at least one successful run. wallet account getoutput showing account state after interaction.- The exact account ID used (for traceability across repeated runs).
Execution Notes
NSSA_WALLET_HOME_DIRmust be set for runners that initializeWalletCore::from_env(). The scaffold wallet commands set this automatically, but directcargo rundoes not.- Use the fresh public account created in the preconditions rather than reusing accounts from other scenarios. This avoids confusion about pre-existing state.
- If additional runners are available (e.g.,
run_hello_world_private,run_hello_world_through_tail_call), exercising them is valuable but not required for this scenario.
D7. run Pipeline and Post-Deploy Hooks
Goal
Validate that lgs run collapses the build → IDL → localnet → topup → deploy chain into a single command, fires [run].post_deploy hooks with the documented environment, and that --post-deploy / --no-post-deploy flags override the configured hooks correctly.
Preconditions
- A default-template project exists at
$SCRATCH_ROOT/dogfood-defaultwithsetupalready complete. - No existing scaffold localnet running on the configured port (the scenario will start one). If one exists from a prior scenario, stop it first.
wallet topuphas worked at least once for this project (D1 or D4 covers this).
Commands / Actions
From the project root, exercise the bare pipeline:
"$SCAFFOLD_BIN" run
Then add a [run] section to scaffold.toml and re-run with hooks:
[run]
post_deploy = [
"echo 'sequencer:' $SEQUENCER_URL",
"echo 'idl:' $SCAFFOLD_IDL_DIR",
"echo 'project root:' $SCAFFOLD_PROJECT_ROOT",
"echo 'wallet home:' $NSSA_WALLET_HOME_DIR",
"echo 'program id:' ${SCAFFOLD_PROGRAM_ID:-unavailable}",
"echo 'guest bin:' ${SCAFFOLD_GUEST_BIN:-unavailable}",
]
"$SCAFFOLD_BIN" run
"$SCAFFOLD_BIN" run --post-deploy "echo override" # one-shot override
"$SCAFFOLD_BIN" run --no-post-deploy # skip hooks
"$SCAFFOLD_BIN" run --post-deploy "x" --no-post-deploy # expect clap conflict error
Expected Success Signals
- The first
run(no hooks configured) prints a numbered step header for each phase ([1/5] Building...through[5/5] Deploying...) and ends with a deployed-programs summary. - A second
runreuses the running localnet (localnet already running (sequencer pid=...)) instead of starting a new sequencer. - After adding the
[run]block,runreports[6/6] Running N post-deploy hook(s)and each hook prints a non-empty value for its env var.cwdfor each hook is the project root (verifiable with apwdhook). For a single-program project,$SCAFFOLD_PROGRAM_IDis the deployed program's risc0 image ID and$SCAFFOLD_GUEST_BINis the absolute path to the guest binary. --post-deploy "echo override"ignores[run].post_deployand runs only the override.--no-post-deployskips the post-deploy step entirely; the run prints the deployed-programs summary instead.--post-deploywith--no-post-deployerrors at clap parse time with acannot be used withmessage; exit code is non-zero.- A non-zero hook exit aborts the run with a clear
post-deploy hook exited with status Nmessage.
Failure Signals / Common Pitfalls
- A
runinvocation that restarts the sequencer when one is already running healthy is a regression in the localnet-reuse path. - Hooks running with
cwdsomewhere other than the project root, or missing any ofSEQUENCER_URL/NSSA_WALLET_HOME_DIR/SCAFFOLD_PROJECT_ROOT/SCAFFOLD_IDL_DIR, is a regression in the env contract. $SCAFFOLD_PROGRAM_IDunset after a successful deploy on a single-program project with a vendoredspelbinary is a regression. Hint:lgs setupbuilds the spel binary; if it's missing,program_id: unavailablewill also appear in the deploy summary.
Evidence to Capture
- Console output of the first
runshowing the step headers and the deployed-programs summary. - Output of
runafter the[run]block is added, showing the===> post_deploy[i/n]:markers and the resolved env values. - Output of
run --post-deploy "echo override"showing only the override hook fires. - Output of
run --no-post-deployshowing the deployed-programs summary instead of hooks.
L1. LEZ Template Bootstrap
Goal
Validate that the LEZ template scaffolds and reaches a ready-to-build state.
Preconditions
- Latest scaffold binary has been built from the repo root.
- Scratch workspace exists.
Commands / Actions
From the scratch workspace:
cd "$SCRATCH_ROOT"
"$SCAFFOLD_BIN" new dogfood-lez --template lez-framework
cd dogfood-lez
ls -d idl crates/lez-client-gen methods/guest/src/bin src/bin
"$SCAFFOLD_BIN" setup
"$SCAFFOLD_BIN" localnet start
"$SCAFFOLD_BIN" doctor
"$SCAFFOLD_BIN" build
The ls step verifies that LEZ-specific directories were scaffolded before proceeding with the build pipeline.
Expected Success Signals
- Project creation succeeds with the LEZ template.
- The generated project contains
idl/,crates/lez-client-gen/,methods/guest/src/bin/lez_counter.rs, andsrc/bin/run_lez_counter.rs. setup,localnet start, anddoctorbehave the same way they do for the default template.buildsucceeds for the LEZ project workspace and also runs IDL generation and client generation automatically.
Failure Signals / Common Pitfalls
- If the generated project is missing LEZ-specific paths such as
idl/,crates/lez-client-gen/, ormethods/guest/src/bin/lez_counter.rs, record that immediately. - If LEZ bootstrap behavior diverges from the default template in setup/localnet/doctor flows, capture the difference explicitly.
- If
builddoes not automatically trigger IDL + client generation for the LEZ template, record that as a regression.
Evidence to Capture
- LEZ project creation output.
- Directory listing showing LEZ-specific scaffolded paths.
setup,localnet start,doctor, andbuildexcerpts.
Execution Notes
- Keep LEZ runs separate from default-template runs. The template-specific directories and follow-up commands are part of the validation.
L2. LEZ IDL Regeneration
Goal
Validate that LEZ projects can regenerate IDL from the current project source.
Preconditions
- LEZ project exists.
- The LEZ project build environment is working.
Commands / Actions
From the LEZ project root:
"$SCAFFOLD_BIN" build idl
find idl -maxdepth 1 -type f -name '*.json' | sort
Expected Success Signals
build idlwrites one or more JSON files underidl/.- Command output includes explicit
Wrote IDL ...lines. - The regenerated files are valid JSON and match the current program surface.
Failure Signals / Common Pitfalls
- If the command prints that IDL build is being skipped due to framework kind, the scenario is running in the wrong project.
- Missing IDL marker output or empty IDL generation is a real regression for the LEZ template.
Evidence to Capture
build idloutput.- Listing of generated files under
idl/. - If relevant, a diff between pre-existing and regenerated IDL.
Execution Notes
- Preserve the raw
Wrote IDL ...lines. They make it much easier to diagnose partial-generation failures.
L3. LEZ Client Generation
Goal
Validate that LEZ client bindings can be regenerated from the current IDL set.
Preconditions
- LEZ project exists.
build idlhas been run successfully, either directly or viabuild client.
Commands / Actions
From the LEZ project root:
"$SCAFFOLD_BIN" build client
find src/generated -type f | sort
Expected Success Signals
build clientreports that it is regenerating IDL before generating client code.- Client artifacts are written under
src/generated. - The generated files reflect the current contents of
idl/.
Failure Signals / Common Pitfalls
- If
build clientdoes not refresh IDL first, record that behavior change. - Missing
src/generatedoutput or missing generator crate paths are LEZ-specific regressions.
Evidence to Capture
build clientoutput.- Listing of files under
src/generated. - Any diff in generated client code when the scenario is rerun after a program change.
Execution Notes
- Treat generated client output as part of the scenario evidence, not as disposable noise.
- When the generator fails, capture the exact manifest path and working directory that were used.
L4. LEZ Template Deploy and Counter Interaction
Goal
Validate that the LEZ counter program can be deployed and that the generated runner binary can invoke init and increment subcommands against the running localnet.
Preconditions
- LEZ project exists with L1 completed (setup, build, localnet running).
wallet -- check-healthsucceeds.- At least one public account exists. If not:
"$SCAFFOLD_BIN" wallet -- account new public
Commands / Actions
From the LEZ project root:
"$SCAFFOLD_BIN" deploy
export NSSA_WALLET_HOME_DIR="$PWD/.scaffold/wallet"
cargo run --bin run_lez_counter -- init --to <account-id>
cargo run --bin run_lez_counter -- increment --counter <account-id> --authority <account-id> --amount 5
Expected Success Signals
deploysubmits thelez_counterprogram and prints a success summary.run_lez_counter initprints confirmation that the counter was initialized at the target account.run_lez_counter incrementprints confirmation of the increment operation.
Note: as of this writing, the LEZ counter runner contains TODO placeholders for actual transaction submission. If the runner only prints diagnostic messages without submitting transactions, record that as the current state. When transaction submission is implemented, update this scenario with account-state verification steps matching D6.
Failure Signals / Common Pitfalls
- If
deploycannot findlez_counterin the discovered program list, record the actual discovered list. - If the runner panics on wallet initialization,
NSSA_WALLET_HOME_DIRmay not be set. - If the runner accepts the subcommand but does nothing (due to TODO stubs), record the output and note the gap.
Evidence to Capture
deployoutput for the LEZ project.run_lez_counter initandincrementoutput.- Whether the runner actually submitted transactions or only printed placeholder messages.
Execution Notes
NSSA_WALLET_HOME_DIRmust be set for the runner. Scaffold wallet commands set this automatically, but directcargo rundoes not.- Keep LEZ interaction evidence separate from default-template interaction evidence.
E1. CLI Discoverability and Error Quality
Goal
Validate that the scaffold CLI provides consistent, non-destructive help and version output, useful error messages for unknown commands, and clear project-context errors when commands are run outside a generated project.
Preconditions
- Latest scaffold binary has been built from the repo root.
- A scratch workspace exists (for verifying that help flags do not create files).
Commands / Actions
From the repo root:
"$SCAFFOLD_BIN" --help
"$SCAFFOLD_BIN" --version
"$SCAFFOLD_BIN" help
"$SCAFFOLD_BIN" setup --help
"$SCAFFOLD_BIN" setup --wallet-install auto
"$SCAFFOLD_BIN" nonexistent-command
"$SCAFFOLD_BIN" build
"$SCAFFOLD_BIN" deploy
"$SCAFFOLD_BIN" doctor
"$SCAFFOLD_BIN" localnet status
"$SCAFFOLD_BIN" wallet list
From the scratch workspace (verify help flags do not mutate the filesystem):
cd "$SCRATCH_ROOT"
ls -la before_help_test > /dev/null 2>&1 || true
"$SCAFFOLD_BIN" create --help
"$SCAFFOLD_BIN" new --help
ls -la
Check that no new directories were created by the --help invocations.
Expected Success Signals
--helpprints a usage summary listing all top-level commands.--versionprints the version string and exits.helpprints the same top-level usage summary as--helpand exits successfully.setup --helpdocuments the setup workflow without a--wallet-installflag.- Legacy
setup --wallet-install autois rejected during argument parsing as an unknown argument. nonexistent-commandfails with an error and directs the user to--helpor an equivalent corrective hint.build,deploy,doctor,localnet status, andwallet listrun from outside a project fail with a message likeNot a logos-scaffold project ... Run logos-scaffold create <name>.create --helpandnew --helpdo not create directories or files in the current working directory.
Failure Signals / Common Pitfalls
- If
create --helpornew --helpcreates a directory named--help, that is a significant UX regression. Record it and the exact argv used. - If project-context errors are missing or unhelpful (e.g., a raw file-not-found instead of a scaffold-specific message), record the exact output.
- If some subcommands support
--helpand others do not, document the inconsistency. - If
setup --helpstill advertises--wallet-install, or the deprecated flag is silently accepted, record that as a command-surface regression.
Evidence to Capture
--helpoutput.--versionoutput.- Error output for unknown command and out-of-project commands.
- Directory listing before and after
create --help/new --helpto confirm no side effects.
Execution Notes
- Run the
create --helptest in an isolated temporary directory so any accidental file creation does not pollute the scratch workspace. - Do not interpret missing
--helpsupport on a subcommand as a blocker. Record it as a finding and move on.
E2. Project Creation with Advanced Flags
Goal
Validate that create/new handle the --template, --vendor-deps, --lez-path (legacy alias: --lssa-path), and --cache-root flags correctly, including error cases for invalid inputs.
Preconditions
- Latest scaffold binary has been built from the repo root.
- Scratch workspace exists and is writable.
Commands / Actions
From the scratch workspace:
cd "$SCRATCH_ROOT"
"$SCAFFOLD_BIN" new dogfood-invalid-template --template nonexistent-template
"$SCAFFOLD_BIN" new dogfood-lez-explicit --template lez-framework
ls -d dogfood-lez-explicit/idl dogfood-lez-explicit/crates/lez-client-gen
"$SCAFFOLD_BIN" new dogfood-vendor --vendor-deps
"$SCAFFOLD_BIN" new dogfood-cache --cache-root "$SCRATCH_ROOT/custom-cache"
find "$SCRATCH_ROOT/custom-cache/repos/lez" -maxdepth 2 -mindepth 1 -type d | sort
grep -n "^\[wallet\]\|^home_dir\|^binary" dogfood-cache/scaffold.toml
Expected Success Signals
- Invalid
--templatename fails with a clear error listing the available templates (default,lez-framework). --template lez-frameworkcreates a project with LEZ-specific structure (same as L1).--vendor-depsis accepted without error and creates a project that vendors the pinned LEZ repo under.scaffold/repos/lez.--cache-rootis honored and scaffold uses the specified directory for cache operations, with non-vendored LEZ clones isolated by pin under<cache-root>/repos/lez/<pin>/.- Generated
scaffold.tomlincludes[wallet].home_dirand does not include a deprecatedwallet.binaryfield.
Failure Signals / Common Pitfalls
- If an invalid template name silently falls back to
default, record that as a regression. - If
--vendor-depsor--cache-rootare silently ignored or produce an error, record the exact output. - If
--lez-pathis tested and the path does not exist, verify the error message points to the bad path. - If non-vendored cache reuse collapses different LEZ pins into a single shared
repos/lezcheckout, record that as a cache-isolation regression.
Evidence to Capture
- Error output for invalid
--template. - Creation output for
--template lez-frameworkwith directory listing. - Creation output for
--vendor-depsand--cache-rootif tested. - Directory listing proving the pin-isolated cache path.
scaffold.tomlexcerpt showing wallet home config without a wallet binary field.
Execution Notes
- Clean up the generated projects after this scenario to avoid consuming disk space with multiple scaffolded projects.
- The
--lez-pathflag is optional to test here because it requires a real LEZ checkout. Only probe it if one is available.
E3. AI Skills Materialized Into Every Project
Goal
Validate that lgs new and lgs init both drop the canonical AI skill set
into a generated project so that Claude Code, Cursor, and Codex pick them up
without manual configuration. Skills are version-controlled in the generated
project (no .gitignore exclusion).
Preconditions
- Latest scaffold binary built from the repo root (
"$SCAFFOLD_BIN"). - Scratch workspace exists.
Commands / Actions
From the scratch workspace:
cd "$SCRATCH_ROOT"
"$SCAFFOLD_BIN" new dogfood-skills-default
"$SCAFFOLD_BIN" new dogfood-skills-lez --template lez-framework
mkdir dogfood-skills-init && cd dogfood-skills-init
"$SCAFFOLD_BIN" init
shasum AGENTS.md .claude/skills/lgs-cli/SKILL.md .cursor/rules/lgs-cli.mdc
"$SCAFFOLD_BIN" init # re-init must succeed and not change skill content
shasum AGENTS.md .claude/skills/lgs-cli/SKILL.md .cursor/rules/lgs-cli.mdc
Inspect the generated layout in each of the three projects:
find dogfood-skills-default/.claude/skills dogfood-skills-default/.cursor/rules -type f | sort
find dogfood-skills-lez/.claude/skills dogfood-skills-lez/.cursor/rules -type f | sort
ls dogfood-skills-default/AGENTS.md dogfood-skills-lez/AGENTS.md dogfood-skills-init/AGENTS.md
Expected Success Signals
- Every generated project (default template, lez-framework template, and
init-adopted bare directory) contains exactly four.claude/skills/<name>/SKILL.mdfiles:lgs-cli,lez-template,lez-framework-template,basecamp. - The same four skills appear under
.cursor/rules/<name>.mdc. AGENTS.mdexists at every project root, lists all four skills with their descriptions, and links to.claude/skills/<name>/SKILL.md.- Re-running
initon an already-migrated project succeeds (no longer bails) and printsAI skills refreshed under .claude/skills/, .cursor/rules/, AGENTS.md.Theshasumoutput before and after a re-init is byte-identical for all three skill files. .claude/skills/<name>/SKILL.mdis byte-identical to the canonical source under<scaffold-repo>/skills/<name>/SKILL.md(rundiffif validating against a built-from-source binary)..cursor/rules/<name>.mdcfrontmatter containsdescription:andalwaysApply: false, and does not contain aname:field. The body after the closing---is identical to the SKILL.md body.- The generated
.gitignoredoes not exclude.claude/,.cursor/, orAGENTS.md.
Failure Signals / Common Pitfalls
- A skill missing from one of the three locations in any generated project is a regression — every project gets the same four-skill set per the v0.1 contract.
- A
.cursor/rules/<name>.mdcthat still carries thename:line from the source SKILL.md is a regression in the frontmatter rewrite. - A re-
initthat errors with "already at schema" is a stale build — that bail was removed when skill refresh became part of init's contract. - A re-
initthat mutates skill content without a corresponding canonical-source change is a regression in idempotency. - Skills appearing in
.gitignoreis a regression — they are version-controlled by design. - Hand-edited team skills under
.claude/skills/<other>/that get clobbered byinitare a regression —apply_skillsonly owns the four shipped names.
Evidence to Capture
- File listings under
.claude/skills/,.cursor/rules/, and the existence ofAGENTS.mdfor each of the three project flavors. - One
.cursor/rules/<name>.mdchead excerpt showing the rewritten frontmatter. AGENTS.mdexcerpt showing the four-row table.shasumpairs from the re-initidempotency check.
Execution Notes
- This scenario does not require
setup,localnet, or any network access — it validates only the materialization contract. - Pair with E2 when validating template-related changes; pair with B1 when validating
initbehavior alongside basecamp adoption.
B1. Basecamp Setup From a Module Project
Goal
Validate that a module project can fetch the pinned basecamp + lgpm binaries, seed the alice and bob profiles, and that re-running setup is idempotent.
Preconditions
- Nix with flakes enabled.
- Latest scaffold binary built from the repo root (
"$SCAFFOLD_BIN"). - A module project on disk whose
flake.nixexposespackages.<system>.lgx(see"$SCAFFOLD_BIN" basecamp docs). Reachable as$MODULE_PROJECT. scaffold.tomlis present at the project root; if not, run"$SCAFFOLD_BIN" initonce.
Commands / Actions
From the module project root:
cd "$MODULE_PROJECT"
test -f scaffold.toml || "$SCAFFOLD_BIN" init
"$SCAFFOLD_BIN" basecamp --help
"$SCAFFOLD_BIN" basecamp docs | head
"$SCAFFOLD_BIN" basecamp setup
ls .scaffold/basecamp/profiles
"$SCAFFOLD_BIN" basecamp doctor
"$SCAFFOLD_BIN" basecamp doctor --json
"$SCAFFOLD_BIN" basecamp setup
Expected Success Signals
basecamp --helplistssetup,modules,install,launch,build-portable,doctor, anddocs.basecamp docsprints the canonical project-compatibility rules (mirrorsdocs/basecamp-module-requirements.md).- First
basecamp setupclones the pinned basecamp repo into a pin-isolated cache path, buildsbasecampandlgpmvia Nix, seeds.scaffold/basecamp/profiles/alice/and.scaffold/basecamp/profiles/bob/, and reports completion. basecamp doctorreports the basecamp + lgpm binaries as present and both profiles as seeded;--jsonreturns parseable JSON with the same checks.- Second
basecamp setupis idempotent: pin unchanged → no rebuild reported, exit 0. - All commands run only inside the project; running them from outside the project must fail with the existing scaffold "not a logos-scaffold project" message.
Failure Signals / Common Pitfalls
- Raw nix or
lgpmstack traces with no scaffold-side hint are a UX regression — the setup-missing path is supposed to be a single one-line hint. - A
setupre-run that rebuilds when the pin has not changed is a regression in idempotency. - Profile directories under
.scaffold/basecamp/profiles/missing after firstsetupis a fail. - If
basecampcommands write to the user's global~/.local/share/Logos/or~/Library/Application Support/Logos/, that is a severe regression — basecamp state is project-local under.scaffold/basecamp/. - If the basecamp binary lands on
PATH, that is a contract violation.
Evidence to Capture
basecamp --helpoutput.- First and second
basecamp setupoutput (to compare rebuild vs. no-rebuild). basecamp doctorandbasecamp doctor --jsonoutput.- Listing of
.scaffold/basecamp/profiles/.
Execution Notes
- Do not pollute the user's home; basecamp setup must stay under
<project>/.scaffold/basecamp/. If something writes outside that root, stop and capture it before continuing. - Pin-changed re-runs (rebuild path) are a separate validation; capture them when intentionally bumping the pin, not as part of this scenario.
B2. Module Capture, Install, and Single-Instance Launch
Goal
Validate the per-project source of truth for module identity ([modules] in scaffold.toml), the install pipeline that builds .lgx artefacts and loads them via lgpm, and a single-profile launch.
Preconditions
- B1 completed in the same project.
- Module project's
flake.nix(root or one or more sub-flakes) exposespackages.<system>.lgx. Sub-flake projects (e.g.,tictactoe-ui-cpp/,tictactoe-ui-qml/) are valid. - A graphical environment if you intend to actually drive the launched basecamp UI;
launchitself does not require X/Wayland to start, but interactive validation does.
Commands / Actions
From the module project root:
"$SCAFFOLD_BIN" basecamp modules
grep -n '^\[modules\.' scaffold.toml
"$SCAFFOLD_BIN" basecamp modules --show
"$SCAFFOLD_BIN" basecamp install
"$SCAFFOLD_BIN" basecamp install --print-output
"$SCAFFOLD_BIN" basecamp doctor
"$SCAFFOLD_BIN" basecamp launch alice
If your project does not auto-discover correctly, capture explicit sources:
"$SCAFFOLD_BIN" basecamp modules --flake "./tictactoe#lgx" --flake "./tictactoe-ui-qml#lgx"
"$SCAFFOLD_BIN" basecamp modules --path /abs/path/to/prebuilt.lgx
Expected Success Signals
basecamp moduleseither auto-discovers project sub-flakes exposing.#lgxor accepts explicit--path/--flakesources and writes one[modules.<name>]sub-section per source intoscaffold.toml. The file remains human-editable; re-runs are byte-identical and never overwrite existing keys.- For each captured project source, scaffold also resolves declared
dependenciesand insertsrole = "dependency"entries unless the dep is already keyed, is a basecamp preinstall (capability_module,package_manager,package_manager_ui,counter,counter_qml,webview_app,basecamp_main_ui; seeBASECAMP_PREINSTALLED_MODULESinsrc/constants.rsfor the authoritative list), or is resolvable via the source's ownflake.lock/ the scaffold-default table. - An unresolvable dep fails fast with a targeted error naming the dep and the two user-side fixes (capture as a project source, or add
[modules.<name>]withrole = "dependency"); no silent drop. basecamp modules --showprints the captured set without mutating state.basecamp installbuilds each project source (sibling--override-inputrewrites apply forpath:../<sibling>inputs in multi-flake projects) and shells out tolgpmto install into bothaliceandbob. By default it logs to.scaffold/logs/<ts>-install.logand prints a one-line status;--print-output(orLOGOS_SCAFFOLD_PRINT_OUTPUT=1) streams nix output directly.basecamp doctorreports each profile's installed modules matching the captured set; drift between[modules]and on-disk profile state is flagged, not hidden.basecamp launch alicekills any priorlogos_host/logos-basecampdescendants for that profile, scrubs the profile's XDG dirs under.scaffold/basecamp/profiles/alice/, reinstalls each captured source for that profile, setsXDG_{CONFIG,DATA,CACHE}_HOMEplusLOGOS_PROFILE=alice, andexecs basecamp.
Failure Signals / Common Pitfalls
- A flake that exposes only
.#lgx-portableand not.#lgxmust fail explicitly with a hint pointing at--flake <ref>#lgx-portablefor opt-in. Silent fallback is a contract violation. - Re-running
basecamp modulesoverwriting an existing key is a regression — manual edits inscaffold.tomlmust win. - An unresolved transitive
logos-module-builderinput that fails without naming the missingfollowsis a regression. installsucceeding when a build orlgpm installstep actually failed is a fail; exit codes must be non-zero on any source failure.launch alicewith an empty[modules]and without--no-cleanmust bail (rather than scrubbing the profile and leaving it empty).- Sibling
--override-inputnot being applied at probe time would surface as a build that resolves the wrong sibling pin duringbasecamp modulesauto-discovery; record any such mismatch with the exact derived module names.
Evidence to Capture
scaffold.tomlexcerpt showing[modules.<name>]sub-sections withflake,role, and (for project sources) the in-project relative path used.basecamp modules --showoutput.basecamp installlog path under.scaffold/logs/plus the printed one-line status, or the--print-outputstream.basecamp doctoroutput post-install.- The first lines of
basecamp launch aliceshowing the kill → scrub → reinstall → exec sequence.
Execution Notes
basecamp modulesis the sole automated writer of[modules]. If the user manually edited an entry, do not re-runbasecamp modulesmid-scenario without recording the pre-edit state — manual entries are intentionally preserved.- Only
path:../<sibling>flake inputs are sibling-rewritten;path:./sub,github:, andgit+schemes pass through. If a project uses multi-line input declarations, the line-level parser may not detect them — record any sibling-override miss along with the offendingflake.nixexcerpt.
B3. Two-Instance P2P Dogfooding
Goal
Validate the canonical basecamp use case: two profiles running simultaneously on one machine and exercising p2p features (chat, delivery, storage) of the project's .lgx modules.
Preconditions
- B1 and B2 completed in the same project.
basecamp installhas captured at least one project source and produced a successful install for bothaliceandbob.- A graphical environment for both basecamp windows.
Commands / Actions
From two terminals, both rooted at the module project:
Terminal 1:
"$SCAFFOLD_BIN" basecamp launch alice
Terminal 2:
"$SCAFFOLD_BIN" basecamp launch bob
Within the running UIs, exercise whatever p2p surface the module exposes (chat exchange, delivery between peers, storage round-trip). Capture screenshots or short transcripts.
Expected Success Signals
- Both basecamp windows open against their own profile dirs under
.scaffold/basecamp/profiles/{alice,bob}/. - Each window shows the project's
.lgxmodules installed and ready. LOGOS_PROFILE=aliceandLOGOS_PROFILE=bobare visible in each respective process environment (helpful for debugging).- The two instances do not collide on Qt remote-objects or any non-module port; per-profile port-override env vars (per the spec) are set on each
launch. - A p2p interaction triggered from
aliceis observable inbob(and vice versa) within the module's expected latency window.
Failure Signals / Common Pitfalls
- Two windows opening but sharing identity keys, profile state, or message history is a clean-slate / XDG-isolation regression.
- A non-module port collision (Qt remote objects, etc.) is a real finding — file upstream against the affected component, do not patch around it inside scaffold.
- A module that does not honor an externally-provided port override is documented as a known gap pending an upstream fix on that module; capture the module name, the env var that should have worked, and the observed collision.
- One window crashing while the other survives is recordable evidence; capture the crashing instance's logs from
.scaffold/basecamp/profiles/<name>/before relaunching. - Running
basecamp launch alicetwice in parallel is undefined in v1 — record the behavior if you trip it accidentally, but don't treat it as a supported scenario.
Evidence to Capture
- The exact two-terminal command sequence used.
- A short transcript or screenshot pair showing a p2p interaction propagating from one instance to the other.
- The env block of each running process (e.g.,
tr '\0' '\n' < /proc/<pid>/environ | grep -E 'XDG_|LOGOS_'). - Any port-collision error text verbatim, with the module that owns the colliding port.
Execution Notes
- Do not start
aliceandbobfrom the same shell with&backgrounding unless you also redirect their logs; use two terminals for clean log separation. - If the underlying module surface is not yet wired for p2p between profiles, record the gap and the module's TODO state rather than declaring B3 a pass.
B4. Clean-Slate Verification
Goal
Validate that basecamp launch <profile> scrubs profile state by default and that --no-clean is the only path to preserve state across launches.
Preconditions
- B2 completed (alice has captured modules and at least one successful install).
Commands / Actions
From the module project root:
"$SCAFFOLD_BIN" basecamp launch alice # let it come up, then close it
ls .scaffold/basecamp/profiles/alice
mkdir -p .scaffold/basecamp/profiles/alice/.scaffold-xdg-data/scratch
echo "marker-$(date -u +%s)" > .scaffold/basecamp/profiles/alice/.scaffold-xdg-data/scratch/marker.txt
"$SCAFFOLD_BIN" basecamp launch alice # default: scrub-and-reinstall
test -e .scaffold/basecamp/profiles/alice/.scaffold-xdg-data/scratch/marker.txt && echo "REGRESSION: marker survived clean launch" || echo "OK: marker scrubbed"
"$SCAFFOLD_BIN" basecamp launch alice --no-clean # escape hatch: preserve state
Expected Success Signals
- The default
launch aliceremoves any user-introduced files under the alice profile XDG dirs and reinstalls each captured source beforeexecing basecamp. launch alice --no-cleanskips the scrub and reinstall; pre-existing files in the profile survive.rm -rfonlaunchis bounded to<project>/.scaffold/basecamp/profiles/<profile>/. Never any path outside that root.- A
launchthat finds no modules in[modules]and is invoked without--no-cleanbails before scrubbing (the empty-install + scrubbed profile combination is the regression we're guarding against).
Failure Signals / Common Pitfalls
- The
marker.txtfile surviving the defaultlaunch aliceis a regression: clean-slate is the v1 contract. --no-cleantriggering a scrub anyway is an escape-hatch regression.- A
launchscrubbing a path outside the profile's XDG dirs is a severe safety regression — capture the offending path and stop. - An empty
[modules]plus a defaultlaunchthat wipes the profile and leaves it empty is the exact bug guarded byfix(basecamp): bail on empty [modules] in launch without --no-clean; if you can reproduce it, that's a real regression.
Evidence to Capture
- The marker write, the post-clean-launch listing, and the post-
--no-cleanlisting. - The exact path under which the marker was placed and the path basecamp scrubbed (verify they match the profile root).
- Any unexpected paths touched by
launchoutside.scaffold/basecamp/profiles/<profile>/.
Execution Notes
- Use a marker filename and timestamp you can search for after the fact; do not rely on visual inspection alone.
- Clean-slate state is project-local; never test scrub behavior against the user's global Logos directories.
B5. Build-Portable Artefacts for AppImage Hand-Loading
Goal
Validate that project sources captured under [modules] with role = "project" can be built against their #lgx-portable flake output for hand-loading into a basecamp AppImage, and that runtime role = "dependency" entries are skipped.
Preconditions
- B2 completed (project sources are captured and
basecamp installhas succeeded against.#lgx). - The same flakes also expose
packages.<system>.lgx-portable.
Commands / Actions
From the module project root:
"$SCAFFOLD_BIN" basecamp build-portable
ls .scaffold/basecamp/portable 2>/dev/null || find .scaffold -maxdepth 4 -name '*lgx-portable*' -o -name '*.tgz' | sort
Expected Success Signals
build-portablebuilds.#lgx-portablefor eachrole = "project"entry in[modules], in dependency order, and writes / symlinks the resulting artefacts under.scaffold/.role = "dependency"entries are skipped — the target AppImage provides its own copies.- A flake that does not expose
.#lgx-portablefails with a targeted error naming the missing attribute, not a raw nix trace.
Failure Signals / Common Pitfalls
- A
build-portablethat silently falls back from.#lgx-portableto.#lgxis a contract violation — the variant choice is the user's. - Building dependency entries (those with
role = "dependency") is wasted work and a behavior regression. - Out-of-order builds that ignore the dependency graph between project sources are a regression introduced by changes to ordering logic.
Evidence to Capture
basecamp build-portableoutput excerpt including the per-source build lines.- The directory listing of the produced artefacts under
.scaffold/. - For any failure, the exact missing flake attribute and the offending project source.
Execution Notes
- This scenario does not exercise the AppImage itself — it stops at producing artefacts. Hand-loading into a basecamp AppImage is owned by the AppImage release, not by scaffold.
Minimum Rerun Guidance for Future Changes
- Changes to onboarding, project creation, setup, localnet, or build flows: rerun
D1,D2, andD6. - Changes to deploy behavior or deploy output formatting: rerun
D3andD6. - Changes to wallet flows or wallet-related defaults: rerun
D4. - Changes to diagnostics, report contents, or redaction logic: rerun
D5. - Changes to example runner binaries or template
src/bin/*code: rerunD6. - Changes to
runstep ordering, post-deploy env vars, post-deploy CLI override flag handling, or[run]config parsing: rerunD7. - Changes to LEZ template scaffolding or generated outputs: rerun
L1,L2,L3, andL4. - Changes to CLI argument parsing, help text, or error messages: rerun
E1. - Changes to
create/newflags or template selection logic: rerunE2. - Changes to AI skill materialization (
apply_skills, the canonicalskills/source, frontmatter rewrite,AGENTS.mdtemplate, orinitre-run semantics): rerunE3. - Changes to
basecamp setup(pin sync, lgpm build, profile seeding, idempotency) orbasecamp doctor: rerunB1. - Changes to
[modules]derivation, dependency resolution, sibling--override-inputhandling, orbasecamp installinvocation oflgpm: rerunB2. - Changes to
basecamp launch(kill-and-scrub semantics, XDG isolation, port-override env vars, p2p surface): rerunB3. - Changes to clean-slate /
--no-cleansemantics or the empty[modules]guard onlaunch: rerunB4. - Changes to
basecamp build-portable(project/dependency role split, ordering, attr selection): rerunB5.
When in doubt, rerun more scenarios rather than fewer.