Skip to content

Commands

Two surfaces drive day-to-day work:

  1. The smpy CLI — installed globally with uv tool install simple_module_cli. Used to scaffold apps and modules and to bump dependency versions.
  2. The Makefile in your scaffolded app — a thin wrapper around uv and npm for the inner dev loop (dev, migrate, build, gen-pages).

Past those, there's no hidden tooling — read the Makefile and pyproject.toml in your app directly when something surprises you.

smpy CLI

bash
smpy --help

Scaffolders

CommandWhat
smpy new <name>Scaffold a new app at ./<name>. Interactive by default; pass --yes for defaults, --preset minimal|standard|full, --with mod1,mod2 for extras, --db sqlite|postgres, --tenancy, --flat (no modules/ dir).
smpy create-module <name>Scaffold a publishable module package at ./simple_module_<name> (or --dest <path>).
smpy create-host <name>Scaffold just a host project (no sample module). Useful when you want a minimal shell that consumes published modules.

Maintenance

CommandWhat
smpy package-updateBump every simple_module_* dependency in pyproject.toml to the latest PyPI version. --dry-run previews the diff.
smpy skills add|list|updateInstall or update the bundled agent skills under .claude/skills/ for use with Claude Code.

Module-contributed plugins

When a module declares a simple_module_cli.cli_plugins entry point, the CLI mounts it as a sm <name> ... subgroup. The bundled modules contribute:

CommandFromWhat
smpy host gen-pagessimple_module_hostingRegenerate client_app/modules.{manifest.json,generated.ts,generated.css} from the installed modules. Run when you add or remove pages.
smpy host sync-js-depssimple_module_hostingInstall JS deps declared by wheel-installed modules into client_app/node_modules. In-repo workspace modules don't need this.
smpy settings import-from-envsimple_module_settingsOne-shot migration: read every SM_<MODULE>_* env var and seed it as a SYSTEM-scope row in the DB-backed settings store. Idempotent.

smpy users create-admin is contributed by the users module as a smpy users subcommand:

bash
uv run smpy users create-admin --email admin@example.com --password changeme

Scaffolded-app Makefile

smpy new writes a slim Makefile to your app. The intent is zero magic — every target is one or two lines you could run by hand.

CommandWhat
make installuv sync + cd client_app && npm install + make sync-js-deps. Re-runs are safe.
make devmake gen-pages, then uvicorn main:app --reload on :8000 and vite on :5050 in parallel.
make migrateuv run alembic upgrade head. Idempotent.
make buildcd client_app && npm run build. Produces the production frontend bundle.
make gen-pagesRegenerate the page manifest. Auto-runs before make dev. Same effect as smpy host gen-pages.
make sync-js-depsInstall JS deps from wheel-installed modules. Same effect as smpy host sync-js-deps.

If you included background_tasks in smpy new, the scaffold appends worker, beat, and worker-docker targets that wrap the Celery commands — read your Makefile to see the exact invocations.

Routine ops without a target

The scaffolded Makefile intentionally doesn't wrap one-off things. Run them directly:

NeedCommand
New Alembic migrationuv run alembic revision --autogenerate -m "..."
Downgrade one revisionuv run alembic downgrade -1
Roll back a single moduleuv run alembic downgrade <module>@base
Single Python testuv run pytest path/to/test_file.py::test_name
Single JS testcd client_app && npx vitest run <path>
Format + lint Pythonuv run ruff format . && uv run ruff check .
Type-check Pythonuv run ty check
Format + lint JScd client_app && npx biome check .
Type-check JScd client_app && npx tsc --noEmit
Free stuck dev portslsof -ti:8000,5050 | xargs kill -9

Working on the framework itself

If you're contributing to simple_module_python — not consuming it — the framework repo's Makefile is bigger: it includes make new-module, make doctor, make lint, make test, make migration, make worker, make memray-run, make loadtest, etc. Those targets exist because the framework repo is a multi-package workspace, not because they're the user-facing surface. See the release playbook and the repo's Makefile for that flow.

Next steps

Released under the MIT License.