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

# Cursor SDK Traces

> Trace Cursor agent runs, streamed messages, wait results, and tool calls.

Catalyst instruments the Cursor SDK in TypeScript. Initialize tracing before
calling `Agent.create()` so the `Agent` static methods and the returned
`SDKAgent` / `Run` objects are patched before any run is observed.

Use this guide for Node applications that run programmatic Cursor agents with
`@cursor/sdk`. Cursor publishes a TypeScript SDK only, so there is no Python
equivalent for this integration.

<Info>
  Cursor's SDK streams runs over HTTP/2 via `@connectrpc/connect-node`. Run
  Catalyst-traced Cursor apps under Node (>= 22). Bun's HTTP/2 client currently
  emits `NGHTTP2_FRAME_SIZE_ERROR` mid-stream against `api.cursor.com`.
</Info>

## What Is Captured

* One AGENT span named `Cursor Agent Run` per observed run, started lazily when
  `run.stream()`, `run.wait()`, `run.conversation()`, or `run.cancel()` is first
  called
* `cursor.agent_id`, `cursor.run_id`, `cursor.run_status`, `cursor.duration_ms`,
  request IDs, and model metadata (`llm.model_name`,
  `llm.invocation_parameters`)
* `input.value` from `agent.send()` and `output.value` from streamed assistant
  text, `run.wait()` results, or `run.conversation()` turns
* TOOL child spans for streamed `tool_call` events, including `tool.name`,
  `tool_call.id`, JSON arguments, and tool results
* Aggregate counts: `agent.tool_call_count`, `agent.llm_call_count`
* Error status and exception details when run streaming, waiting, or cancellation
  fails

## Install

<CodeGroup>
  ```bash TypeScript theme={"system"}
  bun add @inference/tracing @cursor/sdk
  ```
</CodeGroup>

## TypeScript Cursor Agent Run

Initialize tracing before creating Cursor agents. Auto-instrumentation detects
`@cursor/sdk` when it is installed in the project, so the smoothest path is just
`setup()`.

<Metadata text="integrations/traces/cursor-sdk-ts" />

```typescript TypeScript theme={"system"}
import { Agent } from "@cursor/sdk";
import { setup } from "@inference/tracing";

const tracing = await setup({
  serviceName: "cursor-agent-runner",
});

const agent = await Agent.create({
  apiKey: process.env.CURSOR_API_KEY!,
  model: { id: "composer-2" },
  local: { cwd: process.cwd() },
});

try {
  const run = await agent.send("Summarize what this repository does");

  for await (const event of run.stream()) {
    console.log(event.type);
  }

  const result = await run.wait();
  console.log(`run ${run.id} ${result.status}`);
} finally {
  await agent[Symbol.asyncDispose]();
  await tracing.shutdown();
}
```

For manual initialization, pass the SDK namespace into the granular entry point:

```typescript TypeScript theme={"system"}
import * as CursorSdk from "@cursor/sdk";
import { setup } from "@inference/tracing";
import { instrumentCursorSdk } from "@inference/tracing/cursor-sdk";

const tracing = await setup({ autoInstrument: false });
instrumentCursorSdk(CursorSdk, tracing);
```

## Lazy Span Lifecycle

The AGENT span starts when the application first observes a run through
`run.stream()`, `run.wait()`, `run.conversation()`, or `run.cancel()`, not when
`agent.send()` returns. This avoids leaking open spans for fire-and-handoff
workflows where one process kicks off a Cursor run and another process observes
it later. Each unique observed run produces one AGENT span; observing the same
run twice in the same process does not double-emit.

## Stable Agent Identity

Cursor's SDK exposes its own run and agent identifiers, which Catalyst preserves
as `cursor.run_id` and `cursor.agent_id`. For the canonical Agents dashboard
grouping key, wrap the Cursor run you operate with `agentSpan()` and pass your
stable product ID as `agentId`.

<Metadata text="integrations/traces/cursor-sdk-agent-identity" />

```typescript TypeScript theme={"system"}
import { agentSpan } from "@inference/tracing";

await agentSpan(
  {
    agentId: "cursor-repo-maintainer",
    agentName: "Cursor Repo Maintainer",
    spanName: "cursor-repo-maintainer.run",
    sessionId: "conversation-repo-tour",
    role: "code-maintenance",
    system: "cursor",
  },
  async (span) => {
    const input = "Summarize what this repository does";
    span.setInput(input);
    const run = await agent.send(input);
    const result = await run.wait();
    span.setOutput(result);
  },
);
```

## Verify In Catalyst

Filter traces by your `service.name` (for example `cursor-agent-runner`). A
successful run should show one `Cursor Agent Run` AGENT span with `cursor.run_id`
and the model name, plus nested TOOL spans for each tool call the agent
produced.

For short-lived scripts, always call `tracing.shutdown()` before process exit so
batched spans are flushed to Catalyst.
