A small reference project that demonstrates a Click-based Python CLI with a simple plugin-style command discovery mechanism and modern tooling.
- CLI framework: Click
- Dynamic command loading: commands are discovered from the
src/your_cli/commands/tree and loaded lazily at runtime - Package management: uv for fast dependency management
- Code quality: Ruff (lint + format) and Pyright (type checking)
- Testing: pytest (with coverage support)
- Security: pip-audit and bandit
- Automation: a Makefile with common tasks
Install uv.
Create / sync the project environment (this installs the project in editable mode, including the your-cli console script):
make setupuv run your-cli --help
uv run your-cli compute add 1 2
uv run your-cli net ping 1.1.1.1 --count 1Notes:
- If you skip
make setup, you can runuv sync --locked --all-extras --devdirectly. - To install explicitly (editable) and see post-install hints, run
make install. - The Python-module equivalent of
your-cli --helpis:uv run python -m your_cli.main --help.
This repository includes example commands:
compute add <a> <b>compute sub <a> <b>net ping <host> [--count N]
Commands are discovered from:
src/your_cli/commands/<...nested command path...>/
Each plugin directory must contain:
entry.py(required): exportscli, aclick.Command(typically created with@click.command())meta.yaml(required): a YAML mapping containing a non-emptyshort_helpstring
Supported meta.yaml keys:
short_help(required)help_group(optional, default:Commands)enabled(optional, default:true)hidden(optional, default:false; forced totruewhenenabled: false)packaged(optional; used for packaging workflows)no_args_is_help(optional, default:false)
Compatibility note: legacy aliases (shortHelp, HelpSummary, HelpGroup) are still accepted by the loader.
At runtime, the root command lists available command groups and loads subcommands only when invoked.
Dot-prefixed and __-prefixed directories are ignored during command discovery.
uv run your-cli admin new-command mul --short-help "Multiply two integers."
uv run your-cli admin new-command mul --parent compute --short-help "Multiply two integers."
uv run your-cli admin new-command issue --parent github.repo --short-help "Manage repository issues."--parent uses dot-notation to create nested command paths (github.repo => github/repo).
Any missing parent groups are scaffolded automatically.
If you want to generate plugins into a different directory during development, set:
YOUR_CLI_COMMANDS_DIR(used by theadmin new-commandhelper)
make format
make lint
make test
make coverage
make scanThe Makefile supports environment-specific configuration via .env files:
.env(base).env.local(local overrides, gitignored).env.$(ENV)(environment-specific; e.g..env.dev,.env.prod)
Example:
ENV=prod make lint.
├── src/
│ └── your_cli/
│ ├── commands/ # Dynamic command plugins
│ ├── dev.py # Developer utilities ("your-cli dev …")
│ ├── loader.py # Command discovery + lazy loader
│ └── main.py # Console entry point
├── tests/
├── pyproject.toml
├── Makefile
└── README.md
MIT