# @recursive/sdk
TypeScript SDK for the [Recursive Agent](https://github.com/recursive-agent/recursive).
API-compatible with the Claude Agent SDK / Cursor SDK patterns.
## Install
```bash
npm install @recursive/sdk
# or
pnpm add @recursive/sdk
# or
yarn add @recursive/sdk
```
## Prerequisites
Start the Recursive server:
```bash
recursive loop --http 3000
```
Set environment (if auth is enabled):
```bash
export RECURSIVE_API_KEY=your-key
export RECURSIVE_BASE_URL=http://localhost:3000 # optional
```
## Usage
### One-shot (`Agent.prompt`)
```typescript
import { Agent } from "@recursive/sdk";
const result = await Agent.prompt(
"List all TODO comments across the codebase",
{ baseUrl: "http://localhost:3000" },
);
if (result.ok) {
console.log("Success!");
}
```
### Multi-turn with streaming (`Agent.create` + `agent.send`)
```typescript
import { Agent } from "@recursive/sdk";
// `await using` auto-disposes on block exit (TypeScript 5.2+)
await using agent = await Agent.create({
baseUrl: "http://localhost:3000",
});
// First turn — stream tokens as they arrive
const run = await agent.send("Fix all failing tests in the project");
for await (const msg of run.stream()) {
if (msg.type === "assistant") {
for (const block of msg.content) {
if (block.type === "text") process.stdout.write(block.text);
}
}
}
const result = await run.wait();
console.log(`\n[${result.status}]`);
// Follow-up — same conversation context
const run2 = await agent.send("Now update CHANGELOG.md");
await run2.wait();
```
### Resume an existing session (`Agent.resume`)
```typescript
import { Agent } from "@recursive/sdk";
await using agent = await Agent.resume(sessionId, {
baseUrl: "http://localhost:3000",
});
const run = await agent.send("Continue where we left off");
await run.wait();
```
### Error handling
```typescript
import { Agent, RecursiveAgentError } from "@recursive/sdk";
try {
await using agent = await Agent.create({ baseUrl: "http://localhost:3000" });
const run = await agent.send("do something");
const result = await run.wait();
if (result.status === "error") {
// Agent ran but hit an error
console.error("Run failed:", result.error);
process.exit(2);
}
} catch (err) {
if (err instanceof RecursiveAgentError) {
// Couldn't connect / auth failed
console.error("Startup failed:", err.message, "retryable:", err.isRetryable);
process.exit(1);
}
throw err;
}
```
## API Reference
### `Agent` (static factory)
| `Agent.prompt(message, options?)` | One-shot run |
| `Agent.create(options?)` | Create a new session |
| `Agent.resume(sessionId, options?)` | Resume existing session |
| `Agent.listSessions(options?)` | List active sessions |
| `Agent.deleteSession(sessionId, options?)` | Delete a session |
### `AgentSession`
| `agent.send(message)` | Send a message, returns `Promise<Run>` |
| `agent.close()` | Close the session |
| `agent[Symbol.asyncDispose]()` | Used by `await using` |
### `Run`
| `run.stream()` | `AsyncGenerator<SDKMessage>` |
| `run.messages()` | Alias for `stream()` |
| `run.iterText()` | `AsyncGenerator<string>` — text chunks only |
| `run.text()` | `Promise<string>` — all text concatenated |
| `run.wait()` | `Promise<RunResult>` |
| `run.supports(op)` | Check if operation is available |
### `AgentOptions`
```typescript
interface AgentOptions {
baseUrl?: string; // default: RECURSIVE_BASE_URL or http://127.0.0.1:3000
apiKey?: string; // default: RECURSIVE_API_KEY env var
timeout?: number; // ms
systemPrompt?: string;
}
```
### Message types
```typescript
interface AssistantMessage {
type: "assistant";
content: ContentBlock[]; // TextContent | ToolUseBlock | ToolResultBlock
sessionId: string;
}
interface UserMessage {
type: "user";
content: string;
sessionId: string;
}
```
## Environment variables
| `RECURSIVE_BASE_URL` | `http://127.0.0.1:3000` | Server URL |
| `RECURSIVE_API_KEY` | _(none)_ | API key for authenticated servers |