Usage
Basic command
uv-start <project-name> [options]
The project name must not contain spaces or underscores.
Options
Flag |
Description |
|---|---|
|
Project type to create. lib (default) creates a simple library
with a |
|
Python version for the new project (default: 3.13). |
|
Create a uv workspace (monorepo). You will be prompted to add a shared utilities library and additional sub-projects. |
|
Initialise a Git repository and create a GitHub remote. Sets up CI/CD workflows automatically. |
|
Make the GitHub repository private. Requires |
|
Create a data analysis project. Installs Jupyter, pandas, matplotlib,
and seaborn. No |
|
Save author name and email for project templates.
Stored in |
Examples
Create a library (default)
uv-start my-lib
Creates a my-lib/ directory with a src/my_lib/ package, test
directory, and all dev-tool configuration.
Create an installable package
uv-start my-cli -t package
Same as a library but also registers a console script entry-point so the package can be run from the command line.
Specify a Python version
uv-start my-project -p 3.12
Target Python 3.12 instead of the default 3.13.
Create a project with a GitHub repo
uv-start my-project -g
Initialises a local Git repo, creates a public GitHub remote, pushes an initial commit, and sets up CI workflows.
uv-start my-project -g --private
Same as above but the GitHub repository is private.
Create a workspace (monorepo)
uv-start my-workspace -w
Sets up a uv workspace. You will be interactively prompted to:
Add a
common-utilsshared libraryAdd additional sub-projects to the workspace
Combine workspace and GitHub:
uv-start my-workspace -w -g
Create a data analysis project
uv-start my-analysis --data
Creates a flat project (no src/ layout) pre-configured for interactive
data analysis:
Jupyter, pandas, matplotlib, and seaborn installed in the
.venvLab matplotlib style (
hhlab_style01.mplstyle) at the project rootcolors.py— aCOLORenum with the lab’s standard palettesample.ipynb— starter notebook that applies the style and importsCOLORCLAUDE.md— instructions for AI-assisted work that enforce consistent figure styling
Combine with --github to create a GitHub repository at the same time:
uv-start my-analysis --data -g
Generated project structure
Standard project
project-name/
├── src/
│ └── project_name/
│ └── __init__.py
├── tests/
├── pyproject.toml
├── README.md
├── LICENSE
├── .env.example
└── .pre-commit-config.yaml
Workspace
workspace-name/
├── packages/
│ ├── package1/
│ └── package2/
├── pyproject.toml
├── README.md
└── .pre-commit-config.yaml
Data analysis project
analysis-name/
├── hhlab_style01.mplstyle ← lab matplotlib style, loaded by the notebook
├── colors.py ← COLOR enum with the lab palette
├── sample.ipynb ← starter notebook
├── CLAUDE.md ← AI instructions for consistent figure style
├── pyproject.toml
├── README.md
├── .env.example
└── .gitignore
Development tools configured
Every generated project comes with:
Ruff — linter and formatter (line length 79, flake8 + isort rules)
Ty — static type checker (checks
src/andtests/)pytest — test framework with automatic discovery in
tests/commitizen — conventional commits, automatic version bumping, and changelog generation (see Conventional commits and version bumps below)
pre-commit — Git hooks that run linting, formatting, and type checking before each commit
Data analysis project details
Matplotlib style
hhlab_style01.mplstyle is placed at the project root so it can be
referenced by name from any notebook in the same directory:
import matplotlib.pyplot as plt
plt.style.use('hhlab_style01.mplstyle')
Always apply this style before creating any figure.
Lab colour palette
colors.py defines the COLOR enum with the lab’s standard palette.
Use the enum values — never raw hex strings or default matplotlib colors:
from colors import COLOR
ax.scatter(x, y, color=COLOR.BLUE.value)
ax.bar(labels, heights, color=COLOR.PINK.value)
Available colours:
Name |
Hex |
Typical use |
|---|---|---|
|
|
Primary data series |
|
|
Secondary / paired condition |
|
|
Contrast / highlight |
|
|
Third condition |
|
|
Fourth condition |
|
|
Fifth condition |
|
|
Sixth condition |
|
|
Seventh condition |
|
|
Eighth condition |
|
|
Background / negative control |
|
|
Text / annotations |
To add a new colour, extend the COLOR enum in colors.py rather
than scattering raw hex values through notebooks.
Starter notebook
sample.ipynb opens with the standard imports already in place:
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
from colors import COLOR
plt.style.use('hhlab_style01.mplstyle')
It also includes a commented example scatter plot to illustrate the expected usage pattern.
CLAUDE.md
The generated CLAUDE.md tells Claude Code (and other AI tools) to
always apply the lab style and use the COLOR enum. This keeps
AI-generated figure code consistent with hand-written code across the
project.
Conventional commits and version bumps
Generated projects use commitizen to enforce conventional commits and automate semantic versioning.
Use cz commit instead of git commit to get an interactive prompt
that builds a correctly formatted message:
cz commit
To bump the version based on your commit history:
cz bump
Commitizen inspects all commits since the last tag and determines the version bump automatically:
Commit prefix |
Version bump |
Example |
|---|---|---|
|
PATCH (0.0.X) |
|
|
MINOR (0.X.0) |
|
|
MAJOR (X.0.0) |
|
Other commit types — chore:, docs:, refactor:, ci:,
test:, style:, perf:, build: — are recorded in the
changelog but do not trigger a version bump.
Note
While major_version_zero is enabled in the commitizen
configuration (the default for generated projects), breaking changes
bump the minor version instead of major, following the
SemVer spec for 0.x releases.
Workspace versioning
When a workspace is created with -w, all packages share a single
synchronized version. The commitizen configuration lives only in the
root pyproject.toml and its version_files list covers every
sub-package:
src/<module>/__init__.py—__version__stringpyproject.toml—versionfieldREADME.md— version badge
Running cz bump at the workspace root updates all of these files
across the root project and every sub-package in one step. The release
CI workflow does the same automatically when a conventional commit lands
on main.
GitHub CI/CD workflows
When --github is used, two GitHub Actions workflows are created:
CI pipeline — runs on every push and pull request:
Ruff linting and format checking
Ty type checking
pytest test suite
Release pipeline — runs on pushes to main:
Automatic version bumping based on conventional commits
GitHub release creation with changelog
For workspaces, bumps the single synchronized version across all packages
Logging system
Every generated project includes a ready-to-use logging module at
src/<package_name>/config.py. It provides environment-variable-driven
configuration with sensible defaults, console and rotating file handlers,
and environment-specific overrides.
Getting a logger
Import get_logger from your package’s config module:
from my_package.config import get_logger
logger = get_logger(__name__)
logger.debug("Detailed diagnostic info")
logger.info("General operational messages")
logger.warning("Something unexpected happened")
logger.error("Something failed")
The first call to get_logger configures the root logger based on
environment variables. Subsequent calls return child loggers that inherit
this configuration.
Environment variables
Control logging behaviour via the .env file or shell environment.
Each generated project includes a .env.example with sensible
defaults. Copy it to activate:
cp .env.example .env
Warning
The .env file is gitignored by default. Never commit it —
it is for local configuration and secrets only.
Available variables:
Variable |
Default |
Description |
|---|---|---|
|
|
Minimum level to capture ( |
|
|
Print log messages to the terminal |
|
|
Write log messages to a rotating file |
|
|
Path to the log file |
|
|
Max size per log file before rotation (1 MB) |
|
|
Number of rotated log files to keep |
|
see below |
Python logging format string |
|
|
Active environment; loads |
Default log format:
%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s
Environment-specific configuration
Create environment-specific .env files to override defaults:
.env.example— template with defaults (checked into version control).env— your local copy of.env.example(gitignored, never commit).env.development— local development overrides (gitignored).env.production— production settings (gitignored)
Example .env.production:
LOG_LEVEL=WARNING
ENABLE_CONSOLE_LOGGING=false
LOG_FILE_PATH=/var/log/myapp/app.log
Activate an environment:
export ENV=production
The configuration strategy is:
Load hard-coded defaults
Load the base
.envfile (if present)Load
.env.<ENV>(if present), overriding previous values