A synthetic permit-set estimator surface with /diff, /takeoff, and a 7-file export ZIP. Scaffold a new estimator project with:

ck new <name> --template estimator-demo --host <name>.highline.work
cd ~/Work/<name>
python3 validate_estimator.py             # all PASS expected
.venv/bin/uvicorn server.serve:app        # local preview at :18211

What is in the box

PathPurpose
content/sets/demo-permit-2026-05.jsonSeed set A. Synthetic 1200 sqft single-story residence at 100 Demo Lane, Synthville, 8 rooms, 12 openings (4 doors, 8 windows). Schema version creator_kit.estimator.construction_set.v1.
content/sets/demo-permit-2026-06.jsonSeed set B, revision 1. Identical to set A except for one added window in the mech room. The two-set pair gives the /diff route a non-trivial delta.
content/expected/diff-2026-05--2026-06.jsonPrecomputed diff fixture loaded by GET /diff. The demo template returns this verbatim; a real fork would compute it from the two sets at request time.
content/expected/takeoff-2026-05.jsonExpected takeoff for set A. The validator regression-checks the live-computed takeoff against this.
server/serve.pyFastAPI server, five routes plus static mounts. Basic Auth (anonymous in local-dev).
server/render.pyConstruction-set loader, deterministic takeoff computation, diff lookup, export-ZIP builder. Stdlib-only (zipfile plus csv plus io).
server/templates/{base,index,diff,takeoff}.htmlJinja2 templates for the HTML views. /diff and /takeoff content-negotiate: JSON by default, HTML on ?format=html or Accept: text/html.
public/_system/{_system,_patterns,_example}.cssThree-stylesheet load order. _system.css is the vendored Candlefish Design System; _patterns.css is the kit-authored semantic-tokens layer; _example.css carries the estimator-demo-specific extensions.
validate_estimator.pyPer-template validator. Five check groups: fixture integrity, voice rules, /diff JSON shape, /takeoff math (regression vs expected fixture), /export.zip 7-file contract. Stdlib-only for fixture and voice; fastapi.testclient.TestClient for routes (auto-skips with FLAG when fastapi unavailable).
tests/test_estimator.py24 stdlib unittest tests across loader, takeoff math, diff, export ZIP, validator, and routes. Routes auto-skip if fastapi is unavailable.
tests/visual-targets.jsonThree visual-regression targets (index, diff, takeoff). Read by runtime/visual_regression.py (kit-level vendored harness).
ck.config.jsonTemplate metadata consumed by ck new (name, default surface pattern, validator command, server command, port 18211 to avoid collision with essay-series at 18210).

Routes

MethodPathReturns
GET/health{"status":"ok","sets":<count>}. Open, unauthenticated.
GET/HTML index listing seed sets, links to /diff and /export.zip.
GET/diff?a=<set>&b=<set>Precomputed diff JSON. Top-level keys: summary, sheets, rooms, openings, assemblies, structural_callouts, bom_delta, caveats. Returns HTML with ?format=html.
GET/takeoff?set=<set>Live-computed takeoff JSON. Top-level keys: set_id, project_name, address, components, loose, caveats. Returns HTML with ?format=html.
GET/export.zip?a=<set>&b=<set>7-file ZIP: summary.txt, by-position/{loose-estimator,component-designer,gc-framer}.txt, csv/{findings,takeoff,cut-list}.csv.
GET/_system/<path>Static CDS chrome assets.

Takeoff formulas (deterministic, simplified)

lumber_linear_ft = sum(assembly.linear_ft)
drywall_sqft     = interior_lf * 18 + exterior_lf * 9
roof_sqft        = total_finished_sqft * 1.15
doors_qty        = count of openings where kind == "door"
windows_qty      = count of openings where kind == "window"

A real estimator-demo fork replaces these with a real takeoff engine. The route shape (set_id, project_name, components, loose, caveats) is the contract that survives the swap.

Diff is precomputed

GET /diff loads content/expected/diff-<a>--<b>.json and returns it verbatim. The demo template only ships a precomputed diff for the (2026-05, 2026-06) seed pair. A real fork computes the diff from the two sets at request time, matching the same response shape.

Out of scope (v1)

What forking this template gets you

A working FastAPI surface with three load-bearing patterns the kit standardizes:

  1. JSON route plus content-negotiated HTML view. _wants_html() in server/serve.py is the pattern; it works for any route that has both an API consumer and a browser consumer.
  2. Deterministic takeoff plus precomputed diff. Lets the validator regression-check the math without a live server, and lets the export bundle be reproducible.
  3. Per-template validator with FLAG-on-skip. validate_estimator.py is the model: stdlib checks always run; deps-required checks FLAG-skip cleanly so ck validate --offline against a fresh checkout does not hard-fail on missing pip installs.

Visual regression

tests/visual-targets.json ships three baselines: index (full page), diff (HTML view, #diff-summary selector, 1900x1100), takeoff (HTML view, full page, 2-second settle for any future chart rendering). The PNG baselines are committed at tests/visual-baselines/estimator-demo/{index,diff,takeoff}.png. Playwright is installed by the kit’s bootstrap.sh.

See also