Traces
The execution record of a run — one node per agent session, nested by sub-agent call, and the control that erases its content.
Overview
A trace is created for you whenever an agent runs. One trace
covers one agent's execution session; when that agent calls another agent as a
tool, the callee gets its own trace with parent_trace_id pointing back, so a
multi-agent run is a tree rather than a flat log. Every
generation carries the trace_id it belongs to.
Two reads and one erasure, which is the whole surface: list or get a trace, fetch the tree rooted above it (optionally with each node's generations embedded), and purge a run's content while leaving its audit skeleton behind.
This module is a verbatim mirror of the runtime: every field, method, status code and error shape is the runtime's own, re-rooted under the project in the path.
See the OpenAPI spec for the full endpoint and schema reference, or browse it rendered under API Reference → Traces.
Data Model
Trace
| Field | Type | Description |
|---|---|---|
id | string | Public trace ID (trace_ prefix). |
project_id | string | The owning project. |
agent_id | string | The agent whose session this trace records. |
file_id | string, nullable | The stored file holding the serialized steps — null until the trace is saved (saving is fire-and-forget). |
step_count | integer | Steps recorded in this trace. |
parent_trace_id | string, nullable | The trace whose sub-agent call started this one; null on a root. |
root_trace_id | string, nullable | The root of the whole tree; null when this trace is itself the root. |
error | object, nullable | Structured payload recorded when a generation in this trace failed (code, message, meta). |
content_redacted_at | string (date-time), nullable | Non-null once the content was purged — see Purging a run's content. |
content_redacted_by_principal_type | string, nullable | user or api_key. |
content_redacted_by_principal_id | string, nullable | Which principal purged it — for key auth, the API key's own id. |
created_at | string (date-time) |
TraceTreeNode
The tree response is a Trace plus two extras:
| Field | Type | Description |
|---|---|---|
children | array of TraceTreeNode | Traces triggered by sub-agent calls from this node. |
generations | array of Generation | The node's generations. Present only with include=generations. |
Key Concepts
Reading a multi-agent run
GET /v1/projects/{project_id}/traces/{trace_id}/tree
takes any trace in a tree — root or child — resolves the root, and returns
the whole tree from there. So "show me this run" needs one call and the id you
happen to be holding, not a walk up parent_trace_id.
Debug a failed run
starts there when a sub-agent stops on an error.
Add include=generations to embed each node's generations, including the
sub-agent generations linked through initiator_generation_id. That is the
cheapest way to get from "which agent did what" to "what did it actually say":
each embedded generation's id is what
GET /v1/projects/{project_id}/generations/{generation_id}/transcript
reads step by step.
Purging a run's content
DELETE /v1/projects/{project_id}/traces/{trace_id}/content
deletes the steps object and clears the content fields, cascading to every
descendant trace and to all of their generations. The cascade is the point: a
descendant holds its own steps object covering the same run, so erasing only the
trace you asked about would leave the content readable one level down.
What survives is an auditable skeleton — ids, timestamps, step counts, and the
generations' usage attribution — stamped with content_redacted_at and the
principal that acted. A purged trace therefore reads back as a skeleton rather
than a 404: the erasure is provable, which a missing row would not be. The
call is idempotent, and it keeps the original content_redacted_at on a second
purge.
Two related controls live on the project: a retention window
purges content past it on a daily sweep, and trace_content_mode: none — also
settable per agent — never writes content
at all, which is the stronger guarantee.
Run a zero-retention agent
reads back the skeleton such a run leaves.
Who may do what
Every route needs any project member.
file_id names the stored file holding the serialized steps, so
GET /v1/projects/{project_id}/files/{file_id}/download
will fetch it. It is the raw serialization, not a documented format — read a run
through the tree and each generation's transcript when you want the contract, and
reach for the object only when you need what it happens to contain.
Examples
List the project's traces
- CLI
- SDK
- curl
naturali list-traces \
--project-id proj_V1StGXR8Z5jdHi6B \
--limit 20
const { data: traces } = await naturali.traces.listTraces({
path: { project_id: 'proj_V1StGXR8Z5jdHi6B' },
query: { limit: 20 },
});
curl "https://api.naturali.ai/v1/projects/proj_V1StGXR8Z5jdHi6B/traces?limit=20" \
-H "Authorization: Bearer $NATURALI_TOKEN"
Get one trace
- CLI
- SDK
- curl
naturali get-trace \
--project-id proj_V1StGXR8Z5jdHi6B \
--trace-id trace_V1StGXR8Z5jdHi6B
const { data: trace } = await naturali.traces.getTrace({
path: {
project_id: 'proj_V1StGXR8Z5jdHi6B',
trace_id: 'trace_V1StGXR8Z5jdHi6B',
},
});
curl https://api.naturali.ai/v1/projects/proj_V1StGXR8Z5jdHi6B/traces/trace_V1StGXR8Z5jdHi6B \
-H "Authorization: Bearer $NATURALI_TOKEN"
Read a whole run, generations included
- CLI
- SDK
- curl
naturali get-trace-tree \
--project-id proj_V1StGXR8Z5jdHi6B \
--trace-id trace_V1StGXR8Z5jdHi6B \
--include generations
const { data: tree } = await naturali.traces.getTraceTree({
path: {
project_id: 'proj_V1StGXR8Z5jdHi6B',
trace_id: 'trace_V1StGXR8Z5jdHi6B',
},
query: { include: 'generations' },
});
for (const child of tree?.children ?? []) {
console.log(child.agent_id, child.generations?.length);
}
curl "https://api.naturali.ai/v1/projects/proj_V1StGXR8Z5jdHi6B/traces/trace_V1StGXR8Z5jdHi6B/tree?include=generations" \
-H "Authorization: Bearer $NATURALI_TOKEN"
Purge a run's content
- CLI
- SDK
- curl
naturali purge-trace-content \
--project-id proj_V1StGXR8Z5jdHi6B \
--trace-id trace_V1StGXR8Z5jdHi6B
const { data: skeleton } = await naturali.traces.purgeTraceContent({
path: {
project_id: 'proj_V1StGXR8Z5jdHi6B',
trace_id: 'trace_V1StGXR8Z5jdHi6B',
},
});
console.log(skeleton?.content_redacted_at);
curl -X DELETE https://api.naturali.ai/v1/projects/proj_V1StGXR8Z5jdHi6B/traces/trace_V1StGXR8Z5jdHi6B/content \
-H "Authorization: Bearer $NATURALI_TOKEN"