base-demo Contracts
August 28, 2026 ยท View on GitHub
base-demo contracts are binding promises that should fail loudly when implementation, docs, demo behavior, or CI drift apart. This registry lists the highest-value invariants for the reference project and points each one at its source of truth and executable enforcement.
Update this file when adding a new durable invariant, expanding the representative environment, or changing demo behavior that other docs or tests depend on.
Contract Registry
| Contract | Promise | Source of truth | Enforced by | Failure mode | Area |
|---|---|---|---|---|---|
project-baseline-required | The project-baseline catalog entry remains present and required: true. | services/catalog.json | tests/validate.sh, tests/services_test.bats | The baseline project health entry can become optional or disappear, making service checks pass while the project shape is broken. | Services |
http-health-url | Every service with check.type == "http" declares a non-empty health_url. | services/catalog.json | tests/validate.sh, tests/services_test.bats | HTTP checks cannot report a useful endpoint, or service status drifts from the catalog. | Services |
non-interactive-demo | demo/demo.sh --non-interactive succeeds in the baseline CI environment. | demo/demo.sh, base_manifest.yaml demo.script | tests/demo_test.bats, .github/workflows/tests.yml | The project-owned walkthrough becomes stale, interactive-only, or unable to prove the documented Base loop. | Demo |
manifest-trust-flow | The user-facing Base loop reviews safe list/dry-run surfaces before basectl trust allow base-demo, and only then executes project-owned manifest commands. | README.md, .github/workflows/tests.yml | tests/validate.sh | The Quick Start can drift from Base's fail-closed manifest-command trust model, causing first-run command execution to fail or encouraging unreviewed approval. | Security |
agent-ready-repo-guidance | The repo demonstrates Base's agent-ready repository contract with a dry-run repo init --agent-ready preview and a real repo check . --agent-ready verification over AGENTS.md, skills.md, and AI context. | README.md, AGENTS.md, skills.md, .ai-context/ | tests/validate.sh, tests/demo_test.bats, .github/workflows/tests.yml | Repo-local agent guidance can drift into hand-maintained files that Base no longer generates or verifies. | Docs |
language-profile | project.languages declares the normalized Python, Go, Java, C, C++, and JavaScript profile represented by the committed fixtures; the list is metadata-only. | base_manifest.yaml, services/ | tests/validate.sh, tests/demo_test.bats, .github/workflows/tests.yml | The representative environment can drift away from the manifest taxonomy, or the manifest can imply unsupported automatic toolchain setup. | Manifest |
environment-schema | Every environments/*.json file is validated before use for exact top-level fields, HTTP(S) URLs, mode/operational consistency, logging values, nested booleans/ports, and service-catalog plus Compose references. BASE_DEMO_ENV=baseline remains a health marker distinct from the default services --env dev selector. | bin/base_demo_environment.py, bin/base-demo-environments, environments/*.json | tests/environments_test.bats, tests/validate.sh, demo/demo.sh | Invalid nested configuration or unknown service/infrastructure references can reach lifecycle commands, or users can confuse Base activation health with deployment selection. | Environments |
environment-aware-services | Every services operation uses the validated environment selection, and mutating lifecycle commands reject modeled non-operational environments before invoking Compose or processes. | bin/base_demo_environment.py, bin/base-demo-services, environments/*.json | tests/environments_test.bats, tests/services_test.bats, tests/validate.sh | Staging or production examples can start local dependencies, or commands can disagree about enabled services and requiredness. | Runtime |
uv-project-manager | The project manifest opts into python.manager: uv, and the committed pyproject.toml plus uv.lock define the dependency-manager-owned project environment. | base_manifest.yaml, pyproject.toml, uv.lock | tests/validate.sh, Base-backed setup/check/doctor CI | Base-demo can silently fall back to a Base-managed venv, leaving manually installed Python packages outside the uv drift contract. | Python |
uv-runner-command | The uv-info command uses runner: uv in the manifest. | base_manifest.yaml, src/uv-info.py | tests/validate.sh, tests/demo_test.bats | The runner teaching surface silently becomes an ordinary command and no longer proves command-level runner selection. | Manifest |
activation-owned-env | .base/activate.sh owns the BASE_DEMO_ENV=baseline default for the green path. | .base/activate.sh, base_manifest.yaml health.required_env | tests/validate.sh, tests/demo_test.bats | Health checks pass because unrelated shell state sets the variable, hiding activation drift. | Activation |
manifest-artifacts | The manifest artifacts list stays non-empty and includes the bats-core tool artifact. | base_manifest.yaml | tests/validate.sh, demo/demo.sh | Setup no longer demonstrates artifact reconciliation or the test tool prerequisite. | Manifest |
runtime-platform-env | The env command prints BASE_OS, BASE_PLATFORM, BASE_HOST_ENV, and BASE_HOST with the other Base runtime values. | src/env.sh | tests/validate.sh, tests/demo_test.bats, demo/demo.sh | Learners cannot discover the current Base runtime platform and host-environment contract from base-demo. | Runtime |
python-env-privacy | The Python env command exposes only documented public Base diagnostics, renders secret-looking BASE_* names as [REDACTED], and the walkthrough sanitizes captured environment output before displaying it. | lib/python/base_demo_cli/__main__.py, demo/demo.sh | lib/python/base_demo_cli/tests/test_cli.py, tests/demo_test.bats, tests/validate.sh | Project or workflow credentials can leak through direct inspection or the interactive and non-interactive walkthrough. | Security |
installer-checksum | Release-mode bootstrap uses the reviewed Base v1.8.0 installer and commit plus the base-demo v0.1.0 release commit, verifies the installer checksum, and refuses to move divergent existing checkouts. Explicit --dev or BASE_DEMO_DEV_MODE=1 reuses local contributor checkouts without pulling or switching revisions and visibly permits moving-source overrides. | install.sh | tests/install_test.bats, docs/release.md | Two users can receive different bootstrap code, a release installer can execute an unverified input, or a contributor's feature branch can be silently switched or updated. | Security / Release |
service-log-permissions | Process-backed service log files are created or corrected to mode 0600 before writes. | bin/base-demo-services | tests/services_test.bats | Service logs can expose local process output through permissive file modes. | Security |
service-catalog-schema | Canonical services/catalog.json and custom --catalog inputs use one validator for the root object, services array, object entries, safe unique names, and known scalar/nested field types; malformed input returns a field-specific usage error without a traceback. | bin/base_demo_environment.py, bin/base-demo-services, services/catalog.json | tests/services_test.bats, tests/environments_test.bats, tests/validate.sh | Malformed user input can reach lifecycle code, expose Python tracebacks, or behave differently depending on whether the catalog is canonical or custom. | Runtime |
service-state-containment | Canonical and custom catalog names are safe lowercase slugs; process state and log files remain direct, non-symlink children of the configured state directory, use mode 0600, and state updates replace complete temporary files atomically. | bin/base-demo-services, bin/base_demo_environment.py | tests/services_test.bats, tests/environments_test.bats | Crafted catalog names or filesystem links can redirect lifecycle writes outside the state directory, expose process metadata, or leave partial state. | Security |
service-lifecycle-transactions | Lifecycle plans validate before mutation; start stops at the first failure and rolls back invocation-owned process and Compose resources; restart preflights process ownership and never starts replacements after a stop failure; primary and rollback failures remain distinct. | bin/base-demo-services | tests/services_test.bats, tests/infra_test.bats | A failed command can continue starting later services, stop resources that predated the invocation, or launch a restart replacement alongside an instance it could not safely stop. | Runtime |
service-process-identity | Process startup waits for survival and configured readiness, state records PID plus process-group/start identity, and stop refuses mismatched live PIDs. Native fixtures use owned-process health and claim no network port. | bin/base-demo-services, services/catalog.json | tests/services_test.bats, tests/native_services_test.bats, tests/python_api_test.bats | Startup can report dead services as running, stale PID reuse can signal an unrelated process, or never-started native fixtures can appear healthy. | Runtime |
compose-local-isolation | Every published Compose port binds to loopback, Compose owns container names, and every Compose operation uses a stable checkout-and-environment project identity unless automation supplies a validated override. | infra/compose.yaml, bin/base-demo-services | tests/infra_test.bats, tests/validate.sh | Disposable credentials can become remotely reachable, or one worktree's lifecycle and log commands can target another worktree's containers. | Security |
frontend-setup-path | basectl setup base-demo installs Node 22.22.0 with bundled npm 10.9.4 through mise, and basectl test base-demo delegates to a mise task that runs locked npm ci when frontend inputs change or dependencies are absent. | .mise.toml, base_manifest.yaml, services/demo-console/package.json, services/demo-console/package-lock.json | tests/demo_console_test.bats, tests/validate.sh, Base's external base-demo E2E | A clean checkout can pass setup but fail the supported test path because Node, npm, Vite, or node_modules was never provisioned. | Setup |
demo-console-build-gate | macOS and Ubuntu CI install the locked frontend dependencies with Node 22.22.0/npm 10.9.4, compile the production console, run the Vitest/React Testing Library behavioral suite, assert entry artifacts, and fail the audit at moderate severity or higher. | services/demo-console/package.json, services/demo-console/package-lock.json, .github/workflows/tests.yml | services/demo-console/src/App.test.jsx, services/demo-console/vitest.config.js, services/demo-console/build.sh, tests/demo_console_test.bats, tests/validate.sh | Green validation can skip Vite or user-visible behavior, omit production artifacts, retain a known dependency advisory, or regress catalog loading/accessibility without detection. | CI |
security-scanners | Required CI runs pinned Bandit 1.9.4 over project Python sources, pip-audit 2.10.1 against the locked uv export, and ShellCheck over tracked shell entrypoints. | .github/workflows/tests.yml, pyproject.toml, uv.lock | tests/validate.sh, GitHub Actions security | Shell or Python security regressions and vulnerable locked dependencies can merge without a dedicated required signal. | Security |
ci-trigger-deduplication | Feature-branch commits run the validation workflow through pull_request only, push validation remains enabled for main, superseded runs cancel only within the same PR number or ref, and the validate, validate-base-cli-source, and validate-ubuntu job IDs remain stable. | .github/workflows/tests.yml | tests/validate.sh, GitHub Actions | A PR commit can consume two full validation runs, unrelated branches can cancel one another, default-branch validation can disappear, or check names can drift. | CI |
release-identity | VERSION is the authoritative stable SemVer identity; Python/uv metadata, frontend package metadata, the Base-style top README badge strip and release links, and the changelog heading agree, and only an explicit matching annotated vX.Y.Z tag whose target is reachable from main can publish a GitHub Release. | VERSION, pyproject.toml, uv.lock, services/demo-console/package.json, README.md, CHANGELOG.md, .github/workflows/release.yml | bin/base-demo-release-check, bin/base-demo-release-provenance, tests/release_test.bats, tests/validate.sh, GitHub Actions | Users, automation, or release provenance can disagree about the base-demo version, the current release can be hard to discover, the project-status strip can drift, or an unreviewed branch can publish a release. | Release |
ci-pinned-dependencies | CI uses immutable full commits for the published Base v1.8.0 and base-bash-libs v2.0.0 contracts, plus full SHA-pinned GitHub Actions. | .github/workflows/tests.yml | tests/validate.sh | CI can drift with Base main, an older base-bash-libs release, or mutable action tags instead of validating the intended release capability contract. | CI |
ubuntu-ci | The repository has an Ubuntu job that runs basectl setup base --yes --no-notify, validates basectl setup base --profile dev --yes --no-notify, verifies bats/gh/shellcheck, and runs basectl check --ci base-demo --format json against the pinned Base checkout. | .github/workflows/tests.yml | tests/validate.sh, GitHub Actions validate-ubuntu | Ubuntu support can drift from the documented Base setup, dev-profile, and read-only project health boundary. | CI |
platform-boundary | README and CONTRIBUTING document macOS full-demo support plus Ubuntu/Debian and WSL2 support for Base setup, dev-profile prerequisites, read-only project health checks, repo-location guidance, and the native-Windows non-goal. | README.md, CONTRIBUTING.md | tests/validate.sh | Developers on Linux or WSL2 follow macOS-only project setup or demo steps without a documented boundary. | Docs |
ci-json-check | The demo shows basectl check --ci base-demo --format json and asserts JSON status output. | demo/demo.sh, README.md | tests/validate.sh, tests/demo_test.bats, .github/workflows/tests.yml | The reference project stops demonstrating Base's CI-safe machine-readable check path. | CI |
onboard-continuation | CI asserts the basectl onboard base-demo --dry-run preview reaches Check, Setup, Projects, and Trust, then executes the pinned Base test proving that a nonzero Doctor result still reaches Projects, Trust, and Next Steps and returns success when the later stages succeed. | .github/workflows/tests.yml, README.md, pinned Base cli/bash/commands/basectl/tests/onboard.bats | tests/validate.sh, GitHub Actions validate, GitHub Actions validate-ubuntu | Onboarding can regress to stopping at a nonzero Doctor result, the demo can misstate the command sequence or exit behavior, or the preview can become README-only prose. | CI |
workspace-onboarding-agent-brief | The demo and CI exercise basectl workspace onboarding and basectl workspace agent-brief against workspace.yaml.example so the peer base plus base-demo layout proves first-day and agent handoff readiness. | workspace.yaml.example, README.md, demo/demo.sh | tests/validate.sh, tests/demo_test.bats, .github/workflows/tests.yml | Workspace-level onboarding and handoff commands can drift out of base-demo even though the repo already documents the peer-checkout layout. | Docs |
history-report-observability | The README and demo exercise basectl history --project base-demo --limit 5 --report so base-demo shows Base's privacy-conscious local activity report. | README.md, demo/demo.sh | tests/validate.sh, tests/demo_test.bats | Base's reportable local activity history can drift out of the reference walkthrough even though logs and plain history remain visible. | Observability |
github-workflow-hygiene | Contributor docs demonstrate basectl gh issue readiness before issue-backed work and basectl gh branch stale during cleanup without making authenticated GitHub checks part of CI. | AGENTS.md, README.md, .ai-context/overview.md | tests/validate.sh | base-demo can stop showing Base's own GitHub workflow helpers even though its contribution model depends on issue readiness, branch naming, and cleanup discipline. | Workflow |
tooling-testbed-boundary | The tooling matrix separates active baseline tools, optional live wrappers, reference-only examples, Base-generated environment views, and blocked future Docker service support. | docs/tooling-testbed.md, README.md, .ai-context/overview.md | tests/validate.sh | base-demo can accidentally make external tools required, duplicate Base-owned behavior, or imply support before Base publishes the contract. | Docs |
base-generated-environment-reports | CI runs basectl devcontainer base-demo --workspace .. --format json and basectl devenv-report base-demo --workspace .. --format json as read-only compatibility checks. | .github/workflows/tests.yml, docs/tooling-testbed.md | tests/validate.sh, GitHub Actions validate, GitHub Actions validate-ubuntu | Base-generated environment reporting can drift or appear to require Docker, VS Code, Nix, devenv, or committed generated files. | CI |
optional-task-runner-wrappers | justfile and Taskfile.yml remain optional wrappers that delegate check, CI check, test, build, demo, and service status tasks to basectl. | justfile, Taskfile.yml, docs/tooling-testbed.md, README.md | tests/validate.sh | Task-runner examples can drift into a second command contract or become an undeclared setup requirement. | Shell |
reference-env-dotfile-examples | direnv, asdf, chezmoi, and dotbot examples remain under examples/tooling/env-dotfiles/ and do not activate root shell or dotfile behavior by default. | examples/tooling/env-dotfiles/, docs/tooling-testbed.md, README.md | tests/validate.sh | Reference tooling can accidentally mutate developer shell state, home-directory state, or the baseline setup/check/test loop. | Docs |
reference-multirepo-examples | mani, gita, vcs2l, and west examples remain under examples/tooling/multi-repo/, aligned to workspace.yaml.example, and non-authoritative for Base discovery. | examples/tooling/multi-repo/, workspace.yaml.example, docs/tooling-testbed.md, README.md | tests/validate.sh | External multi-repo examples can accidentally imply that Base imports, syncs, or owns those formats. | Docs |
How To Use This Registry
When a change introduces a new promise between files, add a row here and make
sure tests/validate.sh or a focused BATS test fails if the promise drifts.
When deleting or changing a contract, update this registry in the same pull
request as the implementation and documentation changes.