Naming. Agents pick the workload name, and it becomes the public subdomain directly (
<name>.h4a.site) the momentexposeis 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.
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.
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) |
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.
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 }.
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 | 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 |