Skip to content

Scaffolded projects are runtime apps, not Python packages

Decision date: 2026-06-04 (after v7.18.2 scaffolder audit) Closes: .claude/docs/2026-06-03-v7.17-scaffolder-distributable-package-design.md (8 open questions) Architect verdict: memory entry from agent abac9907719d964f5, 2026-06-04

Decision

symfonic init generates a runtime application, not an installable Python package. The scaffolder ships:

  • Dockerfile
  • docker-compose.yml
  • Makefile
  • alembic.ini + alembic/env.py
  • app/main.py (FastAPI entry point)
  • webapp/ (templates, static assets, CSS)
  • requirements.txt (pinned via symfonic-core[…]>=X,<Y)

None of these belong inside a pip install-able wheel. The scaffolder will NOT ship pyproject.toml.j2, NOT auto-generate a setup.py, and NOT add a [project] table to any of the generated files.

Why

When the design question was raised (2026-06-03, after a v7.16.1 hotfix where the CI's pip install -e . against a generated project failed), the surface seemed open. The v7.18.2 audit closed it on three observations:

  1. The scaffold artifact is a runtime app at every layer. Dockerfile, compose file, Alembic config, webapp assets, and a FastAPI entry point are not "Python package" concerns. Wrapping them in a wheel would be a category error.
  2. The friction that prompted the question was a CI bug, not an adopter need. The v7.16.1 hotfix replaced pip install -e . with pip install -r requirements.txt in scaffold-smoke.yml. Adopters never had an installation problem — the smoke workflow had a wrong assumption.
  3. No adopter has requested pip install <generated-app> distributability. A production adopter team (at scale) and the SRE-starter pilot both treat generated projects as Docker / Compose-managed services, not as packages.

Shipping pyproject.toml.j2 would invite design churn — eight open questions covering package name, version scheme, dependency source, build backend, optional-deps groups, console scripts, Python pin, and distribution intent — for a path nobody travels.

What this means for adopters

  • You install dependencies via pip install -r requirements.txt (or docker compose up --build). That is the documented path. It is unchanged.
  • You ship by building a container from the provided Dockerfile, not by uploading a wheel.
  • Editable installs do not apply. If you want to develop the agent code itself, edit files in place — Uvicorn --reload and the Celery beat scheduler pick up changes without pip install -e ..
  • CI testing patterns: the project root contains the application code; tests can cd into the project and run pytest directly. There is no install step before testing the generated app.

What this means for symfonic-core itself

symfonic-core (this package) IS installable — it ships pyproject.toml, a wheel, and publishes to a PyPI registry. The decision above applies ONLY to projects scaffolded BY symfonic init.

The boundary is sharp:

Layer Installable? Build artifact
symfonic-core library Yes (pip install symfonic-core) Wheel + sdist on PyPI
symfonic init <project> output No Docker image from Dockerfile

Closed questions from the v7.17 design doc

All eight open questions at .claude/docs/2026-06-03-v7.17-scaffolder-distributable-package-design.md are retired:

  1. Package name — N/A
  2. Version scheme — N/A
  3. Dependencies source — requirements.txt, no pyproject.toml
  4. Build backend — N/A (no wheel build)
  5. Optional-deps groups — N/A (use requirements.txt comments to gate components)
  6. Console scripts — N/A (use uvicorn / celery / make targets)
  7. Python pin — declared in Dockerfile (FROM python:X.Y-slim)
  8. Distribution intent — Docker image only, never a wheel
  • requirements.txt.j2 pin tightening (v7.19+ backlog) — even though we close the package question, the pin range on the generated requirements.txt line still needs to lift from >=7.1,<8.0 to the current scaffolder's own version floor. See .agent/team/plans/2026-06-04-v7.19-scaffolder-evolution-backlog.md.
  • pre_conditions DSL surfacing in scaffolded code (v7.19+ backlog) — the v7.18.0 state-predicate DSL is invisible in scaffolded app/setup/agent.py. Same backlog file.

These are scaffolder evolution work, NOT a return to the distributable-package question.