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

@zuno-ai/sdk

v0.2.2

Published

Embed [Zuno](https://github.com/iarmankhan/zuno) — a typed AI agent harness with sandboxed tool execution and AI SDK v6 native streaming — directly into your Node app. **No service to deploy, no database to provision.**

Readme

@zuno-ai/sdk

Embed Zuno — a typed AI agent harness with sandboxed tool execution and AI SDK v6 native streaming — directly into your Node app. No service to deploy, no database to provision.

import { createZuno } from "@zuno-ai/sdk";
import { anthropic } from "@ai-sdk/anthropic";

const zuno = await createZuno({ model: anthropic("claude-sonnet-4.6") });
const reply = await zuno.chat("Read package.json and tell me the project name.");
console.log(reply);

That's the whole hello-world. No Postgres, no session ceremony, no schemas. Storage is in-memory by default; swap in Postgres when you need persistence.


Install

pnpm add @zuno-ai/sdk ai @ai-sdk/anthropic

Pick a model provider that matches your stack — Zuno doesn't bundle any:

pnpm add @ai-sdk/anthropic       # Anthropic
pnpm add @ai-sdk/openai          # OpenAI
pnpm add @ai-sdk/google-vertex   # Anthropic via Vertex
# Vercel AI Gateway: `gateway()` ships with `ai`, no extra install.

Continuity

zuno.chat() auto-creates an anonymous session on the first call and reuses it for subsequent calls — so a follow-up question continues the conversation:

await zuno.chat("My favourite colour is teal.");
await zuno.chat("What did I just say my favourite colour was?");
// → "Teal."
zuno.reset();                  // start a fresh thread
await zuno.chat("Again, what is my favourite colour?");
// → "I don't have that information."

Streaming

const stream = await zuno.stream("Walk me through what's in this folder.");
for await (const chunk of stream) {
  // chunk is a v6 UIMessageChunk — drop into useChat / readUIMessageStream / AI Elements
  process.stdout.write(chunk.type === "text-delta" ? chunk.delta : "");
}

Adding a database (production)

The in-memory backend lives in the host process and disappears when it exits. For persistence, pass a Postgres URL:

const zuno = await createZuno({
  model: anthropic("claude-sonnet-4.6"),
  database: {
    connectionString: process.env.DATABASE_URL!,
    runMigrations: true,            // creates Zuno tables on first start
  },
});

You'll also need pnpm add drizzle-orm pg — these are required by the Postgres backend.

Multi-tenant: one Postgres, many Zunos

All Zuno tables live in a configurable Postgres schema (default 'zuno'). Two Zuno installs against the same database stay fully isolated as long as they pick different schema names:

const tenantA = await createZuno({
  model,
  database: { connectionString: SHARED_DB_URL, schema: "zuno",       runMigrations: true },
});
const tenantB = await createZuno({
  model,
  database: { connectionString: SHARED_DB_URL, schema: "zuno_app2",  runMigrations: true },
});

Each schema has its own __drizzle_migrations tracking table, so the two installs version independently. Schema names must match the Postgres unquoted-identifier shape ([a-zA-Z_][a-zA-Z0-9_]{0,62}).

Adding tools, skills, sandbox

By default chat() runs in direct-system sandbox mode — tool execution happens in the host process, scoped to process.cwd(). Pick a different sandbox for stronger isolation:

const zuno = await createZuno({
  model: anthropic("claude-sonnet-4.6"),
  sandbox: { kind: "local-docker", image: "node:22-alpine" },
  // or: { kind: "daytona", apiKey: "..." }
});

Skills, custom tools, and memory are similarly configurable. The full config:

| Field | Required | Default | Notes | |---|---|---|---| | model | yes | — | resolved AI SDK v6 LanguageModel | | database | no | (in-memory) | when set, persists to Postgres | | sandbox | no | { kind: 'direct-system' } | one of direct-system / local-docker / daytona | | skills | no | { kind: 'noop' } | filesystem walks an org/user/repo skill tree | | memory | no | { kind: 'builtin' } | storage-backed memory provider | | systemPrompt | no | bundled | task-specific override | | extraTools | no | [] | additional tools after the built-in + memory union | | builtinAllowList | no | all | restrict registered built-ins by name |

Explicit sessions (multi-user apps)

chat() is for the simple single-thread case. When you're building a multi-user app, manage sessions explicitly:

const session = await zuno.createSession({
  orgId,
  actor: { kind: "user", userId },
});
if (!session.isOk()) throw session.error;

await zuno.storage.appendMessage({
  sessionId: session.value.id,
  role: "user",
  parts: [{ type: "text", text: "Read README.md and summarize it." }],
});
const result = await zuno.runTurn({ sessionId: session.value.id });
const stream = zuno.streamChatTurn({ sessionId: session.value.id });

Power-user subpath exports

When createZuno() is too high-level, drop down to the underlying packages via subpath:

import { createAgentLoop }       from "@zuno-ai/sdk/agent-loop";
import { createPostgresStorage } from "@zuno-ai/sdk/storage";
import { createMemoryStorage }   from "@zuno-ai/sdk/storage";
import { createFsSkillRepository } from "@zuno-ai/sdk/skills";
import { createBuiltinMemory }   from "@zuno-ai/sdk/memory";
import { translateEvent, eventsToChunks } from "@zuno-ai/sdk/stream";

Each subpath re-exports its underlying package; this lets a consumer take a single dep on @zuno-ai/sdk and avoid the workspace fan-out.

AI SDK v6 streaming in a Next.js route

streamChatTurn(...) returns a ReadableStream<UIMessageChunk> already in v6's UIMessage Stream Protocol shape:

// app/api/chat/route.ts
import { createZuno, type ZunoClient } from "@zuno-ai/sdk";

let zuno: ZunoClient;
async function getZuno() {
  zuno ??= await createZuno({ /* … */ });
  return zuno;
}

export async function POST(req: Request) {
  const { messages, sessionId } = await req.json();
  const z = await getZuno();
  // ... append the latest user message, kick off the agent ...
  const stream = z.streamChatTurn({ sessionId });
  return new Response(stream, {
    headers: {
      "content-type": "text/event-stream",
      "x-vercel-ai-ui-message-stream": "v1",
      "cache-control": "no-cache",
    },
  });
}

Browser side, plain DefaultChatTransport:

"use client";
import { useChat } from "@ai-sdk/react";
import { DefaultChatTransport } from "ai";

export function Chat() {
  const { messages, sendMessage } = useChat({
    transport: new DefaultChatTransport({ api: "/api/chat" }),
  });
  // ...
}

Embedding vs. service deployment

The SDK is for embedding Zuno in a Node app (Hono, Fastify, Express, Next.js route handlers, plain scripts). If you instead want to run Zuno as a separate service with HTTP/SSE access (Slack bridge, CLI, external products), use the apps/api-gateway deployment target — it consumes the same internal packages over HTTP. The two paths are not mutually exclusive: a single Postgres instance can host both an embedded SDK and a deployed gateway.