> ## Documentation Index
> Fetch the complete documentation index at: https://docs.armature.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# What the SDK captures

> Telemetry fields, session reconstruction, and exactly what leaves your server

All three SDKs share one wire format, so sessions land in the same dashboard whether your server is TypeScript, Python, or Go.

## Telemetry fields

The SDK adds four optional fields to each instrumented tool's input schema. The calling agent fills them in as it works; the SDK strips them out **before your handler runs**, so your business logic never sees them:

| Field              | Type                        | What the agent reports                                                               |
| ------------------ | --------------------------- | ------------------------------------------------------------------------------------ |
| `user_intent`      | string                      | What the user asked for, in their words. Powers [Use cases](/dashboard/use-cases).   |
| `agent_thinking`   | string                      | The agent's reasoning for this call. Shown in [session replay](/dashboard/sessions). |
| `user_turn`        | integer                     | Which user message (1-based) this call serves. Orders the conversation view.         |
| `user_frustration` | `low` \| `medium` \| `high` | The agent's read of user frustration.                                                |

All fields are optional — agents that ignore them still produce complete sessions with tool calls, timing, and outcomes. Older field spellings (`intent`, `context`, `frustration_level`) are accepted and normalized, so agents with cached schemas keep working.

<Info>
  This is why instrumented sessions show *what the user asked* and *what the agent was thinking* — not just a list of tool calls. The description hint the SDK appends to each tool tells agents how to fill the fields.
</Info>

## Events

The SDK emits two event kinds:

**`session_init`** — once per session: client name and version (Claude, ChatGPT, Cursor, …), protocol version, and capabilities.

**`tool_call`** — one per tool invocation:

* Tool name, start/finish timestamps, duration
* Outcome (`ok` or the error), including MCP results returned with `isError: true`
* Telemetry fields reported by the agent
* A truncated input preview and result preview

## Size limits

Payloads are truncated UTF-8-safely before they leave your process:

| Payload                 | Limit      |
| ----------------------- | ---------- |
| Input / result previews | 8 KiB each |
| Script source           | 32 KiB     |
| Client capabilities     | 4 KiB      |

## Sessions and actors

* **Session identity** comes from the MCP session: HTTP servers use the `Mcp-Session-Id` header; stdio servers get a process-scoped session ID, so each CLI conversation is its own session. Stateless HTTP servers need [one extra helper](/sdks/stateless-servers).
* **Actor identity** is a SHA-256 hash of a seed derived from the request's auth (token, client ID, or `Authorization` header), falling back to `anonymous`. The raw seed never leaves your server — see [Identifying users](/sdks/identifying-users).

## Delivery guarantees

* Events post to Armature's ingest API over HTTPS, authenticated with your ingest key.
* Delivery runs off the request path by default (`background` mode) and never throws into your tools — failures go to your `onError` hook.
* If no ingest key is configured, the SDK no-ops: schemas are still decorated, but nothing is sent.

<Note>
  The agent-facing schema hint instructs agents not to put secrets or PII in telemetry fields, and Armature [scans and redacts](/security/privacy) incoming sessions before storage.
</Note>
