docs(api-reference): split 710-line monolith into a 6-page section #69
@@ -1,710 +0,0 @@
|
||||
---
|
||||
title: API Reference
|
||||
description: Complete reference for all Molecule AI Platform HTTP and WebSocket endpoints.
|
||||
---
|
||||
|
||||
# API Reference
|
||||
|
||||
The Molecule AI Platform exposes a REST API (default port 8080) for workspace management, agent registry, communication, and administration. All endpoints return JSON unless otherwise noted.
|
||||
|
||||
<Callout type="warn">
|
||||
**Breaking changes — PR #701 (2026-04-17)**
|
||||
|
||||
- **`PATCH /workspaces/:id` now requires authentication.** Previously, requests without a bearer token could update cosmetic fields (name, x/y position). All `PATCH` calls now require `Authorization: Bearer <workspace-token>` or receive **401 Unauthorized**.
|
||||
- **`GET /templates` and `GET /org/templates` now require AdminAuth.** Unauthenticated callers receive **401 Unauthorized**.
|
||||
- **All `/workspaces/:id` endpoints validate the `:id` path parameter** as a UUID. Non-UUID values return **400 Bad Request** before any database interaction.
|
||||
|
||||
**Migration:** add `Authorization: Bearer <workspace-token>` to all `PATCH /workspaces/:id` calls. Use an admin bearer token for `GET /templates` and `GET /org/templates`. Ensure `:id` values in automation scripts are valid UUIDs.
|
||||
</Callout>
|
||||
|
||||
**Base URL:** `http://localhost:8080` (self-hosted) or `https://api.moleculesai.app` (SaaS)
|
||||
|
||||
---
|
||||
|
||||
## Authentication Model
|
||||
|
||||
The platform uses three authentication middleware variants depending on the sensitivity of the route.
|
||||
|
||||
### AdminAuth
|
||||
|
||||
Strict bearer-token authentication. Required for any route where a forged request could leak prompts/memory, create/mutate workspaces, or leak operational data.
|
||||
|
||||
```
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
**Fail-open behavior:** When no live tokens exist globally (fresh install), AdminAuth passes all requests through. Once the first token is created, all AdminAuth routes require a valid bearer.
|
||||
|
||||
### WorkspaceAuth
|
||||
|
||||
Per-workspace bearer token binding. Workspace A's token cannot access workspace B's sub-routes. Used for the entire `/workspaces/:id/*` group (except the A2A proxy, which uses `CanCommunicate`).
|
||||
|
||||
```
|
||||
Authorization: Bearer <workspace-token>
|
||||
```
|
||||
|
||||
### CanvasOrBearer
|
||||
|
||||
Accepts either a valid bearer token OR a request whose `Origin` header matches `CORS_ORIGINS`. Used only for cosmetic-only routes where a forged request has zero data/security impact.
|
||||
|
||||
Currently applies only to `PUT /canvas/viewport`. Do not extend to data-sensitive routes.
|
||||
|
||||
---
|
||||
|
||||
## Health and Monitoring
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/health` | None | Returns `200 OK` if the platform is running. Use for load balancer health checks. |
|
||||
| GET | `/metrics` | None | Prometheus text format (v0.0.4) metrics. Scrape-safe, no auth required. |
|
||||
| GET | `/admin/liveness` | AdminAuth | Per-subsystem `supervised.Snapshot()` ages. Check before debugging stuck scheduler/heartbeat goroutines. |
|
||||
|
||||
---
|
||||
|
||||
## Workspaces
|
||||
|
||||
Core workspace CRUD and lifecycle operations.
|
||||
|
||||
### CRUD
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| POST | `/workspaces` | AdminAuth | Create a new workspace. Accepts `name`, `runtime`, `template`, `parent_id`, `tier`, `workspace_dir`, and other fields. Runtime is auto-detected from template config if omitted (defaults to `langgraph`). |
|
||||
| GET | `/workspaces` | AdminAuth | List all workspaces with status, runtime, agent card, position, and hierarchy info. |
|
||||
| GET | `/workspaces/:id` | WorkspaceAuth | Get a single workspace by ID. |
|
||||
| PATCH | `/workspaces/:id` | WorkspaceAuth | Update workspace fields. A workspace bearer token is always required — unauthenticated calls return 401. Validates field constraints: `name` ≤ 255 chars, `role` ≤ 1,000 chars, `model` and `runtime` ≤ 100 chars each; `name` and `role` must not contain newlines (`\\n`, `\\r`) or YAML-special characters (`{}[]|>*&!`). Oversized or invalid field values return 400. `:id` must be a valid UUID. Financial fields (`budget_limit`) are not accepted here — use `PATCH /workspaces/:id/budget` (AdminAuth). |
|
||||
| DELETE | `/workspaces/:id` | AdminAuth | Delete a workspace. Stops the container, revokes all auth tokens, and removes all associated data. |
|
||||
|
||||
### Lifecycle
|
||||
|
||||
| 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. 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. |
|
||||
|
||||
<Callout type="info">
|
||||
**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.
|
||||
</Callout>
|
||||
|
||||
### Budget
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/budget` | AdminAuth | Read a workspace's current spend and ceiling. Returns `budget_limit`, `monthly_spend`, and `budget_remaining` (all in USD cents). |
|
||||
| PATCH | `/workspaces/:id/budget` | AdminAuth | Set or clear a workspace's monthly spend ceiling. Body: `{ "budget_limit": N }` (positive integer, USD cents) or `{ "budget_limit": null }` to remove the cap. Negative values → 400. Returns same shape as GET. |
|
||||
|
||||
**Request / response shape:**
|
||||
|
||||
```json
|
||||
// PATCH request body
|
||||
{ "budget_limit": 500 } // $5.00/month ceiling
|
||||
{ "budget_limit": null } // no ceiling
|
||||
|
||||
// GET and PATCH success response (200)
|
||||
{
|
||||
"budget_limit": 500, // null when no ceiling
|
||||
"monthly_spend": 312, // accumulated spend this period, USD cents
|
||||
"budget_remaining": 188 // null when no ceiling; max(0, limit-spend) — can be negative
|
||||
}
|
||||
```
|
||||
|
||||
<Callout type="warn">
|
||||
**`budget_limit` and `monthly_spend` are absent from `GET /workspaces/:id`**
|
||||
|
||||
Financial fields are stripped unconditionally from the workspace detail
|
||||
response — they do not appear for any caller, authenticated or not. Always
|
||||
use `GET /workspaces/:id/budget` (AdminAuth) to read spend data.
|
||||
|
||||
`budget_limit` is also **not** accepted on the general `PATCH /workspaces/:id`
|
||||
endpoint. Use the dedicated `/budget` route.
|
||||
</Callout>
|
||||
|
||||
<Callout type="info">
|
||||
**Enforcement and fail-open behaviour**
|
||||
|
||||
When `monthly_spend >= budget_limit`, `POST /workspaces/:id/a2a` returns:
|
||||
```
|
||||
HTTP 402 Payment Required
|
||||
{"error": "workspace budget limit exceeded"}
|
||||
```
|
||||
Channel sends (Slack, Telegram, Discord, Lark) are also budget-gated with
|
||||
the same 402 response. The workspace itself is **not paused** — it keeps
|
||||
running; only inbound A2A and channel traffic is blocked.
|
||||
|
||||
**Fail-open:** if the budget check encounters a DB error, traffic is allowed
|
||||
through rather than blocked. The spend ceiling is a soft guardrail, not a
|
||||
hard guarantee.
|
||||
</Callout>
|
||||
|
||||
---
|
||||
|
||||
## Registry
|
||||
|
||||
Workspace registration and heartbeat endpoints. Called by workspace runtimes, not by end users.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| POST | `/registry/register` | None | Register a workspace with the platform. Sets status to `online`. Body includes agent URL, agent card, capabilities. |
|
||||
| POST | `/registry/heartbeat` | Bearer (if token exists) | Send a heartbeat. Updates Redis TTL key (60s expiry). Body can include `active_tasks`, `current_task`, `error_rate`. Triggers `degraded` status if `error_rate > 0.5`. |
|
||||
| POST | `/registry/update-card` | Bearer (if token exists) | Update the workspace's agent card (name, description, skills, etc.). |
|
||||
|
||||
---
|
||||
|
||||
## Discovery
|
||||
|
||||
Peer discovery and access control verification.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/registry/discover/:id` | Bearer + `X-Workspace-ID` | Discover a workspace's agent card and URL. Requires caller identification. Fails open on DB hiccup since hierarchy check is primary. |
|
||||
| GET | `/registry/:id/peers` | Bearer + `X-Workspace-ID` | List all peers (siblings, parent, children) that the caller can communicate with. |
|
||||
| POST | `/registry/check-access` | None | Check whether two workspaces can communicate. Body: `{ "caller_id": "...", "target_id": "..." }`. Returns `{ "allowed": true/false }`. |
|
||||
|
||||
---
|
||||
|
||||
## Communication
|
||||
|
||||
### A2A Proxy
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| POST | `/workspaces/:id/a2a` | CanCommunicate | Proxy an A2A JSON-RPC message to the target workspace. Caller identified via `X-Workspace-ID` header. Canvas requests (no header) bypass access check. On connection error, checks if container is dead and triggers auto-restart. |
|
||||
|
||||
### Delegation
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| POST | `/workspaces/:id/delegate` | WorkspaceAuth | Async fire-and-forget delegation. Supports idempotency keys. Body includes target workspace, prompt, and metadata. |
|
||||
| GET | `/workspaces/:id/delegations` | WorkspaceAuth | List delegation status for a workspace. Returns delegation rows with status, result, timestamps. |
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/config` | WorkspaceAuth | Get the workspace's `config.yaml` contents. |
|
||||
| PATCH | `/workspaces/:id/config` | WorkspaceAuth | Update the workspace config. "Save & Restart" writes config and auto-restarts; "Save" writes only and shows a restart banner in the Canvas. |
|
||||
| GET | `/workspaces/:id/model` | WorkspaceAuth | Get the workspace's current model selection. |
|
||||
| PUT | `/workspaces/:id/model` | WorkspaceAuth | Set the workspace model (e.g. `anthropic:claude-sonnet-4-6`). |
|
||||
| GET | `/workspaces/:id/provider` | WorkspaceAuth | Get the resolved LLM provider for the workspace's runtime + model. |
|
||||
| PUT | `/workspaces/:id/provider` | WorkspaceAuth | Override the LLM provider for the workspace. |
|
||||
|
||||
---
|
||||
|
||||
## Secrets
|
||||
|
||||
### Per-Workspace Secrets
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/secrets` | WorkspaceAuth | List secret keys for a workspace (keys only, values masked). |
|
||||
| POST | `/workspaces/:id/secrets` | WorkspaceAuth | Set a secret `{ "key": "...", "value": "..." }`. Auto-restarts the workspace. |
|
||||
| PUT | `/workspaces/:id/secrets` | WorkspaceAuth | Alias for POST (upsert semantics). Auto-restarts the workspace. |
|
||||
| DELETE | `/workspaces/:id/secrets/:key` | WorkspaceAuth | Delete a secret by key. Auto-restarts the workspace. |
|
||||
| GET | `/workspaces/:id/model` | WorkspaceAuth | Return the model configuration derived from available API keys (which provider keys are set). |
|
||||
|
||||
### Global Secrets
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/settings/secrets` | AdminAuth | List global secrets (keys only, values masked). |
|
||||
| PUT | `/settings/secrets` | AdminAuth | Set a global secret `{ "key": "...", "value": "..." }`. Auto-restarts every non-paused/non-removed workspace that does not shadow the key with a workspace-level override. |
|
||||
| POST | `/settings/secrets` | AdminAuth | Alias for PUT. |
|
||||
| DELETE | `/settings/secrets/:key` | AdminAuth | Delete a global secret. Same auto-restart fan-out as PUT. |
|
||||
|
||||
Legacy aliases `GET/POST/DELETE /admin/secrets[/:key]` also exist and behave identically.
|
||||
|
||||
---
|
||||
|
||||
## Memory
|
||||
|
||||
### Key-Value Memory
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/memory` | WorkspaceAuth | List all key-value memory entries for a workspace. |
|
||||
| POST | `/workspaces/:id/memory` | WorkspaceAuth | Set a memory entry `{ "key": "...", "value": "..." }`. |
|
||||
| DELETE | `/workspaces/:id/memory/:key` | WorkspaceAuth | Delete a memory entry by key. |
|
||||
|
||||
### Agent Memories (HMA-scoped)
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/memories` | WorkspaceAuth | List or search agent memories. Supports `?q=` for semantic search (see below). |
|
||||
| POST | `/workspaces/:id/memories` | WorkspaceAuth | Create an agent memory entry. |
|
||||
| GET | `/workspaces/:id/v2/namespaces` | WorkspaceAuth | List the HMA memory namespaces visible to this workspace (LOCAL / TEAM / GLOBAL scopes resolved along the org hierarchy). |
|
||||
| GET | `/workspaces/:id/v2/memories` | WorkspaceAuth | List agent memories via the v2 namespace-scoped API. |
|
||||
| DELETE | `/workspaces/:id/v2/memories/:memoryId` | WorkspaceAuth | Delete an agent memory by its ID (v2 API). |
|
||||
|
||||
#### Semantic search (`?q=`)
|
||||
|
||||
When a platform-level embedding function is configured, passing `?q=<text>`
|
||||
on `GET /workspaces/:id/memories` triggers vector similarity search instead of
|
||||
the default full-text / ILIKE path:
|
||||
|
||||
```
|
||||
GET /workspaces/{id}/memories?q=authentication+flow&limit=10
|
||||
Authorization: Bearer {token}
|
||||
```
|
||||
|
||||
Matching entries are returned **ordered by cosine similarity** (most similar
|
||||
first). Each row includes an additional `similarity_score` field (0–1, higher
|
||||
is closer):
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "mem_abc123",
|
||||
"key": "auth-design",
|
||||
"value": "We use short-lived JWTs issued by the platform and refreshed via /auth/token.",
|
||||
"similarity_score": 0.91,
|
||||
"created_at": "2026-04-10T14:22:00Z"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**Graceful fallback**: if no embedding function is configured, or if the
|
||||
embedding call fails for a given query, the platform falls back transparently
|
||||
to the text-search path. The `similarity_score` field is absent in fallback
|
||||
responses. You do not need to change client code to handle both modes.
|
||||
|
||||
---
|
||||
|
||||
## Files
|
||||
|
||||
Workspace file management. Files are stored in the workspace's config directory.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/files` | WorkspaceAuth | List files in the workspace config directory. |
|
||||
| GET | `/workspaces/:id/files/*path` | WorkspaceAuth | Read a specific file. |
|
||||
| PUT | `/workspaces/:id/files/*path` | WorkspaceAuth | Write a file. Creates parent directories as needed. On SaaS workspaces (EC2, no Docker), routes via EC2 Instance Connect endpoint using an ephemeral SSH key pair — the key is scoped to the file-write operation and deleted within 30 seconds. Max payload ~10 MiB. Self-hosted Docker workspaces write via `docker cp` as before. |
|
||||
| DELETE | `/workspaces/:id/files/*path` | WorkspaceAuth | Delete a file. |
|
||||
|
||||
---
|
||||
|
||||
## Activity
|
||||
|
||||
Activity logging and search for A2A communications, task updates, and agent logs.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/activity` | WorkspaceAuth | List activity logs for a workspace. Supports `?source=canvas` or `?source=agent` filter, and `?type=delegation` for A2A topology overlay polling. |
|
||||
| POST | `/workspaces/:id/activity` | WorkspaceAuth | Log an activity entry (used by workspace runtimes to self-report). |
|
||||
| POST | `/workspaces/:id/notify` | WorkspaceAuth | Agent-to-user push message via WebSocket. Delivers a notification to connected Canvas clients. |
|
||||
|
||||
---
|
||||
|
||||
## Session Search
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/session-search` | WorkspaceAuth | Search activity logs with filters for type, date range, and text content. Returns paginated results. |
|
||||
|
||||
---
|
||||
|
||||
## Workflow Checkpoints
|
||||
|
||||
Step-level progress persistence for long-running Temporal workflows. Workspaces with `runtime: langgraph` (Temporal) automatically save a checkpoint after each of the three workflow stages (`task_receive`, `llm_call`, `task_complete`) and resume from the last completed stage on restart.
|
||||
|
||||
<Callout type="info">
|
||||
**Automatic resume behavior (runtime: langgraph only)**
|
||||
|
||||
When a Temporal workspace restarts mid-workflow, the runtime reads the highest-index checkpoint and sets `resume_from_step` accordingly. Already-completed stages are skipped — the agent picks up exactly where it left off without re-running earlier steps.
|
||||
|
||||
Checkpoint I/O is non-fatal: network errors are silently swallowed. A crashed or unreachable platform never prevents the agent from running.
|
||||
</Callout>
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| POST | `/workspaces/:id/checkpoints` | WorkspaceAuth | Upsert a step checkpoint. Body: `{ "workflow_id": "...", "step_name": "task_receive\|llm_call\|task_complete", "step_index": 0, "payload": {...} }`. Uses `ON CONFLICT DO UPDATE` — safe to call multiple times. |
|
||||
| GET | `/workspaces/:id/checkpoints/:wfid` | WorkspaceAuth | Return all checkpoints for a workflow, ordered by `step_index DESC`. Returns 404 if no checkpoints exist for the workflow. |
|
||||
| DELETE | `/workspaces/:id/checkpoints/:wfid` | WorkspaceAuth | Clear all checkpoints for a workflow. Called by the runtime on clean task completion. Returns 404 if none exist. |
|
||||
|
||||
**Step names and indices:**
|
||||
|
||||
| Step | `step_index` | Meaning |
|
||||
|------|-------------|---------|
|
||||
| `task_receive` | 0 | Task received from A2A message |
|
||||
| `llm_call` | 1 | LLM inference completed |
|
||||
| `task_complete` | 2 | Task result sent back to caller |
|
||||
|
||||
---
|
||||
|
||||
## Schedules
|
||||
|
||||
Cron-based scheduled tasks per workspace.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/schedules` | WorkspaceAuth | List all schedules for a workspace. |
|
||||
| POST | `/workspaces/:id/schedules` | WorkspaceAuth | Create a schedule. Body: `{ "expression": "0 */6 * * *", "timezone": "UTC", "prompt": "...", "enabled": true }`. |
|
||||
| PATCH | `/workspaces/:id/schedules/:scheduleId` | WorkspaceAuth | Update a schedule (expression, timezone, prompt, enabled). |
|
||||
| DELETE | `/workspaces/:id/schedules/:scheduleId` | WorkspaceAuth | Delete a schedule. |
|
||||
| POST | `/workspaces/:id/schedules/:scheduleId/run` | WorkspaceAuth | Manually trigger a schedule immediately. |
|
||||
| GET | `/workspaces/:id/schedules/:scheduleId/history` | WorkspaceAuth | List past runs for a schedule. Includes status (`success`, `error`, `skipped`) and `error_detail`. |
|
||||
|
||||
Schedule `source` field: `template` for org/import-seeded schedules, `runtime` for Canvas/API-created. The `last_status` includes `skipped` when the scheduler concurrency-aware-skips a busy workspace.
|
||||
|
||||
---
|
||||
|
||||
## Channels
|
||||
|
||||
Social channel integrations (Telegram, Slack, etc.) for workspace agents.
|
||||
|
||||
### Per-Workspace Channels
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/channels` | WorkspaceAuth | List channels for a workspace. |
|
||||
| POST | `/workspaces/:id/channels` | WorkspaceAuth | Create a channel. Body includes platform type, JSONB config, and allowlist. |
|
||||
| PATCH | `/workspaces/:id/channels/:channelId` | WorkspaceAuth | Update a channel's config or allowlist. |
|
||||
| DELETE | `/workspaces/:id/channels/:channelId` | WorkspaceAuth | Delete a channel. |
|
||||
| POST | `/workspaces/:id/channels/:channelId/send` | WorkspaceAuth | Send an outbound message through the channel. |
|
||||
| POST | `/workspaces/:id/channels/:channelId/test` | WorkspaceAuth | Test the channel connection (send a test message). |
|
||||
|
||||
### Global Channel Endpoints
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/channels/adapters` | None | List available social platform adapters (Telegram, Slack, etc.). |
|
||||
| POST | `/channels/discover` | AdminAuth | Auto-detect available chats/groups for a bot token. |
|
||||
| POST | `/webhooks/:type` | None | Incoming webhook endpoint for social platforms. The `:type` parameter identifies the platform (e.g., `telegram`, `slack`). |
|
||||
|
||||
---
|
||||
|
||||
## Plugins
|
||||
|
||||
Plugin registry and per-workspace plugin management.
|
||||
|
||||
### Global Plugin Registry
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/plugins` | None | List all plugins in the registry. Supports `?runtime=` filter to show only compatible plugins. |
|
||||
| GET | `/plugins/sources` | None | List registered install-source schemes (e.g., `github://`, `local://`). |
|
||||
|
||||
### Per-Workspace Plugins
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/plugins` | WorkspaceAuth | List installed plugins for a workspace. |
|
||||
| POST | `/workspaces/:id/plugins` | WorkspaceAuth | Install a plugin. Body: `{ "source": "github://org/repo" }`. Safeguards: 64 KiB body limit, 5 min fetch timeout, 100 MiB max staged-tree. |
|
||||
| DELETE | `/workspaces/:id/plugins/:name` | WorkspaceAuth | Uninstall a plugin by name. |
|
||||
| GET | `/workspaces/:id/plugins/available` | WorkspaceAuth | List plugins available for this workspace (filtered by workspace runtime). |
|
||||
| GET | `/workspaces/:id/plugins/compatibility` | WorkspaceAuth | Preflight runtime-change check. Query: `?runtime=X`. Returns which currently-installed plugins would be incompatible with the target runtime. |
|
||||
|
||||
---
|
||||
|
||||
## Auth Tokens
|
||||
|
||||
Bearer token management for workspaces.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/tokens` | WorkspaceAuth | List active tokens for a workspace (token values are masked). |
|
||||
| POST | `/workspaces/:id/tokens` | WorkspaceAuth | Create a new bearer token for the workspace. |
|
||||
| DELETE | `/workspaces/:id/tokens/:tokenId` | WorkspaceAuth | Revoke a specific token. |
|
||||
|
||||
### Admin token minting
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| POST | `/admin/workspaces/:id/tokens` | AdminAuth | Mint a fresh bearer token for a workspace (admin / bootstrap / E2E use). The earlier unauthenticated `GET /admin/workspaces/:id/test-token` route was removed; minting now requires AdminAuth. |
|
||||
|
||||
---
|
||||
|
||||
## Templates and Bundles
|
||||
|
||||
### Templates
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/templates` | AdminAuth | List available workspace templates with their runtime, description, and config schema. |
|
||||
| POST | `/templates/import` | AdminAuth | Import a workspace template from a `github://` source URL. |
|
||||
|
||||
### Org Templates
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/org/templates` | AdminAuth | List available organization templates. |
|
||||
| POST | `/org/import` | AdminAuth | Import an org template. Applies `resolveInsideRoot` path sanitization. Creates the full workspace hierarchy defined in `org.yaml`. |
|
||||
|
||||
### Bundles
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/bundles/export/:id` | AdminAuth | Export a workspace (or workspace tree) as a portable bundle. Includes config, secrets (keys only), memory, schedules, and hierarchy. |
|
||||
| POST | `/bundles/import` | AdminAuth | Import a previously-exported bundle. Recreates the workspace tree with all associated data. |
|
||||
|
||||
---
|
||||
|
||||
## Approvals
|
||||
|
||||
Human-in-the-loop approval system for agent actions.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| POST | `/workspaces/:id/approvals` | WorkspaceAuth | Create an approval request. Body includes the action description, metadata, and options. |
|
||||
| GET | `/workspaces/:id/approvals` | WorkspaceAuth | List approval requests for a workspace. |
|
||||
| POST | `/workspaces/:id/approvals/:id/decide` | WorkspaceAuth | Approve or reject an approval request. Body: `{ "decision": "approve" }` or `{ "decision": "reject" }`. |
|
||||
| GET | `/approvals/pending` | AdminAuth | List all pending approval requests across all workspaces. |
|
||||
|
||||
---
|
||||
|
||||
## Canvas
|
||||
|
||||
Canvas viewport persistence (cosmetic only).
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/canvas/viewport` | None | Get the saved canvas viewport (zoom, pan position). Open endpoint for bootstrap-friendliness. |
|
||||
| PUT | `/canvas/viewport` | CanvasOrBearer | Save the canvas viewport. Accepts bearer OR matching `Origin` header. Worst case on forgery: viewport corruption, recovered by page refresh. |
|
||||
|
||||
---
|
||||
|
||||
## Traces
|
||||
|
||||
LLM trace retrieval from Langfuse.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/traces` | WorkspaceAuth | List LLM traces for a workspace from Langfuse. |
|
||||
|
||||
---
|
||||
|
||||
## Audit Ledger
|
||||
|
||||
HMAC-SHA256-chained immutable agent event log for compliance record-keeping (EU AI Act Art. 12 / Art. 13). Each event is cryptographically chained to the previous one — tampering with any record breaks all subsequent HMACs.
|
||||
|
||||
<Callout type="warn">
|
||||
**`AUDIT_LEDGER_SALT` required.** The platform and workspace containers must share the same `AUDIT_LEDGER_SALT` environment variable to compute and verify event HMACs. Set it in both your platform env and workspace container env. If the variable is absent, `chain_valid` returns `null` (not `false`) — no records are lost, verification is simply unavailable.
|
||||
</Callout>
|
||||
|
||||
### Query
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/audit` | WorkspaceAuth | Query the audit ledger for a workspace. Returns events in descending chronological order with inline chain verification. |
|
||||
|
||||
**Query parameters:**
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| `agent_id` | string | Filter to a specific agent. |
|
||||
| `session_id` | string | Filter to a specific session. |
|
||||
| `from` | RFC 3339 | Start of time range (e.g. `2026-04-01T00:00:00Z`). |
|
||||
| `to` | RFC 3339 | End of time range. |
|
||||
| `limit` | int | Max records to return. Capped at **500**. |
|
||||
| `offset` | int | Pagination offset. |
|
||||
|
||||
**Response shape:**
|
||||
|
||||
```json
|
||||
{
|
||||
"events": [
|
||||
{
|
||||
"id": "uuid",
|
||||
"workspace_id": "uuid",
|
||||
"agent_id": "my-researcher",
|
||||
"session_id": "sess_abc123",
|
||||
"event_type": "tool_call",
|
||||
"payload": { "tool": "bash", "input": "ls /workspace" },
|
||||
"hmac": "sha256hex...",
|
||||
"prev_hmac": "sha256hex...",
|
||||
"created_at": "2026-04-17T12:00:00Z"
|
||||
}
|
||||
],
|
||||
"chain_valid": true
|
||||
}
|
||||
```
|
||||
|
||||
`chain_valid` values:
|
||||
- `true` — all HMACs verified; ledger is intact.
|
||||
- `false` — at least one HMAC mismatch; possible tampering.
|
||||
- `null` — `AUDIT_LEDGER_SALT` is absent from the platform env; verification skipped.
|
||||
|
||||
### Workspace-side: recording events
|
||||
|
||||
In your workspace template, wire `LedgerHooks` into the agent pipeline:
|
||||
|
||||
```python
|
||||
from molecule_audit.hooks import LedgerHooks
|
||||
|
||||
hooks = LedgerHooks(agent_id="my-researcher", session_id=session_id)
|
||||
|
||||
async with hooks:
|
||||
# hooks.on_task_start / on_llm_call / on_tool_call / on_task_end
|
||||
# fire automatically at each pipeline stage
|
||||
result = await agent.run(task)
|
||||
```
|
||||
|
||||
`LedgerHooks` is exception-safe — a failed ledger write never aborts the agent task.
|
||||
|
||||
### CLI chain verification
|
||||
|
||||
```bash
|
||||
# Verify the full chain for an agent; exit 0 = intact
|
||||
python -m molecule_audit.verify --agent-id my-researcher
|
||||
|
||||
# Custom DB URL
|
||||
python -m molecule_audit.verify --agent-id my-researcher --db postgresql://user:pass@host/db
|
||||
```
|
||||
|
||||
Exit codes: `0` = chain valid · `1` = broken chain · `2` = `AUDIT_LEDGER_SALT` missing · `3` = DB error.
|
||||
|
||||
---
|
||||
|
||||
## Events
|
||||
|
||||
Append-only event log for structure changes.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/events` | AdminAuth | List all structure events across all workspaces. |
|
||||
| GET | `/events/:workspaceId` | AdminAuth | List structure events for a specific workspace. |
|
||||
|
||||
---
|
||||
|
||||
## Terminal
|
||||
|
||||
WebSocket-based terminal access to workspace containers.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| WS | `/workspaces/:id/terminal` | WorkspaceAuth | Open a WebSocket terminal session to the workspace container. Provides interactive shell access. |
|
||||
|
||||
---
|
||||
|
||||
## WebSocket
|
||||
|
||||
Real-time event streaming for Canvas clients.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| WS | `/ws` | None | Connect to the WebSocket hub. Receives all structure events (`WORKSPACE_ONLINE`, `WORKSPACE_OFFLINE`, `HEARTBEAT`, `CONFIG_UPDATED`, `A2A_RESPONSE`, `AGENT_MESSAGE`, etc.). Canvas clients connect here for real-time updates. |
|
||||
|
||||
---
|
||||
|
||||
## Server-Sent Events (AG-UI)
|
||||
|
||||
Per-workspace SSE stream compatible with the [AG-UI protocol](https://github.com/ag-ui-protocol/ag-ui). Use this endpoint to consume structured agent events from a web client or external tool without a WebSocket library.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/events/stream` | WorkspaceAuth | Open an SSE stream for the workspace. Returns `Content-Type: text/event-stream`. Sends an initial `: ping` comment on connect, then delivers every event emitted by the workspace in AG-UI envelope format. Events from other workspaces are filtered out. Returns `404` if the workspace does not exist. |
|
||||
|
||||
### Event envelope format
|
||||
|
||||
Each event is delivered as an SSE `data:` line containing a JSON object:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "AGENT_MESSAGE",
|
||||
"timestamp": 1713398400000,
|
||||
"data": { ... }
|
||||
}
|
||||
```
|
||||
|
||||
- **`type`** — event type string (e.g. `AGENT_MESSAGE`, `A2A_RESPONSE`, `TASK_UPDATED`)
|
||||
- **`timestamp`** — Unix milliseconds at time of broadcast
|
||||
- **`data`** — event-specific payload (same payload as the WebSocket hub delivers)
|
||||
|
||||
### Event types streamed
|
||||
|
||||
All event types emitted by `RecordAndBroadcast` **and** `BroadcastOnly` reach the SSE stream. The `BroadcastOnly` path is important: events like `AGENT_MESSAGE`, `A2A_RESPONSE`, and `TASK_UPDATED` skip Redis and would be invisible to a Redis-only subscriber — the in-process SSE layer catches them.
|
||||
|
||||
### Example: connect with `curl`
|
||||
|
||||
```bash
|
||||
curl -N \
|
||||
-H "Authorization: Bearer <workspace-token>" \
|
||||
http://localhost:8080/workspaces/<id>/events/stream
|
||||
```
|
||||
|
||||
```
|
||||
: ping
|
||||
|
||||
data: {"type":"AGENT_MESSAGE","timestamp":1713398401234,"data":{"text":"Starting task..."}}
|
||||
|
||||
data: {"type":"TASK_UPDATED","timestamp":1713398405678,"data":{"status":"running"}}
|
||||
```
|
||||
|
||||
### Example: connect from JavaScript
|
||||
|
||||
```js
|
||||
const es = new EventSource(
|
||||
`/workspaces/${workspaceId}/events/stream`,
|
||||
{ headers: { Authorization: `Bearer ${token}` } }
|
||||
);
|
||||
|
||||
es.onmessage = (e) => {
|
||||
const event = JSON.parse(e.data);
|
||||
console.log(event.type, event.data);
|
||||
};
|
||||
```
|
||||
|
||||
<Callout type="info">
|
||||
The SSE endpoint uses WorkspaceAuth — the bearer token must be bound to the `:id` in the path. A token for workspace A cannot open a stream for workspace B.
|
||||
</Callout>
|
||||
|
||||
---
|
||||
|
||||
## Error Responses
|
||||
|
||||
All endpoints return standard HTTP status codes:
|
||||
|
||||
| Status | Meaning |
|
||||
|--------|---------|
|
||||
| 200 | Success |
|
||||
| 201 | Created |
|
||||
| 400 | Bad request (malformed body, missing required fields) |
|
||||
| 401 | Unauthorized (missing or invalid bearer token) |
|
||||
| 403 | Forbidden (valid token but insufficient access) |
|
||||
| 404 | Not found (workspace, schedule, channel, etc. does not exist) |
|
||||
| 409 | Conflict (idempotency key collision on delegation) |
|
||||
| 429 | Rate limited (exceeds `RATE_LIMIT` requests/min) |
|
||||
| 500 | Internal server error |
|
||||
|
||||
Error response body format:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "human-readable error message"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Rate Limiting
|
||||
|
||||
All endpoints are subject to a global rate limit of `RATE_LIMIT` requests per minute (default: 600). When exceeded, the platform returns `429 Too Many Requests` with a `Retry-After` header.
|
||||
|
||||
---
|
||||
|
||||
## CORS
|
||||
|
||||
The platform sets CORS headers based on the `CORS_ORIGINS` environment variable (comma-separated list, default: `http://localhost:3000,http://localhost:3001`). Preflight (`OPTIONS`) requests are handled automatically by the Gin CORS middleware.
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
title: "Communication API"
|
||||
description: "Agent registry, discovery, A2A proxy, and delegation endpoints."
|
||||
---
|
||||
|
||||
## Registry
|
||||
|
||||
Workspace registration and heartbeat endpoints. Called by workspace runtimes, not by end users.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| POST | `/registry/register` | None | Register a workspace with the platform. Sets status to `online`. Body includes agent URL, agent card, capabilities. |
|
||||
| POST | `/registry/heartbeat` | Bearer (if token exists) | Send a heartbeat. Updates Redis TTL key (60s expiry). Body can include `active_tasks`, `current_task`, `error_rate`. Triggers `degraded` status if `error_rate > 0.5`. |
|
||||
| POST | `/registry/update-card` | Bearer (if token exists) | Update the workspace's agent card (name, description, skills, etc.). |
|
||||
|
||||
---
|
||||
|
||||
## Discovery
|
||||
|
||||
Peer discovery and access control verification.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/registry/discover/:id` | Bearer + `X-Workspace-ID` | Discover a workspace's agent card and URL. Requires caller identification. Fails open on DB hiccup since hierarchy check is primary. |
|
||||
| GET | `/registry/:id/peers` | Bearer + `X-Workspace-ID` | List all peers (siblings, parent, children) that the caller can communicate with. |
|
||||
| POST | `/registry/check-access` | None | Check whether two workspaces can communicate. Body: `{ "caller_id": "...", "target_id": "..." }`. Returns `{ "allowed": true/false }`. |
|
||||
|
||||
---
|
||||
|
||||
## Communication
|
||||
|
||||
### A2A Proxy
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| POST | `/workspaces/:id/a2a` | CanCommunicate | Proxy an A2A JSON-RPC message to the target workspace. Caller identified via `X-Workspace-ID` header. Canvas requests (no header) bypass access check. On connection error, checks if container is dead and triggers auto-restart. |
|
||||
|
||||
### Delegation
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| POST | `/workspaces/:id/delegate` | WorkspaceAuth | Async fire-and-forget delegation. Supports idempotency keys. Body includes target workspace, prompt, and metadata. |
|
||||
| GET | `/workspaces/:id/delegations` | WorkspaceAuth | List delegation status for a workspace. Returns delegation rows with status, result, timestamps. |
|
||||
|
||||
---
|
||||
@@ -0,0 +1,113 @@
|
||||
---
|
||||
title: "API Reference"
|
||||
description: "Complete reference for all Molecule AI Platform HTTP and WebSocket endpoints."
|
||||
---
|
||||
|
||||
|
||||
# API Reference
|
||||
|
||||
The Molecule AI Platform exposes a REST API (default port 8080) for workspace management, agent registry, communication, and administration. All endpoints return JSON unless otherwise noted.
|
||||
|
||||
<Callout type="warn">
|
||||
**Breaking changes — PR #701 (2026-04-17)**
|
||||
|
||||
- **`PATCH /workspaces/:id` now requires authentication.** Previously, requests without a bearer token could update cosmetic fields (name, x/y position). All `PATCH` calls now require `Authorization: Bearer <workspace-token>` or receive **401 Unauthorized**.
|
||||
- **`GET /templates` and `GET /org/templates` now require AdminAuth.** Unauthenticated callers receive **401 Unauthorized**.
|
||||
- **All `/workspaces/:id` endpoints validate the `:id` path parameter** as a UUID. Non-UUID values return **400 Bad Request** before any database interaction.
|
||||
|
||||
**Migration:** add `Authorization: Bearer <workspace-token>` to all `PATCH /workspaces/:id` calls. Use an admin bearer token for `GET /templates` and `GET /org/templates`. Ensure `:id` values in automation scripts are valid UUIDs.
|
||||
</Callout>
|
||||
|
||||
**Base URL:** `http://localhost:8080` (self-hosted) or `https://api.moleculesai.app` (SaaS)
|
||||
|
||||
---
|
||||
|
||||
## Endpoint reference
|
||||
|
||||
The full endpoint reference is grouped into these pages:
|
||||
|
||||
- **[Workspaces](/docs/api-reference/workspaces)** — workspace CRUD & lifecycle, budget, configuration, files, activity, session search.
|
||||
- **[Communication](/docs/api-reference/communication)** — registry, discovery, A2A proxy & delegation.
|
||||
- **[Memory & Secrets](/docs/api-reference/memory)** — key-value & HMA-scoped memory, secrets, workflow checkpoints.
|
||||
- **[Integrations](/docs/api-reference/integrations)** — schedules, channels, plugins, auth tokens, templates & bundles, approvals.
|
||||
- **[Real-time & Observability](/docs/api-reference/realtime)** — canvas, traces, audit ledger, events, terminal, WebSocket, SSE.
|
||||
|
||||
---
|
||||
|
||||
## Authentication Model
|
||||
|
||||
The platform uses three authentication middleware variants depending on the sensitivity of the route.
|
||||
|
||||
### AdminAuth
|
||||
|
||||
Strict bearer-token authentication. Required for any route where a forged request could leak prompts/memory, create/mutate workspaces, or leak operational data.
|
||||
|
||||
```
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
**Fail-open behavior:** When no live tokens exist globally (fresh install), AdminAuth passes all requests through. Once the first token is created, all AdminAuth routes require a valid bearer.
|
||||
|
||||
### WorkspaceAuth
|
||||
|
||||
Per-workspace bearer token binding. Workspace A's token cannot access workspace B's sub-routes. Used for the entire `/workspaces/:id/*` group (except the A2A proxy, which uses `CanCommunicate`).
|
||||
|
||||
```
|
||||
Authorization: Bearer <workspace-token>
|
||||
```
|
||||
|
||||
### CanvasOrBearer
|
||||
|
||||
Accepts either a valid bearer token OR a request whose `Origin` header matches `CORS_ORIGINS`. Used only for cosmetic-only routes where a forged request has zero data/security impact.
|
||||
|
||||
Currently applies only to `PUT /canvas/viewport`. Do not extend to data-sensitive routes.
|
||||
|
||||
---
|
||||
|
||||
## Health and Monitoring
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/health` | None | Returns `200 OK` if the platform is running. Use for load balancer health checks. |
|
||||
| GET | `/metrics` | None | Prometheus text format (v0.0.4) metrics. Scrape-safe, no auth required. |
|
||||
| GET | `/admin/liveness` | AdminAuth | Per-subsystem `supervised.Snapshot()` ages. Check before debugging stuck scheduler/heartbeat goroutines. |
|
||||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
## Error Responses
|
||||
|
||||
All endpoints return standard HTTP status codes:
|
||||
|
||||
| Status | Meaning |
|
||||
|--------|---------|
|
||||
| 200 | Success |
|
||||
| 201 | Created |
|
||||
| 400 | Bad request (malformed body, missing required fields) |
|
||||
| 401 | Unauthorized (missing or invalid bearer token) |
|
||||
| 403 | Forbidden (valid token but insufficient access) |
|
||||
| 404 | Not found (workspace, schedule, channel, etc. does not exist) |
|
||||
| 409 | Conflict (idempotency key collision on delegation) |
|
||||
| 429 | Rate limited (exceeds `RATE_LIMIT` requests/min) |
|
||||
| 500 | Internal server error |
|
||||
|
||||
Error response body format:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "human-readable error message"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Rate Limiting
|
||||
|
||||
All endpoints are subject to a global rate limit of `RATE_LIMIT` requests per minute (default: 600). When exceeded, the platform returns `429 Too Many Requests` with a `Retry-After` header.
|
||||
|
||||
---
|
||||
|
||||
## CORS
|
||||
|
||||
The platform sets CORS headers based on the `CORS_ORIGINS` environment variable (comma-separated list, default: `http://localhost:3000,http://localhost:3001`). Preflight (`OPTIONS`) requests are handled automatically by the Gin CORS middleware.
|
||||
@@ -0,0 +1,125 @@
|
||||
---
|
||||
title: "Integrations API"
|
||||
description: "Schedules, channels, plugins, auth tokens, templates & bundles, and approvals endpoints."
|
||||
---
|
||||
|
||||
## Schedules
|
||||
|
||||
Cron-based scheduled tasks per workspace.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/schedules` | WorkspaceAuth | List all schedules for a workspace. |
|
||||
| POST | `/workspaces/:id/schedules` | WorkspaceAuth | Create a schedule. Body: `{ "expression": "0 */6 * * *", "timezone": "UTC", "prompt": "...", "enabled": true }`. |
|
||||
| PATCH | `/workspaces/:id/schedules/:scheduleId` | WorkspaceAuth | Update a schedule (expression, timezone, prompt, enabled). |
|
||||
| DELETE | `/workspaces/:id/schedules/:scheduleId` | WorkspaceAuth | Delete a schedule. |
|
||||
| POST | `/workspaces/:id/schedules/:scheduleId/run` | WorkspaceAuth | Manually trigger a schedule immediately. |
|
||||
| GET | `/workspaces/:id/schedules/:scheduleId/history` | WorkspaceAuth | List past runs for a schedule. Includes status (`success`, `error`, `skipped`) and `error_detail`. |
|
||||
|
||||
Schedule `source` field: `template` for org/import-seeded schedules, `runtime` for Canvas/API-created. The `last_status` includes `skipped` when the scheduler concurrency-aware-skips a busy workspace.
|
||||
|
||||
---
|
||||
|
||||
## Channels
|
||||
|
||||
Social channel integrations (Telegram, Slack, etc.) for workspace agents.
|
||||
|
||||
### Per-Workspace Channels
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/channels` | WorkspaceAuth | List channels for a workspace. |
|
||||
| POST | `/workspaces/:id/channels` | WorkspaceAuth | Create a channel. Body includes platform type, JSONB config, and allowlist. |
|
||||
| PATCH | `/workspaces/:id/channels/:channelId` | WorkspaceAuth | Update a channel's config or allowlist. |
|
||||
| DELETE | `/workspaces/:id/channels/:channelId` | WorkspaceAuth | Delete a channel. |
|
||||
| POST | `/workspaces/:id/channels/:channelId/send` | WorkspaceAuth | Send an outbound message through the channel. |
|
||||
| POST | `/workspaces/:id/channels/:channelId/test` | WorkspaceAuth | Test the channel connection (send a test message). |
|
||||
|
||||
### Global Channel Endpoints
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/channels/adapters` | None | List available social platform adapters (Telegram, Slack, etc.). |
|
||||
| POST | `/channels/discover` | AdminAuth | Auto-detect available chats/groups for a bot token. |
|
||||
| POST | `/webhooks/:type` | None | Incoming webhook endpoint for social platforms. The `:type` parameter identifies the platform (e.g., `telegram`, `slack`). |
|
||||
|
||||
---
|
||||
|
||||
## Plugins
|
||||
|
||||
Plugin registry and per-workspace plugin management.
|
||||
|
||||
### Global Plugin Registry
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/plugins` | None | List all plugins in the registry. Supports `?runtime=` filter to show only compatible plugins. |
|
||||
| GET | `/plugins/sources` | None | List registered install-source schemes (e.g., `github://`, `local://`). |
|
||||
|
||||
### Per-Workspace Plugins
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/plugins` | WorkspaceAuth | List installed plugins for a workspace. |
|
||||
| POST | `/workspaces/:id/plugins` | WorkspaceAuth | Install a plugin. Body: `{ "source": "github://org/repo" }`. Safeguards: 64 KiB body limit, 5 min fetch timeout, 100 MiB max staged-tree. |
|
||||
| DELETE | `/workspaces/:id/plugins/:name` | WorkspaceAuth | Uninstall a plugin by name. |
|
||||
| GET | `/workspaces/:id/plugins/available` | WorkspaceAuth | List plugins available for this workspace (filtered by workspace runtime). |
|
||||
| GET | `/workspaces/:id/plugins/compatibility` | WorkspaceAuth | Preflight runtime-change check. Query: `?runtime=X`. Returns which currently-installed plugins would be incompatible with the target runtime. |
|
||||
|
||||
---
|
||||
|
||||
## Auth Tokens
|
||||
|
||||
Bearer token management for workspaces.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/tokens` | WorkspaceAuth | List active tokens for a workspace (token values are masked). |
|
||||
| POST | `/workspaces/:id/tokens` | WorkspaceAuth | Create a new bearer token for the workspace. |
|
||||
| DELETE | `/workspaces/:id/tokens/:tokenId` | WorkspaceAuth | Revoke a specific token. |
|
||||
|
||||
### Admin token minting
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| POST | `/admin/workspaces/:id/tokens` | AdminAuth | Mint a fresh bearer token for a workspace (admin / bootstrap / E2E use). The earlier unauthenticated `GET /admin/workspaces/:id/test-token` route was removed; minting now requires AdminAuth. |
|
||||
|
||||
---
|
||||
|
||||
## Templates and Bundles
|
||||
|
||||
### Templates
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/templates` | AdminAuth | List available workspace templates with their runtime, description, and config schema. |
|
||||
| POST | `/templates/import` | AdminAuth | Import a workspace template from a `github://` source URL. |
|
||||
|
||||
### Org Templates
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/org/templates` | AdminAuth | List available organization templates. |
|
||||
| POST | `/org/import` | AdminAuth | Import an org template. Applies `resolveInsideRoot` path sanitization. Creates the full workspace hierarchy defined in `org.yaml`. |
|
||||
|
||||
### Bundles
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/bundles/export/:id` | AdminAuth | Export a workspace (or workspace tree) as a portable bundle. Includes config, secrets (keys only), memory, schedules, and hierarchy. |
|
||||
| POST | `/bundles/import` | AdminAuth | Import a previously-exported bundle. Recreates the workspace tree with all associated data. |
|
||||
|
||||
---
|
||||
|
||||
## Approvals
|
||||
|
||||
Human-in-the-loop approval system for agent actions.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| POST | `/workspaces/:id/approvals` | WorkspaceAuth | Create an approval request. Body includes the action description, metadata, and options. |
|
||||
| GET | `/workspaces/:id/approvals` | WorkspaceAuth | List approval requests for a workspace. |
|
||||
| POST | `/workspaces/:id/approvals/:id/decide` | WorkspaceAuth | Approve or reject an approval request. Body: `{ "decision": "approve" }` or `{ "decision": "reject" }`. |
|
||||
| GET | `/approvals/pending` | AdminAuth | List all pending approval requests across all workspaces. |
|
||||
|
||||
---
|
||||
@@ -0,0 +1,111 @@
|
||||
---
|
||||
title: "Memory & Secrets API"
|
||||
description: "Key-value and HMA-scoped agent memory, secrets, and workflow checkpoint endpoints."
|
||||
---
|
||||
|
||||
## Secrets
|
||||
|
||||
### Per-Workspace Secrets
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/secrets` | WorkspaceAuth | List secret keys for a workspace (keys only, values masked). |
|
||||
| POST | `/workspaces/:id/secrets` | WorkspaceAuth | Set a secret `{ "key": "...", "value": "..." }`. Auto-restarts the workspace. |
|
||||
| PUT | `/workspaces/:id/secrets` | WorkspaceAuth | Alias for POST (upsert semantics). Auto-restarts the workspace. |
|
||||
| DELETE | `/workspaces/:id/secrets/:key` | WorkspaceAuth | Delete a secret by key. Auto-restarts the workspace. |
|
||||
| GET | `/workspaces/:id/model` | WorkspaceAuth | Return the model configuration derived from available API keys (which provider keys are set). |
|
||||
|
||||
### Global Secrets
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/settings/secrets` | AdminAuth | List global secrets (keys only, values masked). |
|
||||
| PUT | `/settings/secrets` | AdminAuth | Set a global secret `{ "key": "...", "value": "..." }`. Auto-restarts every non-paused/non-removed workspace that does not shadow the key with a workspace-level override. |
|
||||
| POST | `/settings/secrets` | AdminAuth | Alias for PUT. |
|
||||
| DELETE | `/settings/secrets/:key` | AdminAuth | Delete a global secret. Same auto-restart fan-out as PUT. |
|
||||
|
||||
Legacy aliases `GET/POST/DELETE /admin/secrets[/:key]` also exist and behave identically.
|
||||
|
||||
---
|
||||
|
||||
## Memory
|
||||
|
||||
### Key-Value Memory
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/memory` | WorkspaceAuth | List all key-value memory entries for a workspace. |
|
||||
| POST | `/workspaces/:id/memory` | WorkspaceAuth | Set a memory entry `{ "key": "...", "value": "..." }`. |
|
||||
| DELETE | `/workspaces/:id/memory/:key` | WorkspaceAuth | Delete a memory entry by key. |
|
||||
|
||||
### Agent Memories (HMA-scoped)
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/memories` | WorkspaceAuth | List or search agent memories. Supports `?q=` for semantic search (see below). |
|
||||
| POST | `/workspaces/:id/memories` | WorkspaceAuth | Create an agent memory entry. |
|
||||
| GET | `/workspaces/:id/v2/namespaces` | WorkspaceAuth | List the HMA memory namespaces visible to this workspace (LOCAL / TEAM / GLOBAL scopes resolved along the org hierarchy). |
|
||||
| GET | `/workspaces/:id/v2/memories` | WorkspaceAuth | List agent memories via the v2 namespace-scoped API. |
|
||||
| DELETE | `/workspaces/:id/v2/memories/:memoryId` | WorkspaceAuth | Delete an agent memory by its ID (v2 API). |
|
||||
|
||||
#### Semantic search (`?q=`)
|
||||
|
||||
When a platform-level embedding function is configured, passing `?q=<text>`
|
||||
on `GET /workspaces/:id/memories` triggers vector similarity search instead of
|
||||
the default full-text / ILIKE path:
|
||||
|
||||
```
|
||||
GET /workspaces/{id}/memories?q=authentication+flow&limit=10
|
||||
Authorization: Bearer {token}
|
||||
```
|
||||
|
||||
Matching entries are returned **ordered by cosine similarity** (most similar
|
||||
first). Each row includes an additional `similarity_score` field (0–1, higher
|
||||
is closer):
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "mem_abc123",
|
||||
"key": "auth-design",
|
||||
"value": "We use short-lived JWTs issued by the platform and refreshed via /auth/token.",
|
||||
"similarity_score": 0.91,
|
||||
"created_at": "2026-04-10T14:22:00Z"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
**Graceful fallback**: if no embedding function is configured, or if the
|
||||
embedding call fails for a given query, the platform falls back transparently
|
||||
to the text-search path. The `similarity_score` field is absent in fallback
|
||||
responses. You do not need to change client code to handle both modes.
|
||||
|
||||
---
|
||||
|
||||
## Workflow Checkpoints
|
||||
|
||||
Step-level progress persistence for long-running Temporal workflows. Workspaces with `runtime: langgraph` (Temporal) automatically save a checkpoint after each of the three workflow stages (`task_receive`, `llm_call`, `task_complete`) and resume from the last completed stage on restart.
|
||||
|
||||
<Callout type="info">
|
||||
**Automatic resume behavior (runtime: langgraph only)**
|
||||
|
||||
When a Temporal workspace restarts mid-workflow, the runtime reads the highest-index checkpoint and sets `resume_from_step` accordingly. Already-completed stages are skipped — the agent picks up exactly where it left off without re-running earlier steps.
|
||||
|
||||
Checkpoint I/O is non-fatal: network errors are silently swallowed. A crashed or unreachable platform never prevents the agent from running.
|
||||
</Callout>
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| POST | `/workspaces/:id/checkpoints` | WorkspaceAuth | Upsert a step checkpoint. Body: `{ "workflow_id": "...", "step_name": "task_receive\|llm_call\|task_complete", "step_index": 0, "payload": {...} }`. Uses `ON CONFLICT DO UPDATE` — safe to call multiple times. |
|
||||
| GET | `/workspaces/:id/checkpoints/:wfid` | WorkspaceAuth | Return all checkpoints for a workflow, ordered by `step_index DESC`. Returns 404 if no checkpoints exist for the workflow. |
|
||||
| DELETE | `/workspaces/:id/checkpoints/:wfid` | WorkspaceAuth | Clear all checkpoints for a workflow. Called by the runtime on clean task completion. Returns 404 if none exist. |
|
||||
|
||||
**Step names and indices:**
|
||||
|
||||
| Step | `step_index` | Meaning |
|
||||
|------|-------------|---------|
|
||||
| `task_receive` | 0 | Task received from A2A message |
|
||||
| `llm_call` | 1 | LLM inference completed |
|
||||
| `task_complete` | 2 | Task result sent back to caller |
|
||||
|
||||
---
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"title": "API Reference",
|
||||
"pages": ["index", "workspaces", "communication", "memory", "integrations", "realtime"]
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
---
|
||||
title: "Real-time & Observability API"
|
||||
description: "Canvas, traces, audit ledger, events, terminal, WebSocket, and Server-Sent Events endpoints."
|
||||
---
|
||||
|
||||
## Canvas
|
||||
|
||||
Canvas viewport persistence (cosmetic only).
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/canvas/viewport` | None | Get the saved canvas viewport (zoom, pan position). Open endpoint for bootstrap-friendliness. |
|
||||
| PUT | `/canvas/viewport` | CanvasOrBearer | Save the canvas viewport. Accepts bearer OR matching `Origin` header. Worst case on forgery: viewport corruption, recovered by page refresh. |
|
||||
|
||||
---
|
||||
|
||||
## Traces
|
||||
|
||||
LLM trace retrieval from Langfuse.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/traces` | WorkspaceAuth | List LLM traces for a workspace from Langfuse. |
|
||||
|
||||
---
|
||||
|
||||
## Audit Ledger
|
||||
|
||||
HMAC-SHA256-chained immutable agent event log for compliance record-keeping (EU AI Act Art. 12 / Art. 13). Each event is cryptographically chained to the previous one — tampering with any record breaks all subsequent HMACs.
|
||||
|
||||
<Callout type="warn">
|
||||
**`AUDIT_LEDGER_SALT` required.** The platform and workspace containers must share the same `AUDIT_LEDGER_SALT` environment variable to compute and verify event HMACs. Set it in both your platform env and workspace container env. If the variable is absent, `chain_valid` returns `null` (not `false`) — no records are lost, verification is simply unavailable.
|
||||
</Callout>
|
||||
|
||||
### Query
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/audit` | WorkspaceAuth | Query the audit ledger for a workspace. Returns events in descending chronological order with inline chain verification. |
|
||||
|
||||
**Query parameters:**
|
||||
|
||||
| Parameter | Type | Description |
|
||||
|-----------|------|-------------|
|
||||
| `agent_id` | string | Filter to a specific agent. |
|
||||
| `session_id` | string | Filter to a specific session. |
|
||||
| `from` | RFC 3339 | Start of time range (e.g. `2026-04-01T00:00:00Z`). |
|
||||
| `to` | RFC 3339 | End of time range. |
|
||||
| `limit` | int | Max records to return. Capped at **500**. |
|
||||
| `offset` | int | Pagination offset. |
|
||||
|
||||
**Response shape:**
|
||||
|
||||
```json
|
||||
{
|
||||
"events": [
|
||||
{
|
||||
"id": "uuid",
|
||||
"workspace_id": "uuid",
|
||||
"agent_id": "my-researcher",
|
||||
"session_id": "sess_abc123",
|
||||
"event_type": "tool_call",
|
||||
"payload": { "tool": "bash", "input": "ls /workspace" },
|
||||
"hmac": "sha256hex...",
|
||||
"prev_hmac": "sha256hex...",
|
||||
"created_at": "2026-04-17T12:00:00Z"
|
||||
}
|
||||
],
|
||||
"chain_valid": true
|
||||
}
|
||||
```
|
||||
|
||||
`chain_valid` values:
|
||||
- `true` — all HMACs verified; ledger is intact.
|
||||
- `false` — at least one HMAC mismatch; possible tampering.
|
||||
- `null` — `AUDIT_LEDGER_SALT` is absent from the platform env; verification skipped.
|
||||
|
||||
### Workspace-side: recording events
|
||||
|
||||
In your workspace template, wire `LedgerHooks` into the agent pipeline:
|
||||
|
||||
```python
|
||||
from molecule_audit.hooks import LedgerHooks
|
||||
|
||||
hooks = LedgerHooks(agent_id="my-researcher", session_id=session_id)
|
||||
|
||||
async with hooks:
|
||||
# hooks.on_task_start / on_llm_call / on_tool_call / on_task_end
|
||||
# fire automatically at each pipeline stage
|
||||
result = await agent.run(task)
|
||||
```
|
||||
|
||||
`LedgerHooks` is exception-safe — a failed ledger write never aborts the agent task.
|
||||
|
||||
### CLI chain verification
|
||||
|
||||
```bash
|
||||
# Verify the full chain for an agent; exit 0 = intact
|
||||
python -m molecule_audit.verify --agent-id my-researcher
|
||||
|
||||
# Custom DB URL
|
||||
python -m molecule_audit.verify --agent-id my-researcher --db postgresql://user:pass@host/db
|
||||
```
|
||||
|
||||
Exit codes: `0` = chain valid · `1` = broken chain · `2` = `AUDIT_LEDGER_SALT` missing · `3` = DB error.
|
||||
|
||||
---
|
||||
|
||||
## Events
|
||||
|
||||
Append-only event log for structure changes.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/events` | AdminAuth | List all structure events across all workspaces. |
|
||||
| GET | `/events/:workspaceId` | AdminAuth | List structure events for a specific workspace. |
|
||||
|
||||
---
|
||||
|
||||
## Terminal
|
||||
|
||||
WebSocket-based terminal access to workspace containers.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| WS | `/workspaces/:id/terminal` | WorkspaceAuth | Open a WebSocket terminal session to the workspace container. Provides interactive shell access. |
|
||||
|
||||
---
|
||||
|
||||
## WebSocket
|
||||
|
||||
Real-time event streaming for Canvas clients.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| WS | `/ws` | None | Connect to the WebSocket hub. Receives all structure events (`WORKSPACE_ONLINE`, `WORKSPACE_OFFLINE`, `HEARTBEAT`, `CONFIG_UPDATED`, `A2A_RESPONSE`, `AGENT_MESSAGE`, etc.). Canvas clients connect here for real-time updates. |
|
||||
|
||||
---
|
||||
|
||||
## Server-Sent Events (AG-UI)
|
||||
|
||||
Per-workspace SSE stream compatible with the [AG-UI protocol](https://github.com/ag-ui-protocol/ag-ui). Use this endpoint to consume structured agent events from a web client or external tool without a WebSocket library.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/events/stream` | WorkspaceAuth | Open an SSE stream for the workspace. Returns `Content-Type: text/event-stream`. Sends an initial `: ping` comment on connect, then delivers every event emitted by the workspace in AG-UI envelope format. Events from other workspaces are filtered out. Returns `404` if the workspace does not exist. |
|
||||
|
||||
### Event envelope format
|
||||
|
||||
Each event is delivered as an SSE `data:` line containing a JSON object:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "AGENT_MESSAGE",
|
||||
"timestamp": 1713398400000,
|
||||
"data": { ... }
|
||||
}
|
||||
```
|
||||
|
||||
- **`type`** — event type string (e.g. `AGENT_MESSAGE`, `A2A_RESPONSE`, `TASK_UPDATED`)
|
||||
- **`timestamp`** — Unix milliseconds at time of broadcast
|
||||
- **`data`** — event-specific payload (same payload as the WebSocket hub delivers)
|
||||
|
||||
### Event types streamed
|
||||
|
||||
All event types emitted by `RecordAndBroadcast` **and** `BroadcastOnly` reach the SSE stream. The `BroadcastOnly` path is important: events like `AGENT_MESSAGE`, `A2A_RESPONSE`, and `TASK_UPDATED` skip Redis and would be invisible to a Redis-only subscriber — the in-process SSE layer catches them.
|
||||
|
||||
### Example: connect with `curl`
|
||||
|
||||
```bash
|
||||
curl -N \
|
||||
-H "Authorization: Bearer <workspace-token>" \
|
||||
http://localhost:8080/workspaces/<id>/events/stream
|
||||
```
|
||||
|
||||
```
|
||||
: ping
|
||||
|
||||
data: {"type":"AGENT_MESSAGE","timestamp":1713398401234,"data":{"text":"Starting task..."}}
|
||||
|
||||
data: {"type":"TASK_UPDATED","timestamp":1713398405678,"data":{"status":"running"}}
|
||||
```
|
||||
|
||||
### Example: connect from JavaScript
|
||||
|
||||
```js
|
||||
const es = new EventSource(
|
||||
`/workspaces/${workspaceId}/events/stream`,
|
||||
{ headers: { Authorization: `Bearer ${token}` } }
|
||||
);
|
||||
|
||||
es.onmessage = (e) => {
|
||||
const event = JSON.parse(e.data);
|
||||
console.log(event.type, event.data);
|
||||
};
|
||||
```
|
||||
|
||||
<Callout type="info">
|
||||
The SSE endpoint uses WorkspaceAuth — the bearer token must be bound to the `:id` in the path. A token for workspace A cannot open a stream for workspace B.
|
||||
</Callout>
|
||||
|
||||
---
|
||||
@@ -0,0 +1,149 @@
|
||||
---
|
||||
title: "Workspaces API"
|
||||
description: "Workspace CRUD, lifecycle, budget, configuration, files, activity, and session search endpoints."
|
||||
---
|
||||
|
||||
## Workspaces
|
||||
|
||||
Core workspace CRUD and lifecycle operations.
|
||||
|
||||
### CRUD
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| POST | `/workspaces` | AdminAuth | Create a new workspace. Accepts `name`, `runtime`, `template`, `parent_id`, `tier`, `workspace_dir`, and other fields. Runtime is auto-detected from template config if omitted (defaults to `langgraph`). |
|
||||
| GET | `/workspaces` | AdminAuth | List all workspaces with status, runtime, agent card, position, and hierarchy info. |
|
||||
| GET | `/workspaces/:id` | WorkspaceAuth | Get a single workspace by ID. |
|
||||
| PATCH | `/workspaces/:id` | WorkspaceAuth | Update workspace fields. A workspace bearer token is always required — unauthenticated calls return 401. Validates field constraints: `name` ≤ 255 chars, `role` ≤ 1,000 chars, `model` and `runtime` ≤ 100 chars each; `name` and `role` must not contain newlines (`\\n`, `\\r`) or YAML-special characters (`{}[]|>*&!`). Oversized or invalid field values return 400. `:id` must be a valid UUID. Financial fields (`budget_limit`) are not accepted here — use `PATCH /workspaces/:id/budget` (AdminAuth). |
|
||||
| DELETE | `/workspaces/:id` | AdminAuth | Delete a workspace. Stops the container, revokes all auth tokens, and removes all associated data. |
|
||||
|
||||
### Lifecycle
|
||||
|
||||
| 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. 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. |
|
||||
|
||||
<Callout type="info">
|
||||
**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.
|
||||
</Callout>
|
||||
|
||||
### Budget
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/budget` | AdminAuth | Read a workspace's current spend and ceiling. Returns `budget_limit`, `monthly_spend`, and `budget_remaining` (all in USD cents). |
|
||||
| PATCH | `/workspaces/:id/budget` | AdminAuth | Set or clear a workspace's monthly spend ceiling. Body: `{ "budget_limit": N }` (positive integer, USD cents) or `{ "budget_limit": null }` to remove the cap. Negative values → 400. Returns same shape as GET. |
|
||||
|
||||
**Request / response shape:**
|
||||
|
||||
```json
|
||||
// PATCH request body
|
||||
{ "budget_limit": 500 } // $5.00/month ceiling
|
||||
{ "budget_limit": null } // no ceiling
|
||||
|
||||
// GET and PATCH success response (200)
|
||||
{
|
||||
"budget_limit": 500, // null when no ceiling
|
||||
"monthly_spend": 312, // accumulated spend this period, USD cents
|
||||
"budget_remaining": 188 // null when no ceiling; max(0, limit-spend) — can be negative
|
||||
}
|
||||
```
|
||||
|
||||
<Callout type="warn">
|
||||
**`budget_limit` and `monthly_spend` are absent from `GET /workspaces/:id`**
|
||||
|
||||
Financial fields are stripped unconditionally from the workspace detail
|
||||
response — they do not appear for any caller, authenticated or not. Always
|
||||
use `GET /workspaces/:id/budget` (AdminAuth) to read spend data.
|
||||
|
||||
`budget_limit` is also **not** accepted on the general `PATCH /workspaces/:id`
|
||||
endpoint. Use the dedicated `/budget` route.
|
||||
</Callout>
|
||||
|
||||
<Callout type="info">
|
||||
**Enforcement and fail-open behaviour**
|
||||
|
||||
When `monthly_spend >= budget_limit`, `POST /workspaces/:id/a2a` returns:
|
||||
```
|
||||
HTTP 402 Payment Required
|
||||
{"error": "workspace budget limit exceeded"}
|
||||
```
|
||||
Channel sends (Slack, Telegram, Discord, Lark) are also budget-gated with
|
||||
the same 402 response. The workspace itself is **not paused** — it keeps
|
||||
running; only inbound A2A and channel traffic is blocked.
|
||||
|
||||
**Fail-open:** if the budget check encounters a DB error, traffic is allowed
|
||||
through rather than blocked. The spend ceiling is a soft guardrail, not a
|
||||
hard guarantee.
|
||||
</Callout>
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/config` | WorkspaceAuth | Get the workspace's `config.yaml` contents. |
|
||||
| PATCH | `/workspaces/:id/config` | WorkspaceAuth | Update the workspace config. "Save & Restart" writes config and auto-restarts; "Save" writes only and shows a restart banner in the Canvas. |
|
||||
| GET | `/workspaces/:id/model` | WorkspaceAuth | Get the workspace's current model selection. |
|
||||
| PUT | `/workspaces/:id/model` | WorkspaceAuth | Set the workspace model (e.g. `anthropic:claude-sonnet-4-6`). |
|
||||
| GET | `/workspaces/:id/provider` | WorkspaceAuth | Get the resolved LLM provider for the workspace's runtime + model. |
|
||||
| PUT | `/workspaces/:id/provider` | WorkspaceAuth | Override the LLM provider for the workspace. |
|
||||
|
||||
---
|
||||
|
||||
## Files
|
||||
|
||||
Workspace file management. Files are stored in the workspace's config directory.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/files` | WorkspaceAuth | List files in the workspace config directory. |
|
||||
| GET | `/workspaces/:id/files/*path` | WorkspaceAuth | Read a specific file. |
|
||||
| PUT | `/workspaces/:id/files/*path` | WorkspaceAuth | Write a file. Creates parent directories as needed. On SaaS workspaces (EC2, no Docker), routes via EC2 Instance Connect endpoint using an ephemeral SSH key pair — the key is scoped to the file-write operation and deleted within 30 seconds. Max payload ~10 MiB. Self-hosted Docker workspaces write via `docker cp` as before. |
|
||||
| DELETE | `/workspaces/:id/files/*path` | WorkspaceAuth | Delete a file. |
|
||||
|
||||
---
|
||||
|
||||
## Activity
|
||||
|
||||
Activity logging and search for A2A communications, task updates, and agent logs.
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/activity` | WorkspaceAuth | List activity logs for a workspace. Supports `?source=canvas` or `?source=agent` filter, and `?type=delegation` for A2A topology overlay polling. |
|
||||
| POST | `/workspaces/:id/activity` | WorkspaceAuth | Log an activity entry (used by workspace runtimes to self-report). |
|
||||
| POST | `/workspaces/:id/notify` | WorkspaceAuth | Agent-to-user push message via WebSocket. Delivers a notification to connected Canvas clients. |
|
||||
|
||||
---
|
||||
|
||||
## Session Search
|
||||
|
||||
| Method | Path | Auth | Description |
|
||||
|--------|------|------|-------------|
|
||||
| GET | `/workspaces/:id/session-search` | WorkspaceAuth | Search activity logs with filters for type, date range, and text content. Returns paginated results. |
|
||||
|
||||
---
|
||||
@@ -144,7 +144,7 @@ Set `SMOLAGENTS_ENV_DENYLIST=VAR1,VAR2` in the workspace's secrets to extend the
|
||||
2. Truncated at 2 000 characters to prevent oversized payloads
|
||||
3. HTML-entity-escaped to block social-engineering injections embedded in agent output
|
||||
|
||||
These controls complement the platform-level secret redaction described in the [API Reference](/docs/api-reference#agent-memories-hma-scoped).
|
||||
These controls complement the platform-level secret redaction described in the [API Reference](/docs/api-reference/memory#agent-memories-hma-scoped).
|
||||
|
||||
### molecli
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ 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.
|
||||
|
||||
See the [API Reference](/docs/api-reference#budget) for the full endpoint specification.
|
||||
See the [API Reference](/docs/api-reference/workspaces#budget) for the full endpoint specification.
|
||||
|
||||
### Workspace status lifecycle
|
||||
|
||||
@@ -52,7 +52,7 @@ See the [API Reference](/docs/api-reference#budget) for the full endpoint specif
|
||||
| `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.
|
||||
**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/workspaces#lifecycle) for the `/hibernate` endpoint and configuration details.
|
||||
|
||||
## External agents
|
||||
|
||||
|
||||
@@ -343,7 +343,7 @@ If you are routing a Gemini model through a key that triggers the compat shim (e
|
||||
## See also
|
||||
|
||||
- [Concepts — Workspaces](/docs/concepts#workspaces)
|
||||
- [API Reference — POST /workspaces](/docs/api-reference#workspaces)
|
||||
- [API Reference — POST /workspaces](/docs/api-reference/workspaces#workspaces)
|
||||
- [Google ADK Runtime](/docs/google-adk) — Gemini-native alternative to Hermes for ADK-first workflows
|
||||
- PR #240: [Phase 2a — native Anthropic dispatch](https://git.moleculesai.app/molecule-ai/molecule-core/pull/240)
|
||||
- PR #255: [Phase 2b — native Gemini dispatch](https://git.moleculesai.app/molecule-ai/molecule-core/pull/255)
|
||||
|
||||
@@ -168,5 +168,5 @@ This header is added automatically by the workspace executor when `task_budget >
|
||||
- [Concepts — Workspaces](/docs/concepts#workspaces) — workspace primitives overview
|
||||
- [Org Template](/docs/org-template) — deploy effort/task_budget settings across an entire team via `org.yaml`
|
||||
- [Observability](/docs/observability) — monitor token usage per workspace to tune your budget settings
|
||||
- [API Reference — POST /workspaces](/docs/api-reference#workspaces)
|
||||
- [API Reference — POST /workspaces](/docs/api-reference/workspaces#workspaces)
|
||||
- [Claude Opus 4.7 — Anthropic docs](https://platform.claude.com/docs/) — upstream reference for `output_config`
|
||||
Reference in New Issue
Block a user