candle-graph
Disclaimer:
candle-graphis an independent tool. It is not official and is not affiliated with, endorsed by, or maintained by candle-rs or Hugging Face.
candle-graph reconstructs parameter structure, tensor contracts, and gradient connectivity of a
Candle model crate. Its versioned,
crate-wide model IR and bounded query API are designed so coding agents can answer focused
questions without loading an entire source tree into context.
The analyzer combines conservative Rust-source analysis with the Cargo configuration selected for the scan. An optional runtime trace can refine static tensor facts and audit gradients. It never loads checkpoint tensor payloads or requires a GPU for static analysis.
candle-graph/model/1: one unified IR for components, architecture edges, functions, modules, parameters, tensor contracts, stages, artifacts, optimizers, Cargo context, findings, and runtime evidence;candle-graph/query/1: deterministic, bounded agent queries with fully qualified selectors, compact-by-default progressive disclosure, andlimit/offsetpagination;candle-graph/runtime/1: JSON/JSONL tensor observations and per-parameter gradient facts; see docs/runtime-analysis-guide.md for the full workflow and v2 (time series) / v3 (profiler) extensions;candle-graph/viewer/1: standalone interactive HTML visualizer (requires thevisualizerfeature).
See docs/features.md for the static / runtime / visualizer
split: static IR for agents, runtime profiler timings, HTML for humans.
Status
Primary crate-wide UX is the Clippy-like Cargo subcommand cargo candle-graph
(check / report / query / audit / view) over the conservative analyzer. It is an explicit
cargo command, not a rustc lint pass and not a silent cargo build hook.
The agent-analysis path supports:
- automatic component discovery from public API boundaries and
VarBuilder/VarBuilderArgsconstructors, with--rootfor private model roots; - public tensor-boundary and Candle-trait entrypoint candidates with fully qualified identities;
- symbolic tensor rank/shape, dtype, device, layout, and
requires_gradcontracts; - Cargo package, target, feature, Candle-version, active
cfg, and per-function cfg-activity facts; - audited Candle 0.11.0 operation rules that distinguish similarly named APIs such as
RmsNorm::forwardandRmsNorm::forward_diff; - optional runtime tensor refinement and missing/zero/non-finite gradient findings;
- checkpoint-header verification and model-IR CI baselines.
Analysis is deliberately conservative. Unsupported expressions remain Unknown; a same-dtype
operation with one known and one unknown operand is a dtype-risk, while two known differing
dtypes are a dtype-conflict. Call-order architecture, pipeline stages, artifacts, and optimizer
membership require --heuristic-architecture or the future compiler frontend. Struct-field
composition edges are always available via --query composition with Heuristic confidence.
In particular, names such as run_pipeline, train_*, save, and all_vars, filename suffixes,
and source order do not create facts without that flag.
The compiler-backed design needed to derive those relationships without annotations or loading model weights is documented in docs/compiler-evidence-design.md.
Usage
Install once so Cargo discovers the Clippy-like subcommand (cargo-candle-graph →
cargo candle-graph):
Check a model crate the way you would run cargo clippy — an explicit cargo command, not a
silent side-effect of cargo build. Diagnostics go to stderr; the full candle-graph/model/1
document goes to stdout (or --output):
check / --strict exit non-zero on proven Error findings only. Coverage-gap warnings and
Information notes such as compiler-semantic-evidence stay visible but do not fail the gate.
Commit a crate-wide fingerprint with --update-baseline / --check on that same command.
Numeric domain: the analyzer expands audited candle-nn bodies (e.g. 0.11.0
binary_cross_entropy_with_logit) into the same float-range pass used for local
sigmoid?.log()? compositions, then labels whether the hazard can NaN a loss / poison
gradients or risk inference outputs. An affine(mul>0, add>0) epsilon guard discharges
StrictlyPositive and must not false-positive.
The candle-graph binary mirrors the same model-mode engine for scripts:
Ask focused questions. Listings are compact (counts/IDs, drill_down hints, no tensor evidence);
narrow with --select / singular kinds when you need contracts or evidence:
Use fully qualified selectors when bare names collide:
Select Cargo features/target exactly as the analyzed build does:
The analyzer follows the selected Cargo crate root and reachable mod declarations. It defaults
to the library target, then the first ordinary binary; use --cargo-target <name> for another
binary/example/test target. The --target option selects a Rust target triple.
Import an instrumented small-run trace:
Open the interactive multi-view HTML visualizer (requires candle-graph built with the
visualizer or all feature):
--features on this command selects Cargo features on the model crate (e.g. cuda),
not candle-graph. Names like static, visualizer, runtime, and all are candle-graph build flags
and are ignored when passed here. See docs/features.md and docs/visualizer.md.
Write a multi-file audit bundle (summary, doctor, findings, checkpoint verification, …):
See docs/agent-query-api.md for the query map, docs/visualizer.md for the HTML visualizer, docs/runtime-protocol.md for trace field definitions, and docs/runtime-analysis-guide.md for the recommended runtime workflow (gradient audit, phase graphs, offline profiling).
Checkpoint verification reads only the safetensors length prefix and JSON header. A template such
as model.layers.{index}.self_attn.q_proj.weight matches all concrete layer indices.
Create and check a canonical CI baseline:
--strict rejects proven dtype conflicts, numeric-domain violations, and other proven error
findings. Coverage-gap warnings and heuristic architecture notes stay visible but do not fail the
gate by themselves.
Run cargo candle-graph --help for all options.
Supported source patterns
The analyzer intentionally understands a restricted, explicit Rust dialect:
vb.pp(...),push_prefix,set_prefix,root, and metadata-preserving builder methods;- audited candle-nn 0.11.0 constructors and raw
vb.get*calls; - crate-local inherent constructors and free helper functions taking
VarBuilder; - multiple and optional builders, including
then,map, andand_then; - struct literals,
if/matchbranches,forloops, and iteratormap; - literal and
format!prefixes, including mixed segments such asblock_{index}. - ordinary tensor calls, local bindings, branches, symbolic loop iterations, and crate-local calls;
- dtype-preserving, explicit-cast, and same-dtype candle operations;
- version-gated Candle operation semantics. Rules not audited for the resolved Candle version stay unknown instead of silently borrowing another version's behavior.
Unsupported or ambiguous constructs produce diagnostics instead of silently inventing a result. Unknown custom macros, non-literal tensor names, unresolved builders, cycles, and analysis limits are therefore visible in every JSON report.
Output semantics
Parameter keys are namespaced by their originating constructor argument (root). Two identical
keys under different roots are different tensors. Certainty is one of:
certain: always registered on the analyzed path;conditional: gated by a branch, optional field/builder, or constructor configuration;unknown: reserved for constructs whose existence cannot be modeled safely.
Every model fact carries a stable identity and source/evidence where applicable. Function identity
is based on its fully qualified name and active cfg predicates rather than absolute paths or line
numbers, so ordinary source edits do not invalidate runtime correlation. Coverage counts and the
compact doctor query let consumers assess an analysis before trusting individual records.
dead_params(), severing_edges(),
dtype_conflicts(), dtype_risks(), and paths_to() remain available through the library API.
Development
The integration suite covers the unified IR/query/runtime schemas, Cargo feature/cfg discovery, qualified symbol collisions, tensor contracts, optimizer membership, versioned Candle semantics, formatted layer families, multiple builder roots, interprocedural calls, BF16/F32 joins, no-backward severing, deterministic baselines, the CLI, HTML safety, and safetensors headers.