Context
After nitrostack-py init, the generated app folder has no uv project files:
- no
uv.lock
- no
.python-version
- no
uv.toml
The only dependency file today is requirements.txt (nitrostack). TypeScript init is npm-shaped (package.json; install refreshes package-lock.json — see nitrostack CLI docs). Python init has no equivalent lock or interpreter pin.
nitrostack-py install always uses python -m venv + python -m pip (nitrostack/cli/install.py ensure_project_venv / _run_pip). It never calls uv.
PEP 621 pyproject.toml for templates is a separate issue and should land first (or in the same PR if you do both). uv needs a pyproject to lock.
Do not make uv a required runtime dependency of the nitrostack package. If uv is on PATH, use it; otherwise keep the existing venv+pip path.
Work from develop. Do not dirty unrelated SDK protocol files.
Goal
A freshly inited Python app is a uv-ready project:
| File |
Role |
.python-version |
Interpreter pin for uv/pyenv (must satisfy SDK requires-python = ">=3.10"). Recommend 3.12 or 3.11, not a floating 3. |
uv.toml |
uv tool config for the app (not the SDK). Keep it small: e.g. python-preference / default index. If you prefer [tool.uv] in pyproject instead of a standalone file, still ship uv.toml or document why pyproject [tool.uv] is the chosen equivalent — the report asked for uv.toml explicitly, so default to a real uv.toml. |
uv.lock |
Locked deps. Do not check a stale lock into the SDK templates if nitrostack on PyPI will drift. Generate at init: uv lock in the new directory when uv is available. If uv is missing, skip lock, print one line telling the user to run uv lock, and still write .python-version + uv.toml. |
nitrostack-py install / init “Install dependencies (Y/n)”: if uv is on PATH and pyproject.toml exists, prefer uv sync (creates .venv, respects .python-version / lock). If not, existing pip+venv behavior.
Probe
ls nitrostack/templates/starter
cat nitrostack/templates/starter/requirements.txt
rg -n "ensure_project_venv|_run_pip|uv " nitrostack/cli/install.py nitrostack/cli/main.py
which uv || true
uv --help | head
Read:
nitrostack/cli/install.py — entire file
nitrostack/cli/main.py — init_project install step (~1346 comment: requirements/pyproject then widgets npm)
tests/test_cli_install.py
- uv.toml schema: https://docs.astral.sh/uv/reference/settings/ (do not copy a huge config)
Confirm widgets still install via npm when src/widgets / widgets exists; uv must not swallow that step.
Implementation
- Land pyproject in templates if the pyproject issue is not merged yet (dependency). Without pyproject,
uv lock has nothing to lock.
- Add
.python-version to all three templates (same pin).
- Add a short
uv.toml to all three templates (shared content is fine).
- After
copytree in init_project, if shutil.which("uv"): run uv lock in the project dir (network). Tests must not hit the network: mock uv / skip lock when UV is absent. Optional: os.environ.get("NITROSTACK_SKIP_UV_LOCK") for CI.
install_dependencies: if uv available and pyproject present → uv sync (and uv sync --no-dev when production=True if that maps cleanly). Else pip path unchanged.
.gitignore in templates: keep ignoring .venv; do not ignore uv.lock. If templates have no .gitignore, add one (venv, __pycache__, .env but not .env.example).
- Do not add
uv to the SDK’s pyproject.toml dependencies.
Test / verify
pytest tests/test_cli.py tests/test_cli_install.py tests/test_cli_skills.py -q
Add:
- Fresh template tree (unit, no init TTY):
.python-version and uv.toml exist after copy; contents non-empty; python pin is >=3.10 compatible.
install_dependencies with uv patched as missing → still calls pip (existing tests).
install_dependencies with uv patched as present + pyproject present → invokes uv sync, does not also pip-install the same deps (one installer).
- Init lock: when
uv is mocked, assert uv lock cwd is the new project; when mocked missing, init still succeeds.
- All three templates get the uv files.
- No test clones PyPI unless marked and optional.
Manual (if uv installed): nitrostack-py init /tmp/ns-uv --template python-starter, then ls shows pyproject.toml, .python-version, uv.toml, uv.lock; uv sync / nitrostack-py install creates .venv.
Review
- Pip fallback still works on machines without uv (Windows included;
venv_python already has Scripts vs bin).
- Lock is generated or skipped, never a committed lie in the SDK repo unless CI regenerates it.
- Widget npm path unchanged.
Success
Related
Depends on #28 (pyproject.toml in init templates). Independent of mcp-2026 #22–#27.
Context
After
nitrostack-py init, the generated app folder has no uv project files:uv.lock.python-versionuv.tomlThe only dependency file today is
requirements.txt(nitrostack). TypeScript init is npm-shaped (package.json; install refreshespackage-lock.json— see nitrostack CLI docs). Python init has no equivalent lock or interpreter pin.nitrostack-py installalways usespython -m venv+python -m pip(nitrostack/cli/install.pyensure_project_venv/_run_pip). It never callsuv.PEP 621
pyproject.tomlfor templates is a separate issue and should land first (or in the same PR if you do both). uv needs a pyproject to lock.Do not make
uva required runtime dependency of thenitrostackpackage. Ifuvis on PATH, use it; otherwise keep the existing venv+pip path.Work from
develop. Do not dirty unrelated SDK protocol files.Goal
A freshly inited Python app is a uv-ready project:
.python-versionrequires-python = ">=3.10"). Recommend3.12or3.11, not a floating3.uv.tomlpython-preference/ default index. If you prefer[tool.uv]in pyproject instead of a standalone file, still shipuv.tomlor document why pyproject[tool.uv]is the chosen equivalent — the report asked foruv.tomlexplicitly, so default to a realuv.toml.uv.locknitrostackon PyPI will drift. Generate at init:uv lockin the new directory whenuvis available. Ifuvis missing, skip lock, print one line telling the user to runuv lock, and still write.python-version+uv.toml.nitrostack-py install/ init “Install dependencies (Y/n)”: ifuvis on PATH andpyproject.tomlexists, preferuv sync(creates.venv, respects.python-version/ lock). If not, existing pip+venv behavior.Probe
Read:
nitrostack/cli/install.py— entire filenitrostack/cli/main.py—init_projectinstall step (~1346 comment: requirements/pyproject then widgets npm)tests/test_cli_install.pyConfirm widgets still install via npm when
src/widgets/widgetsexists; uv must not swallow that step.Implementation
uv lockhas nothing to lock..python-versionto all three templates (same pin).uv.tomlto all three templates (shared content is fine).copytreeininit_project, ifshutil.which("uv"): runuv lockin the project dir (network). Tests must not hit the network: mockuv/ skip lock whenUVis absent. Optional:os.environ.get("NITROSTACK_SKIP_UV_LOCK")for CI.install_dependencies: ifuvavailable and pyproject present →uv sync(anduv sync --no-devwhenproduction=Trueif that maps cleanly). Else pip path unchanged..gitignorein templates: keep ignoring.venv; do not ignoreuv.lock. If templates have no.gitignore, add one (venv,__pycache__,.envbut not.env.example).uvto the SDK’spyproject.tomldependencies.Test / verify
Add:
.python-versionanduv.tomlexist after copy; contents non-empty; python pin is>=3.10compatible.install_dependencieswithuvpatched as missing → still calls pip (existing tests).install_dependencieswithuvpatched as present + pyproject present → invokesuv sync, does not also pip-install the same deps (one installer).uvis mocked, assertuv lockcwd is the new project; when mocked missing, init still succeeds.Manual (if uv installed):
nitrostack-py init /tmp/ns-uv --template python-starter, thenlsshowspyproject.toml,.python-version,uv.toml,uv.lock;uv sync/nitrostack-py installcreates.venv.Review
venv_pythonalready has Scripts vs bin).Success
.python-versionanduv.tomluv.lockcreated at init when uv exists; init does not fail when uv is missingnitrostack-py installusesuv syncwhen uv+pyproject existRelated
Depends on #28 (pyproject.toml in init templates). Independent of mcp-2026 #22–#27.