Attribute schema
Every attribute key on a Swirls span. Its type, the span it lives on, whether it is identity or content, and what content policy governs it.
What it is. The complete dictionary of attribute keys Swirls sets on a run's spans. Each key is listed with its type, the span it appears on, its category, and a description. Read alongside the Span spec, which defines the spans these attributes live on.
There are two namespaces.
swirls.*for Swirls primitives: executions, nodes, agents, sandboxes, and run identity.gen_ai.*from the OpenTelemetry GenAI semantic conventions, used as-is so an exported trace renders in Datadog, Tempo, or Honeycomb without translation.
Categories
Every attribute falls into one of four categories. The category tells you whether a key is always present and whether a content policy governs it.
| Category | Always present | Description |
|---|---|---|
| Identity | Yes | Ties a span to a tenant, project, and run. Never redacted, so a trace stays navigable. |
| Structure | Yes | Names, kinds, status, and configuration. The shape and outcome of the run. |
| Metric | When reported | Token counts. The numbers cost and usage roll up from. |
| Content | Policy-gated | Run I/O: inputs, outputs, prompts, completions, messages, command text. Governed by the project content policy (full, redacted, off). See Content policy. |
Content keys are the ones a content policy governs. Under redacted only the shape survives; under off the key is never set. Identity, Structure, and Metric attributes are unaffected by the policy.
Identity (swirls.*)
Stamped onto every span in a run from the active scope, so the whole trace tree routes to one project and execution. See Identity and scope.
| Key | Type | Category | Description |
|---|---|---|---|
swirls.org.id | string | Identity | The organization that owns the run. |
swirls.project.id | string | Identity | The project. The key the trace store routes and filters on. |
swirls.deployment.id | string | Identity | The deployment the run came from. |
swirls.workflow.id | string | Identity | The workflow definition. |
swirls.execution.id | string | Identity | The single run. |
swirls.span.kind | string | Structure | Structural classification: workflow, agent, llm, tool, or internal. Stamped from the span name. |
Workflow run (swirls.*)
On the swirls.graph.execution root and its node spans, set by the executor.
| Key | Type | Category | Span | Description |
|---|---|---|---|---|
swirls.workflow.label | string | Structure | graph, node | Human-readable workflow name. |
swirls.execution.status | string | Structure | graph (or root agent turn) | Run outcome: completed or failed. One per trace. |
swirls.parent.execution.id | string | Identity | graph, node | The calling execution, when this run is a nested workflow. |
swirls.trigger.type | string | Structure | graph, node | What started the run (for example webhook, schedule, manual). |
swirls.trigger.id | string | Identity | graph, node | The specific trigger instance. |
swirls.child.execution.id | string | Identity | swirls.workflow.invoke | Links to the root span of a nested workflow's own trace. |
Node (swirls.*)
On the swirls.node.execution span, set by the executor.
| Key | Type | Category | Description |
|---|---|---|---|
swirls.node.id | string | Structure | The node's id within the workflow. |
swirls.node.name | string | Structure | The node's name. |
swirls.node.input | JSON string | Content | The node's input payload. |
swirls.node.output | JSON string | Content | The node's output payload. |
swirls.node.meta | JSON string | Content | Operation metadata the node returned (HTTP status, scrape credits, parallel counts, and similar). |
swirls.ai.prompt | JSON string | Content | The prompt an ai node sent to the model, separable from node input. |
swirls.ai.response | JSON string | Content | The response an ai node received, separable from node output. |
swirls.agent.messages | JSON string | Content | The accumulated transcript of an agent node, stamped when the node ends. |
Agent turn (swirls.*)
On the gen_ai.invoke_agent span, set by the agent host. The content keys are captured only when a content policy is resolved (the chat and API paths); the executor agent-node path captures the transcript through swirls.agent.messages instead.
| Key | Type | Category | Description |
|---|---|---|---|
swirls.session.id | string | Identity | The session for a chat or API agent call. |
swirls.sandbox.key | string | Identity | The sandbox backing the turn. |
swirls.agent.disk.gib | number | Structure | Configured disk allocation, in GiB. |
swirls.agent.max_steps | number | Structure | Configured maximum tool-loop iterations. |
swirls.agent.output_mode | string | Structure | How the turn produces output: text, object, or submit_tool. |
swirls.agent.tool_names | string[] | Structure | The tools made available to the turn. |
swirls.agent.prior_message_count | number | Structure | Length of the message history fed into the turn. |
swirls.agent.step_count | number | Structure | Tool-loop steps actually run. |
swirls.agent.tool_call_count | number | Structure | Total tool calls the model made across the turn. |
swirls.agent.structured_output.repair_count | number | Structure | Times structured output was repaired before validating. |
swirls.agent.user_message | JSON string | Content | The user message that drove the turn. |
swirls.agent.response_message | JSON string | Content | The final agent response. |
swirls.llm.system_prompt | JSON string | Content | The system prompt sent to the model. |
swirls.llm.input_messages | JSON string | Content | The full transcript sent to the model (prior turns plus this message). |
swirls.llm.output_messages | JSON string | Content | The full response transcript from the model. |
swirls.llm.tool_calls | JSON string | Content | Valid tool calls the model made. |
swirls.llm.invalid_tool_calls | JSON string | Content | Malformed or non-existent tool calls the model attempted. |
swirls.llm.tools | JSON string | Content | The tool definitions made available to the model. |
Sandbox and tools (swirls.*)
On the swirls.sandbox.exec span, set by the agent host.
| Key | Type | Category | Description |
|---|---|---|---|
swirls.sandbox.program | string | Structure | The program or command name run in the sandbox. |
swirls.sandbox.exit_code | number | Structure | The process exit code. |
swirls.tool.name | string | Structure | The tool a span executed. |
swirls.sandbox.command | JSON string | Content | The full command text with arguments. Can carry secrets, so it is policy-gated. |
Sentinel (swirls.*)
| Key | Type | Category | Description |
|---|---|---|---|
swirls.trace.complete | boolean | Structure | Set to true on the per-trace completion sentinel span. Marks the trace tree finished. |
GenAI semantic conventions (gen_ai.*)
OpenTelemetry GenAI keys, set on agent turn, model call, and tool spans. Token usage is the headline cost metric and is stamped wherever a provider reports it.
| Key | Type | Category | Description |
|---|---|---|---|
gen_ai.operation.name | string | Structure | Operation: create_agent, invoke_agent, chat, or execute_tool. |
gen_ai.agent.name | string | Structure | The agent's display name. |
gen_ai.system | string | Structure | The model provider (for example anthropic, openai). |
gen_ai.request.model | string | Structure | The model id sent in the request. |
gen_ai.response.model | string | Structure | The model id that answered, which can differ when routed. |
gen_ai.response.finish_reasons | string[] | Structure | Why the model stopped (for example stop, length, tool_call). |
gen_ai.tool.name | string | Structure | The tool name on a tool-call span. |
gen_ai.tool.call.id | string | Structure | The unique id of a tool invocation. |
gen_ai.usage.input_tokens | number | Metric | Prompt tokens consumed. |
gen_ai.usage.output_tokens | number | Metric | Completion tokens generated. |
gen_ai.usage.total_tokens | number | Metric | Input plus output tokens. |
gen_ai.usage.reasoning_tokens | number | Metric | Extended-thinking tokens, where the provider reports them. |
gen_ai.usage.cached_input_tokens | number | Metric | Prompt tokens read from the provider's prompt cache. |
gen_ai.usage.cache_creation_input_tokens | number | Metric | Prompt tokens written to the provider's prompt cache. |
gen_ai.input.messages | JSON string | Content | Messages sent to the model. Emitted by the AI SDK on per-call spans. See note below. |
gen_ai.output.messages | JSON string | Content | Messages returned by the model. Emitted by the AI SDK on per-call spans. See note below. |
gen_ai.input.messages and gen_ai.output.messages are emitted by the AI SDK on its per-call model spans and ride a default-off path that the collector strips, so they do not persist. Durable, policy-gated message capture happens on the owning agent turn span through swirls.llm.input_messages and swirls.llm.output_messages.
Reserved keys
These keys are defined in the schema but are not currently emitted onto customer-facing spans. They are reserved so that adding them later is one change, not a rename. Do not depend on them in queries or exports yet.
| Key | Intended use |
|---|---|
swirls.node.type | The node's type (for example agent, http, code). |
swirls.sandbox.id | A stable sandbox identifier, distinct from the per-turn swirls.sandbox.key. |
swirls.agent.wallet.reserved_cents | Reserved token budget for an agent turn, in cents. |
swirls.agent.wallet.settled_cents | Settled token spend for an agent turn, in cents. |
swirls.agent.wallet.window_key | The billing window an agent turn settled against. |
swirls.agent.zero_run_id | Correlation id for the agent run. |
swirls.agent.disk.external_id | The external volume id for an agent's disk. |
Redaction on export
When you export traces to a destination set to redacted, the Content keys above are stripped from the exported spans while Identity, Structure, and Metric keys are kept, so the exported trace stays navigable. The export denylist and the capture gate are kept together in the codebase, so a new content attribute is redacted on export by the same change that adds it.