kuiper Docs

Agents

Glove on Kuiper

How an agent built with Glove and Glove Foundry runs on Kuiper. Which Kuiper service backs each part of the agent, what to set before the first deploy, and the steps for a personal agent, a support desk, a coding agent and a web or voice front.

On this page

Three layers#

Glove is a TypeScript framework for building agents. Kuiper runs what you build with it. An agent you deploy here has three layers:

LayerBuilt withWhat it adds
HarnessGloveThe agent loop, tools, what the model sees, what it remembers, a workspace for files and code, and the way people reach it
SystemGlove FoundryMany agents from one definition, conversations, schedules and sleep, inbound channels, approvals, an HTTP API and an inspector
ProductionKuiperSomewhere to run it, somewhere to keep its state, models, browsers, sandboxes and mail to reach, and a way to watch it

Glove's first principles page explains each part, and its primitives map lists what already exists for each one. This page covers the last layer: what Kuiper gives a Foundry app, and what you set up for it.

A Kuiper project with a Foundry unit. People and apps reach the unit over HTTPS. The unit reads and writes its /data volume, takes database URLs and secrets through variables, and calls the gateway's models, browsers, sandboxes and inbox with one key. The dashboard, CLI and MCP read its logs and runs.
A Foundry agent on Kuiper: one unit, its volume, the project's databases and secrets, and the gateway's services.

What backs what#

Each part of a Glove agent has a Kuiper service under it:

In your agentOn Kuiper
glove foundry startA unit, built from your folder or repository with no Dockerfile. See Glove Foundry units.
FileFoundryDataAdapter: instances, conversations, schedules, workspace dataA file on the unit's volume, /data. It stays across restarts and deploys.
Conversation stores, glove-memory/sqlite, working environment snapshotsFiles on /data too, or your own adapter on a managed Postgres.
Schedules, sleep and playbook subscriptionsOne running copy of the unit. Every Foundry runtime arms the schedules it finds, and a unit with a volume always runs one copy, so each schedule fires once.
createAdapter from glove-coreThe model gateway, with your own provider keys. Every call is recorded with its tokens and cost.
Glove tools that drive a browserBrowsers: real Chrome behind Steel's API, with profiles for logins.
Glove tools that run codeSandboxes from ready-made images, or Station's own container sandboxes on the unit. See Browsers and sandboxes from glove-execution.
An agent's emailA mailbox, and the Glove tools in @kuiper-sh/inbox/glove.
requestAuthorization and a bearer tokenThe unit's Inspect card and the project's Agents page, which read runs, conversations and approvals from Foundry's own API.
API keys in .envSecrets, bound into the unit's variables. They never enter the image and are redacted from logs.
Foundry's event streamLogs that survive restarts, network logs, and usage with budgets.

The built-in models, browsers, sandboxes and inbox resources give each running copy of a unit the gateway's address and a key. Reference the outputs, under names of your choosing:

OutputWhat it is
${{models.BASE_URL}}The base URL for Glove's providers, except anthropic
${{models.ANTHROPIC_BASE_URL}}The base URL for Glove's anthropic provider
${{browsers.BASE_URL}}, ${{sandboxes.BASE_URL}}, ${{inbox.BASE_URL}}The other services
${{models.API_KEY}}The running copy's gateway key. Any service's API_KEY is the same key

The key opens only the services the unit's variables reference. A unit that calls models and reads mail references both ${{models.…}} and ${{inbox.…}}. See Variables and secrets.

Before the first deploy#

A Foundry app needs four things to run well here.

  1. Keep state on the volume. Foundry's default data adapter lives in memory, and each run starts a new process, so a plain in-memory conversation store forgets earlier turns. Write both to /data:

    foundry.application.ts
    import { defineApplication, FileFoundryDataAdapter } from 'glove-foundry';
    
    export default defineApplication({
      name: 'concierge',
      data: new FileFoundryDataAdapter({ file: '/data/foundry.json' }),
      // conversationStore: a durable store, also under /data
      // requestAuthorization: see step 2
    });

    Glove's persistence guide covers the four kinds of state to keep: Foundry's data, transcripts, memory and the working environment's files.

  2. Add an authorizer. Foundry won't listen on a public address without requestAuthorization. Add an authorizer has one that accepts a bearer token and a dashboard login.
  3. Call models through the gateway. @kuiper-sh/sdk gives Glove's createAdapter its base URL and key:

    agents/concierge/agent.ts
    import { Kuiper } from '@kuiper-sh/sdk';
    import { createAdapter } from 'glove-core/models/providers';
    import { defineAgent } from 'glove-foundry';
    
    const kuiper = new Kuiper(); // reads KUIPER_GATEWAY_KEY
    
    export default defineAgent({
      description: 'Answers for Acme',
      model: () => createAdapter({ provider: 'anthropic', model: 'claude-sonnet-5-5', ...kuiper.models.glove('anthropic') }),
      systemPrompt: 'You answer questions for Acme. Use your tools for facts.',
    });
    Terminal
    kuiper providers add anthropic --key -
    kuiper env set -u concierge 'KUIPER_GATEWAY_KEY=${{models.API_KEY}}'

    Without the SDK, pass baseURL and apiKey yourself: see Models.

  4. Deploy.

    Terminal
    kuiper units create concierge
    kuiper deploy --source . -u concierge --wait

    To deploy on every push instead, kuiper link the repository. See Deploying.

Then turn on the Foundry inspector login, and generate the token the Inspect card reads with.

Deploy a harness#

The same unit takes different shapes of agent. These are the steps for four common ones.

A personal agent#

An assistant you message, that remembers you, sets reminders, browses and writes back.

  1. Give it a mailbox. Run kuiper inbox create assistant and return inboxTools(inbox, { mailbox: 'assistant' }) from the agent's tools. Example: an email agent has the code.
  2. Let it check in on its own. Foundry's built-in glove_foundry_schedule and glove_foundry_sleep tools create reminders and wake-ups. They are kept in /data and survive deploys.
  3. Give it a browser. Use Browsers from a tool, with a profile so logins carry over between sessions.
  4. Keep its memory on the volume. Point glove-memory's SQLite adapters at a file under /data.
  5. Reach it from a chat app. A chat platform that you poll, such as a bot's long-polling API, needs no public route. One that calls a webhook goes through a small forwarding unit, as in the support desk below.

A support desk#

Agents per customer that wake when a ticket or message arrives.

  1. Model the channel in Foundry. A transmission and a playbook decide which agent takes each event. See Apps and transmissions in Glove's docs.
  2. Receive the provider's webhook in a second unit. Foundry's API sits behind your authorizer, so a ticket system can't call it directly. Deploy a small web unit that checks the provider's signature and forwards the event with dispatchInbound from glove-foundry/client.
  3. Reach Foundry privately. Point the web unit at the Foundry unit's private address, which needs no public route:

    kuiper env set -u hooks 'FOUNDRY_URL=${{concierge.INTERNAL_URL}}'
  4. Keep customer data in Postgres if you outgrow files: kuiper db create postgres main, then reference ${{main.DATABASE_URL}}.

A tool that needs approval pauses the run until someone approves or denies it, in the inspector or through Foundry's API, or until the request expires.

A coding agent#

An agent that writes code and runs it somewhere other than your unit's own process. Two ways work today:

  1. Kuiper's sandboxes, from your own tools. kuiper.sandboxes.create({ image: 'kuiper/coding' }) gives a remote computer with a terminal, files and ports. It runs on separate machines, is billed by the second and can hibernate. See Sandboxes.
  2. Station's container sandboxes, on the unit. Foundry's managed Station can host ContainerSandboxAdapter from station-sandbox, which agents reach with mountSandbox from glove-execution. When your app depends on station-sandbox, the builder adds the Docker CLI and asks for a Docker socket that Kuiper serves. Start images by name, such as kuiper/coding; see Sandbox images.

A web or voice front#

A Next.js app, or a voice host, in front of durable Foundry agents.

  1. Deploy two units from one repository: the Foundry unit, with its root set to the Foundry app, and the web or voice unit with its own kuiper.json.
  2. Connect them privately with ${{concierge.INTERNAL_URL}}, as in Next.js with Foundry.
  3. Keep the voice provider's key a secret of the voice unit. The voice host hands durable work to Foundry over the private address.

Browsers and sandboxes from glove-execution#

glove-execution gives a Glove agent execute_browser and execute_sandbox. Its adapters today drive browsers and sandboxes that a Station hosts. It has no adapter for Kuiper's gateway yet.

  • Station on the unit. Foundry's stationDaemon hosts Station's container sandboxes and browsers, and the agent mounts them. On Kuiper, depending on station-sandbox or station-browser-use gives the unit a Docker socket that Kuiper serves and polices. Every container runs under gVisor within the unit's limits. Images other than Kuiper's ready-made ones must be on your operator's allowlist.
  • Kuiper's services in your own tools. Call Browsers and Sandboxes through @kuiper-sh/sdk from Glove tools you write. They run apart from your units and are held to your budgets.

Next#

On Glove's site, Put it in production walks one agent from a laptop to Kuiper, and Deploy on Kuiper is the Foundry side of this page.