Parent → child knowledge sharing previously lived behind a `shared_context` list in config.yaml: at boot, every child workspace HTTP-fetched its parent's listed files via GET /workspaces/:id/shared-context and prepended them as a "## Parent Context" block. That paid the full transfer cost on every boot regardless of whether the agent needed it, single-parent SPOF, no team or org scope, and broken if the parent was unreachable. Replace with memory v2's team:<id> namespace: agents call recall_memory on demand. For large blob-shaped artefacts see RFC #2789 (platform-owned shared file storage). Removed: - workspace/coordinator.py: get_parent_context() - workspace/prompt.py: parent_context arg + injection block - workspace/adapter_base.py: import + call + arg pass - workspace/config.py: shared_context field + parser entry - workspace-server/internal/handlers/templates.go: SharedContext handler - workspace-server/internal/router/router.go: GET /shared-context route - canvas/src/components/tabs/ConfigTab.tsx: Shared Context tag input - canvas/src/components/tabs/config/form-inputs.tsx: schema field + default - canvas/src/components/tabs/config/yaml-utils.ts: serializer entry - 6 tests pinning the removed behavior; 5 doc references Added regression gates so any reintroduction is loud: - workspace/tests/test_prompt.py: build_system_prompt must NOT emit "## Parent Context" - workspace/tests/test_config.py: legacy YAML key loads cleanly but shared_context attr must NOT exist on WorkspaceConfig - tests/e2e/test_staging_full_saas.sh §9d: GET /shared-context must NOT return 200 against a live tenant Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
120 lines
8.8 KiB
Markdown
120 lines
8.8 KiB
Markdown
# API Reference
|
|
|
|
This document describes the REST API exposed by the Molecule AI workspace server (Go/Gin, default port `:8080`). Clients include the Canvas frontend, workspace agents communicating over A2A, and external tooling such as the MCP server and CLI.
|
|
|
|
**Base URL:** `http://localhost:8080` (development default)
|
|
**Rate limit:** 600 req/min (configurable via `RATE_LIMIT`)
|
|
**CORS origins:** `http://localhost:3000,http://localhost:3001` by default (configurable via `CORS_ORIGINS`)
|
|
|
|
---
|
|
|
|
## Authentication
|
|
|
|
Three middleware classes gate server-side routes:
|
|
|
|
- **`AdminAuth`** — strict bearer-only. Required for any route that can leak prompts/memory, create/mutate workspaces, or expose ops intel. Lazy-bootstrap fail-open when no live tokens exist globally.
|
|
- **`WorkspaceAuth`** — binds a bearer token to a specific workspace `:id`. A token for workspace A cannot be used against workspace B's sub-routes.
|
|
- **`CanvasOrBearer`** — accepts a bearer token OR a request Origin matching `CORS_ORIGINS`. Used only for cosmetic routes with zero data/security impact (currently `PUT /canvas/viewport` only). Do not extend to routes that leak data or create resources.
|
|
|
|
Full contract: `docs/runbooks/admin-auth.md`.
|
|
|
|
---
|
|
|
|
## Routes
|
|
|
|
| Method | Path | Handler |
|
|
|--------|------|---------|
|
|
| GET | /health | inline |
|
|
| GET | /metrics | metrics.Handler() — Prometheus text format; no auth, scrape-safe |
|
|
| POST/GET/PATCH/DELETE | /workspaces[/:id] | workspace.go — `GET /workspaces`, `POST /workspaces`, and `DELETE /workspaces/:id` require `AdminAuth`. `PATCH /workspaces/:id` enforces field-level authz: cosmetic fields (name, role, x, y, canvas) pass through; sensitive fields (tier, parent_id, runtime, workspace_dir) require a valid bearer token when any live token exists. |
|
|
| GET/PATCH | /workspaces/:id/config | workspace.go |
|
|
| GET/POST | /workspaces/:id/memory | workspace.go |
|
|
| DELETE | /workspaces/:id/memory/:key | workspace.go |
|
|
| POST/PATCH/DELETE | /workspaces/:id/agent | agent.go |
|
|
| POST | /workspaces/:id/agent/move | agent.go |
|
|
| GET/POST/PUT | /workspaces/:id/secrets | secrets.go (POST/PUT auto-restarts workspace) |
|
|
| DELETE | /workspaces/:id/secrets/:key | secrets.go (DELETE auto-restarts workspace) |
|
|
| GET | /workspaces/:id/model | secrets.go |
|
|
| GET | /settings/secrets | secrets.go — list global secrets (keys only, values masked) |
|
|
| PUT/POST | /settings/secrets | secrets.go — set a global secret `{key, value}`; auto-restarts every non-paused/non-removed/non-external workspace that does not shadow the key with a workspace-level override |
|
|
| DELETE | /settings/secrets/:key | secrets.go — delete a global secret; same auto-restart fan-out as PUT/POST |
|
|
| GET | /admin/workspaces/:id/test-token | admin_test_token.go — mint a fresh bearer token for E2E scripts; returns 404 unless `MOLECULE_ENV != production` or `MOLECULE_ENABLE_TEST_TOKENS=1` |
|
|
| GET/POST/DELETE | /admin/secrets[/:key] | secrets.go — legacy aliases for /settings/secrets |
|
|
| WS | /workspaces/:id/terminal | terminal.go |
|
|
| POST | /workspaces/:id/expand | team.go |
|
|
| POST | /workspaces/:id/collapse | team.go |
|
|
| POST/GET | /workspaces/:id/approvals | approvals.go |
|
|
| POST | /workspaces/:id/approvals/:id/decide | approvals.go |
|
|
| GET | /approvals/pending | approvals.go |
|
|
| POST/GET | /workspaces/:id/memories | memories.go |
|
|
| DELETE | /workspaces/:id/memories/:id | memories.go |
|
|
| GET | /workspaces/:id/traces | traces.go |
|
|
| GET/POST | /workspaces/:id/activity | activity.go |
|
|
| POST | /workspaces/:id/notify | activity.go (agent→user push message via WebSocket) |
|
|
| POST | /workspaces/:id/restart | workspace.go |
|
|
| POST | /workspaces/:id/pause | workspace.go (stops container, status→paused) |
|
|
| POST | /workspaces/:id/resume | workspace.go (re-provisions paused workspace) |
|
|
| POST | /workspaces/:id/a2a | workspace.go |
|
|
| POST | /workspaces/:id/delegate | delegation.go (async fire-and-forget) |
|
|
| GET | /workspaces/:id/delegations | delegation.go (list delegation status) |
|
|
| GET/POST | /workspaces/:id/schedules | schedules.go (cron CRUD) |
|
|
| PATCH/DELETE | /workspaces/:id/schedules/:scheduleId | schedules.go |
|
|
| POST | /workspaces/:id/schedules/:scheduleId/run | schedules.go (manual trigger) |
|
|
| GET | /workspaces/:id/schedules/:scheduleId/history | schedules.go (past runs) |
|
|
| GET/POST | /workspaces/:id/channels | channels.go (social channel CRUD) |
|
|
| PATCH/DELETE | /workspaces/:id/channels/:channelId | channels.go |
|
|
| POST | /workspaces/:id/channels/:channelId/send | channels.go (outbound message) |
|
|
| POST | /workspaces/:id/channels/:channelId/test | channels.go (test connection) |
|
|
| GET | /channels/adapters | channels.go (list available platforms) |
|
|
| POST | /channels/discover | channels.go (auto-detect chats for a bot token) |
|
|
| POST | /webhooks/:type | channels.go (incoming social webhook) |
|
|
| GET/PUT/DELETE | /workspaces/:id/files[/*path] | templates.go |
|
|
| GET | /canvas/viewport | viewport.go — open, no auth required (cosmetic, bootstrap-friendly) |
|
|
| PUT | /canvas/viewport | viewport.go — `CanvasOrBearer` middleware; accepts bearer OR Origin matching `CORS_ORIGINS`. Cosmetic-only route — worst case viewport corruption, recovered by page refresh. |
|
|
| GET | /templates | templates.go |
|
|
| POST | /templates/import | templates.go — `AdminAuth` required |
|
|
| POST | /registry/register | registry.go |
|
|
| POST | /registry/heartbeat | registry.go — requires `Authorization: Bearer <token>` once a workspace has any live token on file (legacy workspaces grandfathered) |
|
|
| POST | /registry/update-card | registry.go — requires `Authorization: Bearer <token>` once a workspace has any live token on file |
|
|
| GET | /registry/discover/:id | discovery.go — requires `X-Workspace-ID` + bearer token on the caller side |
|
|
| GET | /registry/:id/peers | discovery.go — requires `X-Workspace-ID` + bearer token on the caller side |
|
|
| POST | /registry/check-access | discovery.go |
|
|
| GET | /plugins | plugins.go (list registry; supports `?runtime=` filter) |
|
|
| GET | /plugins/sources | plugins.go (list registered install-source schemes) |
|
|
| GET/POST/DELETE | /workspaces/:id/plugins[/:name] | plugins.go — list, install (`{"source":"scheme://spec"}`), uninstall per-workspace |
|
|
| GET | /workspaces/:id/plugins/available | plugins.go (filtered by workspace runtime) |
|
|
| GET | /workspaces/:id/plugins/compatibility?runtime=X | plugins.go (preflight runtime-change check) |
|
|
| GET/POST | /workspaces/:id/tokens | tokens.go — list active tokens (prefix + metadata), create new token (plaintext returned once). Max 50 per workspace. |
|
|
| DELETE | /workspaces/:id/tokens/:tokenId | tokens.go — revoke specific token by ID |
|
|
| GET | /bundles/export/:id | bundle.go — `AdminAuth` required |
|
|
| POST | /bundles/import | bundle.go — `AdminAuth` required |
|
|
| GET | /org/templates | org.go (list available org templates) |
|
|
| POST | /org/import | org.go — `AdminAuth` required; applies `resolveInsideRoot` path sanitiser on template paths |
|
|
| GET | /events | events.go — `AdminAuth` required |
|
|
| GET | /events/:workspaceId | events.go — `AdminAuth` required |
|
|
| GET | /admin/liveness | inline — `AdminAuth` required. Returns per-subsystem `supervised.Snapshot()` ages; use to check health of scheduler/heartbeat goroutines |
|
|
| GET | /ws | socket.go |
|
|
|
|
---
|
|
|
|
## Database
|
|
|
|
Migration files live in `workspace-server/migrations/` (latest: `022_workspace_schedules_source`). Each migration ships as a `.up.sql`/`.down.sql` pair. The migration runner globs `*.sql`, filters out `.down.sql` files, sorts alphabetically, and executes each file on boot. All `.up.sql` files must be idempotent (`CREATE TABLE IF NOT EXISTS`, `ALTER TABLE ... IF NOT EXISTS`) because the runner re-applies every migration on every boot.
|
|
|
|
### Key Tables
|
|
|
|
| Table | Description |
|
|
|-------|-------------|
|
|
| `workspaces` | Core entity — status, runtime, `agent_card` JSONB, heartbeat columns, `current_task`, `awareness_namespace`, `workspace_dir` |
|
|
| `canvas_layouts` | Per-workspace x/y canvas position |
|
|
| `structure_events` | Append-only event log (workspace lifecycle, agent, approval events) |
|
|
| `activity_logs` | A2A communications, task updates, agent logs, errors. `error_detail` is populated by the scheduler so cron run history can surface failure reasons. |
|
|
| `workspace_schedules` | Cron tasks — expression, timezone, prompt, run history, `source` (`'template'` for org/import-seeded, `'runtime'` for Canvas/API-created), `last_status` (includes `'skipped'` when the scheduler concurrency-skips a busy workspace) |
|
|
| `workspace_channels` | Social channel integrations (Telegram, Slack, etc.) with JSONB config and allowlist |
|
|
| `agents` | Agent records |
|
|
| `workspace_secrets` | Per-workspace encrypted secrets |
|
|
| `global_secrets` | Platform-wide encrypted secrets |
|
|
| `workspace_auth_tokens` | Bearer tokens; auto-revoked on workspace delete |
|
|
| `agent_memories` | HMA scoped memory (LOCAL / TEAM / GLOBAL) |
|
|
| `approvals` | Human-in-the-loop approval requests |
|