A terminal tool for managing experimental Python projects
Project description
novo
Spin up Python experiments in seconds, from anywhere in your terminal.
Install once with uv, then use novo from any directory to scaffold isolated, git-tracked Python experiments from reusable seed templates — drive it from the command line or a built-in TUI.
Install
novo is distributed as a uv tool — installed once into an isolated environment and exposed on your PATH.
Prerequisite: uv and git.
# from PyPI
uv tool install novo
# or from this repo
uv tool install git+https://github.com/fmeiraf/novo
If novo isn't found after install, run uv tool update-shell once to add ~/.local/bin to your PATH.
novo --version
That's it — the novo source tree is no longer needed. Use novo from any directory.
First steps
1. Set up a workspace
The workspace is a single git-tracked directory where all your experiments live.
cd ~/code/experiments # or wherever you want them
novo init
This registers the current directory as your workspace and initializes it as a git repo. Skip it entirely and novo will use an XDG-compliant default (~/.local/share/novo/workspace/).
2. Create your first experiment
novo new image-classifier --tag ml --desc "ResNet experiments"
novo creates a date-prefixed directory inside your workspace, sets up a uv project, applies the default seed, and commits the result.
3. Set up a seed (optional)
Seeds are reusable project templates — your favorite stack, scripts, and config files copied into every new experiment.
novo seed list # see what's available
novo seed init data-science # scaffold a new empty seed
This creates ~/.local/share/novo/seeds/data-science/ with a seed.toml manifest and a template/ directory. Edit the manifest to declare dependencies and post-create hooks:
[seed]
name = "data-science"
description = "Numpy + pandas + jupyter starter"
[seed.dependencies]
packages = ["numpy", "pandas", "jupyter"]
[seed.post_create]
commands = ["mkdir notebooks"]
Drop starter files into template/ — they'll be copied into every new experiment that uses the seed:
novo new churn-analysis --seed data-science
Configuration
novo works out of the box, but a handful of settings let you tailor the defaults. They live in a single TOML file at ~/.config/novo/config.toml (XDG-compliant; the exact path depends on your OS).
| Key | Type | Default | What it does |
|---|---|---|---|
workspace.path |
str | "" (XDG default) |
Where experiments are created. Empty falls back to ~/.local/share/novo/workspace/. Set by novo init. |
defaults.seed |
str | "default" |
Seed used when novo new is called without --seed. |
defaults.python |
str | "" (system) |
Python version passed to uv init for new experiments (e.g. "3.12"). Override per-experiment with --python. |
defaults.auto_commit |
bool | true |
Auto-commit the workspace on novo new / novo delete. |
naming.date_prefix |
bool | true |
Prefix experiment directories with today's date (2026-05-06-foo). Skip per-experiment with --no-date. |
Inspecting and changing settings
novo config show # table of all keys
novo config get defaults.python # read one key
novo config set defaults.python 3.12 # write one key
novo config set naming.date_prefix false # accepts true/false, yes/no, 1/0, on/off
You can also edit ~/.config/novo/config.toml directly:
[workspace]
path = "/Users/me/code/experiments"
[defaults]
seed = "data-science"
python = "3.12"
auto_commit = true
[naming]
date_prefix = true
Pinning a Python version
A seed itself can't declare a Python version today — it's resolved per-experiment in this order:
--pythonflag onnovo newdefaults.pythoninconfig.toml- Whatever
uvpicks as the system default
So to make every new experiment use 3.12 by default:
novo config set defaults.python 3.12
novo new quick-test # uses 3.12
novo new legacy --python 3.10 # one-off override
The TUI
Run novo with no arguments to launch the interactive terminal UI — a Textual app for browsing, searching, and managing experiments without memorizing flags.
┌─ Experiments ─────────────┐ ┌─ Details ──────────────────┐
│ > 2026-04-21-transformer │ │ Name: transformer-exp │
│ 2026-04-20-image-cls │ │ Seed: ml-stack │
│ 2026-04-19-data-clean │ │ Tags: nlp, pytorch │
└────────────────────────────┘ └────────────────────────────┘
n new d delete s seeds / search Enter open ? help q quit
| Key | Action |
|---|---|
n |
Create new experiment |
d |
Delete selected |
s |
Browse seeds |
/ |
Search |
Enter |
Open experiment in a new terminal window |
j / k |
Navigate (vim-style) |
? |
Help |
q |
Quit |
See docs/tui.md for the full screen and widget breakdown.
Everyday commands
novo # launch the interactive TUI
novo new <name> # create an experiment
novo list # list experiments
novo info [name] # workspace summary, or details for one experiment
novo search <query> # fuzzy search across name, description, tags
novo open <name> # cd into an experiment (needs shell integration)
novo delete <name>
novo seed list | init <name>
novo config show | get <key> | set <key> <value>
For novo open to actually cd, add this to your ~/.zshrc / ~/.bashrc:
eval "$(novo --shell-init)"
Updating & uninstalling
uv tool upgrade novo
uv tool uninstall novo
Documentation
Deeper docs live in docs/:
| Document | Description |
|---|---|
| architecture.md | Layers, data flow, project structure |
| cli.md | All CLI commands and flags |
| tui.md | Textual app, screens, keybindings |
| core.md | Experiment, seed, config, and git logic |
| models.md | Pydantic schemas |
| development.md | Local dev setup |
| testing.md | Test layout and conventions |
Development
Work on novo itself with an editable install so changes are picked up immediately:
git clone https://github.com/fmeiraf/novo
cd novo
uv tool install --editable .
uv run pytest
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file novo-0.1.3.tar.gz.
File metadata
- Download URL: novo-0.1.3.tar.gz
- Upload date:
- Size: 25.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
98c9737f47ad29bbd1904067ccd04d02df192a66059363b39c6ede2c947bc08f
|
|
| MD5 |
26d47f5098ce6ea4155178ce69f59975
|
|
| BLAKE2b-256 |
7850fc74facce96f80bfc79cfe792dc82b664ab7c07dcd6a8f59b5f2b08aded4
|
Provenance
The following attestation bundles were made for novo-0.1.3.tar.gz:
Publisher:
pypi_workflow.yml on fmeiraf/novo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
novo-0.1.3.tar.gz -
Subject digest:
98c9737f47ad29bbd1904067ccd04d02df192a66059363b39c6ede2c947bc08f - Sigstore transparency entry: 1457901922
- Sigstore integration time:
-
Permalink:
fmeiraf/novo@4cc2fbbe26e6e71d80a2e21267a03b4eee3ad957 -
Branch / Tag:
refs/tags/v0.1.3 - Owner: https://github.com/fmeiraf
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi_workflow.yml@4cc2fbbe26e6e71d80a2e21267a03b4eee3ad957 -
Trigger Event:
push
-
Statement type:
File details
Details for the file novo-0.1.3-py3-none-any.whl.
File metadata
- Download URL: novo-0.1.3-py3-none-any.whl
- Upload date:
- Size: 40.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a4db356c89d4cde4102c6a2c235959f128d2d35ee085aa0720cb13172439a53e
|
|
| MD5 |
2703fe38f87639582a70d8f87b06e034
|
|
| BLAKE2b-256 |
4cefecab2828d26d6866ff2dca21e2c3730b52a81d11eca2c300d680131e7c19
|
Provenance
The following attestation bundles were made for novo-0.1.3-py3-none-any.whl:
Publisher:
pypi_workflow.yml on fmeiraf/novo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
novo-0.1.3-py3-none-any.whl -
Subject digest:
a4db356c89d4cde4102c6a2c235959f128d2d35ee085aa0720cb13172439a53e - Sigstore transparency entry: 1457902004
- Sigstore integration time:
-
Permalink:
fmeiraf/novo@4cc2fbbe26e6e71d80a2e21267a03b4eee3ad957 -
Branch / Tag:
refs/tags/v0.1.3 - Owner: https://github.com/fmeiraf
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi_workflow.yml@4cc2fbbe26e6e71d80a2e21267a03b4eee3ad957 -
Trigger Event:
push
-
Statement type: