JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 24
  • Score
    100M100P100Q86156F
  • License MIT

Define and serve shared human-AI experiences — tools, canvas, state, dev server

Package Exports

  • @vibevibes/sdk

Readme

@vibevibes/sdk

Primitives for building shared human-AI experiences — interactive apps where humans and AI agents collaborate in real-time through shared state, shared tools, and a shared canvas.

npm license

Install

npm install @vibevibes/sdk

Peer dependencies: react (18 or 19), zod. Optional: yjs.

Quick Start

import { defineExperience, defineTool } from "@vibevibes/sdk";
import { z } from "zod";

const tools = [
  defineTool({
    name: "counter.increment",
    description: "Add to the counter",
    input_schema: z.object({
      amount: z.number().default(1),
    }),
    handler: async (ctx, input) => {
      const count = (ctx.state.count || 0) + input.amount;
      ctx.setState({ ...ctx.state, count });
      return { count };
    },
  }),
];

function Canvas({ sharedState, callTool }) {
  return (
    <div>
      <h1>{sharedState.count || 0}</h1>
      <button onClick={() => callTool("counter.increment", { amount: 1 })}>
        +1
      </button>
    </div>
  );
}

export default defineExperience({
  manifest: {
    id: "counter",
    version: "0.0.1",
    title: "Counter",
    description: "A shared counter",
    requested_capabilities: [],
  },
  Canvas,
  tools,
});

That's a complete experience. Humans click the button. Agents call the same tool via MCP. Both mutate the same state. Both see the same canvas.

Core Concepts

Tools are the only way to mutate state. Every tool has a Zod schema and a handler that calls ctx.setState(). Humans use tools via the Canvas. Agents use the same tools via MCP. No backdoors.

Canvas is a React component. It receives current shared state and a callTool function. Re-renders on every state change.

Agents are actors, not assistants. They join rooms, watch for events, react with tools, and persist memory. Same participation model as humans.

Tool Handler Context

type ToolCtx = {
  roomId: string;
  actorId: string;        // Who called this tool
  owner?: string;         // Owner extracted from actorId
  state: Record<string, any>;     // Current shared state (read)
  setState: (s) => void;          // Set new state (write)
  timestamp: number;
  memory: Record<string, any>;    // Agent's persistent memory
  setMemory: (updates) => void;
};

Always spread existing state: ctx.setState({ ...ctx.state, key: value }).

Canvas Props

type CanvasProps = {
  actorId: string;
  sharedState: Record<string, any>;
  callTool: (name: string, input: any) => Promise<any>;
  participants: string[];
  ephemeralState: Record<string, Record<string, any>>;
  setEphemeral: (data: Record<string, any>) => void;
  stream?: (name: string, input: Record<string, unknown>) => void;
};

Hooks

Hook Returns Purpose
useToolCall(callTool) { call, loading, error } Loading/error tracking
useSharedState(state, key, default?) value Typed state accessor
useOptimisticTool(callTool, state) { call, state, pending } Optimistic updates with rollback
useParticipants(participants) ParsedParticipant[] Parse actor IDs
useAnimationFrame(state, interpolate?) displayState Frame-rate buffering

Components

Inline-styled (no Tailwind needed): Button, Card, Input, Badge, Stack, Grid

Agent Slots

manifest: {
  agentSlots: [{
    role: "game-master",
    systemPrompt: "You are the game master.",
    allowedTools: ["world.narrate"],
    autoSpawn: true,
    maxInstances: 1,
  }],
}

Tests

import { defineTest } from "@vibevibes/sdk";

tests: [
  defineTest({
    name: "increment adds to count",
    run: async ({ tool, ctx, expect }) => {
      const inc = tool("counter.increment");
      const c = ctx({ state: { count: 5 } });
      await inc.handler(c, { amount: 3 });
      expect(c.getState().count).toBe(8);
    },
  }),
]

Architecture

Browser (Canvas)  <--WebSocket-->  Server  <--HTTP-->  MCP (Agent)
      |                              |
  callTool(name, input)     validates input (Zod)
                            runs handler(ctx, input)
                            ctx.setState(newState)
                            broadcasts to all clients

Ecosystem

Package Description
@vibevibes/sdk Define experiences — tools, canvas, state
@vibevibes/mcp Runtime engine — MCP server + WebSocket + viewer
@vibevibes/create npx @vibevibes/create — scaffold in seconds
experiences Example experiences — fork and remix

License

MIT