Utilities, patterns, and examples built around @anthropic-ai/claude-agent-sdk. The toolkit streamlines session management, message parsing, and upcoming UI primitives so you can stand up Claude-powered agents quickly.
- Session lifecycle helpers for keeping local state in sync with Claude.
- Message parsing utilities that normalize Claude streaming payloads.
- WebSocket orchestration for multi-client real-time experiences.
- Examples and UI groundwork to accelerate new agent surfaces.
ℹ️ The package currently targets
@anthropic-ai/claude-agent-sdk@^0.1.0. Adjust the version inpackage.jsonto match the SDK release you are using.
pnpm install
pnpm run buildImport the pieces you need from the scoped packages:
import { buildUserMessageContent } from "@claude-agent-kit/messages";
import { SessionManager, SimpleClaudeAgentSDKClient } from "@claude-agent-kit/server";
import { WebSocketHandler } from "@claude-agent-kit/websocket";import { SessionManager, SimpleClaudeAgentSDKClient } from "@claude-agent-kit/server";
import type { AttachmentPayload } from "@claude-agent-kit/messages";
const sessionManager = new SessionManager();
const session = sessionManager.createSession(new SimpleClaudeAgentSDKClient());
const attachments: AttachmentPayload[] | undefined = undefined;
await session.send("List the open pull requests in this repo.", attachments);
for (const message of session.messages) {
console.log(`[${message.type}]`, message.content.map((part) => part.content));
}This repo includes two runnable examples that demonstrate different integration styles:
- Basic chat app powered by Bun WebSocket server:
examples/basic-example - Web app (Express + Vite + ws) with a richer UI:
examples/claude-code-web
Run a minimal chat experience with Bun, a simple React UI, and a WebSocket bridge.
Steps:
pnpm install
export ANTHROPIC_API_KEY=your-key-here
cd examples/basic-example
bun run dev
# open http://localhost:3000Key server wiring (simplified):
// examples/basic-example/server/server.ts
import "dotenv/config";
import path from "node:path";
import { BunWebSocketHandler } from "@claude-agent-kit/bun-websocket";
import { SimpleClaudeAgentSDKClient, type SessionSDKOptions } from "@claude-agent-kit/server";
const sdkClient = new SimpleClaudeAgentSDKClient();
const defaultOptions: SessionSDKOptions = {
cwd: path.join(process.cwd(), "agent"),
thinkingLevel: "default_on",
};
const wsHandler = new BunWebSocketHandler(sdkClient, defaultOptions);
const server = Bun.serve({
port: 3000,
websocket: {
open(ws) { wsHandler.onOpen(ws); },
message(ws, msg) { wsHandler.onMessage(ws, msg); },
close(ws) { wsHandler.onClose(ws); },
},
fetch(req, server) {
const url = new URL(req.url);
if (url.pathname === "/ws") {
server.upgrade(req, { data: { sessionId: "" } });
return;
}
return new Response("OK");
},
});Client sends chat messages over WS as JSON:
// minimal client shape
const ws = new WebSocket("ws://localhost:3000/ws");
ws.onopen = () => {
ws.send(JSON.stringify({ type: "chat", content: "Hello!" }));
};
ws.onmessage = (ev) => {
const msg = JSON.parse(ev.data);
// { type: "message_added" | "messages_updated" | "session_state_changed", ... }
};Run a full-stack dev server that serves the client via Vite and streams messages over ws.
Steps:
pnpm install
export ANTHROPIC_API_KEY=your-key-here
cd examples/claude-code-web
pnpm dev
# open http://localhost:5173Key server wiring (simplified):
// examples/claude-code-web/src/server/server.ts
import express from 'express'
import { createServer as createHttpServer } from 'node:http'
import { WebSocketServer } from 'ws'
import { SimpleClaudeAgentSDKClient } from '@claude-agent-kit/server'
import { WebSocketHandler } from '@claude-agent-kit/websocket'
export async function createServer() {
const app = express()
const httpServer = createHttpServer(app)
const wss = new WebSocketServer({ server: httpServer })
const sdkClient = new SimpleClaudeAgentSDKClient()
const wsHandler = new WebSocketHandler(sdkClient, { thinkingLevel: 'default_on' })
wss.on('connection', (ws) => {
void wsHandler.onOpen(ws)
ws.on('message', (data) => wsHandler.onMessage(ws, String(data)))
ws.on('close', () => wsHandler.onClose(ws))
})
return { app, httpServer, wss }
}Minimal client usage is identical to the Bun example; the endpoint is the WS server you configure (e.g., ws://localhost:5173). For a robust React hook with auto‑reconnect and session resume, see examples/claude-code-web/src/client/hooks/use-web-socket.ts.
This section summarizes the architecture, data flow, and key components of the Claude Agent Kit. It mirrors the dedicated doc previously in docs/system-design.md.
- Purpose: Accelerate building Claude-powered agents by packaging session/state management, message utilities, and transport glue around
@anthropic-ai/claude-agent-sdk. - Packages:
@claude-agent-kit/messages— Types and helpers for composing user inputs and rendering SDK messages.@claude-agent-kit/server— Session, options, streaming, and persistence helpers that wrap the SDK.@claude-agent-kit/websocket— Node.js WebSocket bridge for multi-client real-time chat.@claude-agent-kit/bun-websocket— Bun WebSocket bridge for the same real-time chat flows.
flowchart LR
subgraph Client
B["Browser/App\n(WS Client)"]
end
subgraph Transport
H["WebSocketHandler"]
end
subgraph SessionLayer
SM["SessionManager"]
S["Session\n- options\n- messages\n- busy/loading state\n- clients"]
end
subgraph SDK
CSDK["SimpleClaudeAgentSDKClient\n(simple implementation)"]
AGSDK["@anthropic-ai/claude-agent-sdk"]
I[("IClaudeAgentSDKClient\n<<interface>>")]
end
subgraph Storage
F[(".claude/projects\nJSONL logs")]
end
B -->|chat / setSDKOptions / resume| H
H --> SM
SM --> S
S <--> I
CSDK -. implements .-> I
CSDK --> AGSDK
H -->|messages / state| S
S -. loadMessages .-> F
Key responsibilities:
- Client sends chat, SDK option updates, or resume requests via WebSocket.
- Handler parses inbound messages, delegates to
SessionManager, and re-broadcasts server events to the client. SessionManagerensures aSessionexists per client/session id and routes calls.Sessionorchestrates streaming with the SDK, tracks messages and state, persists session id, and fans out updates to attached clients.- Storage helpers read historical JSONL logs to restore transcripts by session id.
Notes:
SimpleClaudeAgentSDKClientis a minimal implementation of theIClaudeAgentSDKClientinterface. Consumers can derive or replace it with their own SDK client implementation (e.g., to add logging, retries, or custom transport).WebSocketHandlercan be subclassed or swapped for alternative transports while retaining theSessionManager/Sessioncore.
sequenceDiagram
participant U as User (Browser)
participant WS as WebSocketHandler
participant M as SessionManager
participant S as Session
participant SC as IClaudeAgentSDKClient\\n(impl: SimpleClaudeAgentSDKClient)
participant A as @anthropic-ai/claude-agent-sdk
U->>WS: send { type: "chat", content, attachments }
WS->>M: sendMessage(client, content, attachments)
M->>S: ensure + subscribe(client)
M->>S: send()
S->>S: addNewMessage(userMessage)
S->>SC: queryStream(async iterator)
loop stream
SC->>A: query(...)
A-->>SC: SDKMessage
SC-->>S: SDKMessage
S->>S: processIncomingMessage()
S-->>WS: message_added / session_state_changed
WS-->>U: emit JSON event (serialized)
end
Error handling:
- Invalid payloads are rejected with structured errors (e.g.,
code: "empty_message"). - Socket send failures are caught and logged; session state continues.
AbortControlleris used to interrupt in-flight queries per session.
sequenceDiagram
participant U as User (Browser)
participant WS as WebSocketHandler
participant M as SessionManager
participant S as Session
participant F as Session Files (.claude/projects)
U->>WS: { type: "resume", sessionId }
WS->>M: getOrCreateSession(client)
M->>S: subscribe(client)
S->>S: updateSessionId(target)
S->>F: locate + read JSONL
F-->>S: messages[]
S-->>WS: messages_updated + session_state_changed
WS-->>U: emit JSON events
-
@claude-agent-kit/messages- Build user composition blocks from prompt + attachments for the SDK input.
- Normalize and coalesce SDK streaming messages into UI-friendly chat messages.
- Notable APIs:
- buildUserMessageContent(prompt, attachments)
- appendRenderableMessage(messages, incoming)
- convertSDKMessages(sdkMessages)
-
@claude-agent-kit/serverSession: wraps SDK streaming, tracksmessages,isBusy,isLoading, and emits client-facing events. MergesSessionSDKOptionswith safe defaults, inferscwdfrom incoming system messages when possible, and supportsinterrupt().SessionManager: manages multiple sessions, subscription lifecycle, and delegates actions.SimpleClaudeAgentSDKClient: thin adapter around@anthropic-ai/claude-agent-sdkquery()and local log loading.- Persistence utilities: discover
.claude/projectsand parse JSONL transcripts.
-
@claude-agent-kit/websocketand@claude-agent-kit/bun-websocket- WebSocket handlers and session client shims for Node (
ws) and Bun (ServerWebSocket). - Input messages:
chat,setSDKOptions,resume. - Output messages:
message_added,messages_updated,session_state_changed.
- WebSocket handlers and session client shims for Node (
-
Session state
sessionId: Claude session identifier (assigned on first stream result)messages: array ofSDKMessage(as received), plus UI projections in the app using@claude-agent-kit/messagesisBusy/isLoading: driven by system/result stream eventssummary,usageSummary,error: derived metadata
-
Session options (
SessionSDKOptions)- Extends SDK
OptionswiththinkingLevel,cwd,allowedTools,mcpServers, and optionalhooks. - Defaults are composed and normalized; setting
cwdto blank removes it from the effective options.
- Extends SDK
-
Attachments
- Images (base64) are inlined; plain text is decoded to
documentblocks; PDFs are preserved as base64.
- Images (base64) are inlined; plain text is decoded to
- Transports: Implement another
ISessionClientand handler to plug in alternative protocols (e.g., HTTP SSE, Socket.IO). - Persistence: Swap or augment the JSONL reader to use a database or object store; keep
Session.loadFromServer()as the seam. - Policy: Customize
allowedTools,mcpServers, orthinkingLevelat connection time viasetSDKOptions.
- Session lifecycle and streaming: packages/server/src/server/session.ts:1
- WebSocket bridge (Node): packages/websocket/src/websocket-handler.ts:1
- WebSocket bridge (Bun): packages/bun-websocket/src/bun-websocket-handler.ts:1
- Message shaping/coalescing: packages/messages/src/messages/messages.ts:1
- Attachments to user blocks: packages/messages/src/messages/build-user-message-content.ts:1
- Session log discovery/parsing: packages/server/src/utils/session-files.ts:1
- Basic Bun server + client using the Bun WebSocket handler: examples/basic-example/server/server.ts:1
- Express + ws dev server with Vite: examples/claude-code-web/src/server/server.ts:1
pnpm testThe Vitest configuration only scans src/**/*.{test,spec}.{ts,tsx} so you can colocate tests with the implementation without affecting the published build artifacts. Use pnpm run test:watch for an interactive loop.
- Fork the repository.
- Install dependencies with
pnpm install. - Run
pnpm run buildand open a pull request with your changes.
This project is licensed under the MIT License. See LICENSE for details.