CTO directive: "nothing should be fail-open." Remove the dev-mode fail-open auth hatch so AdminAuth/WorkspaceAuth (and the discovery caller) ALWAYS require a real credential — fail-CLOSED in every environment, dev included — fix local dev to stay AUTHENTICATED (not open), and add a regression gate so fail-open cannot return. Removed fail-open call-sites (workspace-server): - internal/middleware/wsauth_middleware.go WorkspaceAuth — deleted the isDevModeFailOpen() short-circuit that let a bearer-less /workspaces/:id/* request through when MOLECULE_ENV=dev + ADMIN_TOKEN unset. - internal/middleware/wsauth_middleware.go AdminAuth — deleted BOTH fail-open branches: the Tier-1 lazy-bootstrap (no live tokens + no ADMIN_TOKEN ⇒ pass, the C4 /org/import pre-empt hole) and the Tier-1b isDevModeFailOpen() dev hatch. HasAnyLiveTokenGlobal is still probed for the 503-on-outage semantics but opens no path. - internal/handlers/discovery.go validateDiscoveryCaller — deleted the IsDevModeFailOpen() allow branch; discovery now requires a verified CP session or valid bearer in every env. - Removed the isDevModeFailOpen()/IsDevModeFailOpen() helper entirely. The two legitimately non-auth uses (rate-limit relaxation in ratelimit.go, loopback bind default in cmd/server) now key on a new NON-security isLocalDevEnv() predicate (MOLECULE_ENV only, decoupled from ADMIN_TOKEN). CanvasOrBearer's cosmetic-only behaviour (PUT /canvas/viewport) is unchanged. Dev path stays authenticated, not open: - scripts/dev-start.sh provisions a deterministic ADMIN_TOKEN into .env and exports the matching NEXT_PUBLIC_ADMIN_TOKEN so the dev Canvas sends a real bearer (canvas/src/lib/api.ts already attaches it; next.config.ts pair-guard). - Docs updated: .env.example, docs/quickstart.md, docs/architecture/overview.md. Regression gate: - internal/middleware/no_fail_open_test.go — asserts AdminAuth + WorkspaceAuth fail CLOSED (401) under the EXACT old-hatch conditions (ADMIN_TOKEN unset + MOLECULE_ENV=dev/development × hasLive 0/1). Proven RED against a temporarily restored hatch, GREEN after. Plus a source-guard test forbidding the isDevModeFailOpen(-style helper from re-appearing. - Converted the stale fail-open assertions in wsauth_middleware_test.go, discovery_test.go, security_regression_685_686_687_688_test.go and the devmode/bind tests to pin the fail-closed contract. Audit (other fail-open patterns on the auth surface): CanvasOrBearer and validateDiscoveryCaller retain a fail-open-on-DB-error (and CanvasOrBearer a no-token lazy-bootstrap) — both are documented availability tradeoffs on cosmetic / low-sensitivity routes, left as-is and flagged for follow-up. Verify: go build ./... ok; go vet middleware/cmd/handlers clean; full module go test ./... = 46 ok / 0 fail. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
9.1 KiB
Quickstart Guide
This path is aligned to the current repository and current UI. It gets you from clone to a live workspace on the canvas without assuming any extra platform wrapper.
Prerequisites
- Docker + Docker Compose v2
- Node.js 20+
- Go 1.25+
jq(for the template-registry clone insetup.sh)- One model/API key for the runtime you want to use
ANTHROPIC_API_KEYOPENAI_API_KEYGOOGLE_API_KEY- or another provider routed through LiteLLM
The one-command path
git clone https://git.moleculesai.app/molecule-ai/molecule-core.git
cd molecule-core
./scripts/dev-start.sh
That single script:
- Generates an
ADMIN_TOKENinto.env(first run only — preserved on re-runs) and exports the matchingNEXT_PUBLIC_ADMIN_TOKENso the canvas authenticates with it. Auth is fail-closed in every environment (including local dev) — there is no dev-mode fail-open; the canvas reaches admin/workspace routes only because it sends this bearer. - Brings up Postgres, Redis, Langfuse, ClickHouse, and Temporal via
infra/scripts/setup.sh - Populates the workspace template + plugin registry from
manifest.json - Builds and starts the platform on
http://localhost:8080 - Installs canvas deps (first run) and starts the canvas on
http://localhost:3000 - Prints next-step instructions and tails both processes —
Ctrl-Ctears everything down
Total wall-clock: ~30 seconds for a re-run, ~2 minutes for a first run (npm install + docker pulls).
Once the canvas is up: open it, add your model API key in Config → Secrets & API Keys → Global, then click a template card or + Create blank workspace.
Manual setup (advanced)
If you'd rather run each component yourself — useful when you're iterating on the platform binary or the canvas in isolation — follow the steps below. Each section is what dev-start.sh does internally; running them by hand gives you per-component logs and lets you keep one piece running while you restart another.
Step 1: Clone the repository
git clone https://git.moleculesai.app/molecule-ai/molecule-core.git
cd molecule-core
Step 2: Start the shared infrastructure
Recommended:
./infra/scripts/setup.sh
That brings up Postgres, Redis, Langfuse, ClickHouse, and Temporal.
If you only want the raw compose flow:
docker compose -f docker-compose.infra.yml up -d
Auth is fail-closed even in local dev. Pick any local admin token and set it on both sides — the platform (
ADMIN_TOKEN) and the canvas (NEXT_PUBLIC_ADMIN_TOKEN, same value). Without it the canvas 401s on every admin/workspace call. (scripts/dev-start.shdoes this for you; the manual steps below set it explicitly.)
Step 3: Start the platform
cd workspace-server
ADMIN_TOKEN=dev-local-admin-token MOLECULE_ENV=development go run ./cmd/server
The control plane listens on http://localhost:8080.
Step 4: Start the canvas
In a new terminal:
cd canvas
npm install
NEXT_PUBLIC_ADMIN_TOKEN=dev-local-admin-token npm run dev # MUST match ADMIN_TOKEN above
Open http://localhost:3000.
Step 5: Deploy your first workspace
On a fresh canvas, the center empty state shows template cards plus a blank-workspace option.
You can either:
- Click a template to provision a ready-made workspace.
- Click
+ Create blank workspace.
At the same time, the bottom-left onboarding wizard appears and guides the first-run flow.
Step 6: Add an API key
- Select the workspace.
- Open the
Configtab. - Expand
Secrets & API Keys. - Add the API key in either:
This WorkspaceGlobal (All Workspaces)
Global keys are inherited by all workspaces. Workspace keys override globals with the same name.
Step 7: Send the first message
- Open the
Chattab. - Send a prompt such as:
What can you help me with in this workspace?
Responses are delivered through the platform A2A proxy and pushed back to the canvas through WebSocket events, with polling kept only as recovery fallback.
Path 2: Remote Agent (run anywhere)
A remote agent runs on your own machine or a cloud VM — no Docker on the platform side. The agent registers with the platform via API, pulls its secrets at boot, and sends heartbeats to stay live on the canvas.
Use this path if you:
- want to run an agent on your laptop for local development
- need an agent on a machine with specific hardware (GPU, on-prem)
- have a data-residency requirement that keeps agent compute off the platform's infra
Step 0: Prerequisites
- Python 3.10+ and
pip install molecule-agent-sdk - Outbound HTTPS access from the agent machine to
https://<your-org>.moleculesai.app - A platform admin token (from the canvas, under
Config → Secrets & API Keys → Global)
Step 1: Create the workspace
PLATFORM="https://acme.moleculesai.app"
ADMIN_TOKEN="your-admin-token"
curl -X POST "$PLATFORM/workspaces" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "my-remote-agent",
"runtime": "external",
"external": true,
"url": "https://my-agent.example.com/a2a",
"parent_id": null
}'
Save the returned workspace_id.
Step 2: Register the agent
WORKSPACE_ID="ws-xyz"
curl -X POST "$PLATFORM/registry/register" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"workspace_id\": \"$WORKSPACE_ID\",
\"name\": \"my-remote-agent\",
\"description\": \"Runs on a cloud VM in us-east-1\",
\"skills\": [\"research\"],
\"url\": \"https://my-agent.example.com/a2a\"
}"
The response includes your bearer token — save it now. It is shown only once.
Step 3: Pull secrets at boot
AGENT_TOKEN="the-token-from-step-2"
curl "$PLATFORM/workspaces/$WORKSPACE_ID/secrets" \
-H "Authorization: Bearer $AGENT_TOKEN"
Store the returned secrets in your environment before starting the agent.
Step 4: Run the agent
molecule-agent run \
--workspace-id "$WORKSPACE_ID" \
--platform-url "$PLATFORM" \
--agent-token "$AGENT_TOKEN"
The agent connects to the platform, appears on the canvas within ~10 seconds, and starts processing tasks.
Step 5: Configure the agent
Edit config.yaml in the agent's working directory:
name: my-remote-agent
role: researcher
runtime: python
platform_url: https://acme.moleculesai.app
a2a:
port: 8000
Step 6: Inspect and iterate
The agent appears on the canvas as a workspace card with a REMOTE badge. Open the chat tab, send a task, and watch it work. To iterate, stop and restart the agent — it re-registers with the same workspace_id and token.
Behind NAT (no public IP)
If the agent machine has no public IP, use a tunnel:
# Terminal 1: start a tunnel
ngrok http 8000 --url https://my-agent.ngrok.io
# Update the registered URL
curl -X POST "$PLATFORM/registry/update-card" \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"workspace_id": "'"$WORKSPACE_ID"'", "url": "https://my-agent.ngrok.io/a2a"}'
No inbound firewall rules needed — the agent initiates the outbound WebSocket connection.
Next steps
- Register a Remote Agent — full tutorial with CI/CD examples
- External Agent Registration Guide — detailed reference
- Remote Workspaces FAQ — common questions
What To Try Next
- Expand to a team: right-click a workspace and choose
Expand to Team. - Switch runtime: use
Config -> Runtimeto move between Claude Code, Codex, Hermes, and OpenClaw. - Inspect operations: check
Activity,Traces,Events, andTerminal. - Use global keys: configure one provider once in
Secrets & API Keys -> Global. - Import a template: use the template palette or
POST /templates/import. - Import/export bundles: duplicate or move workspace trees as
.bundle.json.
Troubleshooting
| Problem | What to check |
|---|---|
| Workspace stays offline | Platform is running, Docker is available, and the runtime has valid credentials |
| Template palette is empty | workspace-configs-templates/ exists and the platform can read it |
| Chat says agent unavailable | Workspace status is not yet online or degraded |
| No responses from model | Add the correct API key in Secrets & API Keys and restart the workspace |
| Want direct DB access | Postgres and Redis are internal-only; use docker compose exec postgres psql or docker compose exec redis redis-cli |
Architecture At A Glance
Browser --> Canvas (Next.js :3000)
|
v
Platform (Go :8080)
| | |
| | +--> WebSocket events / A2A proxy / templates / bundles
| +----------> Redis
+------------------> Postgres
|
v
Provisioned workspaces
(Claude Code / Codex / Hermes / OpenClaw)
For the full system model, see Architecture.