Repository and gates
This page: how the scaffolder repository is organized and what keeps it honest. For the anatomy of a generated app, see Project structure.
This repository produces one publishable artifact, the create-dpas-app CLI, and the application it generates.
packages/create-dpas-app/ the CLI (prompts, flags, safe generation)
templates/default/ the golden app: a real, tested workspace member
examples/generated-default/ committed generator output, drift-gated in CI
docs/ this documentation + ADRs
scripts/ example regen/drift check + scaffold smoke testThe template-first rule
templates/default is a normal, running application, not a bag of files with placeholders. It has its own tests, lint, typecheck and build, and it is a workspace member you can pnpm dev directly. The CLI's build step copies it verbatim into the package (renaming .gitignore → gitignore, which npm would otherwise strip), and generation is name substitution plus .env creation, nothing more.
That is the property that keeps the scaffolder honest: anything the generated app can do, the template can do here, in this repository, with the same tests.
Verification pyramid
- Contract tests ·
pnpm test. Capability discovery, lifecycle, staleness, binding, confirmation; domain governance; host protocol units; CLI unit tests. No model, no network, no browser. - End-to-end ·
pnpm test:e2e. Playwright against a production build: the live pipeline under a scriptedLanguageModelV2(MODEL_PROVIDER=mock), URL-synced narrowing, the chase dialog, and role authority. - Scaffold smoke ·
pnpm test:scaffold. Builds the CLI, generates a fresh app in a temp directory, installs it standalone, and runs that app's lint, typecheck, tests, build and deterministic browser tests. - Drift gate ·
pnpm check:example. The committedexamples/generated-defaultmust equal current generator output byte-for-byte. After changing the template, runpnpm regen:example. - View gate ·
pnpm view:check. The capability contract compiled from the template's source must equal the committed.agent-surface/contract.json, and each difference is reported as widening, narrowing or neutral.pnpm view:inspectprints the same contract to read rather than to gate. After changing a capability, runpnpm view:snapshotintemplates/defaultand commit the artifact. - Domain gate ·
pnpm domain:check. The same bargain for the other plane: the inventory read fromserver/runtime.ts'sgovernanceexport must equal the committedcapabilities.snapshot.json.pnpm domain:inspectprints it as a table, runtime policies included. Update withpnpm domain:snapshot.
Review a diff in either artifact like an API diff, because it is one: a changed description is a changed prompt, and a capability that gains a surface has gained an audience. The domain gate reports each runtime policy's declared scope and matching candidate capabilities in the POLICIES column. It does not evaluate the policy: actor, input, context, and concrete surface still decide the runtime verdict. A 0 in its APPROVAL column is metadata, not a reachability claim.
CI runs lint, typecheck, tests, build and the three gates on Node 22 and 24; the e2e and scaffold-smoke suites run once, on 22. A separate job installs a generated app with npm to catch pnpm-only assumptions, and the docs site is built on every run so a dead link fails the build.
Working on the template
pnpm install
pnpm dev # templates/default on :3000
pnpm lint && pnpm typecheck && pnpm test && pnpm build
pnpm test:e2e
pnpm test:scaffold
pnpm view:inspect # what an agent can reach in the view plane
pnpm view:check # …and whether the committed contract still says so
pnpm domain:inspect # the same two questions for the domain plane
pnpm domain:check
pnpm regen:example # after any template changeTwo review habits carry unusual weight here:
- Both inventories are API.
templates/default/.agent-surface/contract.jsonrecords the view plane andcapabilities.snapshot.jsonthe domain plane;pnpm view:checkandpnpm domain:checkgate them. Review their diffs like API diffs: a changed description is a changed prompt. - Exposure is an architectural decision, not a flag. If you add a domain operation, decide direct tool or contextual reference and never both; the host rejects the catalog either way, but the decision belongs in review.
Documentation
Three guides ship inside every generated app, in templates/default/docs/, and are the single source for their pages on this site: Architecture, Adding a capability and Security model are @included from there, so the app and the site can never drift. Edit them in the template, never twice.
Everything else (this page, the concepts, the reference and the ADRs) lives in docs/. Root markdown (README, CONTRIBUTING, SECURITY, CODE_OF_CONDUCT) is @included by wrapper pages under /project, for the same reason.
pnpm docs:dev # local docs site with hot reload
pnpm docs:build # static build (also checks for dead links)
pnpm docs:preview # serve the built siteArchitectural decisions get an ADR: Decision records. Contribution workflow and release process: Contributing.