Documentation Index
Fetch the complete documentation index at: https://docs.cirron.com/llms.txt
Use this file to discover all available pages before exploring further.
cirron traces
Read and export the local trace data the Cirron Python SDK produces when
ci.profile() runs. Where cirron spool gives you a
file-level view of the raw batch JSON on disk, cirron traces gives you a
semantic view: reconstructs the scope tree across batches, groups records
into sessions, renders flamegraphs, and exports to Parquet, OpenTelemetry,
CSV, or JSON.
Everything under cirron traces runs entirely against the local spool
(./.cirron/spool/) and snapshot directory (./.cirron/snapshots/<span_id>/).
No network is required; no platform authentication is involved. This is the
“no lock-in” surface — your traces are yours, in open formats, on your disk.
Subcommands
Usage
cirron traces view [--last <n>] [--name <substr>] [--session <id>] [--depth <n>]
[--min-wall <dur>] [--spool <dir>] [--no-color] [--json]
cirron traces list [--spool <dir>] [--json]
cirron traces export --format <parquet|otel|csv|json>
[--output <path>] [--session <id>] [--spool <dir>]
cirron traces clear [--before <iso-date>] [--keep <n>] [--yes]
[--no-prune-orphans] [--spool <dir>]
cirron traces snapshots [<spanId>] [--session <id>] [--span <id>]
[--spool <dir>] [--json]
cirron traces snapshot <spanId> [<tensorName>]
[--spool <dir>] [--file <path>]
[--preview <n>] [--tail <n>]
[--export <path>] [--json] [--no-color]
Global Options
| Option | Description | Default |
|---|
--spool <dir> | Override the spool directory | ./.cirron/spool |
--json | Emit machine-readable JSON (supported on view, list, snapshots) | — |
--no-color | Disable ANSI color output (supported on view, snapshot) | color when stdout is a TTY and NO_COLOR is unset |
Sessions, Spans, Marks, Snapshots
Before diving into subcommands, a quick vocabulary:
- Session — One
ci.profile() lifetime in a single process. Identified by the
root cirron.session span. Typically one session per training run.
- Span — A timed scope: epoch, step, forward pass, optimizer step, etc.
Spans nest via
parent_id, forming the scope tree.
- Mark — A named scalar value (
ci.mark("loss", 0.5)) attached to the
innermost open span.
- Snapshot — A per-tensor weight or gradient record captured at an epoch
boundary. Stats (mean/std/min/max/norm/histogram) live inline in the spool
JSON; for
sampled and full modes, the tensor values themselves are stored
as safetensors files under ./.cirron/snapshots/<span_id>/.
cirron traces reconstructs sessions by deduplicating spans across batches
(preferring the record with end_ns set when a span spans two flush
intervals) and walking parent pointers from every cirron.session root.
View the scope tree
Render one or more sessions as an indented text flamegraph. This is the
primary “what happened?” view.
cirron traces view
cirron traces view --last 3
cirron traces view --name epoch
cirron traces view --session 067fc96e
cirron traces view --depth 2
cirron traces view --min-wall 1ms
cirron traces view --spool ./other/.cirron/spool
cirron traces view --no-color
cirron traces view --json
Options
| Option | Description |
|---|
--last <n> | Show the N newest sessions (default: 1) |
--name <substr> | Keep only spans whose name contains the substring — ancestors are preserved so the tree stays readable |
--session <id> | Show a specific session. Prefix match allowed |
--depth <n> | Collapse the tree below depth N. Collapsed subtrees show an aggregate duration and span count |
--min-wall <dur> | Hide spans shorter than the given duration. Accepts ns, us/µs, ms, s, m, h |
Example output
cirron.session — 561.7ms pid=1797 rank=0
epoch[0] — 42.1ms
data_load — 4.5ms data_load_ns=4541667
forward — 5.1ms
backward — 23.0ms
optimizer_step — 974.0us
ci.mark loss=0.6841
epoch[1] — 38.9ms
...
Marks are rendered as indented ci.mark <name>=<value> lines under the
span they attach to. point marks (the default) render as-is; summary
marks carry a (summary) suffix.
Collapsed output
With --depth 1:
cirron.session — 561.7ms pid=1797 rank=0
epoch[0] — 42.1ms
… 33.6ms (4 spans, collapsed)
epoch[1] — 38.9ms
… 31.2ms (4 spans, collapsed)
The collapsed duration sums only descendants, so it’s always ≤ the parent’s
own wall time.
Filtered output
With --name transform:
cirron.session — 7.3ms pid=96540 rank=0
fit — 6.2ms estimator=Pipeline
fit_transform — 803.1us estimator=StandardScaler
predict — 191.0us estimator=Pipeline
transform — 66.8us estimator=StandardScaler
Empty spool
No traces found. Run ci.profile() from Python to produce some.
List sessions
Table of every session found in the spool, newest first.
cirron traces list
cirron traces list --spool ./other/.cirron/spool
cirron traces list --json
Example output
Spool: /home/alice/runs/resnet/.cirron/spool (2 sessions)
┌───────────┬──────────────────────────┬──────────┬───────┬───────┬───────────┬──────────┐
│ SESSION │ STARTED │ DURATION │ SPANS │ MARKS │ SNAPSHOTS │ SIZE │
├───────────┼──────────────────────────┼──────────┼───────┼───────┼───────────┼──────────┤
│ a541b565… │ 2026-04-21T14:22:05.001Z │ 561.7ms │ 5244 │ 5123 │ 0 │ 142.3 KB │
│ ea06e583… │ 2026-04-21T15:01:33.442Z │ (live) │ 64 │ 20 │ 36 │ 48.0 KB │
└───────────┴──────────────────────────┴──────────┴───────┴───────┴───────────┴──────────┘
Live sessions — those whose root cirron.session has no end_ns yet
because the SDK is still running or the process exited mid-flush — show
(live) instead of a duration and are protected from destructive
clear --keep operations.
JSON output
{
"dir": "/home/alice/runs/resnet/.cirron/spool",
"sessions": [
{
"id": "a541b565-b754-42e3-...",
"started_ns": "1776486598051509000",
"ended_ns": "1776486598613253000",
"live": false,
"spans": 5244,
"marks": 5123,
"snapshots": 0,
"bytes": 145723,
"sdk_version": "0.1.0"
}
]
}
Export traces
Convert local traces into an open format so you can analyze them in
DuckDB, pandas, Polars, or ship them to an OpenTelemetry backend like
Jaeger, Tempo, or Honeycomb.
cirron traces export --format parquet --output ./exported/
cirron traces export --format parquet --session a541b565 --output ./one/
cirron traces export --format otel --output ./traces.otlp.json
cirron traces export --format csv --output ./spans.csv
cirron traces export --format json --output ./traces.json
Options
| Option | Description |
|---|
--format <fmt> | Required. One of parquet, otel (alias: otlp), csv, json |
--output <path> | Output path. For Parquet this is a directory; for other formats it’s a file. Defaults to ./cirron-traces[.ext] |
--session <id> | Export a single session by id (prefix match allowed). Without this flag, all sessions are exported together |
Writes three files into the output directory:
spans.parquet — one row per span (columns mirror the platform TraceSpan model)
marks.parquet — one row per mark
snapshots.parquet — one row per snapshot record (stats inline; blobs remain on disk)
All *_ns columns are INT64. Use DuckDB or pandas to query:
duckdb -c "SELECT name, COUNT(*), AVG(duration_ns)/1e6 AS ms
FROM 'exported/spans.parquet'
GROUP BY name ORDER BY ms DESC"
Parquet writing uses @dsnp/parquetjs (pure JavaScript) so the CLI’s
pkg-built binaries work without native modules.
Emits a single file in the OTLP/JSON
wire format. If a tool speaks OTLP, it can read this file.
No Cirron-specific reader, schema, or plugin is required on the receiving side.
Where it works
Anything on the OpenTelemetry traces receive-side. A non-exhaustive list:
| Category | Examples |
|---|
| Open-source backends | Jaeger, Grafana Tempo, SigNoz, Uptrace, ClickStack |
| Commercial backends | Honeycomb, Datadog, New Relic, Dynatrace, Splunk Observability, Lightstep, Elastic APM, Axiom |
| Cloud-native | Azure Monitor, Google Cloud Trace, AWS X-Ray (via OTEL collector) |
| Collectors / proxies | otelcol (OpenTelemetry Collector — core and contrib), Grafana Alloy, Grafana Agent, Vector |
How to ship it
The simplest path is an HTTP POST to any OTLP/HTTP /v1/traces endpoint:
cirron traces export --format otel --output traces.otlp.json
curl -X POST http://localhost:4318/v1/traces \
-H 'Content-Type: application/json' \
--data @traces.otlp.json
That’s the OTLP/HTTP contract verbatim — no Cirron-side involvement. For
backends that require OTLP/gRPC (Protobuf), run the JSON through the
OpenTelemetry Collector, which transparently converts formats:
# otelcol config.yaml
receivers:
otlp:
protocols:
http: {}
exporters:
otlp:
endpoint: your-backend.example.com:4317
service:
pipelines:
traces:
receivers: [otlp]
exporters: [otlp]
Encoding details
- Each session becomes one
resourceSpans[] entry with
service.name=cirron, sdk.version, and cirron.session.id on the
Resource.attributes.
- Each span becomes an OTLP span.
traceId is derived from the session
id (32 hex chars), spanId/parentSpanId from Cirron span ids
(16 hex chars each) — derived, not just truncated, so non-hex ids
(the SDK uses UUIDs) still produce spec-valid fields.
startTimeUnixNano and endTimeUnixNano are string-encoded int64,
per the OTLP spec’s 64-bit integer rule. Values are Unix-epoch
nanoseconds from the SDK’s time.time_ns().
- Attributes are wrapped as
AnyValue (stringValue / intValue /
doubleValue / boolValue / arrayValue / kvlistValue) with
correct scalar promotion.
- Marks attach to their owning span as
events[] with
timeUnixNano, name, attributes.value, and attributes.kind
(point or summary).
Status.code defaults to UNSET (0); becomes ERROR (2) when a span
carries an error attribute. We do not set OK (1) proactively — the
profiler has no success/failure model, and marking everything OK
would paint spans artificially green in UIs like Jaeger.
Flat, spans-only CSV streamed to disk (memory usage stays bounded even
on million-span spools). One row per span; columns:
session_id, span_id, parent_id, name, index, start_ns, end_ns, duration_ns,
cpu_ns, gpu_ns, memory_peak_bytes, thread_id, pid, rank, attrs_json
Marks and snapshots aren’t in the CSV — use Parquet or JSON if you need
full fidelity.
Merged, deduplicated JSON in the same shape as a single spool batch:
{
"schema_version": 1,
"sdk_version": "0.1.0",
"spans": [ ... ],
"marks": [ ... ],
"snapshots": [ ... ]
}
Dedupe is by id across spans, marks, and snapshots — safe to diff or
re-import.
Clear sessions
Delete sessions (batch files plus their snapshot directories) with a
confirmation prompt by default.
cirron traces clear # all non-live sessions, with prompt
cirron traces clear --before 2026-04-20
cirron traces clear --keep 5
cirron traces clear --yes # skip confirmation
cirron traces clear --no-prune-orphans
Options
| Option | Description |
|---|
--before <iso-date> | Only sessions whose start_ns is before this ISO-8601 date are eligible |
--keep <n> | Retain the N most recent non-live sessions |
--yes | Skip the confirmation prompt (for CI/scripting) |
--no-prune-orphans | Do not sweep snapshot directories whose span id isn’t referenced by any surviving session |
What gets deleted
- Every batch JSON under the spool that belongs to an eligible session.
- Every
./.cirron/snapshots/<span_id>/ directory for spans in those
sessions.
- By default, any orphan snapshot directory whose span id isn’t
referenced by any surviving session (common if
cirron spool clear
was used previously and left snapshots dangling).
Live sessions are never deleted by --keep; they only participate
in --before deletion if their start timestamp is already in the past
cutoff.
Confirmation prompt
? Delete 3 sessions (5,244 spans, 142.3 KB, 18 snapshot dirs)? (y/N)
Behavior vs. cirron spool clear
cirron spool clear is file-level: it deletes every batch JSON under
the spool directory and stops there. cirron traces clear is
session-level: it deletes batch JSONs and the matching snapshot
directories, honors live sessions, and can scope by date or count. Both
coexist; prefer traces clear for user-facing cleanup.
List snapshots
Table of weight/gradient snapshots grouped by the span that produced
them. Useful when you want to know which epochs have recorded weights.
cirron traces snapshots
cirron traces snapshots --session a541b565
cirron traces snapshots --span f9480382
cirron traces snapshots f9480382 # positional sugar for --span
cirron traces snapshots --json
Example output
Spool: /tmp/demo/.cirron/spool (3 spans with snapshots)
┌───────────┬───────────┬──────────┬─────────┬───────┬───────────┐
│ SESSION │ SPAN │ NAME │ TENSORS │ MODES │ WITH BLOB │
├───────────┼───────────┼──────────┼─────────┼───────┼───────────┤
│ 5da94f46… │ f9480382… │ epoch[0] │ 12 │ full │ 12 │
│ 5da94f46… │ 5385ac83… │ epoch[1] │ 12 │ full │ 12 │
│ 5da94f46… │ 912b0397… │ epoch[2] │ 12 │ full │ 12 │
└───────────┴───────────┴──────────┴─────────┴───────┴───────────┘
- TENSORS — number of snapshot records (one per parameter and, if
gradients were captured, per parameter’s
.grad).
- MODES —
stats (inline stats only), sampled (stats + blob for a
subset of epochs), full (blob every epoch).
- WITH BLOB — number of records that carry a
blob_uri (i.e., have a
safetensors payload on disk or on the platform).
Inspect a snapshot
The deep-dive view. Combines inline stats with the safetensors file
header on disk, renders an ASCII histogram of tensor values, and
optionally previews or exports raw tensor data.
# Span summary: stats table for every tensor + safetensors headers
cirron traces snapshot f9480382
# Focused view on one tensor
cirron traces snapshot f9480382 2.weight
# Preview the first 10 and last 10 values
cirron traces snapshot f9480382 2.weight --preview 10 --tail 10
# Extract just this tensor to a fresh single-tensor safetensors file
cirron traces snapshot f9480382 2.weight --export ./my-2weight.safetensors
cirron traces snapshot f9480382 2.weight --export ./out/
# Copy the whole span's blob(s) to disk (no tensor arg)
cirron traces snapshot f9480382 --export ./out/
Options
| Option | Description |
|---|
--file <path> | Read a specific safetensors file instead of auto-selecting weights.safetensors and gradients.safetensors under the span directory |
--preview <n> | Print the first N values from the selected tensor (requires a tensor argument) |
--tail <n> | Print the last N values from the selected tensor |
--export <path> | With a tensor: write a single-tensor safetensors file. Without a tensor: copy the whole-span blobs. See Export rules |
--json | Machine-readable output |
--no-color | Disable ANSI color (consistent with cirron traces view) |
Example: span summary
Span f948038257e64867b6557edfd699a210
Name epoch[0]
Session 5da94f46f9ef4db5bfc0a38511ae55b0
Records 12 snapshot records
┌───────────────┬───────┬─────────┬────────────┬──────────┬──────────┬──────┐
│ TENSOR │ DTYPE │ SHAPE │ MEAN │ STD │ NORM │ MODE │
├───────────────┼───────┼─────────┼────────────┼──────────┼──────────┼──────┤
│ 0.weight │ F32 │ [32,16] │ -0.001464 │ 0.144752 │ 3.275535 │ full │
│ 0.bias │ F32 │ [32] │ 0.022988 │ 0.151547 │ 0.867083 │ full │
│ 2.weight │ F32 │ [16,32] │ -0.006097 │ 0.102454 │ 2.322361 │ full │
│ 0.weight.grad │ F32 │ [32,16] │ -2.0163e-4 │ 0.011099 │ 0.251187 │ full │
│ ... │ │ │ │ │ │ │
└───────────────┴───────┴─────────┴────────────┴──────────┴──────────┴──────┘
weights.safetensors (6 tensors, 4.45 KB, file=4.85 KB)
┌──────────┬───────┬─────────┬─────────┐
│ NAME │ DTYPE │ SHAPE │ BYTES │
├──────────┼───────┼─────────┼─────────┤
│ 0.weight │ F32 │ [32,16] │ 2.00 KB │
│ 2.weight │ F32 │ [16,32] │ 2.00 KB │
│ 4.weight │ F32 │ [4,16] │ 256 B │
│ 0.bias │ F32 │ [32] │ 128 B │
│ 2.bias │ F32 │ [16] │ 64 B │
│ 4.bias │ F32 │ [4] │ 16 B │
└──────────┴───────┴─────────┴─────────┘
gradients.safetensors (6 tensors, 4.45 KB, file=4.85 KB)
...
Example: focused tensor view
Span f948038257e64867b6557edfd699a210
Name epoch[0]
Session 5da94f46f9ef4db5bfc0a38511ae55b0
Records 12 snapshot records
Tensor 2.weight (F32, shape=[16,32], mode=full)
mean = -0.006097
std = 0.102454
min = -0.176622
max = 0.175181
norm = 2.322361
histogram: ▇▇▇▆▇▇▆▅█▆▅▆▆█▅▇ [-1.77e-1 … 1.75e-1] max_bucket=41
Blob /tmp/demo/.cirron/snapshots/f948038.../weights.safetensors
dtype=F32 shape=[16,32] bytes=2048
first 10: [0.0179, 0.1631, -0.1491, 0.0919, -0.0841, -0.1328, -0.16, -0.111, -0.1585, -0.1334]
last 10: [-0.1036, 0.0101, -0.089, -0.1747, 0.1161, -0.0149, -0.0135, -7.113e-4, 0.1747, -0.0621]
The histogram uses Unicode block characters (▁▂▃▄▅▆▇█) scaled to the
max bucket count. Range is the bin edges reported by the SDK.
Supported dtypes
The safetensors reader understands every standard safetensors dtype:
F64, F32, F16, BF16, I64, I32, I16, I8, U64, U32,
U16, U8, BOOL. --preview upcasts F16/BF16 to float32 for
display; integer types print exact values (64-bit ints as BigInt).
Export rules
When --export is supplied:
With a tensor name:
Writes a fresh single-tensor safetensors file containing only the
requested tensor. If <path> is an existing directory, the file is
written as <tensor_name>.safetensors inside it (non-filename
characters replaced with _).
Without a tensor name:
Copies the candidate safetensors blob(s) to the destination. File vs
directory is auto-detected:
- If the path exists on disk, we use what’s there (dir → dir, file → file).
- If the path ends in
.safetensors, it’s treated as a file.
- If there’s exactly one blob and the path has no extension, it’s
treated as a file.
- Otherwise the path is treated as a directory.
Mismatches (e.g. pointing at a file path but two blobs exist) produce a
clear error directing you at --file to narrow the selection.
How It Works
-
Spool format. Batch files under
.cirron/spool/ use the name
pattern <created_ns>-<batch_id>.json. The CLI sorts by the nanosecond
prefix and streams each file through a parser that tolerates unknown
fields (spec schema_version: 1 forward-compat rule).
-
Session reconstruction. For each batch, spans are deduped by id;
the record with
end_ns set wins so a span that straddled a flush
boundary appears as a single closed span. Marks and snapshots dedupe
by id, last-write-wins (the SDK may re-emit on flush retries).
-
Session roots. A session is rooted at every span named
cirron.session with parent_id === null. Every other span is
attached to a session by walking parent_id up. Orphan spans (parent
id not resolvable) are bucketed into a synthetic (orphan spans)
session only when no real sessions exist — so the common case stays
clean.
-
Snapshot layout. Safetensors live under
.cirron/snapshots/<span_id>/{weights,gradients}.safetensors. The
tensor name from the snapshot record is used verbatim as the key
inside the safetensors container.
-
Forward compatibility. Unknown top-level and per-span fields are
ignored; known fields outside their documented type (e.g.
start_ns
as a string instead of a number) are coerced through BigInt
safely. This means a newer SDK can add metadata without breaking an
older CLI.
Error Handling
No traces found
No traces found. Run ci.profile() from Python to produce some.
Solution: Ensure your training or inference script calls
ci.profile() before the work you want to trace, or point --spool at
the directory where the spool actually lives.
Session not found
Error: No session found matching <prefix>
Solution: Check cirron traces list for valid session ids. Prefix
matching is substring-prefix, not fuzzy.
Tensor not found
Error: Tensor "<name>" not found in <file>. Available: <names>
Solution: Run cirron traces snapshot <span> without a tensor name
to see the full list. Copy the tensor name verbatim — they commonly
contain dots (layer1.0.conv1.weight).
Export path ambiguity
Error: Destination <path> is a single file but N blobs were found (weights, gradients).
Pass a directory, or narrow the selection with --file.
Solution: Either point --export at a directory, or pass
--file <path> to pick one blob.
Empty --before / bad ISO date
Error: Invalid --before date: <value> (expected ISO-8601)
Solution: Use ISO-8601: 2026-04-20, 2026-04-20T12:00:00Z, etc.
Interrupted clear
If you hit Ctrl-C mid-clear, the command stops deleting as soon as
the signal arrives and reports how many files/dirs made it to disk
before interruption. Exit code is 130.
Examples
Terminal inspection after a training run
python train.py
cirron traces list
cirron traces view --last 1 --depth 3
Compare two epochs’ weight stats
cirron traces snapshots | head
cirron traces snapshot <span_id_epoch_0> 2.weight
cirron traces snapshot <span_id_epoch_5> 2.weight
Export for DuckDB analysis
cirron traces export --format parquet --output ./out/
duckdb -c "
SELECT name, COUNT(*) AS n, AVG(duration_ns)/1e6 AS avg_ms
FROM 'out/spans.parquet'
GROUP BY name ORDER BY avg_ms DESC
"
Ship traces to Jaeger
cirron traces export --format otel --output ./traces.otlp.json
# If your collector exposes the OTLP HTTP ingest endpoint:
curl -X POST -H 'Content-Type: application/json' \
--data @traces.otlp.json \
http://localhost:4318/v1/traces
Air-gapped audit of a tensor
cirron traces snapshot <span_id> layer1.weight \
--preview 16 --tail 16 \
--export ./audit/layer1.weight.safetensors
Clean up after a long training session
cirron traces list
cirron traces clear --keep 3 --yes
cirron spool — File-level view; required for uploading batches to the platform with spool flush.
cirron auth — Authenticate before a spool flush (not needed for any traces subcommand).
cirron status — Check CLI + platform connectivity.