Skip to main content

Canopy

Python 3.10+ MIT License

Orbital SVG visualizations of codebase health.

Canopy analyses your Python project — complexity, dead code, churn, and module structure — then renders a single SVG diagram you can embed in your README or CI artifacts. Click the diagram below for an interactive view with tooltips, zoom and pan.

What it shows

Visual element Meaning
Node colour Health — green (healthy MI), amber (moderate), red (unhealthy)
Node size Lines of code
Pulse ring High git churn (recent changes)
Spots Dead code detected by Vulture
Rings Architectural layers defined in canopy.yml
Edges Import dependencies between modules

Installation

pip install canopy-code

Canopy shells out to radon and vulture, so install them too:

pip install "canopy-code[tools]"

For development:

git clone https://github.com/bruno-portfolio/canopy-code.git
cd canopy-code
pip install -e ".[dev,tools]"
pre-commit install

Quick Start

# Analyse the current directory
canopy run .

# Specify a project path and output file
canopy run ./my-project --output docs/canopy.svg

# Generate SVG + interactive HTML viewer
canopy run . --output docs/canopy.svg --html docs/canopy.html

# Use a custom config
canopy run . --config path/to/canopy.yml

Configuration

Create a canopy.yml (or canopy.yaml) at the project root. All fields are optional — sensible defaults apply.

project: myproject          # display name (default: directory name)
source: src/myproject       # source root relative to project (default: ".")
module_depth: 2             # how many levels to group (default: 2)

ignore:                     # glob patterns to exclude (future)
  - "tests/**"

layers:                     # architectural ring grouping
  core:
    modules: ["_core", "domain"]
  infra:
    modules: ["_cache", "_db"]
    label: Infrastructure

vulture:
  min_confidence: 60        # Vulture confidence threshold (default: 60)
  exclude_types:            # Vulture result types to ignore
    - attribute

git:
  churn_days: 30            # lookback window for churn (default: 30)

thresholds:
  mi_healthy: 40            # MI score above this is green (default: 40)
  mi_moderate: 20           # MI score above this is amber (default: 20)
  churn_high: 20            # commits above this triggers pulse (default: 20)
  min_loc: 50               # modules below this LOC get collapsed (default: 50)

output:
  path: docs/canopy.svg     # output file path (default: canopy.svg)
  width: 1000               # SVG width in pixels (default: 1000)
  height: 800               # SVG height in pixels (default: 800)

GitHub Action

Add this workflow to .github/workflows/canopy.yml to regenerate the diagram on every push to main:

name: Canopy

on:
  push:
    branches: [main]

jobs:
  canopy:
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0    # full history for churn data
      - uses: bruno-portfolio/canopy-code@main

By default, the action creates a pull request with the updated diagram. This works with branch protection rules and required status checks.

If your repo has required status checks on PRs, pass a PAT so the PR triggers your test workflows (the default GITHUB_TOKEN won't):

      - uses: bruno-portfolio/canopy-code@main
        with:
          token: ${{ secrets.CANOPY_PAT }}

Create a fine-grained PAT with Contents: Read and write + Pull requests: Read and write scoped to your repo, then add it as a repository secret named CANOPY_PAT.

For repos without branch protection, you can push directly:

      - uses: bruno-portfolio/canopy-code@main
        with:
          strategy: push

Note: fetch-depth: 0 is required for accurate churn data. Without it the clone is shallow and churn will be unavailable (Canopy warns and continues with churn = 0).

Embedding in README

After the SVG is generated, reference it in your README:

![canopy](docs/canopy.svg)

GitHub renders inline SVGs natively — no external hosting needed.

To link the static SVG to an interactive HTML viewer on GitHub Pages:

<p align="center">
  <a href="https://your-user.github.io/your-repo/canopy.html">
    <img src="docs/canopy.svg" width="100%" />
  </a>
</p>

The HTML viewer is self-contained (zero external dependencies) and provides hover tooltips, click-to-pin, zoom (scroll) and pan (drag).

Limitations

  • Dynamic imports (importlib.import_module, __import__) are not detected by the static AST parser.
  • TYPE_CHECKING imports are treated as real imports (no special handling yet).
  • Shallow clones produce no churn data — use fetch-depth: 0 in CI.
  • exclude_types in Vulture config is a v1 allowlist; per-module exclusions are not yet supported.
  • ignore patterns are declared in config but not yet wired through collectors (planned for a future release).

License

MIT

Metadata

Release files for canopy-code 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for canopy-code 0.1.0
File Size Uploaded
canopy_code-0.1.0.tar.gz 59.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for canopy-code 0.1.0
File Interpreter ABI Platform
canopy_code-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 92.5 kB

Release files / canopy_code-0.1.0.tar.gz

Download URL canopy_code-0.1.0.tar.gz
Size 59.0 kB
Tags Source
SHA-256 checksum
How to use checksums
1c680cac91164a3534b171fe630615564e9866043adc40b99176fcbf550694af
BLAKE2b-256 checksum
How to use checksums
7c1cc88a28091a644a17d1daf397d83e100e647a159bf94c2881e0828df208d5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 4, 2026.

Transparency log

Release files / canopy_code-0.1.0-py3-none-any.whl

Download URL canopy_code-0.1.0-py3-none-any.whl
Size 33.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7c50a9b272f57964fd1a5d58cecdc3160abce54836eb72d944402911d91a7f21
BLAKE2b-256 checksum
How to use checksums
3d16f68a8f196eeb98f145300c15f7b0158a6e1763bca3dc8ef1f2fc87ae9794
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 4, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page