Diagrams
What it does
Section titled “What it does”The diag library lets you visualize how Den resolves aspects — which aspects include which, how policies fan out, which classes each aspect contributes to. It transforms structured trace data from the effects pipeline into a format-agnostic graph Intermediate Representation (Graph IR), applies filters and reshapes, then renders into Mermaid, GraphViz DOT, PlantUML, C4, and other formats.
The pipeline
Section titled “The pipeline”Every diagram passes through four stages:
flowchart LR
A[Trace capture] --> B[Graph construction]
B --> C[Filtering]
C --> D[Rendering]
- Trace capture — collect
structuredTraceentries from aspect resolution. - Graph construction — build format-agnostic IR (nodes, edges, stages, stage transitions).
- Filtering — prune, fold, and reshape the IR (user-declared-only, class slices, adapters-only, etc.).
- Rendering — emit diagram strings in the target format.
Quick start
Section titled “Quick start”Capture the fleet once in den, then cut out the scope you want to draw:
diag = inputs.den-diagram.lib;fleetCapture = den.lib.capture.captureFleet { };
# one host's subtree, including its usersg = diag.projectScope { inherit fleetCapture; kind = "host"; name = "igloo"; };
diag.toMermaid gAdd a filter for a coarser overview:
diag.toMermaid (diag.graph.simplified g)Or slice to a single class:
diag.toMermaid (diag.graph.classSlice "nixos" g)Building graphs
Section titled “Building graphs”projectScope { fleetCapture; kind; name; direction?; }— the graph as seen from one scope of a fleet capture: the scope and all its descendants.kindis any entity kind (host,user,environment, …). This is the usual entry point, since onecaptureFleetserves every view.context { entries; ctxTrace?; pathsByClass?; name; direction?; }— builds a graph from a standalone capture of a single root:
captured = den.lib.capture.captureWithPathsWith { classes = [ "homeManager" ]; root = den.lib.resolveEntity "user" { inherit host user; }; ctx = { inherit host user; };};g = diag.context { inherit (captured) entries ctxTrace; name = user.name;};The diagram case study wires this into a flake and shows the generated output.
Filters and views
Section titled “Filters and views”The graph IR is purely structural — all visual decisions happen at filter and render time. This separation is why filters exist: the same captured graph can answer many different questions depending on which nodes you keep. Filters compose, so you pipe one into another to narrow the view.
A few representative filters under diag.graph give the flavour:
simplified— coarse overview that folds providers and entity-kind subgraphs away, leaving aspect edges only.classSlice "nixos"— the ancestor closure of aspects active in a single class, for answering “what contributes to my NixOS config?”.flattenEntityKinds— a fold that removes entity-kind subgraph grouping when the boxes get noisy.
These are illustrative, not the full set. See the diagram reference for the complete catalogue of predicate, closure, reshape, fold, and composite filters.
Renderers
Section titled “Renderers”A renderer turns the filtered IR into a diagram string in some target format. Because the IR is format-agnostic, the same graph drives every renderer — the choice of renderer is purely a presentation decision. A few representative ones:
toMermaid— Mermaid flowchart, for embedding in docs and GitHub.toDot— GraphViz DOT, better suited to large graphs and PDF export.toScopeEdgesMermaid— a sequence-family renderer that draws scope topology edges.
Den ships many more (C4, sankey, treemap, mindmap, state, JSON, and fleet-wide variants). See the diagram reference for the full list grouped by family.
Every renderer has a *With variant (e.g. toMermaidWith) that accepts theme and config overrides. The renderers constructor builds a complete set with shared settings:
render = diag.renderers { inherit theme; mermaidConfig = { layout = "elk"; }; };render.toMermaid graphThemes
Section titled “Themes”Diagrams support base16 color schemes via themeFromBase16:
theme = diag.themeFromBase16 { inherit pkgs; scheme = "catppuccin-mocha"; };Pass the theme to renderers or individual *With functions. The library provides defaultTheme as a fallback.
Fleet diagrams
Section titled “Fleet diagrams”diag.fleet.of builds a fleet-wide graph across all hosts in a flake:
fleetData = diag.fleet.of { flakeName = "my-fleet"; };Fleet graphs feed into fleet-specific renderers like toFleetSankeyMermaid, toFleetTreemapMermaid, and toFleetProviderMatrix.
Export pipeline
Section titled “Export pipeline”For generating SVG derivations (e.g. for a docs site), use renderContext together with the export helpers:
rc = diag.renderContext { inherit pkgs theme; mermaidConfig = elkCfg; };entries = diag.export.entityEntries { inherit pkgs rc diag; } { entity = diag.projectScope { inherit fleetCapture; kind = "host"; inherit (host) name; }; name = host.name; dir = "hosts/${host.name}"; viewDefs = rc.views.host;};The renderContext bundles pre-configured renderers (rc.render, rc.renderDense), SVG builder functions, and standard view definitions (rc.views.host, rc.views.fleet, etc.) into a single record. export.entityEntries turns those view definitions into per-view derivation entries for one entity; export.fleetEntries does the same for fleet-wide views. Entries then flow through entriesToPackages / entriesToFiles / mkWriteScript.
See also
Section titled “See also”- diagram reference — complete list of wrappers, filters, renderers, themes, and export helpers
- Aspects — how aspects compose
- Entities — the entity kinds that diagrams trace
- Policies — policy fan-out visible in diagram views