- Keep CLAUDE.md, README.md, and the docs site updated when changing the
code.
CLAUDE.mddescribes programming conventions;README.mddescribes basic use;docs/is the user-facing reference. Don't let them drift. - Record user-facing changes in
CHANGELOG.mdunder the## [Unreleased]section as you make them — new parameters, behavior changes, removed features, bug fixes — in Keep a Changelog format. At release time,## [Unreleased]is renamed to## [X.Y.Z] - YYYY-MM-DDand a fresh## [Unreleased]is created. - Single source of truth —
pyproject.toml: canonical for dependencies, supported Python version, build config, tool settings. Don't restate any of these in prose; refer topyproject.toml. - Single source of truth —
PlotConfigand_config.py: every plot-parameter description lives in_config.py. For styling/behavior knobs, the source is the field'sAnnotated[T, "<description>"]metadata onPlotConfig; the click--helptext reads it directly, andtree_annotated_plot.plot.__doc__is assembled at import time by_config._render_numpy_params, so the REPL / mkdocstrings rendering pulls from the same string. Add Python-only prose for a field by setting_config.PARAM_DOC_EXTRAS[field_name] = "...". Adding a parameter = a newPlotConfigfield + a kwarg intree_annotated_plot.plot's signature with the same default. The three data-input parameters (tree,chart,output) can't sit onPlotConfigbecause their types differ between surfaces (the Python API accepts livealtair.Chart/dict/TreeNode; the CLI only accepts file paths), but their descriptions are still single-sourced as_config.{TREE,CHART,OUTPUT}_DESCRIPTIONconstants — both the CLI's--helpand_plot.py's_PLOT_DOC_HEADERinterpolate them. - Docstring style: NumPy (Parameters / Returns sections with the
----------underline), matchingmkdocs.yml'sdocstring_style: numpy. Don't mix Google-styleArgs:blocks in; mkdocstrings won't render them consistently. - Fail fast: validate inputs early and raise clear
ValueErroron unexpected data. Prefer assertions and explicit error messages over silent fallbacks. Tip-set reconciliation errors should include sample values from both sides plus candidate-field hints when possible. - Pure-Python package: managed via
pyproject.tomland a plainvenv(not conda). Required Python version specified inpyproject.toml. Develop with:Thepython3 -m venv .venv source .venv/bin/activate pip install -e ".[dev,docs]"
src/layout requiresdev-mode-dirs = ["src"]under[tool.hatch.build.targets.wheel]for editable installs to work. - Use default
black/ruffline length. Do not addline-lengthoverrides topyproject.tomlunless explicitly requested. - API shape: the user supplies their plot as a Vega-Lite chart (an
altair.Chart-or-subclass object, a JSON path, an HTML path, or a parsed spec dict). The package introspects the chart to find the strain encoding onxory, overrides its sort to match the tree's tip order, and hconcat's or vconcat's a tree panel on the matching side. Tree dictates tip ordering; plot follows. - Two surfaces, one config:
tree_annotated_plot.plot()and thetree-annotated-plotCLI both accept the same parameters viaPlotConfig. They converge on_build(tree, chart, config)so they can never disagree. - Tests must remain green at every commit on
main. Single-developer workflow with no PRs (yet) — discipline replaces review. Lint + format + pytest before committing:The same three checks run in CI viascripts/check.sh
.github/workflows/tests.ymlon push tomainand on PRs (CI also fetches the upstream Kikawa Auspice JSONs so real-data tests run rather than skip). Local green ≈ CI green. - Build docs alongside checks when changing public API surface:
scripts/build_docs.sh
--strictmode catches broken mkdocstrings references and missing cross-links. The script first callsscripts/generate_docs_assets.pyto renderdocs/images/*.svganddocs/charts/*.htmlfrom the example modules; both directories are gitignored — never commit anything into them. The same asset script runs in CI beforemkdocs build. - Eyeball examples after any rendering change. There are no
image-snapshot regression tests (vl-convert/font/platform variance
makes them flaky), so visual regressions only get caught by
looking. After any change to
_plot.py,_tree.py, the example scripts, or anything they touch: runscripts/build_docs.sh, opensite/examples.html, and click through each example — both the embedded SVG and the interactive HTML link. Confirm tip-row alignment, tree orientation, scale bar (if applicable), tooltips, and any selection/cohort bindings still work. The full recipe is inREADME.mdunder "Visual verification after code changes". When telling the user a rendering-affecting task is done, also report whether you ran this check (and that you cannot, from a non-interactive shell, actually verify the rendered output yourself — they need to look). - Docs are auto-deployed. The
.github/workflows/docs.ymlworkflow runs on every push tomain, generates assets, builds withmkdocs build --strict, and deploys to GitHub Pages (https://jbloomlab.github.io/tree-annotated-plot/). Pages source must be set to "GitHub Actions" in repo Settings; the workflow'spermissions:block already declarespages: writeandid-token: writeso no further config is needed. - Releases are tag-driven. Push a
vX.Y.Ztag (after bumpingpyproject.toml'sversion) and.github/workflows/release.ymlbuilds wheel + sdist, publishes to PyPI via trusted publishing (OIDC — no token in the repo), and creates a matching GitHub Release with auto-generated notes + the wheel/sdist attached as assets. The build job verifies the tag andpyproject.tomlversion match before publishing. Per-release recipe and one-time PyPI configuration steps are inREADME.mdunder "Releasing a new version". - Adding a new example (full recipe in
README.md):- Self-contained module under
examples/with module-level helpers (callable from outside). - New clause in
scripts/generate_docs_assets.pythat produces a.svg(intodocs/images/) +.html(intodocs/charts/). - New section in
docs/examples.mdmatching the existing three-section template (motivation → embedded SVG + interactive link → reproduce: CLI first, Python second). scripts/build_docs.shconfirms the page renders.
- Self-contained module under
- Iterating on docs: prefer
mkdocs serve(live-reload local server) for content/layout changes — much faster thanbuild_docs.shand shows the actual rendered page in your browser. Usebuild_docs.shfor the strict pre-commit verification.