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

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:

pnpm add @moonshot-ai/klient

Remove the old dependency if present:

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

2. Replace Imports

Update your import statements to use the new entry points:

// 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.

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

4. Create and Access Sessions

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

// 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:

// 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:

// 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:

// 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:

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

9. Verify with the Smoke Test

Run the bundled verification test to confirm your migration:

pnpm -C packages/klient smoke

Reference: packages/klient/examples/smoke.ts

Complete Code Examples

Minimal "Hello-World" Using the Legacy SDK

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

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

// 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 Public exports of the legacy SDK.
packages/node-sdk/src/kimi-harness.ts High‑level session façade used in old examples.
packages/node-sdk/src/sdk-rpc-client.ts Low‑level RPC client implementation.
klient packages/klient/src/index.ts Main entry point that re‑exports the façade.
packages/klient/src/core/facade/session.ts Session creation & utility methods (create, list, …).
packages/klient/src/core/facade/agent.ts Agent‑level RPC methods (prompt, steer, …).
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 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 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →