Setting up a new Python project should not require rebuilding the same tooling every time.
This project is a compact template with all the components already included. Features include:
- Easy python environment handling
- Full config handling with YAML and env files
- Strict code quality checks
- Layered security: vulnerability + secret scanning,
CycloneDX SBOMs, single-source-of-truth
OpenVEX accepted-risk document with controlled-vocab justifications
- enforced freshness window, hardened docker image and runtime environment.
- Automated testing
- CI (
gitlab, easily swappable) - Enterprise-ready git workflow (conventional commits, semantic-release, pre-commit hooks)
- Automated dependency updates via Renovate (uv, pre-commit hooks, container images, CI image pins)
- Built-in
Makefilecommands to simplify all of the above - LLM-maintained
wikifor easy (project) documentation - A
docsdirectory for usual documentation
Disclaimer: This template aims to serve a wide range of use cases, so you
should adjust it according to your requirements and taste. There is a lot to
take in, docs/REPO_SETUP.md walks through every
moving part, why it's there, and how to swap or remove it.
Just uv!
Clone the template into a directory named after your project:
git clone <template-url> my-new-project
cd my-new-projectRun:
make bootstrapOn the first run, make bootstrap is interactive: it asks for a project
name (defaulting to the directory name), package name, description, and
author, then renames the placeholder layout (src/my_project/ ->
src/<your_package>/) and updates pyproject.toml, the README, and tests
accordingly. After that it installs the pinned Python, dependencies, and
pre-commit hooks. The rename script self-deletes when it's done, so
re-running make bootstrap later just re-installs the dev environment,
which is what you want.
For non-interactive use (CI, dotfiles, etc.) the rename step accepts a
--yes flag; see docs/REPO_SETUP.md.
Finally, configure runtime env variables by copying
config/.env.dist to config/.env and filling in the values.
Run make help to see all available commands, grouped by category. The two
you'll use most:
make check Run the full local check suite, exactly what CI and
pre-commit run. Read-only; never modifies files.
make fix Run every auto-fixer (format + lint + repo hygiene).
Run this locally before committing.
Pre-commit is intentionally check-only, it verifies but never modifies
files mid-commit. A failed commit means "run make fix and try again."
See docs/REPO_SETUP.md
for the full check/fix breakdown.
The central entrypoint of this repo is src/my_project/__main__.py.
You can run it from the root of the repository with:
python -m my_projectOr by running the docker container (built-in) with docker-compose.yaml:
docker compose up -d --buildNote: Because the loading of the config/config.yaml is implemented so that it works out of
the box for both local execution and docker, when running locally the code should be run as specified in the first
example. Otherwise, the config file cannot be resolved.
src/
my_project/ Central code
__main__.py Entry point: `python -m my_project`
__version__.py Version (reads from pyproject.toml metadata)
core/ Core code
config/
config.py Pydantic configuration schemas
config_loader.py YAML loading + Pydantic validation
config/
config.yaml App config (secrets via files or env variables)
.env.dist Environment variable template
assets/ Project-owned static files (safe to commit)
artifacts/ Local runtime inputs mounted into Docker (not baked into image)
docs/
REPO_SETUP.md Template internals & customization guide (safe to delete)
scripts/ Various scripts
tests/
docker/
Dockerfile Hardened image: distroless default + debian convenience
extra-libs.txt System libs to force-stage into the distroless image
README.md Container image guide (targets, staging, import gate)
docker-compose.yaml Hardened local-run compose (volume-mounted config)
.dockerignore Build-context exclusions
wiki/
index.md Catalog of all wiki pages
log.md Timeline of wiki activity
inbox/ Quick capture zone
decisions/ Architecture Decision Records
guides/ How-tos and runbooks
reference/ Architecture docs, specs, conventions
journal/ Thoughts, observations, findings
_templates/ Document templates
The src/my_project/ layout is the standard PyPA-recommended src layout.
As the project grows, add subpackages directly under it (e.g.
src/my_project/core/, src/my_project/api/) rather than dumping modules at
the top level. No pyproject.toml change needed, see
docs/REPO_SETUP.md for the full rationale.
Configuration is defined in config/config.yaml.
Secrets should be provided as files and declared as provider: file in yaml (although env variables are also possible -> provider: env), which is a better practice than env variables. See src/my_project/config/secret.py for details.
All values are validated at startup through Pydantic models in src/my_project/config/config.py.
The wiki/ directory is an LLM-maintained project wiki (inspired by Andrej Karpathy) for capturing decisions, guides, and reference material. The LLM handles all the bookkeeping — metadata, cross-references, index updates — so writing docs doesn't feel like a chore. Tell the LLM to "capture this", "document why we chose X", or "lint the wiki". See wiki/README.md for details.
This project uses Conventional Commits. Commitizen enforces the format via a pre-commit hook. Examples:
feat (autograd): added support for gradient accumulation
fix (config): added missing environment variable handling
docs (readme): update config section in README
Versioning is handled automatically by python-semantic-release in CI.
python-semantic-release
already detects linked issue identifiers in commit messages, including
Jira-style keys such as PROJ-123. Put them in Git trailer format at the end
of the commit message:
feat(api): add customer export
Resolves: PROJ-123
Multiple issues can be listed in one trailer:
fix(config): handle missing env file
Fixes: PROJ-123, PROJ-456
PSR uses these identifiers for changelog/release metadata. Your Git hosting or Jira integration is still responsible for creating the actual issue links.