issue_tree
    Preparing search index...

    issue_tree

    issue_tree v0.12.7

    Version 0.12.7 was built on Thursday, May 28, 2026 at GMT-07:00 1779980888298 from hash 58e5792.

    issue_tree scans one or more GitHub repositories into a local JSON cache, builds a dependency graph from blocking-issue links, and renders that graph in a variety of formats — including a self-contained interactive HTML page.

     

     

    Tip: issue_tree --help (and issue_tree <subcommand> --help) is the canonical flag reference — it is generated from the same enums the parser validates against, so it never drifts out of sync. issue_tree --version prints the package version. This README is the narrative guide.

    issue_tree exposes four subcommands that implement a scan → graph → render pipeline:

    issue_tree scan   [--repo <owner/repo>] ... [--cache <file>] [--token <token>] [--wait] [--force]
    issue_tree render [--cache <file>] [--format <fmt>] [--out <file>] [--scope <scope>]
                      [--repo <owner/repo>] ... [--label <label>] ... [--milestone <title>]
                      [--state <state>] [--child-of-gates] [--edge-style <style>] [--rankdir <dir>]
    issue_tree all    (accepts all scan and render flags)
    issue_tree auto   [<path>] (accepts all scan and render flags)
    

    Fetches issues from one or more GitHub repositories (and any external repositories they block against) and writes a resumable JSON cache. Key flags:

    • --repo <owner/repo> — one or more target repositories (repeatable).
    • --cache <file> — cache file path (default issue-tree-cache.json).
    • --token <token> — GitHub personal access token; falls back to GITHUB_TOKEN env var, then gh auth token.
    • --wait — on hitting the rate limit, sleep until it resets and continue.
    • --force — discard any existing cache before scanning.
    • --quiet / -q — suppress per-page and per-issue progress output. By default scan writes a progress line to stderr for every phase boundary, every page of issues fetched, every external blocker resolved, and every issue whose comments were fetched. Use --quiet to silence all of that (the final scan complete line on stdout still prints).

    Reads an existing cache and renders the dependency graph. A missing cache is a hard error — render never scans. Key flags:

    • --cache <file> — cache to read (default issue-tree-cache.json).
    • --format <fmt> — one of json, dot, svg, png, jpeg, html (default: inferred from --out extension, otherwise svg).
    • --out <file> — write output to a file. For text formats (json/dot/svg/html), omitting --out writes to stdout. For binary formats (png/jpeg), omitting --out writes to a generated default file in the current directory named owner_repo_YYYY-MM-DD_HH-MM-SS.ext, with _and_N_more appended after the first repo when multiple repos contribute to the render.
    • --scope <scope>open (default), connected, or all.
    • --label <label> — keep only issues with this label (repeatable; OR semantics across multiple uses).
    • --milestone <title> — keep only issues in this milestone.
    • --state <state>open, closed, or all (default all).
    • --edge-style <style>color (default) or color+shape.
    • --rankdir <dir>lr (default, left-to-right) or tb (top-to-bottom).
    • --engine <name> — Graphviz layout engine: dot (default, hierarchical), neato/fdp/sfdp (force-directed, more compact for sparse graphs), twopi (radial), or circo (circular).
    • --splines <kind> — edge routing: curved (default), line (straight), ortho (right-angle), polyline, spline, or none.
    • --nodesep <inches> — gap between nodes in the same rank. Graphviz default 0.25.
    • --ranksep <inches> — gap between ranks. Graphviz default 0.5. Halving these roughly halves the corresponding axis of the output.
    • --concentrate — merge parallel edges with shared endpoints.
    • --packmode <mode> — how disconnected components (multiple small trees) are arranged in 2D. node (default, shelf packing — fills space tightly without a grid), array (row-major grid), clust (cluster-by-cluster), graph (whole-graph cell), or off (Graphviz default — stack along the rank-orthogonal axis). For repos with many independent issue chains, node produces a far more readable view than the vertically-stacked default.
    • --graph-pad <inches> — outer pad around the whole graph (~0.055 default).
    • --graph-margin <inches> — outer page margin (0.5 default).
    • --node-margin <x[,y]> — per-node text padding inside boxes (Graphviz default 0.11,0.055).
    • --edge-minlen <N> — minimum rank distance per edge (default 1).
    • --issue-shape <shape> and --pr-shape <shape> — Graphviz shape names for issue and PR nodes (defaults box and ellipse). Accepts box, polygon, ellipse, oval, circle, egg, triangle, diamond, trapezium, parallelogram, house, pentagon, hexagon, septagon, octagon, doublecircle, doubleoctagon, tripleoctagon, Mdiamond, Msquare, Mcircle, square, star, note, tab, folder, box3d, component, cylinder, and rectangle.
    • --raster-max <px> — for png/jpeg output only, the maximum pixel dimension on the longer axis. When the laid-out SVG would exceed this on either axis, the output is downscaled by a single zoom factor that brings the longer axis down to this value, preserving aspect ratio. Defaults to 8192. A one-line notice is written to stderr when capping fires. This guard exists because long dependency chains can produce SVGs with extreme aspect ratios — a 1597-node graph routinely lays out at ~3800 × 81600 px, whose 1:1 RGBA buffer alone is 1.2 GB before any JPEG encoding overhead.

    Runs scan then render in a single invocation, accepting every flag from both.

    Walks a project tree, extracts the GitHub repository URL from every project manifest it finds, forwards the deduped list to scan, and then renders the resulting cache — auto is a scan + render combo, exactly like all, except the repo list comes from filesystem discovery instead of --repo flags. Useful when you are sitting inside a polyglot monorepo or a directory containing several checked-out projects and want a one-shot graph across all of them.

    issue_tree auto                              # discovers + scans + writes auto-named PNG to cwd
    issue_tree auto ./projects --cache big.json  # rooted at ./projects, custom cache
    issue_tree auto --format svg --out g.svg     # render to SVG instead of PNG
    

    The positional argument is the directory to scan (defaults to .). Every scan flag (--cache, --token, --wait, --force, --quiet) and every render flag (--format, --out, --scope, --label, --milestone, --state, --child-of-gates, --edge-style, --rankdir, --engine, --splines, --nodesep, --ranksep, --concentrate, --packmode, --graph-pad, --graph-margin, --node-margin, --edge-minlen, --issue-shape, --pr-shape, --raster-max) is accepted and forwarded.

    The auto default --format is png (unlike render/all, which default to svg). The reasoning: the natural endpoint of issue_tree auto is a finished image, so binary is the best implicit choice. Override with --format <fmt> or by passing --out with a recognized extension (e.g. --out g.svg picks svg).

    Detection logs go to stdout (one detected: <file> → <owner/name> line per repo) and are suppressed by --quiet. If no repos are found, auto exits with code 2 and a no GitHub repos detected message and skips render. If the scan rate-limits, auto still proceeds to render against the partial cache (matching all's semantics).

    Recognized manifest formats (one repo extracted per match; non-GitHub URLs are skipped):

    Ecosystem File pattern Field
    Node/JS/TS package.json .repository or .repository.url
    Rust Cargo.toml [package].repository
    Python pyproject.toml [project.urls].{Repository,Source,Homepage} or [tool.poetry].repository
    Go go.mod module github.com/... line
    PHP composer.json .support.source or .homepage
    Dart pubspec.yaml repository: or homepage:
    Java/Maven pom.xml <scm><url> or <scm><connection>
    .NET *.csproj / *.fsproj / *.vbproj <RepositoryUrl>
    Crystal shard.yml repository: or url:
    Haskell *.cabal source-repository.location: or homepage:
    OCaml dune-project (source (github ...)) or (source (uri ...))
    Ruby *.gemspec spec.metadata['source_code_uri'] or spec.homepage
    ObjC/Swift *.podspec s.source = { :git => ... } or s.homepage
    R DESCRIPTION URL: (first GitHub entry wins)
    Lua *.rockspec source = { url = ... } or homepage
    Elixir mix.exs links: %{"GitHub" => "..."}
    Perl META.json / META.yml .resources.repository.{url,web}
    Julia Project.toml repo = "..."
    PowerShell *.psd1 ProjectUri = '...'
    Zig build.zig.zon .repository = "..."
    D dub.json / dub.sdl .sourceRepository
    Clojure project.clj :url "..." inside defproject
    Common Lisp *.asd :source-control or :homepage
    Fortran fpm.toml [package].repository

    Excluded directories. The traversal never descends into directories that hold vendored dependencies or build artifacts: node_modules, vendor, target, dist, build, out, bin, obj, __pycache__, .venv, venv, env, .tox, .pytest_cache, Pods, .gradle, .idea, .vs, .vscode, .next, .nuxt, coverage, coverage-* (e.g. coverage-typedoc), htmlcov, .git, .svn, .hg, bower_components, elm-stuff, deps, _build, .stack-work, .cargo, .pub-cache. This prevents thousands of unrelated package.json files (or similar) from a dependency tree from polluting the scan list.

    Format Description
    json The filtered graph as JSON (nodes + edges + metadata).
    dot Graphviz DOT source.
    svg SVG rendered via viz.js.
    png PNG rasterized from the SVG via resvg.
    jpeg JPEG rasterized from the SVG via resvg.
    html Self-contained interactive HTML — includes the viz.js layout engine and the browser client bundle, so the file works offline with no server.

    The html format is particularly useful for sharing: the output file opens in any browser and renders the graph interactively without a server or network access.

    render reads a pre-built cache. If the cache file does not exist, the command exits with an error. Run scan (or all) first to produce the cache.

     

     

    Count Statement Branch Func Line
    Unit 448 96.52% {{unitbranch}}% {{unitfunc}}% {{unitline}}%
    Stochastic 18 96.52% {{stochbranch}}% {{stochfunc}}% {{stochline}}%
    Docblock count 38%
    Docblock coverage 272 38%
    star_chart
    sunburst visualization treemap visualization
    network visualization flamegraph visualization

     

     

     

    1. [ ] Decide whether to
      1. Update the deps in the template recommended
      2. Update the deps post-install
      3. Let the deps be out of date

     

    1. [ ] Reset package version
    2. [ ] Turn Github Pages on, and point it at master//docs
    3. [ ] Set up the auth token TODO_TOKEN_FOR_GH_CI_CD after renaming it in ci.yml
    4. [ ] Change all the issue_trees in this file's top block links
    5. [ ] Change all the issue_trees in package.json
    6. [ ] Change the issue_tree in verify_version_bump.js
    7. [ ] Write or copy-paste the description in package.json
    8. [ ] Search for all remaining TODOs
    9. [ ] Update meta tags and TODOs in src/html/index.html
    10. [ ] Write a base-README.md
    11. [ ] Change all the issue_trees in rollup.config.js
    12. [ ] Decide whether to
      1. re-add a bin block to package.json, or
      2. remove the bin config from rollup.config.js
    13. [ ] npm install && npm run build
      1. Maybe update the deps?
    14. Handle the MAYBE-REMOVEs in the HTML HEAD
      1. [ ] Change src/html/index.html 's </li> <li>[ ] Maybe replace src/html/favicon.png</li> </ol> </li> <li>[ ] commit and vroom</li> </ol> <p> </p> <p> </p> <h2 id="scanner-cache-module" class="tsd-anchor-link">Scanner / cache module<a href="#scanner-cache-module" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2> <p><code>issue_tree</code>'s scanner fetches the issues of one or more GitHub repositories — and the external issues that block them — into a single resumable JSON cache, via the GitHub GraphQL API.</p> <h3 id="cli" class="tsd-anchor-link">CLI<a href="#cli" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3> <pre><code>scanner [--cache <file>] [--token <token>] [--wait] [--force] <owner/repo> ... </code></pre> <ul> <li><code><owner/repo> ...</code> — one or more target repositories to scan.</li> <li><code>--cache <file></code> — cache file path (default <code>issue-tree-cache.json</code>).</li> <li><code>--token <token></code> — GitHub token (see Authentication below).</li> <li><code>--wait</code> — on hitting the rate limit, sleep until it resets and continue, rather than stopping.</li> <li><code>--force</code> — discard any existing cache before scanning.</li> </ul> <h3 id="authentication" class="tsd-anchor-link">Authentication<a href="#authentication" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3> <p>The scanner resolves a GitHub token from three sources, in order: the <code>--token</code> flag, the <code>GITHUB_TOKEN</code> environment variable, then <code>gh auth token</code> (the GitHub CLI).</p> <h3 id="resumable-cache" class="tsd-anchor-link">Resumable cache<a href="#resumable-cache" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h3> <p>The scan runs in four phases — repository issues, body blockers, comments, comment blockers — and checkpoints the JSON cache continuously. A scan interrupted by the rate limit is resumed by simply re-running the same command, picking up at the last saved page cursor.</p> <p>An already-complete cache is re-scanned incrementally, fetching only issues changed since the last run. Before opening pagination for a previously-completed repo, a cheap single-scalar GraphQL probe checks <code>repository.updatedAt</code>; when GitHub reports the repo has not changed since the cache's <code>lastScanCompletedAt</code>, the repo is skipped entirely (costing one rate-limit point instead of thousands of page fetches).</p> <p>Even mid-scan, a resumed repo's <code>since</code> filter is set to the maximum <code>updatedAt</code> across already-cached issues, so the GraphQL server only returns issues newer than what is on disk.</p> <p> </p> <p> </p> <h2 id="license" class="tsd-anchor-link">License<a href="#license" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2> <p>MIT</p> </div></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-chevronDown"></use></svg><h3>On This Page</h3></summary><div class="tsd-accordion-details"><a href="#issue_tree-v0127"><span>issue_<wbr/>tree v0.12.7</span></a><ul><li><a href="#issue_tree-cli"><span>issue_<wbr/>tree <wbr/>CLI</span></a></li><li><ul><li><a href="#subcommands"><span>Subcommands</span></a></li><li><ul><li><a href="#_"><span></span></a></li><li><a href="#_-1"><span></span></a></li><li><a href="#_-2"><span></span></a></li><li><a href="#_-3"><span></span></a></li></ul></li><li><a href="#output-formats"><span>Output formats</span></a></li><li><a href="#important-never-scans"><span>Important: never scans</span></a></li></ul></li><li><a href="#test-status"><span>Test status</span></a></li><li><a href="#how-to-use-this-template"><span>How to use this template</span></a></li><li><ul><li><a href="#before-invoking-it"><span>Before invoking it</span></a></li><li><a href="#after-invoking-it"><span>After invoking it</span></a></li></ul></li><li><a href="#scanner-cache-module"><span>Scanner / cache module</span></a></li><li><ul><li><a href="#cli"><span>CLI</span></a></li><li><a href="#authentication"><span>Authentication</span></a></li><li><a href="#resumable-cache"><span>Resumable cache</span></a></li></ul></li><li><a href="#license"><span>License</span></a></li></ul></div></details></div><div class="site-menu"><nav class="tsd-navigation"><a href="modules.html">issue_tree</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>