heyvm-setup
Heyvm is one of three sandbox backends an agent can run in (tensorlake,
vercel, heyvm). It's the only option that gives you a persistent
sandbox — one that survives across runs and threads — and it's wired through
to all of Flapjack's Remote Control surfaces (HTTP, SDK, MCP).
This guide is operational: how to configure the runtime, how to set the provider on an agent from each surface, and how to verify the round-trip.
When to pick heyvm
| You want… | Provider |
|---|---|
| The default — fast, ephemeral, Python-flavoured exec | tensorlake |
| A Node 24 microVM that boots quickly and dies with the thread | vercel |
| A sandbox that persists across threads / runs (long-lived dev env) | heyvm |
To bring your own endpoint (mode: 'custom') | heyvm |
mode: 'persistent' requires provider: 'heyvm'; the UI enforces this.
Runtime configuration
Set in the Flapjack runtime environment (Vercel project env, or local
.env.local):
| Variable | Required | Notes |
|---|---|---|
HEYVM_API_KEY | yes | API key for https://server.heyo.computer. Issued from the Heyo dashboard. |
HEYO_API_KEY | deprecated | Read as a fallback if HEYVM_API_KEY is unset. The adapter logs a warn and continues. Will be removed in a future release. |
Local-dev fallback: if neither env var is set, the adapter reads the JWT
from ~/.heyo/token.json (created by heyvm login). This is a
convenience for running Flapjack locally; production should always use
HEYVM_API_KEY.
Setting the provider on an agent
Four ways, all hit the same PUT /api/agents/:id/computer endpoint:
1. UI
Open the agent's settings → Computer → provider dropdown → pick
heyvm. Persisted to agent_computer_config.provider.
2. HTTP
curl -X PUT "$BASE/api/agents/$AGENT_ID/computer" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"enabled": true,
"provider": "heyvm",
"mode": "persistent",
"scope": "agent",
"sizeClass": "small"
}'
3. SDK (@flapjack/sdk)
import { FlapjackClient } from '@flapjack/sdk';
const client = new FlapjackClient({ apiKey, baseUrl });
await client.updateAgent(agentId, {
computer: {
enabled: true,
provider: 'heyvm', // 'tensorlake' | 'vercel' | 'heyvm'
mode: 'persistent',
scope: 'agent',
sizeClass: 'small',
},
});
The provider field is typed as ComputerProvider
('tensorlake' | 'vercel' | 'heyvm') on both ComputerConfig (read) and
UpdateComputerConfig (write).
4. MCP (flapjack_update_computer_config)
Available to any LLM connected via Flapjack's MCP server:
{
"name": "flapjack_update_computer_config",
"arguments": {
"agentId": "agt_…",
"enabled": true,
"provider": "heyvm",
"mode": "persistent",
"scope": "agent",
"sizeClass": "small"
}
}
The provider field is optional — if omitted, the server defaults to
tensorlake. The MCP schema lists all three valid values so an LLM can pick
the right one from the description.
Verification
After flipping an agent to heyvm, run a real exec to confirm the
end-to-end path is live:
# Start a sandbox and exec a command via Flapjack's Remote Control.
curl -X POST "$BASE/api/agents/$AGENT_ID/computer/exec" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"command": "uname -a"}'
Expect a 200 SSE stream emitting exec_started, stdout, exit events.
/computer/exec does not create sandboxes — it requires an
already-bootstrapped agent-scoped sandbox row in thread_sandboxes. If
you get 409 SANDBOX_NOT_READY, the agent hasn't been bootstrapped yet:
call POST /api/agents/from-template first (or wait for the existing
bootstrap run to finish — watch progress via
GET /api/agents/:id/computer/bootstrap/stream).
Lifecycle
The bootstrap flow is the only thing that provisions a sandbox today.
There is no separate /computer/deploy endpoint:
| Mode | Provisioning | Across runs |
|---|---|---|
ephemeral | First computer.run tool call inside an agent invocation creates a sandbox keyed on (agentId, threadId) via the internal /computer/run route | new sandbox per thread |
persistent (heyvm only) | POST /api/agents/from-template runs runBootstrap, which creates one heyvm sandbox keyed on agentId | every thread reuses the same sandbox |
custom | Caller stands up an HTTP endpoint themselves and stores its URL/auth in agent_computer_config.settings (no sandbox is created Flapjack-side) | reuses the same external endpoint |
Cleanup:
- The
computer-idlecron stops heyvm sandboxes whoselast_used_atis older than 2 hours (configurable). It does not delete thethread_sandboxesrow — the next exec will resume the sandbox. - There is no public
DELETEroute on/api/agents/:id/computertoday. To force-destroy a heyvm sandbox, use the heyvm dashboard orheyvmCLI directly. Heyvm's own TTL (set on the sandbox at deploy time) is the long-tail cleanup.
Cost / billing
Heyvm bills the Heyo account that owns the HEYVM_API_KEY. Flapjack's
cost_events table records each exec for org-level visibility but does
not reprice it.
Troubleshooting
| Symptom | Cause |
|---|---|
SANDBOX_AUTH_FAILED (401) on any heyvm route | HEYVM_API_KEY missing or revoked. Check the Vercel project env. |
SANDBOX_UNREACHABLE (502) on every heyvm call | server.heyo.computer is having an outage; not actionable on our side. |
HEYO_API_KEY is deprecated; rename to HEYVM_API_KEY warn log | You set the legacy var. Rename to HEYVM_API_KEY in Vercel env. |
409 SANDBOX_NOT_READY from /computer/exec | The agent has no bootstrapped sandbox yet (thread_sandboxes row missing/destroyed). Call POST /api/agents/from-template to bootstrap, or wait for the in-flight bootstrap run to finish. |
Migration 059_rename_heyo_to_heyvm.sql fails on apply | A 'heyo' row violates the new CHECK constraint. The migration handles this by dropping the old constraint first; if you still hit it, run SELECT DISTINCT provider FROM agent_computer_config UNION SELECT DISTINCT provider FROM thread_sandboxes; to inspect. |
Related code
lib/sandbox/adapters/heyvm.ts— adapter, uses@heyocomputer/sdklib/sandbox/registry.ts— provider lookuplib/computer-resolve.ts— agent-scoped sandbox resolutionlib/computer-bootstrap-runner.ts— the bootstrap flow that actually provisions the heyvm sandboxapp/api/agents/[agentId]/computer/route.ts— GET/PUT computer configapp/api/agents/[agentId]/computer/exec/route.ts— public exec (SSE)app/api/agents/[agentId]/computer/status/route.ts— public status probeapp/api/agents/[agentId]/computer/bootstrap/stream/route.ts— bootstrap log stream (SSE)app/api/agents/from-template/route.ts— provision-on-create flowapp/api/internal/computer/{run,read-file,write-file,sandbox}/route.ts— internal runtime surface (called by Tensorlake)app/api/cron/computer-idle/route.ts— idle cleanupsupabase/migrations/059_rename_heyo_to_heyvm.sql— provider-name migration