npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@kenkaiiii/agent-home-sdk

v0.3.8

Published

Lightweight SDK to connect any Node.js project to Agent Home as an agent

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-sdk
import { 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

  1. Your agent maintains sessions and calls client.updateSessions(sessions) when the list changes.
  2. Agent Home shows the session list. Users tap a session to chat in it, or start a new chat.
  3. Your onMessage handler receives message.sessionId to route to the right conversation.
  4. For new chats (sessionId is undefined), create a session and pass the new ID via stream.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.
  • sessionId is undefined for new chats — create a session and pass the ID via stream.end(content, { sessionId }).
  • Existing sessions are auto-tagged — when a message arrives with a sessionId, all stream.token() and stream.end() calls are tagged with it. The { sessionId } override is only needed for new sessions.
  • onSessionDelete is 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" \
  --yes

Creates 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