npm.io
0.1.2 • Published 1h ago

@webacp/persistence

Licence
MIT
Version
0.1.2
Deps
1
Size
16 kB
Vulns
0
Weekly
0

WebACP

A TypeScript-first SDK for building MCP/ACP chat apps — bring your own CLI agent (Claude, Cursor, Codex, Gemini, …), define your own tools, and route execution between your server and the user's machine.

Think "LangChain for MCP + ACP": the @webacp/* packages are the product; the apps/ are a reference implementation built on top of them.

Packages

Package Purpose
@webacp/protocol JSON wire contracts (pairing, chat events, generic tool.call/tool.result). Language-neutral.
@webacp/core ACP engine: provider presets, connect/spawn, event adapter, persistent per-thread session manager + model selection.
@webacp/tools Tool SDK: defineTool / defineToolPack (runtime: 'server' | 'local') + MCP exposer.
@webacp/tools-fs Built-in runtime: 'local' filesystem + shell pack.
@webacp/server Framework-agnostic server core: createWebacpServer(), dual MCP hosts, pairing, chat SSE, threads. Hono adapter.
@webacp/agent Local daemon as a library: createLocalAgent({ toolPacks }) + webacp-agent bin.
@webacp/persistence Thread/message store interface + SQLite (bun:sqlite) and in-memory adapters.
@webacp/react Headless hooks: useChat, useThreads, useAgentStatus, useModelSelector.
@webacp/ui Themed chat UI on shadcn-compatible CSS variables + Tailwind. Drop-in WebacpChat or compose primitives.

Theming (rebrand with CSS variables)

@webacp/react = data. @webacp/ui = look. Consumers override tokens only:

/* your-theme.css */
@import "@webacp/ui/theme/default.css"; /* or theme/light.css */

:root {
  --primary: oklch(0.58 0.22 300);
  --font-sans: "Geist", system-ui, sans-serif;
  --radius: 0.75rem;
}
import { WebacpChat } from '@webacp/ui';

export function App() {
  return <WebacpChat brand={{ title: 'My App' }} />;
}

Compose your own layout with primitives: ThreadSidebar, MessageList, Composer, ToolCard, etc.

The CLI agent connects to two MCP endpoints. Each tool declares where it runs.

CLI agent ──> /mcp/server ──> server tools (context, RAG, connectors)  [run in your server]
          └─> /mcp/local  ──WS──> local agent ──> local tools (fs, shell) [run on user machine]
  • runtime: 'server' tools execute in the web/server process.
  • runtime: 'local' tools are routed over WebSocket to the local agent.

A local pack must be registered in both places: on the server (for tool schemas exposed at /mcp/local) and on the agent (for the handlers that run).

Consumer DX

// your server
import { createWebacpServer, defineTool, defineToolPack } from '@webacp/server';
import { sqliteAdapter } from '@webacp/persistence';
import { fsPack } from '@webacp/tools-fs';
import { z } from 'zod';

const memory = defineToolPack({
  name: 'memory', runtime: 'server',
  tools: [defineTool({
    name: 'search_memory', input: z.object({ q: z.string() }),
    handler: async ({ q }) => ({ hits: [q] }),
  })],
});

const wac = createWebacpServer({
  serverToolPacks: [memory],
  localToolPacks: [fsPack],
  persistence: sqliteAdapter('./webacp.db'),
  publicUrl: 'http://127.0.0.1:3000',
});

Bun.serve({ port: 3000, fetch: wac.fetch, websocket: wac.websocket });
// your local agent (or just run ours)
import { createLocalAgent } from '@webacp/agent';
import { fsPack } from '@webacp/tools-fs';
createLocalAgent({ toolPacks: [fsPack] }).start();

A complete runnable example lives in examples/custom-app.

Reference app (dev)

bun install

# Terminal 1 — web (server :3000 + UI :5173)
bun run dev

# Terminal 2 — install agent as a background service (once)
bun run install:agent
# Or: webacp-agent install

# Check status / update later
webacp-agent status
webacp-agent update          # git pull (dev) or bun update -g (published)
webacp-agent update --check
webacp-agent uninstall

The agent auto-starts on login (launchd on macOS, systemd on Linux). Pairing creds live in ~/.webacp/credentials.json — pair once, keep forever.

Updates run on triggers (not a background timer): when you pair, send a chat, or the web UI hits connect — the agent checks git pull (dev) or npm latest and restarts if needed. Disable with WEBACP_UPDATE_ON_TRIGGER=0 in ~/.webacp/env.

Open http://localhost:5173. The UI auto-pairs with the local agent (no token copy/paste), persists threads, and lets you switch CLI provider + model.

Prerequisites: Bun ≥ 1.0, an ACP CLI agent, and its auth (e.g. claude login or agent login for Cursor).

Scripts

Command Description
bun run dev Run the reference web app (server + Vite UI)
bun run dev:agent Run the reference local agent
bun run install:agent Install webacp-agent to ~/.webacp/bin + background service
webacp-agent status Service + pairing + update status
webacp-agent update Pull latest and restart service
bun run typecheck Typecheck every workspace package
bun run build:libs Build all @webacp/* libraries to dist/

Env

Var Default Description
WEBACP_PUBLIC_URL http://127.0.0.1:3000 URL the CLI agent uses to reach MCP endpoints
WEBACP_WEB_URL http://127.0.0.1:3000 Web server URL the local agent connects to
WEBACP_PAIR_TOKEN One-time pairing token (auto-handled by the UI)
WEBACP_PAIR_PORT 9333 Local agent's auto-pair HTTP port
WEBACP_DB ./webacp.db SQLite path for the reference server
WEBACP_CONFIG_DIR ~/.webacp Local agent credential dir
WEBACP_UPDATE_ON_TRIGGER 1 (enabled) Set 0 to disable trigger-based auto-updates

Status

Out of scope for now (protocol kept language-neutral to enable later): a Python SDK/agent, richer event UI (plan/thought/tool-result cards), auth, and multi-device sync.