Official Docker image for running Kubb Agents
10K+
Built on Nitro, it exposes REST endpoints for triggering code generation, a health check, and a bidirectional WebSocket connection to Kubb Studio. Machine tokens are derived from the machine's network identity so they survive restarts. Sessions are cached locally to speed up reconnects.
The agent server is installed as part of @kubb/cli:
bun add -D @kubb/cli
# or
pnpm add -D @kubb/cli
# or
npm install -D @kubb/cli
Start the agent server using the Kubb CLI:
kubb agent start --config kubb.config.ts
With custom options:
kubb agent start --config kubb.config.ts --host 0.0.0.0 --port 8080 --no-cache
If you need to start the server directly:
KUBB_AGENT_CONFIG=./kubb.config.ts node node_modules/@kubb/agent/.output/server/index.mjs
The server will be available at http://localhost:3000.
Run the agent standalone:
docker run --env-file .env \
-p 3000:3000 \
kubblabs/kubb-agent
A default kubb.config.ts is baked into the image at /kubb/agent/data/kubb.config.ts. To use your own config, bind-mount it over the default:
docker run --env-file .env \
-p 3000:3000 \
-v ./kubb.config.ts:/kubb/agent/data/kubb.config.ts \
kubblabs/kubb-agent
Use the provided docker-compose.yaml in packages/agent:
services:
agent:
image: kubblabs/kubb-agent:latest
container_name: kubb-agent
environment:
PORT: 80
KUBB_AGENT_ROOT: /kubb/agent/data
KUBB_AGENT_CONFIG: ./kubb.config.ts
KUBB_STUDIO_URL: https://kubb.studio
volumes:
- agent_kv:/kubb/agent/.kubb/data
restart: unless-stopped
healthcheck:
test: ['CMD', 'node', '-e', "fetch('http://localhost:3000/api/health').then(r => r.ok ? process.exit(0) : process.exit(1)).catch(() => process.exit(1))"]
interval: 15s
timeout: 10s
start_period: 60s
retries: 5
volumes:
agent_kv:
docker compose up
The agent_kv named volume persists the KV store (session cache, machine token) across container restarts and upgrades.
| Variable | Default | Description |
|---|---|---|
KUBB_AGENT_CONFIG | kubb.config.ts | Path to your Kubb config file. Relative paths are resolved against KUBB_AGENT_ROOT. |
KUBB_AGENT_ROOT | /kubb/agent (Docker) / cwd | Root directory for resolving relative paths. |
PORT | 3000 | Server port. |
HOST | 0.0.0.0 | Server host. |
KUBB_STUDIO_URL | https://kubb.studio | Kubb Studio WebSocket URL. |
KUBB_AGENT_TOKEN | (empty) | Authentication token for Studio. Required to connect. |
KUBB_AGENT_ALLOW_WRITE | false | Set to true to allow writing generated files to disk. |
KUBB_AGENT_ALLOW_ALL | false | Set to true to grant all permissions (implies KUBB_AGENT_ALLOW_WRITE=true). |
KUBB_AGENT_RETRY_TIMEOUT | 30000 | Milliseconds to wait before retrying a failed Studio connection. |
KUBB_AGENT_HEARTBEAT_URL | (empty) | URL to call every 5 minutes to signal the agent is alive (e.g. a Healthchecks.io ping URL). Leave empty to disable. |
The agent automatically loads a .env file from the current working directory into process.env on startup. Variables already set in the environment take precedence.
.env file:PORT=3000
KUBB_AGENT_ROOT=/path/to/your/project
KUBB_AGENT_CONFIG=/path/to/your/project/kubb.config.ts
KUBB_AGENT_TOKEN=your-token-here
KUBB_STUDIO_URL=https://kubb.studio
npx kubb agent start
http://localhost:3000
The agent connects to Kubb Studio on startup when KUBB_AGENT_TOKEN is set.
On startup the agent performs these steps before opening a WebSocket:
POST /api/agent/register with a stable machineToken derived from the machine's network interfaces and hostname (SHA-256). This binds the token to the machine. Registration failure is non-fatal — a warning is logged and the agent continues.POST /api/agent/session/create (includes machineToken for verification) and receives a WebSocket URL.Authorization header for authentication.| Feature | Description |
|---|---|
| Automatic reconnection | Caches session tokens to speed up reconnects |
| Real-time events | Streams generation progress and events |
| Command handling | Receives generate and connect commands from Studio |
| Graceful shutdown | Notifies Studio when disconnecting |
| Session management | 24-hour session expiration with auto-refresh; Studio re-validates every incoming message and disconnects if the session is revoked or expired |
Sessions are cached in ./.kubb/data (relative to the working directory, or agent_kv volume in Docker) for faster reconnects:
--no-cache flag to disable cachingConnected — sent in response to a connect command
{
"type": "connected",
"payload": {
"version": "x.x.x",
"configPath": "/app/kubb.config.ts",
"permissions": {
"allowAll": false,
"allowWrite": false
},
"config": {
"plugins": [{ "name": "@kubb/plugin-ts", "options": {} }]
}
}
}
Data Events — streamed during code generation
{
"type": "data",
"payload": {
"type": "plugin:start",
"data": [{ "name": "plugin-ts" }],
"timestamp": 1708000000000
}
}
Available payload.type values: plugin:start, plugin:end, files:processing:start, file:processing:update, files:processing:end, generation:start, generation:end, info, success, warn, error.
Ping — sent every 30 seconds to keep the connection alive
{ "type": "ping" }
Generate Command — triggers code generation
{
"type": "command",
"command": "generate",
"payload": { "plugins": [] }
}
payload is optional. When omitted, the agent falls back to kubb.config.studio.json (a temporal config file next to kubb.config.ts), and then to the config loaded from disk.
The payload may also include an input field containing a raw OpenAPI / Swagger spec (YAML or JSON string). This field is only honoured in sandbox mode — outside of sandbox it is silently ignored for security reasons. See Sandbox Mode below.
Connect Command — requests agent info
{
"type": "command",
"command": "connect",
"permissions": {
"allowAll": false,
"allowWrite": false
}
}
Pong — sent by Studio in response to an agent ping
{ "type": "pong" }
Status — sent by Studio with information about connected agents
{
"type": "status",
"message": "...",
"connectedAgents": 1,
"agents": [{ "name": "...", "connectedAt": "..." }]
}
When Kubb Studio provisions a session for the Sandbox Agent (the shared agent hosted by Studio itself), it sets isSandbox: true in the session response. In sandbox mode the agent behaves differently from a user-owned agent:
| behavior | Normal agent | Sandbox agent |
|---|---|---|
| Write generated files to disk | ✅ (when KUBB_AGENT_ALLOW_WRITE=true) | ❌ Never |
Read input.path from disk | ✅ | ✅ (falls back when no inline input supplied) |
Accept inline input in generate payload | ❌ Ignored | ✅ |
The sandbox agent runs in a shared, docker environment inside Kubb Studio. Allowing arbitrary disk writes would create security and isolation problems. Instead, output.write is always set to false, and the generated files are returned to Studio via the WebSocket generation:end event where the UI renders them.
input in sandbox modeBecause the sandbox agent cannot read arbitrary files from disk, callers must supply the OpenAPI / Swagger spec content inline via the input field in the generate command payload:
{
"type": "command",
"command": "generate",
"payload": {
"input": "openapi: 3.0.0\ninfo:\n title: Pet Store\n version: 1.0.0\n...",
"plugins": [{ "name": "@kubb/plugin-ts", "options": {} }]
}
}
The input value is treated as InputData (i.e. { data: "<content>" }) and overrides the input from the loaded config for that generation cycle. Outside of sandbox mode this field is ignored.
kubb.config.ts):import { defineConfig } from 'kubb'
import { pluginOas } from '@kubb/plugin-oas'
import { pluginTs } from '@kubb/plugin-ts'
export default defineConfig({
input: {
path: './openapi.json',
},
output: {
path: './src/generated',
},
plugins: [pluginOas(), pluginTs()],
})
npx kubb agent start
You'll receive a stream of events as the code generation progresses.
Kubb is an open source project, and its development is funded entirely by sponsors. If you would like to become a sponsor, please consider:
Content type
Image
Digest
sha256:8861c0ff8…
Size
65.5 MB
Last updated
9 days ago
docker pull kubblabs/kubb-agent:main-f780fe8