newstack
Scaffold a new project on any popular stack — and every starter it emits is proven green in CI.
$ newstack new python-lib ~/code/mylib
newstack 0.1.0 · python-lib → /home/you/code/mylib
created 8 files
git initialised on main, first commit made
next:
cd /home/you/code/mylib
uv sync
uv run pytest
Why this exists
cookiecutter, copier, yeoman, degit, npm create … and gh repo create --template
all solve part of the problem. Two things are still missing in practice:
- One tool for every stack. Python templates are Python-only, JS templates are
JS-only, and
gh repo create --templateclones a whole repository with no variables. - A guarantee that the template still works. Templates rot silently. You find out the starter is broken after you have already started building on top of it.
newstack fixes both. It is one zero-dependency CLI that carries a curated stack
registry, and every stack in that registry is generated and checked on every push
(newstack check --all in CI). If a starter breaks, the badge goes red — not your
first day of work.
Install
uvx newstack list # run without installing
uv tool install newstack # or put it on your PATH
pipx install newstack # any of the usual runners works
From a clone:
git clone https://github.com/DawnofGenX/newstack && cd newstack
uv sync && uv run newstack list
Use
newstack list # what is available, and what each stack needs
newstack new react-vite-ts ~/code/app
newstack new fastapi ~/code/api -d "Billing service" --author "Your Name"
newstack new python-lib ~/code/lib --dry-run # preview, write nothing
newstack new python-cli ~/code/tool --github # create the repo and push it too
newstack adopt ~/code/old-project --dry-run # retrofit CI/lint onto existing code
newstack check --all # prove every stack on this machine
newstack doctor # which toolchains do I have?
Every command takes --json where it makes sense, so the tool is scriptable.
newstack new renders variables, initialises git with a first commit, and (with
--github) creates the remote repository and pushes — one command from empty
directory to CI-ready project.
Stacks
| Stack | What you get | Toolchain |
|---|---|---|
python-lib |
src layout, hatchling build, pytest, ruff, 4-version CI matrix | uv |
python-cli |
console entry point on argparse, zero runtime deps, tested CLI | uv |
fastapi |
typed JSON API, pydantic models, TestClient tests, Dockerfile | uv |
django |
Django 6.1 app: config/core split, SQLite, pytest-django, migration drift check | uv |
flask |
Flask app factory: JSON routes, pytest fixtures, ruff, CI | uv |
react-vite-ts |
React 19 + Vite + TS, Vitest + Testing Library, typecheck + build | node, npm |
vue-vite-ts |
Vue 3 + Vite + TS, Vitest + @vue/test-utils, typecheck + build | node, npm |
next-app-ts |
Next.js App Router + TS + Tailwind 4, Vitest + Testing Library | node, npm |
chrome-extension |
MV3 extension: popup + service worker + content script, npm run pack → extension.zip |
node, npm |
astro |
Astro + TS content site: typed frontmatter, Vitest unit tests, astro check + static build |
node, npm |
data-science |
pandas workspace: testable DataFrame helpers, pytest, sample notebook | uv |
node-express-ts |
Express 5 API, typed handlers, supertest tests | node, npm |
svelte-kit-ts |
SvelteKit + TS, Svelte 5 runes component, Vitest, static adapter build | node, npm |
go-cli |
stdlib-only Go CLI: flag parsing, table tests, vet/test/build gates |
go |
go-http |
Go HTTP service on net/http: JSON routes, httptest suite, graceful shutdown |
go |
rust-cli |
std-only Rust CLI: lib+bin split, fmt/clippy/test/release-build gates | cargo |
rust-axum |
axum service: typed routes, shared state, tower oneshot tests, fmt/clippy |
cargo |
cpp-cmake-cli |
C++20 CLI: CMake lib+bin split, CTest suite, warning-clean GCC/Clang build | cmake, g++ |
terraform-module |
Reusable module: validated inputs, computed tags, terraform test cases incl. a rejected input |
terraform |
ruby-sinatra |
Sinatra JSON API: modular app, RSpec + rack-test suite, RuboCop, committed lockfile | ruby, bundle |
java-maven-cli |
Java 21 CLI on Maven: pure counting logic, 21 JUnit 5 tests, runnable jar | java, mvn |
php-composer-cli |
PHP 8.3 CLI on Composer: PSR-4 autoloading, a PHPUnit 11 suite, and a wc-style text counter | php, composer |
csharp-cli |
C# 12 CLI on .NET 8: pure counting library, xUnit suite, exit codes as a contract | dotnet |
elixir-mix-cli |
Elixir CLI on Mix: pure counting module, ExUnit suite, escript binary | elixir, mix |
dart-cli |
Dart 3 CLI: pub package with a pure counting library, package:test suite and zero runtime dependencies | dart |
kotlin-cli |
Kotlin CLI on Maven (no Gradle wrapper to ship): pure counting core, JUnit 5 suite, shaded runnable jar | java, mvn |
zig-cli |
Zig 0.17 CLI: counting module with in-source test blocks, zig build test, no runtime |
zig |
julia-cli |
Julia CLI: pure counting module, Test stdlib suite, zero external packages |
julia |
nim-cli |
Nim CLI: pure counting module, unittest suite that also checks exit codes, nimble build binary |
nim, nimble |
perl-cli |
Perl CLI on core modules only: Makefile.PL + Test::More suite, no CPAN install step |
perl, make |
lua-cli |
Lua 5.4 CLI: stdlib-only modules, a hand-rolled spec harness, zero luarocks dependencies | lua5.4 |
fsharp-cli |
F# on .NET 8: pure counting core, Mode discriminated union parser, xUnit suite that launches the binary for its exit codes |
dotnet |
crystal-cli |
Crystal CLI: stdlib-only modules, crystal spec suite, compiled binary with a 0/2/1 exit contract |
crystal |
static-site |
HTML/CSS/JS page, node:test suite, GitHub Pages deploy workflow |
node |
Each generated project ships its own .github/workflows/ that is ready to run, plus a
README, an MIT licence and a .gitignore.
Adopting an existing project
Most projects do not start from a scaffold. adopt retrofits a stack's infrastructure
onto a directory that already has code — and it is additive by construction: an existing
file is never opened for writing.
$ newstack adopt ~/sites/analytics-dashboard
newstack 0.3.0 · adopt → /home/you/sites/analytics-dashboard
stack static-site (auto-detected)
added 2 files
+ .github/workflows/deploy-pages.yml
+ .gitignore
tests not copied — rerun with --with-tests if you want starter tests
- Detection reads the project's own markers (
go.mod,Cargo.toml,manage.py, the dependencies inpyproject.toml/package.json, a bareindex.html). If two stacks match, it prints the candidates and exits 2 rather than guessing;--stackoverrides. - Scope: workflows,
.gitignore, and per-stack lint/type config only. It will not copy a README, a LICENSE, apyproject.toml, or source files — those carry your project's identity, not infrastructure. - Merges are reported, not attempted. If your
pyproject.tomlneeds the stack's[tool.ruff]block, adopt says so and leaves the file alone. --dry-runprints the same report without writing. Re-running is a no-op.--with-testsadditionally copies the stack's starter tests — experimental, because those tests import the sample module and usually need adapting to your code.
The green guarantee
A template is only as good as its last successful run, so newstack treats
verification as a first-class command:
$ newstack check --all
django PASS 1.5s 5 step(s)
fastapi PASS 1.4s 3 step(s)
go-cli PASS 0.3s 3 step(s)
node-express-ts PASS 6.1s 3 step(s)
python-cli PASS 0.5s 4 step(s)
python-lib PASS 0.5s 3 step(s)
react-vite-ts PASS 5.5s 4 step(s)
rust-cli PASS 0.5s 4 step(s)
static-site PASS 0.1s 3 step(s)
svelte-kit-ts PASS 7.1s 4 step(s)
(Real timings from a warm package cache — a cold run takes about a minute because
npm install and uv pip install have to fetch packages.)
check generates the stack into a throwaway directory, runs the commands listed in its
manifest (install → lint → test → build), reports per-step timings, and deletes the
directory unless you pass --keep. The same command runs in this repository's CI, once
per stack, on every push.
How it compares
| newstack | cookiecutter | copier | yeoman | degit / npm create |
gh repo create --template |
|
|---|---|---|---|---|---|---|
| Cross-language stacks in one tool | yes | no | no | partial | no | n/a |
| Runtime dependencies | 0 | Python | Python + git | Node | Node | gh |
| Generated starter verified in CI | yes, per stack | no | no | no | no | no |
| Template updates after generation | no (roadmap) | no | yes (copier update) |
no | no | no |
| Creates the git repo + remote | yes (--github) |
no | via hooks | no | no | yes |
Pick copier if you need copier update three-way merges against a single template you
own. Pick newstack when you want the same standard applied across several languages
without maintaining one template per stack.
Adding a stack
A stack is a directory with a manifest and a template tree. The manifest carries four
optional keys beyond the basics — detect (how a directory is recognised as this stack),
detect_fallback (a generic stack that must lose to a specific match), and the adopt /
adopt_tests allow-lists used by newstack adopt:
src/newstack/data/stacks/my-stack/
├── stack.json
└── template/
├── README.md
└── ... # {{ project_name }}, {{ package_name }}, {{ npm_name }},
# {{ title }}, {{ description }}, {{ author }}, {{ email }},
# {{ year }}, {{ date }}
{
"name": "my-stack",
"title": "My stack",
"language": "python",
"blurb": "One line shown by `newstack list`",
"requires": ["uv"],
"next_steps": ["cd {path}", "uv run pytest"],
"verify": [
{"name": "test", "cmd": "uv run pytest", "tools": ["uv"], "timeout": 600}
],
"detect": [{"file": "pyproject.toml", "contains": "my-framework"}],
"adopt": [".github/workflows/ci.yml", ".gitignore"],
"adopt_tests": ["tests/test_smoke.py"]
}
adopt entries must exist in the template and must never be an identity file
(README.md, LICENSE, pyproject.toml, package.json, go.mod, Cargo.toml) — a
test enforces both rules.
{{! escapes a literal {{, and ${{ ... }} (GitHub Actions) is left untouched.
Point NEWSTACK_STACKS at a directory of your own stacks to use private ones — same
manifest format, no fork required.
Design
- Zero runtime dependencies.
argparseand the standard library only, souvx newstackstarts instantly and works offline. - Templates are plain files. No Jinja, no DSL — a reviewer can read a template and know exactly what gets written.
- Verification is a product feature, not an afterthought.
checkis the same code path CI uses.
Roadmap
newstack update— re-apply upstream template changes to an existing project.- More stacks: Vue, Next.js, Flask.
--license apache-2.0|bsd-3and other variable choices beyond the current defaults.
Licence
MIT — see LICENSE.
Metadata
Release files for newstack 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| newstack-0.4.0.tar.gz | 189.4 kB | Without provenance | Details for newstack-0.4.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| newstack-0.4.0-py3-none-any.whl | Python 3 | none | any | Details for newstack-0.4.0-py3-none-any.whl |
Total release size: 532.2 kB
Release files / newstack-0.4.0.tar.gz
| Download URL | newstack-0.4.0.tar.gz |
|---|---|
| Size | 189.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
74dff10042c75fdb2c8ae849cbc069e406621d1b5d9137e94e239edb2e4d1936
|
|
BLAKE2b-256 checksum How to use checksums |
cebf1d5212f70eb6ca7a88d47ae959acfc95249a8d643ecd35cea650be3287d6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.31 {"installer":{"name":"uv","version":"0.11.31","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / newstack-0.4.0-py3-none-any.whl
| Download URL | newstack-0.4.0-py3-none-any.whl |
|---|---|
| Size | 342.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
78e0d71b592c13825fd7c1971a84d1b754cd0935a60ecf2e06f143ca80101c77
|
|
BLAKE2b-256 checksum How to use checksums |
f5f38cf7cc9179b3ffed112ed52dcf9b3a81d2a49fc9ec69c369a10b6a1b9d41
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.31 {"installer":{"name":"uv","version":"0.11.31","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for newstack 0.4.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.