Contributing¶
Contributions are welcome. This guide covers the development setup and contribution workflow.
Required Tools¶
Two external tools must be installed separately (not managed by uv sync):
uv (Python Package Manager)¶
# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Or via package manager
brew install uv
just (Command Runner)¶
# macOS/Linux
curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash
# Or via package manager
brew install just
Types of Contributions¶
Report Bugs¶
Report bugs at https://github.com/nfb2021/canvodpy-extensions/issues. Include operating system, local setup details, and steps to reproduce.
Fix Bugs / Implement Features¶
Issues tagged "bug"/"enhancement" and "help wanted" are open for contributions.
Add a New Package¶
New extension packages live under packages/<name>/ and are picked up automatically
by the uv workspace (packages/*). Each package is independently versioned.
canvodpy-extensions is GitHub-only by design (see "Releasing" below) — packages
install via git-subdirectory sources, not PyPI. See packages/canvod-filemap
for the expected layout (pyproject.toml, src/, tests/, README.md).
Development Workflow¶
-
Install required tools (uv and just).
-
Fork and clone the repository:
git clone git@github.com:your_name_here/canvodpy-extensions.git cd canvodpy-extensions -
Install dependencies:
uv sync just hooks -
Create a feature branch:
git checkout -b name-of-your-bugfix-or-feature -
Make changes and verify:
just test just check -
Commit using conventional commits:
git commit -m "feat(filemap): add support for recipe overrides" -
Push and create a pull request:
A maintainer reviews and merges it. Coding agents may push the feature branch and open the pull request, but never merge, pushgit push origin name-of-your-bugfix-or-featuremainor tags, or bypass a check (AGENTS.md, Git and GitHub).
Commit Message Format¶
<type>(<scope>): <subject>
Types: feat, fix, docs, refactor, test, chore, perf, ci
Scopes: filemap, airflow, adapters, deps, ci, docs, release
Examples:
git commit -m "feat(filemap): add recipe-based mapping for non-canonical filenames"
git commit -m "fix(filemap): handle missing site config gracefully"
git commit -m "docs: update installation instructions"
See Conventional Commits for the full specification.
Common Commands¶
just --list # Show all commands
just test # Run all tests
just test-coverage # With coverage report
just check # Lint + format + type-check
Coding agents¶
AGENTS.md (root and per package) holds the instructions for coding
agents; the CLAUDE.md files import it. Task guides for agents are in
.claude/skills/. Keep them correct when you change what they describe;
just check-agent-docs checks that the paths and recipes they name exist.
Pull Request Guidelines¶
- Include tests for new functionality — new code must not reduce test coverage.
- Update the package's
README.mdand the Zensical documentation indocs/if adding or changing public API or behaviour. - Ensure compatibility with Python 3.14+.
- Add yourself to
CONTRIBUTORS.mdif this is your first contribution.
Licensing¶
canvodpy-extensions is licensed under the Apache License 2.0.
By submitting a pull request, you agree that your contribution is licensed under
the same terms. The LICENSE and NOTICE files at the repository root apply to
all source files. Per-file license headers are not required.
Code Quality¶
- ruff for linting and formatting
- ty for type checking
- pytest for testing with coverage
Run just check before committing.
Releasing (Maintainers)¶
Releases are cut by a maintainer, never by a coding agent; only maintainers can create release tags.
Each package is versioned and released on its own. A release is the git tag
<package>-v<version>, e.g. canvod-filemap-v0.2.0, on main.
just versions # current version of every package
just changelog canvod-filemap # changes since its last release
just release canvod-filemap minor # or major, patch, or e.g. 0.2.0
just release runs the package's tests and makes one commit that
- sets the version in
packages/<package>/pyproject.toml(anduv.lock), - writes
packages/<package>/CHANGELOG.mdfrom the commits that changedpackages/<package>/(git-cliff,cliff.toml), - pins the package's install snippets in the READMEs and docs to the new tag.
Commit messages become the changelog, so follow the commit convention above
and mark breaking changes (feat!: or a BREAKING CHANGE: footer).
main requires a PR (branch protection), so the tag is set after the merge:
git checkout -b chore/release-canvod-filemap-0.2.0 # before just release
just release canvod-filemap 0.2.0
git push -u origin chore/release-canvod-filemap-0.2.0
gh pr create --fill
# once merged:
git checkout main && git pull
just tag canvod-filemap # tags main and pushes the tag
(Don't tag before the PR merges: a merge can produce a different commit SHA than the one you tagged, orphaning the tag.)
Pushing the tag runs release.yml, which
checks that the tag matches the package version and drafts a GitHub Release
with the package's changes. Publish the draft by hand. Publishing archives the
repository on Zenodo, versioned by the tag: .zenodo.json and CITATION.cff
carry no version, since the packages have different ones. Then update the pin in
downstream [tool.uv.sources], e.g. canvodpy's root pyproject.toml.
canvodpy-extensions is deliberately GitHub-only. It is where logic for specific needs, workflows and data realities lives, looser than the canvodpy core, so a PyPI release would imply a stability contract it doesn't make. Nothing is published to PyPI or TestPyPI. Users install packages via the git-subdirectory pattern, pinned to a release tag (see each package's README).
A new package under packages/ needs nothing else: its first just release
starts its changelog and tags.