A cross-platform CLI that scaffolds a working starter project for Python, Node.js, Ruby, Java, Go, or C++ from one command.
initra myapi python fastapiThat creates the directory, writes framework-appropriate starter code with a health endpoint, adds a language-specific .gitignore and a README.md with real run instructions, generates the dependency file, builds a Python virtualenv, installs into it, initializes git, and commits.
Fourteen stacks work this way: Flask, FastAPI, Django, and Aiohttp for Python; Express in JS or TS, Next.js, and Koa for Node; Rails and Sinatra for Ruby; Spring Boot and Javalin for Java; Gin for Go; CMake for C++.
The point isn't breadth for its own sake. It's that every generated project has the same shape regardless of language: a health endpoint, a layered structure rather than one file, a tests directory with tests that pass, and a Dockerfile where that makes sense. Switching languages doesn't mean relearning where things go.
Flags cover the parts you'd otherwise do by hand: --gh creates the GitHub repo, --open opens VS Code, --ts switches Express to TypeScript, --dry-run prints exactly what would be written without writing it, and --json prints a machine-readable summary for scripts.
Run it with no arguments and it prompts.
USAGE.md is the full command reference.
| Layer | What it uses |
|---|---|
| Language | Python 3.10+, standard library only |
| Terminal output | rich |
| Templates | Plain files under initra/templates/, shipped as package data |
| Tests | pytest |
One runtime dependency. A tool whose whole job is generating other people's dependency files has no business accumulating its own.
Three modules, and the split is the load-bearing design decision: decide, plan, then act.
flowchart LR
argv["initra myapi python fastapi"] --> cli["cli.py<br/>parse_args, prompts, validation"]
cli -->|"build_spec"| spec["ProjectSpec<br/>name, language, framework, flags"]
spec --> core["core.py<br/>generate_framework_plan"]
templates[("initra/templates/<br/>14 stacks, real files on disk")] -->|"load_template, raises if absent"| core
core -->|"FrameworkPlan: files, commands, notes"| ops["ops.py<br/>scaffold_project"]
ops --> project[("the generated project directory")]
ops -->|"git init, gh repo create, npm install, venv"| shell["git, gh, npm, mvn, python -m venv"]
ops -->|"ScaffoldResult"| cli
cli.py turns argv and interactive answers into a ProjectSpec and never touches the filesystem.
core.py turns that spec into a FrameworkPlan, a list of files to write and commands to run, and never touches the filesystem either.
ops.py is the only module that writes anything or shells out.
That's what makes --dry-run honest rather than a second code path: it builds the real plan and prints it instead of executing it, so a preview cannot disagree with the run it's previewing.
It's also why the tests can cover all fourteen stacks quickly, since asserting on a plan needs no mvn on the machine.
WALKTHROUGH.md traces one command through every step, and explains why core.py used to be 4000 lines.
A fallback that never fires is worse than no fallback.
Every template existed twice, as a packaged file and as an inline DEFAULT_* constant, and instrumenting all 14 stacks showed 113 of 127 lookups resolving from disk, so the constants were unreachable and free to drift silently.
One stack genuinely had no packaged file, so that became a real template and the rest were deleted, and load_template now raises instead of quietly writing an empty file.
Deleting the safety net immediately exposed the bug it had been hiding, twice.
Three dotfiles had never been reaching installed builds because templates/**/* does not match dotfiles, and then a clean checkout broke for a different reason: .env.* in .gitignore meant those files only ever existed on my machine.
Published wheels were fine and fresh clones were broken, a difference the fallback had been papering over.
unittest discover only matches test*.py.
CI was skipping tests/templates_pytest.py, the parametrized every-stack suite, while reporting a pass.
Switching CI to the pytest already configured in pyproject.toml took the test count from 43 to 77.
- QUICKSTART.md is the five-minute version.
- INSTALL.md covers per-framework prerequisites, alternative install methods, and troubleshooting.
- USAGE.md is the complete command reference, every flag, and the interactive walkthrough.
- WALKTHROUGH.md is the architecture reference: the Spec, Plan, Execution model, how the template system resolves files, and the reasoning behind both.
- TESTING.md covers testing initra itself and verifying a generated project.
- CONTRIBUTING.md has the checklist for adding a new stack.
- CHANGELOG.md is the release history.
MIT. See LICENSE.
pipx install initra # recommended
python3 -m pip install initra # also fineinitra myapi python fastapi
cd myapi && source .venv/bin/activate
uvicorn src.main:app --reloadPreview before committing to it:
initra orders-api python fastapi --dry-run --license --tutorialNeeds Python 3.10+ and git. Framework CLIs like rails and mvn are installed separately, gh only for --gh, VS Code only for --open.
initra --list prints the supported stacks and initra --update upgrades in place.
Working on initra itself:
python3 -m pip install -e ".[dev]"
python3 -m pytest testsUse pytest, not unittest discover. The latter doesn't collect tests/templates_pytest.py and will report OK after running about half the suite.
