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

# Cursor Agent SDK (Beta)

> Automatic tracking for the Cursor Agent SDK. Wrap the SDK once to capture agent events and traces with per-context identity and routing metadata.

The `@raindrop-ai/cursor-agent-sdk` package automatically instruments the
[Cursor Agent SDK](https://cursor.com/docs/cli/sdk) to capture events and traces from agent runs.
It wraps the SDK's `Agent.prompt`, `Agent.create`, `Agent.resume`, and
`SDKAgent.send` APIs while preserving Cursor's return values, streams, and
errors.

**Features:**

* No OpenTelemetry setup required
* Automatic event and trace capture for agent runs
* Thinking and tool-call child spans
* Token usage, model, output, status, and error capture
* Support for `Run.stream()`, `Run.wait()`, and `Run.conversation()`
* Per-context identity and routing metadata

## Installation

<CodeGroup>
  ```bash npm theme={null}
  npm install @raindrop-ai/cursor-agent-sdk @cursor/sdk
  ```

  ```bash yarn theme={null}
  yarn add @raindrop-ai/cursor-agent-sdk @cursor/sdk
  ```

  ```bash pnpm theme={null}
  pnpm add @raindrop-ai/cursor-agent-sdk @cursor/sdk
  ```

  ```bash bun theme={null}
  bun add @raindrop-ai/cursor-agent-sdk @cursor/sdk
  ```
</CodeGroup>

## Quick Start

```typescript theme={null}
import * as cursor from "@cursor/sdk";
import { createRaindropCursorAgentSDK, eventMetadata } from "@raindrop-ai/cursor-agent-sdk";

const raindrop = createRaindropCursorAgentSDK({
  writeKey: process.env.RAINDROP_WRITE_KEY,
});

const wrapped = raindrop.wrap(cursor, {
  context: eventMetadata({
    userId: "user-123",
    eventName: "cursor_agent_run",
    convoId: "conversation-1",
  }),
});

const agent = await wrapped.Agent.create({
  model: { id: "composer-1" },
});
const run = await agent.send("Summarize the repository");

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

await raindrop.flush();
```

The wrapper also supports direct prompts:

```typescript theme={null}
const result = await wrapped.Agent.prompt("Summarize the repository");
console.log(result);
```

`Agent.create()` and `Agent.resume()` return wrapped agents whose `send()`
method returns a wrapped run. Consume that run with `stream()`, `wait()`, or
`conversation()`. Each run is finalized once, regardless of which lifecycle
method is used.

## Configuration

```typescript theme={null}
const raindrop = createRaindropCursorAgentSDK({
  writeKey: process.env.RAINDROP_WRITE_KEY, // Optional; disables shipping when absent
  endpoint: "https://api.raindrop.ai/v1", // Optional
  projectId: "support-prod", // Optional project slug
  localWorkshopUrl: false, // Optional local workshop mode
  events: {
    enabled: true,
  },
  traces: {
    enabled: true,
  },
  context: {
    userId: "user-123",
    eventName: "cursor_agent_run",
  },
});
```

When `writeKey` is absent, the wrapper remains usable and does not send
telemetry.

## Per-Run Context

Cursor's method signatures do not provide a trailing metadata argument. Supply
identity and routing metadata through the wrapper context instead:

```typescript theme={null}
const wrapped = raindrop.wrap(cursor, {
  context: eventMetadata({
    userId: "user-456",
    convoId: "conversation-2",
    eventName: "support_agent_run",
    eventId: "event-123",
    properties: { plan: "pro" },
  }),
});
```

Create separate wrapped contexts when concurrent runs need different metadata.

## Events and Traces

Events are enabled by default in the wrapper configuration, and traces include
the run span plus thinking and tool-call child spans. The client also exposes
the event lifecycle methods for partial events:

```typescript theme={null}
const eventId = "event-123";

await raindrop.events.patch(eventId, {
  properties: { source: "cursor" },
});
await raindrop.events.setProperties(eventId, {
  environment: "production",
});
await raindrop.events.addAttachments(eventId, [
  { type: "text/plain", role: "context", value: "run context" },
]);
await raindrop.events.finish(eventId);
```

Use `flush()` to drain queued event and trace delivery, and `shutdown()` to
close the client when the process exits.

## Identifying Users

```typescript theme={null}
await raindrop.users.identify({
  userId: "user-123",
  traits: {
    plan: "pro",
    email: "user@example.com",
  },
});
```

## Signals

```typescript theme={null}
await raindrop.signals.track({
  name: "agent_feedback",
  type: "feedback",
  sentiment: "POSITIVE",
  rating: 5,
});
```

## Flush and Shutdown

Call `flush()` before a short-lived process exits. Call `shutdown()` when the
client will no longer be used:

```typescript theme={null}
await raindrop.flush();
await raindrop.shutdown();
```

## Limitations

* Concurrent runs should use separate wrapped contexts when each run needs
  distinct identity metadata.
* The Cursor SDK requires Node.js `>=22.13`.
* Cloud responses may omit usage, model, or message content; those fields are
  omitted gracefully.
