Skip to main content

qtmp — Q-Templates: Developer Environment Automation CLI

A Python CLI that detects your project environment, resolves dependencies between tech stacks, generates an execution plan, and runs the package-manager commands — instead of you hunting through docs and typing them one by one.

pip3 install qtmp
qtmp create react
qtmp add tailwind
qtmp plan add sqlalchemy   # dry run first
qtmp add sqlalchemy        # then actually run it
qtmp doctor

Why this isn't just "a script that runs npm install"

  • Recipe architecture — every piece of the stack (React, Tailwind, FastAPI, SQLAlchemy, ...) is a self-contained Recipe with three methods: requires(), detect(), plan(). Adding a new one is one file + one line in a registry — nothing in the CLI, planner, or executor changes.
  • Real dependency resolution — qtmp add sqlalchemy in an empty folder resolves to: scaffold FastAPI → install the Postgres driver → install SQLAlchemy, in that order, with shared dependencies (a "diamond") only ever installed once.
  • Project detection — reads package.json, vite.config.*, pyproject.toml, requirements.txt, docker-compose.yml, tailwind.config.* once per run into a ProjectContext, so every recipe and qtmp doctor see the same picture of "what's already here."
  • Dry-run planning — qtmp plan add X shows the exact commands that would run, against the real dependency graph, without touching the filesystem. qtmp add X is the same resolution path, one step later.
  • Idempotent by construction — every recipe's detect() is checked before its plan() is even called. Running qtmp add tailwind twice reports "already installed, nothing to do" instead of reinstalling or corrupting config.
  • Fail-fast, resumable execution — if a step fails (bad network, missing tool), everything after it stops. Already-applied steps are skipped on the next attempt; nothing after the failure was touched.

Commands

Command What it does
qtmp create react / qtmp create fastapi / qtmp create frontend-basic Scaffold a brand-new project
qtmp <capability> Shorthand — qtmp fastapi == qtmp create fastapi; qtmp tailwind == qtmp add tailwind (creatable capabilities go to create, everything else to add)
qtmp add <capability> Resolve dependencies and install/configure a capability
qtmp plan add <capability> Same resolution, dry-run only — prints the commands, changes nothing
qtmp doctor Diagnose which tools are on PATH and what this directory looks like
qtmp list List every registered capability
qtmp cheatsheet [name] View built-in or your own personal cheatsheets
qtmp --version Print the installed version

--cwd works in either position — qtmp --cwd ./my-app create react and qtmp create react --cwd ./my-app both work identically.

Beginner React (b) gets Vite + Tailwind automatically. Advanced (a) gets TypeScript, Tailwind, shadcn/ui, React Router, Axios, and a src/components|pages|hooks|lib layout — all resolved and applied through the same planner/executor path as a manual qtmp add.

frontend-basic (aliases: frontend, html-css-js, vanilla) scaffolds a plain index.html + style.css + script.js — no framework, no npm, no network required. Good for confirming files land where you expect without waiting on any package manager.

Re-running create is safe

Every creatable recipe checks the target folder before scaffolding:

  • Doesn't exist / empty → scaffolds normally.
  • Already a valid project of that type → skipped, reports "already exists," doesn't touch it.
  • Exists, non-empty, and isn't that project type → clean error, doesn't blindly run a scaffolder into someone else's files.

Architecture

qtmp/
├── context.py      ProjectContext.detect(cwd) -- one detection pass, shared everywhere
├── planner.py      Step, Plan, resolve_plan() -- pure dependency-graph resolution
├── executor.py      apply(plan) -- runs pending steps, skips satisfied ones, fails fast
├── doctor.py        read-only environment + project diagnostics
├── recipes/
│   ├── base.py       Recipe ABC: requires() / detect() / plan() / (optional) create()
│   ├── react.py       provides "react", creatable
│   ├── tailwind.py    provides "tailwind", requires "react" only if no node project exists yet
│   ├── router_axios.py provides "router" / "axios" / "shadcn" (shadcn requires "tailwind")
│   ├── fastapi.py      provides "fastapi", creatable
│   ├── database.py     provides "postgres" / "db-driver-postgres" / "sqlalchemy"
│   ├── frontend_basic.py provides "frontend-basic", creatable -- plain HTML/CSS/JS
│   └── __init__.py     REGISTRY = {capability_name: recipe_instance} -- the only file
│                       you edit to add a new recipe
├── cheatsheet_manager.py   bundled vs. personal (~/.qtmp/cheatsheets/) cheatsheets
└── cli.py            argparse subcommands, all going through resolve_plan()/apply();
                       also handles --cwd extraction (works before/after the
                       subcommand) and shorthand expansion ('qtmp fastapi' -> 'qtmp create fastapi')

The dependency-resolution example, end to end

qtmp add sqlalchemy on an empty folder resolves like this:

sqlalchemy
 ├── requires: fastapi          -> not detected -> scaffold venv, install fastapi+uvicorn, write main.py
 └── requires: db-driver-postgres
      └── requires: fastapi     -> already resolved above, not repeated
                                -> not detected -> pip install psycopg2-binary
 -> not detected -> pip install sqlalchemy

Run it for real and check the output of qtmp plan add sqlalchemy first — that's the exact plan the executor will follow, nothing hidden.

Adding a new recipe

# qtmp/recipes/docker.py
from qtmp.recipes.base import Recipe
from qtmp.planner import Step

class DockerRecipe(Recipe):
    name = "Docker"
    provides = "docker"

    def detect(self, ctx):
        return ctx.has_docker_compose

    def plan(self, ctx):
        return [Step("Write docker-compose.yml", apply_fn=lambda: ...)]
# qtmp/recipes/__init__.py
from qtmp.recipes.docker import DockerRecipe
REGISTRY["docker"] = DockerRecipe()

That's the entire integration surface. cli.py, planner.py, and executor.py never need to know Docker exists.

Testing

pip install -e ".[dev]"
pytest -v

60 tests covering:

  • CLI helpers — shorthand expansion (qtmp fastapi → create fastapi), and --cwd extraction working in either position, including the --cwd=value form and repeated occurrences.
  • Existing-target safety — create skips cleanly on an already-valid project of the same type, and raises a clear error (not a crash) on a genuine name collision with unrelated content.
  • Project detection — Node/Vite/Python/venv/Docker/Tailwind sniffing, and that a malformed package.json doesn't crash detection.
  • Dependency resolution — ordering, diamond dependencies installed once, unknown capabilities raising a clear error, and the exact FastAPI→driver→SQLAlchemy shape from the design doc.
  • Idempotency & safe execution — a fully-satisfied chain is a no-op; a failure mid-plan halts everything after it and reports which step failed; already-applied steps are never re-run.
  • Individual recipes — detect()/plan()/requires() logic for React, Tailwind, Router, Axios, shadcn, FastAPI, and the database chain, with no real npm/pip/network calls — commands are asserted on, never executed, in unit tests.
  • Cheatsheets — personal overrides taking precedence over bundled ones, and falling back correctly on removal.

Recipe tests never shell out for real — plan() is asserted on directly, so these pass identically whether or not Node/Python/Postgres happen to be installed on the machine running CI.

Honest limitations (not yet done)

  • Cross-platform: path handling is OS-aware (os.name == "nt" branches for venv paths), but this has only actually been run on macOS/Linux. Windows support is written for, not verified.
  • Package manager choice: assumes npm and pip. No pnpm/yarn/ poetry/uv alternative paths yet — a natural next recipe-level feature (a --pm flag resolved per-ecosystem).
  • postgres recipe deliberately does not auto-install a local Postgres server (that usually needs sudo / a package-manager choice we shouldn't make for you) — it only guides you and checks for psql on PATH. Automating a sudo-requiring step didn't feel like something a CLI should do silently, even in service of a demo.
  • AI-assisted setup from an earlier iteration was removed in this rewrite to keep the core deterministic and testable; if it comes back, it'll be a strictly optional layer on top of resolve_plan(), never a replacement for it.

Metadata

Release files for qtmp 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for qtmp 1.0.0
File Size Uploaded
qtmp-1.0.0.tar.gz 30.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for qtmp 1.0.0
File Interpreter ABI Platform
qtmp-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 58.6 kB

Release files / qtmp-1.0.0.tar.gz

Download URL qtmp-1.0.0.tar.gz
Size 30.7 kB
Tags Source
SHA-256 checksum
How to use checksums
6448af0f4776f40b172b30874c561b81bc09ca6ab1c11bfac911072f479d86d0
BLAKE2b-256 checksum
How to use checksums
92762e013045acb5d703bbceaa10d4d206b30ffb59b6a29ad54e913f1a4d0bb1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Release files / qtmp-1.0.0-py3-none-any.whl

Download URL qtmp-1.0.0-py3-none-any.whl
Size 27.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e9b5854f63d37c2268645e91e39699a07a6cb1cc62cee3cdd4bf1d47bc616477
BLAKE2b-256 checksum
How to use checksums
701bd9846f78fa445f71f6e02091add4ceeb718f1d831e3695d3635159a5f2b9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.5

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

0.3.0

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page