The web console#
The console at /console/ is the hosted API with
a face: sign in with a username and password, then see and manage your environments, the
topologies they are booted from, and the swarms you run over them. It is plain HTML, CSS and
JavaScript modules in cloud/console/, served beside the API on the same
origin, and it calls only the routes of cloud/openapi.yaml with its
session cookie. Everything it does, a script can do with an API key (the hosted
API).
Pages#
Nothing on a page is boxed: parts of a page are told apart by space and a small heading, rows by a hairline. A list page has no title (the sidebar says where you are), and the topology editor fills the whole sheet.
| Page | What it does | Routes |
|---|---|---|
| Sign in, Create account | Username and password, and on Create account an optional referral code, filled in from ?ref= (so create-account.html?ref=FIRST100 arrives with it). The code is kept on the account and applied when it upgrades; an unknown or used-up one is refused with the API's message. A new account goes straight to the overview, where its first API key is shown once in a modal. Sign out from the account menu. | /v1/auth/signup, signin, signout, /v1/me |
| Overview | What is running, and the templates to boot or edit. | /v1/worlds, /v1/catalog/worlds |
| Environments | Running worlds. Boot one from a template (agent-desktop, company-2026, robotics-co, pro-workstation, …), a blueprint, or an exported file; a desktop override redraws every machine as one platform. | /v1/worlds, /v1/worlds/import |
| An environment | Every machine's screen, live: click, drag, wheel and type into it, launch an app, or type text from a field (for phones and touch screens). The clock and state hash beside its name; advance the clock; snapshot and fork in one click, restore, drop, export; grant an agent an environment and copy its actor token once. | /v1/worlds/{id}/…: topology, state_hash, environments, …/render, …/step, snapshots, fork, export, advance |
| Topology | Blueprints, the templates to start one from, and the editor that draws one (below). | /v1/blueprints, /v1/validate, /v1/catalog/vocabulary |
| Swarms | The account's swarms and the society specs to run (built in from worlds/*/societies/, or uploaded), and one swarm's rounds, outcomes and divergence (below). | /v1/catalog/societies, /v1/swarms, …/compile, …/rounds, …/fork, …/summary, …/journal |
| API keys | The keys, and Create API key: name it, and the whole key is shown once in a modal with a copy button. Revoke takes two clicks. | /v1/keys |
| Usage | What the account holds against each limit, this minute's rates, lifetime totals, and each world's environments and snapshots. | /v1/me, /v1/worlds/{id} |
| Settings | Name, email and date of birth, each edited in place (Edit turns the value into a field and itself into Save); the account id, when it was made, and the plan (below); and Change password, a modal with the current password and the new one twice (other sessions are signed out). | /v1/me (GET, PATCH), /v1/me/password, /v1/plans, /v1/billing/checkout, /v1/billing/portal |
The plan#
The Plan row in Settings says the account's plan (Free, Pro or Enterprise, from billing in
GET /v1/me) and, on a paid plan, its status, the date it renews or ends, and its discount
(FIRST100: 20% off for life); a failed payment shows in red with the date the grace period
ends. On Free the row also names the referral code kept from sign-up.
On Free the row's action is Upgrade: a small modal with the plan (Pro, $29 a month, and its
limits from GET /v1/plans) and a Referral code field filled with the account's code.
Continue to checkout posts /v1/billing/checkout and sends the browser to the Stripe
Checkout page it answers. Stripe sends it back to /console/#/settings?billing=success or
?billing=cancel; Settings says what happened, drops the query, and, since the webhook may
land after the browser does, reads /v1/me again every 2 seconds (10 times at most) until
the plan moves. While the deployment has no Stripe key the API answers
503 billing_not_configured and the modal says upgrades open soon; nothing pretends to be
paid. On Pro (or any plan with a Stripe customer) the action is Manage billing, which opens
Stripe's customer portal (/v1/billing/portal) to change the card, see invoices or cancel;
an Enterprise account without one gets Contact sales. The public price list is
/pricing/.
Screens#
The console grants itself one environment per machine it shows, labelled
console:<machine>, because an environment renders the machine it is focused on. It does
not poll pixels: it polls the world's state hash every 2.5 seconds and repaints the screens
on view when the hash moves or after it sent input, at most once a second each. A quiet
world therefore costs no renders against renders_per_minute. Pointer drags are sent as
down, move (at most every 120 ms) and up; a press without movement is one click;
typed characters are batched into one type. Up to eight screens are shown at once; open
one alone with its expand button.
The topology editor#
The editor works on a whole world definition and fills the sheet: a
toolbar, the canvas, and an inspector beside it. Machines are drawn by what they are
(desktop, laptop, phone, server), network nodes that host services as servers, and the
built-in internet's attachment points (edge-router, pop-west, …) as routers; services
are chips on the node they run on; links are lines labelled with their latency and loss,
dashed when lossy.
- Add a desktop, laptop, phone, server, router or service host from the toolbar. A new machine gets a free address, a network node, a user, the default apps for its kind, and the OS profile its desktop needs.
- Drag a node to move it; drag from its right-hand port to another node to link them
(or pick "Link to…" in the inspector). Positions are kept in
metadata.console_layout. Zoom, fit and tidy sit in the canvas's corner. - Select a machine to set its name (renamed everywhere it is referred to), kind,
desktop (
macos,windows,ubuntu,ios,android), user, address, OS profile, installed apps and packages; a link for its latency (ms), loss (%) and direction, with presets from LAN to satellite; a service for its kind, node, port, HTTPS and domains; nothing for the world's id, description, internet, implicit LAN and gateway. - The verdict in the toolbar is the console's own checks as you draw (duplicate names,
undeclared nodes, addresses, link parameters, unlinked machines); click it, or Save,
and the engine boots the definition to check it (
/v1/validate). Save keeps it as a blueprint; Boot saves and starts an environment from it. JSON shows the definition to edit by hand or download.
Swarms#
A swarm runs a society round by round. Starting one takes a built-in or uploaded spec, a seed, and optionally one more arm: a rule appended to everyone, or to a population, or to a random fraction of it, forked with the others. Its page runs one round or all of them, forks the arms early, and draws:
- Outcomes per round: one small chart per outcome (preregistered ones marked), one line
per arm, the fork round dashed. Arms take the three validated colours of
scripts/procedures/swarm.py; with more arms, or to read one, pick it and the rest turn grey. Hovering shows every arm's value at that round. - Divergence from the first arm: people reached, screens that differ, and whether the state hashes are equal, per round.
- Arms: each arm's world (open it as an environment), its preregistered outcomes and their difference from the first arm, and its state hash.
- The common-random-numbers check.
- The model decisions still waiting: a server with no journal entry for a prompt leaves that
person waiting and returns the decision as pending. The console lists them with their
prompts and answers them all with
doneorwait, or uploads a recorded journal (*.journal.jsonl); answers go into the swarm's journal, so a replay repeats them.
Every chart has a table under it with the exact values.
Running it locally#
node cloud/console/dev/mock-api.mjs 8797 # a mock API on real pkg/node worlds
CW_API=http://127.0.0.1:8787 node cloud/console/dev/mock-api.mjs 8797 # or forward to the Worker
# open http://localhost:8797/console/
PLAYWRIGHT_MODULE=…/playwright/index.mjs CHROME_BIN=/usr/bin/google-chrome \
node cloud/console/dev/check-console.mjs http://localhost:8797 target/console-shots
check-console.mjs creates an account and goes through every page at 1440 and 390 pixels
wide — the first key's modal after sign-up, a key made and revoked, a screen driven, a
topology drawn in the full-sheet editor and booted, a swarm run, settings edited in place
and the password changed — failing on any page error, console error, unexpected failed
call or horizontal overflow, and saves a screenshot of each page. A route the API answers 501 for is reported
and its part skipped. It signs up through ?ref=first100 (and is refused an unknown code
first), opens Upgrade and, with billing off, sees upgrades open soon. The mock starts with
billing off, as a deployment without STRIPE_SECRET_KEY is, and has a dev-only switch
(POST /_mock/billing {"configured": true}, or CW_MOCK_BILLING=on) behind which checkout
and the portal are a stand-in Stripe at /_mock/stripe/ that makes the account Pro, as the
webhook would; the check uses it to go through checkout to Pro and Manage billing, and skips
that part against a real API. dev/ is not deployed (scripts/cloud/build-pages.sh leaves it out).