Quickstart
From an empty terminal to a first verified rollout: an API key, the Python SDK, one desktop, one action, one checker result.
You will create an API key, install the Python SDK, start one desktop with an OSWorld task, take a screenshot, act, run the task's checker and close the desktop. Every command and script on this page was run as written against the production gateway before it was published.
1. Create an API key
- Sign in at console.drums.run and open API Keys in your workspace.
- Choose Create key. Give it a name (for example
laptop), keep the default scopescomputers:read,computers:write,runs:readandusage:read, and keep the default expiry of 90 days. - Copy the key from the dialog. It starts with
drums_sk_and is shown only once; Drums stores only a hash of it.
The key acts as you, limited to its scopes and to your role in the workspace. See Authentication.
2. Install the Python SDK
The SDK is the drums-sdk package on PyPI (version 0.3.0); the import name is drums, and it installs the drums command (drums version, drums mcp). It uses only the Python standard library and needs Python 3.9 or later.
python3 -m venv drums-venv
drums-venv/bin/pip install drums-sdk3. Point it at the gateway
export DRUMS_URL=https://beta.drums.run/gw
export DRUMS_TOKEN=drums_sk_... # the key from step 1The SDK sends the key over HTTPS only. A plain http:// URL is refused before any request unless it is loopback (a local drumsd) or you opt in with connect(allow_insecure_http=True) or DRUMS_ALLOW_INSECURE_HTTP=1; see Python SDK.
Check the connection. Both forms call GET /v1/health and print the runtime version:
import drums
client = drums.connect() # reads DRUMS_URL and DRUMS_TOKEN
print(client.health()["version"])curl -s "$DRUMS_URL/v1/health" -H "Authorization: Bearer $DRUMS_TOKEN" | jq -r .versionA 401 (AuthError in Python) means the key is mistyped, revoked or expired.
4. Run a first verified rollout
Save this as quickstart.py and run it with drums-venv/bin/python quickstart.py. It starts a desktop with OSWorld task e0df059f ("rename the folder todo_list_Jan_1 on the Desktop to todo_list_Jan_2"), waits until every gate of the episode has passed, saves a screenshot, performs the task with one action, runs the task's checker and closes the desktop.
import drums
# the client closes every desktop it created when the block ends
with drums.connect() as client:
print("drumsd", client.health()["version"])
# an OSWorld task id; ttl is the desktop's lifetime in seconds
with client.create(task="e0df059f", ttl=900) as env:
env.wait_valid() # every gate of this episode passed
obs = env.observe() # PNG screenshot plus metadata
open("screen.png", "wb").write(obs.png)
print("task:", obs.meta["instruction"])
print("screenshot bytes", len(obs.png))
env.step({"type": "execute", "shell": True,
"command": "mv ~/Desktop/todo_list_Jan_1 ~/Desktop/todo_list_Jan_2"})
reward = env.verify(strict=False) # the task's checker plus episode validity
print("score", reward.score, "valid", reward.valid, reward.invalid_reasons)
print("live computers left", len(client.envs()))Expected output (your ids and byte counts differ):
drumsd 0.4.2
task: I have a directory named "todo_list_Jan_1". Can you help me change its name into "todo_list_Jan_2"?
screenshot bytes 1671333
score 1 valid True []
live computers left 0What happened:
client.create(task=...)fetched the task's JSON, started a desktop from theosworld-ubuntuimage and ran the task's setup (which creates the folder). While it runs, the desktop is listed under Computers in the console, with a live screenshot view.env.wait_valid()waited about 5 seconds for the last gate (every restored process still alive). Acting before that is allowed, but an action that ends a process in those seconds makes the episode invalid.- The action used
execute, a shell command inside the desktop, to keep this page short. A GUI agent acts with pyautogui instead, for exampleenv.step("pyautogui.click(960, 540)"); see Actions. verify(strict=False)returned the checker'sscoreandvalid. Use a score only whenvalidisTrue. With the defaultstrict=True, an invalid episode raisesInvalidEpisodeinstead.
5. Next steps
- Fork the desktop into copies of the same state: GRPO-style group rollouts.
- Run a policy over many tasks: Evaluate a model on OSWorld tasks.
- Every method: Python SDK reference. Every endpoint: HTTP API.
- If something fails: Errors. Every error reply carries a
request_id(gw_...); include it when you contact your platform operator.