Docs / Operate
Observability
Every run ivralo makes is stored with each tool call, its arguments and what it returned. This page covers the commands that read those runs back, and how to send spans to your own OpenTelemetry collector.
Before blaming the model
When a run went wrong, read what the model actually saw before changing a prompt or a model:
ivralo trace last
Most surprises are there in plain sight: a tool that failed, a policy that refused a command, a file that was not what the model expected, a request to the model that timed out.
Listing runs: ivralo runs
ivralo runs
The session's runs, newest first: what was asked, who did it, what it cost. -n sets how many (20 by default). Every run command takes --session (-s) to read another conversation's runs; ivralo sessions lists them.
Opening a run: ivralo trace
ivralo trace takes a run: last (the default) or the first eight characters or more of its id. It prints every tool call with its arguments and output, and the member that made it.
| Option | Does |
|---|---|
--tail N | Lines of each output to show (12 by default) |
--json | The flat list of tool calls as JSON, for your own tools |
--html | Write the run as one self-contained HTML file instead of printing it |
--out PATH | Where --html writes; by default .ivralo/traces/ in the workspace |
The HTML file has a timeline with one bar per tool call, every call with its complete output, and the answer. It inlines its style and loads nothing from the network, so it opens on a machine without ivralo, for example as an attachment to an issue:
ivralo trace last --html --out trace.html
In the session, /trace does the same for the last run.
A failed call says why
Every tool reports a failure in one shape, and the trace shows its code beside the call. The whole run's failures are counted on one line at the end:
shell rmdir /s /q . 0.0s failed REFUSED_BY_POLICY
read_url https://example.com/pricing 1.2s failed NETWORK_BLOCKED
failures: 1 NETWORK_BLOCKED, 1 REFUSED_BY_POLICY
| Code | Meaning |
|---|---|
REFUSED_BY_POLICY | A guardrail said no. The run worked as designed; there is nothing to fix. |
TIMEOUT | The work was still running when the tool's clock ran out |
NETWORK_BLOCKED | The egress policy or the far end stopped the request |
AUTH_REQUIRED, PERMISSION_DENIED | No usable credential, or one that does not reach this thing |
TOOL_UNAVAILABLE | The tool is not configured, or its backend is not there |
UNCLASSIFIED | The call raised and nothing recognised it. For an ivralo tool that is a bug. |
The list has a few more codes (RATE_LIMITED, INVALID_ARGUMENT, CONFLICT, RESOURCE_EXHAUSTED, PARSE_ERROR, PATCH_CONFLICT, VERIFICATION_FAILED), each named for what happened.
A failed request to the model
A request to the model that failed leaves a model row in the trace: the HTTP status, the provider's code, the request id, the start of the response body and how big the request was. A throttled endpoint (429), an unavailable one (503) and a dropped connection are asked again up to three times; a timeout once; a refused connection never. A 400 is a request the model cannot take, often a context that is too big, and is never repeated.
Exporting a conversation: ivralo export
ivralo export last --format md
Writes a whole conversation as one file: every turn, its tool calls and the replies. --format is html (one self-contained page, the default) or md. The file goes to .ivralo/exports/ in the workspace unless --out names a path. /export does the same in the session.
Where a claim came from
The trace shows everything a run did. To follow one number or sentence of the answer back to the file, the line or the tool output it rests on, use ivralo why. See Where a claim came from. To run a stored run again against what its tools answered last time, see Record and replay.
The machine: ivralo doctor
Beyond the services, ivralo doctor reads the machine:
- disk: free space on the workspace's drive (the row fails under 2 GiB, because history and the index are written there), how much history keeps, and the database's size;
- ollama: the server's version and, for each loaded model, how much of it the GPU holds. A model partly on the CPU fails its row: that is the usual reason every token is slow;
- tracing: whether spans leave the machine, and where.
See Doctor for every section.
OpenTelemetry
ivralo can send every run's spans (the team, each member, each model call, each tool call) to an OTLP/HTTP collector: Jaeger, Grafana Tempo, Arize Phoenix or the OpenTelemetry Collector.
It is off until you name an endpoint, because a span carries the prompt, every tool argument and every tool output. The packages are an optional extra, otel. From a checkout:
uv sync --extra otel
For a tool install, add it to the extras you install with, for example ivralo[pg,otel]. Then set the endpoint in .env:
IVRALO_OTEL_ENDPOINT=http://localhost:4318
IVRALO_OTEL_SERVICE=ivralo
| Variable | Default | Meaning |
|---|---|---|
IVRALO_OTEL_ENDPOINT | unset | The collector. /v1/traces is added when the URL has no path. Unset, nothing is exported. |
IVRALO_OTEL_SERVICE | ivralo | The service name on the spans |
An endpoint set without the extra installed is a warning at startup and a finding in ivralo doctor, never a crash: the run goes on untraced.