Observability

Data Model and Schema

Reference for observability sessions, traces, spans, attributes, status, tokens, and cost.

ArmorIQ stores observability as sessions containing traces, with spans forming a parent-child tree inside each trace.

Session
└── Trace
    ├── span
    ├── policy_call
    ├── generation
    └── event

All IDs used for a trace, span, parent span, session, or user must be UUIDs when present. agentId is a free-form string.

Session

A session groups a continuous agent run or conversation. The backend creates or updates the session when it ingests a trace with a session ID.

FieldTypeMeaning
idUUIDStable session identifier
orgIdUUIDOrganization resolved from the API key
userIdUUID or nullUser identity when the producer has a UUID
agentIdstring or nullAgent identifier; not restricted to UUID format
productstring or nullProducer identity, such as armoriq-sdk, armorcodex, or armorclaude
startedAtISO 8601 datetimeEarliest trace start recorded for the session
lastActivityAtISO 8601 datetimeLatest trace activity recorded for the session
traceCountintegerNumber of accepted traces in the session
totalInputTokensintegerSum from accepted generation spans
totalOutputTokensintegerSum from accepted generation spans
totalCacheReadTokensintegerSum of reported cache-read tokens
totalCacheWriteTokensintegerSum of reported cache-write tokens
totalCostUsdnumberSum of reported or SDK-estimated generation cost
statusstringCurrent session status; current values are active, completed, expired, and error

The ingest path currently creates sessions with active status. Status changes require another backend lifecycle path; do not infer completion solely from the absence of new traces.

Trace

A trace is the top-level record for one IAP plan or logical operation.

FieldTypeRequiredMeaning
idUUIDYesTrace identifier and duplicate-ingest key
sessionIdUUID or nullNoParent session
namestring, 1–200 charsYesOperation name, commonly iap.plan
startTimeISO 8601 datetimeYesTrace start
endTimeISO 8601 datetime or nullNoTrace end
durationMsnon-negative integer or nullNoTotal trace duration
statusok, error, or deniedYesTerminal trace status
userIdUUID or nullNoUser identity
agentIdstring or nullNoAgent identity
attributesobjectYesProducer-defined trace metadata
tagsstring arrayYesSearch and summary labels

The backend adds product and source to trace-detail responses. Trace-list and session-detail responses also add token totals, cost, span count, error count, and input/output previews.

Span

A span is one observation inside a trace.

FieldTypeRequiredMeaning
idUUIDYesSpan identifier
parentSpanIdUUID or nullNoParent span; null means a root-level span
sessionIdUUID or nullNoDenormalized session identifier
kindspan kindYesSelects the attribute schema
namestring, 1–200 charsYesOperation name
startTimeISO 8601 datetimeYesSpan start
endTimeISO 8601 datetime or nullNoSpan end
durationMsnon-negative integer or nullNoSpan duration
statusok, error, or deniedYesSpan status
attributesobjectYesKind-specific attributes

Spans are returned as a flat list. Build the tree by matching each parentSpanId to another span's id. A missing or null parent is a root.

Span kinds and attributes

Attribute objects include a kind field matching the span's kind. Producers may add extra attributes; the backend preserves them.

span

Generic operation, commonly a tool call, report, dispatch, delegation, or container operation.

AttributeType
kindspan
toolNameoptional string
toolInputoptional JSON value
toolOutputoptional JSON value
errorMessageoptional string

Some producer-created generic spans use additional keys such as input, output, status, trustId, or fired.

policy_call

Policy evaluation and its enforcement result.

AttributeType
kindpolicy_call
policyIdstring or null
policyNamestring or null
policyHashstring or null
policyVersionstring or null
decisionallow, deny, hold, or ask
matchedRuleIdstring or null
dataClassesstring array
reasonstring or null
inputJSON value
outputJSON value
sourcenative, sdk-local, sdk, proxy, opa, or opa_fallback
enforcementActionallow, allow_log, hold, block, or null
obligationsJSON value
delegationIdstring or null

decision describes the policy result. enforcementAction describes what the integration did with that result.

SDK recorders map allow to span status ok. They map deny, hold, and ask to span status denied.

generation

Model call and token usage.

AttributeType
kindgeneration
modelstring
inputTokensnon-negative integer
outputTokensnon-negative integer
cacheReadTokensnon-negative integer or null
cacheWriteTokensnon-negative integer or null
costUsdnon-negative number
promptstring or null
completionstring or null
finishReasonstring or null

event

Point-in-time annotation.

AttributeType
kindevent
messagestring
levelinfo, warn, or error

An event's level is the event severity. Current SDK recorders keep the event span's lifecycle status as ok, including for level: "error"; use the attributes and surrounding trace status when interpreting an error event.

Example trace

{
  "id": "11111111-1111-4111-8111-111111111111",
  "sessionId": "22222222-2222-4222-8222-222222222222",
  "name": "iap.plan",
  "startTime": "2026-07-17T09:00:00.000Z",
  "endTime": "2026-07-17T09:00:00.240Z",
  "durationMs": 240,
  "status": "ok",
  "userId": null,
  "agentId": "support-agent",
  "attributes": {
    "input": "Find the account owner"
  },
  "tags": ["armoriq-sdk", "search_contacts", "allowed"],
  "spans": [
    {
      "id": "33333333-3333-4333-8333-333333333333",
      "parentSpanId": null,
      "sessionId": "22222222-2222-4222-8222-222222222222",
      "kind": "policy_call",
      "name": "policy.evaluate",
      "startTime": "2026-07-17T09:00:00.010Z",
      "endTime": "2026-07-17T09:00:00.030Z",
      "durationMs": 20,
      "status": "ok",
      "attributes": {
        "kind": "policy_call",
        "policyId": "contacts-read",
        "policyName": "Contacts read policy",
        "policyHash": null,
        "policyVersion": null,
        "decision": "allow",
        "matchedRuleId": "allow-support",
        "dataClasses": [],
        "reason": "Support agents may read contacts",
        "input": { "toolName": "search_contacts" },
        "output": null,
        "source": "sdk",
        "enforcementAction": "allow",
        "obligations": null,
        "delegationId": null
      }
    }
  ]
}

Tags and previews

SDK trace summaries can derive tags from the product, tool names, and the policy outcome, such as allowed, blocked, or mixed. Tags are producer-supplied and are not guaranteed on every trace.

Trace-list previews prefer trace.attributes.input and trace.attributes.output. If those are absent, the backend falls back to input/output on a root span when available.

Token and cost behavior

  • Session totals, trace-list totals, summary metrics, and model- or session-grouped token analytics aggregate generation spans. The groupBy=tool endpoint instead scans generic span records and sums token-shaped attributes when a producer supplies them.
  • The TypeScript and Python SDKs can calculate cost from a static per-model table.
  • Cost is best-effort and is not billing-grade.
  • An unknown model currently produces costUsd: 0. Treat that as pricing unavailable unless you know the provider reported a measured zero cost.
  • A missing generation span means usage was not reported. Current backend aggregate fields are initialized to zero, so list and dashboard views cannot always distinguish this case from measured zero; inspect the raw trace for a generation span.
  • Backend aggregations scan at most 50,000 rows. Results at the cap are approximate and produce a server warning.

Sensitive content

toolInput, toolOutput, policy input and output, prompt, and completion can contain sensitive information. The shared SDK recorders do not automatically redact arbitrary values. Record only what you need, omit prompt/completion content when possible, and restrict access to organization-scoped read APIs.

Next: call the backend API or inspect spans in the dashboard.

On this page