Heyo Web Services

Agents, their sandboxes, and their tools all need a home. So does everything you build with them. Heyo Web Services is the open source stack for running workloads on your own hardware — agents, sandboxes, MCP, and apps in microVM pools, with auth, CI, active security monitoring, and observability around them. And you drive all of it from your agent.

Everything above the VM, as binaries you run

HWS is shaped like the platforms agents already know — deployments, replicas, routes, secrets, namespaces, tokens — but every piece is a single binary on hosts you control, configured by environment variables. The source is on GitHub.

VM

MicroVM images

Firecracker or KVM images built from a Dockerfile, kept in a content-addressed artifact store.

LB

app-lb

Load balancer, autoscaler, TLS, and control plane in one process.

SEC

SIEM

Built-in security monitoring on every request, with block rules on the data plane.

CI

ci

GitHub-Actions-shaped workflows, one fresh microVM per job, on your runner hosts.

OBS

app-obs

Logs and metrics for every deployment, with no shipper in the guest.

ID

Auth

Google, app-token, or JWT/OIDC sign-in in front of any deployment, plus write-only secrets.

MCP

heyo-mcp

Tools for sandboxes, deployments, logs, CI, and artifacts — for your coding agent.

CLI

heyctl

A kubectl-style CLI and a Rust client library for the whole fleet.

PG

pg-fc

Postgres with one microVM per database. Idle databases stop and wake on the next connect.

Dockerfile in, microVM out

Every workload is a Firecracker or KVM microVM (or an Incus container) whose image you build from the Dockerfile you already have, with heyvm. HWS adds everything above the VM.

Images live in art, a content-addressed blob store built for ext4. A blob’s only name is the sha256 of its bytes, so a tag is something you move and a digest is something you roll back to.

01

Sparse by default

Zero runs become holes on disk: a 20 GiB image with ~600 MiB of real data takes ~600 MiB, and the digest still matches the original file.

02

More than images

Site bundles, Dockerfile build inputs, workspace snapshots, and release binaries go in the same store.

03

Build anywhere, pull everywhere

Build once, push, and let each app-lb host pull. Re-pulling unchanged bytes skips the transfer.

# Build a bootable rootfs from your Dockerfile
heyvm mvm build --local-only -f Dockerfile -n web-v2

# Push it to your artifact store
heyctl artifact push --image web-v2

# Point a deployment at the store and roll the pool
heyctl set artifact web --store /srv/artifacts --ref web-v2
heyctl pull web --wait

# Roll back: pin exact bytes by digest
heyctl pull web --ref <digest>

Read the artifacts docs →

The edge, the autoscaler, and the control plane

app-lb is one Rust process built on Pingora. It terminates HTTP and HTTPS, routes each request by host and path, and boots, health-checks, drains, and reaps microVMs to match the traffic each deployment is getting. Its admin API and dashboard run deployments, secrets, builds, artifact pulls, and certificates.

A pool can sleep at zero. When a request arrives at an empty pool, app-lb boots a VM and holds the request until it is healthy.

VM

Managed pool

A microVM template plus a scaling policy: min, max, warm spares, target concurrency, and an idle timeout before scale-to-zero.

UP

Static upstreams

A fixed list of origins you already run, balanced least-in-flight with failover. Cordon and drain one without dropping requests.

FS

Static site

A directory on the host, served straight off disk — ETags, byte ranges, custom 404, SPA fallback.

  • Automatic TLS — set an ACME email and every exact host route gets a Let’s Encrypt certificate, renewed 30 days before expiry. Wildcards over DNS-01.
  • Builds from git — a build block runs heyvm mvm build on the host and rolls the pool onto the result.
  • Candidate-first rollouts — new replicas boot unrouted, cut over only when healthy, and the old ones drain.
  • Private by default — a deployment with no routes is still autoscaled and reachable with exec and shell. The normal shape for an agent sandbox.
# A public pool that sleeps at zero
heyctl create deployment web --host web.example.com \
    --image web-v2 --port 8080 --min 0 --max 4

# Tune the policy in place; the pool keeps running
heyctl scale web --warm 1 --scale-to-zero-after 600
heyctl rollout status web

# Ship the next commit
heyctl build web --ref main --logs

Read the app-lb docs →

A SIEM in the load balancer

Security monitoring is on by default. app-lb analyzes every request off the request path, so detection never slows traffic, and raises alerts with ECS field names. Alerts ship to app-obs; the /siem console shows each finding with a runbook and a pre-filled block rule.

01

Authentication abuse

Brute force, password spraying across deployments, identity enumeration, and scope denials.

02

Attack signatures

RCE, path traversal, SQL injection, XSS, and secret probes. Query strings are scanned but never stored.

03

Traffic anomalies

Scanners walking many paths for 4xx, and rate spikes from a single source.

Block and allow rules are enforced on the data plane and persist across restarts. Match on client address or CIDR, host, deployment, path, method, or user agent; give a rule an expiry; and try a broad one in dry-run mode first, where it counts hits but refuses nothing.

# Block a source for an hour
curl -XPOST localhost:9090/security/rules -H 'content-type: application/json' \
  -d '{"action":"block","match":{"client":"203.0.113.9"},"expires_in_secs":3600}'

Read the security monitoring docs →

CI on your own metal, a fresh microVM per job

Agents push dozens of times an hour. Paying a metered runner to cold-start for each one, while your source and secrets take a trip through someone else’s datacenter, is the slow way. ci runs the pipeline on runner hosts you own: any machine running heyvmd in a heyvm network, with no agent to install.

01

Workflows you already write

GitHub-Actions-shaped YAML — jobs, needs, matrices, expressions — plus a vm: block that describes the machine to boot, built from a Dockerfile.

02

Submit, don’t push

git submit sends an exact revision as a pinned base and a patch — even uncommitted work with --dirty. No webhook, no repository archive.

03

Durable queue

Postgres is the source of truth; NATS JetStream is the queue. Logs stream live to the dashboard.

04

Secrets stay home

Secrets resolve per job from HeyoSecret and are masked in logs. Build outputs upload to your artifact store.

# Check workflows offline, no database or broker needed
ci --check-workflows .ci/workflows/build.yml

# Submit HEAD, or include uncommitted tracked changes
git submit
git submit --dirty

# Run just one workflow
git submit --only app-lb

Read the ci docs →

Logs, latency, and errors with no code changes

app-obs runs next to app-lb and follows every managed VM’s console and start output straight from the heyvm daemon — no shipper or agent inside the guest. It polls app-lb’s metrics for request counts, errors, p50/p90/p99 latency, pool state, and CPU and memory, and it is never part of the data plane: if it goes down, traffic keeps flowing.

01

Push when you want

Applications can also push logs over HTTP or syslog to their default gateway.

02

Parquet you own

Hive-partitioned Parquet, compacted in the background, deleted past a retention window.

03

Dashboard and alerts

Fleet view, per-deployment charts, a log viewer, and webhook alerts on error counts. No CDN required.

# Webhook when "web" logs more than 5 errors in a minute
curl -XPOST localhost:9600/api/alerts \
  -H 'content-type: application/json' \
  -d '{"deployment": "web", "threshold": 5, "webhook_url": "https://hooks.example.com/obs"}'

Read the app-obs docs →

Sign-in in front of anything, no auth code behind it

Add an auth block to any deployment — a VM pool, a static upstream, or a site — and app-lb runs the gate in the proxy before a backend is chosen. Turning a gate on or off never restarts the pool, and the application gets the signed-in user as forwarded identity headers.

G

Google

OAuth with PKCE, admitted by Workspace domain or individual email. Sessions are HMAC-signed, so a restart signs nobody out.

JWT

JWT and OIDC

Verify tokens from Auth0, Okta, Cognito, Keycloak, or your own issuer, with claim constraints. Declare a provider once per namespace and inherit it.

TOK

App-tokens

Scoped, revocable, optionally expiring bearer tokens for programs and agents. Pair with Google for a UI an agent also drives.

KEY

Secrets

app-lb’s secret store is write-only and injects values by name. HeyoSecret keeps the canonical copies, versioned and AES-256-GCM encrypted.

# Put a deployment behind Google sign-in
heyctl create secret google --from-stdin client_secret < ~/.google-oauth-secret
heyctl set auth web \
  --client-id 1234-abc.apps.googleusercontent.com \
  --secret google/client_secret \
  --allow-domain example.com

Read the auth docs →  ·  Read the HeyoSecret docs →

Run the whole cloud from your agent

heyo-mcp gives coding agents such as Claude Code 65 tools across sandboxes, app-lb deployments, app-obs logs and metrics, ci runs, and the artifact store. Run it locally over stdio, or host it over HTTP as an app-lb deployment behind a sign-in gate, acting as each caller with their own token.

01

Deploy

applb_deploy validates a spec, creates or updates the deployment, starts the right job, waits, and reports TLS.

02

Diagnose

diagnose_empty_pool combines pool state, logs, and metrics to explain why a pool won’t fill.

03

Guardrails

Read-only tools only issue GETs. Destructive tools carry the MCP destructiveHint.

# Add HWS to Claude Code
claude mcp add heyo \
  -e HEYO_API_KEY=heyo_api_… \
  -- node /path/to/hws/mcp/dist/index.js

Read the MCP server docs →

kubectl verbs, without the cluster

heyctl drives the app-lb admin API: apply declarative specs, use create, scale, and set to write them for you, and read them back with get, describe, and top. Named contexts switch between fleets, and exec and shell get you inside any VM.

heyctl ships in the hws crate, which is also a Rust client library. Depend on it with default-features = false for the typed client without the CLI — the foundation for building your own sandbox platform.

# Install the heyctl CLI
cargo install hws

# Copy a deployment from one load balancer to another
heyctl get deployment web -o json | heyctl --context staging apply -f -

# Cargo.toml: the typed client, no CLI
hws = { version = "0.1", default-features = false }

Read the heyctl docs →

Rent the cloud, or run your own

HWS runs anywhere with Linux and /dev/kvm: a desktop under your desk, servers you rent, or Heyo’s bare metal. One bootstrap script turns a fresh Debian or Ubuntu machine into an app-lb host in one step.

Managed databases, sandbox platforms, hosted CI, app hosting — each one is a fine product and a permanent line item. They add up to a cloud you rent forever for software you wrote yourself. HWS is the other path: the same primitives, running as files and pools on machines with your name on them.

Renting the cloud

  • Every service is a separate bill that scales with usage
  • Idle capacity is billed like peak capacity
  • Agents get throwaway sandboxes priced per seat
  • Your images, data, and build history live in their region

Running your own

  • One stack runs apps, Postgres, agents, and CI
  • Scale-to-zero pools release their VMs when idle and wake on demand
  • Agent sandboxes are deployments on hardware you already pay for
  • Images are content-addressed files you keep, move, and roll back

Wondering how this stacks up next to E2B, Modal, Daytona, Northflank, or Microsandbox? See the head-to-head →  ·  Read the installation docs →

Build your own cloud

Open source, on your hardware, driven from your agent.