diff --git a/content/docs/api-reference.mdx b/content/docs/api-reference.mdx index e1c671b..31f66ef 100644 --- a/content/docs/api-reference.mdx +++ b/content/docs/api-reference.mdx @@ -80,8 +80,33 @@ Core workspace CRUD and lifecycle operations. | Method | Path | Auth | Description | |--------|------|------|-------------| | POST | `/workspaces/:id/restart` | WorkspaceAuth | Restart the workspace container. Sends a `restart_context` A2A message after successful re-registration. | -| POST | `/workspaces/:id/pause` | WorkspaceAuth | Stop the container and set status to `paused`. Paused workspaces skip health sweep, liveness monitor, and auto-restart. | +| POST | `/workspaces/:id/pause` | WorkspaceAuth | Stop the container and set status to `paused`. Paused workspaces skip health sweep, liveness monitor, and auto-restart. Resume manually via `/resume`. | | POST | `/workspaces/:id/resume` | WorkspaceAuth | Re-provision a paused workspace. Status transitions to `provisioning`. | +| POST | `/workspaces/:id/hibernate` | WorkspaceAuth | Immediately hibernate a workspace (stop container, set status to `hibernated`). Useful for manual cost control. See hibernation note below. | + + + **Workspace hibernation** + + A workspace with `hibernation_idle_minutes` set in its config will be **automatically hibernated** by the platform after that many idle minutes (no active tasks, no recent heartbeat). The monitor checks every 2 minutes. + + `hibernated` differs from `paused`: + - **`paused`** — manual, resumes only via `POST /resume`. + - **`hibernated`** — automatic (or via `POST /hibernate`), resumes **automatically** when an A2A message arrives. + + When a message is sent to a hibernated workspace, the platform returns: + ``` + HTTP 503 Retry-After: 15 + {"waking": true} + ``` + Callers should retry after ~15 seconds. The workspace typically returns to `online` within that window. + + To opt a workspace into auto-hibernation, add to its `config.yaml`: + ```yaml + hibernation_idle_minutes: 30 # hibernate after 30 min idle; null (default) = disabled + ``` + + **Atomic hibernation guarantee:** The platform uses a single atomic SQL claim (`UPDATE … WHERE active_tasks = 0`) before stopping the container. If a task arrives between the idle check and the container stop, the claim fails and hibernation is aborted — no in-flight tasks are silently lost. + ### Budget diff --git a/content/docs/concepts.mdx b/content/docs/concepts.mdx index 596e533..ae426c0 100644 --- a/content/docs/concepts.mdx +++ b/content/docs/concepts.mdx @@ -24,104 +24,22 @@ Workspaces talk to each other via **A2A** (agent-to-agent) messages, routed by the platform. Communication rules: same workspace, siblings, and parent/child are allowed; everything else is denied. -### AGENTS.md auto-generation - -At startup, every workspace automatically generates `/workspace/AGENTS.md` -from its `config.yaml`. The file follows the -[AAIF (Agent Artifact Interchange Format)](https://github.com/google/A2A) standard -and contains: - -| Section | Source | -|---------|--------| -| Name | `config.yaml → name` | -| Role | `config.yaml → role` (falls back to description) | -| Description | `config.yaml → description` | -| A2A Endpoint | `$AGENT_URL` env var, or `http://localhost:{a2a.port}/a2a` | -| MCP Tools | union of `config.yaml → tools` + `plugins` | - -Peers fetch it via `GET /workspace/AGENTS.md` for capability discovery. Keep -`name`, `role`, and `description` accurate in `config.yaml` — they are the -sole source of truth for what this agent announces to the org. - -```yaml -# config.yaml — relevant fields for AGENTS.md -name: Backend Engineer -role: "Owns the Go platform — API, migrations, tests, and CI gates." -description: "Senior backend engineer focused on correctness, security, and performance." -``` - -The generator is non-fatal: a missing or unreadable `config.yaml` prints a -startup warning but does not prevent the workspace from booting. - -## Workspace budgets - -A **budget limit** is a per-workspace monthly spend ceiling, expressed in -**USD cents** (e.g. `500` = $5.00/month). It is set by a tenant admin — workspace -agents cannot read or clear their own financial ceiling. - -### What happens at the ceiling - -When `monthly_spend >= budget_limit`, the platform blocks new A2A proxy calls -to that workspace: - -``` -HTTP 402 Payment Required -{"error": "workspace budget limit exceeded"} -``` - -The workspace itself keeps running — only inbound A2A messages and channel -sends are gated. Raising `budget_limit` or resetting spend immediately -restores traffic. - -**Fail-open behaviour:** if the platform cannot reach the budget record -(e.g. a transient DB error), traffic is **allowed through** rather than -blocked. The spend ceiling is a soft guardrail, not a hard guarantee. - -### Setting a limit (admin only) - -```bash -# Set ceiling to $5.00/month -curl -X PATCH https://api.moleculesai.app/workspaces//budget \ - -H "Authorization: Bearer " \ - -H "Content-Type: application/json" \ - -d '{"budget_limit": 500}' - -# Remove ceiling entirely -curl -X PATCH https://api.moleculesai.app/workspaces//budget \ - -H "Authorization: Bearer " \ - -H "Content-Type: application/json" \ - -d '{"budget_limit": null}' -``` - -Values must be a positive integer (USD cents) or `null`. Negative values are -rejected with `400 Bad Request`. - -### Monitoring spend - -Use the dedicated budget endpoint — financial fields are **not** included in -the standard `GET /workspaces/:id` response: - -```bash -curl https://api.moleculesai.app/workspaces//budget \ - -H "Authorization: Bearer " -``` - -```json -{ - "budget_limit": 500, - "monthly_spend": 312, - "budget_remaining": 188 -} -``` - -| Field | Description | -|-------|-------------| -| `budget_limit` | Ceiling in USD cents, or `null` if no limit is set | -| `monthly_spend` | Accumulated spend this billing period in USD cents | -| `budget_remaining` | `null` if no limit; otherwise `max(0, limit − spend)`. Can read negative if spend exceeded the ceiling before enforcement kicked in. | - See the [API Reference](/docs/api-reference#budget) for the full endpoint specification. +### Workspace status lifecycle + +| Status | Meaning | Resumes via | +|--------|---------|-------------| +| `provisioning` | Container being started | automatic | +| `online` | Running and accepting tasks | — | +| `degraded` | Heartbeat `error_rate > 0.5` | auto-recovers | +| `offline` | Missed heartbeats (liveness sweep) | auto-restart | +| `paused` | Manually stopped via `/pause` | `POST /resume` | +| `hibernated` | Auto-paused after idle timeout (or via `/hibernate`) | automatic on next A2A message | +| `removed` | Deleted | — | + +**Hibernation** is an opt-in automatic cost-saving mode. Set `hibernation_idle_minutes` in the workspace's `config.yaml` to enable it. When a hibernated workspace receives an A2A message, the platform wakes it automatically (returning `503 Retry-After: 15` while it comes online). See [API Reference — Lifecycle](/docs/api-reference#lifecycle) for the `/hibernate` endpoint and configuration details. + ## External agents An **external agent** is a workspace with `runtime: external` — it runs on