Computaco

Start

Clients for the hosted API#

Two small clients drive the hosted API without writing HTTP by hand: computerworld-cloud for Python (standard library only, Python 3.9 or later) in clients/python, and computerworld-cloud for JavaScript (one ES module, no dependencies, Node 18 or later and browsers, with TypeScript declarations) in clients/js. They have the same shape: a Client holding an API key, and World, Environment and Swarm handles whose methods are named after the engine's own World and Environment, so code moves between a local world and a hosted one with few changes. Python uses snake_case, JavaScript camelCase.

Install#

Neither is published to PyPI or npm; both install from their public repository, ComputaCo/computerworld, MIT-licensed.

# Python
pip install "computerworld-cloud @ git+https://github.com/ComputaCo/computerworld.git#subdirectory=python"

# JavaScript, in a Node project
npm install github:ComputaCo/computerworld
// JavaScript, from a URL (browsers, Deno); pin a tag or commit for anything lasting
import { Client } from 'https://cdn.jsdelivr.net/gh/ComputaCo/computerworld@main/computerworld-cloud.mjs';

The JavaScript client is one file, so copying computerworld-cloud.mjs (and computerworld-cloud.d.mts for types) into a project works too.

A first run#

Both read COMPUTERWORLD_API_KEY and COMPUTERWORLD_API_BASE when no key or base URL is passed. The base URL may be given with or without /v1. It defaults to https://computaco.ai/v1; https://dev.computaco.ai/v1 is the dev tier (Stripe test mode, its own accounts).

from computerworld_cloud import Client

client = Client()
with client.create_world("agent-desktop", seed=1) as world:     # deleted on exit
    env = world.environment()
    env.click(interaction="shell:launch:editor")                # find in the scene, click the centre
    env.click(role="textbox", label="Document text")
    env.type_text("Hello")
    env.render().save("screen.png")

    fork = world.fork()
    run = fork.run("agent-desktop/legal-engagement", seed=1)
    print(run["verification"]["passed"])
    fork.delete()
import { Client } from 'computerworld-cloud';

const client = new Client();
const world = await client.createWorld('agent-desktop', { seed: 1 });
try {
  const env = await world.environment();
  await env.click({ interaction: 'shell:launch:editor' });
  await env.click({ role: 'textbox', label: 'Document text' });
  await env.typeText('Hello');
  const { bytes } = await env.render();                         // PNG

  const fork = await world.fork();
  const run = await fork.run('agent-desktop/legal-engagement', { seed: 1 });
  console.log(run.verification.passed);
  await fork.delete();
} finally {
  await world.delete();
}

Local and hosted, side by side#

Local enginePython clientJavaScript client
World(definition, seed)client.create_world(name | definition= | blueprint=, seed=)client.createWorld(name, { definition, blueprint, seed })
world.environment(config)world.environment(config)world.environment(config)
world.session(id)world.session(id)world.session(id)
snapshot, restore, forkthe same; a snapshot is kept by the API and named by idthe same
export_snapshot / import_snapshotexport_snapshot() / client.import_world(bundle)exportSnapshot() / client.importWorld(bundle)
state_hash, inspect, definition, trajectory, resetthe samestateHash, inspect, …
add_computer, remove_computerthe sameaddComputer, removeComputer
instantiate, stage, project, verifyclient.instantiate, world.stage/project/verify, world.runthe same, and world.run
env.step, observe, scenethe same; scene(elements=True) adds the interactive elementsscene({ elements: true })
env.render(w, h) → RGBAenv.render(w, h) → PNG bytes with .etag, .state_hash, .tick{ bytes, etag, stateHash, tick }

Beyond the engine's calls: the account (me, profile, usage, keys), the catalog, blueprints and their topology edits, advance on the world clock, service state, a grounded perform, and swarms (create_swarm / createSwarm, rounds, the journal, the trace and the summary). Environment.connect(token, env_id) builds an agent's handle from an actor token alone, which can only step, observe, read the scene and render.

Behaviour both share#

  • Finding and clicking. find returns the frontmost interactive element matching every field given among label, role, interaction and value (a string exactly, a regular expression by search), skipping disabled ones; a miss raises ElementNotFound naming what is on screen. click takes a point, an element, or the same fields and sends a pointer.v1 click at the element's centre in the environment's viewport (1280×800 unless changed). The helpers raise ActionFailed on an unsuccessful outcome; step itself never does, as in the engine.
  • Retries. A 429 or 503 is sent again for any method; a 500, 502, 504 or a lost connection only for GET, PUT and DELETE, so a POST that may have changed a world is not repeated. The wait is Retry-After when sent, otherwise exponential backoff from 0.5 s, jittered and capped at 30 s; four retries by default, and a Retry-After longer than 120 s is raised at once.
  • Errors carry the HTTP status and the API's code (not_found, rate_limited, quota_exceeded, invalid_world, …), its message, Retry-After and the request's method and path. An answer that is not the API's JSON is http_<status>.
  • User-Agent. Every request from Python, Node, Bun or Deno sends computerworld-cloud-python/<version> or computerworld-cloud-js/<version>, with the caller's own in front when given. Cloudflare refuses urllib's default with 403 error code: 1010. A browser sends its own, since a cross-origin fetch may not set one.

Measured#

The live smoke tests (clients/python/tests/test_live.py, clients/js/test/live.test.mjs) boot agent-desktop, click the editor's launcher, type, render, snapshot, fork, run legal-engagement in the fork (34 GUI actions, verified) and delete both worlds. Client side, from the US against computerworld.pages.dev on 2026-10-28, median of three runs each, in milliseconds:

PythonJavaScript
boot agent-desktop2,3603,181
scene with elements194128
step (click)150148
step (type)11792
render 1280×800 PNG9731,260
render, unchanged (304)8895
snapshot345206
fork3,3452,453
procedure run legal-engagement644526

The two clients are within the run-to-run spread of each other: boot, render and fork vary by a second or more between runs of the same client, because each lands on a new Durable Object.

Tests#

cd clients/python && python -m unittest discover -s tests -v    # 27 offline tests, a local mock
cd clients/js && npm test                                       # 26 offline tests, a local mock
COMPUTERWORLD_API_KEY=cw_live_… python -m unittest tests/test_live.py -v
COMPUTERWORLD_API_KEY=cw_live_… npm run test:live