---
title: SDK v0.2 → v0.3
description: Breaking changes in @codespar/sdk@0.3.0 and how to migrate an existing 0.2 codebase. Create / execute / send signatures changed; 2-level tenancy shipped.
---

import { Callout } from "fumadocs-ui/components/callout";

# Migration — SDK v0.2 → v0.3

`@codespar/sdk@0.3.0` is a breaking release aligned end-to-end with the backend's canonical wire contract. Every framework adapter (`@codespar/claude`, `@codespar/openai`, `@codespar/vercel`, etc.) was bumped to `0.3.0` in lockstep. This page walks through each change and shows the before / after for real code.

<Callout type="info">
The 0.2 line stays on npm — your production code will not break until you bump. We recommend upgrading in one PR per service, against sandbox (`csk_test_`) first, then production.
</Callout>

## Summary of breaking changes

| Before (0.2) | After (0.3) |
|---|---|
| `codespar.sessions.create({ servers })` | `codespar.create(userId, { servers })` |
| `session.execute({ name, arguments })` | `session.execute(name, params)` |
| `session.send({ name, arguments })` (fire-and-forget tool call) | `session.send(message)` (natural-language agent loop) |
| `session.sendStream({ name, arguments })` | `session.sendStream(message)` (streams agent events) |
| `session.mcp()` (method) | `session.mcp` (property) |
| No project scoping | `SessionConfig.projectId` + `x-codespar-project` header |
| TypeScript only | Python published on PyPI (`codespar>=0.1.1`) |

Everything else (tool result shapes, `session.tools`, `session.connections`, `session.close`, `session.authorize`, `session.findTools`) is unchanged.

## 1. Session creation takes a `userId` first

The session is now scoped to an end-user. Credentials, audit logs, and billing all attach to that ID.

**Before**

```typescript
const session = await codespar.sessions.create({
  servers: ["stripe", "mercadopago"],
});
```

**After**

```typescript
const session = await codespar.create("user_123", {
  servers: ["stripe", "mercadopago"],
});
```

Pass a real identifier from your own system (Clerk userId, Supabase auth ID, the end-customer's email hash — whatever uniquely maps to the human on whose behalf the agent acts). For server-side jobs, pick a stable synthetic ID like `"cron-worker"` or `"webhook-processor"`.

### Migration strategy

- Search your codebase for `sessions.create(` — replace each call with `codespar.create("user_123", ...)` (use your real user ID).
- Where your backend already has an authenticated user context, pipe it through instead of hardcoding.
- The `user_id` now also flows into tool-call logs and is filterable in the dashboard, which helps for per-user debugging.

## 2. `session.execute` takes two positional args

No more `{ name, arguments }` object.

**Before**

```typescript
const result = await session.execute({
  name: "codespar_pay",
  arguments: {
    method: "pix",
    amount: 15000,
    currency: "BRL",
  },
});
```

**After**

```typescript
const result = await session.execute("codespar_pay", {
  method: "pix",
  amount: 15000,
  currency: "BRL",
});
```

The return shape is unchanged — same `success`, `data`, `error`, `duration`, `server`, `tool`, `tool_call_id`, `called_at`.

### Adapter helpers keep working

`handleToolUse` (Claude), `handleToolCall` (OpenAI), and the framework adapters internally call `session.execute` — they shield you from the signature change. If you only use adapter helpers, no code-level migration is needed beyond bumping package versions.

## 3. `send` / `sendStream` now drive a natural-language agent loop

This is the biggest semantic shift. In 0.2 these were fire-and-forget and streaming variants of `execute` — taking a tool name + arguments. They are **not**.

In 0.3 they take a plain-text message. The backend runs a Claude tool-use loop against the session's connected servers and returns the final response plus every tool call the agent made along the way.

**Before (does not work in 0.3 — throws at compile time)**

```typescript
await session.send({
  name: "codespar_notify",
  arguments: { channel: "whatsapp", to: "+55...", template: "receipt" },
});
```

**After — if you wanted an async tool call**

Use `session.execute` — same effect without the "queued" indirection:

```typescript
await session.execute("codespar_notify", {
  channel: "whatsapp",
  to: "+55...",
  template: "receipt",
});
```

**After — if you want the natural-language agent loop (0.3's new primitive)**

```typescript
const result = await session.send(
  "Send a receipt to +5511999887766 via WhatsApp",
);
console.log(result.message);     // agent's final response
console.log(result.tool_calls);  // every tool the agent invoked
```

The same applies to `sendStream` — yields an async iterable of `StreamEvent` values with `assistant_text`, `tool_use`, `tool_result`, `done`, `error` types.

### Audit the difference

In 0.2, `send` was often used for "fire the notification and don't care about the response." In 0.3 you have two ways to express that:

- **Just fire** — `session.execute("codespar_notify", params)`. Synchronous, cheap, unambiguous.
- **Let the agent decide** — `session.send("Tell them their order shipped")`. Useful when the message template is LLM-generated.

## 4. `session.mcp` is a property, not a method

In 0.2 you called `await session.mcp()` to get the MCP endpoint config. In 0.3 it is a property on the session object that is set at creation time.

**Before**

```typescript
const mcpConfig = await session.mcp();
// { transport, url, tools }
```

**After**

```typescript
console.log(session.mcp);
// { url, headers }
```

The returned shape changed too — it is now just the endpoint URL + auth headers, which is what MCP clients (Claude Desktop, Cursor) actually consume. The `tools` list is available via `session.tools()` as it always was.

## 5. 2-level tenancy via `projectId`

Account → Project is now a first-class tenancy dimension. Sessions (and all downstream artifacts) live in one project.

**SDK**

```typescript
const session = await codespar.create("user_123", {
  servers: ["stripe"],
  projectId: "prj_a1b2c3d4e5f6g7h8",
});
```

**HTTP**

```bash
curl -X POST https://api.codespar.dev/v1/sessions \
  -H "Authorization: Bearer csk_live_..." \
  -H "x-codespar-project: prj_a1b2c3d4e5f6g7h8" \
  ...
```

If you omit `projectId` / the header, the backend resolves to the account's default project (auto-created at signup). Existing 0.2 traffic continues to land there automatically — no data migration needed.

See [Projects](/docs/concepts/projects) for the full tenancy model.

## 6. Python package on PyPI

New in 0.3 — not a breaking change, but if you were waiting for Python support:

```bash
pip install codespar
```

```python
from codespar import CodeSpar

cs = CodeSpar()  # reads CODESPAR_API_KEY
with cs.create("user_123", preset="brazilian") as session:
    result = session.execute("codespar_pay", {"method": "pix", "amount": 15000, "currency": "BRL"})
```

Sync (`CodeSpar`) and async (`AsyncCodeSpar`) flavours ship in the same wheel. See [Quickstart (Python)](/docs/quickstart-python).

## Framework adapters

Every adapter was bumped to 0.3.0 in lockstep:

```bash
npm install @codespar/sdk@^0.3.0 @codespar/claude@^0.3.0
# or
npm install @codespar/sdk@^0.3.0 @codespar/openai@^0.3.0
# ...
```

The adapter surfaces (`getTools`, `handleToolUse`, `handleToolCall`, `toClaudeTool`, `toOpenAITool`, etc.) did not change — same function names, same return shapes. The version bump is to align the peer-dep against `@codespar/sdk@^0.3.0`.

## Checklist

- [ ] Bump `@codespar/sdk` to `^0.3.0` in `package.json`
- [ ] Bump every `@codespar/ADAPTER` package (claude, openai, vercel, etc.) to `^0.3.0` in the same commit
- [ ] Replace `codespar.sessions.create(` with `codespar.create(userId, ` across the codebase
- [ ] Replace the old object-form `session.execute` calls with the two-positional form `session.execute(name, params)`
- [ ] Audit every `session.send` call — decide: `execute` for a direct tool call, or pass a string message for the agent loop
- [ ] Replace `await session.mcp()` with `session.mcp`
- [ ] (Optional) Pass `projectId` on session creation if you want explicit project scoping
- [ ] Run the test suite against a sandbox `csk_test_` key before swapping production keys

## Troubleshooting

**`Argument of type 'string' is not assignable to parameter of type SessionConfig`**
— You have `codespar.sessions.create(...)` somewhere. `sessions` is gone; use `codespar.create(userId, config)` directly.

**`Type ToolCallInput is not assignable to parameter of type string`** (on a `session.send(...)` call)
— `session.send` now takes a string message. If the call used to be a tool invocation, switch to `session.execute(name, params)`.

**"codespar.sessions is not a function"**
— Same as above, at runtime. TypeScript should have caught it — double-check your build.

**Adapter import fails with peer-dep warning**
— Your lockfile is pinning `@codespar/sdk@^0.2.0`. Run `npm install @codespar/sdk@latest @codespar/claude@latest` (or whichever adapter you use) to upgrade both together.

## Next steps

<NextStepsGrid items={[
  { label: "REFERENCE", title: "SDK Reference", description: "Full TypeScript reference for v0.3 — every method and type.", href: "/docs/api/sdk" },
  { label: "QUICKSTART", title: "Quickstart", description: "Greenfield setup on v0.3 from scratch.", href: "/docs/quickstart" },
  { label: "QUICKSTART", title: "Quickstart (Python)", description: "New in 0.3 — pip install codespar, sync and async.", href: "/docs/quickstart-python" },
  { label: "CONCEPT", title: "Sessions", description: "The full session model on 0.3.", href: "/docs/concepts/sessions" },
  { label: "CHANGELOG", title: "Changelog", description: "Full release notes across packages.", href: "/docs/changelog" },
]} />
