← stitchkitDocumentation

Getting started

stitchkit turns one contract into an HTTP API, MCP tools, AI-agent tools and a typed client. This page gets a working app running; the rest of the guide goes deep on each piece.

Requirements

  • Bun >= 1.2 (recommended) or Node.js >= 22. Bun is first-class; Node is supported via stitchkit/node.

Install

bun add stitchkit zod

zod is a required peer — schemas are the source of truth everywhere. Other peers are optional and pulled in only when you use the matching feature (@modelcontextprotocol/server for MCP servers, ai for agents, socket.io* for realtime, @tanstack/react-query + react-query-kit for React). See deps below.

Entrypoints

Every entrypoint is import-safe for one environment — keeping server-only code (Bun.serve, the MCP SDK) out of browser bundles.

Each also declares how settled it is. Stable means the shape changes rarely and only with a reason worth a migration. Evolving means the shape is still being found and may be redefined in any minor — always with a ### ⚠️ Breaking changes entry and a migration section, never silently. Both are legitimate choices; the difference is how often you should expect to read the changelog. Moving an entrypoint from evolving to stable is a decision on its own, recorded as an ADR.

Import Use in Maturity Holds
stitchkit browser and server stable defineContract, createClient, createHttpClient, createSocketIOClient, parseSSE, the error model
stitchkit/http browser, React Native/Hermes and server evolving typed HTTP client factories and ApiError, without optional realtime peers
stitchkit/realtime browser, React Native/Hermes and server evolving typed realtime clients and retained topics with a required explicit Socket.IO peer loader
stitchkit/contract browser and server stable the contract layer alone — defineContract, errors, pagination
stitchkit/live browser and server evolving defineEvents — topic declarations beside the operation contract — and watched reads: createWatchClient, the value/difference frame and its reassembly
stitchkit/primitives browser and server evolving generic values and declarations for lifecycle, access, audit, delivery and exports
stitchkit/server server (Bun) stable createServer, implement, hooks, auth, Socket.IO server, server primitives
stitchkit/node server (Node ≥ 22) stable serveNode + the runtime-agnostic core — the Node mirror of /server
stitchkit/tools server stable createMcpHandler, mountMcp, mountAgent, the OAuth provider, native tools
stitchkit/tools/mcp server (Bun or Node) evolving the canonical MCP HTTP/stdio server, schemas and typed MCP presenters; only Zod and the MCP server SDK peers
stitchkit/tools/contract browser + server evolving the shapes a tool surface speaks — async-operation contract, snapshot and cancel schemas, view-file input/output — without the runtime that serves them
stitchkit/tools/invoker server stable peer-free createToolInvoker over the canonical contract tool runner
stitchkit/tools/connections server (Bun or Node) evolving consume external MCP servers and a bounded OpenAPI subset — typed reauthorization, a per-request host fence and per-call credentials
stitchkit/cli server stable createCli / createCliInvoker — runtime and strict NodeNext declarations without MCP SDK / ai
stitchkit/cli/publish build and release tooling (Bun or Node, POSIX) evolving publishCli — commit a verified CLI distribution and move its public manifest last; see CLI guide
stitchkit/remote browser and server stable peer-free implementRemote for thin HTTP proxy processes
stitchkit/process server (Bun or Node, POSIX) evolving finite native commands, byte sinks, bounded capture, process-group cancellation and opt-in Linux/Darwin owner-loss cleanup
stitchkit/process/owner-loss bundled server entry (Bun, POSIX) evolving narrow bootstrap that keeps the process runner lazy while carrying its owner-loss guard in a single-file bundle
stitchkit/files/packaging build time (Bun or Node) evolving installed native asset graph, integrity, Bun packaging plugin and the artifact loader check; no runtime install policy
stitchkit/files server (Bun or Node) stable peer-free managed local-file boundary
stitchkit/telegram server (Bun or Node) evolving peer-free Telegram platform primitives — Mini App initData verification, send-failure classification, resumable broadcasts, the operator channel with dedupe, a Bot API transport that separates a request that never left from an unknown outcome, local Bot API files, webhook ownership and durable webhook update intake
stitchkit/telegram/html browser and server evolving Telegram’s HTML as a tree — clean any markup to what Telegram accepts, cut long text into valid parts by what the reader sees, check markup before it is sent
stitchkit/telegram/screens server (Bun or Node) evolving a bot’s menus as declared screens over grammY — typed paths, actions and input, message reconciliation, state in any StorageAdapter, a test chat
stitchkit/tracking browser and server evolving visitor-tracking mechanics — createTrackingClient, the tab-shared outbox, the page-leave beacon, attribution, the contract factory; no event vocabulary, no React
stitchkit/tracking/server server (Bun or Node) evolving the decisions a tracking backend makes — dispositions, visit lease over an application-owned store, active intervals, presence; no database
stitchkit/release browser and server evolving a page follows the release it was built for — createReleaseMarker on the server, createReleaseWatcher in the browser, the X-Build-Id header and a socket event between them
stitchkit/voice browser and server evolving the mechanics of a live voice reply — SentenceCutter, speakableText, a SpeechQueue that synthesises ahead and stops on interruption, the conversation phases
stitchkit/geo server (Bun or Node) evolving managed GeoIP reader generations, last-known-good reload and the optional MaxMind adapter
stitchkit/oauth browser and server evolving provider-neutral Authorization Code + PKCE request and one-shot callback transaction mechanics
stitchkit/google server (Bun or Node) evolving optional Google code exchange and verified OIDC identity adapter
stitchkit/observability server stable
redefined in 2 of the 56 minors since 0.56.2, most recently 0.92.0
request/tool event projections — createObservability, trace context, sanitisation
stitchkit/testing tests on Bun or Node stable in-process generated clients over a real Fetch handler, the managed-resource conformance kit and manual time for schedules and retries
stitchkit/declaration browser + build and deployment tooling (Bun or Node) evolving ProjectDeclarationSchema — the one machine-readable statement a repository makes about itself
stitchkit/react browser + server rendering stable createCursorQuery, createCacheBridge, QueryClient and ApiError retry policy
stitchkit/react/keyboard browser evolving which part of a screen gets a key — ordered layers, one Escape per level, list zones with real focus; see keyboard guide
stitchkit/agent-runtime server evolving
redefined in 23 of the 56 minors since 0.56.2, most recently 0.105.0
optional durable conversation/run loop, history, models, prompts, fencing and events
stitchkit/agent-runtime/sandbox server evolving optional Linux Bubblewrap sessions, durable workspaces and a host HTTP credential gateway; see sandbox guide
stitchkit/agent-runtime/testing tests on Bun or Node evolving credential-free replay, scripted provider faults, deterministic race controls and the agent-store conformance kit
stitchkit/agent-runtime/harness server evolving resource-aware process-local facade over the canonical Agent runtime; supervision stays outside
stitchkit/agent-runtime/coding-tools server (Bun or Node) evolving bounded host-authorized direct file and shell tools; a root boundary, not an OS sandbox
stitchkit/agent-runtime/openrouter server evolving isolated OpenRouter language-model adapter
stitchkit/agent-runtime/browser browser + server evolving canonical agent records, events, reconnect cursor and optional conversation controller
stitchkit/agent-runtime/react browser + server evolving, experimental: no committed consumer React subscription to an application-owned agent controller
stitchkit/agent-runtime/realtime server (Bun or Node) evolving, experimental: no committed consumer authorized agent control over the existing Socket.IO server
stitchkit/agent-runtime/sqlite/bun server (Bun) evolving durable built-in SQLite store for the agent runtime
stitchkit/agent-runtime/sqlite/node server (Node ≥ 22.5) evolving durable built-in SQLite store for the agent runtime
stitchkit-tui terminal (Bun) evolving optional official OpenTUI host over a caller-composed headless runtime
stitchkit/application browser + server evolving
redefined in 14 of the 56 minors since 0.56.2, most recently 0.110.0
managed resource graph, readiness, admission, schedules, subtree restart and bounded shutdown
stitchkit/application/grammy server evolving a grammY bot as application resources — configuration, then polling with updates admitted by batch — and the webhook adapter
stitchkit/application/opentelemetry server evolving maps application snapshots onto an injected OpenTelemetry Meter
stitchkit/application/schemas browser + server evolving the application’s snapshot, health and shutdown schemas alone, without the kernel
stitchkit/application/diagnostic-journal server evolving the local diagnostic journal — an exclusive bounded writer and snapshot reader with explicit anomalies
stitchkit/application/directory-inbox server evolving the directory inbox — entries another program drops into a directory, delivered to the application at least once

Rule of thumb: browser code imports stitchkit and stitchkit/react; server code adds stitchkit/server (or stitchkit/node on Node) and opts into stitchkit/tools, stitchkit/remote or stitchkit/files by capability. The full export list of each is in the API reference.

Project layout

A contract is shared by both sides, so it lives in its own folder:

src/
├── shared/contracts.ts   the contract — imported by server and client
├── server/index.ts       implement() + createServer()
└── client/api.ts         createClient()

A first app

1. Define the contract

// src/shared/contracts.ts
import { defineContract } from 'stitchkit'
import { z } from 'zod'

const Note = z.object({ id: z.string(), text: z.string() })

export const notes = defineContract({ prefix: 'notes' }, {
  list:   { method: 'GET',  path: '/',    desc: 'List notes',  output: z.array(Note) },
  create: { method: 'POST', path: '/',    desc: 'Create note', input: z.object({ text: z.string() }), output: Note },
  get:    { method: 'GET',  path: '/:id', desc: 'Get a note',  params: z.object({ id: z.string() }), output: Note },
})

2. Implement and serve

// src/server/index.ts
import { implement, createServer } from 'stitchkit/server'
import { notes } from '../shared/contracts'

const service = implement(notes, {
  list:   ()    => db.list(),
  create: (ctx) => db.create(ctx.input.text),   // ctx.input is typed
  get:    (ctx) => db.get(ctx.params.id),       // ctx.params is typed
})

createServer({ services: [service], port: 3000 })

3. Call it, typed

// src/client/api.ts
import { createClient, createHttpClient } from 'stitchkit'
import { notes } from '../shared/contracts'

export const api = createClient(notes, createHttpClient({ baseUrl: '/api' }))

await api.list()                   // GET  /notes      → Note[]
await api.create({ text: 'hi' })   // POST /notes      → Note
await api.get({ id: '1' })         // GET  /notes/1    → Note

Run the server with bun run src/server/index.ts. The contract is the single source of truth — change it and both the handler and the client are re-typed at once.

On Node

createServer is Bun’s Bun.serve. On Node ≥ 22, swap it for serveNode (from stitchkit/node, built on srvx) — the contract, implement and the client are identical:

import { serveNode } from 'stitchkit/node'

serveNode({ services: [service], port: 3000 })

Add @types/bun as a dev dependency on Node (an optional peer — it types the shared stitchkit/server surface). See deployment.

Dependencies

ky is the only bundled runtime dependency. Everything else is an optional peer — your app installs only what the features it uses need, and owns the version (one shared instance, no dual-version skew). This matrix is the install map — feature → packages:

Feature you use Install
anything (validation) zod
createServer (Bun) — (uses Bun.serve)
serveNode (Node ≥ 22) srvx (+ @types/bun dev)
In-process contract tools (stitchkit/tools/invoker) —
MCP / agent adapters (stitchkit/tools) @modelcontextprotocol/server ai
Agent application runtime (stitchkit/agent-runtime) ai
Headless Agent harness (stitchkit/agent-runtime/harness) ai
Agent coding tools (stitchkit/agent-runtime/coding-tools) —
OpenRouter runtime adapter (stitchkit/agent-runtime/openrouter) ai @openrouter/ai-sdk-provider
SQLite agent store (stitchkit/agent-runtime/sqlite/bun or /node) — (runtime built-in)
MCP host/client tests @modelcontextprotocol/client
MCP Apps UI widgets @modelcontextprotocol/ext-apps
React data layer (stitchkit/react) @tanstack/react-query react-query-kit
Keyboard layers and list zones (stitchkit/react/keyboard) react
MaxMind GeoIP (stitchkit/geo) maxmind
Browser OAuth client (stitchkit/oauth) —
Google OIDC verifier (stitchkit/google) google-auth-library
Socket.IO server on Bun socket.io @socket.io/bun-engine
Socket.IO server on Node socket.io
Socket.IO client socket.io-client (runtime peer; unrelated root declarations remain peer-free)
grammY lifecycle adapters (stitchkit/application/grammy) grammy
Telegram platform primitives (stitchkit/telegram) — (peer-free)
Telegram message markup (stitchkit/telegram/html) — (peer-free)
Telegram screens (stitchkit/telegram/screens) grammy (types only; the bot brings it)
OpenTelemetry gauges (stitchkit/application/opentelemetry) @opentelemetry/api
bun add socket.io @socket.io/bun-engine    # e.g. the Socket.IO server on Bun

Dynamic optional-peer adapters fail with an actionable error naming the package and install command. Static entrypoints such as stitchkit/tools fail during ESM resolution by naming the exact missing package; the feature-to-peer matrix below is the canonical install command.

The combined tools entry owns MCP and AI-agent adapters, so install both runtime peers before importing stitchkit/tools:

bun add @modelcontextprotocol/server@^2 ai@^7

Browser, HTTP-client and React entrypoints remain usable without either MCP package. MCP hosts and client E2E additionally install @modelcontextprotocol/client@^2; Apps additionally install @modelcontextprotocol/ext-apps.

Next

For a complete production-shaped app, run bun create stitchkit my-app. The canonical generated topology is maintained in packages/create-stitchkit/template.

For a terminal Agent host instead, run bun create stitchkit my-agent --template agent, copy .env.example to .env, set OPENROUTER_API_KEY, then run bun run dev and choose a live tool-capable model with /model. The provider catalog owns the exact model id and context window and presents weekly popularity separately from sourced benchmark observations; OPENROUTER_MODEL is only an optional preferred row. That profile is a thin stitchkit.agent.ts composition over the official stitchkit-tui package and canonical headless harness: durable SQLite history, lazy skills, direct coding tools, approval continuations and recovery stay framework-owned primitives, while model choice, permissions, executables and OS isolation remain application policy.