All Packages

Glove is a monorepo of small, independently versioned packages. Nothing here is required except the runtime — you install the pieces the app actually needs, and each one has a single job. This page is the tour: what each package solves, how to install it, and the smallest snippet that puts it to work.

Everything below assumes you already have an agent — either a Glove builder or a built runnable. If not, start with the Quickstart. Deployment (glovebox-*) has its own guide and is only summarised here.

The map

FamilyPackagesUse it when
Runtimeglove-core, glove-react, glove-nextAlways — this is the framework.
Voiceglove-voice, -native, -s2s, -avatar, -livekitThe interface is speech, not typing.
Memory & dataglove-memory, glove-scratchpad, glove-sqlThe agent must remember, or must reason over more data than fits in context.
Sandboxesglove-working-environment, glove-env-*The agent produces artifacts — documents, spreadsheets, decks, media.
Code executionglove-js, glove-python, glove-lisp, glove-egressDozens of tools would blow the context window, or data must not leak.
Generative mediaglove-imageThe agent generates and refines images — recurring characters, scenes, references.
Coordinationglove-mesh, glove-continuum-signalMore than one agent, or agents that run on a schedule.
Integrationglove-mcpYou want tools you did not write.
Deploymentglovebox-core, -kit, -clientShip the agent as an isolated, addressable service.

Runtime

glove-core

the runtime

The agent loop, tool execution, model adapters, the display manager, stores, subscribers, hooks, skills and subagents. Everything else in this list plugs into it. Works in Node and in the browser.

terminalbash
pnpm add glove-core zod
agent.tstypescript
import { Glove, MemoryStore, Displaymanager, createAdapter } from "glove-core";
import { z } from "zod";

export const agent = new Glove({
  store: new MemoryStore("session-1"),
  model: createAdapter({ provider: "anthropic", model: "claude-sonnet-4-20250514" }),
  displayManager: new Displaymanager(),
  systemPrompt: "You are a helpful assistant.",
  compaction_config: { compaction_instructions: "Summarize the conversation so far." },
})
  .fold({
    name: "get_weather",
    description: "Get current weather for a city",
    inputSchema: z.object({ city: z.string() }),
    async do(input) {
      return { status: "success", data: await weather.lookup(input.city) };
    },
  })
  .build();

await agent.processRequest("What's the weather in Tokyo?");

Core API reference · Server-side agents

glove-react

React bindings

Hooks and components for the client: GloveClient, GloveProvider, useGlove, <Render>, defineTool for typed tools and display props, plus createRemoteStore. Bundles glove-core.

terminalbash
pnpm add glove-react zod
app/chat.tsxtsx
"use client";
import { useGlove, Render } from "glove-react";

export function Chat() {
  const glove = useGlove();
  return <Render glove={glove} renderMessage={({ entry }) => <p>{entry.text}</p>} />;
}

React reference · Display stack

glove-next

Next.js route handlers

One function that turns a route into a streaming (SSE) chat endpoint, holding your provider key server-side. Supports every provider the core adapter factory does, plus prompt caching and reasoning options.

terminalbash
pnpm add glove-next
app/api/chat/route.tstypescript
import { createChatHandler } from "glove-next";

export const POST = createChatHandler({
  provider: "anthropic",
  model: "claude-sonnet-4-20250514",
  cache: true,
});

Next.js reference

Voice

glove-voice

cascade pipeline

The classic pipeline — VAD → STT → agent → TTS — with barge-in, push-to-talk, narration control and speech-gated noise robustness (mic audio only reaches the STT provider once the VAD confirms speech). ElevenLabs adapters ship in the box; the contracts are open.

terminalbash
pnpm add glove-voice
app/voice.tsxtsx
import { createElevenLabsAdapters } from "glove-voice";
import { useGloveVoice } from "glove-react/voice";

const { stt, createTTS } = createElevenLabsAdapters({
  // Tokens are minted server-side — the API key never reaches the browser.
  getSTTToken: () => fetch("/api/voice/stt-token").then(r => r.json()).then(d => d.token),
  getTTSToken: () => fetch("/api/voice/tts-token").then(r => r.json()).then(d => d.token),
  voiceId: "JBFqnCBsd6RMkjVDRZzb",
});

const { runnable } = useGlove({ tools, sessionId });
const voice = useGloveVoice({ runnable, voice: { stt, createTTS } });
// voice.mode: "idle" | "listening" | "thinking" | "speaking"

Voice guide

glove-voice-native

React Native / Expo

The pipeline is platform-neutral; only mic capture and playback are platform edges. This package supplies them for iOS and Android, backed by react-native-audio-api and onnxruntime-react-native (Silero VAD on-device).

terminalbash
pnpm add glove-voice-native
VoiceScreen.tsxtsx
import { withNativeAudio } from "glove-voice-native";
import { SileroVADNativeAdapter } from "glove-voice-native/silero-vad";

const vad = new SileroVADNativeAdapter();
await vad.init();

const voice = useGloveVoice({
  runnable,
  voice: withNativeAudio({ stt, createTTS, vad }),
});

React Native & Expo

glove-voice-s2s

speech-to-speech

Run a built Glove agent directly on a realtime speech-to-speech model (OpenAI Realtime, Gemini Live). The cascade's ~1.3–1.6s voice-to-voice collapses to ~500–800ms, turn-taking is decided by the model listening, and your tools run unchanged through the same Tool.run.

terminalbash
pnpm add glove-voice-s2s
realtime.tstypescript
import { RealtimeAgent, createS2SAdapter } from "glove-voice-s2s";

// Provider/model/credentials from args, falling back to S2S_* env vars.
const adapter = createS2SAdapter({ provider: "openai" });

const rt = new RealtimeAgent({ agent, adapter });
await rt.start();

// Push a result in from elsewhere and have the agent speak about it.
rt.inject("The order shipped.", { respond: true });

Realtime voice & avatars

glove-voice-avatar

a face over the voice

An avatar provider is a lip-sync renderer over an audio stream — the same shape as the PCM a transport-mode S2S adapter already emits. attachAvatar is the one-call bridge; Tavus (echo mode) and Anam (audio passthrough) adapters ship, both passing the conformance suite.

terminalbash
pnpm add glove-voice-avatar
avatar.tstypescript
import { TavusEchoAdapter, attachAvatar } from "glove-voice-avatar";

const avatar = new TavusEchoAdapter({
  apiKey: process.env.TAVUS_API_KEY!,   // server-side only
  faceId: process.env.TAVUS_FACE_ID!,
  // palId omitted → a minimal echo PAL is ensured, so the ONLY voice is the agent's.
  sendInteraction: (event) => duct.send({ t: "avatar_interaction", event }),
});

const detach = await attachAvatar(rt, avatar);
avatar.view; // { kind: "webrtc-room", url: … } — hand this to the client

Avatars

glove-voice-livekit

LiveKit transport + avatars

LiveKit as an adapter rather than a rewrite. LiveKitTransport is the room leg — join, publish the agent's voice as a paced track, feed remote mics back as PCM, carry JSON on the data channel, with server-authoritative barge-in. The LiveKit Tavus/Anam avatars join your room as a second participant.

terminalbash
pnpm add glove-voice-livekit
room.tstypescript
import { LiveKitTransport, attachRealtime, mintParticipantToken } from "glove-voice-livekit";

const transport = new LiveKitTransport({
  url: process.env.LIVEKIT_URL!,
  token: await mintParticipantToken(
    { apiKey: process.env.LIVEKIT_API_KEY!, apiSecret: process.env.LIVEKIT_API_SECRET! },
    { roomName: "call-42", identity: "agent" },
  ),
});

await transport.connect();
attachRealtime(rt, transport);   // mics → model, model → track, interrupt → flush
await rt.start();

LiveKit

Memory & data

glove-memory

long-term memory

Five orthogonal subsystems, each an independent bring-your-own-storage adapter with its own tool surface: an entity graph (typed nodes with deterministic identity keys), episodic memory (an append-only, time-indexed, semantically searchable timeline), resources (a POSIX-style virtual filesystem the agent walks with ls/read/grep), context (the user's standing brief, injected into the system prompt every turn), and forms (structured collection over a conversation — Zod-authored definitions, lazily loaded, with colocated executors).

terminalbash
pnpm add glove-memory
memory.tstypescript
import {
  useMemoryReader, useEpisodicReader, useContext,
  InMemoryEntityAdapter, InMemoryEpisodicAdapter, InMemoryContextAdapter,
} from "glove-memory";

// Reference in-memory adapters ship for dev/test; implement the contracts
// (EntityMemoryAdapter, EpisodicMemoryAdapter, …) against your own storage.
const entities = new InMemoryEntityAdapter({ schema: ontology });

useMemoryReader(agent, entities);                      // read-only entity tools
useEpisodicReader(agent, new InMemoryEpisodicAdapter());
useContext(agent, new InMemoryContextAdapter());       // injected every turn

// Writes belong to a separate curator instance:
// useMemoryCurator(curator, entities);
forms.tstypescript
import { FormRegistry } from "glove-memory/forms";
import { useFormRunner, InMemoryFormAdapter } from "glove-memory";

const registry = new FormRegistry().register("travel-claim", {
  name: "Travel reimbursement claim",
  description: "Claimant, trip, travel and approval details.",
  load: () => import("./forms/travel-claim").then((m) => m.travelClaim),
});

// Folds seven glove_form_* tools and injects the one-line tier-0 status
// into the system prompt each turn.
const { runner } = useFormRunner(agent, new InMemoryFormAdapter({ schema }), {
  registry,
  subject: conversationId,
});

The recommended shape is not to hang every memory tool off the main agent: build one subagent per retrieval task with defineSubAgent so each attaches only the adapter slice it needs and token cost scales with role, not with ontology size. Writes belong to a separate curator instance running over conversation history.

Memory reference · Why Memory

glove-scratchpad

tools as a database

A database emulator for LLM tool use. Resources become tables and the agent drives everything through one execute_sql tool: information_schema is discovery, WHERE clauses push arguments down to your handlers, transactions stage outbound effects as a real dry-run, and every statement is parsed before any tool runs. Benchmarked at up to 35× less context than equivalent tool definitions.

terminalbash
pnpm add glove-scratchpad
scratchpad.tstypescript
import { Database, defineResource, mountDatabase } from "glove-scratchpad";
import { z } from "zod";

const db = await Database.create({ policy: { writes: true } });

db.register(defineResource({
  name: "github_pull_requests",
  volatility: "volatile",
  schema: z.object({
    number: z.number().int(),
    title: z.string(),
    state: z.string().describe("open | merged | closed"),
  }),
  keys: ["number"],
  // WHERE state = 'open' arrives as a binding — an argument, not a post-filter.
  select: (b) => github.listPRs({ state: b.one("state") }),
}));

mountDatabase(agent, { db });   // folds execute_sql + explain_sql, primes the prompt

Scratchpad guide

glove-sql

the SQL engine

A zero-dependency, pure-JS Postgres-subset engine: runtime-built tables, joins, CTEs, set operations, subqueries and window functions, serialisable to bytes. It is the default backend for the scratchpad, and usable on its own wherever you want SQL without a database.

terminalbash
pnpm add glove-sql
sql.tstypescript
import { MemoryBackend } from "glove-sql";

const be = await MemoryBackend.create();
await be.exec(`CREATE TABLE orders (id int, total numeric, region text)`);
await be.exec(`INSERT INTO orders VALUES (1, 42.00, 'emea')`);

const { rows } = await be.query(
  `SELECT region, sum(total) AS revenue FROM orders GROUP BY region`,
);

const bytes = await be.dump();   // serialise the whole database

SQL engine reference

Sandboxes

glove-working-environment

persistent VFS

A small, fast, in-memory sandboxed working environment: a virtual filesystem where state accumulates across tool calls. The agent writes scripts, runs them, inspects intermediates and iterates — with no networking, no host filesystem and no process spawning, because scripts only see the capabilities you inject. Zero-dependency core.

terminalbash
pnpm add glove-working-environment
env.tstypescript
import { createWorkingEnvironment, mountWorkingEnvironment } from "glove-working-environment";
import { spreadsheets } from "glove-env-spreadsheets";

const env = await createWorkingEnvironment({
  stdlib: [spreadsheets()],
  limits: { runTimeoutMs: 30_000 },
});

await env.mount("./q3.xlsx", "/inbox/q3.xlsx");   // host-side door
mountWorkingEnvironment(agent, { env });          // model-facing verbs + preamble

const deliverables = await env.export("/out/**"); // → [{ path, bytes }]

Back the tree with memory, a real directory (hostDirectory, copy-on-write), a snapshot, or object storage (cachedRemote). Expose your own libraries to the model with defineAdapter (I/O), defineBuilder (stateful builder APIs), or definePureModule (pure, synchronous computation) — and your own capabilities, an MCP server or a plain async function, with defineTools.

Working environment guide

glove-env-*

stdlib adapters

An adapter bridges a real host library into the tree; the model experiences it as a typed importable module plus docs at /std/<name>/. Install only the formats your agent handles.

PackageModuleGives the model
glove-env-documentsenv:documentsOne document spec → PDF and DOCX; describe / merge / split / stamp; text extraction
glove-env-spreadsheetsenv:spreadsheets.xlsx as plain-JSON records; write, append, CSV bridging, plus exceljs's own Workbook
glove-env-imagesenv:imagesDescribe without decoding; resize / convert / crop / rotate / composite / contact sheets
glove-env-slidesenv:slidesPowerPoint decks from a spec, read back independently — outline, slide text, notes
glove-env-zipenv:archiveszip / tar / tar.gz in and out, traversal- and bomb-safe. No dependencies
glove-env-mediaenv:mediaVideo and audio via ffmpeg: describe, thumbnail, frames, clip, concat, transcode
glove-env-renderenv:renderRasterize a PDF, deck or Word file to page PNGs — so the agent can look at what it made
glove-env-motionenv:motionA React scene → mp4, GIF, PNG frames or a still, rendered deterministically. Reanimated scenes work unchanged
env.tstypescript
import { documents } from "glove-env-documents";
import { images } from "glove-env-images";

const env = await createWorkingEnvironment({ stdlib: [documents(), images()] });

Stdlib adapters

Code execution

Three surfaces over the same ToolFn catalog — one set of functions mounts on any of them unchanged. Pick the language your models are most fluent in.

glove-js

one execute_js tool

A sandboxed JavaScript interpreter (acorn parse → whitelist validation → fuel-budgeted evaluation). The model discovers capabilities in-band, keeps big intermediates in the REPL instead of its context, and can branch — decide-and-act — inside a single call.

terminalbash
pnpm add glove-js glove-scratchpad
js.tstypescript
import { JsSession, mountJs } from "glove-js";
import { fnsFromMcp } from "glove-scratchpad/fns/mcp";

const session = JsSession.create();
session.registerAll(await fnsFromMcp(githubConn));  // github__list_pull_requests, …

mountJs(agent, { session });

Code execution guide

glove-python

one execute_python tool

The same surface in Python — the language most models reach for when the task is “manipulate this data”. Keyword arguments, list comprehensions, f-strings; the same discovery tiers and the same off-context data flow.

terminalbash
pnpm add glove-python glove-scratchpad
py.tstypescript
import { PySession, mountPy } from "glove-python";

const session = PySession.create();
session.registerAll(await fnsFromMcp(githubConn));

mountPy(agent, { session });

glove-lisp

one execute_lisp tool

A tiny Clojure-flavored Lisp over the same catalog, plus the scratchpad's ResourceTable contract — so it can also stage several outbound effects, preview them, and commit! or rollback! as a real dry run.

terminalbash
pnpm add glove-lisp glove-scratchpad
agent-program.cljclojure
;; What the model writes inside execute_lisp
(def prs (github_pull_requests {:state "open"}))   ; 320 rows stay in the REPL
(if (empty? (pagerduty_incidents {:urgency "high"}))
  (insert! :slack_messages {:channel "ops" :text "All clear."})
  (insert! :emails {:to_addr "oncall@acme.io" :subject "Incidents live"}))

glove-egress

measured privacy boundary

The one-eval-tool boundary already makes an agent context-efficient. This package makes it a privacy boundary and gives you the instruments to measure it: quantitative-information-flow metering, an enforced egress gate where programs must end in a bounded decision, and red-team extraction simulation.

terminalbash
pnpm add glove-egress
egress.tstypescript
import { egressFns, guardEffectFns, DEFAULT_EGRESS_POLICY, BoundaryMeter } from "glove-egress";

session.registerAll(egressFns(DEFAULT_EGRESS_POLICY));  // assert/count/choose/bucket/report
const guarded = guardEffectFns(catalog, DEFAULT_EGRESS_POLICY, onBlock);

const meter = new BoundaryMeter();
meter.cross("assertion", true, { decisionSpace: 2 });
meter.report(canaries);  // what actually crossed

Egress control

Generative media

glove-image

agentic image generation

Image generation as a workflow rather than a single call: a prompt pipeline of enhancer inbetweens, durable characters and scenes spliced verbatim into every prompt, reference images with roles, editing, deterministic assembly, an optional vision model to review its own output, and per-call cost tracking. The image model is an adapter you bring.

terminalbash
pnpm add glove-image
image.tstypescript
import {
  mountImage,
  InMemoryImageAssetStore,
  InMemoryImageLibrary,
  expandCharacters,
  expandScenes,
  styleDirective,
  openrouterImages,
} from "glove-image";

await mountImage(glove, {
  adapter: openrouterImages(),               // OPENROUTER_API_KEY
  assets: new InMemoryImageAssetStore(),
  library: new InMemoryImageLibrary(),
  pipeline: [expandCharacters(), expandScenes(), styleDirective("gouache, muted palette")],
});

// The agent then works in asset ids:
//   glove_image_character_save({ name: "mira", appearance: "..." })
//   glove_image_generate({ intent: "Mira at the harbor", characters: ["mira"] })
//   glove_image_regenerate({ asset: "img_...", tweak: "at dusk" })

Image workflows guide

Coordination

glove-mesh

agents talking

Direct, broadcast and acknowledged messaging between agents, riding the same inbox primitive the core already has, over a transport you bring (in-process, Redis, a queue, HTTP).

terminalbash
pnpm add glove-mesh
mesh.tstypescript
import { mountMesh, MeshNetwork, InMemoryMeshAdapter } from "glove-mesh";

const network = new MeshNetwork();

await mountMesh(planner, {
  adapter: new InMemoryMeshAdapter(network),
  identity: {
    id: "planner",
    name: "Planner",
    description: "Breaks work down and hands it to specialists.",
    capabilities: ["planning"],
  },
});

// Folds glove_mesh_send_message / _broadcast / _list_agents / _acknowledge.
// Inbound messages land in this agent's inbox and surface on its next turn —
// so the store must support the inbox methods.

Mesh guide · The inbox

glove-continuum-signal

subprocess runtime

Discovery, supervision, observability and IPC for agents running as subprocesses. Triggered agents are cold and wake per event (a call, a schedule fire, an inbound mesh message), resume their persistent store, run a turn and exit. Concurrent agents stay warm and are notified inline.

terminalbash
pnpm add glove-continuum-signal
agents/baker.tstypescript
import { agent, z, ContinuumRunner, MemoryAdapter } from "glove-continuum-signal";

export const pizzaBaker = agent("pizza-baker")
  .input(z.object({ orderId: z.string() }))
  .triggered()
  .timeout(60_000)
  .retries(2)
  .every("5m").withInput({ orderId: "tick" })
  .factory(async (ctx) => buildGlove(ctx));

const runner = new ContinuumRunner({ adapter: new MemoryAdapter() });
runner.registerAgent(pizzaBaker, import.meta.url);
await runner.start();

Continuum guide

Integration

glove-mcp

Model Context Protocol

Bridge any MCP server's tools into an agent as first-class tools. A discovermcp subagent lets the model find and activate servers from a catalogue mid-conversation. The framework's only auth seam is getAccessToken(id) — for the spec OAuth flow, glove-mcp/oauth ships an opt-in runner and reference stores.

terminalbash
pnpm add glove-mcp
mcp.tstypescript
import { mountMcp } from "glove-mcp";

await mountMcp(runnable, {
  adapter: myAdapter,          // getActive / activate / deactivate / getAccessToken
  entries: [{
    id: "notion",
    name: "Notion",
    description: "Search, read, and edit pages in a Notion workspace.",
    url: "https://mcp.notion.com/mcp",
    tags: ["docs", "notes", "wiki"],
  }],
  clientInfo: { name: "my-app", version: "1.0.0" },
});

MCP guide

Deployment

glovebox-core (authoring kit + glovebox build CLI), glovebox-kit (the in-container runtime) and glovebox-client (the client SDK) package an agent as an isolated, network-addressable service: one authenticated WebSocket endpoint per session, files crossing the wire as FileRef rather than raw bytes, and a storage policy DSL that routes payloads by size.

It is a bigger surface than the rest of this page and has a guide of its own → Glovebox, with a worked example in the showcase.

Deprecated

glove-sqlite

deprecated

The SQLite StoreAdapter. Still published and still works, but it receives no new features — implement StoreAdapter against whatever storage your app already runs instead. The contract is small and documented in the Core API reference.