stacktower
Visualize dependency graphs as physical tower structures, inspired by XKCD #2347
About stacktower
This large README is shown as a plain-text preview. Read the full README at the source
# Stacktower [](https://github.com/matzehuels/stacktower/actions/workflows/ci.yml) [](https://codecov.io/gh/matzehuels/stacktower) [](https://goreportcard.com/report/github.com/matzehuels/stacktower) [](https://pkg.go.dev/github.com/matzehuels/stacktower) [](https://github.com/matzehuels/stacktower/releases) [](https://opensource.org/licenses/Apache-2.0) Inspired by [XKCD #2347](https://xkcd.com/2347/), Stacktower renders dependency graphs as **physical towers** where blocks rest on what they depend on. Your application sits at the top, supported by libraries below—all the way down to that one critical package maintained by _some dude in Nebraska_. <p align="center"> <img src="blogpost/plots/showcase/python/fastapi.svg" alt="FastAPI dependency tower" width="600"> </p> --- <p align="center"> <a href="https://app.stacktower.io"><strong>🚀 Try the Web App</strong></a> · <a href="https://www.stacktower.io"><strong>📖 Read the Story</strong></a> </p> --- > ⚠️ **Note:** The ordering algorithms are still experimental and may not produce nicely stacked towers for projects with a large number of dependencies. Results can vary. We're actively working on improvements. ## Installation ### Homebrew (macOS/Linux) ```bash brew install matzehuels/tap/stacktower ``` ### Go ```bash go install github.com/matzehuels/stacktower@latest ``` ### From Source ```bash git clone https://github.com/matzehuels/stacktower.git cd stacktower go build -o bin/stacktower ./cmd/stacktower ``` ## Quick Start ```bash # Render the included Flask example (XKCD-style tower is the default) stacktower render examples/real/flask.json -o flask.svg ``` ## Usage Stacktower works in two stages: **parse** dependency data from package registries or manifest files, then **render** visualizations. ### Parsing Dependencies The `parse` command auto-detects whether you're providing a package name or a manifest file: ```bash stacktower parse <language> <package-or-file> [flags] ``` **Supported languages:** `python`, `rust`, `javascript`, `ruby`, `php`, `java`, `go` #### From Package Registries ```bash stacktower parse python fastapi -o fastapi.json # PyPI stacktower parse rust serde -o serde.json # crates.io stacktower parse javascript yargs -o yargs.json # npm stacktower parse ruby rails -o rails.json # RubyGems stacktower parse php monolog/monolog -o monolog.json # Packagist stacktower parse java com.google.guava:guava -o guava.json # Maven Central stacktower parse go github.com/gin-gonic/gin -o gin.json # Go Module Proxy ``` Use `package@version` to pin a specific version. Without it, the latest version is resolved: ```bash stacktower parse python [email protected] -o fastapi.json stacktower parse rust [email protected] -o serde.json stacktower parse javascript @angular/[email protected] -o angular.json # scoped packages work too ``` #### From Manifest Files (Auto-Detected) ```bash stacktower parse python examples/manifest/poetry.lock -o deps.json stacktower parse python examples/manifest/requirements.txt -o deps.json stacktower parse rust examples/manifest/Cargo.toml -o deps.json stacktower parse javascript examples/manifest/package.json -o deps.json stacktower parse ruby examples/manifest/Gemfile -o deps.json stacktower parse php examples/manifest/composer.json -o deps.json stacktower parse java examples/manifest/pom.xml -o deps.json stacktower parse go examples/manifest/go.mod -o deps.json ``` When the argument exists on disk or matches a known manifest filename, Stacktower automatically parses it as a manifest. The project name (root node) is auto-detected from the manifest or a sibling file: - **Cargo.toml**: `[package].name` - **go.mod**: `module` directive - **package.json**: `name` field - **composer.json**: `name` field - **pom.xml**: `groupId:artifactId` - **poetry.lock / requirements.txt**: `pyproject.toml` (sibling) - **Gemfile**: `*.gemspec` (sibling) Use `--name` to override the auto-detected name: ```bash stacktower parse python requirements.txt --name="my-project" -o deps.json stacktower parse ruby Gemfile -n my-rails-app -o deps.json ``` #### Metadata Enrichment By default, Stacktower enriches packages with GitHub metadata (stars, maintainers, last commit) for richer visualizations. Set `GITHUB_TOKEN` to enable this: ```bash export GITHUB_TOKEN=your_token stacktower parse python fastapi -o fastapi.json # Skip enrichment if you don't have a token stacktower parse python fastapi --enrich=false -o fastapi.json ``` #### Vulnerability Scanning Stacktower can scan your dependency graph for known vulnerabilities using the [OSV.dev](https://osv.dev/) database. Add the `--security-scan` flag during parsing to annotate every package with its highest vulnerability severity: ```bash # Parse with vulnerability scanning stacktower parse python fastapi --security-scan -o fastapi.json # Parse a manifest with scanning stacktower parse javascript package.json --security-scan -o deps.json ``` When `--security-scan` is enabled, Stacktower queries OSV.dev in a single batch request and writes severity data (`critical`, `high`, `medium`, `low`) into each node's metadata. The scanned graph is cached separately from non-scanned graphs, so subsequent runs are instant. During rendering, vulnerable packages are automatically colour-coded by severity (red for critical, orange for high, amber for medium, yellow for low). Both tower and node-link visualizations support this. Use `--show-vulns=false` to suppress the colours while keeping the data in the graph: ```bash # Render with vulnerability colours (default when data exists) stacktower render fastapi.json -o fastapi.svg # Render without vulnerability colours stacktower render fastapi.json --show-vulns=false -o fastapi.svg ``` The `--show-vulns` flag is available on the `render`, `layout`, and `visualize` commands and defaults to `true`. ### Resolving Dependencies The `resolve` command is a lightweight alternative to `parse`, designed for quickly testing dependency resolution on local manifest and lock files. It auto-detects the language from the filename and prints a human-readable dependency tree instead of graph JSON: ```bash stacktower resolve <manifest-file> stacktower resolve <language> <package[@version]> ``` #### From Manifest / Lock Files (Auto-Detected) ```bash stacktower resolve poetry.lock # Python (Poetry) stacktower resolve uv.lock # Python (uv) stacktower resolve requirements.txt # Python (pip) stacktower resolve package-lock.json # JavaScript (npm) stacktower resolve Cargo.lock # Rust stacktower resolve Gemfile.lock # Ruby stacktower resolve composer.lock # PHP stacktower resolve go.mod # Go ``` No `--language` flag needed — the filename is enough. #### From Package Registries ```bash stacktower resolve python fastapi stacktower resolve rust [email protected] stacktower resolve javascript yargs ``` #### Output By default, `resolve` prints an indented dependency tree to stdout: ``` fastapi 0.104.1 starlette 0.27.0 anyio 4.0.0 sniffio 1.3.0 pydantic 2.5.2 pydantic-core 2.14.5 typing-extensions 4.8.0 Resolved 7 packages (max depth: 3, direct: 2) ``` Use `-o` to save the resolution as JSON (same format as `parse`), suitable for piping into `stacktower render`: ```bash stacktower resolve Cargo.lock -o deps.json stacktower render deps.json -o deps.svg ``` ### Listing Versions The `list` command shows all available versions of a package from its registry, sorted semantically with the latest stable version highlighted: ```bash stacktower list <language> <package> [flags] ``` ```bash stacktower list python fastapi stacktower list rust serde stacktower list javascript react stacktower list go github.com/gin-gonic/gin ``` Output (truncated to 20 most recent by default): ``` fastapi python · 277 versions latest 0.129.2 0.129.1 0.129.0 0.128.8 0.128.7 0.128.6 0.128.5 0.128.4 0.128.3 0.128.2 0.128.1 0.128.0 0.127.1 0.127.0 0.126.0 0.125.0 0.124.4 0.124.3 0.124.2 0.124.1 0.124.0 … 256 older versions not shown (use --all to show all) ``` Use `--all` to see every version: ```bash stacktower list python fastapi --all ``` Pre-release versions (alpha, beta, rc, dev) are shown dimmed and sorted after stable releases. ### Rendering The `render` command generates visualizations from parsed JSON graphs: ```bash stacktower render <file> [flags] ``` This is a shortcut that combines `layout` and `visualize` in one step. For more control, you can run them separately: ```bash # Two-step workflow with intermediate layout stacktower layout examples/real/flask.json -o flask.layout.json stacktower visualize flask.layout.json -o flask.svg ``` #### Visualization Types ```bash # Hand-drawn XKCD-style tower (default) stacktower render examples/real/flask.json -o flask.svg # Disable hand-drawn effects for a cleaner look stacktower render examples/real/serde.json --style simple --randomize=false --popups=false -o serde.svg # Traditional node-link diagram (uses Graphviz DOT) stacktower render examples/real/yargs.json -t nodelink -o yargs.svg ``` #### Output Formats ```bash # SVG output (default) stacktower render examples/real/flask.json -o flask.svg # JSON layout export (for external tools or re-rendering) stacktower render examples/real/flask.json -f json -o flask.json # PDF output stacktower render examples/real/flask.json -f pdf -o flask.pdf # PNG output (2x scale by default) stacktower render examples/real/flask.json -f png -o flask.png # Multiple formats at once (outputs flask.svg, flask.json, flask.pdf) stacktower render examples/real/flask.json -f svg,json,pdf -o flask ``` Output path behavior: - **No `-o`**: Derives from input (`input.json` → `input.<format>`) - **Single format**: Uses exact path (`-o out.svg` → `out.svg`) - **Multiple formats**: Strips extension, adds format (`-o out -f svg,json` → `out.svg`, `out.json`) > **Note:** PDF and PNG output requires [librsvg](https://wiki.gnome.org/Projects/LibRsvg): > > - macOS: `brew install librsvg` > - Linux: `apt install librsvg2-bin` ### Included Examples The repository ships with pre-parsed graphs and manifest files so you can experiment immediately: ```bash # Real packages with full metadata (XKCD-style by default) stacktower render examples/real/flask.json -o flask.svg stacktower render examples/real/serde.json -o serde.svg stacktower render examples/real/yargs.json -o yargs.svg # With Nebraska guy maintainer ranking stacktower render examples/real/flask.json --nebraska -o flask.svg # Synthetic test cases for layout algorithm testing stacktower render examples/test/diamond.json -o diamond.svg stacktower render examples/test/crossing.json -o crossing.svg ``` > **Note:** For accurate Nebraska rankings, parse with `--contributors` to fetch maintainer data: > ```bash > stacktower parse python flask --contributors -o flask.json > stacktower render flask.json --nebraska -o flask.svg > ``` #### Example Manifest & Lock Files The `examples/manifest/` directory contains sample manifest and lock files for every supported ecosystem, useful for testing `resolve` and `parse` locally: | File | Language | Type | | --- | --- | --- | | `poetry.lock` | Python | Lock file | | `uv.lock` | Python | Lock file | | `pyproject.toml` | Python | Manifest | | `requirements.txt` | Python | Manifest | | `package-lock.json` | JavaScript | Lock file | | `package.json` | JavaScript | Manifest | | `Cargo.lock` | Rust | Lock file | | `Cargo.toml` | Rust | Manifest | | `Gemfile.lock` | Ruby | Lock file | | `Gemfile` | Ruby | Manifest | | `composer.lock` | PHP | Lock file | | `composer.json` | PHP | Manifest | | `go.mod` | Go | Manifest | | `pom.xml` | Java | Manifest | ```bash # Quickly test dependency resolution on any of these stacktower resolve examples/manifest/poetry.lock stacktower resolve examples/manifest/Cargo.lock stacktower resolve examples/manifest/package-lock.json stacktower resolve examples/manifest/Gemfile.lock stacktower resolve examples/manifest/composer.lock ``` ## Command Reference Stacktower provides a suite of commands organized around a parse → render workflow. Each command is documented below with all available options and reproducible examples. ### Global Options These flags apply to all commands: | Flag | Description | | ----------------- | ---------------------------------------------------------- | | `-v`, `--verbose` | Enable debug logging (search space info, timing details) | | `-q`, `--quiet` | Suppress non-essential output (success messages, stats) | | `-h`, `--help` | Show help for any command | | `--version` | Show version information | --- ### `stacktower parse` Parse dependency graphs from package registries or local manifest files. ```bash stacktower parse <language> <package-or-file> [flags] stacktower parse <manifest-file> # Auto-detect language stacktower parse github [owner/repo] # Parse from GitHub ``` #### Parse Options | Flag | Description | | ----------------------- | ------------------------------------------------------------------------------------ | | `-o`, `--output` | Output file (stdout if empty) | | `-n`, `--name` | Project name for manifest parsing (auto-detected if not set) | | `--max-depth N` | Maximum dependency depth (default: 10, max: 100) | | `--max-nodes N` | Maximum packages to fetch (default: 5000, max: 50000) | | `--workers N` | Concurrent fetch workers (default: 20) | | `--enrich` | Enrich with GitHub metadata — stars, maintainers (default: true) | | `--contributors` | Fetch GitHub contributors for Nebraska rankings (slower API calls) | | `--security-scan` | Scan dependencies for known vulnerabilities via OSV.dev | | `--dependency-scope` | Dependency scope: `prod_only` (default) or `all` (includes dev dependencies) | | `--include-prerelease` | Include prerelease versions (alpha/beta/rc/dev) in resolution | | `--runtime-version` | Target runtime version for marker evaluation (e.g., `3.11` for Python) | | `--no-cache` | Disable caching | #### Parse Examples ```bash # Parse from package registries stacktower parse python requests -o requests.json stacktower parse python [email protected] -o fastapi.json # Pin specific version stacktower parse rust serde -o serde.json stacktower parse javascript @angular/[email protected] -o angular.json stacktower parse go github.com/gin-gonic/gin -o gin.json # Parse from manifest files (language auto-detected) stacktower parse poetry.lock -o deps.json stacktower parse package-lock.json -o deps.json stacktower parse Cargo.lock -o deps.json # Parse with explicit language stacktower parse python requirements.txt -o deps.json stacktower parse javascript package.json --name="my-app" -o deps.json # Include dev dependencies stacktower parse python poetry.lock --dependency-scope all -o deps.json # Target specific Python version for environment markers stacktower parse python fastapi --runtime-version 3.9 -o fastapi-py39.json # Scan for vulnerabilities during parsing stacktower parse python django --security-scan -o django.json # Full metadata including contributors (slower) stacktower parse python flask --contributors -o flask.json ``` #### Parse from GitHub Parse dependencies directly from a GitHub repository with interactive selection: ```bash stacktower parse github # Full interactive flow stacktower parse github owner/repo # Select ref + manifest stacktower parse github owner/repo --ref v2.0.0 # Parse at specific tag stacktower parse github owner/repo --ref main # Explicit branch stacktower parse github owner/repo --timeout 10m # Custom timeout ``` | Flag | Description | | ----------- | --------------------------------------------------- | | `--ref` | Git ref (branch, tag, or commit SHA) | | `--timeout` | Timeout for GitHub operations (default: 5m) | > **Private repos:** To parse private repositories, first install the GitHub App with > `stacktower github install` and grant access to the repos you need. --- ### `stacktower resolve` Lightweight alternative to `parse` for quick dependency resolution testing. Auto-detects language from manifest filenames and outputs a human-readable dependency tree. ```bash stacktower resolve <manifest-file> stacktower resolve <language> <package[@version]> ``` #### Resolve Options | Flag | Description | | ---------------------- | ---------------------------------------------------------------------------- | | `-o`, `--output` | Output file for JSON (stdout shows tree by default) | | `-n`, `--name` | Project name (for manifest parsing) | | `--max-depth N` | Maximum dependency depth (default: 10) | | `--max-nodes N` | Maximum packages to fetch (default: 5000) | | `--enrich` | Enrich with GitHub metadata (off by default, unlike `parse`) | | `--dependency-scope` | Dependency scope: `prod_only` (default) or `all` | | `--include-prerelease` | Include prerelease versions in resolution | | `--runtime-version` | Target runtime version for marker evaluation | | `--no-cache` | Disable caching | #### Resolve Examples ```bash # Auto-detect language from filename stacktower resolve poetry.lock stacktower resolve Cargo.lock stacktower resolve package-lock.json stacktower resolve go.mod # Resolve from registry stacktower resolve python fastapi stacktower resolve rust [email protected] # Save resolution as JSON stacktower resolve poetry.lock -o deps.json # Include dev dependencies stacktower resolve poetry.lock --dependency-scope all # Target specific runtime stacktower resolve python fastapi --runtime-version 3.8 ``` #### resolve vs parse | | `resolve` | `parse` | | --- | --- | --- | | Language detection | Auto-detected from filename | Must specify language subcommand | | Default output | Human-readable tree | Graph JSON | | Metadata enrichment | Off (opt-in with `--enrich`) | On by default (`--enrich=false` to skip) | | Best for | Local testing, inspecting deps | Rendering pipeline, CI | ---
Frequently Asked Questions
What is stacktower?
stacktower is a Utilities library for the Go programming language. Visualize dependency graphs as physical tower structures, inspired by XKCD #2347
How do I install stacktower?
Install stacktower with the Go module system using `go get matzehuels/stacktower`. Check the repository for the current installation instructions.
What category does stacktower belong to?
stacktower is listed under Utilities, specifically Utilities.