Primitives

Naming. Agents pick the workload name, and it becomes the public subdomain directly (<name>.h4a.site) the moment expose is called. Choose something descriptive and memorable (solar-dashboard, recipe-api, demo-2026) — not a UUID or random slug. The platform never generates names on your behalf.

Every verb is idempotent by name. Retrying is always safe. The MCP tool surface and the REST surface are generated from the same Go interface — adding a capability to one adds it to the other.

Provision

POST /api/provision · MCP tool: provision

Create (or retrieve if it already exists) a workload by name.

| Field | Type | Required | Notes | |---|---|---|---| | name | string | yes | DNS-safe: [a-z0-9][a-z0-9-]{0,62} | | tenant | string | no | defaults to "default" in v0 | | size | enum | no | nano/small/medium/large; defaults to small |

Returns { name, tenant, ipv4, ssh_command, status }. On a second call with the same name, returns the existing VM's IPv4 — no duplicate is created.

Destroy

POST /api/destroy · MCP tool: destroy

Destroy a workload by name. Idempotent — calling on a non-existent workload is a no-op success.

| Field | Type | Required | |---|---|---| | name | string | yes | | tenant | string | no | | force | bool | no (v0: no-op; M1+ bypasses soft-delete grace) |

Info

POST /api/info · MCP tool: info

Return the current state from the control plane's store. No provider round-trip.

Returns { name, tenant, ipv4, status, created_at }. Returns ErrNotFound (404/status: "not-found" over MCP) if the workload doesn't exist.

Expose

POST /api/expose · MCP tool: expose

Attach a reachable URL to a running workload. See /docs/expose for full details.

| Field | Type | Required | Notes | |---|---|---|---| | name | string | yes | | | tenant | string | no | | | mode | enum | no | public (default): <name>.h4a.site over HTTPS via Caddy+LE on the VM. private: attach a Netbird peer; returns a routable hostname on the mesh. | | port | int | no | Application port on the VM (default 8080). |

Returns { name, tenant, mode, url }.

Deploy

POST /api/deploy · MCP tool: deploy

One call from a git repo to a live URL. Platform auto-detects tier (static vs dynamic). See /docs/deploy for full details including request/response schemas, tier-detection rules, and the .h4a.yaml override.

Wave-A status: static tier works end-to-end (plain + node builds, Bunny CDN delivery, Let's Encrypt on custom hostname). Dynamic tier arrives in wave B.

Status values

| Status | Meaning | |---|---| | provisioning | VM is being created | | running | VM is up and reachable | | destroying | Destroy in flight | | destroyed | Soft-deleted; pending grace period (M1+) | | failed | Create or destroy failed; destroy to clean up |