diff --git a/content/docs/meta.json b/content/docs/meta.json index 908d8eb..8fbe4e4 100644 --- a/content/docs/meta.json +++ b/content/docs/meta.json @@ -15,6 +15,7 @@ "external-agents", "tokens", "api-reference", + "platform-management-api", "mcp-server", "self-hosting", "self-hosting/admin-token", diff --git a/content/docs/platform-management-api/auth-model.mdx b/content/docs/platform-management-api/auth-model.mdx new file mode 100644 index 0000000..7122122 --- /dev/null +++ b/content/docs/platform-management-api/auth-model.mdx @@ -0,0 +1,154 @@ +--- +title: Auth Model +description: Every Molecule management credential — WorkOS session, CP admin bearer, provision secret, Org API Key, per-workspace token, ADMIN_TOKEN — how to obtain each, and the credential → route tier matrix. +--- + +# Auth Model + +Molecule's management surface spans [two services](/docs/platform-management-api#the-one-structural-fact-two-services-two-auth-stacks), +each with its own auth stack. This page enumerates every credential type, how +to obtain it, and exactly which routes it authorizes. + +## The six credential types + +### 1. WorkOS session cookie + +- **Service:** Control plane (`api.moleculesai.app`). +- **What it is:** the browser AuthKit session set after a user signs in through + the dashboard. Carries user identity and org ownership/membership. +- **How to obtain:** sign in via `/auth/login` (AuthKit/WorkOS); the session + cookie is set by the `/auth/callback` redirect. The dashboard sends it + automatically. +- **Authorizes:** the human-owner CP surface — create/delete orgs, manage + members, billing, and (proxied) tenant operations. This is the dashboard's + credential, not a headless-integration credential. +- **Header:** sent as a cookie, plus `X-Molecule-Org-Slug` for org-scoped + routes. + +### 2. CP admin bearer (`CP_ADMIN_API_TOKEN`) + +- **Service:** Control plane, `/api/v1/admin/*` (`/cp/admin/*` is the older, + identical alias). +- **What it is:** the platform-operator master token for fleet operations. +- **How to obtain:** set as an environment variable on the control plane; held + by platform operators only. Not user-facing. +- **Authorizes:** fleet ops, tenant teardown, force-setting workspace env, + image/AMI pins, reapers, beta allowlist. (LLM billing-mode is **not** a CP + route — it lives on the tenant, behind an Org API Key.) +- **Header:** `Authorization: Bearer `. + + +The CP admin bearer is platform-root. It is **not** the Org API Key and **not** +the tenant `ADMIN_TOKEN`. Keep it out of per-org integrations entirely. + + +### 3. Provision shared-secret (+ tenant-admin-token) + +- **Service:** Control plane, `/api/v1/workspaces/provision|:id` (the + `/cp/workspaces/*` prefix is the older, identical alias). +- **What it is:** a shared secret that gates the EC2-side provisioning path. + Deprovision additionally requires the target org's tenant-admin-token. +- **How to obtain:** provisioning is normally driven by the platform itself; + the tenant-admin-token for an org is read from CP admin + (`GET /api/v1/admin/orgs/:slug/admin-token`, CP-admin-bearer gated). +- **Authorizes:** only `POST /api/v1/workspaces/provision`, + `DELETE /api/v1/workspaces/:id`, and `GET …/status`. Nothing else. +- **Header:** the provision secret as `Authorization: Bearer `. + Deprovision adds the per-tenant admin token in **`X-Molecule-Admin-Token`** + (not `Authorization`, not `X-Molecule-Org-Id`). + +### 4. Org API Key (`org_api_tokens`) — the common one + +- **Service:** Tenant (`.moleculesai.app`). +- **What it is:** a named, sha256-hashed, prefixed, revocable token that grants + **full tenant-admin** over its own org. This is the credential behind + dashboard **Settings → Org API Keys**. +- **How to obtain:** mint via the dashboard, or + `POST /org/tokens` on the tenant host (authorized by an existing Org API Key, + `ADMIN_TOKEN`, or a CP session). The plaintext is shown **once**. See + [Getting started](/docs/platform-management-api/getting-started). +- **Authorizes:** the entire tenant-admin surface of its org — workspaces + (list/create/delete/restart), secrets (workspace and org), per-workspace + billing-mode and budget, templates, + bundles, org tokens, plugin allowlist. **Reaches nothing on the CP.** +- **Header:** `Authorization: Bearer ` **and** `X-Molecule-Org-Id: ` + to the tenant host. + + +An Org API Key can **mint and revoke other Org API Keys**. Treat it as tenant +root. There is no scope-down below full-admin today. See the +[security note](/docs/platform-management-api/getting-started#security-tenant-root). + + +### 5. Per-workspace token + +- **Service:** Tenant, `/workspaces/:id/*`. +- **What it is:** a bearer token bound to a **single** workspace; a token for + workspace A cannot touch workspace B. +- **How to obtain:** issued during workspace registration + (`POST /registry/register`). Two mint routes exist: + `POST /workspaces/:id/tokens` (WorkspaceAuth — self-service, from a token + already bound to that workspace) and `POST /admin/workspaces/:id/tokens` + (AdminAuth — Org API Key / `ADMIN_TOKEN`, the route the management MCP/CLI + uses). List with `GET /workspaces/:id/tokens`. See + [Token Management API](/docs/guides/token-management). +- **Authorizes:** run/secrets/config/restart on the bound workspace only. It is + **rejected** on tenant-admin routes (list/create/delete workspaces, org + secrets, org import, templates import, bundles) when `ADMIN_TOKEN` is set. +- **Header:** `Authorization: Bearer `. + +### 6. `ADMIN_TOKEN` (tenant) + +- **Service:** Tenant. +- **What it is:** the per-tenant break-glass bootstrap credential set as an + environment variable on the workspace server. Required in production. +- **How to obtain:** configured at deploy time. See + [ADMIN_TOKEN — Production Requirement](/docs/self-hosting/admin-token). +- **Authorizes:** the full tenant surface (same reach as an Org API Key). Use + it to mint the first Org API Key, then prefer scoped Org API Keys for + day-to-day work. +- **Header:** `Authorization: Bearer `. + +## Credential → route tier matrix + +Read this as: *for a given route surface (rows), which credentials (columns) +are accepted.* `✓` = accepted; `✗` = rejected (401/403); `—` = not applicable +to that service; `public` = no auth required. + +| Surface | WorkOS session | CP admin bearer | Provision-secret | Org API Key (tenant) | Per-workspace token | `ADMIN_TOKEN` (tenant) | +|---|---|---|---|---|---|---| +| **CP** `/api/v1/orgs/*` — create, delete, export, members, billing | ✓ (+ownership) | ✗ | ✗ | ✗ (401) | — | — | +| **CP** `/api/v1/orgs/:slug/instance` — routing lookup | public | public | public | public | — | — | +| **CP** `/api/v1/admin/*` (alias `/cp/admin/*`) — fleet, tenant teardown, ws-env, pins | ✗ (403) | ✓ | ✗ | ✗ | — | — | +| **CP** `/api/v1/workspaces/provision` \| `:id` (deprovision) | ✗ | ✗ | ✓ (deprovision +`X-Molecule-Admin-Token`) | ✗ | — | — | +| **Tenant** `/workspaces/:id/*` — run, secrets, config, restart | via CP-session | — | — | ✓ (any ws in org) | ✓ (bound to `:id`) | ✓ | +| **Tenant** admin — `/workspaces` list/create/delete, `/settings/secrets`, `/org/import`, `/org/tokens`, `/templates/import`, `/bundles` | via CP-session | — | — | ✓ | ✗ (rejected when `ADMIN_TOKEN` set) | ✓ | + +**Notes:** + +- All bearer-token gates use **constant-time** comparison. +- Tenant gates fail-open **only** on a fresh self-host / dev boot — never on + hosted SaaS. +- `GET /api/v1/orgs/:slug/instance` is genuinely public — it is a routing + lookup, not an authenticated read. A `200` from it does not imply your key is + valid. +- An Org API Key can mint/revoke more Org API Keys via `/org/tokens`; revoke + with `DELETE /org/tokens/:id`. +- There is no scope-down below full-admin yet (planned — see + [Scoped roles](/docs/guides/org-api-keys#scoped-roles--coming-soon)). + +## Picking the right credential + +- **Headless integration scoped to one org** → Org API Key. This is the + default. ([Getting started](/docs/platform-management-api/getting-started).) +- **An agent that should only touch its own workspace** → per-workspace token. +- **Per-workspace billing-mode and budget automation** → Org API Key (these are + **tenant** routes — `/admin/workspaces/:id/llm-billing-mode` and + `/workspaces/:id/budget` — *not* CP-session). See the + [reference](/docs/platform-management-api/reference). +- **Workspace provisioning / deprovisioning** → provision shared-secret tier + (credential #3), not CP-session. +- **Org create/delete, member management, and the billing portal/subscription** + → CP session tier (the Org API Key cannot reach these). Today this means + driving the dashboard's session-authed `/cp/*` proxy. +- **Platform-operator fleet work** → CP admin bearer. Operators only. diff --git a/content/docs/platform-management-api/getting-started.mdx b/content/docs/platform-management-api/getting-started.mdx new file mode 100644 index 0000000..2399da1 --- /dev/null +++ b/content/docs/platform-management-api/getting-started.mdx @@ -0,0 +1,139 @@ +--- +title: Getting Started (Org API Key) +description: The most common developer entry point to the Molecule Management API — mint an Org API Key, call the tenant host, and understand the tenant-root security caveat. +--- + +# Getting Started with an Org API Key + +The **Org API Key** is the most common developer entry point to Molecule's +management surface. It is a tenant credential that grants full admin over your +own organization — workspaces, secrets, templates, bundles, and org tokens — +through your org's tenant host. This page gets you from zero to your first +authenticated call. + +## Prerequisites + +- An organization (slug, e.g. `acme`). Its tenant host is + `acme.moleculesai.app`. +- One bootstrap credential to mint the first key — either a signed-in dashboard + session, or the tenant `ADMIN_TOKEN` + ([what that is](/docs/self-hosting/admin-token)). + +## Step 1 — Mint an Org API Key + +### Dashboard + +**Settings → Org API Keys → Mint new key**, name it (e.g. `ci-bot`), and copy +the plaintext token — it is shown **once only**. + +### HTTP + +```bash +curl -X POST https://acme.moleculesai.app/org/tokens \ + -H "Authorization: Bearer $ADMIN_TOKEN" \ + -H "X-Molecule-Org-Id: $ORG_ID" \ + -H "Content-Type: application/json" \ + -d '{"name": "ci-bot"}' +``` + +```json +{ + "id": "tok_01HZX3B7N8PQ9K4M5R6T", + "name": "ci-bot", + "prefix": "mola_k7x9p2q4", + "auth_token": "mola_k7x9p2q4r8s1t3u5v6w0x2y3z", + "created_by": "admin-token", + "created_at": "2026-06-01T00:00:00Z" +} +``` + +**Save the `auth_token` value immediately** — the plaintext is shown **once** +and is never returned again. Store it as `MOLECULE_ORG_TOKEN`. (The `prefix` is +a non-secret identifier you can use to recognize the key later; subsequent list +calls return only `id`/`prefix`/metadata, never `auth_token`.) + +## Step 2 — Find your tenant host (optional) + +The org's routing host is a **public** CP lookup — no auth required: + +```bash +curl https://api.moleculesai.app/api/v1/orgs/acme/instance +``` + +The response gives the tenant hostname you address for every tenant call. + +## Step 3 — Make your first authenticated call + +Every tenant call needs **two** headers: the bearer key and the org-id routing +header. + +```bash +curl https://acme.moleculesai.app/workspaces \ + -H "Authorization: Bearer $MOLECULE_ORG_TOKEN" \ + -H "X-Molecule-Org-Id: $ORG_ID" +``` + +That lists your org's workspaces. From here, see the +[task guides](/docs/platform-management-api/tasks) for provisioning, secrets, +templates, and billing. + +## Step 4 — Use it from the CLI or an MCP client + +- **CLI:** the `molecule` CLI authenticates with `MOLECULE_API_KEY` + (your Org API Key). See [task guides](/docs/platform-management-api/tasks) for + per-task verbs. + + + The current `molecule` CLI's `runHTTP` path does **not** attach an + `Authorization` header, so its `workspace create`/`delete` verbs will `401` + against a hardened tenant. Fixing this (attach `Authorization: Bearer + $MOLECULE_API_KEY`) is the first item on the CLI roadmap — **verify against + the CLI source** before relying on a given verb. + + +- **MCP:** point an MCP client at your org by setting `MOLECULE_API_KEY` plus + the org headers. See [MCP Server Setup](/docs/guides/mcp-server-setup). Note + that today's MCP server is single-tenant **workspace-ops**; org-lifecycle, + cross-org, member, and billing tools are not part of it. + +## What an Org API Key can and cannot do + +**Can** (full tenant-admin over its own org): + +- Create, delete, inspect, restart/pause/resume all workspaces +- Set workspace and org-wide secrets +- Import/export org definitions and bundles; import templates +- Manage the plugin allowlist +- Mint and revoke other Org API Keys +- Approve/reject pending workspace requests + +**Cannot** (all reject it): + +- Anything on the control plane — org create/delete, members, billing, + provisioning, fleet ops (`/api/v1/admin/*`, `/api/v1/orgs/*`) +- Cross into any other organization + +## Security: tenant root + + +**An Org API Key is full tenant-admin and self-minting.** Because it can mint +and revoke more Org API Keys via `/org/tokens`, anything that holds one holds +**tenant root** for that org. There is **no scope-down below full-admin +today** — a "read-only" or "single-workspace" Org API Key does not exist yet. + + +Practical consequences: + +- **An MCP server or CI job holding an Org API Key holds tenant root.** Scope + the blast radius accordingly — dedicated key per integration, least number of + holders, rotate on suspicion. +- **Prefer per-workspace tokens** when an agent only needs its own workspace — + they are bound to a single `:id` and cannot reach the admin surface. See + [Token Management API](/docs/guides/token-management). +- **Keep `ADMIN_TOKEN` as break-glass**, not as a day-to-day credential; mint + named Org API Keys instead so usage is attributable and revocable. +- **Revoke instantly** with `DELETE /org/tokens/:id` — revocation takes effect + on the next request, not after a background sweep. + +Per-role / per-workspace scoping is planned to ship alongside a dedicated +management MCP. Until then, treat every Org API Key as a tenant-root secret. diff --git a/content/docs/platform-management-api/index.mdx b/content/docs/platform-management-api/index.mdx new file mode 100644 index 0000000..4023ae9 --- /dev/null +++ b/content/docs/platform-management-api/index.mdx @@ -0,0 +1,91 @@ +--- +title: Platform Management API +description: Manage Molecule organizations, workspaces, secrets, templates, and API keys over HTTP. The two-service architecture, the credential model, and task-oriented guides — with CLI and MCP equivalents. +--- + +# Platform Management API + +This is the developer-facing guide to **managing a Molecule deployment over +HTTP** — provisioning workspaces, setting secrets, minting API keys, creating +organizations from templates, and configuring billing. It covers the auth +model, a task-oriented cookbook, and the machine-readable contract. + + +This guide is the prose layer. The **machine-readable contract** is the +OpenAPI spec at +[`workspace-server/docs/openapi/management.yaml`](/docs/platform-management-api/reference#machine-readable-contract-openapi) +in `molecule-core` — endpoint shapes (paths, request bodies, response schemas) +derive from that file, not from this page. When this guide and the spec +disagree, the spec wins. Anything this guide marks **"verify against handler"** +is a known-uncertain detail to confirm against the spec or the route handler +before you depend on it. + + +## The one structural fact: two services, two auth stacks + +Molecule is **not one API**. It is two services with two separate auth stacks, +and the single most common integration mistake is presenting a credential to +the wrong host. + +### Control plane (CP) + +- **Host:** `api.moleculesai.app` +- **Route prefixes:** `/api/v1/*` (stable, versioned — build against this) and + `/cp/*` (the older, identical surface; sunset-headed) +- **Owns:** organizations, members, billing, provisioning, fleet operations — + everything that exists *above* a single org. +- **Auth tiers:** WorkOS **session cookie**, CP **admin bearer** + (`CP_ADMIN_API_TOKEN`), **provision shared-secret**, **tenant-admin-token**. + +### Tenant platform (per-org workspace server) + +- **Host:** `.moleculesai.app` (one EC2 per org — e.g. + `agents-team.moleculesai.app`) +- **Owns:** workspaces, agents, secrets, templates, org tokens, bundles, + channels — everything *inside* one org. +- **Auth tiers:** **Org API Key** (`org_api_tokens`), **per-workspace token**, + `ADMIN_TOKEN`, and verified CP-session cookie — all behind `TenantGuard` + (which matches the `X-Molecule-Org-Id` routing header to the host). + +### When to call which host + +| You want to… | Call | Credential | +|---|---|---| +| Create / delete an org, manage members, billing | **CP** `api.moleculesai.app` | WorkOS session (ownership) | +| Fleet ops, tenant teardown, workspace env force-set, image pins | **CP** `/api/v1/admin/*` (`/cp/admin/*` is the older identical alias) | CP admin bearer | +| Provision / deprovision a workspace EC2-side | **CP** `/api/v1/workspaces/*` | provision-secret (+ `X-Molecule-Admin-Token` to deprovision) | +| List / create / restart workspaces, set secrets, mint org keys, import templates | **Tenant** `.moleculesai.app` | Org API Key (most common) | +| Look up an org's routing host (public) | **CP** `GET /api/v1/orgs/:slug/instance` | none (public) | + + +The **Org API Key** — the credential you create under dashboard **Settings → +Org API Keys** — is a **tenant** credential, not a CP one. It authorizes the +*entire tenant-admin surface of its own org* and **nothing** on the CP. Org +create/delete, members, billing, and provisioning all reject it (401/403). See +[Auth model](/docs/platform-management-api/auth-model). + + +## Where to go next + +- **[Getting started](/docs/platform-management-api/getting-started)** — the + Org API Key path, the most common developer entry point. Start here. +- **[Auth model](/docs/platform-management-api/auth-model)** — every credential + type, how to obtain each, and the full credential → route tier matrix. +- **[Task guides](/docs/platform-management-api/tasks)** — provision a + workspace, set a secret, mint/revoke an Org API Key, create an org from a + template, set billing-mode and budget. Each with the exact request plus CLI + and MCP equivalents. +- **[Reference & OpenAPI contract](/docs/platform-management-api/reference)** — + the machine-readable spec and the per-surface endpoint summary. + +## Related existing docs + +This guide ties together several existing references; consult them for depth: + +- [Org-Scoped API Keys](/docs/guides/org-api-keys) — mint/audit/revoke walkthrough. +- [Token Management API](/docs/guides/token-management) — per-workspace bearer tokens. +- [ADMIN_TOKEN — Production Requirement](/docs/self-hosting/admin-token) — the break-glass tenant credential. +- [Org Templates](/docs/org-template) — define a whole org in one YAML file. +- [Platform API (Go Backend)](/docs/api-protocol/platform-api) — tenant route tables. +- [API Reference](/docs/api-reference) — the full endpoint listing. +- [MCP Server Setup](/docs/guides/mcp-server-setup) — connect an MCP client. diff --git a/content/docs/platform-management-api/meta.json b/content/docs/platform-management-api/meta.json new file mode 100644 index 0000000..00e8e11 --- /dev/null +++ b/content/docs/platform-management-api/meta.json @@ -0,0 +1,10 @@ +{ + "title": "Platform Management API", + "pages": [ + "index", + "getting-started", + "auth-model", + "tasks", + "reference" + ] +} diff --git a/content/docs/platform-management-api/reference.mdx b/content/docs/platform-management-api/reference.mdx new file mode 100644 index 0000000..3028c82 --- /dev/null +++ b/content/docs/platform-management-api/reference.mdx @@ -0,0 +1,107 @@ +--- +title: Reference & OpenAPI Contract +description: The machine-readable OpenAPI contract for the Molecule Management API, and a per-surface endpoint summary that derives from it. +--- + +# Reference & OpenAPI Contract + +This guide's prose is the *human* layer. The **contract** — exact paths, +request bodies, response schemas, status codes — is the OpenAPI spec. This page +points you at it and gives a navigational summary by surface. It does **not** +re-author endpoint definitions, to avoid a second source of truth. + +## Machine-readable contract (OpenAPI) + + +The Management API contract is authored as an OpenAPI 3 document at +**`workspace-server/docs/openapi/management.yaml`** in the `molecule-core` +repository (branch `feat/openapi-management-spec`, in review as of 2026-06). +This document is the **single source of truth** for endpoint shapes. The prose +guides in this section derive from it; when they disagree, the spec wins. + + +The pre-existing swaggo-generated `workspace-server/docs/openapi/swagger.yaml` +is a `/schedules`-only **stub** and is **not** the management contract — do not +generate clients from it. Use `management.yaml` once it lands. + +When the spec is published to the docs site, this page will embed the rendered +schema. Until then, read the YAML directly from the source repo. + +## Endpoint summary by surface + +The tables below are a **navigational index**, not the contract. Auth tiers are +per the [auth model](/docs/platform-management-api/auth-model). For request and +response shapes, consult `management.yaml`. + +### Control plane — `api.moleculesai.app` + +Build against the stable `/api/v1/*` prefix; `/cp/*` is identical but +sunset-headed. + +| Method · Path | Purpose | Tier | +|---|---|---| +| `/auth/{signup,login,callback,signout,me,...}` | AuthKit session lifecycle | — | +| `POST /api/v1/orgs` | Create org (`412`/`402`/`409`) | WorkOS session | +| `GET /api/v1/orgs` · `GET/DELETE /api/v1/orgs/:slug` | List / get / delete (owner GDPR purge, `204`) | WorkOS session (+ownership) | +| `GET /api/v1/orgs/:slug/{export,provision-status}` | Export, provision status | WorkOS session | +| `GET /api/v1/orgs/:slug/instance` | Routing lookup | **public** | +| `…/orgs/:slug/members[...]`, invitations | Member management | WorkOS session | +| `/billing/{invoices,checkout,portal,topup,auto-credits}` | Billing | WorkOS session | +| `POST /webhooks/stripe` | Stripe webhook | signature | +| `GET /templates[/:slug]` | List templates | WorkOS session | +| `POST/DELETE /api/v1/admin/templates[/:slug]` | Manage templates | CP admin bearer | +| `GET/POST /api/v1/admin/orgs` (`?dry_run=true`) | Admin org ops | CP admin bearer | +| `GET /api/v1/admin/orgs/:slug/admin-token` | Read tenant-admin-token | CP admin bearer | +| `GET /api/v1/admin/orgs/:slug/workspaces` | List org workspaces | CP admin bearer | +| `DELETE /api/v1/admin/tenants/:slug` (body `{"confirm":""}`) | Tenant teardown | CP admin bearer | +| `/api/v1/admin/tenants/:slug/{redeploy,reboot,diagnostics,console-output,boot-events,scrub-artifacts}` | Tenant fleet ops | CP admin bearer | +| `POST /api/v1/admin/tenants/redeploy-fleet` | Fleet rollout | CP admin bearer | +| `POST /api/v1/admin/workspaces/:id/env` | Force-set workspace env (SSM + restart) | CP admin bearer | +| `/api/v1/admin/tenants/:slug/migrate-data-volume` | Data-volume migration | CP admin bearer | +| `/api/v1/admin/{thin-ami,runtime-image}/{promote,list,rollback}` | Image/AMI pins | CP admin bearer | +| `POST /api/v1/workspaces/provision` (`422 RUNTIME_PIN_MISSING`) | Provision workspace | provision-secret | +| `DELETE /api/v1/workspaces/:id?prune=` | Deprovision | provision-secret + `X-Molecule-Admin-Token` | +| `GET /api/v1/workspaces/:id/status?instance_id=` | Provision status | provision-secret | + +### Tenant workspace server — `.moleculesai.app` + +| Method · Path | Purpose | Tier | +|---|---|---| +| `GET/POST/DELETE /workspaces[/:id]` | Workspace lifecycle | AdminAuth (Org API Key / `ADMIN_TOKEN`) | +| `PATCH /workspaces/:id` · `/restart\|/pause\|/resume\|/hibernate` | Update / lifecycle | WorkspaceAuth | +| `GET/PUT /admin/workspaces/:id/llm-billing-mode` `{mode}` | Read/set billing-mode (`platform_managed\|byok\|disabled`; `null` clears) | AdminAuth (Org API Key) | +| `GET/PATCH /workspaces/:id/budget` | Read/set budget (`budget_limits` period map) | AdminAuth (Org API Key) | +| `POST/PUT /workspaces/:id/secrets` `{key,value}` | Set workspace secret (auto-restart) | WorkspaceAuth | +| `POST /settings/secrets` | Set org-wide secret | AdminAuth | +| `POST /org/import` · `GET /org/templates` | Create workspaces from org template · list | AdminAuth | +| `GET/POST/DELETE /org/tokens[/:id]` | Mint / list / revoke Org API Keys | AdminAuth | +| `GET/PUT /orgs/:id/plugins/allowlist` | Plugin allowlist | AdminAuth | +| `GET /templates` · `POST /templates/import` | Templates | AdminAuth | +| `GET /bundles/export/:id` · `POST /bundles/import` | Bundles | AdminAuth | +| `GET/POST /workspaces/:id/tokens` | Per-workspace tokens (self-service) | WorkspaceAuth | +| `POST /admin/workspaces/:id/tokens` | Mint a per-workspace token (admin tier; used by the management MCP/CLI) | AdminAuth (Org API Key / `ADMIN_TOKEN`) | +| a2a, delegations, registry, activity, schedules, memory, approvals, traces, channels, files, mcp-bridge | Agent/runtime surface | per route | + +For deeper tenant route tables see +[Platform API (Go Backend)](/docs/api-protocol/platform-api) and the +[API Reference](/docs/api-reference). + +## Tooling that consumes this contract + +- **CLI** — the `molecule` CLI (Go/cobra). Today it is primarily a + runtime-bridge; management verbs are being extended and its `runHTTP` path + does not yet attach `Authorization` (verify against source). See per-task + CLI lines in the [task guides](/docs/platform-management-api/tasks). +- **MCP** — [MCP Server Setup](/docs/guides/mcp-server-setup). Today's MCP + server is single-tenant **workspace-ops**; a dedicated org-key-authed + **management MCP** (org/secret/template/token tools) is planned and will be + generated from this same OpenAPI contract. +- **Dashboard** — the canonical management surface (AuthKit session + + `X-Molecule-Org-Slug`), org ops via the `/cp/*` proxy, tenant ops direct. + + +Generate clients and MCP tools from `management.yaml`, **not** from the +`/schedules`-only swaggo stub. The MCP, CLI, and these docs all derive from the +one OpenAPI contract — keeping them downstream of a single SSOT is what prevents +drift. + diff --git a/content/docs/platform-management-api/tasks.mdx b/content/docs/platform-management-api/tasks.mdx new file mode 100644 index 0000000..7b5aa8f --- /dev/null +++ b/content/docs/platform-management-api/tasks.mdx @@ -0,0 +1,300 @@ +--- +title: Task Guides +description: Cookbook for the Molecule Management API — provision a workspace, set a secret, mint/revoke an Org API Key, create an org from a template, and set billing-mode/budget. Each with the exact HTTP request plus CLI and MCP equivalents. +--- + +# Task Guides + +A task-oriented cookbook for the Management API. Each task gives the **exact +HTTP request** (host, method, path, headers, body) plus the **CLI** and **MCP** +equivalents where they exist. + +Conventions used below: + +- `$ORG_SLUG` / `$ORG_ID` — your org's slug and id. +- `$TENANT` — your tenant host, `$ORG_SLUG.moleculesai.app`. +- `$MOLECULE_ORG_TOKEN` — an [Org API Key](/docs/platform-management-api/getting-started). +- `$CP_ADMIN_TOKEN` — the CP admin bearer (operators only). + + +Request bodies and response schemas below are the prose rendering of the +[OpenAPI contract](/docs/platform-management-api/reference). Where a header name +or field is not yet pinned in the synthesis, it is marked **"verify against +handler"** — confirm against the spec or the route handler before depending on +it. + + +--- + +## Provision a workspace + +There are **two** ways to create a workspace, on two different hosts: + +### A. Tenant-side create (the common path) + +Creates and provisions a workspace within your org. Org API Key works. + +```http +POST https://$TENANT/workspaces +Authorization: Bearer $MOLECULE_ORG_TOKEN +X-Molecule-Org-Id: $ORG_ID +Content-Type: application/json + +{ + "name": "researcher", + "role": "Research agent", + "model": "claude-sonnet-4", + "runtime": "claude-code" +} +``` + +Field constraints (enforced server-side): `name` ≤ 255 chars, `role` ≤ 1000, +`model`/`runtime` ≤ 100; `name` and `role` reject newlines and YAML-special +chars (`{}[]|>*&!`). See +[Platform API breaking changes](/docs/api-protocol/platform-api#breaking-changes). + +- **CLI:** `molecule workspace create --name researcher --role "Research agent" --model claude-sonnet-4 --runtime claude-code` +- **MCP:** `provision_workspace` (planned management MCP) — today, workspace + create is available in the single-tenant workspace-ops MCP. + +### B. Control-plane provision (EC2-side) + +The low-level provisioning entrypoint, gated by the provision shared-secret. +Build against the stable `/api/v1/workspaces/*` surface (the `/cp/workspaces/*` +prefix is the older, identical alias). Returns `422 RUNTIME_PIN_MISSING` if no +runtime image is pinned. Normally driven by the platform server-to-server, not +by integrations. + +```http +POST https://api.moleculesai.app/api/v1/workspaces/provision +Authorization: Bearer +Content-Type: application/json + +{ ... } +``` + +**Deprovision** additionally requires the per-tenant admin token in the +**`X-Molecule-Admin-Token`** header (so a leaked shared secret can't terminate +other tenants' workspaces — controlplane #118): + +```http +DELETE https://api.moleculesai.app/api/v1/workspaces/:id?prune= +Authorization: Bearer +X-Molecule-Admin-Token: +``` + +- **Status:** `GET https://api.moleculesai.app/api/v1/workspaces/:id/status?instance_id=` + +--- + +## Set a workspace or org secret + +Workspace **environment variables *are* secrets** — there is no separate `/env` +route on the tenant. Setting a secret **auto-restarts** the workspace. + +### Per-workspace secret + +```http +POST https://$TENANT/workspaces/:id/secrets +Authorization: Bearer $MOLECULE_ORG_TOKEN +X-Molecule-Org-Id: $ORG_ID +Content-Type: application/json + +{ "key": "MY_API_KEY", "value": "..." } +``` + +(`PUT` is also accepted for upsert.) The value is encrypted AES-256-GCM into +`workspace_secrets`, emits a `secret.set` audit event, and the workspace +restarts automatically. + +### Org-wide secret + +```http +POST https://$TENANT/settings/secrets +Authorization: Bearer $MOLECULE_ORG_TOKEN +X-Molecule-Org-Id: $ORG_ID +Content-Type: application/json + +{ "key": "...", "value": "..." } +``` + + +**Platform-managed billing strips vendor-LLM keys.** Under platform-managed +billing, keys like `ANTHROPIC_API_KEY` and `CODEX_AUTH_JSON` are stripped on +set unless the workspace's billing-mode is flipped to `byok` +([see below](#set-billing-mode-or-budget)). Generic `GIT_HTTP_*` secrets are +never stripped. + + +- **CLI:** `molecule secret ws set --workspace MY_API_KEY=...` + / `molecule secret org set KEY=...` +- **MCP:** `set_workspace_secret` / `set_org_secret` (planned management MCP). + +--- + +## Mint and revoke an Org API Key + +Minting and revoking happen on the tenant host (`/org/tokens`). See the full +[Org-Scoped API Keys](/docs/guides/org-api-keys) walkthrough for audit fields. + +### Mint + +```http +POST https://$TENANT/org/tokens +Authorization: Bearer $MOLECULE_ORG_TOKEN +X-Molecule-Org-Id: $ORG_ID +Content-Type: application/json + +{ "name": "ci-bot" } +``` + +Returns the plaintext `auth_token` (alongside `id` and `prefix`) **once** — it +is never returned again. An existing Org API Key, the tenant `ADMIN_TOKEN`, or a +CP session can mint. + +### List + +```http +GET https://$TENANT/org/tokens +Authorization: Bearer $MOLECULE_ORG_TOKEN +X-Molecule-Org-Id: $ORG_ID +``` + +Returns metadata only — the plaintext is never returned after creation. + +### Revoke + +```http +DELETE https://$TENANT/org/tokens/:id +Authorization: Bearer $MOLECULE_ORG_TOKEN +X-Molecule-Org-Id: $ORG_ID +``` + +Revocation is instantaneous — the next request with the revoked key fails. + +- **CLI:** `molecule org token create --name ci-bot` + / `molecule org token list` + / `molecule org token revoke ` +- **MCP:** `mint_org_token` / `list_org_tokens` / `revoke_org_token` (planned + management MCP). + + +Because an Org API Key can mint **and revoke** Org API Keys, any holder is +tenant root. See the +[security note](/docs/platform-management-api/getting-started#security-tenant-root). + + +--- + +## Create an org from a template + +Two distinct operations live under "templates": **creating workspaces from an +org template inside an existing org** (tenant `/org/import`), and **creating a +brand-new org** (CP `/api/v1/orgs`, session-tier). + +### Populate an existing org from an org template + +Imports a YAML org template — provisions every workspace, wires parent/child +relationships, seeds schedules, installs plugins. See +[Org Templates](/docs/org-template). + +```http +POST https://$TENANT/org/import +Authorization: Bearer $MOLECULE_ORG_TOKEN +X-Molecule-Org-Id: $ORG_ID +Content-Type: application/json + +{ ...org template YAML/JSON... } # verify body shape against handler / OpenAPI +``` + +List the available org templates with `GET https://$TENANT/org/templates`. + +- **CLI:** `molecule org create --template ` +- **MCP:** `create_org_from_template` → `POST /org/import` (planned). + +### Create a brand-new org (CP, session-tier) + +Creating the organization *itself* is a control-plane, session-authed +operation — **an Org API Key cannot do this.** + +```http +POST https://api.moleculesai.app/api/v1/orgs + + X-Molecule-Org-Slug +Content-Type: application/json + +{ ...org create body... } +``` + +Errors: `412` (no ToS accepted), `402` (quota), `409` (slug taken). A dry-run +exists for the admin variant only: `POST /api/v1/admin/orgs?dry_run=true`. + +--- + +## Set billing-mode or budget + +### LLM billing-mode + +Billing-mode governs whether vendor-LLM secrets are honored +([see secret-stripping above](#set-a-workspace-or-org-secret)). It is a +**tenant** route, keyed by **workspace id** and authorized by an **Org API Key** +(plus the `X-Molecule-Org-Id` routing header) — *not* a control-plane operation: + +```http +GET https://$TENANT/admin/workspaces/:id/llm-billing-mode +PUT https://$TENANT/admin/workspaces/:id/llm-billing-mode +Authorization: Bearer $MOLECULE_ORG_TOKEN +X-Molecule-Org-Id: $ORG_ID +Content-Type: application/json + +{ "mode": "platform_managed" } # or "byok" or "disabled" +``` + +The `mode` field enum is **`platform_managed`**, **`byok`**, or **`disabled`**. +`{"mode":null}` **clears** the per-workspace override (falling back to the org / +default mode); an empty body `{}` is a **400** — the caller must be explicit. + +- **CLI:** `molecule workspace billing-mode ` (verify against CLI source). +- **MCP:** `set_llm_billing_mode` (planned management MCP). + +### Workspace budget + +The per-workspace LLM budget cap is read and written on the **tenant** host, +keyed by workspace id and authorized by an **Org API Key** (`PATCH` is +tenant-admin): + +```http +GET https://$TENANT/workspaces/:id/budget +PATCH https://$TENANT/workspaces/:id/budget +Authorization: Bearer $MOLECULE_ORG_TOKEN +X-Molecule-Org-Id: $ORG_ID +Content-Type: application/json + +{ "budget_limits": { "hourly": 100, "daily": null, "weekly": 500, "monthly": 2000 } } +``` + +The canonical body is the multi-period **`budget_limits`** map (per-period USD +cents; `null` clears that period). The legacy single-monthly shape +`{ "budget_limit": 2000 }` / `{ "budget_limit": null }` is still accepted for +back-compat. Sending neither `budget_limits` nor `budget_limit` is a **400**. + +- **CLI:** `molecule workspace budget` (verify against CLI source). +- **MCP:** `set_workspace_budget` (planned management MCP). + +--- + +## Other common tasks (quick reference) + +| Task | Host | Method · Path | Tier | +|---|---|---|---| +| Restart / pause / resume a workspace | Tenant | `POST /workspaces/:id/{restart\|pause\|resume\|hibernate}` | Org API Key / ws-token | +| List workspaces | Tenant | `GET /workspaces` | Org API Key | +| List org templates | Tenant | `GET /org/templates` | Org API Key | +| Import a template | Tenant | `POST /templates/import` | Org API Key | +| Export / import a bundle | Tenant | `GET /bundles/export/:id` · `POST /bundles/import` | Org API Key | +| Get / set plugin allowlist | Tenant | `GET/PUT /orgs/:id/plugins/allowlist` | Org API Key | +| Delete an org (GDPR purge) | CP | `DELETE /api/v1/orgs/:slug` | WorkOS session (owner) | +| Export an org | CP | `GET /api/v1/orgs/:slug/export` | WorkOS session | +| Provision status | CP | `GET /api/v1/orgs/:slug/provision-status` | WorkOS session | + +For the authoritative per-endpoint contract, see +[Reference & OpenAPI](/docs/platform-management-api/reference).