Commands
Two surfaces drive day-to-day work:
- The
smpyCLI — installed globally withuv tool install simple_module_cli. Used to scaffold apps and modules and to bump dependency versions. - The Makefile in your scaffolded app — a thin wrapper around
uvandnpmfor 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
smpy --helpScaffolders
| Command | What |
|---|---|
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
| Command | What |
|---|---|
smpy package-update | Bump every simple_module_* dependency in pyproject.toml to the latest PyPI version. --dry-run previews the diff. |
smpy skills add|list|update | Install 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:
| Command | From | What |
|---|---|---|
smpy host gen-pages | simple_module_hosting | Regenerate client_app/modules.{manifest.json,generated.ts,generated.css} from the installed modules. Run when you add or remove pages. |
smpy host sync-js-deps | simple_module_hosting | Install JS deps declared by wheel-installed modules into client_app/node_modules. In-repo workspace modules don't need this. |
smpy settings import-from-env | simple_module_settings | One-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:
uv run smpy users create-admin --email admin@example.com --password changemeScaffolded-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.
| Command | What |
|---|---|
make install | uv sync + cd client_app && npm install + make sync-js-deps. Re-runs are safe. |
make dev | make gen-pages, then uvicorn main:app --reload on :8000 and vite on :5050 in parallel. |
make migrate | uv run alembic upgrade head. Idempotent. |
make build | cd client_app && npm run build. Produces the production frontend bundle. |
make gen-pages | Regenerate the page manifest. Auto-runs before make dev. Same effect as smpy host gen-pages. |
make sync-js-deps | Install 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:
| Need | Command |
|---|---|
| New Alembic migration | uv run alembic revision --autogenerate -m "..." |
| Downgrade one revision | uv run alembic downgrade -1 |
| Roll back a single module | uv run alembic downgrade <module>@base |
| Single Python test | uv run pytest path/to/test_file.py::test_name |
| Single JS test | cd client_app && npx vitest run <path> |
| Format + lint Python | uv run ruff format . && uv run ruff check . |
| Type-check Python | uv run ty check |
| Format + lint JS | cd client_app && npx biome check . |
| Type-check JS | cd client_app && npx tsc --noEmit |
| Free stuck dev ports | lsof -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
- Environment variables — every
SM_*knob the framework reads. - Diagnostic codes — what each
SM0XXfrom boot diagnostics means and how to fix it. - Deployment — taking a build to production.