Skip to main content

Activity

What the agents in a project actually did, newest first.

Overview​

One entry per autonomous act: a tool call that executed, an approval someone resolved, an exception that was filed, a schedule that fired. Each carries a one-line summary you can read at a glance and a detail object with the structured context behind it.

The feed is read-only and append-only — entries are written by the runtime, never by a caller — and it is paged with an opaque cursor rather than an offset, because a fast-moving feed shifts under offset pages.

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 → Activity.

Data Model​

ActivityEntry​

FieldTypeDescription
idstringPublic entry ID (acte_ prefix).
project_idstringThe owning project.
kindstringaction_executed, approval_created, approval_resolved, exception_created, schedule_fired or tool_resolution_failed.
severitystringinfo, warning or critical.
summarystringOne-line, human-readable description.
detailobject, nullableKind-specific context — the tool, the node, the generation, the guardrail version.
orchestration_run_idstring, nullableThe orchestration run this happened in, if any.
agent_idstring, nullableThe agent involved, if any.
generation_idstring, nullableThe generation the entry was produced during, if any.
ref_idstring, nullableThe producing record — the approval, exception or trigger firing the entry came from, or the executed tool.
created_atstring (date-time)

Key Concepts​

Three surfaces record "what happened"​

They are easy to confuse, and each answers a different question:

SurfaceQuestionSubject
Activity (this module)What did the agents do?the agent or orchestration run
Audit logWho asked the platform for what, and was it allowed?the credential behind a request
TracesHow did one generation execute, step by step?a single generation

Neither of the first two is a subset of the other, and one tool call can appear in both. A call a guardrail blocked leaves an audit record and no action_executed entry — nothing executed. A call that ran leaves an action_executed entry here, while the audit log separately records the request that set it off.

The sharpest difference is the classifier: kind here is one of six fixed values and never a permission string, while the audit log's action is the permission string that authorized the request. This feed records what happened; the audit log records decisions, including refusals.

Severity is not a restatement of kind​

Severity defaults per kind — info for the routine ones, warning for exception_created and tool_resolution_failed — but an exception_created entry inherits the filed exception's own severity, so it spans all three values. That is the only path that writes critical, which makes severity=critical a filter worth having: it surfaces the entries a kind filter cannot express.

A dropped tool binding is recorded here​

When a tool binding contributes no tool to a turn, the runtime leaves it out and runs the turn anyway — one unreachable server must not take an agent down. The generation then completes carrying no error, over a trace with no children, having answered without a capability it was configured to have. A tool_resolution_failed entry, severity warning, is the only record that anything was missing.

It covers both halves of "contributed nothing": a binding that produced no listing at all — the server unreachable or refusing the credential, or an unresolvable {{secret:…}} in its URL or headers — and a listing that was read and left nothing to attach. Only an mcp tool can fail this way; the other types need no network to resolve, and one whose endpoint is down fails when the model calls it instead.

detail names the binding and the turn:

KeyDescription
tool_idThe tool, null for a binding defined inline on the agent. Repeated on ref_id.
tool_typeThe binding's type.
tool_nameIts name, as summary reads it.
reasonWhy nothing attached — tools/list answered 401, tools/list returned no tools, an unresolved secret reference.

agent_id is the agent whose turn it was, generation_id the turn itself, and orchestration_run_id the run it happened inside, if any — all three are fields on the entry rather than detail keys, which is what makes them filterable.

Filters compose​

kind, severity, agent_id, generation_id and orchestration_run_id are all composable, and an entry carries at most one of each subject, so naming two narrows to the rows where both hold.

generation_id is what turns this feed from alertable into usable during an incident: given a generation that answered oddly, one query returns everything that turn did — including whether a binding was dropped.

Cursor pagination​

GET /v1/projects/{project_id}/activity returns next_cursor; pass it back as cursor for the next page, and a null next_cursor means you have reached the end. The cursor encodes a position, not an offset, so a page does not shift as new entries land ahead of it.

The feed is also a guardrail input​

A guardrail can read a rolling rate of tool calls — runtime.projects.tool_calls.1h, runtime.agents.tool_calls.24h, runtime.tools.tool_calls.7d — so "an agent that has done an unusual amount in the last hour" is expressible as a gate rather than only as something to notice afterwards. This feed is where you read what those calls did.

Retention​

Entries are kept indefinitely. There is no delete endpoint and no sweep, so the feed grows with autonomous execution volume.

Examples​

Read what happened, newest first​

naturali list-activity \
--project-id proj_V1StGXR8Z5jdHi6B \
--limit 20

Surface only what went wrong​

naturali list-activity \
--project-id proj_V1StGXR8Z5jdHi6B \
--severity critical

Alert on a tool binding that did not resolve​

Nothing else reports this: poll or alert on the kind itself.

naturali list-activity \
--project-id proj_V1StGXR8Z5jdHi6B \
--kind tool_resolution_failed

An entry means a generation ran with fewer tools than its agent declares; detail.generation_id is the one to look at and detail.reason is what to fix. An empty page over a window means every binding attached.

Read everything one generation did​

Given a generation that answered oddly, this is the query that says whether it ran with every tool it was meant to have.

naturali list-activity \
--project-id proj_V1StGXR8Z5jdHi6B \
--generation-id gen_V1StGXR8Z5jdHi6B

Page through with the cursor​

naturali list-activity \
--project-id proj_V1StGXR8Z5jdHi6B \
--cursor eyJjcmVhdGVkX2F0IjoiMjAyNi0wOC0yMSJ9