5.6.8 Skyscope — Skyframe Visualizer

extra

Skyscope turns one retained Skyframe graph into an interactive browser view. It is useful when a label-level query is too coarse and the text from bazel dump --skyframe is too large or opaque to inspect directly. The boundary is that it visualizes a snapshot of internal dependency state. It is not a supported query API, an execution timeline, or a history of invalidations.1

The project remains available and its GitHub repository is not archived, but the latest published release is v0.4.3 from July 2024 and the repository's last code activity was also in 2024. Treat it as a specialist diagnostic aid with version-sensitive compatibility, not as a maintained part of Bazel's toolset. In particular, verify an import against the exact Bazel version that produced the graph before relying on it in an investigation.2

Install the tool outside the workspace

Current upstream instructions require Graphviz's dot executable. They offer a prebuilt, statically linked Skyscope binary for Linux. MacOS users are directed to build the backend from source with Nix. Put the resulting skyscope binary on PATH and run it below the Bazel workspace whose server you want to inspect. The older http_archive plus @skyscope//:import installation shown in the 2023 announcement describes v0.2.7 and is no longer the current workflow.1,2

Before collecting a real diagnostic capture, check these operational details:

  • Skyscope starts a local HTTP server, using port 28581 by default, and stores imports under $HOME/.skyscope unless SKYSCOPE_DATA overrides it.
  • Importing shells out to the bazel found on PATH. SKYSCOPE_BAZEL_BIN can select a different binary.
  • The imported graph and its optional enrichment can contain labels, paths, command lines, and other workspace details. Treat the database as diagnostic data, especially on a shared machine.

Capture the smallest graph that answers the question

Skyframe belongs to the long-lived Bazel server and changes as commands run. Populate that server deliberately, then import it:

bazel shutdown
bazel build //app:release
skyscope import --query='//app/...' --aquery='//app/...'

bazel shutdown is appropriate here only when a deliberately cold, bounded snapshot answers the question. It discards the very incremental state you might otherwise be trying to diagnose. If the symptom exists only in a warm server, reproduce it first and import that server without clearing it. Record the Bazel version, startup options, output base, workload, and import options just as you would for a raw dump. 5.6.7 bazel dump — Internal State Inspection explains why that provenance matters.

Skyscope obtains topology from bazel dump --skyframe. By default it also runs aquery 'deps(//...)' and query 'deps(//...)' --output build to decorate otherwise terse nodes with action and target context. Those enrichment commands can be slow, can fail when unrelated targets are broken, and can themselves change the server graph. Narrow them with --query and --aquery, or use --no-query --no-aquery when preserving the captured topology matters more than friendly labels. A failed enrichment does not necessarily abort the topology import. It leaves some context absent.2

The importer loads a snapshot into SQLite and the server presents a link in the browser. Previously imported graphs are listed at http://localhost:28581 and can be deleted there.2

Read nodes as SkyKeys, not BUILD targets

Search matches the key text printed by bazel dump --skyframe. % is a wildcard. ConfiguredTarget, FileState, and ActionExecution are useful examples, not an exhaustive support list. Skyscope imports the dependency graph generically and displays the SkyFunction-derived node type plus raw key data. Consequently, the node vocabulary and formatting follow Bazel internals and can change between versions.3,2

This graph crosses several abstractions:

  • A ConfiguredTarget is configuration-specific. Similar labels may therefore denote different internal nodes.
  • A FileState node represents filesystem state used by Skyframe's incremental evaluation, not a declared BUILD dependency by itself.
  • An ActionExecution key identifies an action associated with a configured target and an action index. Optional aquery context can recover a mnemonic, inputs, and outputs that the dump key alone does not explain.2

Edges mean that evaluation of one Skyframe value depends on another. They do not establish wall-clock action order. Use 5.2.3 bazel aquery — Action Graph for the analyzed action plan and execution profiles or the BEP for what actually ran. Likewise, a snapshot may expose nodes associated with configurations and transitions, but Skyscope does not replace 5.2.2 bazel cquery — Configured Graph for explaining a transition or comparing configured target options.

Explore without rendering the whole graph

A fresh import initially hides every node. Search for one or two precise keys, make them visible, and expand outward:

  1. A collapsed node shows only edges to other visible nodes.
  2. Clicking it expands the node, exposing edges to hidden neighbors as small circles. Double-clicking reveals all neighbors.
  3. A dotted connection between visible components says that a dependency path exists. Choose Open to reveal one such path, much like somepath().
  4. Shift-select and crop to keep only the useful subgraph. Browser back and forward undo and redo exploration states.

This progressive reveal is the tool's main advantage over rendering an entire DOT graph. It is also where restraint matters: expanding a high-fanout internal node can still produce thousands of edges and slow Graphviz. Skyscope lets you interrupt a render and return to its last completed checkpoint.3,2

Use the picture to choose the next supported probe

Skyscope is strongest as a hypothesis generator:

  • Reveal a path between an internal file node and a configured target, then use cquery to verify the configured target relationship.
  • Reveal an ActionExecution neighborhood, then use focused aquery output to inspect the action's declared inputs, outputs, owner, and command.
  • Notice unexpected internal fan-in or retained node families, then capture a filtered raw dump or compare controlled cold and warm experiments.

Do not conclude from a single picture that an edge caused a rebuild, that one action ran before another, or that a transition invalidated the analysis cache. The import contains the current dependency graph, not the before/after dirtying events needed to prove those claims. It can suggest where to instrument next. The producing command, profile, log, BEP, or controlled mutation supplies the causal evidence.

Import cost is another practical limit. The 2023 prototype could take minutes on large graphs and could exhaust memory because it first loaded the whole graph before writing SQLite. Upstream later implemented streaming import, so the old 10 GB Envoy anecdote is not a current architectural description. Large imports and high-fanout renders can nevertheless remain expensive, and neither the dump format nor Skyscope's parsing of it is a stable Bazel compatibility contract.1,2

key takeaway

Use Skyscope when you need an interactive, selectively revealed view of one Bazel server's internal Skyframe dependencies. Install the standalone tool, populate or preserve the server state deliberately, and narrow or disable its default query/aquery enrichment according to the investigation.

Interpret nodes as version-sensitive SkyKeys and edges as evaluation dependencies. Skyscope can reveal internal paths and neighborhoods, but it cannot by itself prove execution order, rebuild causality, configuration transition behavior, or why a cache was invalidated. Turn each visual clue into a focused query, cquery, aquery, dump, profile, or BEP check.

Check your understanding · 4 questions

1.A Skyscope snapshot shows an unexpected path from a FileState node to a ConfiguredTarget. Which conclusions or next steps are justified?

Select all that apply

2.A team wants to try the current Skyscope release on Linux. Which setup follows the article's guidance?

Select one answer

3.How should you interpret nodes in an imported Skyframe graph?

Choose True or False for each sentence

Two ConfiguredTarget nodes with similar labels may represent different configurations.
A FileState node is automatically a declared dependency in a BUILD file.
An ActionExecution key may need aquery enrichment to expose useful action details.
Node names and key formatting are a stable public Bazel API.

4.A slow build appears only after several commands have reused the same Bazel server. What is the most useful Skyscope capture strategy?

Select one answer

0 of 4 answered

Footnotes

  1. Announcing Skyscope — motivation, snapshot workflow, path and action examples, and original performance limitations 1 2 3

  2. Skyscope upstream repository — current installation, import and enrichment behavior, storage, supported graph interaction, release history, and project status (verified 18 July 2026) 1 2 3 4 5 6 7 8

  3. Visualizing Build Graphs with Skyscope — node semantics, progressive reveal, path opening, cropping, history, and render interruption 1 2