# How to Migrate from the Legacy Node-SDK to the New Klient SDK Architecture

> Migrate from the legacy Node-SDK to the new Klient SDK architecture. Learn to replace RPC calls, initialize transport-agnostic, and adopt the v2 engine bootstrap pattern for seamless integration.

- Repository: [Moonshot AI/kimi-code](https://github.com/MoonshotAI/kimi-code)
- Tags: migration-guide
- Published: 2026-08-16

---

**Migrate from `@moonshot-ai/kimi-code-sdk` to `@moonshot-ai/klient` by replacing direct RPC calls with contract-driven façade methods, switching to transport-agnostic initialization, and adopting the v2 engine bootstrap pattern.**

The `@moonshot-ai/klient` SDK replaces the legacy `@moonshot-ai/kimi-code-sdk` Node-SDK with a **contract-driven façade architecture** built on the v2 engine (`agent-core-v2`). This migration guide walks through the architectural differences, step-by-step code changes, and key source files you need to understand when moving your codebase.

## Architectural Differences Between Legacy and Klient SDK

The two SDKs represent fundamentally different design philosophies. Understanding these differences clarifies why the migration changes your import patterns and API calls.

### Entry Points and Public API

| Aspect | Legacy Node‑SDK | New Klient SDK |
|--------|----------------|----------------|
| **Entry point** | `export * from '#/sdk-rpc-client'` (exposes `SDKRpcClient`, `createKimiHarness`) | `export * from '#/core/facade/*'` (exposes `klient.global.*`, `klient.session(id).*`, `klient.session(id).agent(name).*`) |
| **Transport** | RPC‑client talks to the server over HTTP/WebSocket via a custom wire format. | Two transports (`memory` for in‑process, `ipc` for socket) share a single `KlientChannel` SPI; the transport is chosen once when the client is created. |
| **API style** | Mostly imperative functions that accept many optional parameters. | Fully *facade‑oriented*: single‑object parameter calls, all inputs validated by **zod** contracts. |
| **Session lifecycle** | `new Session(...)` + explicit `session.start()` etc. | `klient.global.sessions.create({ workDir })` → `klient.session(id)` gives a typed session object. |
| **Agent interaction** | `KimiHarness.prompt(...)`, `KimiHarness.steer(...)` | `klient.session(id).agent('main').prompt({ input })`, `agent.steer({ ... })`. |
| **Configuration & Auth** | `config-rpc`, `auth` modules expose raw RPC methods. | `klient.global.config.*`, `klient.global.auth.*` are high‑level, contract‑validated helpers. |
| **Event handling** | Direct `EventEmitter` on `KimiHarness`. | Centralised `klient.events.on(...)` with typed event names (`assistant.delta`, `prompt.completed`, …). |
| **Error handling** | `KimiError` types from `agent‑core`. | Same error types re‑exported, but now wrapped in façade methods that automatically convert payloads. |

The **Klient** design deliberately isolates the consumer from the engine's internal services. All communication happens through a **typed contract** in `packages/klient/src/contract/*`. This makes the SDK version-stable, easier to test, and transport-agnostic as implemented in the MoonshotAI/kimi-code repository.

## Step-by-Step Migration Guide

Follow these steps to convert your existing Node-SDK code to the Klient architecture.

### 1. Install the New Package

Replace the legacy package with the new Klient SDK:

```bash
pnpm add @moonshot-ai/klient

```

Remove the old dependency if present:

```bash
pnpm remove @moonshot-ai/kimi-code-sdk

```

### 2. Replace Imports

Update your import statements to use the new entry points:

```typescript
// Old: packages/node-sdk/src/index.ts
import { createKimiHarness, SDKRpcClient } from '@moonshot-ai/kimi-code-sdk';

// New: packages/klient/src/index.ts
import { createKlient } from '@moonshot-ai/klient/memory';   // or `/ipc`

```

The `/memory` transport is recommended for testing and in-process usage. Use `/ipc` for socket-based communication.

### 3. Bootstrap the Engine and Create a Klient Instance

The Klient SDK requires explicit engine initialization using the v2 bootstrap pattern. This replaces the implicit engine startup in the legacy SDK.

```typescript
import { bootstrap, logSeed, resolveLoggingConfig } from '@moonshot-ai/agent-core-v2';
import { createKlient } from '@moonshot-ai/klient/memory';

const { app } = bootstrap({ homeDir: '~/.kimi-code' }, [
  ...logSeed(resolveLoggingConfig({ homeDir: '~/.kimi-code', env: process.env })),
]);

const klient = createKlient({ scope: app });

```

Reference: [`packages/klient/src/transports/memory/index.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/klient/src/transports/memory/index.ts)

### 4. Create and Access Sessions

Replace direct `Session` instantiation with the façade-based session management:

```typescript
// Old: packages/node-sdk/src/session.ts
const session = new Session({ workDir: process.cwd() });
await session.start();

// New: packages/klient/src/core/facade/session.ts
const { id } = await klient.global.sessions.create({ workDir: process.cwd() });
const session = klient.session(id);

```

The new approach uses `klient.global.sessions.create()` to spawn sessions and `klient.session(id)` to obtain a typed session handle.

### 5. Interact with Agents

Agent interaction moves from the `KimiHarness` class to the agent façade:

```typescript
// Old: packages/node-sdk/src/kimi-harness.ts
const harness = await createKimiHarness(session);
await harness.prompt({ input: [{ type: 'text', text: 'Hello' }] });

// New: packages/klient/src/core/facade/agent.ts
const agent = klient.session(id).agent('main');
await agent.prompt({ input: [{ type: 'text', text: 'Hello' }] });

```

The `agent('main')` method returns an agent façade with typed methods for `prompt`, `steer`, and other operations.

### 6. Handle Events

Event handling shifts from per-instance emitters to the central event hub:

```typescript
// Old: packages/node-sdk/src/events.ts
harness.events.on('assistant.delta', e => process.stdout.write(e.delta));

// New: packages/klient/src/core/events/hub.ts
agent.events.on('assistant.delta', e => process.stdout.write(e.delta));

```

The event names remain consistent, but the subscription mechanism uses the agent's event interface.

### 7. Update Configuration and Authentication Calls

Replace raw RPC configuration calls with high-level façade methods:

```typescript
// Old: packages/node-sdk/src/config-rpc.ts
const cfg = await configRpcClient.getConfig();
const auth = await authFacade.login(...);

// New: packages/klient/src/contract/global/config.ts
const cfg = await klient.global.config.get();
const authResult = await klient.global.auth.login(...);

```

### 8. Close the Client Properly

Add explicit cleanup to release resources:

```typescript
await klient.close();   // flushes transports and releases resources

```

### 9. Verify with the Smoke Test

Run the bundled verification test to confirm your migration:

```bash
pnpm -C packages/klient smoke

```

Reference: [`packages/klient/examples/smoke.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/klient/examples/smoke.ts)

## Complete Code Examples

### Minimal "Hello-World" Using the Legacy SDK

```typescript
import { createKimiHarness } from '@moonshot-ai/kimi-code-sdk';

async function legacyHello() {
  const harness = await createKimiHarness();
  await harness.prompt({ input: [{ type: 'text', text: 'Hello from legacy SDK!' }] });
}
legacyHello();

```

### Equivalent Functionality with the Klient SDK

```typescript
import { bootstrap, logSeed, resolveLoggingConfig } from '@moonshot-ai/agent-core-v2';
import { createKlient } from '@moonshot-ai/klient/memory';

async function klientHello() {
  const { app } = bootstrap({ homeDir: '~/.kimi-code' }, [
    ...logSeed(resolveLoggingConfig({ homeDir: '~/.kimi-code', env: process.env })),
  ]);

  const klient = createKlient({ scope: app });
  const { id } = await klient.global.sessions.create({ workDir: process.cwd() });
  const agent = klient.session(id).agent('main');

  await agent.prompt({ input: [{ type: 'text', text: 'Hello from Klient SDK!' }] });
  await klient.close();
}
klientHello();

```

### Event-Driven Streaming Comparison

```typescript
// Legacy approach
harness.events.on('assistant.delta', e => process.stdout.write(e.delta));
await harness.prompt({ input: [{ type: 'text', text: 'Stream me' }] });

// Klient approach
const agent = klient.session(id).agent('main');
agent.events.on('assistant.delta', e => process.stdout.write(e.delta));
await agent.prompt({ input: [{ type: 'text', text: 'Stream me' }] });

```

## Key Source Files for Migration Reference

| Package | Important File | What It Provides |
|---------|----------------|------------------|
| **node‑sdk** | [`packages/node-sdk/src/index.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/node-sdk/src/index.ts) | Public exports of the legacy SDK. |
| | [`packages/node-sdk/src/kimi-harness.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/node-sdk/src/kimi-harness.ts) | High‑level session façade used in old examples. |
| | [`packages/node-sdk/src/sdk-rpc-client.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/node-sdk/src/sdk-rpc-client.ts) | Low‑level RPC client implementation. |
| **klient** | [`packages/klient/src/index.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/klient/src/index.ts) | Main entry point that re‑exports the façade. |
| | [`packages/klient/src/core/facade/session.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/klient/src/core/facade/session.ts) | Session creation & utility methods (`create`, `list`, …). |
| | [`packages/klient/src/core/facade/agent.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/klient/src/core/facade/agent.ts) | Agent‑level RPC methods (`prompt`, `steer`, …). |
| | [`packages/klient/src/transports/memory/index.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/klient/src/transports/memory/index.ts) | In‑process "memory" transport (default for tests & smoke). |
| | `packages/klient/src/contract/*` | Zod‑validated contract schemas for every RPC call. |
| | [`packages/klient/examples/smoke.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/klient/examples/smoke.ts) | Minimal end‑to‑end usage demonstration. |

## Summary

- **Switch imports** from `@moonshot-ai/kimi-code-sdk` to `@moonshot-ai/klient/memory` or `/ipc`
- **Bootstrap the v2 engine** explicitly using `bootstrap()` from `agent-core-v2` before creating any Klient instance
- **Use the `global` façade** (`klient.global.sessions.create()`, `klient.global.config.get()`) for lifecycle and configuration operations
- **Access agents through the session façade** (`klient.session(id).agent('main')`) rather than standalone harness creation
- **Rely on zod-validated contracts** for type-safe, version-stable API calls
- **Call `klient.close()`** to properly release resources when finished

## Frequently Asked Questions

### What happens to my existing `SDKRpcClient` code?

The `SDKRpcClient` class from [`packages/node-sdk/src/sdk-rpc-client.ts`](https://github.com/MoonshotAI/kimi-code/blob/main/packages/node-sdk/src/sdk-rpc-client.ts) is not directly exposed in the Klient SDK. Replace direct RPC client instantiation with `createKlient({ scope: app })` and use the façade methods. The underlying RPC mechanism still exists but is encapsulated behind the contract layer.

### Can I use both SDKs simultaneously during migration?

Technically possible but not recommended. Both SDKs expect ownership of the engine bootstrap process. Running `bootstrap()` twice or mixing `Session` instances with Klient sessions causes resource conflicts. Complete the migration in a single codebase transition instead.

### Why does Klient require explicit engine bootstrap?

The legacy SDK hid engine initialization inside `createKimiHarness()` or `new Session()`. The Klient architecture separates **engine lifecycle** from **client usage** to support multiple transport types and testing scenarios. This explicitness matches the `agent-core-v2` design philosophy in the MoonshotAI/kimi-code repository.

### How do I choose between `memory` and `ipc` transports?

Use **`memory`** for in-process integration, unit tests, and single-machine deployments where the engine runs in the same Node.js process. Use **`ipc`** for multi-process architectures, containerized deployments, or when the engine runs as a separate service. The transport choice is fixed at `createKlient()` time.