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://app.stacktower.io/github/stacktower-io/stacktower) [](https://github.com/stacktower-io/stacktower/actions/workflows/ci.yml) [](https://codecov.io/gh/stacktower-io/stacktower) [](https://goreportcard.com/report/github.com/stacktower-io/stacktower) [](https://pkg.go.dev/github.com/stacktower-io/stacktower) [](https://github.com/stacktower-io/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_. [](https://app.stacktower.io/github/stacktower-io/stacktower) --- <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> --- ## Installation ### Homebrew (recommended) The Homebrew install includes everything out of the box — GitHub authentication, private repo access, and all CLI features work without extra configuration. ```bash brew tap stacktower-io/homebrew-tap brew install --cask stacktower ``` ### Alternative: build from source > **⚠️ Important:** Building from source (or `go install`) does **not** embed the GitHub App credentials needed for `stacktower github login`, `stacktower github install`, and `stacktower parse github`. These commands will fail unless you manually set `STACKTOWER_GITHUB_APP_CLIENT_ID` and `STACKTOWER_GITHUB_APP_SLUG`. All other commands (parse, render, resolve, etc.) work fine without these. **Go install:** ```bash go install github.com/stacktower-io/stacktower/cmd/stacktower@latest ``` **Clone & build:** ```bash git clone https://github.com/stacktower-io/stacktower.git cd stacktower make build ``` ## Quick Start ```bash # Render the included Flask example (XKCD-style tower is the default) stacktower render examples/real/flask.json -o flask.svg # Parse a package from a registry, then render it stacktower parse python fastapi -o fastapi.json stacktower render fastapi.json -o fastapi.svg # Or pipe parse straight into render stacktower parse python flask | stacktower render - -o flask.svg ``` > **Want more?** The CLI generates static SVGs locally. [**Stacktower Cloud**](https://app.stacktower.io) adds interactive towers, dependency history tracking, automated PR diffs via the [GitHub Action](https://github.com/stacktower-io/stacktower-action), AI-powered health grading, and team dashboards — all from the same `parse` output. ## 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 from filename stacktower parse github [owner/repo] # Parse from a GitHub repository ``` **Supported languages:** `python`, `rust`, `javascript`, `ruby`, `php`, `java`, `go` ### Parse Options | Flag | Description | | ----------------------- | ------------------------------------------------------------------------------------ | | `-o`, `--output` | Output file (if omitted: TTY shows summary/tree, piped stdout emits JSON) | | `-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` | Best-effort scan 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 | ### 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 ```bash stacktower parse python poetry.lock -o deps.json stacktower parse python requirements.txt -o deps.json stacktower parse rust Cargo.toml -o deps.json stacktower parse javascript package.json -o deps.json stacktower parse ruby Gemfile -o deps.json stacktower parse php composer.json -o deps.json stacktower parse java pom.xml -o deps.json stacktower parse go go.mod -o deps.json ``` When the argument exists on disk or matches a known manifest filename, Stacktower auto-detects the language from the filename so you can omit the language subcommand: ```bash stacktower parse poetry.lock -o deps.json stacktower parse package-lock.json -o deps.json stacktower parse Cargo.lock -o deps.json ``` 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: ```bash stacktower parse python requirements.txt --name="my-project" -o deps.json ``` ### Metadata Enrichment By default, `parse` enriches packages with GitHub metadata (stars, maintainers, last commit) for richer visualizations. Set `GITHUB_TOKEN` for higher rate limits: ```bash export GITHUB_TOKEN=your_token stacktower parse python fastapi -o fastapi.json # Skip enrichment if you don't need it stacktower parse python fastapi --enrich=false -o fastapi.json ``` ### Vulnerability Scanning Add the `--security-scan` flag to annotate every package with its highest vulnerability severity via [OSV.dev](https://osv.dev/): ```bash stacktower parse python fastapi --security-scan -o fastapi.json stacktower parse javascript package.json --security-scan -o deps.json ``` When `--security-scan` is enabled, Stacktower performs a best-effort query to OSV.dev in a single batch request and writes severity data (`critical`, `high`, `medium`, `low`) into each node's metadata when available. 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. Use `--show-vulns=false` to suppress the colours while keeping the data in the graph: ```bash stacktower render fastapi.json --show-vulns=false -o fastapi.svg ``` ### 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) | | `--public-only` | Show only public repositories in interactive picker | > **Private repos:** Install the GitHub App with `stacktower github install` and grant access to the repos you need. ### Piping When `parse` detects that stdout is piped, it emits clean JSON with no chrome — making it composable with other tools: ```bash # Pipe directly into render stacktower parse python flask | stacktower render - -o flask.svg # Pipe into jq for analysis stacktower parse python requests | jq '.nodes | length' # Combine with security scan stacktower parse python django --security-scan | stacktower render - --show-vulns -o django.svg ``` Progress indicators and summary messages always go to stderr, so they never corrupt piped JSON. ### Terminal Output A typical `parse` run looks like this: ``` ⠙ Resolving python/flask... [42/5000] starlette jinja2 markupsafe click ✓ Resolved flask (python) 42 packages · 67 edges · depth 5 · fresh · 2.3s → flask.json Render: stacktower render flask.json ``` --- ## `stacktower resolve` Lightweight alternative to `parse` for quickly testing dependency resolution. Auto-detects the language from manifest filenames and prints a human-readable dependency tree. ```bash stacktower resolve <manifest-file> stacktower resolve <language> <package[@version]> ``` ### Resolve Options | Flag | Description | | ---------------------- | ---------------------------------------------------------------------------- | | `-o`, `--output` | Write JSON to file (resolve tree still prints to stdout) | | `-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 for rendering stacktower resolve poetry.lock -o deps.json stacktower render deps.json -o deps.svg ``` **Output:** ``` 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) ``` ### resolve vs parse | | `resolve` | `parse` | | --- | --- | --- | | Language detection | Auto-detected from filename | Auto-detected from filename (or explicit language subcommand) | | Default output | Human-readable tree | TTY: summary/tree, piped stdout: 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 | --- ## `stacktower list` List all available versions of a package from its registry. Requires a language subcommand: ```bash stacktower list <language> <package> [flags] ``` ### List Options | Flag | Description | | ---------------------- | --------------------------------------------------------------------- | | `--all` | Show all versions (default: newest 20) | | `--limit N` | Show the newest N versions (default: 20; ignored when `--all` is set) | | `--runtime-version` | Filter versions compatible with a specific runtime (e.g., `3.8`) | | `--supported-runtimes` | Display runtime constraint for each version | | `--no-cache` | Bypass cached version data | ### List Examples ```bash stacktower list python fastapi stacktower list rust serde stacktower list javascript react stacktower list go github.com/gin-gonic/gin # Show all versions stacktower list python django --all # Filter by Python version compatibility stacktower list python fastapi --runtime-version 3.8 # Show runtime requirements for each version stacktower list python fastapi --supported-runtimes ``` **Output:** ``` 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 list all) ``` --- ## `stacktower render` Generate visualizations from parsed JSON graphs. This is a shortcut that combines `layout` and `visualize` in one step. ```bash stacktower render <graph.json|-> [flags] ``` Use `-` to read graph JSON from stdin. ### Render Options | Flag | Description | | ------------------ | ------------------------------------------------------------------------ | | `-o`, `--output` | Output file or base path for multiple formats | | `-t`, `--type` | Visualization type: `tower` (default), `nodelink` | | `-f`, `--format` | Output format(s): `svg` (default), `json`, `pdf`, `png` (comma-separated)| | `--normalize` | Apply graph normalization (default: true) | | `--show-vulns` | Show vulnerability severity colours (default: true) | | `--show-licenses` | Show license compliance indicators — copyleft/unknown borders (default: true) | | `--flags-on-top` | Render security flags on top of all blocks (default: true) | | `--no-cache` | Disable caching | ### Tower-Specific Options | Flag | Description | | --------------------------------- | --------------------------------------------------------------------- | | `--width N` | Frame width in pixels (default: 800) | | `--height N` | Frame height in pixels (default: 600) | | `--style handdrawn\|simple` | Visual style (default: handdrawn) | | `--randomize` | Vary block widths to visualize load-bearing structure (default: true) | | `--merge` | Merge subdivider blocks into continuous towers (default: true) | | `--popups` | Enable hover popups with package metadata (default: true) | | `--nebraska` | Show "Nebraska guy" maintainer ranking panel | | `--edges` | Show dependency edges as dashed lines | | `--ordering optimal\|barycentric` | Crossing minimization algorithm (default: optimal) | | `--ordering-timeout N` | Timeout for optimal search in seconds (default: 60) | ### Render Examples ```bash # Basic tower rendering (XKCD-style) stacktower render flask.json -o flask.svg # Clean style without hand-drawn effects stacktower render serde.json --style simple --randomize=false --popups=false -o serde.svg # Node-link diagram (uses Graphviz DOT layout) stacktower render yargs.json -t nodelink -o yargs.svg # With Nebraska maintainer rankings stacktower render flask.json --nebraska -o flask.svg # Multiple output formats stacktower render flask.json -f svg,pdf,png -o flask # Large graph with faster ordering stacktower render big-project.json --ordering barycentric -o big.svg # Custom dimensions stacktower render flask.json --width 1200 --height 900 -o flask-large.svg # Show dependency edges stacktower render flask.json --edges -o flask-edges.svg # Disable vulnerability colours stacktower render scanned.json --show-vulns=false -o clean.svg ``` ### Output Formats 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` ### Two-Step Workflow For more control, run `layout` and `visualize` separately: ```bash stacktower layout flask.json -o flask.layout.json stacktower visualize flask.layout.json -o flask.svg ``` --- ## `stacktower layout` Compute visualization layout from a dependency graph. Outputs a layout JSON that can be rendered separately with `visualize`. ```bash stacktower layout <graph.json> [flags] ``` ### Layout Options | Flag | Description | | --------------------------------- | --------------------------------------------------------------------- | | `-o`, `--output` | Output file (default: `<input>.layout.json`) |
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 stacktower-io/stacktower`. Check the repository for the current installation instructions.
What category does stacktower belong to?
stacktower is listed under Utilities, specifically Utilities.