Skip to main content

CLI tool that generates orbital SVG visualizations of codebase health

Project description

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

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

canopy_code-0.1.0.tar.gz (59.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

canopy_code-0.1.0-py3-none-any.whl (33.5 kB view details)

Uploaded Python 3

File details

Details for the file canopy_code-0.1.0.tar.gz.

File metadata

  • Download URL: canopy_code-0.1.0.tar.gz
  • Upload date:
  • Size: 59.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for canopy_code-0.1.0.tar.gz
Algorithm Hash digest
SHA256 1c680cac91164a3534b171fe630615564e9866043adc40b99176fcbf550694af
MD5 c347a358026f03beaef9159d2f6d616f
BLAKE2b-256 7c1cc88a28091a644a17d1daf397d83e100e647a159bf94c2881e0828df208d5

See more details on using hashes here.

Provenance

The following attestation bundles were made for canopy_code-0.1.0.tar.gz:

Publisher: publish.yml on bruno-portfolio/canopy-code

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file canopy_code-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: canopy_code-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 33.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for canopy_code-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7c50a9b272f57964fd1a5d58cecdc3160abce54836eb72d944402911d91a7f21
MD5 c12e32f7a49926c71dd88b292ee54984
BLAKE2b-256 3d16f68a8f196eeb98f145300c15f7b0158a6e1763bca3dc8ef1f2fc87ae9794

See more details on using hashes here.

Provenance

The following attestation bundles were made for canopy_code-0.1.0-py3-none-any.whl:

Publisher: publish.yml on bruno-portfolio/canopy-code

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page