Scaffolding a tenant: from cookiecutter to conformance

2026-06-19T02:18:45Z by Showboat 0.6.1

Scaffolding a tenant: from cookiecutter to conformance

One command turns nothing into a tenant the platform already trusts.

chimpy-lake is the scaffold — the platform repo that holds the catalog substrate, the lifecycle SDK, the telemetry hub, the plugin contract, and the cookiecutter templates that mint new tenants. Onboarding a data source shouldn’t be tribal knowledge; it should be generation plus a gate. If you’ve run npm create, cargo new, or create-react-app, you already know the shape: one command, a correct skeleton, ready to fill in.

This walkthrough follows one tenant from a single command to passing the live contract, and shows the provenance stamp that keeps a generated tenant honest about which platform version made it. Every beat runs the real cookiecutter, the real validator, and the real conformance suite against a tenant generated into a throwaway directory.

1 · One command, a fresh tenant

What. A new tenant starts as a cookiecutter render — a runnable skeleton conforming to the plugin contract, not a blank repo.

Why it matters. The correct shape is the default: manifest, entry point, Quadlet stub, and conformance test are all there from the first commit.

How we do it — generate one and list what landed:

uv run python docs/demos/scaffold-a-tenant/_driver.py generate

Generate — one command, a fresh tenant repo
===========================================
$ cookiecutter templates/tenant-extract  (tenant_name=demo-tenant)

generated repo: cl-extract-demo-tenant/
  .env.example
  .gitignore
  Dockerfile
  Makefile
  README.md
  app.py
  chimpy-tenant.toml
  docker-compose.yml
  pyproject.toml
  quadlet/<host>/cl-extract-demo-tenant.container
  sql/.gitkeep
  systemd/<host>/cl-extract-demo-tenant.timer
  tests/test_contract_conformance.py
  tests/test_smoke.py

The blueprint is real: a runnable tenant skeleton, contract-shaped from line one.

2 · A validated manifest — with provenance

What. The generated chimpy-tenant.toml is a Tier-3 manifest (it has the [lifecycle] section the control plane operates) and a [scaffold] section recording which chimpy-lake version minted it.

Why it matters. Provenance is first-class: the platform can later see, per tenant, which version it came from — and it validates against the live Tier-3 validator, so a generated tenant is conformant by construction.

Term to know: provenance; Tier-3 (contract + lifecycle).

How we do it — parse the generated manifest with the real validators:

uv run python docs/demos/scaffold-a-tenant/_driver.py manifest

Manifest — Tier-3 + version provenance, validated
=================================================
tenant.name        demo-tenant
tenant.kind        extract
lifecycle.subcommands  ['run', 'status', 'dry-run', 'migrate']
scaffold.template      tenant-extract
scaffold.chimpy_lake_version  0.2.0

It passes the live Tier-3 validator, and it records WHICH platform version
scaffolded it — provenance baked into the contract, not lost to tribal memory.

3 · You write run(); the SDK gives you the rest

What. The generated app.py wraps the tenant’s own run() in LifecycleApp, which supplies the uniform status / dry-run / migrate verbs.

Why it matters. The only tenant-specific code is the extract logic. Every verb the control plane relies on is inherited — uniform across all tenants.

How we do it — inspect the generated entry point:

uv run python docs/demos/scaffold-a-tenant/_driver.py app

app.py — you write run(); the SDK gives you the rest
====================================================
  supplies its own run()            True
  wraps it in LifecycleApp          True
  inherits for free: status / dry-run / migrate  (SDK defaults)

The one tenant-specific thing is the extract logic inside run(). Every other
verb the control plane relies on comes from the SDK — uniform across all tenants.

4 · The live conformance gate

What. chimpy-lake ships a conformance suite that a tenant must pass: its manifest validates, the telemetry SDK imports, a Quadlet stub is present, and the app runs.

Why it matters. “Conforming” isn’t a promise — it’s a test that runs. Here it runs against a tenant that was generated seconds ago, with nothing hand-edited.

Term to know: conformance gate (the single CI gate that proves cookiecutter + validator + plugin contract all interlock).

How we do it — run the real suite against the freshly generated tenant:

uv run python docs/demos/scaffold-a-tenant/_driver.py conform

Conform — the live gate runs against a 30-second-old tenant
===========================================================
...s.                                                                    [100%]
4 passed, 1 skipped

4 passed, 1 skipped — the one skip is the container-image presence check
(we don't build the image for the demo). A tenant that didn't exist a moment
ago already satisfies the manifest contract, imports the telemetry SDK, and
ships a Quadlet stub.

5 · Lockstep — the stamp can’t drift

What. The [scaffold].chimpy_lake_version stamp equals chimpy-lake’s own version, and a CI guard asserts it — bump the platform without bumping the template and the build goes red.

Why it matters. Provenance is only useful if it’s true. The lockstep guard makes drift unmergeable, so the stamp is always trustworthy.

Term to know: lockstep (template ↔︎ contract ↔︎ version, enforced by CI).

How we do it — compare the stamp to the live platform version:

uv run python docs/demos/scaffold-a-tenant/_driver.py lockstep

Lockstep — the stamp can't drift from the platform
==================================================
  scaffolded tenant stamp   chimpy_lake_version = 0.2.0
  chimpy-lake pyproject     version             = 0.2.0
  in lockstep?              True

A CI guard (test_cookiecutter_template) asserts these are equal — bump the
platform without bumping the template and the build goes red. Provenance you
can trust, because drift can't merge.

Proof

Every command above re-runs under showboat verify. And the thesis — a generated tenant is Tier-3, version-stamped, and passes the live gate — ships green:

uv run pytest tests/demos/test_scaffold_a_tenant.py -q 2>&1 | sed -E 's/ in [0-9.]+s//'
..                                                                       [100%]
2 passed

Glossary

Where scaffolding goes next — open questions, not commitments

Three directions the provenance stamp unlocks but that are not built:

Nothing exotic — one command, a gate, and a stamp that can’t lie. Everything above re-runs on demand.


all walkthroughs · Rendered from e906d4b on 2026-06-19 · showboat verify: reproduces. A living artifact — the version ledger is git.