Skip to main content

Scaffold your next Python project with one command

Project description

zenit

A CLI that scaffolds a new Python project from a template with optional addons — sets up the package structure, dev tooling, config files, and an initial git commit, then tells you what to run next.

zenit my-project

What it does

  1. Asks you to pick a template (blank or FastAPI)
  2. Asks you to pick addons (Docker, Redis, Celery, Sentry, GitHub Actions)
  3. Generates the project directory, all files, pyproject.toml, and justfile
  4. Runs git init and makes the first commit

It does not run uv sync, start servers, or do anything network-dependent. You get a directory you can immediately cd into and start working.


Requirements

All platforms need:

  • Python 3.14+
  • uv 0.4+install
  • git
  • justinstall (optional but the generated projects use it heavily)
  • direnv — optional, auto-activates the virtualenv on cd (see per-platform notes below)

The fastapi template additionally needs Docker running locally.


Installation

macOS

# Install uv if you haven't
curl -LsSf https://astral.sh/uv/install.sh | sh

# Install zenit
uv tool install zenit

# Or run without installing
uvx zenit my-project

direnv (recommended):

brew install direnv
# Add to ~/.zshrc or ~/.bash_profile:
eval "$(direnv hook zsh)"   # or bash

Linux (non-NixOS)

curl -LsSf https://astral.sh/uv/install.sh | sh
uv tool install zenit

direnv:

# Ubuntu/Debian
sudo apt install direnv

# Arch
sudo pacman -S direnv

# Fedora
sudo dnf install direnv

# Add to ~/.bashrc or ~/.zshrc:
eval "$(direnv hook bash)"   # or zsh

NixOS

NixOS does not allow uv to download or manage its own Python binaries — UV_PYTHON_DOWNLOADS must be set to never and uv must use the system Python. zenit handles this for you when run via the Nix flake, but you need Python 3.14+ available in your environment first.

Option A — run directly from the flake (recommended):

nix run github:BojanKonjevic/zenit -- my-project

This uses the bundled flake which sets UV_PYTHON_DOWNLOADS=never and points uv at the Nix-provided Python 3.14 automatically.

Option B — install and run manually:

# Make sure python3.14 is in your PATH (via nix-shell, home-manager, etc.)
# Then:
UV_PYTHON_DOWNLOADS=never uv tool install zenit
UV_PYTHON_DOWNLOADS=never zenit my-project

Generated projects on NixOS:

When zenit detects it's running on NixOS (by checking /etc/NIXOS), it generates a .envrc that uses use nix shell.nix instead of uv's own environment management, and writes a shell.nix that provides the correct LD_LIBRARY_PATH for compiled wheels like greenlet. So the generated project will also work correctly on NixOS.

direnv on NixOS — add to your configuration.nix:

programs.direnv.enable = true;

Or install it in your user environment:

nix-env -iA nixpkgs.direnv
# Add to ~/.bashrc or ~/.zshrc:
eval "$(direnv hook bash)"

Windows

Windows is supported. The generated justfile uses cmd as the shell, and all just recipes work without WSL.

# Install uv
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

# Install zenit
uv tool install zenit

direnv on Windows — direnv does not have an official Windows build. Your options:

  1. Skip it — instead of auto-activation, run uv sync once after scaffolding, then uv run <command> (or just use just, which routes through uv run already).
  2. Use WSL2 — install direnv inside WSL2 as per the Linux instructions above.
  3. Use scoop — a community-maintained build exists: scoop install direnv (not officially supported).

zenit will copy .envrc regardless, but will warn you if direnv is not found rather than failing.


Usage

zenit <project-name>            scaffold a new project
zenit <project-name> --dry-run  preview what would be created (nothing is written)
zenit list-templates            show available templates
zenit list-addons               show available addons
zenit --version

The interactive prompt uses arrow keys and space to select. If stdin is not a tty (e.g. piped input or CI), it falls back to numbered selection.


Templates

blank

A minimal Python package with dev tooling. Good for CLIs, scripts, and libraries.

my-project/
  src/my_project/
    __init__.py
    main.py
    __main__.py
  tests/
    test_main.py
  pyproject.toml
  justfile
  .gitignore
  .envrc

Includes: pytest, ruff, mypy, pytest-cov, ipython.

fastapi

A production-oriented FastAPI setup. Requires the docker addon (selected automatically).

my-project/
  src/my_project/
    main.py           FastAPI app + lifespan
    lifecycle.py      startup/shutdown logic
    settings.py       pydantic-settings (reads from .env)
    exceptions.py     HTTP exception helpers
    api/
      router.py
      routes/
        health.py     GET /health → {"status": "ok"}
    core/
      security.py     JWT encode/decode, bcrypt hashing
    db/
      base.py         SQLAlchemy DeclarativeBase
      session.py      async engine, session factory, get_session dep
    models/
      mixins.py       TimestampMixin (created_at, updated_at)
    schemas/
      common.py       PaginationParams, PaginatedResponse
  alembic/
    env.py            async-compatible Alembic env
    versions/
  tests/
    conftest.py       session + anon_client + client fixtures
    integration/
      test_health.py
    unit/
    fixtures/
  scripts/
    wait_db.py        waits for postgres container to be ready
  .env                auto-generated with a random SECRET_KEY
  .env.example
  alembic.ini

Addons

Addons are selected interactively and can be mixed freely with either template, with a few constraints noted below.

docker

Generates a multi-stage Dockerfile (uv-based, minimal final image), compose.yml, and .dockerignore.

  • For blank: compose starts just the app container.
  • For fastapi: compose also starts a db (postgres:16) service.
  • Required by fastapi (auto-selected).

redis

Adds src/<pkg>/integrations/redis.py — an async connection pool with a get_redis FastAPI dependency and a close_redis shutdown helper.

  • If docker is also selected: appends a redis:7-alpine service to compose.yml.
  • If docker is not selected: writes a standalone compose.redis.yml.
  • For fastapi: also patches settings.py to add a redis_url field.
  • Required by celery.

celery

Adds src/<pkg>/tasks/celery_app.py (Celery app configured against Redis) and tasks/example_tasks.py with a trivial add task.

  • Requires redis.
  • If docker is selected: appends celery-worker and celery-beat services to compose.yml.

sentry

Adds src/<pkg>/integrations/sentry.py with an init_sentry() function that no-ops when SENTRY_DSN is unset — safe to commit and run locally without a DSN.

  • For fastapi: patches lifecycle.py to call init_sentry() on startup, and patches settings.py and .env to add SENTRY_DSN / SENTRY_ENVIRONMENT.
  • For blank: patches main.py to call init_sentry() at startup.

github-actions

Writes .github/workflows/ci.yml that runs lint (ruff check), format check (ruff format --check), type check (mypy), and tests (pytest) on push and pull requests.

  • Spins up a postgres:16 service automatically when the fastapi template is used.
  • Spins up a redis:7-alpine service automatically when redis is selected.
  • Runs migrations before tests when postgres is present.

Generated commands (just)

All generated projects come with a justfile. Run just with no arguments to list what's available.

Command What it does
just test run pytest
just cov pytest with coverage report
just lint ruff check
just fmt ruff format
just fix ruff check --fix + ruff format
just check mypy
just run start the app (uvicorn --reload for fastapi, python -m for blank)

FastAPI only:

Command What it does
just migrate "message" generate an Alembic migration
just upgrade apply all pending migrations
just downgrade roll back one step
just db-create start db container, create app + test databases, migrate
just db-reset drop and recreate both databases
just wait-db wait until postgres is accepting connections

Docker addon:

Command What it does
just docker-up docker compose up --build
just docker-down docker compose down

Redis addon:

Command What it does
just redis-up start redis
just redis-down stop redis
just redis-cli open redis-cli

Celery addon:

Command What it does
just celery-up start worker + beat via compose
just celery-down stop worker + beat
just celery-flower open Flower monitoring UI on port 5555
just celery-logs tail worker logs

Sentry addon:

Command What it does
just sentry-check print sentry-sdk version
just sentry-test print whether SENTRY_DSN is set

Dry run

Pass --dry-run to preview everything that would happen without touching disk:

zenit my-project --dry-run

Output shows every file that would be created or modified, every dependency that would be added to pyproject.toml, every just recipe, and every git command — then exits without writing anything.


Adding auth to a FastAPI project

The fastapi template lays out the security plumbing but stops short of generating auth routes (everyone's auth is different). When you're ready:

  1. Define User and RefreshToken models in models/ — import them in models/__init__.py so Alembic discovers them.
  2. Add core/dependencies.py with a get_current_user dependency using decode_access_token from core/security.py.
  3. Add api/routes/auth.py with register, login, and refresh endpoints.
  4. Register it in api/router.py.
  5. Uncomment the auth block in tests/conftest.py to enable the authenticated client fixture.
  6. Run just db-create && just migrate "add users" && just upgrade.

Running from source

If you want to hack on zenit itself:

git clone https://github.com/BojanKonjevic/zenit.git
cd zenit
uv sync
uv run python main.py my-project

On NixOS, enter the dev shell first:

nix develop
python main.py my-project

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

zenit-1.0.0.tar.gz (67.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

zenit-1.0.0-py3-none-any.whl (67.8 kB view details)

Uploaded Python 3

File details

Details for the file zenit-1.0.0.tar.gz.

File metadata

  • Download URL: zenit-1.0.0.tar.gz
  • Upload date:
  • Size: 67.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"NixOS","version":"26.05","id":"yarara","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for zenit-1.0.0.tar.gz
Algorithm Hash digest
SHA256 8dc42c7feaf6978c654725df4eba9a11e73b112cbb1fea51a05de0b7c08d6928
MD5 9daeeeb870ad54c3c1412739f8191220
BLAKE2b-256 432debdfafab8691d1afc96ecdcab59ea5a642995f9114092ed5c5c4d5fad4d9

See more details on using hashes here.

File details

Details for the file zenit-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: zenit-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 67.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"NixOS","version":"26.05","id":"yarara","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for zenit-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 31a7c19096709ce14823ac2c5f0906a2ad373ac92bf7d6850a1be05ea173b5e6
MD5 4975e9b5d4e0394a56b5e1e2f9f5ee76
BLAKE2b-256 0789a61dea08cdf815e31afecb8b56d1636cd2d674459ad032a16f4cef4d798d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page