The Build Loop
Every stk command lives under stk. Run stk --help to see them grouped by purpose.
uv run stk --helpPrefer bare stk? Activate the venv once per shell:
source .venv/bin/activatestk run1. Is everything ready?
Section titled “1. Is everything ready?”uv run stk doctor✓ env file .env✓ secrets SECRET_KEY and password salt look random✓ database sqlite stk.db (124 KiB)! migrations database at 20261006_0001, head is 20261006_0002 → uv run stk db upgrade✓ admin user 1 admin(s)✓ assets vue 3.5.40 vuetify 4.1.6✓ agent login disabled✓ browser chromium ready for stk smoke✓ shell ptpython: highlighting and completion
Usable, with the warnings above.Every line that is not ✓ tells you the command that fixes it. A ! is a warning, a
✗ is a failure, and the exit code is 1 only on a failure, so it works in scripts.
--json for tooling.
2. Scaffold a feature
Section titled “2. Scaffold a feature”uv run stk new invoiceNAME is a lowercase snake_case identifier. This writes the blueprint package (model
and views) and its template, registers it in app.py, adds a sidebar entry to
navigation.js, generates the migration for the new model, applies it, and then tells
you where to look:
Open: http://localhost:5000/invoices/ (start it with: stk run)Pass --no-migrate if you would rather write the migration yourself, and --port if
your dev server is not on 5000.
3. Keep the gate running while you edit
Section titled “3. Keep the gate running while you edit”uv run stk verify --watchIt checks everything once, then polls for saved files and re-runs only what the change
can break. A .py edit re-runs ruff, the sanity checks, and migration drift; a template,
JS, or CSS edit re-runs only the sanity checks.
changed: stk/invoice/models.py✗ migration-drift add_column: invoice due_date → uv run stk db revision -m "describe change" && uv run stk db upgrade✓ ruff✓ checksLeave it in a split pane. You find out the moment you break something, not ten minutes later, and the fix is on screen.
4. Prove it in a real browser
Section titled “4. Prove it in a real browser”uv run stk smokeBoots a throwaway app on a free port against a temporary database, drives Chromium
through the home page, login, dashboard, and admin users page, then visits every other
GET page that takes no URL arguments. It fails on any of: an HTTP status of 400 or
above, a console or uncaught error, a failed request, or button, chip, and alert text
below 3:1 contrast with its background. That last one catches the class of bug no
console error ever reports. The dashboard screenshot lands in
.stk/smoke/dashboard.png; --json emits the per-page report.
Smoke needs Playwright’s Chromium. stk doctor tells you if it is missing.
5. Ship
Section titled “5. Ship”uv run stk verify && uv run stk smokeuv run stk report # docs/stk-report.html: routes, auth, gate resultsstk verify runs ruff, checks.py, and migration drift, and exits 1 if any fail.
CI runs both stk verify --json and stk smoke --json (after the unit tests), so the
pair above is the same gate locally. stk report --json prints the routes and verify
results instead of writing HTML, and -o picks another output path.
The whole loop
Section titled “The whole loop”uv run stk doctor # am I ready?uv run stk new invoice # scaffold to a clickable URLuv run stk verify --watch # instant feedback while editinguv run stk smoke # real browser before shipping