> ## 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.

# ci.trace

> In-process read-back of the current session scope tree.

`ci.trace()` returns the current session's scope tree without leaving
the Python process. It is the on-demand companion to the continuous
[`output=` sinks](/sdk/reference/profile#output-sinks): a notebook
user can call it after a training cell to see the tree inline; a
script can call it mid-run to inspect what has happened so far.

The data source is a process-wide in-memory buffer that the flush
thread populates each tick. `ci.trace()` performs a best-effort
synchronous drain into the buffer before reading, so spans closed
between the last tick and the call are visible immediately.

## Signature

```python theme={null}
def trace(
    format: Literal["tree", "dict", "json", "df"] = "tree",
    name: str | None = None,
    last: int | None = None,
) -> _TraceTreeRepr | dict | str | pandas.DataFrame | None
```

## Parameters

| Name     | Type   | Default  | Purpose                                                          |
| -------- | ------ | -------- | ---------------------------------------------------------------- |
| `format` | `str`  | `"tree"` | Output format. One of `"tree"`, `"dict"`, `"json"`, `"df"`.      |
| `name`   | `str?` | `None`   | Keep only spans whose `name` matches and their descendants.      |
| `last`   | `int?` | `None`   | Keep only the N most recently closed spans (ranked by `end_ns`). |

## Formats

| Format   | Returns                               | Notes                                                                                                                                                                          |
| -------- | ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `"tree"` | `None` (prints) or `_TraceTreeRepr`   | In a Jupyter kernel returns a notebook-renderable wrapper; otherwise prints to stdout.                                                                                         |
| `"dict"` | `{"roots": [...], "span_count": int}` | Nested dict form: each node has `name`, `index`, `wall_us`, `attrs`, `marks`, `children`.                                                                                      |
| `"json"` | `str`                                 | Same shape as `"dict"`, serialized with `json.dumps`.                                                                                                                          |
| `"df"`   | `pandas.DataFrame`                    | Flat: one row per span. Columns: `id`, `parent_id`, `name`, `index`, `wall_us`, `cpu_ns`, `gpu_ns`, `memory_peak_bytes`, `mark_count`, `depth`. Requires `cirron-sdk[pandas]`. |

`format="df"` raises [`CirronDependencyError`](/sdk/errors#cironndependencyerror)
when pandas is not installed, with a `pip install` hint.

## Examples

### Print the tree in a script

```python theme={null}
import cirron as ci

ci.profile(output="none")     # purely in-memory; no spool writes
for epoch in ci.epochs(range(3)):
    for batch in ci.batches(loader):
        loss = train_step(batch)
        ci.mark("loss", loss.item())

ci.trace()
# epoch[0] - 142us {epoch_loss=0.5234}
#   batch[0] - 12us {loss=0.6124}
#   batch[1] - 11us {loss=0.5410}
#   ...
```

### Render in a Jupyter cell

```python theme={null}
ci.trace()       # last expression renders inline; nothing prints to stdout
```

The Jupyter detection probes `IPython.get_ipython()` and only treats
the ZMQ kernel as a notebook. A plain `ipython` REPL still prints.

### Custom analysis with a DataFrame

```python theme={null}
df = ci.trace(format="df")
df[df["name"] == "forward"]["wall_us"].quantile([0.5, 0.95, 0.99])
```

```python theme={null}
df.groupby("name")["wall_us"].agg(["count", "mean", "max"])
```

### Filter to a single scope name

```python theme={null}
epochs = ci.trace(format="dict", name="epoch")
# Returns only the epoch subtrees and their children.
```

### Recent spans only

```python theme={null}
ci.trace(format="dict", last=5)
# The 5 most recently closed spans, ranked by end_ns.
```

## Behavior with no profiler attached

`ci.trace()` works without a prior `ci.profile()` call. In that mode
it drains the in-memory buffer directly and **never** writes a spool
file as a side effect, so it is safe on read-only filesystems and in
notebook inspection contexts.

```python theme={null}
import cirron as ci

with ci.scope("standalone"):
    ci.mark("x", 1)

ci.trace()    # no profiler, no spool writes, just the tree
```

When a profiler **is** active, the synchronous drain routes through
[`ci.flush()`](/sdk/reference/lifecycle#flush) so the user's
configured [`output=`](/sdk/reference/profile#output-sinks) sinks
still fire (an `output="spool"` run continues to land batches on
disk).

## Buffer bounds

The in-memory buffer is bounded:

* **Spans:** keeps the most recent `trace_buffer_max_spans` (default
  `100_000`).
* **Marks per span:** keeps every `kind="summary"` mark and the most
  recent `1024` `kind="point"` marks. This bound matters for
  long-lived open spans like `cirron.session` whose `span_id` never
  appears in the span eviction list.

Tune via [`Cirron`](/sdk/reference/cirron):

```python theme={null}
from cirron import Cirron
c = Cirron(trace_buffer_max_spans=10_000)
c.profile()
```

## Related

<CardGroup cols={2}>
  <Card title="output= sinks" icon="bars-staggered" href="/sdk/reference/profile#output-sinks">
    Continuous spool / log / stdout streaming as scopes close.
  </Card>

  <Card title="Lifecycle" icon="power-off" href="/sdk/reference/lifecycle">
    `flush`, `health`, `shutdown`.
  </Card>
</CardGroup>
