Files
core-be 8cea4a30c4
gate-check-v3 / gate-check (pull_request) Waiting to run
qa-review / approved (pull_request) Waiting to run
security-review / approved (pull_request) Waiting to run
sop-checklist / review-refire (pull_request) Waiting to run
sop-tier-check / tier-check (pull_request) Waiting to run
sop-tier-check / tier-check (pull_request_review) Successful in 9s
ci-arm64-advisory / fast-checks (pull_request) Waiting to run
Block internal-flavored paths / Block forbidden paths (pull_request) Successful in 11s
Lint shellcheck (arm64 pilot) / shellcheck-arm64 (pilot) (pull_request) Successful in 12s
E2E Chat / detect-changes (pull_request) Successful in 16s
E2E Staging Canvas (Playwright) / detect-changes (pull_request) Successful in 11s
Handlers Postgres Integration / detect-changes (pull_request) Successful in 12s
Harness Replays / detect-changes (pull_request) Successful in 12s
Lint forbidden tenant-env keys / Scan workspace_secrets writers for forbidden env keys (pull_request) Successful in 12s
Lint no tenant GITEA or GITHUB token write / Scan for repo-host token write into tenant workspace surface (pull_request) Successful in 8s
Secret scan / Scan diff for credential-shaped strings (pull_request) Successful in 7s
sop-checklist / review-refire (pull_request_target) Has been skipped
sop-checklist / all-items-acked (pull_request) acked: 7/7
sop-checklist / na-declarations (pull_request) N/A: (none)
qa-review / approved (pull_request_target) Successful in 4s
sop-checklist / all-items-acked (pull_request_target) Successful in 4s
security-review / approved (pull_request_target) Successful in 4s
gate-check-v3 / gate-check (pull_request_target) Successful in 4s
sop-tier-check / tier-check (pull_request_target) Successful in 4s
verify-providers-gen / Regenerate providers artifact and fail on drift (pull_request) Successful in 59s
Handlers Postgres Integration / Handlers Postgres Integration (pull_request) Successful in 0s
lint-required-no-paths / lint-required-no-paths (pull_request) Successful in 1m28s
E2E Staging Canvas (Playwright) / Canvas tabs E2E (pull_request) Successful in 2s
Harness Replays / Harness Replays (pull_request) Successful in 1s
E2E Chat / E2E Chat (pull_request) Successful in 6s
E2E API Smoke Test / detect-changes (pull_request) Successful in 13s
E2E API Smoke Test / E2E API Smoke Test (pull_request) Successful in 1m35s
audit-force-merge / audit (pull_request_target) Successful in 4s
CI / Platform (Go) (pull_request) Has been cancelled
CI / Canvas (Next.js) (pull_request) Has been cancelled
CI / Shellcheck (E2E scripts) (pull_request) Has been cancelled
CI / Canvas Deploy Reminder (pull_request) Has been cancelled
CI / Detect changes (pull_request) Has been cancelled
CI / all-required (pull_request) Failing after 40m22s
CI / Python Lint & Test (pull_request) Has been cancelled
docs(openapi): apply Five-Axis review fixes to management spec
Verified each against the authoritative handler source (molecule-core
workspace-server + molecule-controlplane) before editing:

1. tenantAdminToken: http/bearer -> apiKey header X-Molecule-Admin-Token.
   authenticateTenant (controlplane workspace_provision.go) reads that
   header, NOT Authorization, and derives org from the token
   (SELECT org_id ... WHERE admin_token=$1). Removed orgRoutingHeaderId
   from the DELETE /api/v1/workspaces/{workspace_id} security — no
   X-Molecule-Org-Id is read on deprovision.
2. ProvisionStatus.stage: added `failed` (emitted by orgs.go on
   failed/deprovisioning/deprovisioned). Existing launching/installing/
   starting/configuring_https/ready all confirmed emitted by
   orgs_progress.go + estimateBootProgress — none trimmed.
3. GET /workspaces/{id}: set security: [] — router.go registers it
   outside every auth group (intentionally open for canvas-node self-
   polling). Dropped the now-inapplicable 401.
4. Multi-period budget shape: added `budget_limits` (canonical) + legacy
   `budget_limit` to PatchBudgetRequest, and `periods` (+ PeriodBudget)
   to BudgetResponse, matching budget.go budgetResponse/PatchBudget.
5. GET tenant llm-billing-mode already modeled (handler serves GET+PUT) —
   no change needed; verified.
6. Added prune=true destructive note (only literal "true" permanently
   deletes, internal#734) and the CP-admin
   /api/v1/admin/workspaces/{id}/llm-billing-mode GET+PUT pair
   (cpAdminBearer, requires ?org_slug=).

redocly lint clean under both recommended and recommended-strict.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 22:29:07 -07:00
..

Molecule Platform OpenAPI specs

This directory holds the machine-readable API contracts for the Molecule platform.

File Spec Scope Status
management.yaml OpenAPI 3.1 The management surface across both services (orgs, billing, admin, provisioning, workspaces, secrets, templates, org-tokens, bundles). SSOT — hand-authored.
swagger.yaml / swagger.json OpenAPI 2.0 swaggo-generated stub, /schedules only (the per-workspace runtime surface). Legacy stub; superseded for management by management.yaml.

management.yaml is the single source of truth the management tooling derives from — the management MCP server, the management CLI (molecule-cli), and the human-facing API docs (RFC #1706, the gap closed by PLATFORM-MANAGEMENT-API.md §5c). Do not hand-edit those clients' route maps; change them here and regenerate/derive.

The two-service split

One structural fact drives the whole spec: there are two services with two auth stacks, and the management surface spans both.

                         ┌─────────────────────────────────────────┐
   browser / CLI / MCP   │  Control plane (CP)                      │
        │                │  molecule-controlplane @ api.moleculesai │
        │  session       │  /api/v1/* (stable) [+ /cp/* sunset]      │
        ├───────────────▶│  orgs · members · billing · provisioning │
        │  admin bearer  │  · fleet/admin ops · pins                 │
        │  provision sec │                                          │
        └────────────────┴──────────────┬───────────────────────────┘
                                         │ edge reverse-proxy
                                         │ (subdomain / X-Molecule-Org-Slug)
                                         ▼
                         ┌─────────────────────────────────────────┐
   Org API Key / ws tok  │  Tenant workspace-server                 │
        │                │  molecule-core/workspace-server          │
        └───────────────▶│  ONE EC2 per org @ <slug>.moleculesai.app│
                         │  workspaces · secrets · templates ·      │
                         │  org-tokens · bundles                    │
                         └─────────────────────────────────────────┘
  • Control plane (CP)api.moleculesai.app, routes modelled under /api/v1/* (the /cp/* mirror is identical but sunset-headed per RFC #61 and is not duplicated in the spec). Owns orgs, members, billing, provisioning, fleet/admin ops.
  • Tenant workspace-server — one EC2 per org at <slug>.moleculesai.app. Owns workspaces, agents, secrets, templates, org-tokens, bundles. Requests may also be sent to the CP host with an X-Molecule-Org-Slug header; the CP edge reverse-proxies them to the tenant host (the Authorization, X-Molecule-Org-*, and cookie headers pass through unchanged and the tenant's own middleware validates them).

The key consequence, called out in PLATFORM-MANAGEMENT-API.md: the Org API Key is a TENANT credential, not a CP one. It is full tenant-admin over its own org's workspace-server surface and reaches nothing on the CP (org create/delete, billing, members, provisioning all 401/403 it). That is why member/billing tools belong in a separate CP-admin MCP, not the org-key-authed management MCP.

Security scheme → surface map (the tier matrix)

management.yaml defines these securitySchemes; each operation declares the one(s) it accepts. Mirror of PLATFORM-MANAGEMENT-API.md §1:

Scheme What it is Where it applies
workosSession WorkOS AuthKit session cookie mcp_session (+ org membership/ownership checks) CP /api/v1/orgs/*, /api/v1/billing/*. Also accepted on the tenant surface via the CP-session path.
cpAdminBearer CP CP_ADMIN_API_TOKEN operator bearer (AdminGate, constant-time) CP /api/v1/admin/* — admin-create-org, tenant teardown, workspace env, ListOrgWorkspaces, redeploy, pins.
provisionSecret CP PROVISION_SHARED_SECRET bearer CP /api/v1/workspaces/provision, …/status. Routes unmounted when the secret is unset.
tenantAdminToken Per-tenant admin_token (+ X-Molecule-Org-Id) CP DELETE /api/v1/workspaces/:id (deprovision) — in addition to provisionSecret (issue #118).
orgApiKey Tenant Org API Key — Authorization: Bearer <key> + routing header; full tenant-admin, self-minting All tenant routes: /workspaces[/:id], /workspaces/:id/secrets, budget, billing-mode, /settings/secrets, /org/import, /org/templates, /org/tokens, /templates, /bundles.
workspaceToken Per-workspace bearer, bound to one workspace id (+ routing header) Read/lifecycle/secrets on a single /workspaces/:id/*. Rejected on admin list/create/delete when ADMIN_TOKEN is set — use orgApiKey.
orgRoutingHeaderId / orgRoutingHeaderSlug X-Molecule-Org-Id / X-Molecule-Org-Slug Required on every tenant-host request so the edge / TenantGuard route + authorize against the correct org. Send one of them alongside the bearer.

Guards worth knowing (modelled per-operation)

  • Dry-run: POST /api/v1/admin/orgs?dry_run=true — validate + echo, no org created. (The only dry-run on the whole management API.)
  • Confirm token: DELETE /api/v1/admin/tenants/:slug and …/scrub-artifacts — body confirm MUST equal the URL slug, else 400 before any teardown.
  • Force flag: POST /api/v1/admin/workspaces/:id/env — keys matching the secret-keyword guard (TOKEN/SECRET/KEY/PASSWORD) require force=true.
  • Runtime-pin gate: POST /api/v1/workspaces/provision returns 422 RUNTIME_PIN_MISSING when no runtime image pin exists.
  • Auto-restart side-effects: writing a workspace or global secret auto-restarts the affected workspace(s).

Security note (carried from the synthesis spec)

The Org API Key is full tenant-admin and self-minting — a management MCP holding one holds tenant root. There is no scope-down today (TODO in orgtoken). Per-role / per-workspace scoping should ship alongside the management MCP.

Validate

cd workspace-server/docs/openapi
npx @redocly/cli lint management.yaml   # must be clean (0 errors, 0 warnings)

Scope notes / best-effort flags

  • The per-workspace runtime surface (schedules, agent, registry, a2a, memory, approvals, channels, terminal, files) is intentionally out of scope here — that's the runtime contract, not management.
  • A handful of bodies are best-effort from the handlers (org-import inline template, bundle import, list responses with open shapes) and are marked with additionalProperties: true in the schema. Tighten as the handler structs stabilise.
  • /cp/* deprecated mirrors are omitted (identical shapes; RFC #61 Deprecation/Sunset). Build against /api/v1/*.