@kenkaiiii/agent-home-sdk
v0.3.8
Published
Lightweight SDK to connect any Node.js project to Agent Home as an agent
Maintainers
Readme
@kenkaiiii/agent-home-sdk
Connect any Node.js app to Agent Home as an agent. Zero dependencies.
Your app connects to the relay as an agent — it receives user messages and sends responses back. The Agent Home iOS app is the client that users chat from.
Quick Start
npm install @kenkaiiii/agent-home-sdkimport { AgentHomeClient } from '@kenkaiiii/agent-home-sdk';
const client = new AgentHomeClient({
relayUrl: 'wss://your-relay.workers.dev/ws',
token: 'your-bridge-token',
agent: {
id: 'my-agent',
name: 'My Agent',
},
});
client.onMessage(async (message, stream) => {
// Your logic here — call an LLM, query a DB, whatever
stream.end('Hello!');
});
client.connect();That's it. The SDK handles authentication, registration, heartbeats, and reconnection automatically.
Getting a Token
You need a relayUrl and a token.
From the iOS app: Open Agent Home → Settings → "Generate SDK Token" → copy both values.
HTTP API (programmatic):
const response = await fetch('https://your-relay.workers.dev/auth/bridge-token', {
method: 'POST',
headers: { Authorization: `Bearer ${existingToken}` },
});
const { token, relayUrl } = await response.json();Provisioning secret (server-side):
curl -X POST https://your-relay.workers.dev/auth/token \
-H "Authorization: Bearer YOUR_PROVISIONING_SECRET" \
-H "Content-Type: application/json" \
-d '{"clientType": "bridge"}'API
new AgentHomeClient(options)
| Option | Type | Required | Description |
| ------------------- | -------- | -------- | ---------------------------------------- |
| relayUrl | string | ✅ | WebSocket URL of the relay (wss://...) |
| token | string | ✅ | Bridge auth token |
| agent.id | string | ✅ | Unique agent identifier (lowercase, no spaces) |
| agent.name | string | ✅ | Display name in the app |
| agent.description | string | | Shown below the agent name |
client.onMessage(handler)
client.onMessage(async (message, stream) => {
message.content; // string — the user's message
message.sessionId; // string | undefined — which session this belongs to
// Streaming (for LLMs / typewriter effect):
stream.token('Hello ');
stream.token('world!');
stream.end('Hello world!'); // must call end() with the full assembled text
// OR single response:
stream.end('Here is my answer.');
// OR error:
stream.error('Something went wrong');
});You must call stream.end() to complete every response, even when streaming.
client.onConnect(handler) / client.onDisconnect(handler)
client.onConnect(() => console.log('Connected'));
client.onDisconnect(() => console.log('Disconnected'));Auto-reconnect is built in (exponential backoff up to 30s). Only client.disconnect() stops it.
Sessions (Optional)
Sessions let your agent expose multiple conversations to Agent Home. Skip this entirely if you only need a single chat per agent.
How it works
- Your agent maintains sessions and calls
client.updateSessions(sessions)when the list changes. - Agent Home shows the session list. Users tap a session to chat in it, or start a new chat.
- Your
onMessagehandler receivesmessage.sessionIdto route to the right conversation. - For new chats (
sessionIdisundefined), create a session and pass the new ID viastream.end(content, { sessionId: newId }).
Complete example
import { AgentHomeClient, type AgentSession } from '@kenkaiiii/agent-home-sdk';
const sessions = new Map<string, { id: string; title: string; messages: string[] }>();
function createSession(title: string): string {
const id = `session-${Date.now()}`;
sessions.set(id, { id, title, messages: [] });
pushSessions();
return id;
}
function pushSessions() {
const list: AgentSession[] = Array.from(sessions.values()).map((s) => ({
id: s.id,
title: s.title,
updatedAt: Date.now(),
}));
client.updateSessions(list);
}
const client = new AgentHomeClient({
relayUrl: 'wss://your-relay.workers.dev/ws',
token: 'your-token',
agent: { id: 'my-agent', name: 'My Agent' },
});
client.onMessage(async (message, stream) => {
const { content, sessionId } = message;
if (sessionId) {
const session = sessions.get(sessionId);
if (!session) {
stream.error(`Session ${sessionId} not found`);
return;
}
session.messages.push(content);
stream.end(`Echo: ${content}`); // sessionId is auto-tagged from the incoming message
} else {
// New chat — create a session and tag the response with its ID
const title = content.length > 50 ? content.slice(0, 50) + '...' : content;
const newSessionId = createSession(title);
sessions.get(newSessionId)!.messages.push(content);
stream.end(`Echo: ${content}`, { sessionId: newSessionId });
}
});
// Optional: clean up your own state when a user deletes a session from the app
client.onSessionDelete((sessionId) => {
sessions.delete(sessionId);
});
// Push existing sessions on connect/reconnect
client.onConnect(() => pushSessions());
client.connect();Key rules
updateSessions()is a full replacement — always send the complete list, not a delta.- Call it after creating or renaming sessions. You do not need to call it after deletions — the SDK automatically filters deleted sessions from all future
updateSessions()calls. The relay also filters server-side. sessionIdisundefinedfor new chats — create a session and pass the ID viastream.end(content, { sessionId }).- Existing sessions are auto-tagged — when a message arrives with a
sessionId, allstream.token()andstream.end()calls are tagged with it. The{ sessionId }override is only needed for new sessions. onSessionDeleteis for your own cleanup only — remove the session from your internal state (maps, DB, etc.). The SDK and relay handle everything else.
CLI Scaffolding
For new projects, scaffold in one command:
npx create-agent-home-agent \
--url "wss://agent-home-relay.buzzbeamaustralia.workers.dev/ws" \
--token "your-token" \
--name "My Agent" \
--yesCreates a ready-to-run agent file with sessions support and installs the SDK.
| Flag | Description |
| ---------------------- | ------------------------------------------------ |
| --url <url> | Relay WebSocket URL (required) |
| --token <token> | Auth token (required) |
| --name <name> | Agent display name (default: directory name) |
| --id <id> | Agent ID (default: derived from name) |
| --description <desc> | Agent description |
| --filename <file> | Output file (default: agent.ts or agent.mjs) |
| --no-install | Skip npm install |
| -y, --yes | No prompts, accept defaults |
Types
import {
AgentHomeClient,
AgentHomeClientOptions,
AgentInfo,
AgentSession,
IncomingMessage,
ResponseStream,
StreamOptions,
} from '@kenkaiiii/agent-home-sdk';Requirements
- Node.js 18+ (uses native
WebSocket) - A bridge token from Agent Home
- Tokens expire after 30 days
