Skip to main content
Glama

mandala-computer-mcp

An MCP server for Mandala Computer — cloud desktops for AI agents.

Point Claude Code, Claude Desktop, or anything else that speaks MCP at a real Linux desktop it can see and drive. Screenshots come back as images, so the model looks at the screen and clicks what it sees.

Status: alpha. The tool surface is settling; expect breaking changes before 1.0. Tracks the platform's /api/v1, which is itself still moving.

Install

MCP requires Node 20.3 or newer. The TypeScript CLI login setup requires Node 22 or newer (mandala-computer on npm). Sign in once, then add the MCP server:

npm install -g mandala-computer
mandala login
claude mcp add mandala -- npx -y mandala-computer-mcp

On Node 20, MCP can use an existing saved profile or an environment key. The TypeScript CLI guides you through browser approval and saves an API key in ~/.mandala/credentials.json. MCP only reads that file; it never issues or approves a device, writes credentials, or starts login automatically. The Python distribution also provides a mandala command; use the TypeScript CLI for login.

To select a separate profile and workspace:

mandala login --profile Work --workspace Research
claude mcp add mandala -- npx -y mandala-computer-mcp --profile Work

--profile takes precedence over MANDALA_PROFILE, then the saved default. Names are case-sensitive. An explicit key or nonempty MANDALA_API_KEY takes precedence over every profile and avoids accessing the credential store. Empty explicit keys fail; an empty or whitespace-only environment key is absent. You can still use a key from Settings → Credentials → API keys with MANDALA_API_KEY.

Saved credentials require POSIX protection: a real directory owned by you with mode 0700, and an owned regular file with mode 0600 and one link. Symlinks, hardlinks, unsafe permissions, malformed files and unsupported protection are refused before any API request. Windows file loading is unsupported; explicit or environment keys remain available. Only your home directory's store is read.

A saved profile also binds its API base URL. --base-url or MANDALA_BASE_URL must match that stored base after canonicalization, including the entire path prefix and port. An explicitly empty base flag is invalid with saved credentials. Each stdio session resolves once: restart to pick up another saved key. Revoking the key in Settings → Credentials → API keys makes later calls fail; MCP does not switch profiles, reread the file, or retry a refused action. Run login explicitly when new credentials are needed.

A saved profile can also carry a default workspace, set with mandala workspaces use <workspace> (and removed with --clear); the CLI keeps it in ~/.mandala/defaults.json, beside credentials.json, which it never changes. Started from that profile, the secret tools (list_secrets, get_secret, create_secret, set_secret, replace_secret, delete_secret), create_computer and list_computers use it when a call leaves out workspace_id, as mandala computers create and computers list do; an explicit workspace_id always wins. Their descriptions say so and name the workspace, list_secrets, list_computers and create_computer say when the default chose the workspace, and startup prints it on stderr. There is no "every workspace" value: to list elsewhere, pass another workspace_id (or 'unassigned'), or start the server from a profile with no default. MCP only reads that file, once at startup, with the same checks as credentials.json. It is not applied when the profile's key is confined to a workspace (that key's own scope applies), when the default was saved for another account than the profile is logged in to now, or with an explicit or environment key. A file that cannot be read (not valid JSON, another version, or readable by others) is noted on stderr: list_secrets, get_secret and list_computers then use account-wide, but create_secret, set_secret, replace_secret, delete_secret and create_computer refuse a call without workspace_id, sending nothing, rather than act account-wide; pass workspace_id, or fix or delete the file and restart the server. The hosted HTTP server never reads it, and its tools are unchanged.

Claude Code — as a plugin, which installs the server and a skill together:

# Run mandala login first, or export MANDALA_API_KEY in this shell.
/plugin marketplace add mandalacomputer/mcp
/plugin install mandala-computer@mandala

The skill — plugin/skills/mandala-computer/SKILL.md — is the part the tools cannot say for themselves: when a cloud desktop is the right answer at all, that it consumes running capacity until suspended or stopped, that run_agent is usually the right level and a screenshot per click is not, and which refusals are worth a second try. It is a description of when and how, not a second client; once the server is installed it stays out of the way. MANDALA_MODEL_KEY, if exported alongside, is passed through and turns on run_agent when the configured filters permit it. Without it, run_agent runs on the account's AI credits when they can pay (see Agents on AI credits).

To use an environment key instead of a saved profile:

claude mcp add mandala -e MANDALA_API_KEY=com_… -- npx -y mandala-computer-mcp

Claude Desktop — in claude_desktop_config.json:

{
  "mcpServers": {
    "mandala": {
      "command": "npx",
      "args": ["-y", "mandala-computer-mcp"]
    }
  }
}

Cursor, Windsurf and the rest take the same three fields — command, args, env — in whichever file they keep their MCP servers in.

Your MCP client starts this as a subprocess. It uses the saved profile’s API base, or https://app.mandala.computer/api/v1 by default with an environment key. Programmatic local hosts can call runStdio({ profile: 'Work' }); the exported StdioConfig allows a local key or profile. createServer still requires an explicit API key, and HttpConfig has no local credential options.

Related MCP server: da-mcp

Use

Ask for what you want. A first session usually goes:

Create a computer from the base template, open example.com, and show me what's on the screen.

Under that, the model is doing roughly this:

create_computer(template="base")     → builds it and selects it for the session
wait_for_computer(until="guest")     → the desktop inside is answering, not just the VM
open_url(url="https://example.com")  → puts the page on the screen
screenshot()                         → an image the model can point at
click(x=640, y=400)                  → clicks what it saw
screenshot()                         → looks again

create_computer(size="large") is the fast path: the named shapes from list_sizes are the ones the platform keeps pre-booted, so one of those is usually answered in about a second where a custom cpu/ram_mb/disk_gb shape boots cold. A size sets the template and the numbers together, so send it alone or the explicit fields alone.

use_computer binds a machine to the session, so every later call can leave computer_id out. Pass computer_id explicitly on any call to override it without changing the binding, which is how you drive two machines at once.

Set MANDALA_COMPUTER_ID to bind one at startup and skip use_computer entirely.

The tools

This is the unfiltered inventory. The filters below can withhold tools from both listing and calling; workflows in this README apply only when the needed tools are available. The offline fixture checks exercised operation coverage; verification against the live publication is a separate required CI gate. Parameter and response-mode support remains a separate contract.

Choosing a machine — list_templates, list_sizes, list_computers, get_computer, use_computer, wait_for_computer, get_desktop_url

Lifecycle — create_computer, start_computer, stop_computer, suspend_computer, restart_computer, update_computer, clone_computer, delete_computer, move_computer_to_workspace, move_computer, list_moves, get_operation, list_operations, wait_for_operation — see Lifecycle operations

move_computer_to_workspace changes workspace membership and who can access a computer. It requires an account-wide member or owner credential and explicit computer_id and workspace_id arguments (null means unassigned). The selected computer and default workspace are not used. The computer must be stopped, with no saved session, snapshots or snapshot history copies, secret bindings, or proxy credentials. Refusals leave those resources intact; the tool never removes them to force a move. This is separate from move_computer, which relocates a computer to different hardware.

Driving the desktop — screenshot, click, type_text, paste_text, press_key, scroll, drag, move_mouse, mouse_button, cursor_position, wait

Every one of these that acts — all but screenshot and cursor_position — takes context: true and then answers the desktop as it stands just after the action: the windows list_windows would list and the one with focus, without a second call. They are read once, straight after the action, so a window still opening may not be listed yet; when they cannot be read the action still happened, and the answer says why. When the focused window is Chromium the answer also carries page: the page's URL and title and one line per interactive element visible in it — what it is, what it says (and its accessible name when that is something else), and the point to click. Firefox, the default browser, has no page; then page_not_read gives the platform's reason beside the windows.

Inside the guest — exec, exec_poll, exec_kill, get_execution, read_execution_output, open_url, list_windows, window_action, read_clipboard, write_clipboard, read_file, write_file, write_file_chunk, get_file_upload, cancel_file_upload, list_directory

write_file replaces a file already at the path. With overwrite: false it creates the file only if nothing is there, and a path that is taken is refused without that attempt writing anything (Linux computers only). Incomplete contents are never published at the path, but a failure while publishing or answering can leave the complete file there, so after any error read the path before retrying or overwriting. read_file and write_file take no_wake: true to refuse (409) rather than resume a computer that is not running. For embedders, the Api raises that refusal as FileExistsError, and a create-only 409 whose reason could not be read as CreateOnlyConflictError, which says nothing about the path; isTransient is false for both.

Retained versions — retain_execution_output, get_result, read_result_output, delete_result, publish_artifact, get_artifact, read_artifact, delete_artifact

Passive metadata — list_activities, get_activity, get_activity_results, read_signals

Being told rather than asking — wait_for_event, poll_events, wait_for_file_change

Snapshots — list_snapshots, snapshot_holdings, create_snapshot, restore_snapshot, clone_snapshot, snapshot_schedule, get_retention, delete_snapshot

Your own templates — get_template_schema, check_template, publish_template, get_template, retire_template

Building one — build_template, list_builds, get_build, watch_build

Account quota — get_account

Who you are — whoami, list_api_keys, list_workspaces, get_workspace, list_workspace_members, create_workspace, rename_workspace, delete_workspace. Minting and revoking API keys are deliberately not tools — see Who you are, and API keys.

Deliberately not tools — five API operations, each because it would put a credential in a model's context: minting and revoking API keys (above), and the three browser-connection routes (create, renew and revoke). A browser connection is a raw capability to drive the guest's browser; the TypeScript and Python SDKs' browser drivers create, renew and revoke it and keep it to themselves. Every other API operation has a tool.

Every tool refuses an argument it does not declare. A misspelt or unknown key is an input error naming the key, and nothing is sent — so a misspelt flag can never be dropped and the call go ahead without it.

Spending — get_usage, get_credits

Being told somewhere else — list_webhooks, create_webhook, get_webhook, update_webhook, rotate_webhook_secret, test_webhook, list_webhook_deliveries, delete_webhook

SSH access — list_ssh_keys, add_ssh_key, remove_ssh_key, get_computer_ssh, set_computer_ssh. Keys belong to the person the API key was issued to, not to the account. A key added with add_ssh_key (an API key or connected app) is accepted only by computers with SSH on in the account that credential acts on, and is removed when the credential is revoked; a key added from the dashboard is accepted on every account where that person is an owner or member. list_ssh_keys marks each key with where it works from the account the API key acts on: every account, this account only, or another account only (refused here; which account is not said). A key is registered once, so a key bound to another account cannot be added again here. remove_ssh_key removes only a key marked this account only: one added from the dashboard (every account) or bound to another account answers as if there were no such key, and the person removes it from the dashboard. A workspace-scoped key can read keys but not add or remove them.

Showing an app on the internet — list_public_urls, create_public_url, update_public_url, delete_public_url. A port inside a computer served at https://<label>.<base_domain> (the domain is in the list_public_urls answer, e.g. mandala.dev), on 443 with no port in the address. Omitted access defaults to public on paid plans and private on trials. Public means anyone with the link can open it; trials requesting public receive 402 PUBLIC_ACCESS_REQUIRES_PLAN. Private URLs accept an account API key as Authorization: Bearer (workspace-scoped keys must match the computer's workspace), or browser sign-in through the dashboard's Open button. The key never reaches the app. The app must listen on 0.0.0.0, not 127.0.0.1. Labels that read as the platform's or another company's address are refused. A deleted URL's label stays with the account: no other account can ever take it, and the account may use it again unless the platform has blocked it. A computer over its plan's limit serves only its oldest URLs, and the listing marks the rest.

A browser opening a new account's URL may first see a one-time notice page. It goes to any request that looks like a browser opening a page — a navigation by its fetch metadata, or, without fetch metadata, Accept: text/html from a Mozilla/ user agent — so a program sending browser headers sees it too. A client that sets headers skips it with mandala-skip-warning: 1; in the computer's own browser, where open_url cannot send headers, click Continue.

Calling an API without handing the computer the key — list_credential_gateway_bindings, create_credential_gateway_binding, delete_credential_gateway_binding. A binding names a secret from the account's store, an exact https:// origin, a path prefix and the HTTP methods allowed. Programs inside the computer send requests to the binding's base_url followed by the provider path, with the placeholder as the API key — Authorization: Bearer <placeholder> or x-api-key: <placeholder> (both values are in the answer) — and the platform sends them on with the secret in their place: the secret never reaches the computer. The secret goes upstream as Authorization: Bearer <secret> by default, or as x-api-key: <secret> with auth_header: "x-api-key". An Anthropic key binding uses x-api-key (origin https://api.anthropic.com, path prefix /v1), and Claude Code inside the computer then runs with ANTHROPIC_BASE_URL=<base_url> and ANTHROPIC_API_KEY=mandala-placeholder. Answers stream, server-sent events included; a request is limited to 7 MiB, an answer to 64 MiB and a call to 10 minutes. Up to 8 per computer; a binding cannot be changed, only deleted and made again. Owners create and delete them; members can list them. Origins, paths and methods that can only be refused are refused before any request.

Secrets — list_secrets, get_secret, create_secret, set_secret, replace_secret, delete_secret for the account's secret store, and get_computer_secrets, set_computer_secrets and create_computer's secrets for which of them a computer receives. A value goes in through create_secret, set_secret (create the name, or replace its value if the scope holds it — names match ignoring ASCII case) or replace_secret, and never comes back out. No route answers one, and a store tool's result holds only the decoded documented fields (success) or the status, the reason word and a sentence of its own (refusal). It never includes the platform's response text, and the Api keeps none for these routes. The bindings carry only secret ids, revisions and names. A computer receives a secret as an environment variable (env) or as a file under /run/mandala-secrets/user/files (file). A set replaces the whole binding list ([] removes every binding) and reaches the guest at the computer's next start or restart; send the version a read answered to have it refused with 409 if the list changed since. A replaced value also reaches a running computer: a file binding's file is rewritten in place, and on an image that supports it an env binding reaches new shells, and every exec, plain or with desktop: true, runs with the bound variables as they are at that moment (programs already running keep the old value until a restart). replace_secret and delete_secret need the current revision_id, and a stale one is a 409. delete_secret also needs confirm: true: a computer still bound to a deleted secret cannot start again until that binding is removed. A bound computer runs, and its guest answers, a few seconds before its secrets land, so wait_for_computer(until="guest") on one also waits until they have; get_computer shows the gap as "its secrets are still on their way in".

A proxy for the browsers — browser_proxy: {server, bypass} on create_computer and update_computer sends a Linux computer's browsers (Chromium, Chrome, Firefox) through a proxy; nothing else on the computer uses it. On update_computer it goes alone, replaces the setting whole, and null removes it. Which proxies are accepted is the platform's rule, and its refusal comes back as it is. A running computer has a change within seconds: wait_for_computer(until="guest") waits until its browsers have it, and get_computer shows the gap as "its browser proxy is still being applied".

A proxy for all outbound traffic — egress_proxy: {server, credentials_secret_id} on create_computer and update_computer sends ALL of a computer's outbound TCP (exec, terminals, package managers and browsers alike) through a proxy, taken on its host so nothing inside the computer can opt out. The server is http://, https:// or socks5:// with an explicit port; there is no bypass list. credentials_secret_id names a secret holding user:password that is not bound to the computer and never reaches it: the computer's host signs in to the proxy with it. It fails closed (proxy down or refusing, or credentials not on the host yet: the connection fails, nothing goes direct), drops UDP to the internet and ICMP, and does not proxy DNS lookups. On update_computer it goes alone — beside any other field it is refused before a request is sent — replaces the setting whole, and null removes it. get_computer names the proxy and, while the host waits for its credentials, says "its egress proxy is waiting for credentials; connections are closed until they arrive".

An end time — ends_at (an RFC 3339 time) or ends_in_hours (hours from now, fractions allowed) on create_computer and update_computer makes the computer stop by itself at that time, as stop_computer would; its disk is kept. It fires once and is then cleared. On create the time must be at least 10 minutes and at most 366 days away; on update_computer it only has to be in the future, it goes alone — beside any other field it is refused before a request is sent — and null clears it. Send one spelling, not both. get_computer shows it as ends_at, and its summary says "stops by itself at …". A host that cannot keep an end time answers 409 with reason unsupported. An answer that does not confirm the end time asked for (no ends_at, a malformed or different one, or one still there after clearing it) is an error naming the computer; the computer is left as it is. A same-key retry answered with the first request's stored answer can only have an ends_in_hours end time checked to be no later than asked for, so it succeeds with a line saying the end time is UNCONFIRMED; read it back with get_computer. So does an answer with no Date header, which leaves only this machine's clock to check an ends_in_hours end time against. A clear is confirmed by the absence of ends_at in the answer.

Delegating — run_agent, start_agent_run, run_agent_chat, registered when a model key is present: MANDALA_MODEL_KEY on stdio, or the caller's own X-Model-Key header over HTTP. Without a key, run_agent and start_agent_run are registered when the account's AI credits can pay for a run (see Agents on AI credits). All of them must also survive the configured filters.

Background runs and kept conversations — get_agent_run, list_agent_runs, cancel_agent_run, list_agent_threads, get_agent_thread, delete_agent_thread, registered whether or not anything can pay for a run, since a run or a thread can come from any client — see Background runs and threads

Tool filters

Set MANDALA_READ_ONLY=1 to register only tools whose existing annotations.readOnlyHint is exactly true. It accepts 1, true, yes, on for on and 0, false, no, off, empty or unset for off, ignoring surrounding whitespace and letter case. Any other value fails at startup. Safety is not inferred from a tool's name or HTTP method: read_file and cursor_position can wake a computer and consume running capacity, so they are withheld. So are mixed read/write tools such as wait_for_computer and snapshot_schedule. screenshot, read_clipboard and list_windows retain their read-only hints.

Set MANDALA_TAGS=input,guest to select a union of named tool groups. Names are lowercase only, comma-separated, trimmed and deduplicated. Empty or unset means no tag filter; empty comma-separated entries are ignored. An unknown nonempty tag fails before stdio connects or HTTP starts listening, with an error listing all valid tags.

Tag

Tools

account

get_account, whoami, list_api_keys, list_workspaces, get_workspace, list_workspace_members, create_workspace, rename_workspace, delete_workspace

computers

list_computers, get_computer, use_computer, wait_for_computer, get_desktop_url, list_sizes

lifecycle

create_computer, start_computer, stop_computer, suspend_computer, restart_computer, update_computer, clone_computer, delete_computer, move_computer_to_workspace, move_computer, list_moves, get_operation, list_operations, wait_for_operation

input

screenshot, click, type_text, paste_text, press_key, scroll, drag, move_mouse, mouse_button, cursor_position, wait

guest

exec, exec_poll, exec_kill, open_url, list_windows, window_action, read_clipboard, write_clipboard

files

list_directory, read_file, write_file, write_file_chunk, get_file_upload, cancel_file_upload, wait_for_file_change

executions

get_execution, read_execution_output

results

get_activity_results, retain_execution_output, get_result, read_result_output, delete_result

artifacts

publish_artifact, get_artifact, read_artifact, delete_artifact

snapshots

All snapshot tools listed above, including get_retention

templates

list_templates, all your-own-template tools and all build tools listed above

events

wait_for_event, poll_events, wait_for_file_change

usage

get_usage, get_credits

webhooks

All webhook tools listed above

ssh

All SSH tools listed above

public_urls

list_public_urls, create_public_url, update_public_url, delete_public_url

credential_gateway

list_credential_gateway_bindings, create_credential_gateway_binding, delete_credential_gateway_binding

secrets

list_secrets, get_secret, create_secret, set_secret, replace_secret, delete_secret, get_computer_secrets, set_computer_secrets

agent

run_agent, run_agent_chat, start_agent_run, get_agent_run, list_agent_runs, cancel_agent_run, list_agent_threads, get_agent_thread, delete_agent_thread

activities

list_activities, get_activity, get_activity_results

signals

read_signals

The selected tags form a union, then intersect with read-only and the existing lifecycle and model-key restrictions. MANDALA_NO_LIFECYCLE=1 still withholds its five tools even when their tags are selected; selecting agent cannot enable run_agent_chat without a per-session model key, nor run_agent or start_agent_run without one or credits that can pay. The tools that start a run, cancel_agent_run and delete_agent_thread are withheld by read-only, but remain available with lifecycle disabled alone; an agent selection with read-only keeps the four reads of runs and threads. MANDALA_TAGS=files MANDALA_READ_ONLY=1 exposes only list_directory. activities,results includes get_activity_results once; signals is separate from the active events socket. Filters never grant API privileges: the API checks current member/owner and workspace authorization on every request.

use_computer is not read-only. When it is withheld, pass computer_id explicitly, or bind a computer with MANDALA_COMPUTER_ID at stdio startup. HTTP callers must supply their own computer selection. These variables apply to both transports and the plugin forwards them. Embedders can pass readOnly: true and tags: ['input', 'guest'] in ServerConfig; the server does not read the environment itself.

Lifecycle operations

Every accepted create, clone, start, stop, suspend, restart, snapshot restore, resize, host move and delete records a lifecycle operation, and the tool that made the call says its operation_id — in its sentence, as (operation op_…), and in the JSON. move_computer carries it onto the outcome it reports. It is absent where the platform could not record one; the call happened either way.

get_operation reads one, and list_operations pages through them newest first (computer_id, limit, cursor, idempotency_key; computer_id is not defaulted to the selected computer, and idempotency_key finds the operation a call sent with that key recorded, even when the call's answer was lost). wait_for_operation polls one until it is final: it answers on succeeded, and a failed one is an error carrying the platform's error.code (start_failed, build_failed, computer_gone, move_failed, resize_not_applied, lost, and more may be added) and its sentence.

succeeded means the platform finished its step, not that the desktop has booted: wait_for_computer is still the wait for a desktop that answers. Most operations are already succeeded when their tool answers; a clone is running until its disk is copied, and a move until it lands. All three are reads, and all three stay registered when the lifecycle tools are withheld, since start, stop, suspend and restart record operations too.

The eleven lifecycle tools (create_computer, clone_computer, start_computer, stop_computer, suspend_computer, restart_computer, update_computer, move_computer, delete_computer, restore_snapshot, clone_snapshot) take an optional idempotency_key. Leave it out and a fresh one is sent for you; a failure whose outcome is unknown names the key it went with. What to do next depends on who answered:

  • The answer was lost (the connection dropped after the request went out, or a proxy in front of the platform gave up), or the platform answers idempotency_in_progress: call the same tool again with the same idempotency_key. The platform answers with the first call's result, or says it is still running; the step is not done twice.

  • The platform answered a 5xx that names no operation_id: nothing may have been done. A refusal given before the call was sent anywhere — another launch already in progress, no host to place it on, the template catalogue incomplete — names none, and the platform releases its key. Call the same tool again with the same idempotency_key: the platform carries it out if the key was released, or answers idempotency_outcome_unknown if not, and only then does the case below apply.

  • The platform answered a 5xx that names an operation_id, or idempotency_outcome_unknown: the key is spent, and resending with it only answers idempotency_outcome_unknown. The platform then keeps the call's operation pending for up to an hour, whatever happened, while its host may be carrying it out. What to read depends on the tool:

    • start_computer, stop_computer, suspend_computer, delete_computer, move_computer and update_computer: read get_computer (and get_operation with the operation_id the error named: succeeded means the step happened, running means wait on it, and pending alone is no reason to wait). If the step did not take effect, send the call again with a new key, or none.

    • restart_computer, which get_computer cannot show: a computer reads running before and after a reset. Read the operation instead (get_operation with the operation_id the error named, or list_operations with the key): succeeded means the restart happened, running means wait on it. Anything else leaves the restart possibly done, so ask the user before sending it again with a new key, or none; a second restart resets the guest again.

    • create_computer, clone_computer, clone_snapshot and restore_snapshot, where a read of the computer made straight away can show no effect for a build or restore that then lands, and a second one is a second computer or a second overwrite: read the operation first — get_operation with the operation_id the error named, or list_operations with the key — and while it is pending or running, wait (wait_for_operation) and do not resend with any key. Only once it is final as failed (error.code lost, for one) or no longer found, AND get_computer (list_computers after a create or a clone) shows the step did not happen, send the call again with a new key, or none. If no operation is found at all, read the computer again after a few minutes before resending.

  • idempotency_key_reused: a different call already used that key, and nothing was done. Send this one with a new key, or none.

Keys last 24 hours.

Who you are, and API keys

whoami takes no arguments and reads GET /api/v1/whoami: the person this server's API key was issued to, the account and role it acts with (the role as it is now), the workspace it is confined to, and the key itself — including manage_keys, whether it may manage API keys. It needs no permission and any role, and a suspended account can call it; the answer says so when the account is suspended. Behind the hosted server's OAuth sign-in, the key is the Connected app's (prefix oauth).

list_api_keys lists the key holder's API keys on the account, newest first — never a raw key. Each carries minted_by_key_id: the key that minted it over the API, or null for one minted from the dashboard. Revoking a key does not revoke the keys it minted. It needs this server's key to be allowed to manage keys, which only a person can turn on in the dashboard (Settings → Credentials → API keys → the key's menu → Allow managing keys); without it the tool answers the platform's 403, whose sentence says exactly that. A Connected app's key never has the permission.

Minting and revoking keys are not offered here, on purpose. A mint answers the new key in full, once, and a model's context — the conversation, the client's logs, whatever the transcript is shared with — is the worst place for a long-lived credential and one nobody can take it back from. A revoke is irreversible, and on a model's reading of a list it can cut off the person's CI, another agent, or this very session. People do both from the dashboard or with the mandala api-keys CLI.

list_workspaces, get_workspace and list_workspace_members read the account's workspaces, which partition its computers. A key confined to a workspace lists only that one, and is refused (403) the member list, which is the whole account's: workspaces do not divide people. All three are reads.

create_workspace, rename_workspace and delete_workspace change them, and need an owner's key that is not confined to a workspace: any key confined to one is refused (403), so none of them can touch the workspace this server's own key stands in. delete_workspace needs confirm: true and REVOKES every API key confined to the workspace, whoever holds it — a person's CI or another agent may be using one — and answers how many. Only an empty workspace can be deleted: one that still holds computers or active secrets is refused (409), saying how many, and nothing is deleted or revoked. Move its computers out with move_computer_to_workspace (or delete them) and delete its secrets with delete_secret, then send it again. None of the three is offered to a read-only session (MANDALA_READ_ONLY).

An account-wide key can work in one workspace without a key confined to it: create_computer(workspace_id: ...) creates the computer there, and names its secrets and an egress proxy's credentials_secret_id from that workspace's scope (its own secrets and the account-wide ones), and list_computers(workspace_id: ...) lists that workspace's computers, or with 'unassigned' the ones in none. A workspace the key cannot reach is not found, and so is 'unassigned' from a confined key. Left out, these two tools apply the saved profile's default workspace, as the secret tools do (see above); with no default, the computer goes in the key's own workspace or in none, and the listing is every computer the key can see.

Current account quota

get_account takes no arguments and reads GET /api/v1/account once with the caller's account credential. Viewer or stronger access is required. It reports account-wide aggregates, including for a workspace-scoped key, without resource identities. It needs no selected computer or model key, opens no event stream, and remains available with read-only and no-lifecycle filters. Select the account tag to expose it on its own.

The report includes the effective plan, pool ceilings, per-computer maxima, Windows capability, current consumption and remaining quota. Configured CPU and disk include kept computers regardless of power state; running or reserved RAM includes current reservations. CPU, MB, GB and snapshot bytes retain the API's units. get_usage separately reports historical metered consumption over time.

Quota is advisory: observed_at is an observation time, not a reservation or consistency token. Later create, resize, start or snapshot requests can still be refused, and existing 402 messages remain unchanged. Snapshot headroom is against indexed stored bytes; it does not include in-flight capture reservations and does not establish that a new capture will fit.

complete.computers and complete.snapshots are independent. An incomplete group has null for all its consumption and remaining figures, meaning unknown, while the other group can retain numeric values. Complete zero usage and zero remaining quota remain numeric zeros. Verified plan ceilings remain available in a partial report, including a no-plan account that still has retained usage. Malformed reports and HTTP failures remain errors, never an empty account. The tool prints unknown and advisory guidance before the projected public fields.

Things worth knowing

Every computer is a Linux desktop today. Windows guests are not offered on any plan; where this README mentions Windows it is describing behaviour the client already supports for when they are.

Running computers consume running capacity until suspended or stopped. Runtime and individual exec calls do not add a charge to the monthly subscription; AI-credit usage is charged separately. create_computer says so in its own description, and so does everything that starts a machine by a side door — restore_snapshot boots a stopped computer, and write_clipboard, read_file and cursor_position each resume a suspended one, because each has to reach the guest agent to do its job. All of them are subject to running-capacity limits, and on a plan at its limit can come back 402 rather than a result. The two reads are the surprising half of that list, and are why neither is annotated readOnlyHint: a host that auto-approves read-only tools would otherwise wake a machine and consume running capacity with nobody asked. screenshot, read_clipboard and list_windows genuinely do not start anything and keep the hint. When a stretch of work is over, suspend_computer (a pause: start_computer brings the same session back in about a second) or stop_computer (a shutdown: the disk is kept, the session is not). Idle suspend catches the ones a model forgets, but only after 30 minutes untouched. get_usage reports the resources used over time, not an invoice amount.

Some defaults here differ from the SDKs', on purpose. screenshot's fresh defaults to true (the SDKs default to false), because after a click a cached frame can predate the action and a model reading it clicks again. Its width outside 64-3840 is refused rather than clamped as the API would. wait_for_computer polls every 2 seconds (an SDK launch polls every 3), and refuses a suspended computer and names start_computer, where the SDKs' waitForGuest resumes it.

A screenshot need not be the whole screen. screenshot takes region (a crop, in full-size capture pixels before any scaling), scale (0 to 1), format (png or jpeg) and quality (JPEG, 1-100). A cropped or scaled picture is in its own pixel space, so the tool says alongside it how to turn a position in it back into screen coordinates.

Live screenshots also return a capture name and the capture's original size, before cropping or scaling. Use that size instead of the computer record's resolution, which can differ. To crop a frame you already measured, send its capture with region; omit fresh or set it to false. Without capture, screenshots remain fresh by default. fresh: true cannot be combined with capture. If the capture is no longer held (stale_capture), take a new screenshot without capture or region, then remeasure the region and use the new capture name. Saved frames of suspended computers cannot be pinned this way.

Ten clicks need not be ten screenshots. Driving the desktop one tool at a time — screenshot, click, screenshot — puts an image in the calling model's context for every step. run_agent hands a task in plain language to the platform's own loop instead, which screenshots, decides and clicks inside the platform and answers with a sentence and the list of what it did. It is registered when a model key is present (see Configuration), and bills that key for the run, or else when the account's AI credits can pay (see Agents on AI credits). max_steps bounds the WORK rather than the bill: a step is one action on the desktop, one model reply can ask for several and spends a step on each, a paused turn costs tokens and no step, and not every step takes a screenshot. It defaults to 20 and is capped at 100 here.

A screenshot is how you find out what the screen looks like. A click that landed and a click that did nothing produce the same tool result, so a model that acts without looking is the single most common way one of these sessions goes wrong. The tools say so in their own descriptions and the server's instructions say it once more.

But a screenshot is no longer how you find out whether anything happened. The platform's computers report what they do — a window opening, closing or taking focus, the clipboard changing hands, a background command exiting, the desktop coming up, the machine going idle, every power transition — and wait_for_event blocks until one of those arrives instead of screenshotting in a loop to discover that nothing has.

The part worth understanding is where the socket lives. A model takes turns; it is not sitting in a loop reading a stream, and between two of its turns there is nobody here to read one. So this server holds the connection, one per computer, opened the first time a tool asks about it and kept across turns. What arrives while the model is doing something else is buffered, and the next wait_for_event or poll_events is handed it in order. The model holds a cursor and never learns that a socket exists.

Three consequences, and they are the whole of the design:

  • A wait that times out has missed nothing. The stream stayed open while the tool call was not running. That is why the timeout is capped at 55 seconds rather than the fifteen minutes wait_for_computer allows — a short wait costs nothing, because calling again picks up exactly where it left off. A timeout is a normal answer here, not an error.

  • An event that already happened still ends a wait. computer.ready fires once per desktop session, so a machine that has been up for an hour will never send it again; attach to one and you are handed a computer.ready marked synthesized rather than waiting forever for an event that cannot arrive.

  • A hole in the history is answered, not forwarded. When the platform cannot replay from where this server had got to, the events that survived come back with a count of what did not and with the state the missing ones would have reported — the window listing and the computer's own record. The gap frame itself never reaches the model, because a model handed one would invent a recovery procedure.

A file being written is an event, once you ask for one. file.changed is the one thing on this stream nobody is sent unasked: a directory has to be nominated on the connection, and without one the platform sends no file events at all. wait_for_file_change is that nomination and the wait in one call — give it an absolute directory in the guest and it blocks until something under it is created, modified or deleted. Use it for a build writing its output, a download landing, a script producing a file; the alternative is running ls in a loop, which is the file-shaped version of the screenshot loop.

Three things about it are worth knowing before you use it, because each is a way to read an answer wrongly:

  • A nomination is not a watch. The guest has to be asked, and on a computer nobody has opened a terminal on the watcher is installed into the guest first — seconds, not milliseconds. inotify reports changes and not state, so nothing that happens before a tree is armed is ever reported. This tool never returns "nothing changed" from inside that window: until the tree is genuinely being watched it says so, in as many words, and tells you to call again.

  • lost is not an error. A tree that changes faster than the stream reports it comes back as one marker rather than thousands of events — which is what makes a watch under a build usable at all. The watch is still on and the tree is still being watched; what you have lost is your picture of it, so list the directory and carry on. The one exception is unwatchable, which means the tree is not being watched: the path is not there yet, is not a directory, cannot be read, or is a symlink, and symlinks are refused rather than followed.

  • Nominate the narrowest tree you care about. A home directory under a build is thousands of changes a second, and what you get for it is a flood marker rather than the changes. Your session holds four trees at once per computer — a fifth evicts the one you asked about longest ago, and you are told which one went — while the computer itself watches at most 32 across every client connected to it. A nomination past that limit is refused where a websocket client is told nothing at all, so this server works it out by elimination: it drops the tree, the rest of the stream comes back, and it says which of the two it was. Adding a watch can never cost you the window and process events you already had.

A computer holds at most 8 event streams at once, and an account 128 on one server. A stream past either is refused with a 409 and no reason, and waiting does not lift it until another stream closes. A websocket client is told nothing about that refusal, and the computer still reads running, so this server reports it after five failed connections in a row: the stream stops and poll_events says to close another stream on that computer. Each SDK waitFor/events call holds one, and so does each MCP session that has asked about the computer's events.

Not everything else is an event, though. A click landing and a page painting are not, and no amount of waiting will produce one — screenshot, list_windows and exec_poll are still the answers there. wait_for_event refuses at once, naming what the computer can emit, when asked for something this guest will never produce.

The guest half is not one capability. A Windows guest has no event stream at all. A Linux one whose hardware carries no terminal channel produces nothing the guest reports about itself. But file.changed runs against libc's own inotify calls and needs only that channel, while window.*, the clipboard and readiness also need the X bindings their desktop watcher is written against — so an older Linux image reports every file change and no window event whatever, and a host old enough to predate file watches reports the reverse. The refusals name which shape it is, because the three want different things done about them: a stop and a start gets a channel, nothing gets an image its bindings, and a host that predates the feature is not something a caller can act on at all.

running does not mean ready. A computer reports running when the hypervisor has started the VM; the desktop inside comes up seconds later. wait_for_computer(until="guest") waits for the software to answer, which is what exec, files and a painted screen actually need. On a Linux computer it also waits for the desktop session to be logged in, so an exec with desktop: true sent next is not refused. That is more than the SDKs' waitForGuest / wait_for_guest, which return once the guest agent answers; the value keeps the name "guest" because renaming it would break callers.

A resize can be refused with an offer rather than a no. Growing a computer past what the host it is on can run comes back as a refusal that says another host in the region could run it. That one does not clear by waiting — retrying the same resize gets the same answer for as long as the computer is on that host. move_computer is how you take the offer up: it moves the machine to different hardware, copying its disk to get there, and applies the size on arrival. Tell whoever you are working for what it costs before you call it, and read list_moves if the wait runs out. A move that ends moved rather than done is the one to read carefully — the computer is on another host, at its old size, and an ordinary update_computer finishes the job.

A webhook is the same events, delivered to somebody who is not here. wait_for_event is for the model, which takes turns and can afford to ask. A CI job or a queue worker cannot, and create_webhook is how it gets woken instead: an HTTPS endpoint the platform POSTs each event to, byte for byte the object the socket frames, signed with the three Standard Webhooks headers. The secret that signs them is in the create answer once and never readable again, which is why the first line of that answer says so; rotate_webhook_secret is the only way to another. This server only sets webhooks up and reads how they are doing — it does not receive them and has no verify, because a server with no endpoint has nothing to verify. list_webhook_deliveries is where a delivery that ran out of retries shows up; nothing is dropped silently.

A capture outlives the request that starts it. POST /computers/:id/snapshots answers 202 with a placeholder row and copies the disk afterwards, which takes minutes and scales with how much has been written — longer than any HTTP request survives. So create_snapshot polls: it holds the id the platform allocated before the copy, watches list_snapshots for that row to stop reading capturing, and answers with the finished snapshot. It waits for not capturing rather than for pending, because replication can carry a small snapshot straight on to durable between two polls; and it matches on the id rather than on the newest row for the computer, because a scheduled capture finishing in the same window makes that wrong on exactly the long captures where it matters. wait: false hands back the id instead, for a caller that would rather poll on its own schedule.

The three answers it can end on are kept apart deliberately. A capture that lands is the snapshot. A capture that FAILS mid-copy leaves no snapshot and no row — the capturing row simply disappears, and that absence is the only signal there is, which is why an incomplete listing is never allowed to decide it. A wait that runs out says the capture is still running and names the id to follow, because that one asks for a look rather than for another attempt.

A deletion outlives its request too, and reads the other way round. DELETE /snapshots/:id answers 202 and then detaches the dependent snapshots and removes the stored objects. There is no state that means deleted, so delete_snapshot polls for the row to go — the mirror of a capture, which polls for a row to stay and change. A row that stays is one that STALLED, and it sits in deleting, a state a bare listing hides: the poll asks with include=unfinished for exactly that reason, since without it a half-deleted snapshot is indistinguishable from a deleted one. The platform retries a stalled deletion itself every fifteen minutes, so the give-up sentence says to watch rather than to repeat.

Because absence is the success signal here, "Deleted" is said only off a listing read whole. A row missing because a hypervisor did not answer is not a row that is gone, and that mistake is unrecoverable in a way the others are not: nobody goes looking for a snapshot they have been told was destroyed. A 409 saying the snapshot is already being deleted is progress, not a fault — the answer is to watch that deletion finish, never to go and delete something else.

A schedule says when, not how long. snapshot_schedule sets the window a computer's automatic snapshot is taken in; get_retention is what says how many of them survive, and it takes no computer because the window belongs to the account. Only automatic snapshots are ever aged out, so taking one with create_snapshot is how a model keeps something past it.

A usage total that is short does not look short. get_usage answers what the account has used — read it before and after a batch to monitor resources. It reports usage, not a monetary cost. Every figure in it is a sum across the hypervisors the account's computers are on, so a host that could not be reached does not leave a gap: it leaves a total that is quietly too small. The answer says so in its FIRST line when that has happened, ahead of the numbers, because a caveat under a figure is a caveat that has already been acted on. Two kinds, and only one of them clears by retrying.

One window at a time, at most 62 days of it, reaching back 399 — every hypervisor replays its ledger a day at a time to answer, so an older period is read by naming both from and to rather than by widening one of them. to on its own is measured from the current billing period and is refused.

exec runs as root with no display. A GUI application started without desktop: true cannot draw. open_url is the reliable way to put a web page on the screen — and it returns before the browser paints, sometimes by ten seconds.

A variable belongs in env, not in front of the command. exec takes an env object, and FOO=bar cmd is a different thing: it is shell syntax, so a value with a space or a quote in it is yours to quote and is silently cut in half when you get it wrong. It also puts the value in the guest's ps for anyone logged into the machine, and a background command's command line comes back inside every exec_poll answer.

Anything slow wants background: true. A build or an install run in the foreground comes back as a timeout, with the work still going inside the guest and its output unreadable. With a handle you get the exit code and the output, and exec_kill stops it.

A command running across a host restart keeps its status, not its output. When the service on the computer's host restarts, a background command that was already running still answers exec_poll with whether it is running and, once it ends, its exit_code — but both streams stay empty and output_unavailable (today "daemon_restarted") says the output cannot be read; the tool says so above the JSON. For a few seconds after the restart a poll can be refused as worth sending again; a refusal that does not say so is not worth sending again at once — the guest agent has not confirmed the command for five minutes — and a later poll answers again once it does or the command exits. exec_kill on such a command is refused while it still runs, so stop it from inside the computer with exec. Its command is the copy the platform kept, at most the first 1 KiB, and command_truncated: true (said above the JSON too) means it was cut. get_execution answers for its execution_id with the same output_unavailable, refused with a 409 contention (worth sending again) for those first seconds and with a 409 carrying no reason once the guest agent has not confirmed it for five minutes (not worth retrying at once; a later read answers again when the agent does or the command exits); read_execution_output refuses it with a 409 output_unavailable carrying the same marker, which no retry changes (without the marker, the same code is a log not opened, possibly not created yet, and a later read can succeed). Do not run the command again to recover its output: that repeats whatever it did.

Stable background reads. When an accepted exec returns execution_id, use get_execution for its last observed running, exited or lost state. Only exited carries an ended_at and signed exit_code; running does not prove the computer is awake, and lost establishes neither success nor failure. Older replies can omit the ID. A malformed supplied ID leaves the accepted command and its valid PID usable, but supplies no stable identity: do not replay the command to obtain one. PID polls/kills never reconstruct this association.

read_execution_output takes that ID and both stdout_offset and stderr_offset byte positions. Start each reader at zero, then pass its own returned positions. For example:

{"execution_id":"exec_0123456789abcdef0123456789abcdef","stdout_offset":0,"stderr_offset":0,"limit":4096}

Each stream is bounded to 4,096 bytes by default, at most 16,384. Complete lossless UTF-8 appears as stdout/stderr with its BOM preserved. NUL, binary and split UTF-8 chunks remain exact canonical stdout_b64/stderr_b64; nothing is trimmed or replaced. stdout_more and stderr_more are independent, and false means EOF at that moment, not that the command has finished.

The separate diagnostic/diagnostic_b64 repeats on every read. At most 4,096 of its up-to-65,536 available bytes are displayed: inspect diagnostic_available_bytes, diagnostic_displayed_bytes, and diagnostic_display_truncated. The independent diagnostic_truncated flag is the platform's capture limitation. Diagnostics never advance either cursor. Neither new tool consumes output from another reader or the shared exec_poll cursor, and both carry read-only, non-destructive, idempotent annotations.

These are single requests with cancellation, no automatic resume, retry, watcher, capture or command replay. Metadata reads no guest files. Output reads perform guest I/O without refreshing activity and are unsuitable for passive Activities/history. Files are mutable guest data, not retained artifacts; handles can vanish on restart, replacement or cleanup, and observed exits expire after ten minutes. An unavailable read is an error, not empty output. Every new-tool result is bounded to 256 KiB of serialized data.

Explicit immutable retained versions. retain_execution_output accepts an execution_id and captures one version of its volatile output with one POST. It performs guest I/O, without resuming or replaying the command. Its optional max_bytes_per_stream defaults to 1 MiB (maximum 4 MiB); retention_seconds defaults to 86400 (maximum 604800). Diagnostics are separate, up to 64 KiB. Each capture creates a version; there is no automatic capture or retry.

get_result reads finite metadata by result_id. read_result_output requires result_id, stream (stdout, stderr or diagnostic) and offset, with limit defaulting to 4096 and capped at 16384 bytes. It reads one independent page, with exact offset, next_offset, eof and returned bytes count. Content is lossless text (BOM preserved) or canonical base64 for binary, controls and split UTF-8. EOF means the end of this retained prefix, not task completion. A page alone does not verify the full manifest hash. delete_result deletes that version once; a repeated 404 remains unavailable.

Existing synchronous exec accepts retain_output: true or a strict object with those same two options. False or absence leaves default behavior alone. It cannot be combined with background: true. A canonical returned result_id confirms optional retention; no execution ID is fabricated. Missing, malformed or unsupported optional metadata leaves the command outcome unchanged and does not authorize replay. Retained-prefix truncation and upstream response truncation are distinct. Synchronous results have no diagnostic stream; an explicit diagnostic read can return 409.

Nominated file versions. publish_artifact requires an absolute path, expected_size and expected_sha256 supplied by the caller. For example:

{"path":"/tmp/empty.txt","expected_size":0,"expected_sha256":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}

Paths preserve legal Unicode, spaces and Linux backslashes; Windows drive and UNC paths are also accepted, subject to the platform's current OS proof. Publication performs one nominated guest-file capture, without a client-side stat, list, read, hash or exec preflight. max_bytes defaults to 8 MiB and is at most 64 MiB; expected size must fit. Retention has the bounds above. Optional execution_id records verified caller selection, not proof the execution created the file. Every publication creates an independent immutable version.

get_artifact reads metadata. read_artifact first reads that metadata and, only if the complete size fits max_bytes (default 4096, maximum 16384), reads the entire retained object and verifies its exact length and SHA-256. Over-cap objects return metadata with a refusal before any content request; use an SDK whole download with an adequate cap. There are no partial artifacts, Range requests, local destinations, filenames, image/HTML previews or guest fallbacks. Verified content uses the same lossless text/base64 presentation. delete_artifact deletes only that stored version, not the guest file; repeat 404s remain truthful failures.

All eight retained tools resolve the computer selection once. Reads are passive but require current authorization and scope availability; retained bytes can be unavailable when the host cannot verify access, after expiry or deletion, or when storage is unavailable. They never wake a guest or substitute live output. New operations have one 90-second budget across headers, bodies, and both artifact requests. An MCP client can impose an earlier deadline. Cancellation, redirects and malformed responses never trigger a retry; a lost publication response means commitment is unconfirmed, not undone. Each entire serialized retained tool result is bounded to 256 KiB. Reads are marked read-only; capture/publication create new versions; deletes are destructive with an idempotent deletion effect. Activities result detail remains outside this MCP runtime.

Past about two minutes it does not even come back as a timeout. A proxy in front of the platform abandons a request that has produced no response for roughly that long and answers 524, which arrives as GatewayTimeoutError — whatever timeout_s said, because the hop that gives up never saw it. Measured against app.mandala.computer: sleep 130 failed at 125.2s with timeout_s: 300 and at 125.3s with timeout_s: 3600. Raising timeout_s buys nothing; background: true is the only thing that works. The abandoned command keeps running, so the call after one of these often reports the guest agent as busy — that is the first failure continuing, not a second one.

That roughly two-minute ceiling belongs to the hosted proxy. The server accepts integer foreground timeout_s values from 1 through 600 seconds (default 30), and the tool exposes that range for a MANDALA_BASE_URL reached without the proxy. The HTTP client allows 630 seconds for response headers so the server can report a 600-second timeout. Use background: true and poll the handle for longer work.

list_windows sees what a screenshot cannot. It is how you tell an application that failed to start from one that has not painted yet. Match on class (the application), not title (whatever page it is showing).

The clipboard is two tools, not a shell recipe. read_clipboard and write_clipboard reach the desktop's CLIPBOARD selection — what Ctrl-C writes and Ctrl-V pastes — on Linux computers whose desktop image includes its desktop's clipboard tool: xclip on X11, or wl-clipboard (wl-paste/wl-copy) on a Wayland image such as Omarchy. An image without that tool gets a permanent 400 from both tools that names it; changing the computer's runtime state or retrying cannot fix that image dependency. Pair write_clipboard with press_key and keys: ["ctrl","v"] — two key names, not the string "ctrl+v" — to get the text into whatever has focus. Do not reach for xclip through exec instead: exec runs a login shell, so the guest user's profile prints onto the same output your command does and corrupts a read you are trying to parse, and a write that way needs a resident holder, a redirect, base64 and a polling loop. The write here is confirmed by the platform reading the selection back before it answers. 64 KiB in, 128 KiB out, and the read is refused rather than truncated past its cap. write_clipboard resumes a suspended computer; read_clipboard does not.

Computers suspend themselves. After 30 minutes untouched, by default. Input, exec and file transfers count as use and resume it automatically; screenshots deliberately do not, so a loop that only watches can see its own machine go down under it.

A stop asks first, then forces. stop_computer asks the guest to shut down and gives it up to 45 seconds; a guest still up after that — a hung X session, a modal "unsaved changes" dialog, a service that ignores its own shutdown — is forced off by the platform, so an ordinary stop ends stopped and can take about 83 seconds to answer. Configure the MCP client to allow at least 95 seconds for a stop; caller cancellation is still honored. force: true skips the asking and the wait and pulls the power at once — the equivalent of holding the button in — and whatever the guest had not written to disk goes with it. It saves 45 seconds, not a failed stop, so leave it out unless the computer must be off immediately.

Purging snapshots is bound to the set you were shown. Deleting a computer keeps its snapshots by default. To destroy them too, read snapshot_holdings first — a count, a byte total and a fingerprint — and pass that fingerprint to delete_computer as expect. The purge is then refused if the set has changed since you looked, so a capture that finished in between cannot be swept up by a decision that was never about it. delete_computer will not purge without one, and the platform makes expect optional only for callers that had no way to read the holdings.

A short list is refused, not silently served. list_computers, list_snapshots and list_builds fan out across hypervisors, and if one cannot be reached the platform answers 503 rather than a list that is quietly missing things. allow_partial: true accepts the incomplete answer instead — and when it does, the result opens with an INCOMPLETE: line saying so, because a short list reads exactly like the missing things were deleted.

list_builds is the one where that line is always all you get. The platform keeps no record of which hypervisor ran which build, so a short build listing simply has fewer rows, an unknown number missing and nothing marking the gap.

The other two append a row marked unreachable for each thing they could not reach, with one difference by key. A WORKSPACE-SCOPED key gets no marked snapshot rows, because naming the missing ids would mean reading them out of a host cache that has no workspace column, and handing a confined credential ids from the workspaces it is confined away from. Its computer listing still marks the rows the platform's own record holds as unreachable or being deleted, since that record has the workspace column the cache lacks. (Such a key cannot call list_builds at all: builds need an account-wide key.) Whatever the key, the INCOMPLETE: line is the one signal every short listing carries, which is why it is written first and in prose.

A computer has a lifecycle of its own, separate from what its guest is doing. state is the platform's record of whether the machine exists — live, deleting, deleted, lost, or unreachable when a listing could not confirm the row against its host — while status is the host's answer about the guest. A row served from the record has the first and not the second, so list_computers prints both when both are there: a computer can be running and being deleted at once.

An unfiltered listing is live, unreachable and deleting. The two terminal states are withheld from it, so list_computers(state: 'deleted') is the only way a computer that has gone is ever shown — and an empty answer to a filtered listing is a fact about the filter rather than about the account, which is what it says rather than inviting you to create one.

Snapshots mid-deletion still count against storage but are hidden. A deletion that began and did not finish still holds objects and still counts against storage, and the default listing leaves it out — every ordinary caller is asking "what can I restore". list_snapshots(include_unfinished: true) is the flag for when the question is about storage instead.

Read the reason, not the status. Whether a refusal clears on its own is the platform's reason word, and each tool's answer says what it means: contention (something was in flight) and starting (the guest agent is still inside its boot window) clear, so the same call works in a moment; unavailable, running, unsupported, exists and revoked do not. A 409 does not mean "wait": exec, input and the clipboard on a stopped computer answer 409 unavailable, and start_computer is what fixes that, while running needs the computer stopped first. A 409 with no reason is unclassified, and is treated as one that does not clear — a label that is taken, a computer at its public URL limit, the webhook cap, an SSH key already registered — unless its code is one the platform documents as passing (idempotency_in_progress, or WORKSPACE_MOVING while the move settles). The platform's own error messages come through unedited, because they are written to be acted on.

HTTP failures preserve their actual response status. An unsupported method on a known path is MethodNotAllowedError (405), with the received Allow value when available. A missing computer, snapshot, route or guest file remains NotFoundError (404); other guest failures keep their own status and message. Neither response causes an automatic retry or method switch.

isTransient(err) answers "is this worth sending again unchanged". A 503 is transient only for a GET or HEAD. Any change answered 503 may or may not have happened, because the platform answers a failure after the request was sent the same way. So, with one exception, isTransient is false for it whatever reason it carries, the tool's answer says to read the current state first, and error.method records the method. The exception is reason: "draining" at the top level of a 503, beside a flat error sentence and no record of a run (steps, usage, a cost or a thread): a call that starts an agent run, refused before anything started while the platform updates. Nothing ran and nothing was billed, so isTransient is true for it, and the same request can be sent again after error.retryAfterMs. The rule is read from the answer alone, not from the route: the platform sends draining only on the calls that start an agent run, and both isTransient and the tools' answers rely on that. That is a rule about the 503, not a word that clears: reasonKind returns undefined for draining, as for any word it does not classify, and a 409 carrying it is not transient. A reason this version does not know, such as a new word, is treated as no classification. reasonKind returns undefined for it, and the status decides — which, for a 409, is no: a 409 is transient only when its reason clears or its code is idempotency_in_progress or WORKSPACE_MOVING (with no reason saying otherwise). APIError.code carries the platform's code.

The secret store has typed calls on api.secrets: list, create, get, replace and delete. Each answer is decoded strictly to the documented fields, and none of them carries a value:

const { secrets } = await api.secrets.list();
const s = await api.secrets.create({ name: 'OPENAI_API_KEY', value: key });
await api.secrets.replace(s.id, { value: next, revisionId: s.revision_id });

Embedders can inspect optional diagnostics on every APIError:

import { Api, APIError, MethodNotAllowedError } from 'mandala-computer-mcp';

const api = new Api(process.env.MANDALA_API_KEY!);
try {
  await api.json('GET', 'account');
} catch (error) {
  if (error instanceof APIError) {
    console.error({ status: error.status, requestId: error.requestId,
      reason: error.reason, allow: error.allow,
      wwwAuthenticate: error.wwwAuthenticate });
    if (error instanceof MethodNotAllowedError) {
      // Inspect error.allow before correcting the request method.
    }
  }
}

requestId uses a nonblank X-Request-ID header first, then the top-level request_id body field. It is an opaque diagnostic, never an idempotency key. The raw body remains available on error.body, including any differing body ID and nested chat accounting. allow and wwwAuthenticate come only from received headers. HEAD failures can carry these fields with no body. Older servers, intermediaries and connection failures may supply none of them. Existing constructor arguments retain their meanings; an optional trailing APIErrorMetadata object adds these three fields, and method.

MCP error results include supplied code, reason, request_id, allow, www_authenticate and retry_after_ms as labelled JSON metadata. code is the platform's machine-readable code (LABEL_TAKEN, WORKSPACE_MOVING, …), the word to switch on rather than the sentence. Diagnostic strings are limited to 128, 128, 256, 512 and 512 characters respectively; an oversized field is omitted with a notice, so a shortened Allow is never presented as complete. Tool-specific warnings about partial work, retained publication, execution reads and explicit template continuation still apply. Serialized JSON object or array prefixes are not displayed as error prose. Valid scalar error messages retain their wording; embedders still have the original APIError.message and APIError.body for diagnostics. Native agent error frames retain their supplied numeric status even without a reason or request ID, independently of the successful HTTP stream carrying them.

For a 401, missing means a platform credential was not supplied; invalid means the supplied platform credential was not accepted; revoked means its authority no longer holds. Unknown reasons stay visible. An unclassified 401 alone does not identify whether the account key or model key was refused, including a nested chat failure. A 403 remains a permission or authority refusal. Inspect recorded work before another run; no key fallback, login or automatic replay is performed. Nested error reasons and in-band stream errors do not grant permission to replay a partly completed run.

For desktop events, use the exact returned events_url, including its desktop capability, in a WebSocket client. A REST Bearer key alone is not sufficient; the HTTP events response provides JSON guidance rather than another login flow.

Desktop links are credentials. get_desktop_url returns the watch-only URL by default — the platform drops input on that socket, so it is safe to hand to somebody. control: true returns the full-control one, which is root-equivalent on that machine. Neither appears in any other tool's output, deliberately: a tool result lands in a model's context and from there in whatever captured it. It is also why get_desktop_url carries no readOnlyHint even though its route neither writes nor spends: hosts treat that hint as licence to call without asking, so keeping it would let a model pass out control of a desktop with nobody prompted.

Templates and builds are the account's, and need an account-wide key. A key confined to a workspace is refused (403) by publish_template, retire_template, get_template on the account's own namespace, and every build tool — build_template, list_builds, get_build and watch_build. Such a key can still list_templates, read system templates and launch a computer from a published template by its ref. A build's spec.secrets resolve among the account-wide secrets, never a workspace's.

Retiring a template cannot be undone, and takes more than it looks. retire_template without a version retires every version of the name — that is what retiring a template means, and it is deliberately not get_template's "the newest". A retired ref is then refused for ever, identical bytes included, so the version you retire can never be published again. What it does not touch is any computer: a computer is built from the image the ref resolved to and holds no reference to the document, so anything already running, stopped or suspended keeps working. The tool says all of this in its own description, carries destructiveHint, and requires confirm: true — the same gate delete_computer, restore_snapshot and delete_snapshot take. It is strictly less recoverable than any of them: a deleted snapshot's name can be used again, a retired ref never can.

An empty version is refused here rather than sent. That spelling — which a model is more likely than a program to produce for an optional argument — read as "no version was named" on the platform and retired an entire template. The platform answers 400 for it now; this server will not send one at all.

A build is minutes, and watch_build is how you follow one. build_template returns immediately with a job; watching it streams the platform's own progress, emitting both a progress notification and a log line for each step, so a long build is visibly alive rather than indistinguishable from a hang.

Set resetTimeoutOnProgress if you intend to watch a real build. The MCP default request timeout is 60 seconds and only a progress notification can reset it — but the SDK resets it only for a caller that passed that option, so a client which merely accepts progress is still cancelled a minute into a fifteen-minute build. get_build is the answer for a client that cannot hold a request open: it reads once and returns.

The same applies to every tool here that waits. wait_for_computer, move_computer, create_snapshot and delete_snapshot all poll, and all report progress on every poll — a changed line at once, an unchanged one on a ten-second heartbeat, so the request stays open without flooding the client. A live capture took 107 seconds and was cancelled at 60 before this existed, which turned every carefully-worded answer about what had actually happened into a transport error. Each of them has a way out for a client that cannot opt in: wait: false on the two snapshot tools, list_moves after a move, a shorter timeout_s and a second call on the wait. A build that failed is a normal answer from watch_build, not an error — it names the step that stopped it, which is the thing to fix. An error event is the stream failing and says nothing about the build, and the tool says so rather than letting a model rewrite a document that is fine.

A completed template build can launch with create_computer when eligible capacity and its image are available. Publishing a template and completing its build are separate steps; publication alone does not guarantee launch capacity.

When the API supports image preparation continuation, a create_computer refusal with code template_image_preparing preserves template_transfer and preparation (including state and error) in the JSON appended to the tool's error text. retry_after_ms, when present, is the parsed Retry-After delay in milliseconds, also available to embedders as APIError.retryAfterMs. Both integer seconds and HTTP dates are accepted; missing or invalid delays are omitted. Delays are capped at 2,147,483,647 milliseconds to fit a timer.

For preparing, copying, or ready with a usable token and delay, wait for that delay, then repeat the original identical create arguments, including template, adding the token exactly as returned. The token must be a nonblank string, requires the original template, and cannot be combined with size. A failed preparation reports its error for inspection before deciding what to do next. Missing or unknown states and missing or invalid delays do not supply automatic retry advice. The server never replays a create automatically, and isTransient returns false for this refusal code because unchanged replay is not the continuation protocol.

The token selects the image build; it is not a create idempotency key. Stop after success. After a lost or ambiguous response, inspect list_computers before deciding what to do; never automatically replay the create.

Running it as a service

The same server speaks streamable HTTP, for clients that cannot spawn a subprocess — claude.ai, mobile, a shared team endpoint:

MANDALA_ALLOWED_HOSTS=mcp.example.com npx mandala-computer-mcp --http --port 3000
claude mcp add --transport http mandala https://mcp.example.com/mcp \
  --header "Authorization: Bearer com_…"

The MCP endpoint is /mcp; /healthz answers a JSON { ok, name, version } for whatever is checking that the process is up.

It holds no credential of its own. Each caller's key arrives as their own bearer token and is used only for their session; there is no store, and nothing outlives a session but a digest of the key — kept so that a later request can be shown to come from the same holder, which means a leaked session id on its own is not enough to drive somebody else's desktop. HTTP startup and requests never read the operator's credential store, MANDALA_API_KEY or MANDALA_PROFILE. --profile is local-only and ignored with --http.

That is also why anyone can run their own: point the same container at the same API and it works, with no secret to provision.

Bound to loopback — the default — it answers only to 127.0.0.1, localhost and [::1], so a page the user happens to be visiting cannot reach it by resolving its own name there. Served under a name, or bound to 0.0.0.0, that default cannot be guessed and MANDALA_ALLOWED_HOSTS is what turns the check back on.

Which matters most in the arrangement that looks like neither: bound to 127.0.0.1:3000 behind a proxy — nginx, Caddy, cloudflared, ngrok. The proxy forwards the original Host: mcp.example.com, the loopback default does not list it, and every request is refused with a 403. Set MANDALA_ALLOWED_HOSTS to the name it is served under. Startup says which list is in force, so a 403 on a deployment that worked before has a line above it naming the fix.

Hosted, with OAuth

The endpoint at https://app.mandala.computer/mcp is this server run with --http behind the platform's own proxy, with the platform as its OAuth 2.1 authorization server. Nobody pastes a key:

claude mcp add --transport http mandala https://app.mandala.computer/mcp

Two variables make an HTTP server behave that way, and without them nothing changes — self-hosters keep bringing API keys:

MANDALA_MCP_RESOURCE_METADATA_URL=https://app.mandala.computer/.well-known/oauth-protected-resource/mcp \
MANDALA_MCP_SERVICE_SECRET=… \
MANDALA_ALLOWED_HOSTS=app.mandala.computer \
  npx mandala-computer-mcp --http --host 127.0.0.1 --port 3000

In this mode X-Forwarded-For is believed from a loopback peer only, so the proxy in front must be on the same machine and must set it to the real client address.

  • Every /mcp request needs a bearer, initialize and tools/list included. One without is answered 401 with exactly WWW-Authenticate: Bearer resource_metadata="<that URL>", scope="mcp:tools", which is how a client finds where to authorize. /healthz stays open.

  • The bearer is passed through unchanged — an mcpat_… access token, or an API key, which the platform still accepts. The access token is good for this endpoint only. It is not an API key: sent to the API directly, the platform refuses it with 401 (reason: "invalid"). A person revokes it under Settings → Credentials → Connected apps.

  • A bearer is checked with the platform before it gets anything. An initialize makes no session until the platform accepts its token — a 2xx from GET whoami, which every valid credential gets, a suspended account's included — so invented tokens cannot fill the session pool. A 401 is the challenge above; any other answer is 503 and nothing is remembered. Refused initializes are budgeted per source address, 20 a minute. Past that, a token already accepted still passes and a new one is still checked, but only one every 5 s per address; the rest get 429 with Retry-After. The budget comes back when its minute is up. A POST carrying a request is checked again before it is dispatched, with an acceptance cached for 60 s under the token's digest, so an expired or revoked token is a clean 401 before any stream opens.

  • One bearer holds at most 16 sessions, and a suspended account one in all (below), so no single token can fill the pool. At that limit, an initialize closes the bearer's least recently used idle session to make room, once its own session exists (a refused initialize closes nothing), and a client whose old session is gone initializes again; if none is idle, the answer is 429 with Retry-After. One race differs: if the idle session it planned to close is put to work before the new session is made, the new one is dropped instead and the initialize is answered 404 (Session not found, no Retry-After), which an SDK client reports as a failed connect. Other bearers' sessions are never touched, except a suspended account's (below). A 429 names what the bearer holds, so one still over its limit is told to wait for its busy sessions rather than to close one. runHttp takes the 16 as maxSessionsPerBearer, and the CLI reads it from MANDALA_MCP_MAX_SESSIONS_PER_TOKEN (a whole number from 1 to 256, the whole pool; anything else is refused at startup; a token is also held to its account's ceiling, below). A self-hosted --http server applies it too, but checks no bearer with the platform, so there any string is its own bucket: the per-bearer cap spreads one key's clients, and what bounds an untrusted caller is the process-wide cap (256), and the default loopback bind until you expose the port.

  • One account holds at most 64 sessions, a quarter of the pool, across all its tokens. Sessions are counted by the account id the platform's whoami names for each token, so an account with many keys or grants counts once; a token whose whoami names no account counts as an account of its own. Initializes in flight are counted too, so a burst across one account's keys cannot pass the ceiling together. At the ceiling, an initialize makes room by closing idle sessions of two kinds only: the account's sessions whose token the platform has already refused on a request made there, first, and then the requesting token's own least recently used, as at its own cap and even while it is under that cap. When that is not enough the answer is 429 with Retry-After, saying it is the account's limit and naming only that number. A live session of another token is never closed for the ceiling, nor any session of another account, and the race above applies here too (404). A refused session counts until it is closed, so revoking keys never lets an account past its ceiling; a session whose token was revoked but never sent a request again is not known to be refused, and counts until it idles out. So does the session a token leaves behind when the client refreshes it (see below): it is neither the new token's own nor refused, so an account that holds more than half its ceiling when its clients refresh can be answered 429 for up to the session idle timeout (30 minutes), longer than its Retry-After suggests, unless those clients close their old sessions. A revoked token's session idles out within about the acceptance window (60 s) plus that timeout even while its holder keeps sending notifications, holding the stream, or sending HEAD /mcp or a DELETE /mcp the server refuses: traffic that carries no request is never checked with the platform, so it keeps a session alive only while the token's acceptance is still cached. A full pool (256) is answered 503 with Retry-After, whoever holds it, and nothing is closed to make room in it. The last 64 of the 256 go only to accounts holding less than their share, where a share is the other 192 divided by the accounts holding sessions, the asking one included (initializes in flight count as held): an account at its share once only those 64 are free is answered 503 with Retry-After too, saying so, and nothing is closed for it. A lone account therefore stops at 192 even with its ceiling raised, and each newcomer still gets in. runHttp takes the ceiling as maxSessionsPerAccount, and the CLI reads it from MANDALA_MCP_MAX_SESSIONS_PER_ACCOUNT (a whole number from 1 to 256; anything else is refused at startup). A self-hosted server verifies no account, so there each token is an account of its own, held to the ceiling as well as to its own cap; to let one token hold more than 64 sessions, raise both.

  • One workspace holds at most 16 sessions, a quarter of its account's ceiling, across all its tokens. A workspace-scoped key is counted by the workspace the platform's whoami names for it as well as by its account; a key of the account as a whole (workspace: null) is held by no workspace limit. Workspace-scoped keys share their operator's account ceiling above the sub-ceiling: the operator's own sessions and all its end customers' together stay under 64, so a workspace with room is still answered the account's 429 when the account is full. The same workspace id under two accounts is two workspaces. Room is made, and in-flight initializes are counted, as for the account ceiling; past it the answer is 429 with Retry-After, saying it is the workspace's limit and naming only that number. runHttp takes it as maxSessionsPerWorkspace (default a quarter of the account ceiling, whatever that is set to; above it, it is the account ceiling), and the CLI reads it from MANDALA_MCP_MAX_SESSIONS_PER_WORKSPACE (a whole number from 1 to 256; anything else is refused at startup). Hosted only: a self-hosted server verifies no workspace.

  • A suspended account holds one session in all, across all its tokens (enough to ask whoami, the one call the platform still answers for it). Whether an account is suspended is the platform's latest answer about it from any of its tokens: each check is numbered as it starts, and a slower check that started earlier never overrides a newer one, in either direction. So a newer check that finds the account active lifts the hold at once for every token, and one that finds it suspended holds every token, including one whose own acceptance is still cached. Held, an initialize from any of the account's tokens (a refreshed token, say) closes the account's idle sessions to take the one slot: first those whose token the platform has refused, then the least recently used. A session serving a request is never closed; while the one the account holds is busy, an initialize is answered 429 with Retry-After, saying the account is suspended. An account suspended after it opened sessions keeps only one: its next initialize, or the next request, notification or event stream on any of its sessions, closes its other idle sessions, keeping the one being served, and a busy one goes at a later one of these once it is idle. Notifications and streams, which ask the platform nothing, do this only while their token's acceptance is cached (60 s). A self-hosted server asks the platform nothing, so nothing is suspended there.

  • A token the platform refuses during a call comes back as that same 401, not as a tool error, so the client refreshes or authorizes again — the answer is held until its first byte for this. The one case that cannot work: a token that dies mid-call AFTER the stream has committed (the SDK's 15 s keep-alive, a progress notification or a partial result). That call ends as a tool error, the session remembers the refusal, and the next request on that token gets the 401 without reaching the platform.

  • A refreshed token starts a new session. A session is bound to the digest of the bearer that opened it, and a different bearer on it is answered 404 Unknown session, the MCP spec's signal to initialize again. An access token says nothing this server can check about which grant it came from, so rebinding would let any valid credential that learned a session id take over its bound computer, buffered events and retained results. The old session is not closed by the refresh: it still counts against the token's account ceiling (above) until the client closes it with DELETE /mcp under the old token (only the token's digest is compared, so an expired one still works) or it idles out after 30 minutes. On a suspended account the new token's initialize closes it instead, while it is idle (above).

  • X-Mandala-MCP-Service carries MANDALA_MCP_SERVICE_SECRET on every platform request, only ever to MANDALA_BASE_URL, so a token cannot be replayed at the API directly by the app it was issued to. A client's own header of that name is never forwarded.

Configuration

Variable

Meaning

MANDALA_API_KEY

Optional local API key, taking precedence over saved credentials. Ignored by HTTP; each caller sends their own bearer token.

MANDALA_PROFILE

Local saved profile; --profile overrides it. Otherwise the file default is selected. Ignored by HTTP.

MANDALA_BASE_URL

With a saved profile, must match its stored base. Otherwise defaults to https://app.mandala.computer/api/v1.

MANDALA_COMPUTER_ID

Bind a computer at startup, so use_computer is not needed. stdio only — under --http it is ignored rather than bound into every caller's session, since it names a machine on the operator's account.

MANDALA_MODEL_KEY

An Anthropic or OpenAI key. Enables run_agent, start_agent_run and run_agent_chat when filters permit them, which runs the platform's own loop on that key. Without it, run_agent and start_agent_run run on the account's AI credits when they can pay. stdio only — under --http each caller sends their own as X-Model-Key, and this variable is ignored.

MANDALA_NO_LIFECYCLE

1, true, yes or on withholds create_computer, clone_computer, clone_snapshot, delete_computer and delete_snapshot — every tool that makes a computer or destroys one. 0, false, no, off or unset leaves them registered. Any other value is refused at startup rather than read as off: a typo here would otherwise leave those tools in place on a server whose operator believes they are gone. The --no-lifecycle flag reads the same vocabulary and refuses the same way, except that it has no spelling for unset: --no-lifecycle= is refused rather than ignored, so a launcher template whose variable did not expand stops instead of quietly leaving the tools registered.

PORT, HOST

For --http. Default 3000, 127.0.0.1.

MANDALA_READ_ONLY

Keep only tools annotated readOnlyHint: true; strict boolean parsing as described under Tool filters.

MANDALA_TAGS

Comma-separated lowercase tool tags; see Tool filters for the inventory and intersection rules.

MANDALA_ALLOWED_HOSTS, MANDALA_ALLOWED_ORIGINS

Comma-separated. Which Host and Origin values this server answers to. On a loopback bind the host list defaults to the address it was given, so DNS-rebinding protection is on without configuration; set this when serving under a name.

MANDALA_MCP_RESOURCE_METADATA_URL

--http only. The OAuth protected-resource metadata URL this server is published under. Set, it answers OAuth clients as described under Hosted, with OAuth; unset, callers bring an API key.

MANDALA_MCP_SERVICE_SECRET

--http only. Sent as X-Mandala-MCP-Service on every platform request, to MANDALA_BASE_URL only. Never logged.

MANDALA_MCP_MAX_SESSIONS_PER_TOKEN

--http only. How many live sessions one bearer token may hold. Default 16; a whole number from 1 to 256 (the server's whole session pool), and anything else is refused at startup. A suspended account is held to one session in all, across its tokens, whatever this says. A token is also held to its account's limit, below.

MANDALA_MCP_MAX_SESSIONS_PER_ACCOUNT

--http only. How many live sessions one account may hold across all its tokens. Default 64, a quarter of the pool; a whole number from 1 to 256, and anything else is refused at startup. Hosted (the metadata URL set), the account is the one the platform's whoami names for the token; self-hosted, or when whoami names none, each token is an account of its own. Past it an initialize is refused 429, after closing only the token's own idle sessions or the account's refused ones. A suspended account is held to one session whatever this says. Whatever this says, the last quarter of the pool goes only to accounts holding less than their share of it.

MANDALA_MCP_MAX_SESSIONS_PER_WORKSPACE

--http, hosted only. How many live sessions one workspace may hold across all its tokens. Default a quarter of the per-account limit (16 of 64); a whole number from 1 to 256, and anything else is refused at startup; above the per-account limit it is that limit. Counted by the workspace the platform's whoami names for a workspace-scoped token; such tokens also share their account's limit, above, with the account's own tokens and its other workspaces.

Every one of these but the model key, the two tool filters, the two hosted settings (MANDALA_MCP_RESOURCE_METADATA_URL and MANDALA_MCP_SERVICE_SECRET) and the three session limits has a flag as well, and a flag overrides the environment: --http, --port, --host, --base-url, --computer, --allowed-hosts, --allowed-origins, --no-lifecycle, local --profile, plus --help and --version. --key exists for a caller launching several servers under different keys, and warns when used, because an argument vector is readable by ps, lands in shell history and is recorded verbatim by any exec audit — none of which is true of MANDALA_API_KEY.

run_agent deserves a note. It hands a task to the platform's own agent loop, which drives the computer inside the platform and answers with a sentence. Worth it when a stretch of pixel work would otherwise cost the calling model a screenshot per step — ten clicks stop being ten images. It bills your selected provider key, and the platform never stores that key.

Both run_agent and run_agent_chat accept provider: "openai" to use gpt-6.1-sol by default, or infer OpenAI from a recognized GPT model name. Set MANDALA_MODEL_KEY (stdio) or X-Model-Key (HTTP) to the matching provider key. Custom model names require an explicit provider; omitting model and provider preserves the Anthropic default. OpenAI is BYOK only and stores Responses continuations at OpenAI; tasks, screenshots and tool results go to that provider. A native OpenAI action batch must fit the remaining step and API budget before it begins. Partial failures stop the run without replaying input.

Agents on AI credits

Without a model key, run_agent can run on the account's Mandala AI credits. The server reads GET /credits on the session's own API key and registers run_agent only when the account is not frozen and has at least $0.25 available, which is what a run's first model call reserves. On stdio that read happens once, at startup. Over HTTP it happens per session, at initialize, with that caller's bearer token; a caller who sends X-Model-Key is not asked, and no operator key or setting is ever used. Any failure of the read — a refusal (a workspace-scoped key cannot read the account-wide ledger), an error, a timeout or a record that does not parse — leaves run_agent out. A session started unfunded does not gain the tool when credits arrive later; reconnect, or restart a stdio server.

On credits run_agent takes max_cost_usd (0.25 to 20; the platform defaults to 2), the most a run may start spending. The last model call can go past it, and a run that reaches it ends with stop: "max_cost". It does not take system or provider: a run on credits uses the platform's own prompt and Anthropic, with claude-sonnet-5-5 by default and claude-opus-5-5 on request. The result reports cost_usd, the run's charge so far, and credits_remaining_usd, the balance the last step reported. A run whose credits run out partway ends with stop: "credits_exhausted", and a run that cannot reserve its first call is refused 402 with a top_up_url; the tool reports that as the account's credits running out, with the billing page, rather than as a plan limit or the model provider's billing error. The platform reports its AI service failing a run on credits as Mandala AI is unavailable over the provider's status. On such a run that sentence, at any status, and any other 402, are worded as the service failing, not as the caller's credential, the computer, the request or a model key. run_agent_chat is never registered without a model key: the platform runs that route only on the caller's own key.

get_credits reads the ledger: available, balance, held, debt, whether the account is frozen, this period's plan grant, the unexpired lots and one page of the journal, newest first (before and limit page through it). Amounts are integer USD micros. It needs an account-wide key.

Passive directories, activity history and signals

list_directory takes an exact absolute guest path. Unicode, spaces and punctuation survive query encoding. It requires an already running computer, does not resume it or extend its idle timer, and still contacts the guest with ordinary rate/capacity admission. The result preserves path, entries with name, type and optional size_bytes, truncated and skipped. An unavailable entry has no inferred type or zero size. Symlinks are not followed, and a final symlink directory is refused. No file content is read. A partial listing is an unordered subset: at most 512 examined entries/128 KiB, with no continuation token. Narrow the path when names are omitted; do not automatically rescan.

list_activities returns one newest-first history page with a fixed watermark. Pass an opaque cursor for continuation, or changes:true with a cursor for late final updates to older rows. False/absent changes is omitted on the wire; there is no limit argument. Preserve next_cursor, changes_cursor, gap and health fields. A gap requires refreshing history. The tools keep no cursor cache and never drain pages automatically. get_activity takes an activity_id shaped as act_ plus 32 lowercase hex digits, a request identity rather than an idempotency key. Recorded state, scope, revision, timestamps, execution identity and status remain distinct: accepted background work is not finished execution, and a dispatched error may have had effects. History is selected, retained, best-effort metadata, not all guest work or an agent identity.

get_activity_results returns at most eight newest metadata links, preserving revision, availability, association, byte/truncation metadata and observations. more:true has no continuation cursor and does not mean all versions were returned. An unavailable item is not an empty available item. Caller-selected artifact association does not prove creation or command success. This tool never follows a link to content, files, captures, downloads or execution polling.

read_signals reads one passive daemon page, independently of the active event socket. Omit since or send an empty string for a head-only baseline with no replay. Optional limit is 1–100; omitting it uses the API default 50. Preserve the returned cursor even when events is empty: filtered-out rows may advance it. Retention is ephemeral; expired/restarted/migrated cursors can return an explicit reset gap. Baselines and gaps do not prove there was no earlier work or that a task succeeded. Unsupported (501) and unavailable (503) responses remain errors, never empty history or new checkpoints. There is no watcher, guest action, retry loop or automatic checkpoint cache in this tool.

Background runs and threads

run_agent holds one tool call open for the whole run, which is minutes. A client that cannot keep a call open that long, or has other work to do meanwhile, starts the same run with start_agent_run instead: it takes the same arguments as run_agent on the same payer (less store), answers as soon as the run holds the computer with a run_id, and the run goes on without the call. get_agent_run reads it back — its status, every step so far, its cost on AI credits and, once it has ended, its closing text — and is meant to be polled every few seconds; cancel_agent_run stops it where it is, and list_agent_runs pages through the account's runs newest first (computer_id, status, limit, before). One run drives a computer at a time: a start on a computer another run is driving is refused 409 with reason: "contention", and list_agent_runs with status: "running" finds the run to wait for or cancel. If a start's answer is lost, or it fails with a 5xx, list_agent_runs with computer_id and no status is the read to make before starting another: a short run may already have ended, and is then the newest on the list. The exception is a 503 with reason: "draining", below, which started nothing.

Only status: "completed" with stop: "end_turn" means the task was finished, and the tools say so in as many words. Any other stop on a completed run (max_steps, max_cost, rate_limited, …), failed, cancelled and interrupted are runs that did not finish, and the steps they took stand. interrupted is a run the platform was executing when it restarted, or whose ending was not recorded: it is not resumed, and it may have done more than it recorded, so look at the desktop before starting another.

Every run that acts on the desktop or finishes with an answer is kept in a thread, and its thread_id comes back — in the text and the JSON of run_agent and run_agent_chat (as agent.thread_id), on a failed run that was kept, and on a background run once it has one. Send it as thread_id with the next task, on the same computer, to continue the conversation: the model is given the thread's earlier turns, told they are done, and acts only on the new task. A thread of another computer, and a full one (100 turns), are refused 409. store: false on run_agent or run_agent_chat keeps nothing and cannot be combined with thread_id; a background run is always kept, since it is read back. list_agent_threads and get_agent_thread read the kept conversations; an assistant turn that ended running, aborted or interrupted may have done more than it reported. A thread holds up to 100 turns of up to 32,000 characters, so get_agent_thread answers with the newest turns that fit in about 48,000 characters, says which earlier turns it left out, and reads further back with before_turn. delete_agent_thread (with confirm: true) removes one for good: it stops no run and changes nothing on a desktop, and is meant for a thread the conversation made or the user named — every thread on the account is visible to the key. The native route's messages (a history the caller keeps itself) is not sent by these tools: a model's own context goes in the prompt, and a kept thread carries the runs' own turns.

JSON chat with your own model key

run_agent_chat drives the selected computer using the same BYOK Anthropic or OpenAI loop as run_agent. It accepts a nonempty array of textual OpenAI-shaped messages, including string content or arrays of {type:"text",text:"..."} parts. The last user message supplies the task; system messages supply standing instructions; the user and assistant messages before it are given to the model as the conversation so far, told they are done. With thread_id the thread's own turns are the conversation instead, and earlier messages are not read.

All agent runs have a fixed 60-minute wall-clock limit. Reaching it ends the run with stop: "time_limit", preserving the work already done. A background status of completed means the loop ended; only stop: "end_turn" means the task finished. Background runs accept 1–500 steps (default 20); foreground sync, streaming and chat runs accept 1–100 (default 20).

Optional model selects a computer-capable Anthropic or OpenAI model. max_steps is 1–100, default 20. This is computer control, not hosted general-purpose inference or a chat UI; it adds no key storage or model billing service.

This tool deliberately sends stream:false and uses the JSON response so the result preserves the underlying agent.stop, step count and token usage: the streamed form of this route carries no usage and no agent block. The price is time. On the hosted API a request that does not stream is cut at the edge after about 120 seconds (a bodiless 524), which stops the run where it was and loses its result, usage and steps; the default 20 steps can take longer than that. Use run_agent, which streams, for anything that may. The tool answers a 524 by saying so rather than as a generic gateway failure. Only explicit end_turn consistent with the completion's finish reason can report success. Limits, refusal, missing or conflicting terminal fields remain errors with valid partial results. Nested failures preserve the agent computer, recorded steps and native usage, including separate cache-read and cache-write token counts, alongside OpenAI-shaped aggregate usage. Malformed native detail is explicitly marked incomplete. A failed call may include completed, billed work: inspect it before deciding what remains, and do not automatically replay. Neither agent tool starts the computer or switches endpoints after a failure.

The caller supplies the model key through MANDALA_MODEL_KEY on stdio or their own X-Model-Key header on HTTP. The account Authorization remains separate; HTTP never falls back to the operator's model key. Waiting heartbeats count notifications, not completed actions. A progressToken plus resetTimeoutOnProgress keeps the MCP client waiting, but not the hosted edge above; max_steps is neither a time cap nor a spend cap.

On both agent tools a failure status is read for what it is on these routes rather than for what it means elsewhere. The platform's own re-check of the caller is a 401 or 403 carrying reason: "revoked", and only that gets account advice. A 402, 504 or 529 is the model provider's own status for the configured model key (its billing, timeout or overloaded error), so the advice is to check the model-provider account, not the Mandala plan; a 403 without revoked may be the provider's permission error for that key. The one 402 that is Mandala's own carries a top_up_url: a run on AI credits the account cannot cover, worded as such. The exception is a refusal run_agent_chat is given before any run started — a flat {error: string} body, from the role gate, a bad body, a suspension or the meter: nothing ran, and it keeps the usual role and plan advice every other tool gets.

While the platform updates, it stops starting agent runs for a few minutes. run_agent, start_agent_run and run_agent_chat are then refused with a 503 carrying reason: "draining" and a Retry-After. The refusal comes before anything starts, and runs already going are not affected. So these tools do not give the usual 5xx answer here (that the change may have happened, a run may have started, or work may already be billed). They say that nothing started and nothing was billed, and give the number of seconds to wait before sending the same call again. This server does not resend it itself: it retries no call that starts a run. Any other 5xx on these tools keeps the uncertain answer, and so does a draining body that also records work (steps, usage, a cost, a thread, or a run's own failure envelope): that answer shows the word but does not say nothing started, and the tool descriptions grant the resend only on that sentence.

Development

npm ci
npx vitest run    # deterministic offline tests, including the synthetic contract
npm test          # offline tests plus the separate private mirror check
npm run build
npm run lint

CI runs the offline suite on Node 20, 22, 24 and 26. A separate Node 22 published-openapi job runs on pull requests and main pushes:

npx vitest run --config vitest.openapi.config.ts

It anonymously fetches the fixed publication at https://app.mandala.computer/api/docs/openapi.json once, with a 20-second overall deadline and an 8 MiB body ceiling, then exercises the real MCP tools and requires request evidence for every published /api/v1 operation. Every exercise variant must succeed and dispatch a request, including later variants of a tool that already dispatched successfully. Non-v1 operations are explicitly excluded and reported. Protocol forms are reported but not required, since no tool sends them: OPTIONS (the CORS preflight) and a HEAD published beside a GET at the same URL (that GET without its body). A HEAD with no such GET is required like any other operation. The check uses OpenAPI server inheritance and literal-path precedence, not the local route allowlist. Each path is appended to its effective server base; repeated prefixes are not removed. Fully prefixed paths work with an absent or root server. It fails on a blocked fetch, redirect, invalid document or missing operation; there is no fixture fallback, credential requirement or skip branch.

The committed OpenAPI fixture is synthetic, assembled from the public MCP route inventory, and is never presented as a downloaded publication. Offline green proves deterministic implementation coverage only. Each published-openapi run logs the publication's digest and how many operations it matched with how many requests from how many tools; a result applies to that commit and that publication, and every head must pass the gate independently. Those counts are observations, never fixed thresholds or exemptions. A blocked or red public gate must not be merged. Parameters and response modes remain separate contracts, with documented parameter exceptions and JSON-only chat support.

Where the platform's rules live

This server gets no privileged access. Everything it does goes through the same curated /api/v1 surface the Python SDK uses, owner-scoped to the key's account and audited against it. Anything it needs that /api/v1 does not expose is a change to the platform's route table, not a wider pass-through here.

Maintainers: the surface check

The platform allowlists every route /api/v1 will answer and 404s the rest. test/allowlist.ts mirrors that table, and the tests assert two things: that every successful exercised call lands on an allowlisted route, and that no non-excluded mirrored operation remains unexercised. UNIMPLEMENTED in test/allowlist.ts documents the five intentional exclusions: API-key creation and deletion, and browser-connection creation, renewal and deletion. Tool names and exercise entries must match in both directions, and every tool must make an observed HTTP request during its callback. The independent public gate also detects a new published operation when the mirror has not yet been updated.

npm run check:surface goes further and diffs the mirror against the platform's published surface manifest — a file the platform generates from its own tables and commits like a lockfile — whenever the platform repository happens to be checked out next door, or wherever MANDALA_PLATFORM_REPO points. Without it the script says it is skipping and exits 0, which is what it does for anyone outside the platform team; a manifest it cannot read is a failure, never a comparison of nothing. The diff is enforced from the platform's own CI, which checks this repository out beside itself and runs the same script.

check:surface — the mirror matches the platform (N routes, N parameters, from …).

See also

  • typescript-sdk — the TypeScript SDK and the mandala CLI, for writing code against the same API rather than driving it from a model.

  • python-sdk — the Python SDK and the mandala-py CLI, for the same thing from Python.

The same operation under each client's name

The clients follow their own language's naming, so one operation can go by several names. Where a client has no way to do it, the cell says so with —.

Operation

TypeScript SDK

Python SDK

MCP tool

mandala CLI

mandala-py CLI

A command in the background

execBackground(), then execPoll(pid) and execKill(pid)

start_exec(), then background_command(pid).poll() and .kill()

exec with background: true, then exec_poll and exec_kill

computers exec --background, then computers exec-poll and computers exec-kill

—

Delete a computer with its snapshots

delete({ deleteSnapshots: true, expect })

delete(delete_snapshots=True, expect=…); purge_snapshots is the deprecated name

delete_computer with delete_snapshots and expect

computers delete --delete-snapshots --expect

—

Snapshot holdings (count, bytes, fingerprint)

holdings(), or its alias snapshotHoldings()

snapshot_holdings()

snapshot_holdings

snapshots holdings

—

The usage window

usage.read({ from, to })

usage.read(since=…, until=…), or from_= and to=

get_usage with from and to

usage --from … --to …

—

Change a computer (PATCH)

update({ … })

rename(), resize(), set_idle_suspend(), set_browser_proxy(), set_egress_proxy()

update_computer

computers rename, resize, idle-suspend, browser-proxy set/clear, egress-proxy set/clear

browser-proxy set/clear, egress-proxy set/clear

Wait until the computer is ready

waitForGuest(), waitForDesktop()

wait_for_guest(), wait_for_desktop()

wait_for_computer with until: "guest", which on Linux also waits for the desktop session

computers wait --until guest or --until desktop

—

A screenshot, fresh or cached

screenshot(width, { fresh, capture }): cached unless fresh: true

screenshot(fresh=…, capture=…): cached unless fresh=True

screenshot: fresh by default unless capture is given; fresh: false for the cache

computers screenshot --fresh

—

The windows after an input action

{ context: true } on an input method, e.g. click(x, y, [], { context: true })

context=True on an input method, e.g. click(x, y, context=True)

context: true on an input tool

—

—

Security

Please report anything security-sensitive privately — see SECURITY.md rather than opening an issue.

Resumable file uploads

write_file_chunk, get_file_upload, and cancel_file_upload expose Linux resumable uploads up to 2 GiB. Each tool write carries at most 256 KiB of decoded base64 to bound model-context transfers; prefer the SDK or CLI for large local datasets. Retain a fresh random 32-character lowercase hexadecimal upload_id, destination path, total size, and unchanged source. Send chunks at the confirmed offset. After any error, read status before retrying. The final chunk publishes atomically; overwrite: false refuses an occupied destination.

Cancel removes only staging and the completion receipt, never the published destination. Staging consumes guest disk until cancelled and has no automatic expiry. These tools may resume a computer and consume running capacity unless no_wake is set; they are included in the files tool group and excluded from read-only mode. They require Linux with Python 3 and an updated host. Existing write_file behavior is unchanged.

Licence

MIT.

Available Tools

125 tools
add_ssh_keyAdd an SSH public keyAInspect

Register an OpenSSH public key to the person this API key belongs to. It is accepted only by computers with SSH on in the account this credential acts on, and is removed when the credential is revoked. Accepted: Ed25519, ECDSA (P-256, P-384, P-521), their security-key forms, and RSA of at least 3072 bits. Refused: DSA, shorter RSA, certificates, a line with SSH options in front of the key, and anything but one key on one line. A key can belong to one person only, and each person may hold eight. Never send a PRIVATE key.

NameRequiredDescriptionDefault
nameNoA label, up to 60 characters. Defaults to the comment on the line.
public_keyYesOne line from a .pub file: "<type> <base64> [comment]". The file's contents can be passed as read: surrounding whitespace, including a trailing newline, is dropped. The comment is dropped too.

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and delivers: lifecycle behavior (removed when credential is revoked), acceptance criteria (Ed25519, ECDSA, security-key forms, RSA >= 3072), explicit refusals (DSA, short RSA, certificates, option lines, multiple keys), cardinality limits (one person per key, eight per person), and a safety warning against private keys.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded in the first sentence, and the accepted/refused enumerations, while dense, each carry actionable constraint information that earns its space. It runs long but contains no filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no annotations and no output schema, the description covers authorization context, input constraints, lifecycle, and limits comprehensively. The only omission is any indication of what the call returns, which is a minor gap given the absence of an output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3, but the description adds genuine param-relevant meaning: the accepted/refused algorithm list, the one-key-per-line constraint, and the 'never send a PRIVATE key' warning are not in the schema. It adds nothing for the 'name' parameter, which the schema already documents fully.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource ('Register an OpenSSH public key') and scopes it to the person the API key belongs to. It is unmistakably distinct from its siblings list_ssh_keys and remove_ssh_key without any schema lookup.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description establishes context (the key works only on computers with SSH enabled in the acting account, and is removed on credential revocation), which implies when it is applicable. However, it never explicitly routes the agent among alternatives (e.g. set_computer_ssh, remove_ssh_key) or states when not to call it, so the guidance is inferable rather than explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

build_templateCompile a template document into an imageAInspect

Compile a document that declares spec.build steps into a golden image. Returns IMMEDIATELY with a job — a build takes minutes, an agent image roughly fifteen — and watch_build is how you follow it. THE NAMESPACE AND THE FAMILY BOTH HAVE TO BE YOURS: spec.family is what the image is called on a hypervisor, in a directory shared with every computer on that machine, so a build may only write into golden-<your account id> or that and a - and a name of your choosing. A document with build steps must LAYER ONTO ONE OF OURS: spec.from has to name a system/... template (and spec.build or spec.env need a parent at all); anything else is a 400. spec.secrets names secrets by ID (csec-…) and the environment variable each appears as, never by value, and at most 32 of them — check_template does not check that cap. They resolve among the account-wide secrets. Its refusals: a 400 saying the document names a secret that does not exist is deliberately the same for a deleted secret, a missing one, a workspace's and another account's, and is not worth retrying, nor is a 400 for a malformed reference or more than 32; a 409 saying a secret's value cannot be read right now, and a 503, are worth retrying. A refusal saying a host is busy is not a problem with your document — one build runs per hypervisor — and is worth retrying. After a successful build, pass the published ref to create_computer as template. create_computer may still return image preparation instructions or a capacity refusal; follow that result rather than assuming the successful build made every destination ready. ACCOUNT-WIDE KEYS ONLY: builds are the account's, so a key confined to a workspace is refused (403) here and by list_builds, get_build and watch_build; such a key launches a published template by its ref instead.

NameRequiredDescriptionDefault
documentYesThe document itself, as JSON or YAML — the file contents, not a wrapper.
no_reuseNoBuild again even when an image already carries this document's build digest. Identical documents normally share an image, which is what makes a repeated build cheap — so leave this off unless you specifically want the work done twice.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With only openWorldHint in annotations, the description carries the full load and does so richly: it returns immediately with a job rather than blocking, explains namespace/family ownership rules, the 32-secret cap, account-wide-key-only (403) restriction, and the exact retry semantics of each refusal (400 not worth retrying, 409/503/host-busy worth retrying). This is exactly the behavioral context an agent needs and cannot derive from the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The critical facts (immediate return, watch_build to follow, family/namespace ownership, retry guidance) are front-loaded. It is long but information-dense, with only mild redundancy around the repeated 'not worth retrying' framing for several 400 variants.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex, asynchronous build tool with no output schema, it covers the return shape (a job plus published ref), the constraints on inputs, the failure taxonomy, and the handoff to create_computer including the caveat that image preparation may still follow. Nothing essential is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description goes beyond that by detailing what the `document` argument must contain — spec.family naming rules, that spec.from must reference a system/... template, and that spec.secrets use ID+env-var rather than values — which materially affects how the single required param must be built. It adds real meaning beyond the schema's one-line description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence states a specific verb and resource — 'Compile a document that declares spec.build steps into a golden image' — and clearly distinguishes this from the sibling check_template, publish_template and list_builds by naming the downstream tools (watch_build, create_computer) it works with. An agent knows exactly what this produces.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly says when to use it ('compile a document...'), how to follow it (watch_build), and what to do with the result (pass the published ref to create_computer). It also names exclusions and conditions — a workspace-scoped key must use the launch-a-template path instead — and spells out which refusals are worth retrying versus not.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

cancel_agent_runCancel a background agent runA
DestructiveIdempotent
Inspect

Stop a background agent run where it is: the model call in flight is abandoned and no further action is taken. What it already did to the desktop stands, and so does what it cost: take a screenshot before deciding what is left. Cancelling a run that has already ended changes nothing and answers it as it is. A run this key cannot see is not found.

NameRequiredDescriptionDefault
run_idYesThe run_id start_agent_run or list_agent_runs answered: run_ and 24 hex characters.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the idempotentHint/destructiveHint annotations by explaining exactly what is destroyed (the in-flight model call), what survives (desktop side effects), and what is not refunded (the cost already incurred). It also clarifies the idempotent behavior in practice and the not-found case for out-of-scope runs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core action in the first clause and packs useful edge-case detail into three more sentences. Slightly literary phrasing ('what it cost: take a screenshot before deciding what is left') adds mild density, but every sentence carries substantive information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive, idempotent mutation tool with no output schema and full schema coverage, the description covers the safety profile, side-effect persistence, cost implications, idempotence, and error behavior. An agent has everything needed to call it correctly and to reason about consequences.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single run_id parameter is already fully documented in the schema, including its pattern and provenance (from start_agent_run or list_agent_runs). The description adds no parameter-specific detail, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Stop/Cancel) and resource (background agent run) with precise scope: the in-flight model call is abandoned and no further action is taken. An agent can immediately distinguish this from siblings like get_agent_run or list_agent_runs, which observe runs rather than terminate them.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete usage context (take a screenshot before deciding what is left) and covers two edge cases: cancelling an already-ended run is a no-op, and an invisible run returns not found. It does not explicitly name an alternative tool or contrast with get_agent_run, so it stops short of the full when/when-not/alternatives bar.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

cancel_file_uploadRemove upload stagingA
DestructiveIdempotent
Inspect

Remove an interrupted upload or completed upload receipt. Never deletes the published destination. Idempotent if staging is absent. May resume the computer unless no_wake is set.

NameRequiredDescriptionDefault
pathYesAbsolute path inside the guest.
no_wakeNotrue: do not resume a computer that is not running — refuse instead (409), so nothing is resumed and no running capacity is consumed. Use it to look at a suspended computer’s files only if it is already awake. false (the default) resumes a suspended computer to answer, which consumes running capacity.
upload_idYesA fresh random 32-character lowercase hex ID; retain it to resume. Never reuse for different contents.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations give destructiveHint and idempotentHint, and the description adds real operational context beyond them: the destruction is confined to staging, idempotency only holds when staging is absent, and the call may resume a suspended computer, consuming running capacity. That capacity side effect is the kind of non-obvious behavior an agent needs; missing is any note on permissions or what is returned.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four short sentences, front-loaded with the action and the key safety boundary. 'Idempotent if staging is absent' largely restates the idempotentHint annotation, a small redundancy, but nothing else is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive, idempotent cleanup call with no output schema, the description covers scope of deletion, repeat-call safety, and the resume/capacity side effect, which is what an agent needs to invoke it correctly. Only permission requirements and the effect on the upload_id afterwards are left implicit.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, including a detailed no_wake description, so the schema already carries parameter meaning. The description reinforces no_wake's consequence ('may resume the computer unless no_wake is set') but adds nothing about path or upload_id, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (remove) and a precise resource (upload staging: an interrupted upload or completed upload receipt), and scopes it against what it is not ('Never deletes the published destination'), which separates it from artifact/result deletion tools. It stops short of naming a sibling, but the operation is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Remove an interrupted upload or completed upload receipt' defines the situation that selects this tool, and 'never deletes the published destination' acts as an explicit when-not constraint. No alternative tool (e.g., delete_artifact) is named for removing the published file, so it falls short of a full routing statement.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

check_templateCheck a template documentA
Read-only
Inspect

Check a document against the SCHEMA, without publishing it. Nothing is stored and no ref is claimed, so this is safe on a draft and safe to call repeatedly, and every problem comes back at once. Always check before publishing: a ref is immutable, so a document published with a mistake in it cannot be corrected under that version. WHAT IT CANNOT SEE: this reads the document alone and knows nothing about your account, so valid: true does not mean publish_template will succeed. Whether the namespace is yours, whether the family is yours, whether your plan may publish at all, and whether the ref is already taken or retired are all decided at publish time and can still refuse a document that checks out here — among them a spec.hardware.disk_gb below the disk floor of its family or parent template (400), and a document that declares a build into a family that is not your account's (403). It DOES report that spec.build and spec.env need a parent in spec.from, and that a document with build steps may only layer onto a system/... template (anything else is a 400). It does NOT check spec.secrets beyond its shape: the cap of 32 references, and whether each id is a secret in your scope, are decided when build_template is called.

NameRequiredDescriptionDefault
documentYesThe document itself, as JSON or YAML — the file contents, not a wrapper.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With readOnlyHint=true the safety baseline is already covered, and the description goes well beyond it: nothing is stored, no ref is claimed, idempotent, and all problems returned at once. It also clearly delineates blind spots (account/namespace/plan/ref availability, spec.secrets beyond shape) and reports 400/403 conditions. The only slight gap is a lack of detail on the exact return shape of the problem list.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The strongest, most decision-relevant facts (what it does, safety, always-check-before-publish) are front-loaded. The 'WHAT IT CANNOT SEE' block is well-structured, though the long em-dash sentences are dense and could be tightened a little.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, yet the description explains the meaning of a `valid: true` result and enumerates the specific failures it does and does not catch. For a validator, this is complete enough for an agent to interpret results and decide next steps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single 'document' parameter is already documented as file contents (JSON or YAML, not a wrapper). The description adds domain context around what is being validated but no additional syntax or format detail for the parameter itself, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb+resource+scope: 'Check a document against the SCHEMA, without publishing it.' The contrast with publishing is immediate, so an agent can distinguish this from publish_template and build_template without inspecting either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states exactly when to use it ('Always check before publishing'), why (a ref is immutable, so mistakes are uncorrectable under that version), and that it is safe and repeatable on drafts. The trigger condition and its rationale are explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

clickClickAInspect

Click the mouse. Left button once by default. Take a screenshot afterwards to see what happened — the desktop does not report back on its own.

NameRequiredDescriptionDefault
xNoLeave x and y out to act where the pointer already is. Both or neither — half a coordinate is refused rather than completed with a zero.
yNo
countNoHow many clicks, 1 to 10: 2 is a double click and 3 a triple click, on any button. The presses are paced as a double click's are, so the desktop sees one multi-click.
buttonNoleft
contextNoAnswer the desktop's windows, and which one has focus, as they stand just after the action — what list_windows would say, without a second call — and, when the focused window is Chromium, the page on screen: its URL, title and the interactive elements visible in it, each with the point to click. Read at once, so a window still opening may not be listed yet. If they cannot be read the action still happened, and the answer says why.
modifiersNoKeys held down for the duration of the action.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden and does the most important job: it discloses that the desktop gives no feedback on its own, which is a non-obvious behavioral trait that changes how an agent sequences calls. It omits other operational context such as the need for an active/selected computer, but the central behavior is well covered.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, front-loaded with the action, followed by the key operational caveat. No filler and nothing buried.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 7-parameter action tool with no output schema, the description supplies the essential missing piece — that results must be observed via screenshot rather than a return value. Combined with the detailed schema for context/modifiers/computer_id, an agent has enough to call it correctly; broader prerequisites (active computer) are left implicit.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 71%, and the schema itself documents the non-obvious parameters richly (x/y pairing rules, count as multi-click, context read semantics). The description only reinforces the defaults ('Left button once by default'), adding little beyond the schema, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names a concrete verb and resource ('Click the mouse') and immediately fixes the default (left button, single click), which lets an agent distinguish it from drag, move_mouse, and mouse_button without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly tells the agent what to do after clicking ('Take a screenshot afterwards to see what happened'), giving clear operating context. It does not name the alternatives (drag, mouse_button for press/release, move_mouse for pointer movement) or state exclusions, so it falls short of a full when/when-not routing statement.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

clone_computerClone a computerAInspect

Copy a computer's current disk to a new computer — the fork half of snapshot-and-fork. The source is untouched and must be stopped or suspended: a running source is refused with 409. The answer arrives as soon as the copy exists, reading status "building" while its disk is copied — wait for that to finish before starting it. The copy keeps the source's size and resolution (its disk carries a desktop laid out at that size), lands stopped, and has no secrets bound.

NameRequiredDescriptionDefault
nameNoA name for the copy.
computer_idNoWhich computer. Defaults to the one selected with use_computer.
idempotency_keyNoOptional. Omit it on a first attempt: a fresh key is sent for you, and an answer that is lost names it. Pass the key such an answer named to send the SAME call again without it being done twice — the platform answers with the first call's result, or says it is still running. After a 5xx that names no operation_id, send the same call again with the same key: nothing may have been done, and the platform either carries it out (the key was released) or answers idempotency_outcome_unknown. After idempotency_outcome_unknown, or a 5xx that names an operation_id, the key is spent (resending with it answers idempotency_outcome_unknown), and the call may still be under way: read its operation first (get_operation with the operation_id the error named, or list_operations with the key), wait while it is pending or running and do not resend meanwhile, and send the call with a new key (or none) only once the operation is final as failed or not found AND get_computer shows the step did not happen. Keys last 24 hours; the same key with different arguments is refused.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and delivers: source is untouched, running source yields 409, the call returns early with status 'building', the copy inherits size/resolution, lands stopped, and has no secrets bound. That is exactly the behavioral context an agent needs to avoid misuse.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the operation, then prerequisites, then return semantics and resulting state. Dense but every clause carries actionable information; nothing is padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema and no annotations exist, so the description must cover return behavior and state transitions — and it does, including the 'building' status and the stopped landing state. Nothing an agent needs to invoke this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the idempotency_key semantics are documented exhaustively in the schema itself. The description adds no parameter-level meaning beyond what the schema already provides, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource: 'Copy a computer's current disk to a new computer.' It positions itself precisely within the family ('the fork half of snapshot-and-fork') and is clearly distinguishable from siblings like create_computer and clone_snapshot.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a real precondition ('The source is untouched and must be stopped or suspended: a running source is refused with 409') and the sequencing rule ('wait for that to finish before starting it'). It does not explicitly name a sibling to use instead for the other half of the workflow, so it stops short of full when-not/alternative guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

clone_snapshotFork a snapshot into a new computerAInspect

Build a new computer from a snapshot, leaving the original untouched. This is the fork half of snapshot-and-fork, and the only thing that works on an orphaned snapshot. A MEMORY snapshot is resumed: the copy comes up running the captured session, and is given its own MAC, address, hostname, machine ID, SSH host keys and desktop password before its network comes up, so it runs beside its source; if that fails it is left stopped, and starting it cold-boots its disk. Pass memory: false to build it from the disk alone instead. A clone built from a DISK — a disk snapshot, memory: false, or a memory snapshot the platform did not resume — comes back building and ends its build STOPPED: start it with start_computer once the build finishes (wait_for_operation on its operation). A memory snapshot of a computer that held SECRETS is resumed only with inherit_secrets: true, and then the copy HOLDS THE SAME CREDENTIALS as the computer it came from; without it the clone is built from the disk and this tool says so.

NameRequiredDescriptionDefault
nameNoA name for the new computer.
memoryNoMemory snapshots only. false builds the new computer from the disk alone, and it ends its build stopped, to be started with start_computer; omitted or true resumes the captured session.
selectNoMake the new computer this session's selected one.
snapshot_idYes
idempotency_keyNoOptional. Omit it on a first attempt: a fresh key is sent for you, and an answer that is lost names it. Pass the key such an answer named to send the SAME call again without it being done twice — the platform answers with the first call's result, or says it is still running. After a 5xx that names no operation_id, send the same call again with the same key: nothing may have been done, and the platform either carries it out (the key was released) or answers idempotency_outcome_unknown. After idempotency_outcome_unknown, or a 5xx that names an operation_id, the key is spent (resending with it answers idempotency_outcome_unknown), and the call may still be under way: read its operation first (get_operation with the operation_id the error named, or list_operations with the key), wait while it is pending or running and do not resend meanwhile, and send the call with a new key (or none) only once the operation is final as failed or not found AND get_computer shows the step did not happen. Keys last 24 hours; the same key with different arguments is refused.
inherit_secretsNoConsent to resuming a memory snapshot of a computer that held secrets. The new computer holds the same credentials, bound to the same secrets. Only set this when that is what the user asked for.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and delivers rich disclosure: a resumed memory snapshot receives its own MAC, address, hostname, machine ID, SSH host keys and desktop password before networking, falls back to stopped on failure, and diskgit clones end STOPPED. It also discloses the security-relevant fact that inherit_secrets makes the copy hold the same credentials, which no structured field conveys.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and topology are front-loaded in the first sentence, and almost every sentence carries behavior an agent needs. It is dense and slightly repetitive about disk clones ending their build stopped, stating it once in prose and again tied to start_computer, which costs it a point.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a six-parameter clone tool with no annotations and no output schema, it covers outcomes, failure fallbacks, post-build starting, the secrets hazard, and points to wait_for_operation for the resulting operation. Nothing essential to calling it correctly appears to be missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 83%, so baseline is 3, but the description adds real meaning beyond the schema: it explains the disk-vs-memory outcome difference for memory:false and the consent semantics and credential consequences of inherit_secrets. Name and select are left to the schema, and idempotency_key is not touched in the prose.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb and resource, 'Build a new computer from a snapshot', and immediately distinguishes scope with 'leaving the original untouched'. It further differentiates from siblings by calling itself 'the fork half of snapshot-and-fork' and noting it is 'the only thing that works on an orphaned snapshot', so an agent can tell it apart from restore_snapshot without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear routing conditions: use memory:false to build from disk alone, use inherit_secrets:true only for a memory snapshot of a secret-holding computer, and start a disk-derived clone with start_computer after the build. It stops short of naming restore_snapshot or clone_computer explicitly as alternatives, leaving the 'when not to use this' side to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_computerCreate a computerAInspect

Build a new cloud desktop and select it for this session. Creating a computer consumes storage; running it consumes running capacity on this account. Continue an image preparation refusal only as its result instructs, retaining all original create arguments, including template, and adding the returned preparation token as an argument. This token is not a create idempotency key. Stop after success; never automatically replay after a lost or ambiguous response without the idempotency_key that response names — with it, the same call answers the first one's result instead of building a second computer.

NameRequiredDescriptionDefault
cpuNo
nameNoA label. The platform picks one if you do not.
sizeNoA named size from list_sizes, e.g. "large" — the fast path, since these are the shapes the platform keeps pre-booted. It sets template, cpu, ram_mb and disk_gb together, so send it alone or the explicit fields alone, never both.
startNoBoot it immediately. True by default.
ram_mbNo
disk_gbNoThe template's own disk is a FLOOR, not a default — read it from list_templates. A smaller number is raised to it silently and the raised figure counts against storage limits, so asking for less than the template needs spends more of the plan's disk pool than the number here suggests and can be refused outright.
ends_atNoWhen the computer stops by itself: at that time its host stops it, as stop_computer would, and its disk is kept; get_computer's ends_at says when, and is gone once it has fired or been cleared. It fires once. A host that cannot keep an end time answers 409 with reason unsupported. An RFC 3339 time at least 10 minutes and at most 366 days from now, e.g. "2026-11-01T18:00:00Z". Give this or ends_in_hours, not both.
secretsNoSecrets from the account to deliver into the desktop session each time the computer starts, each as an environment variable (`env`) or as a file under /run/mandala-secrets/user/files (`file`). Only ids and names are sent — never a value. Secret ids come from list_secrets (create_secret stores a new one). Linux only, and only on a template whose image can receive them. A value replaced later reaches the running computer live when bound as a file, and as a variable on an image that supports it reaches new shells and every exec, plain or with desktop: true. get_computer_secrets and set_computer_secrets read and change the bindings later.
templateNoFrom list_templates: the short name of a template the platform publishes, e.g. "base" for Linux/Xfce, or a pinned ref (namespace/name@version) — which a template you published must be named by. A short name that is none of the published templates falls back to base — except while list_templates is INCOMPLETE (a host did not answer), when the create is refused with a retryable 503 that changed nothing; send it again shortly with the same idempotency_key, or pass a ref to avoid the guess. A ref that names nothing is refused. Defaults to base.
resolutionNoWIDTHxHEIGHT or WIDTHxHEIGHTxDEPTH, 640x480 to 3840x2160, even numbers, depth 16, 24 or 32 (24 when left out); anything else is refused. Create-time only — the display is a QEMU property and there is no route that changes it later. Defaults to 1280x800x24.
egress_proxyNoSends ALL of the computer's outbound TCP through a proxy — exec, terminals, package managers and browsers alike — taken on its host, so nothing inside the computer can opt out. There is no bypass list. It FAILS CLOSED: when the proxy is down or refuses, or its credentials have not reached the host yet (get_computer then says its egress proxy is waiting for credentials), the connection fails and nothing is sent directly. UDP to the internet and ICMP are dropped (QUIC falls back to TCP; NTP and other UDP stop working). DNS lookups are NOT proxied; they go to the platform's resolver. Connections open through the proxy are closed when the setting changes. A host that cannot take it yet — or cannot take an https:// one, or one naming credentials — answers 409 with reason unsupported; one that cannot put it into effect now answers 503, and nothing is changed unless that error says the new setting was stored. It is in effect from the first packet the computer sends: until a proxy's credentials reach its host, connections are closed, not sent directly (wait_for_computer with until="guest" waits for them). A create carrying one is never answered from the warm pool, and a clone does not inherit it. A credentials_secret_id naming no secret, or one whose value is not user:password, is refused with 400 before anything is created. update_computer changes or removes it later.
workspace_idNoThe workspace to create the computer in, an id from list_workspaces. Its secrets and an egress proxy's credentials_secret_id are then named from that workspace's scope: its own secrets and the account-wide ones. Left out, the computer goes in this key's workspace, or in none for an account-wide key. A workspace this key cannot reach — another account's, one that does not exist, or any but its own for a key confined to a workspace — is not found, and nothing is created.
browser_proxyNoSends the computer's browsers (Chromium, Chrome, Firefox) through a proxy; nothing else on it uses the proxy, so exec and a terminal go out directly. Linux only. A create carrying one is always a cold boot. A credentials_secret_id must name a secret bound as a file in this create's secrets. A template you published may carry a default browser proxy, which the computer inherits when this is left out; send another proxy to use that instead, or null to create the computer with none. wait_for_computer with until="guest" waits until its browsers have it; update_computer changes or removes it later.
ends_in_hoursNoWhen the computer stops by itself: at that time its host stops it, as stop_computer would, and its disk is kept; get_computer's ends_at says when, and is gone once it has fired or been cleared. It fires once. A host that cannot keep an end time answers 409 with reason unsupported. Hours from now, fractions allowed (0.5 is half an hour); the platform turns it into ends_at. Give this or ends_at, not both.
idempotency_keyNoOptional. Omit it on a first attempt: a fresh key is sent for you, and an answer that is lost names it. Pass the key such an answer named to send the SAME call again without it being done twice — the platform answers with the first call's result, or says it is still running. After a 5xx that names no operation_id, send the same call again with the same key: nothing may have been done, and the platform either carries it out (the key was released) or answers idempotency_outcome_unknown. After idempotency_outcome_unknown, or a 5xx that names an operation_id, the key is spent (resending with it answers idempotency_outcome_unknown), and the call may still be under way: read its operation first (get_operation with the operation_id the error named, or list_operations with the key), wait while it is pending or running and do not resend meanwhile, and send the call with a new key (or none) only once the operation is final as failed or not found AND get_computer shows the step did not happen. Keys last 24 hours; the same key with different arguments is refused.
template_transferNoNonblank opaque token from an image preparation refusal; preserve it exactly. When the result permits continuation, keep all original create arguments including template, add this token, and wait for the supplied delay. Requires template and cannot be combined with size. Not a create idempotency key: stop after success and never automatically replay after a lost or ambiguous response.

TDQS

A3.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare openWorldHint and destructiveHint=false; the description adds substantial behavior beyond that: storage vs running-capacity cost split, the image-preparation continuation protocol with the preparation token, and the precise replay/idempotency contract including that the token is NOT an idempotency key. This is exactly the kind of context structured fields cannot carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core purpose is front-loaded in the first sentence and every sentence is load-bearing. The middle sentences are dense and run together (continuation plus idempotency in one breath), which costs some readability but no wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 16-parameter tool with nested objects and no output schema, the description covers the highest-risk behaviors: cost, continuation, and idempotent retry. Parameter-specific concerns (secrets delivery, proxy fail-closed semantics, ends_at) are handled in the schema at 88% coverage, so the description is adequate without duplicating them.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 88%, so nearly every parameter is already well documented (size, template, ends_at, secrets, egress_proxy, idempotency_key all carry rich inline text). The description reinforces template ('including template') and the idempotency key, but adds little parameter-level detail the schema does not already provide. Baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence names a specific verb and resource: 'Build a new cloud desktop and select it for this session.' It distinguishes create from the start/restart/clone siblings implicitly via 'new' and 'select it for this session', though it never names an alternative tool explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives operational guidance on the retry path ('Stop after success; never automatically replay after a lost or ambiguous response without the idempotency_key') but says nothing about when to use create_computer versus clone_computer, or what prerequisites (workspace, template lookup via list_templates/list_sizes) an agent needs before calling. Usage is implied, not stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_credential_gateway_bindingLet a computer use a secret through the credential gatewayAInspect

Let programs inside the computer call an HTTPS API with a secret from the account’s store (create_secret) WITHOUT the secret ever reaching the computer. The platform adds the secret as Authorization: Bearer <secret> (or, with auth_header x-api-key, as x-api-key: <secret>) to requests the computer sends to the answered base_url followed by the provider path, with the placeholder as the API key — Authorization: Bearer <placeholder> or x-api-key: <placeholder> (the placeholder is in the answer) — and only for the given exact https:// origin (port 443, no path), path prefix (matched at segment boundaries) and methods. For example, origin https://api.github.com, path_prefix /repos/acme/app and methods ["GET"] lets the computer GET <base_url>/repos/acme/app/issues. For an Anthropic key: origin https://api.anthropic.com, path_prefix /v1, methods ["POST"] and auth_header x-api-key; Claude Code inside the computer then runs with ANTHROPIC_BASE_URL=<base_url> and ANTHROPIC_API_KEY=mandala-placeholder. Answers stream (server-sent events work). The platform uses the secret’s latest value on every call. Owners only; needs a paid or trial account with secrets enabled and a secret in the computer’s workspace or account. Up to 8 per computer (409 past that). A binding cannot be changed: delete it and create another. Clones do not inherit bindings; moving the computer to another workspace or owner removes them. Not idempotent: a retry after a lost answer makes a second binding — list_credential_gateway_bindings first. Use a narrowly scoped provider key: code inside the computer can make any request the binding allows.

NameRequiredDescriptionDefault
originYesThe exact HTTPS origin the secret may be sent to, e.g. `https://api.github.com`: no path, query, fragment, credentials or port.
methodsYesThe HTTP methods allowed, each once: GET, HEAD, POST, PUT, PATCH, DELETE.
secret_idYesThe secret to use — `csec-` and sixteen hex, from list_secrets or create_secret.
auth_headerNoWhere the platform puts the secret upstream: `authorization` (default) as `Authorization: Bearer <secret>`, or `x-api-key` as `x-api-key: <secret>` — use `x-api-key` for an Anthropic key. A host that cannot send `x-api-key` yet answers 409.
computer_idNoWhich computer. Defaults to the one selected with use_computer.
path_prefixYesThe absolute path prefix allowed under that origin, matched at segment boundaries (`/v1` allows `/v1` and `/v1/...`, not `/v10`). `/` allows every path.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and does so thoroughly: it explains secret injection, placeholder behavior, exact origin/path/method scoping, latest secret value usage, streaming answers, limits, immutability, clone/move behavior, and non-idempotence. It also warns that code inside the computer can make any request the binding allows.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core purpose is front-loaded and every major clause conveys operational detail, but the description is a single dense paragraph with some redundancy around placeholder headers. It is appropriately thorough for a security-sensitive tool, yet could be structured more cleanly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex tool with no annotations and no output schema, the description is nearly complete: it covers permissions, limits, immutability, non-idempotence, and the fact that the placeholder is in the answer. It stops short of fully describing the response shape or all returned fields, which is the main remaining gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all six parameters well. The description nevertheless adds useful examples showing how origin, path_prefix, methods, and auth_header compose for GitHub and Anthropic, though much of the prose still repeats schema-level constraints.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb/resource — creating a credential gateway binding — and explains the mechanism: letting programs inside a computer call an HTTPS API with a stored secret without the secret reaching the computer. It also distinguishes the tool from related siblings such as create_secret and list_credential_gateway_bindings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It provides explicit contextual guidance: owners only, paid/trial account, secrets enabled, secret in the workspace or account, up to 8 per computer, and a 409 past that. It names alternatives and prerequisites directly — list_credential_gateway_bindings before retry, and delete rather than update because bindings are immutable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_public_urlServe a port on a public URLAInspect

Serve a port inside the computer at https://<label>.<base_domain> (e.g. https://brave-otter-3f2a.mandala.dev), on 443 with no port in the address. Omitted access defaults to public on paid plans and private on trials. Public URLs are open to anyone with the link; trials cannot request public access. Pass access: "private" to require an account API key (workspace-scoped keys must match the computer) or browser sign-in through the dashboard Open button. The app must listen on 0.0.0.0:, not 127.0.0.1. Without a label one is picked. A label is 3 to 40 letters, digits and hyphens, and the platform refuses names that read as its own or another company’s (www, login, brand names and their look-alikes) with a 400 that says why. Other refusals: 402 PLAN_REQUIRED when the plan includes no public URLs, or PUBLIC_ACCESS_REQUIRES_PLAN when a trial requests public access (use private access or choose a paid plan); 403 PUBLIC_URLS_BLOCKED when the platform has turned public URLs off for this computer or account (not a role, and not something to retry — tell the user); 404 PUBLIC_URLS_DISABLED when public URLs are not enabled here at all (not a missing computer); 409 LABEL_TAKEN when the label is taken — a label is never given to a second account, so one another account has ever held, or one the platform has blocked, reads as taken — and 409 PUBLIC_URL_LIMIT when the computer has as many as its plan allows (trial 1 private URL, Solo 2, Studio 5, Swarm 10); neither 409 clears by waiting. 429 after too many in a day, with Retry-After. Responses are marked noindex, cookies the app sets stay on its own host name, and a Mandala API key sent to a public URL never reaches the app. Not idempotent: a retry after a lost answer makes a second URL — list_public_urls first.

NameRequiredDescriptionDefault
portYesThe port inside the computer to serve, 1 to 65535 except 22, which is the computer’s own SSH. The app must listen on 0.0.0.0:<port>, not 127.0.0.1.
labelNoThe name before the domain, lowercased. Leave it out to have one like `brave-otter-3f2a` picked.
accessNo`public`: ANYONE WITH THE LINK can open it. Omitted access defaults to public on paid plans and private on trials; trials cannot request public access. `private`: an account API key as `Authorization: Bearer` (workspace-scoped keys must match the computer), or browser sign-in through the dashboard Open button. The key never reaches the app.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so: non-idempotency, noindex responses, cookie host scoping, API keys not reaching the app, and a complete error taxonomy (400 reserved labels, 402 PLAN_REQUIRED/PUBLIC_ACCESS_REQUIRES_PLAN, 403 blocked-not-retryable, 404 not-a-missing-computer, 409 LABEL_TAKEN/PUBLIC_URL_LIMIT with plan quotas, 429 with Retry-After).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Dense and front-loaded with the core behavior, but it is one long block paragraph that strings error codes and caveats into a single run-on. Most sentences carry information, yet the labels-rules and 409 explanations are wordier than needed for scanning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers everything an agent needs for a no-annotation, no-output-schema mutation: binding requirements, auth model, plan limits and quotas, retry/non-idempotency, and what each failure status means and whether it can be retried. Nothing material is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3, but the description adds real value: label constraints (3-40 chars, letters/digits/hyphens, platform refuses impersonating names like www/login/brands), the 0.0.0.0 binding requirement, and the default-label behavior. The access semantics are largely duplicated by the schema enum description, keeping it from a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource: serving a port on `https://<label>.<base_domain>`, including a concrete example URL and the 443/no-port behavior. An agent can immediately tell this apart from list_public_urls, update_public_url, delete_public_url, and get_desktop_url.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit decision rules for the access parameter (default public on paid, private on trials; pass private to require auth) and explicitly says 'list_public_urls first' before retrying because the call is not idempotent. It does not explicitly compare against sibling URL tools like get_desktop_url, so no exclusions are stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_secretStore a new secretAInspect

Store a value under a name on this account, encrypted, for binding to computers with set_computer_secrets (or the secrets field of a create). The value is sent once and NEVER shown again: this answer, every other tool and every route give back only the name, id and revision. Do not put the value anywhere else — not in a command line, a file or a message — when a binding can deliver it. Owners only. A name is unique within its scope (up to 60 characters, no control characters); a taken name is refused with 409. The account holds at most 100 secrets at once and may create at most 1000 over its lifetime — list_secrets reports both. Without workspace_id the secret is account-wide and any computer on the account may be bound to it. NOT safe to repeat blind: if the answer is lost, list_secrets before creating again, since the secret may exist.

NameRequiredDescriptionDefault
nameYesWhat the secret is called, e.g. OPENAI_API_KEY. Up to 60 characters, unique in its scope. This is a label, not where the value lands: set_computer_secrets names the variable or file.
valueYesThe value, as text: 1 to 4096 bytes of UTF-8. Sent to the platform once, encrypted there, and never shown again — not in this tool's answer, not by any other tool, not by any route.
workspace_idNoThe workspace it belongs to. Leave it out for an account-wide secret.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds substantial behavior beyond the sparse annotations: the value is write-only and never returned again, names are unique per scope (409 on conflict), accounts have hard limits of 100 active and 1000 lifetime secrets, workspace_id controls whether the secret is account-wide or workspace-scoped, and blind retries are unsafe. The idempotentHint=false annotation is consistent with the 'NOT safe to repeat blind' warning.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose and the write-once warning; quotas, naming rules, workspace scoping, and retry guidance each earn their place. It is somewhat long, but every sentence carries operational information rather than filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description explains what is returned (only name, id, and revision), covers authorization (owners only), quotas, conflict behavior, scoping semantics, and safe retry guidance. Nothing an agent needs to invoke this correctly appears missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents name, value, and workspace_id with comparable detail. The description reinforces the 60-character limit and adds 'no control characters' and the 409 conflict behavior, but most parameter meaning is not new beyond the structured fields.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Store a value under a name on this account, encrypted.' It distinguishes itself from siblings by naming set_computer_secrets for binding, list_secrets for visibility, and the create operation's secrets field. An agent can tell it apart from get_secret, set_secret, and replace_secret without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says when to use it: owners only, for binding to computers, and warns against putting the value in a command line, file, or message when a binding can deliver it. It also names the alternative (set_computer_secrets) and the recovery path (list_secrets before recreating after a lost answer).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_snapshotSnapshot a computerAInspect

Capture a computer so it can be restored or forked later. A disk snapshot is the filesystem; a memory snapshot also saves the running session, so a fork of it comes up with the same processes and windows already open. Name it after the step it is about — that name is what picks it out of the list later. THE CAPTURE OUTLIVES THE REQUEST that starts it: the platform accepts it and copies the disk afterwards, which takes minutes and scales with how much has been written. This waits for the copy to land by default and answers with the finished snapshot; pass wait: false to get the id straight back and poll list_snapshots yourself. Everything that can refuse a capture — no such computer, one already running, a memory snapshot of a computer that is not running, an allowance that will not stretch — is refused by this call, so anything else is a capture that started. A wait reports progress while it runs, so a client that sends a progressToken and sets resetTimeoutOnProgress can hold the request open; a client that cannot should pass wait: false and poll list_snapshots, rather than watch its own default timeout cancel a call while the capture goes on running.

NameRequiredDescriptionDefault
nameNoWhat this capture is of: "before the upgrade", "clean install", "reproduces the bug". It is the only place the reason for taking it can be written down — restore_snapshot, clone_snapshot and delete_snapshot all take an id, so a set of captures of one computer is otherwise told apart by timestamp alone, and the wrong guess on the last of those is unrecoverable. Omit it and the platform names the snapshot after the computer and the time, which says when but never why.
waitNoWait for the copy to finish, and answer with the snapshot rather than with the placeholder. Set it false to get the id back at once — useful when the capture is a side errand and there is other work to do meanwhile — and then poll list_snapshots for that id, which is what this does for you.
memoryNoInclude the running session. A memory snapshot is a saved machine, so it only loads back into the shape it came off: resize the computer afterwards and the restore is refused, because the vCPU count and the memory size are part of the state rather than decoration around it. Clone it with memory: false instead in that case, which builds a new computer from the disk alone; it ends its build stopped, to be started with start_computer.
timeout_sNoHow long to wait for the capture before handing back and letting you poll. Ignored when wait is false. Giving up on the wait does not stop the capture.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations present, the description carries the full burden and does: it discloses that the capture outlives the request, that the platform copies the disk after accepting, that it takes minutes scaling with written data, and it enumerates every refusal case (missing computer, already running, memory snapshot of a stopped computer, quota). It also states that abandoning the wait does not stop the capture.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the purpose and the disk/memory distinction, and the wait/poll behavior follows logically. It is long and occasionally repeats the schema's parameter prose (name, memory), but almost every sentence conveys a distinct behavioral fact, so the length is largely earned.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, yet the description states what a wait returns (the finished snapshot) versus a non-wait call (the id), how to poll, and the full refusal surface. For an asynchronous long-running operation this is complete enough to call correctly on the first attempt.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3, but the description goes beyond the schema by framing parameters in workflow terms: 'pass wait: false to get the id straight back and poll list_snapshots yourself', the naming rationale for later disambiguation, and the fork/resize consequence of memory snapshots. Some of this repeats the already-rich schema descriptions, so it is additive rather than essential.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Capture a computer so it can be restored or forked later') and immediately distinguishes the disk vs memory variants. It also implicitly separates itself from siblings like clone_snapshot, restore_snapshot and list_snapshots by describing what a capture is versus what consumes it. An agent can identify this tool without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly covers when to use wait:true vs wait:false, when to poll list_snapshots instead, when to prefer clone_snapshot with memory:false over a memory snapshot, and how progressToken/resetTimeoutOnProgress clients should behave. It names alternatives and the conditions that select them, leaving nothing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_webhookSubscribe an endpoint to this account’s eventsAInspect

Subscribe an HTTPS endpoint to this account’s events. THE ANSWER CARRIES THE SIGNING SECRET ONCE — it is not readable again, so store it or hand it over before doing anything else. Each event is POSTed as the same JSON object wait_for_event hands you, byte for byte, signed with Standard Webhooks v1 headers (webhook-id, webhook-timestamp, webhook-signature); the receiver should verify the raw body, acknowledge with a 2xx before doing the work, and refuse a timestamp more than 300 seconds off. A failing delivery gets eight attempts (seven retries) over about fourteen hours; an endpoint that keeps failing for a day is disabled. The url must be https, at most 2048 characters, must not carry a username or password, and must resolve to a public address — a private or loopback address is refused. Paid plans allow ten subscriptions; an account with no plan allows none.

NameRequiredDescriptionDefault
urlYesWhere to POST. https:// only, at most 2048 characters, no username or password, resolving to a public address. A port other than 443 is fine.
eventsNoEvent types to deliver: window.opened, window.closed, window.focused, window.blurred, clipboard.changed, process.exited, computer.idle, computer.ready, computer.started, computer.stopped, computer.suspended. Omit or send [] for every type. file.changed is never delivered to a webhook. An unknown type is refused by the platform with the current list.
enabledNoWhether deliveries are made.
computersNoComputer ids to deliver for, up to 64. Omit or send [] for every computer the key can see. Not checked against your computers — a subscription may name a computer you are about to create.
descriptionNoFree text for the listing, up to 200 characters.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so thoroughly: secret-shown-once semantics, byte-for-byte payload parity with wait_for_event, Standard Webhooks v1 signing headers, the 300s timestamp tolerance, the 8-attempt/~14-hour retry schedule, endpoint disabling after a day of failures, and the plan-based subscription cap. This is exactly the behavioral surface an agent needs and cannot get from structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Dense but front-loaded: purpose first, then the highest-stakes fact (the one-time secret) in emphasis, followed by distinct facts about delivery, signing, retries, and constraints. Every sentence carries unique information, though the run-on density costs it a perfect score.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema and no annotations, so the description must supply return-value and behavioral context — and it does, explaining that the response carries the signing secret exactly once. Combined with constraints, retry policy, and plan limits, an agent has everything needed to call this correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all five parameters are already documented in the schema. The description largely restates the url constraints (https, length, no credentials, public address) rather than adding new parameter semantics, so the baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Subscribe an HTTPS endpoint to this account's events') and the scope of what it creates. An agent can immediately distinguish it from the read/update/delete/rotate webhook siblings without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives strong operational context: the secret is returned once and must be stored before anything else, and paid plans vs no plan determine whether creation is even allowed. It does not explicitly name alternatives (update_webhook, test_webhook) or state when-not to use it, so it stops just short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_workspaceCreate a workspaceAInspect

Make a workspace on this account: a partition of its computers, which API keys can be confined to. Answers its id, name and created_at. A name the account already uses, a blank or over-long one, or an account already holding 500 workspaces is refused with 400. Needs an owner's key that is not confined to a workspace: a member, a viewer, or any key confined to a workspace is refused with 403 — relay that rather than retrying. NOT safe to repeat blind: if the answer is lost, list_workspaces before creating again, since it may exist.

NameRequiredDescriptionDefault
nameYesThe name: 1 to 40 characters once trimmed, no control characters, unique within the account.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=false/idempotentHint=false/destructiveHint=false, and the description corroborates and enriches them: it lists the 400 validation failures (duplicate name, blank/over-long, 500-workspace cap), the 403 auth requirement (owner key not confined to a workspace), and the non-idempotency warning with a recovery procedure. This is exactly the surplus behavioral context the annotations can't express.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action and definition, then layers return values, failure modes, auth, and idempotency in a logical order. It is dense with em-dash clauses and runs slightly long, but nearly every sentence carries operational value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no output schema, the description covers the essentials an agent needs: what it returns, which errors fire and why, the auth requirement, and how to behave when the response is lost. Little is left to inference.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents the single name parameter, making 3 the baseline. The description adds useful constraints (uniqueness within the account, 400 on duplicate) but also introduces a length conflict — it says '1 to 40 characters once trimmed' while the schema declares maxLength 200 — which weakens rather than clarifies parameter semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Make a workspace on this account') and even defines the concept ('a partition of its computers, which API keys can be confined to'), which cleanly separates it from list_workspaces/get_workspace/delete_workspace. It also names the return fields (id, name, created_at), so an agent knows exactly what it produces.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete usage conditions: it routes the agent to list_workspaces before retrying when the response is lost, and explains the 403 case ('relay that rather than retrying'). It doesn't broadly contrast against siblings like rename or delete, but for a create tool the guidance is unusually strong and actionable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

cursor_positionWhere is the pointerA
Idempotent
Inspect

Where the pointer was last put. known is false on a computer nothing has moved it on yet — the guest cannot be asked, so there is no coordinate to report and a confident 0,0 would be a wrong answer dressed as a right one. This reads a coordinate but reaches the computer to do it: a suspended one is resumed to answer, and that resume consumes running capacity. read_clipboard, by contrast, refuses a suspended computer rather than starting it.

NameRequiredDescriptionDefault
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A3.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the idempotent/non-destructive annotations by disclosing a non-obvious side effect: the call reaches the computer, resumes a suspended one, and that resume consumes running capacity. The known=false rationale also pre-empts a wrong interpretation of the return value.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core answer, then the known=false caveat, then the side-effect warning. The closing read_clipboard comparison is slightly tangential to answering "where is the pointer" but earns its place by flagging the resume behavior difference.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the return-value burden and does explain the known flag's meaning. It leaves the coordinate's shape (x/y object vs. array) unstated, which is a minor remaining gap for a tool whose only output is that coordinate.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single computer_id parameter already documents its default to the use_computer selection. The description adds no further semantics about that parameter, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

"Where the pointer was last put" plus "This reads a coordinate" states a specific verb (read) and resource (pointer coordinate), and the known=false clause clarifies what the value means. It does not explicitly name sibling readers like screenshot or list_windows to draw the boundary, so it stops short of a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The read_clipboard contrast gives a usable decision signal about suspended computers, but it is framed as a behavioral difference rather than "use this when X, use Y when Z." There is no explicit guidance on when to call this versus screenshot or move_mouse for pointer-related tasks.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_agent_threadDelete a kept agent conversationA
DestructiveIdempotent
Inspect

Permanently delete a kept conversation: its turns are gone and its id can no longer be continued. Nothing else changes — no run is stopped (cancel_agent_run stops a background run), and what its runs did to the desktop stands. Delete only a thread this conversation started or one the user asked to remove: every thread on the account is visible to this key, including other people's. It is for removing a prompt that held private text, or making room: the account keeps 1000 threads, replacing the least recently used, and a key that can delete none of them gets runs that are not kept. Needs confirm: true.

NameRequiredDescriptionDefault
confirmYesMust be true. The conversation is gone for good and cannot be continued.
thread_idYesThe thread: thr_ and 24 hex characters, from an agent run or list_agent_threads.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already flag destructiveHint and idempotentHint, but the description adds substantial context the annotations cannot carry: turns are irreversibly gone, the id can no longer be continued, desktop side effects persist, all account threads are visible to this key including other users', and the 1000-thread LRU retention consequence of not deleting. This is exactly the beyond-annotations behavioral detail expected of a destructive tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Dense but front-loaded: the irreversible effect lands in the first clause, the sibling contrast immediately after. A few clauses are rhetorically wordy ('Nothing else changes — no run is stopped...'), but each sentence carries distinct, non-redundant information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter destructive tool with no output schema, the description covers irreversibility, side-effect scope, permissions/visibility caveats, retention implications, and the confirm requirement. An agent has everything needed to decide and invoke correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description exceeds it by adding meaning about which thread_id to supply (one this conversation started or one the user asked to remove) and by reinforcing that confirm must be true. It still defers format details (pattern, source of the id) to the schema, so it is not a full 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb and resource plus a scope qualifier: 'Permanently delete a kept conversation'. It explicitly distinguishes itself from the nearest sibling by noting 'no run is stopped (cancel_agent_run stops a background run)', so an agent can separate this from run-cancellation without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

States both when to use it ('removing a prompt that held private text, or making room') and when not to ('no run is stopped', 'delete only a thread this conversation started or one the user asked to remove'). It names the alternative tool and the condition that selects it, leaving little to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_artifactDelete an immutable artifact versionB
DestructiveIdempotent
Inspect

Delete exactly this retained artifact, without metadata preflight or guest file deletion. Same deletion effect on repeat; repeated 404 remains unavailable. No retry.

NameRequiredDescriptionDefault
artifact_idYes
computer_idNoComputer, or the current use_computer selection.

TDQS

B3.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and idempotentHint=true, but the description adds real context on top: no metadata preflight, no guest file deletion, repeat calls produce the same effect, a repeated call on an already-deleted artifact returns 404, and the operation should not be retried. That 'no retry' and 404-persistence detail is genuinely useful beyond the structured hints.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with the core action and with the idempotency/no-retry guidance trailing. Nothing is wasted, though the telegraphic phrasing ('without metadata preflight') is dense enough to risk misreading.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive two-parameter tool with no output schema, the description covers idempotency, error behavior after repeat deletion, and retry policy reasonably well. It omits permissions/auth requirements and what 'retained' means, which an agent would want before issuing a destructive call.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 50%: artifact_id carries only a regex pattern with no prose, while computer_id is documented in the schema. The description does not explain the artifact_id format, the 'exactly this artifact' semantics, or the meaning of omitting computer_id, so it fails to compensate for the gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Delete exactly this retained artifact'), which is clear enough to separate it from delete_result, delete_snapshot, delete_webhook and delete_secret among the siblings. It does not, however, explicitly name or contrast against any of those siblings, so the differentiation is implicit rather than stated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use guidance: nothing says when to delete an artifact versus reading it, retaining it, or using delete_result/delete_secret instead. The clauses about preflight and guest file deletion are behavioral, not selection guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_computerDelete a computerA
DestructiveIdempotent
Inspect

Destroy a computer and its disk. Irreversible. Its snapshots are kept by default and become orphans, which can still be cloned but not restored. To destroy those too, read snapshot_holdings first and pass its fingerprint as expect.

NameRequiredDescriptionDefault
expectNoThe fingerprint from snapshot_holdings. The purge is refused unless it still names the same set, so a capture that finished after you looked cannot be swept up in a decision that was never about it.
confirmYesMust be true. This destroys the disk and everything on it.
computer_idYesRequired in full, even when one is selected — a delete is not a call to infer a target for.
idempotency_keyNoOptional. Omit it on a first attempt: a fresh key is sent for you, and an answer that is lost names it. Pass the key such an answer named to send the SAME call again without it being done twice — the platform answers with the first call's result, or says it is still running. After a 5xx that names no operation_id, send the same call again with the same key: nothing may have been done, and the platform either carries it out (the key was released) or answers idempotency_outcome_unknown. After idempotency_outcome_unknown, or a 5xx that names an operation_id, the key is spent (resending with it answers idempotency_outcome_unknown): read get_computer (and get_operation when the error named an operation_id: succeeded means it happened, running means wait on it, pending alone is no reason to wait), and if the step did not take effect, send the call again with a new key, or none. Keys last 24 hours; the same key with different arguments is refused.
delete_snapshotsNoAlso destroy every snapshot of this computer. Requires `expect`. Opt-in because the wrong answer here is unrecoverable: a snapshot kept by mistake costs storage, one destroyed by mistake costs the disk it was the last copy of.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and idempotentHint=true, so the safety profile is partly covered. The description nonetheless adds real behavioral consequence not in the annotations: snapshots survive as orphans that can be cloned but not restored, and the disk destruction is unrecoverable. It does not cover permissions or response shape, so not a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the destructive action and its irreversibility, then the default snapshot behavior, then the opt-in path. No filler; each clause carries a distinct rule.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive tool with no output schema, the description supplies the consequence model (disk gone, snapshots orphaned, clone-vs-restore distinction) and the sequencing to purge snapshots. Sufficient for correct invocation, though it stays silent on authorization requirements and the observable result of a successful delete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description goes beyond the schema by explaining the cross-tool workflow for `expect` (read snapshot_holdings, pass its fingerprint) and the rationale for the opt-in delete_snapshots flag, giving the parameter orchestration meaning rather than just restating field names.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Destroy a computer and its disk") and immediately distinguishes it from soft-stop siblings by pairing it with "Irreversible." An agent can separate this from stop_computer, suspend_computer, and delete_snapshot without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear conditional guidance: snapshots are kept by default, and to destroy them too you must first read snapshot_holdings and pass its fingerprint as `expect`. It names the sibling tool and the ordering constraint. It does not explicitly say when to prefer delete_computer over stop_computer/suspend_computer for a merely-halted machine, so it falls just short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_credential_gateway_bindingRevoke a credential gateway bindingA
DestructiveIdempotent
Inspect

Revoke one of a computer’s credential gateway bindings. Requests not yet sent to the provider can no longer use the secret; one already sent may finish. The secret itself stays in the account’s store. Owners only.

NameRequiredDescriptionDefault
confirmYesMust be true. Programs inside the computer lose the binding at once.
binding_idYesThe binding’s id — `cgw-` and 24 hex characters, from list_credential_gateway_bindings.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only supply idempotentHint and destructiveHint; the description goes further by explaining the exact destruction boundary — unsent requests lose the secret immediately, in-flight requests may finish, and the stored secret is untouched. That is precisely the nuance an agent needs before a destructive call and is not recoverable from the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four short sentences, front-loaded with the action and scope, then the effect, then the caveat, then the authority requirement. No sentence is redundant against the others.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description still tells the agent what is destroyed and what is not, that confirmation is mandatory, and who may call it — everything needed to invoke a destructive one-way operation safely. Parameters are fully covered by the schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, and the schema already documents binding_id format and provenance, the confirm=true requirement, and computer_id's default via use_computer. The description adds no additional parameter guidance, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Revoke) and resource (credential gateway binding) scoped to one computer, which cleanly separates it from create_credential_gateway_binding and list_credential_gateway_bindings. The explicit note that the secret itself survives also separates it from delete_secret.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear context for use and a permission constraint ('Owners only'), so an agent knows both the intended action and the caller requirement. It stops short of naming the alternative for removing the underlying secret (delete_secret), leaving that routing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_public_urlRemove a public URLA
DestructiveIdempotent
Inspect

The URL stops answering at once. Its label stays with this account: no other account can ever take it, and this account may use it again (create_public_url with that label) unless the platform has blocked it. The app inside the computer keeps running. A URL made again is a new id.

NameRequiredDescriptionDefault
url_idYesThe public URL’s id — `pu-` and sixteen hex characters.
confirmYesMust be true. The URL stops answering at once.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A3.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations give destructiveHint and idempotentHint, and the description goes well past them: immediate cessation of answering, label retention scoped to the account, no other account can take the label, possible platform block on reuse, the guest app keeps running, and a recreated URL gets a new id. This is exactly the post-destruction context an agent needs before confirming.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Five short sentences with no filler, front-loaded with the most important effect (it stops answering at once). Minor overlap with the confirm parameter text ("The URL stops answering at once") and no explicit purpose verb keep it from a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive delete with annotations already covering safety, the description supplies retention, recreation, and side-effect context. It omits any permission/authorization requirement, and no output schema exists, but the essential consequences are covered.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents url_id, confirm, and computer_id, including the `pu-`+16-hex format and the confirm constraint. The description's mention of a "label" and "new id" adds only indirect context and no syntax beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description never states the action plainly ("deletes the public URL"), but the combination of name/title plus the consequence-focused text ("The URL stops answering at once") makes the purpose unambiguous. It also references the sibling create_public_url as the recreation path, giving some differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It implies when the tool is relevant (the label can be reclaimed unless blocked, so deleting is recoverable and the app need not be touched) but never states a when-to-use condition or an explicit alternative to choose instead. The create_public_url reference is about recreating, not about a competing removal path.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_resultDelete a retained output versionA
DestructiveIdempotent
Inspect

Delete exactly this immutable result version. No metadata preflight or guest mutation. Same deletion effect on repeat, but a repeated 404 remains unavailable; no automatic retry.

NameRequiredDescriptionDefault
result_idYes
computer_idNoComputer, or the current use_computer selection.

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructive and idempotent, but the description adds real value beyond them: no metadata preflight, no guest mutation, identical effect on repeat, and the specific nuance that a repeated 404 stays unavailable with no automatic retry. Permission/auth requirements and whether retention records are affected remain unstated.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three compact front-loaded sentences with no filler, and the core action leads. The middle clause ('No metadata preflight or guest mutation') is terse internal jargon that could cost an agent a beat, keeping it just short of a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a no-output-schema mutation tool whose annotations already carry destructive/idempotent hints, the description covers the key behaviors an agent needs: immutability of the target, repeat semantics, and no automatic retry. Missing auth/permission expectations and downstream effect on the parent execution is the remaining gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is exactly 50%: computer_id is described in the schema, while result_id relies on its pattern constraint for meaning. The description scopes the parameter ('this immutable result version') but adds no format, defaulting, or selection semantics beyond what the schema already conveys, so the baseline 3 fits.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Delete exactly this immutable result version'), which distinguishes it from sibling deletion tools like delete_artifact and delete_snapshot by naming 'result version' as the target. It does not explicitly name a sibling it is not, so it falls short of full differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Implied usage is clear: use it when you need to remove a specific retained result version. However, there is no explicit when-to-use versus alternatives (delete_artifact, delete_snapshot, get_result), no prerequisite (e.g. retention state), and no exclusions, so guidance is only inferable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_secretDelete a secretA
DestructiveIdempotent
Inspect

Permanently delete a stored secret. This cannot be undone, and it is NOT refused while computers are bound to it: such a computer keeps the value it already holds, but can never be given its secrets again — its next start is refused (409), a restart or a reboot inside it stops it, and a suspended one cannot resume. Remove the binding with set_computer_secrets first (or on the stopped computer afterwards) so it can start. Deleting does not recall a value already delivered. Needs the current revision_id (a stale one is refused and nothing is deleted) and confirm: true. Owners only. Deleting frees a place under the account's limit on secrets held at once, but not under its lifetime limit on secrets created.

NameRequiredDescriptionDefault
confirmYesMust be true. A computer still bound to this secret cannot start again until that binding is removed.
secret_idYesThe secret — `csec-` and sixteen hex characters, from list_secrets.
revision_idYesThe `revision_id` list_secrets or get_secret answered for this secret — `csr-` and twenty-four hex characters. Required; a stale one is refused and nothing is deleted.
workspace_idNoThe workspace the secret belongs to. Leave it out for an account-wide secret. A secret in a workspace is found only with its workspace_id.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true and idempotentHint=true, but the description goes well beyond them: irreversibility, the exact consequence for bound computers (keeps held value, next start refused with 409, mid-restart/reboot stops, suspended cannot resume), that an already-delivered value is not recalled, that a stale revision_id causes refusal with no deletion, the owner restriction, and which quota is and is not freed. This is the full behavioral burden discharged.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and irreversibility are front-loaded, and nearly every clause carries new information. It is a dense single block, however, with some duplication of the schema (revision_id staleness, confirm: true) and long em-dash-chained sentences that make the binding consequences harder to scan than they need to be.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive tool with no output schema, the description covers preconditions (owner, revision_id, confirm), side effects on bound computers, remediation (set_computer_secrets), and quota effects. Nothing an agent needs in order to invoke it correctly is missing; the only mild tension is that idempotentHint=true while a repeat call with the same stale revision_id is refused, but since nothing further is deleted this is not a contradiction.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description still adds value by restating and motivating revision_id ('a stale one is refused and nothing is deleted') and confirm: true, tying both to the deletion contract. Workspace scoping for account-wide vs. workspace secrets is only covered in the schema, not the description, so it stops short of a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource and a scope qualifier ('Permanently delete a stored secret') that separates it cleanly from get_secret, create_secret, set_secret and replace_secret. It immediately adds the non-obvious rule that the delete is NOT refused while computers are bound, which an agent could never infer from the name.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Names the alternative action explicitly and the condition that selects it: 'Remove the binding with set_computer_secrets first (or on the stopped computer afterwards) so it can start.' It also states the precondition ('Owners only') and the required inputs (current revision_id, confirm: true), so an agent knows both when to call it and when to do something else first.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_snapshotDelete a snapshotA
DestructiveIdempotent
Inspect

Remove a snapshot permanently. Later snapshots in the same chain are unaffected. THE DELETION OUTLIVES THE REQUEST that starts it: the platform accepts it and then detaches the dependent snapshots and removes the stored objects, which takes time that scales with the chain and with how much is stored. This waits for it by default and reports what actually happened; pass wait: false to hand back as soon as it is accepted. A 409 saying the snapshot is ALREADY BEING DELETED is progress rather than a fault — the platform is doing what you asked, and the answer is to watch that one finish, never to go and delete something else. A wait reports progress while it runs, so a client that sends a progressToken and sets resetTimeoutOnProgress can hold the request open; a client that cannot should pass wait: false and poll list_snapshots.

NameRequiredDescriptionDefault
waitNoWait for the snapshot to stop being listed, which is the only thing that means it is gone. Set it false to hand back as soon as the platform accepts the deletion, and then poll list_snapshots yourself.
confirmYesMust be true.
timeout_sNoHow long to wait for the deletion before handing back. Ignored when wait is false. Giving up on the wait does not stop the deletion.
snapshot_idYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only supply idempotentHint and destructiveHint; the description adds the traits that actually matter here: the deletion outlives the request, it is asynchronous and its duration scales with chain length and stored bytes, the 409 is progress rather than a fault, and progressToken/resetTimeoutOnProgress controls how the wait is held open. This is well beyond what the structured fields declare and is consistent with idempotentHint=true.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded correctly: permanence and chain-scope come first, behavioral caveats after. Every sentence carries information, though the ALL-CAPS emphasis and the density of the async explanation make it heavier than it needs to be for an agent already reading the schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive, asynchronous mutation with no output schema, the description covers everything an agent needs: irreversibility, chain scope, async lifetime, the idempotency-relevant 409, timeout semantics, and the polling fallback. Nothing material is left to inference.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 75% and the schema already documents wait, timeout_s and confirm thoroughly (including that timeout_s is ignored when wait is false and that giving up does not stop the deletion). The description reinforces the wait/poll trade-off and the client-capability condition for progress tokens, but adds little to the already-documented parameters and says nothing about snapshot_id.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource ('Remove a snapshot permanently') and immediately scopes the blast radius ('Later snapshots in the same chain are unaffected'), which separates it from restore_snapshot, clone_snapshot and list_snapshots. An agent can tell exactly what state change this produces without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use branches: default wait behavior, wait: false for hand-back-and-poll, and which sibling to poll (list_snapshots). It also names a specific error condition (409 already-being-deleted) and tells the agent the correct reaction — watch that one finish, never delete something else — which is genuine routing guidance, not implied usage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_webhookDelete a webhook subscriptionA
DestructiveIdempotent
Inspect

Remove a subscription and every delivery record it holds, pending ones included. Nothing more is sent to the endpoint. Irreversible: a new subscription to the same url gets a new id and a new secret. To stop deliveries without losing the record, update_webhook with enabled: false instead.

NameRequiredDescriptionDefault
confirmYesMust be true. This removes the subscription and its delivery history.
webhook_idYesThe subscription id — `whk-` and sixteen hex characters.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint and idempotentHint, but the description adds real context beyond them: the cascade to delivery history including pending records, that no further deliveries occur, that the action is irreversible, and that re-subscribing to the same url yields a new id and secret. That is exactly the behavioral detail an agent needs before an irreversible call.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences, each earning its place: what is destroyed, what the endpoint observes, and the safer alternative. The irreversible warning is front-loaded before the alternative, so an agent reads the risk before the escape hatch.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter destructive tool with no output schema, the description covers everything needed to call it correctly and safely: scope of deletion, irreversibility, and the alternative. Nothing material is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and both params (webhook_id, confirm) are documented in the schema with format hints and the const:true constraint. The description adds no syntax or format detail beyond what the schema provides, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Remove) and resource (subscription) and immediately scopes it to include every delivery record, pending ones included. An agent can distinguish it from update_webhook, get_webhook, and rotate_webhook_secret without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly names the alternative path: 'To stop deliveries without losing the record, update_webhook with enabled: false instead.' That gives both the when-not condition and the sibling to use instead, which is the strongest possible guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_workspaceDelete a workspaceA
DestructiveIdempotent
Inspect

Permanently delete a workspace. It REVOKES every API key confined to it, whoever holds it, in the same step: anything using one of those keys — a person's CI, another agent — is refused from its next request, and this cannot be undone. The answer says how many were revoked. Webhook subscriptions confined to the workspace (those created with a key scoped to it) are deleted with it in the same step, with every delivery record they hold, pending ones included, as delete_webhook does; the answer does not count them, and account-wide subscriptions are not affected. Only an empty workspace can be deleted: one that still holds computers (counting one an unfinished workspace change is moving into it) or active secrets is refused with 409, saying how many, and nothing is deleted or revoked. To empty it, move its computers to another workspace with move_computer_to_workspace (or in the dashboard) or delete them, and delete its secrets with delete_secret, giving their workspace_id and current revision_id; then send this again. Say what is in it before moving or deleting anything to empty it. A 503 means the platform could not confirm it is empty: nothing was deleted, and it can be sent again shortly. Snapshots taken in it remain, and an account-wide key can still clone them. Needs confirm: true. Needs an owner's key that is not confined to a workspace: a member, a viewer, or any key confined to a workspace is refused with 403 — relay that rather than retrying.

NameRequiredDescriptionDefault
confirmYesMust be true. Every API key confined to this workspace is revoked with it.
workspace_idYesThe workspace id (wsp-…), from list_workspaces or a computer's workspace_id.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructive=true and idempotent=true, but the description goes far beyond them: it reveals that all confined API keys are revoked in the same step, confined webhook subscriptions and their delivery records are deleted uncounted, snapshots remain, and specific 409/503/403 conditions are explained. This is exceptionally rich behavioral context for a destructive tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core action and its irreversible side effects before moving into preconditions, alternatives, and error codes. It is long, but for a destructive tool with many caveats the length is largely earned; minor tightening could remove repeated phrases like 'in the same step'.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the destructive nature, two required params, lack of an output schema, and complex side effects, the description covers all the essentials: what is deleted, what is revoked, what remains, required auth, refusal conditions, and retry guidance. Nothing an agent needs to call this safely is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both parameters are already documented. The description adds only a restatement that confirm must be true and that revocation occurs, which duplicates the schema's own confirm description rather than adding new syntax or format guidance.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: permanently delete a workspace. It immediately distinguishes this from sibling tools by spelling out the cascading revocation of API keys and deletion of confined webhook subscriptions, which no other sibling does.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states the precondition (workspace must be empty) and the exact alternatives for emptying it: move_computer_to_workspace or delete_computer plus delete_secret. It also names when not to retry (403) and when the request can be safely retried (503), leaving no routing ambiguity.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

dragDragAInspect

Press, move and release as one gesture — for selecting text, moving a file, or dragging a slider. Not the same as two clicks. modifiers holds keys down for the whole gesture, e.g. ["shift"] to extend a selection.

NameRequiredDescriptionDefault
to_xYes
to_yYes
from_xNoWhere to start. Both from_x and from_y, or neither — half of an origin is refused rather than ignored.
from_yNo
contextNoAnswer the desktop's windows, and which one has focus, as they stand just after the action — what list_windows would say, without a second call — and, when the focused window is Chromium, the page on screen: its URL, title and the interactive elements visible in it, each with the point to click. Read at once, so a window still opening may not be listed yet. If they cannot be read the action still happened, and the answer says why.
modifiersNoKeys held down for the duration of the action.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full disclosure burden; it does add real value by explaining the atomic press-move-release semantics and that modifiers stay held for the whole gesture. But it says nothing about what the drag does to the target desktop, whether it can trigger destructive actions, timing/interpolation, or how failures surface.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with the core gesture and followed by the disambiguation and the one non-obvious parameter. The 'not the same as two clicks' line earns its place as a routing cue.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 7-parameter, annotation-free interaction tool with no output schema, the description leaves notable gaps: the context parameter (which returns windows and Chromium page contents after the action) is completely unmentioned, and coordinate/origin semantics are left entirely to the schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 57%, so several parameters rely on schema text alone. The description usefully illustrates the modifiers parameter with a concrete shift-to-extend-selection example, but says nothing about to_x/to_y, the from_x/from_y origin pairing, or the context flag.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific compound action (press, move, release as one gesture) and lists concrete outcomes — selecting text, moving a file, dragging a slider. It also explicitly distinguishes itself from the sibling click by saying it is 'not the same as two clicks.'

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The use cases given (text selection, file move, slider) make it clear when a drag is the right verb, and the negative contrast with double-clicking rules out one misreading. It stops short of naming click, move_mouse, or mouse_button as the alternatives for simpler pointer actions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

execRun a command in the guestAInspect

Run a shell command inside the computer. Runs as root with no display by default — anything that opens a window needs desktop: true, anything slower than a few seconds needs background: true, and anything that needs an environment variable takes env rather than an assignment written into the command. Against the hosted platform, waiting here is capped at about two minutes by a proxy in front of it, not by timeout_s. One computer runs at most sixteen background commands at once: the seventeenth is refused rather than queued, and exec_kill on a pid you already hold is what makes room. What the command printed comes back as stdout and stderr when it is text, and as stdout_b64 and stderr_b64 — base64 of the exact bytes — when it is not, so a command that emits binary is never quietly turned into replacement characters.

NameRequiredDescriptionDefault
cwdNoAbsolute path to run in. If it does not exist the command does not run, and exit_code is 127.
envNoEnvironment for this command, as {NAME: "value"}. Use it instead of writing FOO=bar in front of the command: a prefix assignment is shell syntax, so a value holding a space, a quote, a newline or a $ has to be quoted correctly by you and is silently truncated or re-parsed when it is not, while this reaches the process whole and unquoted. It also keeps a secret out of the command line, which is world-readable in the guest's ps and, for a background command, comes back to you inside every exec_poll answer. The variables are added on top of the guest's login profile rather than replacing it, so PATH and the rest are still there, and they apply to this command only — including with desktop: true. Names must not be empty or contain "=". At most 64 entries, each at most 4096 bytes counted as NAME=value in UTF-8; past either nothing runs.
commandYesA shell command line.
desktopNoRun inside the logged-in desktop session instead of as root with no display. Required for anything with a window: the guest agent has no DISPLAY, so a GUI app started without this cannot draw. Not needed for secrets bound as environment variables (set_computer_secrets): on an image that supports it, every exec, plain or desktop, runs with the bound variables as they are at that moment. Linux only.
timeout_sNoHow long to wait for it to exit, up to the server limit of 600 seconds. A command that outlives this keeps running inside the guest — your deadline passing means you stopped waiting, not that the work was destroyed. Against the hosted app.mandala.computer, do not reach past about 120 here: a proxy in front of the platform abandons the request at roughly two minutes and answers 524 whatever this says, so a larger number buys no time and only delays the failure. Use background: true for anything slower. The range above 120 is for a self-hosted MANDALA_BASE_URL reached without that proxy.
backgroundNoReturn a handle immediately instead of waiting. Use for builds, installs, test suites and servers, then read output with exec_poll. To learn that it finished, wait_for_event with types ["process.exited"] and the pid this returns — the computer reports the exit, so waiting for it costs one call rather than an exec_poll loop. Strictly better than backgrounding with "&", which throws away the exit code and the output. A computer runs at most sixteen of these at once, and past that this is refused with a 409 saying how many are already running rather than queued. A slot is held until its command exits, which for a server is never, so the way out of that refusal is exec_kill on a pid an earlier exec returned — not another attempt.
computer_idNoWhich computer. Defaults to the one selected with use_computer.
retain_outputNoExplicit synchronous output retention only. False/absent preserves default behavior. A valid result_id confirms a retained version; optional failure never replays the command.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does: it discloses running as root with no display by default, the ~2-minute proxy cap against hosted platform (independent of timeout_s), the 16-concurrent-background-command limit with a 409 refusal rather than queueing, and that a timeout only stops waiting, not the work. It also explains output encoding (stdout/stderr vs base64 byte streams).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core action, then layers on behavior in a single dense paragraph where nearly every clause carries specific information. It is long but nearly all content earns its place; a modest structural improvement (splitting the behavioral caveats) would help readability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 8 parameters, nested env object, no output schema, and no annotations, the description covers execution context, limits, timeout semantics, and return format. Nothing an agent needs to call it correctly and interpret results is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the per-parameter descriptions already document env, desktop, timeout_s, background, cwd, and retain_output in depth. The description reinforces usage (env vs assignment, background for slow work) but adds little parameter meaning beyond what the schema already provides, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Run a shell command inside the computer'), and the surrounding text distinguishes it from exec_poll, exec_kill, and wait_for_event by role. An agent can immediately tell this is the command-execution entry point versus the polling/killing siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes conditions to mechanisms: window-opening needs desktop:true, slow work needs background:true, environment variables go in env rather than prefix assignment, and freeing a background slot uses exec_kill on a held pid. It names the alternatives (exec_poll, wait_for_event, exec_kill) and the situations that select them.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

exec_killStop a background commandA
Destructive
Inspect

Kill a backgrounded command and everything it started. Answers with its final state, including whatever it printed that you had not read. Also how you make room when a computer is already running its maximum of sixteen background commands: the slot comes back with the command. A command that was already running when the service on the computer’s host restarted cannot be stopped here while it runs — that is refused, and sending it again does not help — so stop it from inside the computer with exec.

NameRequiredDescriptionDefault
pidYesThe positive, safe-integer pid exec returned.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructiveHint=true, so the mutation risk is known. The description does add real context beyond that: the whole process tree dies, the result includes unread output, and the slot is reclaimed. However, it doesn't say whether termination is graceful vs SIGKILL or what happens to output already retained, so it adds useful but not rich behavioral detail against an annotation that already flags destruction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded in the first clause, and every subsequent sentence carries operational value (return content, slot reclamation, refusal case). The third sentence is long and heavily em-dashed, which costs some readability but does not contain waste.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With only two fully-described parameters, no output schema, and destructiveHint already set, the description covers what an agent still needs: what is destroyed (the whole tree), what comes back (final state plus unread output), the capacity side effect, and the one failure mode that cannot be worked around by retrying.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so both pid and computer_id (including its default to use_computer) are fully documented in the schema. The description adds no pid format or computer_id semantics beyond that, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: kill a backgrounded command and its entire process tree. It also distinguishes itself from the read-side siblings (exec_poll, read_execution_output) by saying it returns the final state rather than polling, so an agent can pick it without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives three concrete usage conditions: terminate a running background command, free a slot when the 16-command cap is hit, and the explicit exclusion for commands that predate a host restart, with the alternative named ('stop it from inside the computer with exec'). It even warns that retrying the call will not help.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

exec_pollRead a background commandAInspect

What a backgrounded command has printed since the last time you asked, and whether it has finished. The output is a cursor, not a buffer: each poll gives you only the new bytes, so two readers on one pid split the output between them rather than each seeing all of it. Finishing is also what releases a computer's background slot, so this is how you tell which of your handles still hold one — the poll itself frees nothing. Output comes back as stdout and stderr when it is text and as stdout_b64 and stderr_b64 when it is not; a chunk cut through the middle of a character keeps both halves, with the text stopping at the last whole one and a note naming the bytes the next poll begins with. A command that was already running when the service on the computer's host restarted still answers whether it is running and its exit code, but never its output: both streams stay empty and output_unavailable says why. Its command is then the platform's kept copy, only the first 1 KiB at most, and command_truncated: true says it was cut. Shortly after such a restart a poll can be refused as worth sending again; a refusal that does not say so is not worth sending again at once: for such a command it means the guest agent has not confirmed its state for five minutes, and a later poll answers again once the agent does or the command exits.

NameRequiredDescriptionDefault
pidYesThe positive, safe-integer pid exec returned.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description is exceptionally thorough regarding technical behavior that goes far beyond simple function description, including output streaming (cursor vs. buffer), output splitting between two readers, restart failure modes, and waiting periods after agent refusal.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness2/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is excessively long and extremely technical. It reads more like internal developer documentation detailing OS behavior than a concise explanation meant to guide an AI agent quickly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity of background process monitoring (handling restarts, truncation, and stream splitting), the description is highly complete, providing nearly every edge case an agent might encounter.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Since the schema coverage is 100%, the baseline score of 3 is maintained. The description does not add any clarifying constraints or meaning to the 'pid' or 'computer_id' fields that are not already defined in the structured schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly identifies the function: reading printed output and status of a backgrounded command using a PID. It is highly specific about what the tool reveals.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The usage is implied—it is used to check the status and output of an existing background process. However, it fails to suggest when to use this tool versus other siblings like `read_result_output` or when the background command should be terminated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_accountRead current account quotaA
Read-onlyIdempotent
Inspect

Read account-wide plan ceilings, per-computer maxima, current consumption and advisory remaining quota. Viewer or stronger; workspace-scoped keys receive aggregates without resource identities. No arguments, selected computer or model key. Incomplete computer/snapshot groups have null consumption and remaining values, meaning unknown. Snapshot headroom covers indexed stored bytes, excludes in-flight capture reservations and cannot promise that a capture will fit. This observation reserves nothing; later mutations still enforce quota.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare read-only/idempotent/non-destructive; the description goes well beyond them by disclosing null-means-unknown semantics for incomplete computer/snapshot groups, what snapshot headroom does and does not cover (indexed stored bytes, excludes in-flight reservations, no fit guarantee), and that the observation reserves nothing while later mutations still enforce quota.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose, then progressively finer caveats; every sentence carries distinct information for a quota read. It is dense and occasionally terse ('selected computer or model key', 'meaning unknown'), but nothing is redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, yet the description enumerates the returned quantities (ceilings, maxima, consumption, remaining), explains null handling, and flags the advisory nature of the remaining figure. An agent knows both what it will get and how to interpret it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With zero parameters, the baseline is 4. The description usefully reinforces the no-argument contract and notes that the selected computer or model key is irrelevant to the result, which is meaningful context for an agent that may assume ambient selection applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource with scope: 'Read account-wide plan ceilings, per-computer maxima, current consumption and advisory remaining quota.' That is far more precise than the title. It does not, however, explicitly differentiate from the close siblings get_usage and get_credits, so an agent must infer the boundary.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives access conditions ('Viewer or stronger', workspace-scoped keys get aggregates without resource identities) and clarifies it takes no arguments and ignores selected computer/model context, which is genuine usage context. But it never states when to prefer this over get_usage or get_credits, so the alternative-selection guidance is only implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_activityRead one activity recordB
Read-onlyIdempotent
Inspect

Selected, retained, best-effort request history; not all guest work or an agent identity. Accepted background work is not completed execution; a dispatched error may have had effects. Activity IDs identify requests, never idempotency keys.

NameRequiredDescriptionDefault
activity_idYes
computer_idNoComputer, or the current use_computer selection.

TDQS

B3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint and destructiveHint=false, but the description adds genuine semantics beyond them: the history is 'best-effort', 'accepted background work is not completed execution', and 'a dispatched error may have had effects'. These are important interpretive caveats for trusting the returned record. It stops short of describing freshness windows or pagination, keeping it from a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three compact semicolon-delimited clauses, each carrying content with little waste. However it is not front-loaded with what the tool does — the opening clause is a caveat about the data's reliability rather than the action, so a reader must reach the title to orient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description reasonably covers what a returned record does and does not represent. But it omits entirely how the fetched record is used relative to list_activities/get_activity_results, leaving a routing gap for a tool that has obvious siblings.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 50% (activity_id undocumented, computer_id documented), so the description should carry some load. It indirectly touches activity_id semantics by noting IDs 'identify requests, never idempotency keys', but supplies no format or usage detail to compensate for the untagged required parameter. Baseline 3 is appropriate given partial schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description characterizes the resource ('selected, retained, best-effort request history') but never states a verb, relying on the title 'Read one activity record' for the action. It does not distinguish this single-record fetch from siblings list_activities or get_activity_results, leaving the agent to infer the difference. Purpose is recoverable but not stated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no guidance on when to use this tool versus list_activities or get_activity_results, and no prerequisites or conditions are given. The caveats describe how to interpret a record once fetched, not when to fetch it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_activity_resultsRead passive result links for an activityB
Read-onlyIdempotent
Inspect

Metadata only: at most eight newest links. more has no cursor and does not mean all versions were returned. No content reads, guest files, captures, execution polling or downloads. An unavailable link is not empty content. Caller-selected artifact association does not prove creation or command success.

NameRequiredDescriptionDefault
activity_idYes
computer_idNoComputer, or the current use_computer selection.

TDQS

B3.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish read-only, idempotent, non-destructive semantics, so the bar is lower, and the description adds substantive behavior the annotations cannot: an eight-link cap, that "more" has no cursor and does not imply completeness, that an unavailable link is not empty content, and that artifact association does not prove command success. These are exactly the non-obvious traits that prevent misreads of results.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Roughly forty words with the cardinality cap front-loaded, and each following clause is a distinct caveat rather than filler. The clipped, telegraphic sentences ("Metadata only:") cost some readability, but nothing reads as padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the burden of explaining the return shape, and it partially does: link count cap, the semantics of "more", and the meaning of unavailable links. It omits what a returned link actually points to or which sibling consumes it, leaving a gap for a tool whose only purpose is handing back links.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 50%: computer_id is documented (including the use_computer fallback) while the required activity_id carries only a pattern and no prose. The description says nothing about either parameter, so it does not compensate for the undocumented required parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

"Metadata only: at most eight newest links" implies a read of result links for an activity, but the description never states the core action in a subject+verb+resource form the way the title does. It is not a tautology, yet an agent must infer from the title and the caveat list what the tool actually returns, and it is not clearly separated from siblings like get_result or read_result_output.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives real when-not-to-use guidance (no content reads, guest files, captures, execution polling or downloads), which is genuinely useful routing information. However it never names the alternative tools an agent should call instead for those cases, so the selection guidance is implied rather than actionable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_agent_runRead a background agent runA
Read-onlyIdempotent
Inspect

A background agent run as it stands: its status, every step so far, its cost on AI credits, and once it has ended, how. Poll it every few seconds while its status is running; a step takes at least that long, so polling faster only spends rate budget. Only status completed with stop end_turn means the task was finished. completed with any other stop (time_limit, max_steps, max_cost, credits_exhausted, rate_limited, refusal, …) stopped without finishing; failed carries the error that ended it; cancelled was stopped by cancel_agent_run; interrupted means the platform restarted while it was going, or its ending was not recorded, and it was not resumed — it MAY HAVE DONE MORE THAN IT RECORDED. Whatever the ending, the steps a run took stand: take a screenshot before deciding what is left, and continue with its thread_id rather than running the whole task again. A run this key cannot see is not found.

NameRequiredDescriptionDefault
run_idYesThe run_id start_agent_run or list_agent_runs answered: run_ and 24 hex characters.

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover read-only/idempotent/non-destructive, but the description adds substantial beyond-schema semantics: the full stop-reason taxonomy, the meaning of interrupted (MAY HAVE DONE MORE THAN IT RECORDED), and that a run outside this key's scope reads as not found. These are the kind of behavioral subtleties annotations cannot express.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with what is returned, then polling cadence, then the stop-reason interpretation. Dense but every sentence carries distinct information. The lengthy parenthetical of stop reasons is slightly heavy but earns its place given no output schema exists to enumerate them.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema and one required parameter, the description carries the full burden of describing the return shape and does so thoroughly (status, steps, cost, ending taxonomy) plus failure/interruption semantics. Nothing an agent needs to call and interpret this tool is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the run_id format is already documented. The description adds a scoping rule not present in the schema — 'a run this key cannot see is not found' — clarifying a permission-based not-found case, which meaningfully extends parameter semantics beyond the pattern regex.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names the specific resource (a background agent run) and enumerates exactly what the read returns: status, steps so far, cost in AI credits, and ending. Combined with the title 'Read a background agent run' and the existence of siblings like list_agent_runs and get_agent_thread, an agent can tell immediately which tool fetches a single run's state.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit operational guidance: poll every few seconds while status is running, and specifically warns that faster polling only spends rate budget. It also routes follow-up behavior ('continue with its thread_id rather than running the whole task again') and names cancel_agent_run as the cause of cancelled status.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_agent_threadRead a kept agent conversationA
Read-onlyIdempotent
Inspect

One kept conversation, oldest turn first: each user turn is a prompt, and each assistant turn is how that run answered — its closing text, how it ended, its steps, and its cost on AI credits. Read it to see what earlier runs on a computer were asked and did before continuing it with thread_id. An answer holds the newest turns that fit in about 48,000 characters; when earlier turns did not fit it says so, and before_turn reads the ones before. Only an assistant turn that ended end_turn finished its task. One that is running (its run is still going), aborted (stopped part way) or interrupted (the platform restarted mid-run) MAY HAVE DONE MORE THAN IT REPORTED: look at the desktop before relying on it. A thread this key cannot see is not found.

NameRequiredDescriptionDefault
thread_idYesThe thread: thr_ and 24 hex characters, from an agent run or list_agent_threads.
before_turnNoOnly turns numbered below this one, for the turns an earlier answer said did not fit. Leave it out for the newest turns.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the readOnly/idempotent annotations: discloses the ~48,000 character window, that truncation is announced and recoverable via before_turn, the meaning of end_turn vs running/aborted/interrupted, and the warning that non-terminal runs MAY HAVE DONE MORE THAN REPORTED. It also documents the not-found behavior for threads outside the caller's key, which no annotation covers.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with what is returned and ordered by importance, and every clause (turn shape, pagination, status caution, not-found) carries information. It is dense and long-ish for a two-parameter read tool, and the all-caps warning, while justified, adds bulk.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries return-value explanation and does so fully: record shape, ordering, pagination fallback, status semantics and failure mode. An agent could call this correctly and interpret truncated or in-progress results without any other source.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 100%, so the baseline is 3. The description earns the extra point by explaining the interaction between the two parameters: before_turn exists precisely for turns an earlier answer said did not fit, which tells the agent how to chain calls rather than just what the field holds.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('One kept conversation, oldest turn first') and immediately spells out the shape of the record: user prompts and assistant answers with closing text, ending status, steps and credit cost. It also positions the tool against the list/run siblings by saying it is what you read 'before continuing it with thread_id'.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Read it to see what earlier runs on a computer were asked and did before continuing it with thread_id' gives a concrete use context and the follow-on action. It stops short of naming an explicit alternative (e.g. list_agent_threads to discover an id) or stating when not to call it, so it is clear context rather than full when/when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_artifactRead immutable artifact metadataC
Read-onlyIdempotent
Inspect

Passive finite metadata for one retained artifact. No guest file or execution lookup, resume, capture or fallback.

NameRequiredDescriptionDefault
artifact_idYes
computer_idNoComputer, or the current use_computer selection.

TDQS

C2.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint and destructiveHint=false, so safety is covered. The description adds only the vague notion of 'passive finite' metadata (implying a bounded, non-streaming response), which is useful but underspecified, and says nothing about auth or scoping beyond the excluded operations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tightly packed sentences with no filler, and the core capability is front-loaded before the exclusions. The terseness drifts into jargon ('passive finite metadata'), but there is no wasted structure.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple two-parameter read with no output schema, the description conveys the scope but omits what the returned metadata actually contains and how computer_id interacts with the current use_computer selection. Annotations carry the safety profile, so this is adequate but not complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 50%: computer_id has a description, but artifact_id (the sole required parameter, with a strict '^art_[a-f0-9]{32}$' pattern) has none. The description contributes nothing about either parameter, so it fails to compensate for the coverage gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description is a noun phrase ('Passive finite metadata for one retained artifact') rather than a verb+resource statement, though the title supplies 'Read immutable artifact metadata'. The negation list scopes it away from read_artifact/read_execution_output, but it never names those siblings, so differentiation is only implied.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It lists excluded capabilities ('No guest file or execution lookup, resume, capture or fallback') but does not name the alternative tool an agent should use for any of them, nor state when this tool is the right choice. Exclusions without named alternatives leave the agent to infer routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_buildGet a buildA
Read-only
Inspect

What became of one build, which template it was for, and which step it is on. Reads once and returns; watch_build is what follows a running one. It stays readable after the build has finished, so this is also how you find out which step failed on a build nobody was watching. Needs an account-wide key: a key confined to a workspace is refused (403).

NameRequiredDescriptionDefault
build_idYesThe id build_template returned.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare readOnlyHint=true. The description adds substantial context beyond this: it reads once and returns (no streaming), remains readable after the build finishes, and critically requires an account-wide key with a 403 refusal for workspace-scoped keys. This auth requirement is vital behavioral disclosure not in the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with what the tool returns, then contrasts with watch_build, then explains the post-completion use case, then gives the auth requirement. Dense but every sentence earns its place. Slightly long but no waste.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Complete for a single-param read tool. Covers what it returns, when to use it vs. the sibling, behavior on finished builds, and the auth prerequisite. No output schema exists, but the description explains the return sufficiently ('what became of one build, which template, which step').

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with build_id documented as 'The id build_template returned'. The description adds no parameter-specific detail beyond the schema baseline, which is appropriate for a single-param tool.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (get) and resource (one build), and clarifies scope with 'which template it was for, and which step it is on'. Explicitly distinguishes from sibling watch_build ('watch_build is what follows a running one').

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Names the alternative watch_build and the condition that selects it (running build vs. reading a finished one). Also clarifies a specific use case: finding out which step failed on an unwatched build.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_computerGet a computerB
Read-only
Inspect

Everything the platform knows about one computer: status, size and its recorded screen resolution. Click coordinates are the capture size a screenshot returns, which can differ from the record's resolution.

NameRequiredDescriptionDefault
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

B3.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

readOnlyHint=true already establishes the safe-read profile, so the burden is lighter. The description adds genuine context by listing the returned fields and warning that click coordinates are the capture size, not the record's resolution. It does not, however, cover auth/permission needs or any field the agent might need beyond status, size, and resolution.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the return summary followed by the coordinate caveat. Both earn their place, though the coordinate note leans toward a different tool's parameter semantics.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, yet the description enumerates the key returned fields, which is the right compensation. For a single-parameter read tool with a readOnlyHint, this is close to complete, missing only guidance on when to prefer it over use_computer.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the schema already explains that computer_id defaults to the one selected with use_computer. The description adds nothing about the parameter, so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource and enumerates what is returned (status, size, recorded screen resolution). The singular 'one computer' implicitly separates it from list_computers, but no sibling is named for explicit differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives no when-to-use guidance, no mention of the alternative use_computer (which the parameter schema references) or list_computers. The agent must infer that this is the single-record read path from the name alone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_computer_secretsRead a computer's secret bindingsA
Read-only
Inspect

Which of the account's secrets a computer is bound to: for each, the secret id, the revision last delivered, and where the guest finds it — an environment variable name, or a file under /run/mandala-secrets/user/files. Values are NEVER shown — no value crosses this route. Also answers version, the number to send to set_computer_secrets so it changes only this list (0 for a computer never bound). Any role may read it. The list is what the computer receives at its next start or restart, which a running computer may not have yet. Every start and restart delivers each secret's latest value. Separately, when a secret's value is replaced on a running computer: a secret bound as a FILE has that file rewritten in place within seconds; one bound as an ENVIRONMENT VARIABLE, on an image that supports it, reaches new shells within seconds, and every exec — plain or with desktop: true — runs with the bound variables as they are at that moment, so the next exec sees the new value; programs already running — the desktop session among them — keep the value they started with until a restart (older images wait for the restart). A file newly bound or renamed waits for the restart either way.

NameRequiredDescriptionDefault
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond readOnlyHint=true, it discloses that values are NEVER returned, that the list reflects next start/restart and a running computer may be stale, and detailed propagation behavior (file rewrite in place; env vars in new shells/execs; running processes and renamed files wait for restart). This is exactly the extra behavioral context annotations cannot carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The return-contents portion is well front-loaded, but the second half is a dense multi-clause paragraph on delivery timing that is tangential to invoking a read tool. It is informative yet longer than needed and could be trimmed without harming selection or invocation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description fully specifies what is returned and explicitly what is not (values). For a one-parameter read tool it leaves no gap an agent would need to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single parameter is fully documented in the schema (computer_id with its use_computer default), so coverage is 100%. The description adds no additional parameter semantics, which is the expected baseline when the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb+resource (which secrets a computer is bound to) and enumerates the exact fields returned (secret id, revision last delivered, location). It distinguishes itself from siblings like list_secrets/get_secret by stressing that no values cross the route, and from set_computer_secrets by explaining the version number.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states who may call it (any role), what the list represents (what the computer receives at next start/restart), and ties directly to set_computer_secrets via the version token. It stops short of an explicit 'use this rather than list_secrets when...' routing statement, so it is clear context without full exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_computer_sshRead whether SSH is on for a computerA
Read-only
Inspect

Whether SSH is switched on for a computer, whether that computer can run SSH at all (one made from an older template image cannot), how many keys can log in, whether its hypervisor has the current setting yet, and whether that hypervisor refused the setting (it is not sent again until a key or the setting changes). Any role may read it.

NameRequiredDescriptionDefault
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare readOnlyHint=true; the description goes well beyond by disclosing non-obvious behavior: older template images cannot run SSH at all, the hypervisor setting may lag behind, and a refused setting is not re-sent until a key or the setting changes. It also states the access requirement (any role). This is exactly the kind of context annotations cannot carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One dense enumerative sentence followed by a short permission note; the primary question (is SSH on) is front-loaded. The long clause chain is information-packed rather than padded, though it could be broken into shorter sentences for scannability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the full burden of explaining return values, and it does so thoroughly, covering the non-obvious states (unsupported image, hypervisor lag, refused setting). Nothing an agent needs to interpret the result is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single parameter has 100% schema description coverage, including the default-to-use_computer behavior, so the schema already does the work and baseline 3 applies. The description adds nothing about computer_id syntax or scoping.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific read operation on a specific resource and enumerates exactly what is read: SSH enabled state, template-image capability, key count, hypervisor sync state, and refusal state. It is trivially distinguishable from set_computer_ssh and list_ssh_keys, which appear as siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage through its read-only framing and explicitly notes 'Any role may read it,' which is useful permission context. However, it never names alternatives (set_computer_ssh, list_ssh_keys) or states when an agent should call this versus those, so the routing guidance is only implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_creditsRead AI creditsA
Read-onlyIdempotent
Inspect

This account's Mandala AI credits, which pay for run_agent when no model key is configured: available (balance minus debt and credits held for runs in progress; can be negative, and zero while frozen), balance, held, debt, frozen (no plan or a suspended account: credits are kept and still expire, but cannot be spent), this billing period's plan grant, the unexpired lots, and the journal, newest first. Amounts are integer USD micros (1,000,000 = $1). A key confined to a workspace is refused (403): the ledger is the whole account's.

NameRequiredDescriptionDefault
limitNoJournal entries per page, 1 to 100; the platform defaults to 50.
beforeNoOlder journal entries: the next_before of the page before.

TDQS

A4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive, yet the description goes well beyond them: it discloses the 403 refusal for workspace-confined keys and that the ledger is account-wide, defines frozen/negative 'available' semantics, and explains that frozen credits are kept, still expire, and cannot be spent. That is genuine behavioral context an agent could not get from the structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core resource and then structured around the returned fields; with no output schema the field enumeration earns its place. It is somewhat dense in a single long clause-chain, but no sentence is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the return-value burden and does so thoroughly (available/balance/held/debt/frozen/grant/lots/journal), plus units in integer USD micros and the auth constraint. An agent has everything needed to call and interpret it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so limit and before are already fully documented in the schema, establishing a baseline of 3. The description adds only tangential meaning ('the journal, newest first'), which implies the before-pagination cursor direction but does not restate or extend the parameters themselves.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific resource (this account's Mandala AI credits) and even explains what those credits are for (paying for run_agent when no model key is configured), so the agent knows exactly what it is reading. It does not explicitly distinguish itself from the closest siblings (get_usage, get_account), which is the only thing keeping it from a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied — the agent can infer this is the tool to consult for credit/balance state, and the mention of run_agent and unconfigured model keys hints at the relevant context. But there is no explicit 'use this when / use get_usage instead when' guidance or exclusion, leaving routing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_desktop_urlGet a link to watch the desktopA
Idempotent
Inspect

A URL that opens this computer's live desktop in a browser. Watch-only by default. These are credentials in a link: anyone holding one has that desktop until the computer restarts or is moved to another workspace, either of which issues new desktop credentials.

NameRequiredDescriptionDefault
controlNoReturn the full-control URL instead of the watch-only one. It carries a token that is root-equivalent on that machine — the watch-only socket has input dropped by the platform, not merely hidden by the client.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A3.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the idempotentHint and destructiveHint annotations, the description discloses a non-obvious and important trait: the URL is a bearer credential whose holder keeps access until restart or workspace move, at which point new credentials are issued. This lifecycle/security disclosure is exactly the value a description should add.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with what the tool returns, then the default mode, then the security caveat. It is efficient, though the opening noun phrase overlaps somewhat with the title.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema and two well-documented parameters, the description covers the essentials: what is returned, the default mode, and the credential lifetime. It omits any mention of the control option or whether links expire on a timer, which would round it out.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the control parameter is already documented in depth (root-equivalence, input dropping). The description only echoes the watch-only default and adds no syntax or format detail beyond the schema, so baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific resource and outcome: a URL that opens this computer's live desktop in a browser. It clearly conveys what the tool returns, and the watch-only default is stated. It does not, however, explicitly distinguish itself from URL-producing siblings like create_public_url or get_computer_ssh.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied — 'Watch-only by default' hints that full control is available, but the description never says when to prefer this tool over alternatives such as screenshot or create_public_url. No explicit when/when-not guidance is given; the schema carries the only routing information.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_executionRead a stable execution observationA
Read-onlyIdempotent
Inspect

Read one background execution by stable execution_id. Last-observed running, exited or lost; running is not proof the computer is awake, and lost establishes no success or failure. Metadata only: no guest I/O, activity refresh, resume, polling loop, PID fallback or command replay. Handles are volatile and can become unavailable after restart, replacement, expiry or cleanup. A command that was already running when the service on the computer’s host restarted keeps its execution_id and answers with output_unavailable (today "daemon_restarted"): its status and exit code are still reported, but its output cannot be read. For a few seconds after such a restart this read is refused with a 409 whose reason is contention, which is worth sending again; a 409 with no reason means the guest agent has not confirmed the command’s state for five minutes, which an immediate retry will not clear: check that the computer is healthy, and a later read answers again once the agent does or the command exits.

NameRequiredDescriptionDefault
computer_idNoComputer to read; defaults to use_computer selection.
execution_idYesStable execution_id returned by an accepted background exec; never a PID.

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive, yet the description still adds substantial behavior the agent could not otherwise know: 'running is not proof the computer is awake,' 'lost establishes no success or failure,' handle volatility after restart/replacement/expiry, and the `output_unavailable` / `daemon_restarted` semantics where status and exit code survive but output does not. The two distinct 409 cases and their differing retry policies are exactly the kind of failure-mode disclosure that prevents a wasted retry storm.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and the metadata-only boundary are front-loaded in the first two sentences, and every subsequent sentence carries real behavioral information. The final sentence is a long run-on bundling both 409 variants and would read better as two sentences, which costs a point.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema in play, the description does the work of explaining what the read returns: last-observed state (running/exited/lost), status, exit code, and the inability to read output after a daemon restart. The exact field set beyond those is not enumerated, but the semantic picture an agent needs to interpret a response is essentially complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both parameters already carry their own documentation (execution_id pattern and 'never a PID', computer_id defaulting to use_computer). The description reinforces the stability of execution_id across restarts but adds no new meaning for computer_id, so the baseline 3 is right.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Read one background execution by stable execution_id') and immediately bounds scope with 'Metadata only: no guest I/O, activity refresh, resume, polling loop, PID fallback or command replay,' which implicitly separates it from read_execution_output, exec_poll and get_result. It never names an actual sibling, so an agent must infer the routing rather than being told it.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear operational conditions: retry after a 409 with reason `contention`, do not retry a 409 with no reason, and check host health instead. The exclusions ('no polling loop', 'no command replay') imply exec_poll is the polling alternative, but no alternative tool is named explicitly, so the when-to-use-this-vs-sibling guidance stays implicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_file_uploadRead resumable upload statusA
Idempotent
Inspect

Read the confirmed offset and completion receipt before retrying an interrupted chunk. Missing uploads return 404. May resume the computer unless no_wake is set.

NameRequiredDescriptionDefault
pathYesAbsolute path inside the guest.
no_wakeNotrue: do not resume a computer that is not running — refuse instead (409), so nothing is resumed and no running capacity is consumed. Use it to look at a suspended computer’s files only if it is already awake. false (the default) resumes a suspended computer to answer, which consumes running capacity.
upload_idYesA fresh random 32-character lowercase hex ID; retain it to resume. Never reuse for different contents.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds important behavior beyond the annotations: missing uploads return 404, and the call may resume a computer unless no_wake is set. The side effect of waking a suspended computer is critical context that annotations alone (idempotentHint, destructiveHint) do not convey. It stops short of describing authentication or output format.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with the core purpose and key usage trigger. The 404 and no_wake caveats are compact and earn their place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description identifies the returned information as confirmed offset and completion receipt, which is enough for an agent to know what to expect. It also discloses the 404 case and wake behavior. A little more detail on the receipt structure could improve it, but it is largely complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all four parameters in detail. The description only briefly references no_wake in the context of computer resumption and does not add further parameter semantics beyond what the schema provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: reading the confirmed offset and completion receipt for an upload. It clearly distinguishes this from sibling tools like write_file_chunk and cancel_file_upload by focusing on status inspection, though it does not explicitly name those alternatives.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It tells the agent when to use the tool: before retrying an interrupted chunk. It also states that missing uploads return 404, giving useful context. However, it does not explicitly exclude cases or name sibling alternatives for status/cancel operations.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_operationRead a lifecycle operationA
Read-onlyIdempotent
Inspect

One lifecycle operation: what an accepted create, clone, start, stop, suspend, restart, snapshot restore, resize, move or delete started, and where it got to. A call made with an idempotency_key is recorded pending before it is carried out, so it can be found even when its answer was lost; one the platform never heard end is failed with error.code lost. state is pending or running while live, and succeeded or failed once final; a failed one carries error.code (start_failed, build_failed, computer_gone, move_failed, resize_not_applied, lost, and more may be added) and a sentence. Most are already succeeded when the call that started them answered; a clone is running until its disk is copied, and a move until it lands. succeeded means the platform finished its step, not that the desktop has booted: wait_for_computer is still the wait for a desktop that answers. An id this key cannot see — another account's, or for a key confined to a workspace, one about a computer outside it — or one that has expired, is not found.

NameRequiredDescriptionDefault
operation_idYesThe operation_id a lifecycle tool answered: a create, a clone, a start, stop, suspend or restart, a resize, a snapshot restore, or a move.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive, and the description adds substantial behavioral context: idempotency_key operations recorded pending, the special lost error.code, the full state machine (pending/running/succeeded/failed), and why succeeded does not mean the desktop has booted. It leaves some room (e.g. it never states retention duration or that reads are side-effect free beyond the annotation).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the tool's purpose and no filler sentences; most content (state transitions, error codes, not-found scoping) is non-redundant and useful. It is dense and somewhat run-on for a single-parameter read, with mild repetition around pending/succeeded states, keeping it short of a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the burden of explaining return values, and it does so thoroughly: state values, error.code enumeration, the pending/lost semantics, and not-found behavior. An agent has everything needed to interpret the response and handle failures.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% so the schema already documents operation_id, making 3 the baseline. The description goes beyond it by explaining which ids resolve and which do not (another account's id, ids outside a workspace-scoped key, expired ids), adding real semantic value about the parameter's acceptance.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("One lifecycle operation ... and where it got to") and enumerates the lifecycle actions it tracks, which distinguishes it from sibling list_operations and wait_for_operation. An agent immediately knows this fetches the status of a single operation by id.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear context for when this is the right call (recovering an operation whose answer was lost, checking where a create/clone/start landed) and differentiates it from wait_for_computer for desktop readiness. It does not explicitly contrast with the sibling wait_for_operation or list_operations, so the routing guidance is strong but incomplete.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_resultRead retained result metadataA
Read-onlyIdempotent
Inspect

Read one immutable result manifest without guest output/files, resume, capture or command replay. Expiry, current scope or storage availability can make a version unavailable.

NameRequiredDescriptionDefault
result_idYes
computer_idNoComputer, or the current use_computer selection.

TDQS

A3.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover readOnly/idempotent/non-destructive, and the description adds genuinely useful traits beyond them: the manifest is immutable, and a version can become unavailable due to expiry, current scope, or storage availability. That is real failure-mode disclosure. It stops short of saying whether an unavailable version errors or returns an empty/partial manifest.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two dense but well-formed sentences with no filler; the core scope statement is front-loaded and the caveats follow. The middle clause packs four exclusions into one run-on list, which costs a little readability for the compression gained.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only, two-parameter tool with no output schema, the description covers what is and isn't returned plus availability failure modes, which is most of what an agent needs. It omits any sense of the manifest's contents and the computer_id resolution rule, which are the remaining gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 50% — computer_id has a description but result_id carries only a pattern/length constraint — so the description is expected to compensate and does not. Neither the result_id format (res_ + 32 hex) nor the meaning of omitting computer_id (falling back to the use_computer selection) is mentioned in the description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Read one immutable result manifest") and sharply bounds it by listing what it does NOT include — guest output/files, resume, capture, command replay — which separates it from siblings like read_result_output and read_artifact. The term "result manifest" is somewhat internal jargon, so an agent still has to infer that this is metadata rather than the result payload itself.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The exclusion list implies the right context (use this when you want the manifest rather than the output), but the description never names read_result_output or delete_result as alternatives, nor states a positive trigger like "call this to check result status/expiry before fetching output". Usage is inferable rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_retentionRead how long automatic snapshots are keptA
Read-only
Inspect

The plan's retention window — the other half of snapshot_schedule, which says when snapshots are taken and deliberately has no field for how long they survive. Read it before promising anyone that a backup will still be there, and before taking a snapshot you mean to keep. Takes no arguments: the window belongs to the ACCOUNT, not to a computer, though each computer keeps its own set under it. ONLY AUTOMATIC SNAPSHOTS ARE AGED OUT — one you took yourself with create_snapshot is never removed automatically, which is how you keep something past the window.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare readOnlyHint=true, so safety is covered, and the description adds rich context beyond that: no arguments needed, the window belongs to the ACCOUNT rather than a computer, and only automatic snapshots are aged out while self-taken create_snapshot copies persist. This is exactly the behavioral detail an agent needs to avoid wrong assumptions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Key definition is front-loaded and each clause adds information, but it is quite dense with em-dashes and stacked caveats. It earns most of its length, though it could be tightened slightly without losing substance.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, so the description must imply the return value; it does so via 'retention window' without stating the unit or format explicitly. Given the tool's simplicity and the strong surrounding context, this is nearly complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Zero parameters, so the schema cannot mislead. The description usefully explains the scope of the implicit subject — the window is account-level, not per-computer — which is the only meaningful 'parameter-like' semantics here.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific resource and scope — 'The plan's retention window' — and explicitly distinguishes it from the sibling snapshot_schedule, even explaining that the schedule deliberately omits this field. An agent can tell immediately what this returns and how it differs from its nearest neighbor.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete conditions for use: 'before promising anyone that a backup will still be there, and before taking a snapshot you mean to keep.' It also frames it as the counterpart to snapshot_schedule, routing the agent between the two tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_secretRead one secretA
Read-only
Inspect

One secret's name, scope, current revision_id and when it was last delivered — never its value. Read it for the current revision_id after replace_secret or delete_secret is refused because the revision moved. A secret in a workspace is found only with its workspace_id; otherwise it is not found.

NameRequiredDescriptionDefault
secret_idYesThe secret — `csec-` and sixteen hex characters, from list_secrets.
workspace_idNoThe workspace the secret belongs to. Leave it out for an account-wide secret. A secret in a workspace is found only with its workspace_id.

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only say readOnlyHint=true; the description adds that the secret value is never returned and that workspace-scoped secrets are only found with workspace_id. That is useful context beyond the annotation, though it doesn't cover rate limits or error formats.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three compact sentences, front-loaded with what is returned and the value exclusion. The revision_moved trigger is slightly dense but earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter read tool with full schema coverage and a readOnly annotation, the description covers purpose, return shape, and the workspace scoping caveat. It is close to complete, missing only error/pagination behavior.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so both parameters are already documented in the schema. The description restates the workspace_id rule but adds no syntax or format details beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a precise verb and resource ('One secret's name, scope, current revision_id and when it was last delivered') and explicitly excludes the value, distinguishing it from list_secrets and the mutation siblings.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It names conditions for use — read after replace_secret or delete_secret is refused because the revision moved — and states the workspace_id requirement. No explicit when-not guidance, but the trigger condition is concrete.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_templateRead a template documentA
Read-only
Inspect

One template as the document it was written as — the lineage, the build steps and the digest, which list_templates drops. Works for your own namespace and for system, so you can read what you are layering onto before writing a document of your own. Without version this is the newest, which is also what a create naming the unpinned namespace/name resolves to. Your account's own namespace needs an account-wide key: a key confined to a workspace is refused (403) there, because the document is the account's and may carry its build steps and scripts; it can still read system templates.

NameRequiredDescriptionDefault
nameYesThe template name, without the namespace or the version.
versionNoA specific MAJOR.MINOR.PATCH. Send it or omit it entirely — an empty string is refused, because omitting it does not mean the same thing on both tools.
namespaceYesThe account id the template is published under. READ IT OFF A `ref`: every row of list_templates carries one shaped `<namespace>/<name>@<version>`, and the part before the slash is the namespace. Rows reading `system` are the templates we publish; anything else is your own account id. There is no separate `namespace` field on a template — the ref is where it lives.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare readOnlyHint=true; the description goes well beyond that by disclosing that the account's own namespace requires an account-wide key, that a workspace-confined key is refused with a 403, and that such a key can still read `system` templates. It also explains the default-version resolution behavior, which is real operational context absent from structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core purpose followed by scope, default-version behavior, and auth caveat in a tight sequence. It is dense rather than padded, though the multi-clause sentences require careful reading.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema, so the description must carry the burden, and it does: it frames the return shape, the namespace/version resolution rules, and the exact auth failure mode. An agent has everything needed to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds genuine semantic meaning on top: omitting `version` resolves to newest (and to what an unpinned create would resolve to), and an empty string is refused. This exceeds what the schema conveys, warranting above baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('One template as the document it was written as') and enumerates the payload it uniquely returns — lineage, build steps, digest — while explicitly contrasting with the sibling that omits them ('which list_templates drops'). An agent can distinguish this from list_templates purely from the text.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear context for when to reach for it ('read what you are layering onto before writing a document of your own') and covers both namespaces it serves. It does not explicitly route away from get_template_schema or name an exclusion, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_template_schemaGet the template document schemaA
Read-only
Inspect

The JSON Schema for a mandala/v1 template document — the declarative form a template is written in. Read this before writing one: it describes the ref, the image family, what the template is layered onto, and the shape a computer gets when a create names no numbers.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

readOnlyHint=true already tells the agent this is a safe read; the description goes further by characterizing the returned content (the ref, the image family, what a template is layered onto, and the default virtual-machine shape). It does not mention caching or size of the schema, but adds meaningful value beyond the annotation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One dense, front-loaded sentence that names the artifact first and then explains its contents. The trailing clause about "the shape a computer gets when a create names no numbers" is slightly oblique phrasing, costing a point but not obscuring the core message.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, so the description must convey what is returned, and it does enumerate the schema's subject areas. For a zero-parameter read tool this is adequately complete, though it could say more about the schema's format or size.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so there is nothing for the description to disambiguate; the baseline for a parameterless tool is 4. The description correctly implies no inputs are required.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb+resource: returns the JSON Schema for a `mandala/v1` template document, and qualifies it as the declarative authoring form. This is clearly distinguishable from siblings like get_template (fetches a specific template) and check_template (validates one).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"Read this before writing one" gives a clear triggering condition for callers authoring a template. It does not name explicit alternatives or when-not-to-use, so it stops short of a 5, but the usage context is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_usageRead what this account has usedA
Read-only
Inspect

What this account has used: running hours weighted by cores and memory, the storage it holds, and the per-computer breakdown behind the totals. Read it before and after a batch to monitor resource use. These measurements do not add a usage charge to the monthly subscription; AI-credit usage is separate. Defaults to the current billing period. READ THE FIRST LINE OF THE ANSWER: a hypervisor that could not be reached makes every total too LOW rather than absent, and that line is the only thing that says so.

NameRequiredDescriptionDefault
toNoEnd of the window, same format. Omit for now. A time in the future is answered as now, and the answer says which instant it used. The window itself may be at most 62 days — every hypervisor replays its ledger a day at a time to answer — so read an older period by naming both bounds rather than by widening this one.
fromNoStart of the window, RFC 3339 with a time zone — "2026-08-01T00:00:00Z". Omit for the start of the billing period, and send it WITH `to` when you are asking about a period that has closed — `to` on its own is measured from the current period and is refused. A timestamp without a zone is refused rather than guessed at. Records go back 399 days.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare readOnlyHint; the description adds the substantive traits: measurements do not add a charge to the subscription, the default window is the current billing period, and an unreachable hypervisor silently makes totals too LOW with only the first line of the answer disclosing it. That last caveat is exactly the kind of failure-mode disclosure annotations cannot carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with what is measured, then usage timing, then the caveat. Dense and mostly waste-free, though the all-caps emphasis sentence is longer than needed to convey the warning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, so the description carries the return shape itself: totals plus a per-computer breakdown, and the first line that flags incomplete hypervisor data. Together with the 100%-covered schema, an agent has everything needed to call it and interpret the result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema already documents the RFC 3339 format, the 62-day cap, the 399-day history, and the paired from/to rule in more detail than the description. The description only restates the current-billing-period default, adding little beyond structured fields.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names a specific resource (account usage) and enumerates exactly what is measured: core/memory-weighted running hours, held storage, and the per-computer breakdown. This is clearly distinguishable from get_credits and get_account, whose names alone would otherwise be confusable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'Read it before and after a batch to monitor resource use' gives a concrete situation that selects this tool. The note that AI-credit usage is separate implicitly routes that question elsewhere, but it stops short of naming get_credits as the alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_webhookRead a webhook subscriptionA
Read-only
Inspect

One subscription with its health: whether it is enabled and why not if not, when the endpoint last accepted a delivery, when one last failed, and the status of the newest attempt. Never the secret. For the individual deliveries and what became of each, list_webhook_deliveries.

NameRequiredDescriptionDefault
webhook_idYesThe subscription id — `whk-` and sixteen hex characters.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare readOnlyHint=true, so the description adds real value: it promises a secret-free response ('Never the secret') and explains that a disabled subscription comes with the reason, plus timestamps for last success/failure. It omits error/not-found behavior, keeping it below 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences with no filler: what you get, the key negative guarantee (no secret), and the sibling pointer. The highest-value content (health/state) is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description correctly enumerates the returned fields, and with only readOnlyHint for annotations the safety profile is covered. Missing only edge-case behavior such as unknown-id handling, which is minor for a read tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single webhook_id parameter is fully documented in the schema (including the `whk-` + 16 hex format), so the description adds nothing on parameters. Baseline 3 applies when structured fields carry the parameter burden.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (read/get) and resource (a single webhook subscription) and enumerates exactly what the response contains: enabled state, reason if disabled, last successful delivery, last failure, newest attempt status. This clearly separates it from list_webhooks and list_webhook_deliveries.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It routes the agent explicitly to list_webhook_deliveries when per-delivery history is needed, which is a meaningful alternative selection. It does not, however, state any exclusion or precondition (e.g., behavior for an unknown id), so it stops short of full when/when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_workspaceRead a workspaceA
Read-onlyIdempotent
Inspect

One workspace: id, name and created_at. An id this key cannot see is not found, the same as one that does not exist — another account's, any workspace but its own for a key confined to one, and a deleted workspace a computer's workspace_id can still name.

NameRequiredDescriptionDefault
workspace_idYesThe workspace id (wsp-…), from list_workspaces or a computer's workspace_id.

TDQS

A3.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description adds real non-obvious context: an id the key cannot see is indistinguishable from a nonexistent one, spanning cross-account ids, keys confined to a single workspace, and deleted workspaces still referenced by a computer's workspace_id. It does not describe error shape or response envelope, so it stops short of 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is compact at two sentences, but the first sentence leads with returned fields rather than what the tool does, and the second sentence packs three nested visibility cases into an em-dash chain that is dense to parse. Reasonably sized but not cleanly front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description compensates by naming the returned fields, and it thoroughly documents the not-found visibility semantics that an agent would otherwise get wrong. Missing only an explicit statement of the fetch verb and error/invalid-format handling, so it is nearly, but not fully, complete for this simple read tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single workspace_id parameter is fully documented in the schema, including format (wsp-…) and its source (list_workspaces or a computer's workspace_id). The description adds no parameter syntax or format detail beyond that, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description conveys that this fetches a single workspace and enumerates the returned fields (id, name, created_at); the singular 'One workspace' implicitly distinguishes it from list_workspaces in the sibling set. It never states an explicit verb like 'retrieve/fetch', so the action is inferred rather than stated, keeping it short of a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: you call this when you have a workspace_id and want that one workspace. No alternative (e.g., list_workspaces) is named and no when-not condition is given, aside from the visibility caveat that is really a behavior, not usage guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_activitiesRead one activity history pageB
Read-onlyIdempotent
Inspect

Selected, retained, best-effort request history; not all guest work or an agent identity. Accepted background work is not completed execution; a dispatched error may have had effects. Activity IDs identify requests, never idempotency keys. History is newest first with a fixed watermark. Changes include late final updates to older rows. No automatic paging. A gap requires refreshing history.

NameRequiredDescriptionDefault
cursorNo
changesNo
computer_idNoComputer, or the current use_computer selection.

TDQS

B3.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only cover safety (readOnly, idempotent, non-destructive), yet the description supplies substantial fresh context: best-effort/partial retention, accepted background work not being completed execution, dispatched errors possibly having effects, IDs being request IDs rather than idempotency keys, newest-first ordering with a fixed watermark, and late final updates to older rows. This is exactly the kind of semantic disclosure annotations cannot convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Sentence-by-sentence the caveats are dense and mostly earn their place, but the paragraph is entirely caveats with no front-loaded statement of what the call does. A reader must assemble the purpose from the name and title rather than the opening clause.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only, non-destructive list tool with no output schema, the semantic caveats are unusually thorough, but the description omits what a returned page contains, how to advance the cursor, and how this tool relates to the sibling readers of the same activity data. Adequate but with clear gaps given the crowded sibling set.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 33% (just computer_id documented), so the description is expected to compensate. It partially does: "No automatic paging" and the cursor implication, plus "Changes include late final updates to older rows" gestures at the `changes` parameter, but neither parameter is named or its format explained, and computer_id usage is left to the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description never states a verb+resource plainly; it opens with the noun phrase "Selected, retained, best-effort request history," leaving the name/title to carry the actual purpose. An agent can infer it lists activity history entries, but nothing distinguishes it from siblings like get_activity, get_activity_results, or list_operations.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no explicit when-to-use guidance relative to the closely named siblings (get_activity, get_activity_results, list_operations). The only procedural hint is "A gap requires refreshing history" and "No automatic paging," which describe mechanics rather than selection criteria.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_agent_runsList background agent runsA
Read-onlyIdempotent
Inspect

Background agent runs on this account, newest first, a page at a time: each run's id, computer, status (running, completed, failed, cancelled or interrupted), how it stopped, its steps and cost. Only completed with stop end_turn is finished. computer_id keeps one computer's runs — it is not defaulted to the selected computer — and status keeps one status: status running finds a run still going, which is the one to wait for or cancel before starting another on that computer. Steps and closing text are not listed, and long prompts are shortened; get_agent_run reads one whole. Pass before with the last run's id for the next page. A key confined to a workspace sees that workspace's runs. The account keeps its 1000 newest ended runs and every run still going.

NameRequiredDescriptionDefault
limitNoPage size; default 20.
beforeNoThe id of the last run on the previous page, for the page after it.
statusNoOnly runs in this status.
computer_idNoOnly this computer's runs. Not defaulted to the selected computer.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only, idempotent, non-destructive, so safety is covered. The description adds substantive behavior beyond that: pagination via before, workspace confinement of keys, and the retention model ('1000 newest ended runs and every run still going'). Also discloses what is NOT returned (steps, closing text, truncated prompts). Missing only explicit rate-limit or ordering guarantees beyond 'newest first', which is stated.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose, but the middle becomes a dense run-on mixing status semantics, filtering caveats, truncation notes, and retention in rapid succession. Content is all useful but structure could be cleaner; dense phrasing risks missed details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema, yet the description enumerates returned fields, discloses omitted/truncated data, explains pagination, workspace scoping, and retention. An agent has everything needed to call correctly and interpret results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3; the description goes further by explaining computer_id is NOT defaulted to the selected computer and by clarifying the status=running use case. before is explained in schema and reinforced. Adds genuine interpretation value above schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('List background agent runs on this account') and immediately enumerates the returned fields (id, computer, status, how it stopped, steps, cost). Clearly distinguished from sibling get_agent_run, which is named for full detail.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when/when-not guidance: 'status running finds a run still going, which is the one to wait for or cancel before starting another on that computer,' and routes to get_agent_run for whole records. Names the exact conditions that select each behavior.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_agent_threadsList kept agent conversationsA
Read-onlyIdempotent
Inspect

The conversations agent runs have kept on this account, most recently used first: each thread's id, the computer it belongs to, a title (the first line of its first prompt) and how many turns it holds. Runs from run_agent, run_agent_chat and start_agent_run are kept unless they sent store: false. To continue one, send its id as thread_id on the next run, on the same computer. computer_id keeps one computer's threads — it is not defaulted to the selected computer. Pass before with the last thread's id for the next page. A key confined to a workspace sees that workspace's threads; viewers are refused, since a prompt is where private text ends up.

NameRequiredDescriptionDefault
limitNoPage size; default 20.
beforeNoThe id of the last thread on the previous page, for the page after it.
computer_idNoOnly this computer's threads. Not defaulted to the selected computer.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well past the readOnly/idempotent annotations: it discloses the retention rule (store: false runs are dropped), the pagination contract, that computer_id is NOT defaulted to the selected computer, and the authorization model (workspace-scoped keys see only their workspace; viewers are refused because prompts contain private text). That permission detail is exactly the kind of context annotations cannot carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with what the tool returns, then usage, then paging, then permissions. Dense but each sentence carries new information; the return-field enumeration is a little list-like but earns its place given there is no output schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description supplies the return shape; with only three simple parameters it covers paging, filtering, continuation and authorization. An agent has everything needed to list, page, and follow up on threads.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so limit, before and computer_id are already documented in the schema, and the description largely restates them (pagination via before, computer_id scoping). It adds the permission-derived nuance that a workspace key sees its own workspace's threads, but adds no new syntax or format detail beyond the schema. Baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource (list kept agent conversations), names the ordering (most recently used first) and enumerates the returned fields (id, computer, title, turn count). The mention that runs come from run_agent/run_agent_chat/start_agent_run cleanly separates it from list_agent_runs and get_agent_thread.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explains when threads exist (kept unless store: false), how to continue one (pass the id as thread_id on the next run on the same computer), and how to page (before = last thread's id). It does not explicitly name sibling alternatives such as get_agent_thread for fetching a single thread, so the routing is implied rather than spelled out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_api_keysList your API keysA
Read-onlyIdempotent
Inspect

The API keys of the person this server's key belongs to, on the account it acts on, newest first: id, name, prefix (display only), scope, when last used, manage_keys, expires_at (null for never), computer_ids (null for every computer its scope reaches), and minted_by_key_id: the key that minted this one (null for a key minted from the dashboard); revoking a key does not revoke the keys it minted. Never a raw key. Needs this server's key to be allowed to manage keys, which only a person can turn on in the dashboard (Settings → Credentials → API keys → the key's menu → Allow managing keys); without it the answer is a 403 that says so — relay it rather than retrying. A key confined to a workspace sees only keys confined to that workspace. Minting and revoking keys are deliberately not tools here, so a raw key never lands in this transcript and a model never revokes one on its own reading of this list: a person does both in the dashboard or with the mandala CLI (mandala api-keys create / revoke).

NameRequiredDescriptionDefault

No parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds substantial behavioral context beyond the readOnly/idempotent/non-destructive annotations: no raw key is ever returned, output field semantics are explained, permission requirements are spelled out, the 403 failure mode is documented, and workspace scoping is clarified. It also explains why minting and revoking are deliberately absent, which safely shapes agent behavior. Nothing contradicts the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The most important information is front-loaded: what is listed, for whom, and in what order. The description is somewhat long and dense for a zero-parameter list tool, but every clause adds relevant scope, permission, or safety context. Minor structural improvements, such as separating the field list, would help readability without changing meaning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given that there is no output schema, the description carries the full burden of explaining returned fields and their null semantics. It also covers the permission prerequisite, the 403 failure mode, workspace scoping, and the deliberate absence of mint/revoke operations. An agent has everything it needs to call the tool correctly and interpret the result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so the baseline is 4 per the rubric. The description does not need to explain input parameters, and the schema is fully empty. It does explain returned fields, but that is output semantics rather than parameter semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states exactly what is listed: API keys belonging to the person behind the server's key, on the account it acts on, ordered newest first. It also names the fields returned, making the scope unambiguous. Though it does not explicitly contrast with siblings, the resource is specific enough that no other sibling tool could be confused with it.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives important usage context: the caller needs a key allowed to manage keys, a missing permission yields a 403 that should be relayed rather than retried, and workspace-scoped keys only see keys in that workspace. It also explicitly says minting and revoking are not available here and must be done in the dashboard or CLI. There is no explicit alternative for listing keys, but the operational guidance is clear and actionable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_buildsList buildsA
Read-only
Inspect

Every build this account has started that the fleet still holds a record of, newest first. A build lives on the hypervisor that ran it, so this asks all of them — and WITHOUT allow_partial, one that cannot be reached makes the platform refuse rather than answer short, so an empty or small list is the truth rather than an outage. Pass allow_partial and that stops being so: you get the short answer, opening with an INCOMPLETE line, and nothing else in the result says how much is missing. Needs an account-wide key: a key confined to a workspace is refused (403).

NameRequiredDescriptionDefault
allow_partialNoAccept a short list when a hypervisor cannot be reached, instead of the 503 the platform answers by default. Nothing in the rows will say the answer was partial — a short build list has no marker in it at all, so the INCOMPLETE line is the whole of the evidence. Read it before concluding anything about what this account has built.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With only readOnlyHint provided, the description carries the behavioral load and delivers: fan-out to every hypervisor, abort-vs-partial failure semantics, the INCOMPLETE marker as the only evidence of truncation, and a 403 for workspace-scoped keys. This is context the annotations do not convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads scope and ordering, then moves to the failure-mode tradeoff and auth in a tight sequence. It is dense and somewhat long with mild repetition ("short answer"/"short list"), but nearly every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, so the description must describe returns — and it does (newest-first records, the INCOMPLETE line). Auth requirements and the partial-result caveat are both covered, leaving no material gap for a single read-only list tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 100%, so baseline is 3, but the description adds meaning beyond the schema by stressing that nothing else in the rows marks a partial answer. It slightly restates the schema's allow_partial explanation, keeping it from a 5.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource (list builds), the exact scope ("every build this account has started"), ordering ("newest first"), and the retention caveat ("that the fleet still holds a record of"). It is clearly distinguishable from get_build and watch_build.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Spells out the condition that selects the allow_partial behavior and the consequence of omitting it (refusal/503 vs. short list), which is strong decision guidance. It does not explicitly route to siblings like get_build or watch_build, so it stops just short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_computersList computersA
Read-only
Inspect

Every computer on this account that exists or may exist. Desktop credentials are deliberately not included — use get_desktop_url for those. Read state before acting on a row: it is the platform's record of whether the machine exists, which is a different question from status, what its host says the guest is doing. A row reading deleting is on its way out and is not one to bind, start or wait for, and one reading unreachable is a row served from the record because the host did not answer — the computer is most likely fine, but nothing only its host knows is on it, status included. The two terminal states are not here at all: deleted and lost come back only when asked for with state.

NameRequiredDescriptionDefault
stateNoOnly computers the platform's own record puts in this state — a different question from what the machine is doing, which is `status`. 'live': its host lists it. 'unreachable': its host did not answer THIS request, so the row is the identity on record and not what the machine says; the computer is most likely fine. 'deleting': a delete was sent and not answered yet. 'deleted' and 'lost' are terminal, and asking here is the ONLY way to see one — an unfiltered listing is live, unreachable and deleting, so a computer missing from it may still have a record.
workspace_idNoOnly the computers in this workspace (an id from list_workspaces), or 'unassigned' for the computers in no workspace. Combines with `state`. A workspace this key cannot reach — another account's, one that does not exist, or any but its own for a key confined to a workspace — is not found, and so is 'unassigned' from a confined key. Left out: every computer this key can see.
allow_partialNoAccept a short list when a hypervisor cannot be reached, instead of the 503 the platform answers by default. The answer then says it is short — a short list reads exactly like the missing computers were deleted.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The lone annotation (readOnlyHint) only says the call is safe; the description adds substantial context beyond it: credentials are omitted from rows, `unreachable` rows are served from the platform record rather than the host, those rows lack host-only fields like `status`, and `deleted`/`lost` only appear when explicitly filtered. This materially changes how an agent should interpret and trust the output.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the resource definition, then the credential exclusion, then the state-interpretation guidance, which is good ordering. It is on the verbose side and its state paragraph overlaps heavily with the schema description, so some sentences repeat rather than earn their place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the burden of explaining what a returned row means, and it does: row states, terminal states, partial-list semantics and the credential omission. Combined with 100% schema coverage and a readOnly annotation, an agent has everything needed to call and interpret this correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the parameter docs are already exhaustive on `state`, `workspace_id` and `allow_partial`. The description's discussion of state and the 503 behavior largely paraphrases the schema, so it adds only the 'read state before acting' interpretation and does not go meaningfully beyond structured data. Baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('every computer on this account that exists or may exist') and immediately draws a boundary against a sibling by declaring desktop credentials excluded and routing to get_desktop_url. An agent can distinguish it from get_computer and get_desktop_url without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes credential needs to get_desktop_url and instructs the agent to read `state` before acting on a row, warning that `deleting` rows should not be bound, started or waited for. It does not, however, clarify when to prefer this over get_computer or how it relates to list_workspaces, so alternative-selection guidance is clear but not exhaustive.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_credential_gateway_bindingsList a computer’s credential gateway bindingsA
Read-only
Inspect

The credential gateway bindings of one computer: for each, the secret it uses (its id, never its value), the HTTPS origin, path prefix and methods it allows, and the base_url and placeholder the computer calls it with. Owners and members may read them. A computer may have up to 8.

NameRequiredDescriptionDefault
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, yet the description still adds substantial value: secrets are returned only as ids, never values (a critical safety disclosure), the access level required is stated, and a hard limit of 8 bindings per computer is given. It stops short of saying what happens when the computer is stopped or whether the list is ever truncated.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the resource and the returned fields before the permission and quota constraints. The enumerated field list is dense but every item carries information the agent needs to interpret the response.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description correctly takes on the job of explaining return contents, and it does so field by field. The permission statement and the 8-binding ceiling round it out; only edge behavior (empty list, stopped computer) is unaddressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single parameter already documents its own default ('use_computer'). The description's phrase 'of one computer' contextualizes but adds no syntax, format or validation detail beyond the schema, so the baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names the exact resource (credential gateway bindings of one computer) and enumerates what each binding contains, so an agent knows precisely what will come back. It lacks an explicit verb like 'lists' and never names the sibling tools (create_/delete_credential_gateway_binding) it complements, so sibling differentiation is only implicit in the name.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied rather than stated: the description establishes the read scope and the permission model ('Owners and members may read them'), which is a real gating condition. However, it gives no explicit when-to-use guidance versus create_credential_gateway_binding or delete_credential_gateway_binding, and no statement about prerequisites such as the computer being running.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_directoryList a guest directory without waking itA
Read-onlyIdempotent
Inspect

Read one passive, unordered directory listing from an already running computer. No resume or idle extension; ordinary API rate/capacity admission still applies. At most 512 examined entries/128 KiB, with no continuation token. Narrow the path when partial. Symlinks are not followed; a final symlink directory is refused. No file content is read.

NameRequiredDescriptionDefault
pathYes
computer_idNoComputer, or the current use_computer selection.

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnly, idempotent, non-destructive), yet the description adds substantive behavior beyond them: 512-entry/128 KiB cap, no continuation token, no resume or idle extension, symlinks not followed and a final symlink directory refused, and that the computer is not woken. That is exactly the additional context the annotations cannot convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action, then layered constraints that each carry information. It is terse and slightly telegraphic in places ('No resume or idle extension'), but no sentence is filler and the ordering is sensible.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description supplies the missing return semantics (single, unordered, bounded listing), permission/rate context, and symlink handling, which is enough to call it correctly. Minor gaps remain around error behavior and whether the cap truncation is signalled, but nothing critical is absent.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Two parameters at 50% schema coverage: 'computer_id' is documented in the schema, but 'path' has only a '/'-prefix pattern with no description. The description partially compensates with 'Narrow the path when partial' and the symlink-on-final-component rule, but never explains the path semantics (absolute guest path, trailing separator behavior) for the undocumented parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource with scope: 'Read one passive, unordered directory listing from an already running computer.' The phrase 'No file content is read' and 'already running' explicitly distinguishes it from sibling read_file and from start_computer/wait_for_computer, so an agent can place it without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives situational context ('already running computer', 'ordinary API rate/capacity admission still applies') and an actionable tip ('Narrow the path when partial'). It does not name a concrete alternative (e.g. exec or read_file) or state exclusions, so it falls short of the explicit when/when-not/alternatives bar, but the usage context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_movesList moves in progress and their outcomesA
Read-only
Inspect

Every move on this account that this key can see — a key confined to a workspace sees only the moves of computers in that workspace: the ones running and the ones that finished in the last day. Read this after move_computer if the wait ran out, and read it when a move is refused because another computer on the account is already being moved — only one runs at a time, and this says which one and how far along. live is the flag to poll on.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover safety with readOnlyHint=true, but the description adds real operational context: workspace-scoped visibility, a one-day retention window for finished moves, single-move concurrency, and 'how far along' progress reporting. It also names `live` as the polling flag, though it is ambiguous whether that is a response field or an input (the schema has none), which keeps this just short of a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The scoping rule, use conditions, and polling hint are front-loaded and each sentence carries information, but the em-dash-heavy run-on sentence requires unpacking. Slightly dense for a no-argument list call, though nothing is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the return burden and mostly does so, explaining what a move entry tells you (running, recently finished, progress via `live`). It stops short of describing the shape or fields of a move record beyond progress, leaving a small gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters and the schema is empty with additionalProperties:false, so there is nothing for the description to document. The reference to `live` reads as an output field rather than a parameter, which slightly muddies an otherwise clean no-arg contract.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (listing 'every move on this account') and immediately scopes it by key visibility and time window. It is clearly distinguishable from the sibling move_computer, which it explicitly references, so an agent can tell the two apart without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-read conditions: after move_computer when a wait timed out, and when a move was refused because another computer is already moving. It also surfaces the concurrency rule (only one move runs at a time) that explains why the alternative failed.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_operationsList lifecycle operationsA
Read-onlyIdempotent
Inspect

The lifecycle operations started on this account, from the API or the dashboard, newest first, a page at a time: kind, computer_id, state, error and timestamps. A key confined to a workspace sees only the operations of computers in that workspace. computer_id keeps one computer's (for a clone, the new computer's) — omitted, it is every one this key can see, not the selected computer's. Pass next_cursor back as cursor for the next page; it is null on the last. Calls made from the dashboard are listed too, except a move.

NameRequiredDescriptionDefault
limitNoPage size; default 20.
cursorNoThe next_cursor of the page before.
computer_idNoOnly this computer's operations. Not defaulted to the selected computer.
idempotency_keyNoOnly the operation the lifecycle call sent with this idempotency_key recorded — found even when that call's answer was lost — within the key's 24 hours.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnly/idempotent/non-destructive annotations, it discloses auth-scoping behavior ('A key confined to a workspace sees only the operations of computers in that workspace'), pagination semantics (next_cursor null on the last page), and result-coverage exceptions (a move is excluded). This is rich behavioral context an agent could not get from annotations alone.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the resource and ordering, and each clause (scoping, filtering, pagination, exceptions) carries information. The single dense sentence with dashes and semicolons is slightly harder to parse than it needs to be.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description compensates by naming the returned fields (kind, computer_id, state, error, timestamps), the pagination contract, and the workspace-scoping rule. An agent has everything needed to call and page through this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning by explaining that an omitted computer_id returns every computer the key can see 'not the selected computer's' and by spelling out next_cursor round-tripping. It does not elaborate on idempotency_key, which only the schema documents.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('The lifecycle operations started on this account') plus the ordering ('newest first, a page at a time') and the fields returned. It is easily distinguished from siblings like get_operation, wait_for_operation, and list_moves.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear context for use: listing account-wide operations from API or dashboard, with the note that dashboard calls are included 'except a move' (implicitly routing moves to list_moves). It does not explicitly name alternative tools like get_operation or list_moves, so it stops short of full when/when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_public_urlsList a computer’s public URLsA
Read-only
Inspect

The public URLs of one computer, oldest first: each is https://<label>.<base_domain> serving a port inside the computer, public (anyone with the link) or private (an account API key (workspace-scoped keys must match the computer), or dashboard browser sign-in). Also says whether they can answer here at all — enabled is false, with a reason, where public URLs are off or the account’s plan includes none, and the URLs are listed either way so you can delete them — and how many this computer may have. If the plan drops below the number a computer has, the oldest within the limit keep answering and the rest answer 404.

NameRequiredDescriptionDefault
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond readOnlyHint=true: discloses ordering, the public/private access model (API key scoping vs dashboard sign-in), that `enabled` may be false with a reason, that URLs are returned even when disabled, the per-computer quota, and the 404 overflow behavior when a plan shrinks. This is exactly the behavioral context annotations cannot carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the resource and ordering, then the format, which is the right order. It is dense and uses heavy parenthetical nesting in the access-model clause, but no sentence is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the return-shape burden and does so: it explains the URL format, the ordering, the `enabled`/reason field, the quota field, and the 404 edge case. An agent can predict and act on the response without further documentation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one optional parameter, and the schema already documents it at 100% coverage ('Defaults to the one selected with use_computer'). The description adds no syntax or selection guidance beyond that, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource — 'The public URLs of one computer, oldest first' — plus the exact URL shape `https://<label>.<base_domain>`. This clearly distinguishes it from create_public_url, delete_public_url, and get_desktop_url.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied rather than stated: the 'listed either way so you can delete them' clause hints at the delete_public_url follow-up, and the auth note hints at when a URL will work. But there is no explicit when-to-use/when-not guidance or named alternative for retrieving a single URL or enumerating computers.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_secretsList the account's secretsA
Read-only
Inspect

The secrets stored on this account, in one scope: the account-wide ones by default, or one workspace's with workspace_id. For each: its name, its id (what set_computer_secrets binds), its current revision_id (what replace_secret and delete_secret need), its scope and when it was last delivered to a computer. Values are NEVER shown — no route returns one. Also says whether binding secrets to computers is switched on here, and the store's limits. Owners and members may read; a viewer is refused. An API key confined to a workspace lists that workspace's secrets, and naming another scope is refused.

NameRequiredDescriptionDefault
workspace_idNoThe workspace to list. Leave it out for the account-wide secrets.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare readOnlyHint=true, but the description adds substantial context beyond that: secret values are never returned by any route, the response includes whether computer binding is enabled and the store's limits, and it spells out the authorization model. This is rich behavioral disclosure the annotations cannot provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the scoping rule, then return fields, then permissions. Dense but every sentence carries information; the single paragraph runs long but none of it is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, so the description carries the burden of describing the return shape (name, id, revision_id, scope, last delivery, binding flag, limits) and it does so explicitly. Nothing an agent needs to call this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single parameter is already documented. The description reinforces the semantics (omit workspace_id for account-wide, supply it for a workspace) and links the returned revision_id to replace_secret/delete_secret, adding modest value over the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (list the account's stored secrets) plus the scoping model (account-wide by default, or one workspace). It also enumerates what each entry contains, so an agent can immediately distinguish it from get_secret, replace_secret, and set_computer_secrets.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explains when to omit workspace_id vs. supply it, states the access-control rule (owners/members may read, viewers refused), and notes the API-key-confined-to-workspace case and the refusal when another scope is named. It also routes to the sibling tools that consume the returned id and revision_id.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_sizesList sizesA
Read-only
Inspect

The named sizes a computer can be launched at — each a template plus a CPU/RAM/disk shape. These are the shapes the platform keeps pre-booted, so create_computer with a size is typically answered in about a second where a custom shape boots cold. allowed says whether this account’s plan admits a row; when false, cheapest_plan names the plan that would.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint annotation, the description discloses meaningful behavioral traits: these shapes are pre-booted so create_computer with a `size` answers in ~1 second, versus a cold custom-shape boot. It also explains output-field semantics — `allowed` gates by plan and `cheapest_plan` names the qualifying plan when the row is disallowed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core definition, then the performance and plan-gating context. Every sentence carries information, though the three-clause first sentence is dense enough to require a second read.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no parameters and no output schema, the description carries the whole burden and does so well: it explains what each row is, the boot/latency tradeoff, and the meaning of the plan-gating fields an agent will encounter in the response.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes no parameters, so the baseline is 4. The description instead usefully documents the returned fields (`allowed`, `cheapest_plan`), which is above and beyond what a parameter-free schema can convey.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource — the named sizes a computer can be launched at — and goes further by defining what a size actually is (a template plus a CPU/RAM/disk shape). An agent immediately knows this enumerates launch shapes and can relate it to create_computer's `size` parameter.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description ties the output to create_computer's `size` parameter, giving clear context for why and when an agent would call it. However, it never states this explicitly as guidance (e.g. 'call this to discover valid size values') and names no alternative or exclusion, so it falls short of full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_snapshotsList snapshotsA
Read-only
Inspect

Every snapshot on this account. orphaned means its computer is gone: such a snapshot can still be cloned into a new computer, but cannot be restored, because a restore puts the disk back on a source that no longer exists. restore_available: false means the only usable copy is on a host its computer has since left: restore_snapshot will not work on it, though it can still be cloned. Read state ON EVERY ROW before acting, rather than on the newest one — this is one answer per hypervisor concatenated in a fixed host order that has nothing to do with time, so a capture running on one host routinely appears after finished snapshots from another. A row reading capturing is not a snapshot yet: the copy is still being taken and restore, clone and delete all fail on it. It carries the id the finished snapshot will keep, so this is also the route to poll after create_snapshot: the row stops reading capturing in place rather than being replaced under another id, and a row that vanishes without ever leaving capturing is a capture that failed. pending is the point at which it can be acted on, and durable means it has reached backup storage as well.

NameRequiredDescriptionDefault
computer_idNoOnly snapshots of this computer. Omit for the whole account.
allow_partialNoAccept a short list when a hypervisor cannot be reached, instead of the 503 the platform answers by default. The answer then says it is short.
include_unfinishedNoAlso return deletions that began and did not finish. They are not usable — their state is "deleting" and nothing can be restored or cloned from one — but they still hold objects and still count against storage, so this is the flag to set when the question is about storage rather than about what can be restored. It is also the flag to set when following a deletion: without it a snapshot stuck half-deleted is hidden, and a poll watching for the row to go cannot tell that from one that finished.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

readOnlyHint=true is consistent with the description, and the text adds substantial behavior beyond the annotation: results are one answer per hypervisor concatenated in fixed host order with no time relation, failed captures appear as vanished `capturing` rows, and a state can transition in place rather than under a new id. None of this is derivable from annotations or schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Scope is front-loaded and most sentences carry non-obvious information, but the state explanations are dense and partially redundant — 'cannot be restored, because a restore puts the disk back on a source that no longer exists' and later 'restore, clone and delete all fail' restate the same failure mode. A tighter paragraph would read better, though little is truly wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, and the description compensates by explaining every row-level field an agent must interpret (orphaned, restore_available, state values capturing/pending/durable/deleting) plus ordering behavior. Nothing needed to call and correctly read this tool is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds operational meaning the schema does not: include_unfinished exists for storage questions and for detecting half-deleted rows during a deletion poll, and it clarifies why allow_partial matters. computer_id is left to the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific scope statement — 'Every snapshot on this account' — and the rest of the text makes clear it is a per-row snapshot listing with state semantics. It does not explicitly name or distinguish itself from siblings like snapshot_holdings or snapshot_schedule, which is the only thing keeping it from a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use rules that are otherwise invisible: always read `state` on every row instead of the newest, poll this listing after create_snapshot, and set include_unfinished when the question is about storage or when following a deletion. It also states when NOT to act (capturing/deleting rows fail on restore, clone and delete).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_ssh_keysList your SSH keysA
Read-only
Inspect

The SSH public keys registered to the person this API key belongs to — the same list whichever account the key acts on. A key added from the dashboard is accepted by every computer with SSH on, on every account where that person is an owner or member; one added through an API key or connected app (add_ssh_key) only on the account that credential acts on, until the credential is revoked. Shows id, type, SHA256 fingerprint, name and reach: every account, this account only, or another account only (refused on this account's computers; which account is not said).

NameRequiredDescriptionDefault

No parameters

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With readOnlyHint=true already covering safety, the description adds substantial context: the reach semantics (every account / this account only / another account only), the rule that dashboard-added keys work everywhere while API-key-added keys are single-account until revoked, and the refusal behavior on this account's computers. This is real behavioral disclosure beyond the annotation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is a single dense sentence, but it is front-loaded with the core resource and scope before drilling into edge-case reach semantics. The lengthy 'reach' exposition earns its place because that behavior is non-obvious, though the run-on structure is heavier than ideal.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter, read-only list tool with no output schema, the description supplies the important missing pieces: what fields are returned and the non-intuitive propagation/refusal rules. Pagination or ordering behavior is not addressed, which keeps it short of a 5.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There are zero input parameters, so the baseline is 4. The description never needs to explain arguments; instead it usefully enumerates the returned fields (id, type, SHA256 fingerprint, name, reach), which compensates for the absent output schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description precisely identifies the resource (SSH public keys registered to the person the API key belongs to) and its scope is person-level rather than account-level, which cleanly separates it from account-scoped siblings. It names add_ssh_key as the add counterpart. It stops short of an explicit 'list' framing but the resource is unmistakable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the scope explanation (a person's keys, not an account's) and add_ssh_key is named as the way to add keys, but there is no explicit 'use this when / not when' routing or comparison against siblings like get_computer_ssh. An agent can infer intent but the guidance is not spelled out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_templatesList templatesA
Read-only
Inspect

The base images a computer can be created from — name, OS, the default CPU and RAM each one implies, and its minimum disk (a smaller disk_gb is raised to it and counted against storage limits). For the templates the platform publishes, name is what a create takes as template; for one you published yourself, pass its ref (namespace/name@version) — a short name is not resolved to your own templates. A short name that is none of the published templates falls back to base, except while this list is INCOMPLETE (a host did not answer): then the create is refused with a retryable 503 that changed nothing, so send it again shortly with the same idempotency_key, or pass a ref to avoid the guess.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint annotation, the description discloses several important behavioral traits: minimum disk enforcement and storage accounting, short-name resolution limitations, incomplete-list fallback behavior, and the retryable 503 error with idempotency guidance. This is rich context that an agent could not infer from annotations alone.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single dense paragraph but front-loads the core resource and its fields before moving into usage and edge-case details. Every sentence carries useful information, though the density and length make it slightly harder to scan than an ideally structured definition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has no parameters, no output schema, and only a readOnly annotation, the description provides complete context: what fields are returned, how names and refs are interpreted, storage implications, and failure/retry behavior. There is no meaningful gap for an agent to fill.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so the baseline score is 4. No parameter semantics need to be described, and the description appropriately focuses on return content and naming conventions instead.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states that the tool returns the base images a computer can be created from and enumerates the relevant fields (name, OS, default CPU/RAM, minimum disk). It does not explicitly differentiate from sibling template tools like get_template or check_template, but the core purpose is unmistakable.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives detailed guidance on how to use the returned identifiers: published templates are passed by `name` as `template`, while user-published templates require `ref` (namespace/name@version). It also explains the fallback behavior for short names and when to pass a ref to avoid guessing, though it does not explicitly compare this tool to sibling template-listing tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_webhook_deliveriesList a webhook’s deliveriesA
Read-only
Inspect

The newest hundred deliveries to one subscription, newest first, each with its state (pending, in_flight, delivered, exhausted or dropped), its attempt count, and the HTTP status or one-line error of its newest attempt. This is where a delivery that ran out of attempts shows up — nothing is dropped silently. Finished deliveries are kept until seven days after they were queued; pending ones until they finish. The one-line error is an open set — timeout, dns, refused, reset, unreachable, tls, redirect, address refused, status NNN and others — and a dropped delivery says why it was dropped. Each carries the event’s cursor, which is what to pass as since to the socket to read on from that point.

NameRequiredDescriptionDefault
webhook_idYesThe subscription id — `whk-` and sixteen hex characters.

TDQS

A3.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond the readOnlyHint annotation: it documents retention windows (seven days after queuing, pending ones until finish), that nothing is dropped silently, the full state vocabulary, attempt counts, and the error set. It does not disclose auth or rate-limit behavior, which keeps it from a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The single long run-on sentence is front-loaded with the most important facts but packs state lists, retention rules, error enums, and cursor semantics into an undifferentiated block. It is dense and would benefit from structure, though little is truly wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-param read tool with no output schema, the description is unusually complete about what each delivery carries and how long records survive. The main missing piece is how the returned cursor should be consumed relative to pagination/limit behavior.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one parameter and schema coverage is 100%, so the schema already documents webhook_id fully. The description adds no parameter-level detail (no pagination, no since/limit arg), so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (list deliveries for one subscription) and specifies ordering (newest first) and scope (newest hundred). It clearly distinguishes itself from sibling webhook tools like get_webhook and test_webhook, though it does not explicitly name an alternative.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage context is implied — you call this to inspect delivery history — but there is no explicit when-to-use vs when-not, no mention of alternatives, and no stated prerequisites. Adequate but with clear gaps given the sibling set.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_webhooksList webhook subscriptionsA
Read-only
Inspect

Every webhook subscription on the account, with its health: whether it is enabled, when its endpoint last accepted a delivery and when one last failed. A webhook is an HTTPS endpoint the platform POSTs events to — the other transport for the same events wait_for_event reads, for a CI job or a queue worker that wants to be woken rather than to wait. Never carries a secret: that is shown once, by create_webhook or rotate_webhook_secret. A workspace-scoped key sees only the subscriptions confined to that workspace.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

readOnlyHint=true already establishes the safety profile, but the description adds meaningful context beyond it: the health fields returned, the security-relevant 'Never carries a secret' guarantee, and the tenancy rule that a workspace-scoped key sees only workspace-confined subscriptions. It omits pagination/return-size behavior, which keeps it from a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core operation and its return fields before elaborating, so an agent gets the essentials in the first clause. The middle sentence defining a webhook is longer than strictly necessary but earns its place by grounding the wait_for_event distinction; still, it could be trimmed.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the burden of describing return values and does so (enabled state, last successful and last failed delivery). Combined with the tenancy scope and secret-exclusion notes, an agent has everything needed to call and interpret this zero-param read.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so there are no parameter semantics for the description to add; baseline is 4. Schema coverage is nominally 100% on an empty property set, so nothing is left undocumented.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource+scope ('Every webhook subscription on the account') and immediately names the return payload (health: enabled, last accepted, last failed). It also differentiates itself from siblings by contrasting with wait_for_event, create_webhook and rotate_webhook_secret, so an agent can place it without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly frames the tool against the alternative transport ('the other transport for the same events wait_for_event reads, for a CI job or a queue worker that wants to be woken rather than to wait'), which gives real selection guidance. It stops short of stating when to prefer this over the sibling get_webhook or list_webhook_deliveries, so the redirect is implied rather than complete.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_windowsList what is on the desktopA
Read-only
Inspect

The windows the window manager knows about — id, title, class, geometry, focus. A screenshot says what the desktop looks like; this says what any of it is, which is how you tell a browser that failed to open from one that has not painted yet. Match on class, not title: the class is the application, the title is whatever page it is showing. Linux only.

NameRequiredDescriptionDefault
computer_idNoWhich computer. Defaults to the one selected with use_computer.
include_allNoInclude panels, the desktop wallpaper and other furniture. Off by default — a stock guest with one terminal open has five windows, four of which are not applications.

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, so the safety profile is covered, and the description adds an environment constraint not present anywhere else: 'Linux only.' It still omits return-volume or pagination behavior, but the platform caveat is a genuinely useful behavioral disclosure beyond the structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the resource and its fields, then compresses usage guidance and the class-vs-title rule into two tight sentences. The 'browser that failed to open' clause is slightly literary but earns its place as usage guidance; every sentence carries signal.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description compensates by naming the returned fields, and the Linux-only note plus class/title guidance cover the main correctness pitfalls. For a simple two-parameter read tool this is nearly complete; only window ordering/count behavior is unaddressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both computer_id and include_all are already documented, including the 'panels, wallpaper and other furniture' rationale. The description adds no parameter-level syntax or defaults beyond that, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific resource (windows known to the window manager) and enumerates the returned fields (id, title, class, geometry, focus). It actively distinguishes itself from the sibling screenshot tool ('A screenshot says what the desktop looks like; this says what any of it is'), so an agent can route correctly without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a concrete decision context versus screenshot (diagnosing a browser that failed to open vs one that has not painted) and a matching heuristic ('Match on class, not title'). It lacks explicit when-not-to-use guidance and does not name window_action as the mutating alternative, but the context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_workspace_membersList a workspace's membersA
Read-onlyIdempotent
Inspect

The people who reach a workspace, oldest member first: user_id, email, name (null when unset), role, accepted_at, suspended (a sign-in suspension: they cannot sign in anywhere) and seat_suspended (true while they wait for a seat on this account and cannot act on it; it returns to false when their seat is restored). Either flag, or both, can be true. Workspaces do not divide people — everybody on the account reaches every workspace at their account role — so this is the account's accepted members; invitations not yet accepted are left out. A key confined to a workspace is refused with 403, because the list is the whole account's: relay that rather than retrying, and use an account-wide key.

NameRequiredDescriptionDefault
workspace_idYesThe workspace id (wsp-…), from list_workspaces or a computer's workspace_id.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare a safe read (readOnlyHint, idempotentHint, destructiveHint=false), and the description adds substantial context on top: return ordering ('oldest member first'), the meaning of both suspended flags and that either or both can be true, exclusion of unaccepted invitations, and the 403/auth constraint. This is well beyond what structured fields convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the resource and ordering, then layers in field semantics and the 403 caveat. It is a dense single paragraph but nearly every sentence carries actionable information; the parenthetical on suspended flags is verbose yet genuinely clarifying.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description takes on the burden of describing return values and does so (field list plus flag semantics), and it covers the auth failure mode. Nothing an agent needs to call this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the single workspace_id parameter is already documented in the schema (with its wsp- prefix and provenance). The description adds no parameter-level syntax or format detail, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource ('The people who reach a workspace') and immediately clarifies the scope: it returns the account's accepted members, not a workspace-scoped subset. It lists the exact fields returned, so an agent can distinguish it from list_workspaces or get_workspace without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a clear prerequisite (use an account-wide key) and explicit error handling: a workspace-confined key is refused with 403 and the agent should relay it rather than retry. It does not explicitly route the agent away from sibling tools, but the account-vs-workspace scoping statement effectively defines when this tool is the right choice.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_workspacesList workspacesA
Read-onlyIdempotent
Inspect

The account's workspaces, oldest first: id, name and created_at. A workspace partitions the account's computers: a key confined to one reaches that workspace's computers only, and a computer's workspace_id names the one it is in. A key confined to a workspace lists only that one. create_workspace, rename_workspace and delete_workspace change them. No arguments.

NameRequiredDescriptionDefault

No parameters

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/idempotent/non-destructive, so the safety profile is covered. The description adds genuine value beyond that: the return shape and ordering plus the key-confinement behavior that changes what a caller actually sees.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the resource, returned fields, and ordering before the explanatory context. The workspace-partition sentence is somewhat long but earns its place by disambiguating the tool's result set.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a no-argument listing tool with no output schema, the description supplies the return fields and ordering that an agent would otherwise lack. Complete enough to call correctly, with only minor room for richer sibling differentiation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Zero parameters, so per the baseline this scores 4. The description reinforces this with 'No arguments,' aligning with the empty schema without adding ambiguity.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (the account's workspaces) and even names the returned fields and ordering (id, name, created_at, oldest first). It also routes to create/rename/delete_workspace for mutation, though it doesn't explicitly contrast with get_workspace or list_workspace_members.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explains the scoping condition a caller must reason about (a key confined to a workspace lists only that workspace's workspaces) and points to the create/rename/delete siblings for changing them, giving clear usage context. No explicit exclusions or step-by-step when-to-use, keeping it just short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

mouse_buttonHold or release the mouse buttonBInspect

The two halves of a click, for gestures drag cannot express — a lasso across several stops, or a press held while the keyboard is used.

NameRequiredDescriptionDefault
xNoLeave x and y out to act where the pointer already is. Both or neither — half a coordinate is refused rather than completed with a zero.
yNo
stateYes
contextNoAnswer the desktop's windows, and which one has focus, as they stand just after the action — what list_windows would say, without a second call — and, when the focused window is Chromium, the page on screen: its URL, title and the interactive elements visible in it, each with the point to click. Read at once, so a window still opening may not be listed yet. If they cannot be read the action still happened, and the answer says why.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

B3.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations at all, the description carries the full behavioral burden, and it does disclose the key stateful trait: the button can remain held across calls while other tools (keyboard) run. That is genuinely useful. Missing, however, is any warning about leaving the button stuck down if 'up' is never sent, and nothing about failure modes — that detail lives only in the 'context' schema text.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single tight sentence that front-loads the essential framing ('the two halves of a click') before the examples. Every clause earns its place, though the poetic register costs a little precision relative to its brevity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a stateful pointer-control tool with no annotations and no output schema, the description conveys the hold-across-calls model and the optional context read, which is the core need. It is still thin on the sequence contract (that every 'down' needs a matching 'up'), on coordinates being optional, and on what the response contains — the schema covers the latter two but the description does not reinforce them.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description adds zero parameter information; all meaning comes from the schema, which explains the optional coordinate pair and the 'both or neither' rule on x and richly documents the context flag. With 60% coverage and 'y' and 'state' left undocumented in the schema, the definition gets by mainly because those two are self-evident (symmetric coordinate, down/up enum).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description is metaphorical — 'the two halves of a click' — and never states the verb 'press' or 'release' explicitly; that only arrives via the title and the required 'state' enum. It does signal that this is not a whole click and not a drag, which helps separate it from click/drag siblings, but an agent must infer the actual operation from context rather than reading it in the description.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives two concrete use cases (a lasso spanning several stops, and a press held while the keyboard is used) and explicitly routes away from drag for gestures drag cannot express. It stops short of naming click as the alternative for a simple press-release pair or stating when not to use it, so it is clear context rather than a full decision rule.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

move_computerMove a computer to a host that can run a bigger sizeAInspect

Grow a computer past what its current host can run, by moving it to another host in the same region first. Only call this after update_computer has refused a resize and said a move is possible: it is the second half of that refusal and nothing else. THIS MOVES THE MACHINE TO DIFFERENT HARDWARE and copies its disk to get there — say so before you call it. The computer must be STOPPED (suspended is not stopped here: a saved desktop only loads on the host that wrote it, so resume and stop it, or discard the session). One move runs per account at a time. Everything is decided again when this runs, so it can still refuse. Waits for the outcome and reports it, reporting progress while it waits so a client that sends a progressToken and sets resetTimeoutOnProgress can hold the request open; list_moves reads the outcome if the wait runs out, and is the answer for a client that cannot.

NameRequiredDescriptionDefault
cpuNoApplied with the move. Omit to leave alone.
ram_mbYesThe size that did not fit. Must be MORE than the computer has now.
disk_gbNoApplied with the move, after the copy. Disks grow only.
timeout_sNoHow long to wait for the move to finish before handing back and letting you poll.
computer_idNoWhich computer. Defaults to the one selected with use_computer.
idempotency_keyNoOptional. Omit it on a first attempt: a fresh key is sent for you, and an answer that is lost names it. Pass the key such an answer named to send the SAME call again without it being done twice — the platform answers with the first call's result, or says it is still running. After a 5xx that names no operation_id, send the same call again with the same key: nothing may have been done, and the platform either carries it out (the key was released) or answers idempotency_outcome_unknown. After idempotency_outcome_unknown, or a 5xx that names an operation_id, the key is spent (resending with it answers idempotency_outcome_unknown): read get_computer (and get_operation when the error named an operation_id: succeeded means it happened, running means wait on it, pending alone is no reason to wait), and if the step did not take effect, send the call again with a new key, or none. Keys last 24 hours; the same key with different arguments is refused.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and does so well: it discloses that the machine moves to different hardware and copies its disk, that the computer must be STOPPED rather than suspended with an explanation of why, that one move runs per account at a time, and that everything is re-decided at execution time so refusal remains possible. It also explains the waiting behavior, progressToken/resetTimeoutOnProgress handling, and the list_moves fallback.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with purpose and the critical usage constraint, then proceeds through preconditions, concurrency, and async behavior in a logical order. It is dense and long, but nearly every sentence carries operational value; the progress/waiting sentence is slightly convoluted but still earns its place for a complex mutation tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the absence of annotations and an output schema, the description covers the essential context: why the move exists, the required stopped state, the per-account concurrency limit, the fact that preconditions are revalidated, and how to obtain the outcome through waiting or list_moves. There is no significant missing information for an agent to call this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all six parameters thoroughly, including ram_mb, disk_gb, timeout_s, computer_id, and idempotency_key semantics. The description does not add parameter-level detail beyond what the schema provides, which is acceptable given full schema coverage but is not a value-add.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: moving a computer to another host in the same region so it can grow beyond its current host's capacity. It is clearly distinct from update_computer and list_moves in context, but it never explicitly differentiates itself from the sibling move_computer_to_workspace, which is a meaningful ambiguity for an agent choosing between move operations.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit precondition: only call after update_computer has refused a resize and said a move is possible, and it is the second half of that refusal and nothing else. It also names list_moves as the alternative for clients that cannot hold the request open, so both when-to-use and fallback routing are covered.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

move_computer_to_workspaceMove a computer to a workspaceA
DestructiveIdempotent
Inspect

Change which workspace a computer belongs to, within the same account. This changes who can access it. Requires an account-wide member or owner credential; workspace-scoped credentials are refused, even for a no-op. Supply computer_id explicitly and workspace_id as a wsp- ID, or null to make it unassigned. Neither the selected computer nor the default workspace is used. The computer must be stopped, with no saved session, snapshots or snapshot history copies, secret bindings, or proxy credentials. The platform checks these conditions; a fleet that cannot prove safety can refuse. Do not stop the computer, discard its session, delete snapshots, or remove bindings automatically to overcome a refusal. This changes workspace membership, not hardware or size. Once moved, keys confined to the old workspace lose it, its events and webhooks follow it, and its desktop and share credentials are replaced, so a get_desktop_url link from before stops working. If the outcome cannot be confirmed, read get_computer before deciding whether to retry; repeating the same call reconciles a change whose outcome was uncertain.

NameRequiredDescriptionDefault
computer_idYesThe explicit computer ID to move.
workspace_idYesDestination workspace ID, or explicit null for unassigned.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare destructiveHint=true and idempotentHint=true, but the description goes far beyond: it enumerates the concrete consequences (old-workspace keys lose access, events/webhooks follow, desktop and share credentials replaced, prior get_desktop_url links break) and the platform refusal behavior. This is exactly the behavioral context annotations cannot carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and scope, then prerequisites, then consequences, then retry guidance — a logical order with no filler sentences. It is dense and long, but each sentence carries substantive information; the only cost is overall length rather than wasted prose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, yet the description covers the outcome-confirmation path (read get_computer, retry reconciles uncertain outcomes), so an agent has what it needs to call correctly and recover safely. Preconditions, credentials, side effects, and idempotency are all addressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds genuine meaning beyond the schema by specifying that computer_id must be supplied explicitly, workspace_id is a 'wsp-' ID or null for unassigned, and critically that 'Neither the selected computer nor the default workspace is used' — an inference guard the schema does not state.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Change which workspace a computer belongs to, within the same account') and immediately scopes it against the sibling move_computer by clarifying it is about workspace membership, 'not hardware or size'. An agent can distinguish it from move_computer and update_computer without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states credential requirements (account-wide member/owner; workspace-scoped refused, even for a no-op), the preconditions that select or block the call (computer stopped, no session/snapshots/bindings), and the failure path (read get_computer before retrying). It names the alternative and the condition that routes to it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

move_mouseMove the pointerAInspect

Move the pointer without clicking — for hovering over a menu or a tooltip.

NameRequiredDescriptionDefault
xYes
yYes
contextNoAnswer the desktop's windows, and which one has focus, as they stand just after the action — what list_windows would say, without a second call — and, when the focused window is Chromium, the page on screen: its URL, title and the interactive elements visible in it, each with the point to click. Read at once, so a window still opening may not be listed yet. If they cannot be read the action still happened, and the answer says why.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description must carry the full behavioral burden. It discloses the most important trait — that no click/button event occurs — but says nothing about cursor motion timing (instant vs animated), whether the action waits for the pointer to settle, or that coordinates map to the remote desktop's screen space.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One short sentence, zero filler, with the behavioral constraint ('without clicking') front-loaded ahead of the use case. Nothing wasteful.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema and no annotations, and the tool mutates desktop focus/hover state, so the description is the only source of behavioral context. It covers purpose but leaves coordinate semantics, motion timing, and failure behavior unaddressed, so an agent could easily call it with wrong-space coordinates.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 50%: context and computer_id are richly documented in the schema, but x and y have no description anywhere. The description does not clarify the coordinate space (screen pixels, which monitor, origin at top-left), which is the single most consequential semantic for a pointer-move tool.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Move the pointer') plus the key differentiator 'without clicking', which separates it from click, drag and mouse_button. It does not name any sibling explicitly, so the agent must infer the boundary rather than read it.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

'For hovering over a menu or a tooltip' gives a concrete use context, which is more than most siblings offer. It stops short of saying when NOT to use it (e.g. use click when a press-and-release is needed) or any prerequisite such as the computer being started.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

open_urlOpen a URL on the desktopAInspect

Put a web page on the screen in the guest's browser: the first of firefox-esr, firefox or chromium the image has (the Debian desktops open firefox-esr, Omarchy opens chromium). An image with none of them is an error, not a silent success. The command returns before the window draws — on a cold browser that gap has been as long as ten seconds — so screenshot until the screen changes rather than concluding from one frame that nothing launched.

NameRequiredDescriptionDefault
urlYes
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so richly: browser preference order (firefox-esr, firefox, chromium), the image-dependent behavior (Debian vs Omarchy), error-not-silent-success when no browser exists, and the async return that can lag up to ten seconds. This is exactly the non-obvious behavior an agent needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded in the first clause, and each subsequent sentence (browser order, error case, latency, verification) earns its place. The single flowing block is dense but not padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema and no annotations, so the description must stand alone; it covers purpose, failure mode, latency, and post-call verification. It omits what the command returns on success or how load failures surface, leaving a small gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 50% and the description adds nothing about the url parameter's format or computer_id's defaulting behavior, which the schema already documents. Baseline 3 for a mid-coverage schema where the structured fields do the explaining.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Put a web page on the screen in the guest's browser.' The phrasing 'in the guest's browser' disambiguates it from the similarly named get_desktop_url sibling, and the browser-selection detail makes the action concrete.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear operational context: call it to display a page, then 'screenshot until the screen changes rather than concluding from one frame that nothing launched.' It doesn't explicitly compare against alternatives like exec or get_desktop_url, so it stops short of full when/when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

paste_textPaste textAInspect

Put text on the desktop clipboard and press the paste shortcut, as one step: the fast way to insert up to 8192 bytes of UTF-8, including accents, CJK and emoji, into whatever has focus. Linux desktops only; Windows and a guest without working clipboard support are refused. The paste REPLACES the clipboard and leaves the text there — after pasting a secret, clear it with write_clipboard and text "". A success means the clipboard write and the shortcut were delivered, not that the application inserted the text (a paste-disabled field ignores it): check with a screenshot. An interrupted call may already have pasted, so look before sending it again, and do not fall back to type_text without looking.

NameRequiredDescriptionDefault
textYesThe text to paste: 1 to 8192 bytes of UTF-8, no NUL.
contextNoAnswer the desktop's windows, and which one has focus, as they stand just after the action — what list_windows would say, without a second call — and, when the focused window is Chromium, the page on screen: its URL, title and the interactive elements visible in it, each with the point to click. Read at once, so a window still opening may not be listed yet. If they cannot be read the action still happened, and the answer says why.
shortcutNo"ctrl+v" (the default) or "ctrl+shift+v", which terminals need. Shift+Insert is not offered: it can paste the separate primary selection instead.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so richly: Linux-only with Windows/guests refused, clipboard is REPLACED and left behind, success means 'delivered' not 'inserted' (paste-disabled fields ignore it), and an interrupted call may already have pasted. These are exactly the side-effect and idempotency disclosures an agent needs for a mutation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the action and then layers constraints, with every sentence carrying operational weight (platform limits, secret cleanup, success semantics, retry caution). It is dense and long, but no line is filler; slightly tighter grouping would earn a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema and no annotations exist, yet the description fully covers platform eligibility, clipboard side effects, what 'success' actually guarantees, verification method, and interrupted-call recovery. Nothing essential for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents all four parameters including the shortcut enum rationale and the context flag. The description adds only minor emphasis (the 8192-byte limit) that the schema already states, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific compound action (write clipboard + press paste shortcut) with scope (up to 8192 bytes UTF-8, into whatever has focus) and platform constraints. It is clearly distinguishable from siblings write_clipboard, type_text, and press_key, which the description explicitly references.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly names the alternative paths and their conditions: clear a pasted secret with write_clipboard + empty text, verify with a screenshot rather than assuming success, and do not fall back to type_text without looking. This routes the agent correctly across multiple sibling tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

poll_eventsRead what has happenedAInspect

Everything the computer has reported that you have not been handed yet, without waiting. This server holds the event stream open between your turns, so this drains what accumulated while you were doing something else — including while you were running other tools on the same machine. Use it after a long exec, or whenever you want to know what changed without spending a screenshot. Returns immediately, and an empty list genuinely means nothing has happened.

NameRequiredDescriptionDefault
limitNoAt most this many, oldest first. The rest stay buffered and come back on the next call — more_waiting says how many.
sinceNoA cursor from an earlier call. Omit it and you get everything since the last time you read, which is what you usually want.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only cover idempotentHint=false and destructiveHint=false, so the description must carry the rest — and it does: it discloses that the stream is held open between turns, that this drains a buffer accumulated from other tool activity, that it is non-blocking, and that an empty result is meaningful rather than an error. It stops short of stating pagination/continuation behavior ('more_waiting' lives only in the schema), but the added behavioral context is substantial.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core action and its non-blocking nature are front-loaded, and the four sentences each carry distinct information (buffering model, when to use, return timing, empty-result semantics). Slightly longer than needed but not padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description must convey return semantics, and it does: immediate return, a list of accumulated events, and that an empty list is a genuine negative result. Combined with the schema's explanation of cursor and buffering behavior, this is nearly complete for a zero-required-parameter polling tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3; limit, since, and computer_id are all fully documented in the schema. The description adds only the framing that this drains what accumulated while working elsewhere, which reinforces but does not extend the parameter semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action (draining the accumulated event stream) and a specific resource (what the computer has reported), and it distinguishes itself from siblings in the same breath: 'without waiting' separates it from wait_for_event/wait, and 'without spending a screenshot' separates it from screenshot. An agent can place it in the toolset without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives concrete contexts — 'after a long exec' or 'whenever you want to know what changed without spending a screenshot' — which implicitly routes against wait_for_event and screenshot. It does not give an explicit when-not or name the blocking alternative outright, so it falls short of the top band.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

press_keyPress a key or a chordBInspect

Press named keys — "Return", "Tab", "Escape", "Page_Down", or a chord like ["ctrl","c"]. X keysym names, so "Return" rather than "Enter".

NameRequiredDescriptionDefault
keysYesOne key, or several for a chord pressed together.
contextNoAnswer the desktop's windows, and which one has focus, as they stand just after the action — what list_windows would say, without a second call — and, when the focused window is Chromium, the page on screen: its URL, title and the interactive elements visible in it, each with the point to click. Read at once, so a window still opening may not be listed yet. If they cannot be read the action still happened, and the answer says why.
computer_idNoWhich computer. Defaults to the one selected with use_computer.
hold_secondsNoHold the keys down this long instead of tapping them. Capped at 30s.

TDQS

B3.4/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations at all, the description carries the full behavioral burden and does not meet it. It never says what happens to the target window (does the computer need focus?), whether keys are sent to the focused window only, what occurs on an unrecognized keysym, or what the call returns by default; the hold_seconds/context behaviors live only in the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, front-loaded with the action and immediately followed by the naming convention that prevents the most likely invocation error. Nothing is padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Input syntax is well covered, and there is no output schema to explain, so the description is adequate for calling the tool. It is thin for a side-effecting desktop action, though: no mention of focus requirements, failure behavior, or the default return, leaving the agent to reconstruct behavior from the schema's context/hold_seconds fields.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 100%, so the baseline is 3, but the description genuinely adds meaning for `keys`: it names valid X keysym spellings and flags the "Return" vs "Enter" trap, which the schema's terse "One key, or several for a chord" does not convey. It does not touch the context/hold_seconds/computer_id semantics, but those are well documented in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Press named keys ... or a chord") with concrete examples that make the operation unmistakable. It does not explicitly distinguish itself from the adjacent input siblings type_text/paste_text, so an agent has to infer the boundary, but the resource is clear enough that confusion is unlikely.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: an agent can infer this is for discrete keys and chords while type_text/paste_text handle strings, but the description never states when to pick this tool over those siblings. The X-keysym note ("Return" rather than "Enter") is a partial usage hint rather than a routing rule.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

publish_artifactPublish a nominated immutable file versionAInspect

Explicitly capture a caller-nominated absolute Linux, Windows drive or UNC file path with expected_size and lowercase expected_sha256 already supplied. One guest file read, no preflight stat/list/hash/exec. Optional execution_id is verified caller-selected association, not proof of authorship. Default 8 MiB/max 64 MiB capture cap; default 86400s/max 604800s retention. New version per call; a lost response leaves publication unconfirmed.

NameRequiredDescriptionDefault
pathYes
max_bytesNo
computer_idNoComputer, or the current use_computer selection.
execution_idNo
expected_sizeYes
expected_sha256Yes
retention_secondsNo

TDQS

A4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations it discloses substantial behavior: exactly one guest file read, no preflight operations, the 8 MiB default/64 MiB max capture cap, 86400s default/604800s max retention, one new version per call, and that a lost response leaves publication unconfirmed. That last point in particular is non-obvious and valuable.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Dense, front-loaded, and each clause contributes information (input requirements, cap/retention defaults, versioning, failure mode). It is sentence-heavy and slightly run-on, but no filler is present.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 7-param, non-idempotent write with no output schema, the description covers input requirements, limits, versioning semantics, and the failure mode. It stops short of describing what the caller gets back on success, which would close the remaining gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With only 14% schema coverage, the description must carry the burden and largely does: it explains path format (absolute Linux/Windows drive/UNC), the required expected_size and lowercase expected_sha256, the meaning of execution_id (verified caller-selected association, not proof of authorship), and the caps/defaults for max_bytes and retention_seconds. Only computer_id goes unmentioned.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb+resource: capturing an absolute Linux/Windows/UNC file path and creating an immutable published version. It contrasts implicitly with read_artifact/get_artifact (which read stored versions) by framing this as the capture step from a live guest, though it never names those siblings explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states a key prerequisite (expected_size and lowercase expected_sha256 must already be supplied, no preflight stat/list/hash/exec), which is real usage guidance. However, it never routes the agent between this and alternatives like retain_execution_output, read_artifact, or publish_template, leaving selection to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

publish_templatePublish a template documentAInspect

Store a document under a ref of your own, so create_computer can launch it by name. THE NAMESPACE IS YOUR ACCOUNT: metadata.namespace has to be your account id, and anything else is refused rather than rewritten — system included. A REF IS IMMUTABLE: publishing the identical document again succeeds and changes nothing, but publishing a DIFFERENT document under the same ref is refused, and the fix is to bump metadata.version. What counts as different is the digest, so a changed label is a change. Check the document first — a mistake published under a version can never be corrected under that version. NEEDS AN ACCOUNT-WIDE KEY: templates are the account's, so a key confined to a workspace is refused (403) whatever it sends; such a key can still list_templates and launch a template by its ref.

NameRequiredDescriptionDefault
documentYesThe document itself, as JSON or YAML — the file contents, not a wrapper.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations carry only openWorldHint, so the description does the heavy lifting and delivers rich context: namespace refusal semantics, immutability, digest-based change detection, idempotent success on identical republish, and the account-wide-key requirement with the 403 consequence. It omits what a successful call returns, which keeps it short of a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core purpose in the first clause and then layers in constraints, but the capitalized emphasis and dense run-on clauses make it longer than necessary. Every sentence still earns its place by carrying distinct behavioral rules.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no output schema and minimal annotations, the description covers auth requirements, the namespace rule, idempotency, conflict resolution, and the safe-path alternative for restricted keys. Only the response behavior is unaddressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema documents the single 'document' parameter at 100% coverage, but the description adds real meaning by revealing the document's internal structure, specifically that metadata.namespace must be the account id and metadata.version drives the version bump. That goes beyond what the schema states.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Store a document under a ref') plus the downstream purpose ('so create_computer can launch it by name'), naming a sibling tool explicitly. An agent can place it relative to create_computer, list_templates, and check_template immediately.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when/when-not guidance: which namespace is refused, that identical republishing is a no-op while a different document needs a version bump, and that a workspace-confined key is refused (403) but can still list_templates and launch by ref. Alternatives and constraints are spelled out rather than implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_artifactRead a complete verified small artifactA
Read-onlyIdempotent
Inspect

Read metadata, then only if the complete artifact fits max_bytes (default 4096/max 16384), read the whole immutable object and verify size/SHA-256. Over cap returns metadata only, with zero content GETs. One 90s operation budget; no Range, prefix, assembly, file destination, guest fallback or image/HTML rendering. Lossless UTF-8/BOM or exact base64.

NameRequiredDescriptionDefault
max_bytesNo
artifact_idYes
computer_idNoComputer, or the current use_computer selection.

TDQS

A4.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations cover only the safety profile (readOnly/idempotent/non-destructive), and the description adds substantial context beyond them: a 90s operation budget, zero content GETs over cap, explicit exclusions (no Range, prefix, assembly, file destination, guest fallback, image/HTML rendering), SHA-256 verification, and lossless UTF-8/BOM or exact base64 output. These are exactly the operational traits an agent needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Extremely dense and front-loaded: the gating condition and cap appear first, followed by fallback behavior, then exclusions and encoding. Every clause carries distinct information with no filler, despite being telegraphic.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description correctly explains return behavior itself (metadata-only over cap vs full verified content, plus encoding format), and covers constraints and exclusions. Nothing essential for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 33% (only computer_id is documented in-schema), so the description carries weight. It fully explains max_bytes' role as the cap that gates content retrieval, including the default 4096 and max 16384, and implies artifact_id's role as the target object. computer_id is left entirely to the schema, but overall the description compensates well for the coverage gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Read ... the whole immutable object and verify size/SHA-256') and describes the two-phase metadata-then-content flow, which is a genuine behavioral distinction from a pure metadata reader like get_artifact. It does not name any sibling explicitly, so the agent must infer the boundary against get_artifact/read_file.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly specifies the condition that selects content retrieval (only if the artifact fits max_bytes) and the fallback behavior over cap, which is useful usage context. However, it never names an alternative tool or states when to prefer get_artifact or read_file instead, leaving the routing decision to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_clipboardRead the desktop's clipboardA
Read-only
Inspect

What is on the computer's desktop clipboard right now — the CLIPBOARD selection, which is what Ctrl-C writes and Ctrl-V pastes. Use this rather than running xclip through exec: exec runs a login shell, so anything the guest user's profile prints lands on the same output ahead of your command's, which corrupts a read you are trying to parse. This does not share that stream. It requires a Linux desktop image with its desktop's clipboard tool installed — xclip on X11, wl-clipboard (wl-paste/wl-copy) on Wayland images such as Omarchy — and is refused on Windows. An image without that tool gets a 400 that names it and never clears; changing runtime state or retrying cannot fix that image dependency. It is a READ, not a subscription: this call notices nothing on its own, and repeating it is how a copy inside the guest is discovered. What does notice is wait_for_event on clipboard.changed, which fires when the selection changes hands and says which selection it was — the text is deliberately not on that stream, so this is still the call that fetches it. It also does not wake a suspended computer, so a stopped or suspended one is refused rather than started; start_computer first if you need it, unless a start is already under way — wait_for_computer tells you which. The 409s are not alike either, and the answer says which KIND it is rather than leaving you to match on the sentence: a computer that is not running does not clear by waiting UNLESS a start has already been admitted for it, in which case wait_for_computer is the call and start_computer would only start it twice — while a guest agent that is busy or still inside its boot window is worth asking again in a moment. A desktop session or X server that is not answering carries no such word, deliberately, because the platform cannot tell a guest still coming up from one nobody is logged into: bound your attempts there rather than looping on it. At most 128 KiB comes back, and more than that is refused rather than cut short.

NameRequiredDescriptionDefault
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only supply readOnlyHint=true, so the description carries the rest — and it does: 128 KiB return cap, 400 on images lacking the clipboard tool, refused on Windows, no wake of suspended computers, and a differentiation of 409 causes (not-running vs busy/booting vs unresponsive session) with guidance for each. This is well beyond what the annotation provides.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and scope are front-loaded in the first sentence, and most sentences carry distinct behavioral information (errors, limits, alternatives). However, the dense em-dash style and the extended 409 taxonomy push it toward over-long for a single read call, costing some readability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description supplies the return-size cap and notes the text is fetched only by this call rather than the wait_for_event stream. Prerequisites, error taxonomy, and platform constraints are all covered, so an agent has everything needed to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one parameter (computer_id) and schema description coverage is 100%, so the schema already documents it, including its use_computer default. The description adds no syntax or format detail for the parameter, so the baseline of 3 for high-coverage schemas applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a precise statement of verb and resource: it reads the desktop's CLIPBOARD selection, defined as what Ctrl-C writes and Ctrl-V pastes. It distinguishes itself from siblings both by content (vs write_clipboard) and by explicitly ruling out the exec/xclip path. An agent can identify exactly what this call returns without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit when-to-use and when-not-to-use guidance: prefer this over running xclip through exec (with the reason external to the tool), use wait_for_event on clipboard.changed to notice changes, start_computer first if suspended, use wait_for_computer if a start is already admitted. Alternatives and the conditions selecting them are named, not implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_execution_outputRead an independent execution output chunkA
Read-onlyIdempotent
Inspect

Read volatile, mutable guest output once at explicit independent stdout_offset and stderr_offset byte positions. Performs guest I/O but does not refresh activity, resume, change shared PID cursors, retry, tail, capture or replay a command. Unsuitable for passive Activities/history. Each stream is limited to 4096 bytes by default, at most 16384. Text is lossless UTF-8 (BOM preserved); NUL, binary and split UTF-8 remain exact base64. False more flags mean current EOF, not completion. Diagnostics repeat independently; only the first 4096 diagnostic bytes are displayed, with distinct available/displayed counts and display/daemon truncation flags. A 409 with code output_unavailable that also carries output_unavailable (today "daemon_restarted", for a command that was already running when the service on the computer’s host restarted, and on get_execution too) is final: the output cannot be read, and sending the read again will not help; its status is still on get_execution. Without that marker it means a guest log could not be opened, which just after a command starts can be a log not created yet, so a later read at the same offsets can succeed. Either way, running the command again repeats what it did rather than recovering its output.

NameRequiredDescriptionDefault
limitNo
computer_idNoComputer to read; defaults to use_computer selection.
execution_idYesStable execution_id returned by an accepted background exec; never a PID.
stderr_offsetYes
stdout_offsetYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only cover read-only/idempotent/non-destructive; the description adds substantial context beyond them: one-shot volatile reads, default 4096/max 16384 byte stream limits, lossless UTF-8 with BOM preservation, exact base64 for NUL/binary/split UTF-8, EOF-flag semantics that do not mean completion, and diagnostic truncation with available/displayed counts. It also flags that guest I/O occurs without side effects on cursors or activity.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core verb/scope, and nearly every clause carries information that changes how an agent calls it. The final 409 paragraph is a dense run-on with a nested parenthetical that is harder to parse than it needs to be, costing some readability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex, volatile-read tool with no output schema, the description covers limits, encoding behavior, EOF semantics, diagnostics truncation and error finality. The remaining gap is that return-field names/shape are only partially implied (flags, available/displayed counts) rather than spelled out.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 40%, so the description must compensate, and it largely does: it defines the offsets as explicit, independent byte positions, and specifies the limit default (4096) and ceiling (16384). It does not clarify computer_id's default-vs-explicit behavior beyond what the schema states, leaving one parameter thinly covered.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Read volatile, mutable guest output once at explicit independent stdout_offset and stderr_offset byte positions') and immediately bounds the scope with what it does NOT do (no refresh, resume, cursor movement, retry, tail, capture, replay). An agent can distinguish it from exec_poll, get_execution and read_result_output from this text alone.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit exclusions are given ('Unsuitable for passive Activities/history', 'does not refresh activity... change shared PID cursors') plus recovery guidance: a 409 with the output_unavailable marker is final, without it a later read at the same offsets can succeed, and re-running the command will not recover output. That is when-to-use, when-not-to-use, and what to do on failure.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_fileGet a file out of the guestA
Idempotent
Inspect

Read a file from inside the computer. Text comes back as text and images come back as images; anything else comes back base64. A large file comes back a window at a time rather than filling the conversation: offset says where the window starts, and the note under a truncated read gives the exact offset to pass next. There is no size a file can be that makes it unreadable this way — a 2 GB log is pages, not a refusal — but a file you want whole is still better pushed out of the guest than carried through a conversation, and the note says how. This reaches the guest agent to do it, so a suspended computer is resumed to answer and that resume consumes running capacity — it can even come back 402 — unless no_wake is set, which refuses instead. read_clipboard, by contrast, refuses a suspended computer rather than starting it.

NameRequiredDescriptionDefault
pathYesAbsolute path inside the guest.
offsetNoByte offset to start at. 0 is the beginning of the file. Each call returns a window from here, and the truncation note names the offset of the byte after the last one it returned — pass that to read on. Never assume a window covers what you asked for: read the offset out of the note rather than adding a fixed number.
no_wakeNotrue: do not resume a computer that is not running — refuse instead (409), so nothing is resumed and no running capacity is consumed. Use it to look at a suspended computer’s files only if it is already awake. false (the default) resumes a suspended computer to answer, which consumes running capacity.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the idempotent/non-destructive annotations: it discloses that reads go through the guest agent, that a suspended computer is resumed at a cost in running capacity and can return 402, that no_wake refuses with 409, and that truncation yields a note carrying the next offset. This is exactly the operational context an agent needs before calling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose and return shapes, then pagination, then the wake economics. All sentences earn their place, though the rhetorical flourishes ('a 2 GB log is pages, not a refusal') add length without adding decision-relevant facts.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the full burden of explaining return values — and it does, covering text/image/base64 encoding, windowed reads, and the truncation note. Combined with the resume and capacity caveats, an agent has everything needed to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 100%, so the baseline is 3, but the description adds interpretive value on top: it frames `offset` as a window start and warns against assuming a window covers the request or adding a fixed number, and it ties `no_wake` to the resume/refusal tradeoff. It reinforces rather than merely repeats the schema text.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Read a file from inside the computer') and immediately characterizes the result shapes (text, image, base64), which lets an agent separate it from write_file, list_directory, and read_clipboard without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a clear context for use and an explicit exclusion — a file wanted whole should be 'pushed out of the guest rather than carried through a conversation', which is a genuine routing rule. It also names read_clipboard as the contrasting tool for suspended computers, though the transfer alternative is left unnamed among ~80 siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_result_outputRead an independent retained byte pageA
Read-onlyIdempotent
Inspect

Read one passive retained stdout, stderr or diagnostic page at an explicit offset. Default 4096/max 16384 bytes. EOF concerns this immutable prefix, not task completion. Lossless UTF-8/BOM or exact base64; no guest read, shared cursor, implicit capture, iteration or replay.

NameRequiredDescriptionDefault
limitNo
offsetYes
streamYes
result_idYes
computer_idNoComputer, or the current use_computer selection.

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the read-only/idempotent/non-destructive profile, and the description adds real behavioral context beyond them: 'EOF concerns this immutable prefix, not task completion' and the 'no shared cursor, implicit capture, iteration or replay' boundaries. It also hints at the return encoding (UTF-8/BOM or base64).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Dense and front-loaded: the action and scope lead, then terse operational constraints. Jargon-heavy but nearly every clause carries information, so little is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the return burden and does so reasonably ('Lossless UTF-8/BOM or exact base64', EOF semantics). It is fairly complete for a paged reader, though the computer_id/result_id semantics remain unaddressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 20%, so the description must compensate. It does clarify stream choices and the limit default/max, but those already exist in the schema, and it says nothing about result_id format or the computer_id fallback to the current use_computer selection.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: read one retained stdout/stderr/diagnostic page at an explicit offset. The 'passive retained ... immutable prefix' framing distinguishes it implicitly from live-output siblings like read_execution_output, but no sibling is named directly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the subject (retained pages) and by contrastive clauses ('no guest read, shared cursor, ... iteration or replay'), but there is no explicit when-to-use or routing to an alternative such as get_result or read_execution_output.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_signalsRead one passive platform signal pageA
Read-onlyIdempotent
Inspect

Read finite daemon facts without waking the computer, guest contact, event socket, watcher, capture or polling loop. Omit since or send empty for a head-only baseline with no replay; neither a baseline nor gap proves no earlier activity or task success. Keep the returned cursor even on an empty page: filtered-out rows can advance it. Retention is ephemeral, and resets are explicit gaps.

NameRequiredDescriptionDefault
limitNo
sinceNo
computer_idNoComputer, or the current use_computer selection.

TDQS

A3.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover readOnly/idempotent/non-destructive, but the description adds substantive context beyond structured data: retention is ephemeral, filtered-out rows can advance the cursor, keep the cursor even on empty pages, and a baseline/gap does not prove absence of earlier activity. These caveats materially change how an agent interprets results.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four dense sentences, front-loaded with the passive/no-wake scoping that most distinguishes the tool, then cursor and retention caveats. Every sentence carries information, though the first sentence's list of exclusions is somewhat run-on.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description should carry more of the return-shape burden. It mentions a returned cursor and page framing, but never says what a 'signal' row contains or how paging terminates, so an agent knows how to call it but only partially what to expect back.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 33% (only computer_id documented), so the description must compensate. It explains the semantics of since (omitting it yields a head-only baseline with no replay) but says nothing about limit or its 1-100 bounds, leaving one of three parameters undocumented in both places. Partial compensation only.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource (read finite daemon 'signal' facts, one page) and explicitly distinguishes itself from the active mechanisms nearby: no waking the computer, guest contact, event socket, watcher, capture or polling loop. That contrast against wait_for_event/poll_events is real differentiation. The jargon 'daemon facts' is a bit opaque, but the read/passive-page intent is clear.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives a conditional for one parameter ('omit since or send empty for a head-only baseline with no replay'), which is actionable. However, there is no explicit when-to-use/when-not guidance versus siblings such as poll_events, list_activities, or get_activity, so the agent must infer that this is the passive, non-waking alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

remove_ssh_keyRemove an SSH public keyA
DestructiveIdempotent
Inspect

Remove one of your SSH keys. New connections with it are refused at once, and it is removed from the computers it was written into within moments, and any session opened with it is closed as each computer receives the new key list. Only a key bound to the account this API key acts on, one list_ssh_keys marks "this account only", can be removed here. Any other key, one added from the dashboard ("every account") or one bound to another account ("another account only"), answers as if there were no such key, and is removed from the dashboard.

NameRequiredDescriptionDefault
key_idYesThe key id — `sshk-` and sixteen hex characters.
confirmYesMust be true. This stops the key opening connections.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare idempotentHint and destructiveHint; the description goes well beyond them by disclosing the propagation behavior (new connections refused at once, key stripped from computers within moments), the session-closing side effect, and a subtle auth/ownership constraint with a specific failure mode. This is exactly the kind of destructive-behavior detail an agent needs before calling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the purpose in the first sentence and every clause carries information. The middle sentence is a long run-on stacking three comma-linked effects, which slightly hurts readability, but nothing is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter destructive tool with no output schema, the description covers the action, its immediate and deferred effects, session termination, ownership scoping, and the ineligible-key failure mode. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with key_id format (`sshk-` + 16 hex) and the confirm const already documented in the schema. The description contextualizes which key_ids are valid but adds no syntax or format detail beyond the schema, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ("Remove one of your SSH keys") and immediately distinguishes itself from siblings add_ssh_key and list_ssh_keys. An agent knows exactly what this does and the ownership scope it applies to without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly defines the condition for a successful call (only keys bound to the acting account, marked "this account only" by list_ssh_keys) and the outcome for ineligible keys. It references the sibling list_ssh_keys for identification but never names the add/list tools as the alternative path, so the routing is clear but not fully spelled out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

rename_workspaceRename a workspaceA
Idempotent
Inspect

Rename a workspace. Its id does not change, so the API keys confined to it and the computers in it are untouched. The name follows create_workspace's rules; a name the account already uses is refused with 400, and an id this key cannot see is not found. Needs an owner's key that is not confined to a workspace: a member, a viewer, or any key confined to a workspace is refused with 403 — relay that rather than retrying.

NameRequiredDescriptionDefault
nameYesThe name: 1 to 40 characters once trimmed, no control characters, unique within the account.
workspace_idYesThe workspace id (wsp-…), from list_workspaces or a computer's workspace_id.

TDQS

A4.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=false and idempotentHint=true, so the mutation and idempotency profile is covered structurally. The description goes well beyond that, disclosing that the workspace id is stable, that API keys confined to it and its computers are untouched, and the exact HTTP failure semantics (400 for a duplicate name, 403 for insufficient key scope, not-found for an invisible id) — genuinely useful side-effect and error context not derivable from annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded in four words, and every subsequent sentence adds a distinct, actionable fact (id stability, name rules, 400, 403, not-found, retry guidance) with no filler or restatement of the tool name.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, but the description does not need one: for a simple two-parameter rename it covers side effects, authorization prerequisites, error semantics, and the correct agent response to each failure. Nothing an agent needs in order to invoke this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so both parameters are already documented, including the name length/character/uniqueness rules and the workspace_id source ('wsp-…, from list_workspaces'). The description adds only a cross-reference to create_workspace's naming rules, which is marginal value on top of a fully documented schema, so the baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence names a specific verb and resource ('Rename a workspace'), and the following clauses immediately distinguish it from create_workspace ('the name follows create_workspace's rules') and clarify scope ('its id does not change'). An agent can tell this apart from sibling tools like create_workspace, delete_workspace, or move_computer_to_workspace without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states the when-not conditions explicitly: a member, a viewer, or any workspace-confined key is refused with 403, and it goes further with an operational directive — 'relay that rather than retrying' — which prevents a wasteful retry loop. Duplicate-name (400) and not-found cases are also spelled out, so the agent knows which failures are terminal versus retryable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

replace_secretReplace a secret's valueA
Destructive
Inspect

Replace a stored secret's value, and move its revision_id. Send the revision_id list_secrets or get_secret answered: if it has moved since, this is refused with 409 and nothing changed — read it again, and replace again only if you still mean to. The new value is NEVER shown back. Owners only. Every start and restart delivers each secret's latest value. Separately, when a secret's value is replaced on a running computer: a secret bound as a FILE has that file rewritten in place within seconds; one bound as an ENVIRONMENT VARIABLE, on an image that supports it, reaches new shells within seconds, and every exec — plain or with desktop: true — runs with the bound variables as they are at that moment, so the next exec sees the new value; programs already running — the desktop session among them — keep the value they started with until a restart (older images wait for the restart). A file newly bound or renamed waits for the restart either way. That live send is asynchronous and best effort: this answer does not wait for it or say whether it landed, and a running computer may still hold the old value until its next start or restart, which always delivers the latest. get_computer's secrets_pending says whether one is still missing the change.

NameRequiredDescriptionDefault
valueYesThe new value, as text: 1 to 4096 bytes of UTF-8. Sent to the platform once, encrypted there, and never shown again — not in this tool's answer, not by any other tool, not by any route.
secret_idYesThe secret — `csec-` and sixteen hex characters, from list_secrets.
revision_idYesThe `revision_id` list_secrets or get_secret answered for this secret — `csr-` and twenty-four hex characters. A stale one is refused and nothing changes.
workspace_idNoThe workspace the secret belongs to. Leave it out for an account-wide secret. A secret in a workspace is found only with its workspace_id.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Far exceeds the annotations (destructiveHint/idempotentHint): it discloses the 409-on-stale-revision refusal with 'nothing changed', that the value is never shown back, the owner-only authorization, and the asynchronous best-effort live propagation semantics for file- vs environment-variable bindings. It even points to get_computer's secrets_pending to detect a pending change.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose and concurrency contract are front-loaded, but the live-propagation paragraph is a dense run-on that is longer than needed and mixes several concerns (file rewrites, env-var delivery, running programs, older images) in one block.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive, non-idempotent mutation with no output schema, the description covers prerequisites, error behavior, the retry loop, the never-shown-back guarantee, and async propagation limits plus how to verify pending state. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents all four parameters, but the description adds workflow meaning: why revision_id must be fresh and what happens when it is stale. This goes beyond restating the field names.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Replace a stored secret's value') and distinguishes itself from siblings by its revision_id concurrency contract, which set_secret/create_secret do not share. An agent can tell it apart from get_secret/list_secrets/delete_secret immediately.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a clear operational protocol: read the revision_id from list_secrets or get_secret, retry after a 409 only if you still mean to, and states the prerequisite 'Owners only.' It stops short of naming when to prefer this over the sibling set_secret, so it is clear context without explicit alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

restart_computerRestart a computerAInspect

Reset the computer, like the reset button — not a fresh boot, so a change that needs a new machine shape (a resize) needs a stop and a start instead. A suspended computer is refused with 409: start it to resume, or stop it to discard the session. A stopped computer with no secrets bound is started instead; one with secrets bound is refused with 409 while stopped (start it, which delivers them) or while its secrets are being delivered, and otherwise gets its secrets again as it comes back up, a few seconds after it reads running: wait_for_computer with until="guest" waits for them where the platform reports that redelivery, and where it does not, a command run in those seconds can see them unset. A restart issues new desktop credentials and closes open desktop connections, so a get_desktop_url link from before it stops working.

NameRequiredDescriptionDefault
computer_idNoWhich computer. Defaults to the one selected with use_computer.
idempotency_keyNoOptional. Omit it on a first attempt: a fresh key is sent for you, and an answer that is lost names it. Pass the key such an answer named to send the SAME call again without it being done twice — the platform answers with the first call's result, or says it is still running. After a 5xx that names no operation_id, send the same call again with the same key: nothing may have been done, and the platform either carries it out (the key was released) or answers idempotency_outcome_unknown. After idempotency_outcome_unknown, or a 5xx that names an operation_id, the key is spent (resending with it answers idempotency_outcome_unknown). A restart cannot be seen in get_computer (it reads running before and after one), so do not read the computer to decide: read get_operation with the operation_id the error named, or list_operations with the key. Succeeded means the restart happened; running means wait on it. Anything else leaves it possibly done, so ask the user before sending it again with a new key, or none — a second restart resets the guest again. Keys last 24 hours; the same key with different arguments is refused.

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so richly: 409 conditions per state, the auto-start fallback for stopped computers, secret redelivery timing (and the window where secrets can appear unset), the fact that it issues new desktop credentials and closes open desktop connections, and that a prior get_desktop_url link stops working. That is exactly the side-effect disclosure a mutation tool needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core semantic is front-loaded, but the rest is a single dense paragraph with a multi-clause run-on covering the stopped/secrets-bound cases, which is hard to parse under time pressure. Most sentences earn their place informationally, but the structure does not.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a stateful mutation tool with no annotations and no output schema, this covers state transitions, error codes, secret redelivery timing, desktop credential invalidation, and where to verify the outcome (get_operation / list_operations). Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% — computer_id and idempotency_key are both fully documented in the schema, including the elaborate idempotency contract. The description adds no parameter-level meaning beyond that, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a precise verb+resource and an analogy that pins down scope: 'Reset the computer, like the reset button — not a fresh boot.' It explicitly distinguishes restart from stop/start (a resize needs a stop and a start) and from the state-transition siblings, so an agent can route without opening other schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear conditional routing: use stop+start for shape changes, start a suspended computer to resume, stop it to discard the session. It covers when the call is refused and what to do instead, though it never states the plain 'use this when you want to reset guest state' case as directly as it states the exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

restore_snapshotRestore a snapshotA
Destructive
Inspect

Put a snapshot back onto the computer it came from, discarding everything on that disk since. Check restore_available in list_snapshots first: where it is false, the snapshot's usable copy is on a host its computer has left, and a restore is refused while clone_snapshot still works. Refused on an orphaned snapshot — clone_snapshot is what works there. It leaves the computer RUNNING whatever state it was in: restoring a stopped one boots it, which is a start like any other and consumes running capacity. A disk snapshot comes back to a fresh boot, a memory one to the captured session, and either way a suspended session the computer was holding is discarded with the disk it was saved against.

NameRequiredDescriptionDefault
confirmYesMust be true. This overwrites the source computer's current disk.
snapshot_idYes
idempotency_keyNoOptional. Omit it on a first attempt: a fresh key is sent for you, and an answer that is lost names it. Pass the key such an answer named to send the SAME call again without it being done twice — the platform answers with the first call's result, or says it is still running. After a 5xx that names no operation_id, send the same call again with the same key: nothing may have been done, and the platform either carries it out (the key was released) or answers idempotency_outcome_unknown. After idempotency_outcome_unknown, or a 5xx that names an operation_id, the key is spent (resending with it answers idempotency_outcome_unknown), and the call may still be under way: read its operation first (get_operation with the operation_id the error named, or list_operations with the key), wait while it is pending or running and do not resend meanwhile, and send the call with a new key (or none) only once the operation is final as failed or not found AND get_computer shows the step did not happen. Keys last 24 hours; the same key with different arguments is refused.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Although destructiveHint=true already warns of destruction, the description adds materially: it says everything on the disk since the snapshot is discarded, defines refusal conditions, and explains that the computer is left running and may consume running capacity if a stopped one is booted. It also discloses disk-vs-memory snapshot behavior and that a held suspended session is discarded.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core action and then layers preconditions and side effects in a logical order. It is dense and useful, but the orphaned-snapshot/clone_snapshot point is repeated in slightly different words, costing some conciseness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive, state-changing restore operation, the description covers legality checks, refusal alternatives, disk and memory outcomes, and running-capacity side effects. Since no output schema exists and idempotency details are carried by the schema, the remaining omissions are not material.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema describes confirm and idempotency_key, but snapshot_id has no schema description. The prose implies snapshot_id is a snapshot tied to the originating computer but adds no format, lookup, or idempotency detail beyond what the schema already provides, so with 67% schema coverage this is minimally adequate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource — putting a snapshot back onto its source computer — and makes clear it overwrites changes since the snapshot. It also distinguishes the operation from clone_snapshot and list_snapshots, so an agent can identify it without reading sibling schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit pre-check: inspect restore_available in list_snapshots first. It then spells out what to do when restore is refused, including the orphaned-snapshot case and the fact that clone_snapshot is the working alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

retain_execution_outputRetain an explicit execution output versionAInspect

Capture one immutable prefix version from volatile guest output by stable execution_id. Explicit guest I/O; never resumes, retries or replays a command. Each call creates a separate version. Capture may commit even if its response is lost. Default 1 MiB per stream/max 4 MiB and default 86400s/max 604800s retention; diagnostics separately capped 64 KiB.

NameRequiredDescriptionDefault
computer_idNoComputer, or the current use_computer selection.
execution_idYes
retention_secondsNo
max_bytes_per_streamNo

TDQS

A3.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds substantial context beyond the annotations: 'Each call creates a separate version' reinforces the non-idempotent write, and 'capture may commit even if its response is lost' warns about uncertainty on retry after failure. Retention/byte limits and the separate 64 KiB diagnostics cap are disclosed operational constraints an agent needs before calling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Dense but front-loaded: the core action leads, followed by behavioral caveats and then the limit figures. Every sentence carries information, with only minor jargon overhead.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a non-idempotent write with no output schema, the description covers the key risks (per-call versioning, response-loss commit, retention ceilings). It omits what the response contains or how the retained version is later retrieved, but the safety-critical context is present.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 25% (just computer_id documented), so the description must compensate, and it does provide defaults and maxima for retention_seconds and max_bytes_per_stream that the schema lacks. However, execution_id and computer_id semantics are not elaborated, leaving half the parameters thin.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (capture) and resource (an immutable prefix version of execution output) keyed by execution_id, which distinguishes it from read_execution_output/get_execution. It is somewhat jargon-heavy ('prefix version', 'volatile guest output') and never names a sibling, but the core action is clear.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clarifies what the tool is NOT ('never resumes, retries or replays a command') but gives no positive when-to-use guidance and never mentions alternatives like read_execution_output, so the agent must infer selection criteria from the sibling list alone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

retire_templateRetire a template you publishedA
Destructive
Inspect

Stop a template resolving, and give its row back against your ceiling. WITHOUT version THIS RETIRES EVERY VERSION OF THE NAME — that is what retiring a template means here, and it is deliberately not get_template's "the newest". Pass version to take exactly one. THIS CANNOT BE UNDONE: a retired ref is refused for ever, identical bytes included, so the version you retire can never be published again — publish the next version instead. Computers are NOT affected: a computer is built from the image the ref resolved to and holds no reference to the document, so anything already running, stopped or suspended keeps working. What a retire breaks is resolution — a NEW create naming the ref is refused. Needs an account-wide key: a key confined to a workspace is refused (403) whatever it names. Say what it costs before you call it.

NameRequiredDescriptionDefault
nameYesThe template name, without the namespace or the version.
confirmYesMust be true. Retiring cannot be undone, and without `version` it takes every version of the name.
versionNoA specific MAJOR.MINOR.PATCH. Send it or omit it entirely — an empty string is refused, because omitting it does not mean the same thing on both tools.
namespaceYesThe account id the template is published under. READ IT OFF A `ref`: every row of list_templates carries one shaped `<namespace>/<name>@<version>`, and the part before the slash is the namespace. Rows reading `system` are the templates we publish; anything else is your own account id. There is no separate `namespace` field on a template — the ref is where it lives.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds substantial context beyond the destructiveHint/idempotentHint annotations: the retirement is permanent, a retired ref is refused forever even for identical bytes, existing computers keep running, only new creates naming the ref break, and an account-wide key is required (workspace-scoped key gets 403). This is a rich behavioral disclosure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core effect and the dangerous default, but the ALL-CAPS emphasis and a somewhat sprawling final sentence about auth add length. Every sentence still carries information, so restructuring rather than trimming is the only issue.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a destructive, irreversible, account-wide-required operation with no output schema, the description covers effect, irreversibility, scope of impact, and authorization requirements — everything an agent needs to call it safely.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and each param already carries a description, so the baseline is 3. The description nonetheless adds the key nuance that omitting version retires every version (reinforcing the destructive default) and explains the all-versions semantics that the confirm/version params hinge on.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Names a specific verb+resource (retire a template), states the precise semantic (stop resolving, free the ceiling row), and explicitly distinguishes itself from get_template's "the newest" resolution behavior. The all-versions-by-default semantics make the distinction from siblings unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explains the version/omit distinction, tells the agent the operation is irreversible and to publish the next version instead, and notes computers are unaffected. It does not name an explicit alternative tool for each case (e.g. publish_template routing is implied rather than stated), which keeps it below a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

rotate_webhook_secretRotate a webhook’s signing secretAInspect

Mint a new signing secret for a subscription. THE ANSWER CARRIES IT ONCE, like create_webhook. The old secret goes on being honoured for 24 hours — every delivery in that window carries two signatures on the one webhook-signature header, new first, so a receiver that accepts either passes throughout — which is the window to get the new one deployed. Rotating again inside it replaces the previous secret rather than keeping three. Do this when a secret has leaked or when whoever held it has moved on.

NameRequiredDescriptionDefault
webhook_idYesThe subscription id — `whk-` and sixteen hex characters.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations exist, so the description carries the full burden and does so unusually well: the answer carries the new secret exactly once (like create_webhook), the old secret is honored for 24 hours with both signatures on the webhook-signature header, and rotating again inside the window replaces rather than triples. These are non-obvious, high-stakes behaviors an agent must know.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Dense but front-loaded: the once-only secret warning leads, followed by the 24-hour dual-signing window, then the re-rotation caveat, then the trigger. Every sentence earns its place though the long em-dash clause takes effort.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Everything an agent needs is present: what is produced, how many times it can be retrieved, the grace period and dual-signing mechanics, re-rotation semantics, and when to invoke it. No output schema exists, but the description covers the return behavior explicitly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only one parameter, and schema coverage is 100% with the format spelled out ('whk-' plus sixteen hex characters). Description adds no new parameter detail beyond the schema's own documentation, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States the specific action (mint a new signing secret) and the resource (a webhook subscription's signing secret), and distinguishes itself from the sibling rotate-adjacent tools by naming the exact effect (replaces signing material for the subscription). No sibling does this, so the boundary is unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use triggers — 'when a secret has leaked or when whoever held it has moved on' — plus the operational window for deploying the new secret. This is exactly the kind of selection guidance an agent needs.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

screenshotScreenshot the desktopA
Read-only
Inspect

A picture of the screen, returned as an image with its capture name and original size when available. Fresh by default; give capture to crop the earlier frame you measured. Full-size capture pixels are the coordinates click, drag and scroll take; cropped or scaled pictures include a mapping. A saved frame of a suspended computer (served with fresh: false) is labelled as one: a downscaled picture of the screen as it was, not in click coordinates.

NameRequiredDescriptionDefault
freshNoSkip the platform's frame cache, which serves any capture under 1.5s old — up to 30s old while the computer is busy with another operation. True by default unless capture is given; fresh: true and capture cannot be combined. After a click, a cached frame can predate the action entirely. A new capture needs a computer that is awake, so on a suspended one this is refused rather than answered — pass false without capture to ask for the last saved frame instead, which is refused in turn when there is no saved frame to serve. A saved frame answers "what was on the screen" and cannot answer "did my click land".
scaleNoShrink the picture by this factor, greater than 0 and at most 1: 0.5 halves both sides, a quarter of the pixels. Not with width. Divide a position in the smaller picture by this before clicking there.
widthNoScale the image down to this width before returning it. The coordinates you click with are still the full-size ones, so only use this to save context, and do your pointing on a full-size frame.
formatNopng (the default) or jpeg (the default with width). A JPEG is much smaller for the same picture.
regionNoCrop to this rectangle of the capture. x, y, width and height are full-size capture pixels, measured before any scaling; use the returned capture size, which can differ from the computer record's resolution. Give capture to pin the crop to the frame you measured. A region outside it is refused rather than clipped. The picture that comes back starts at (0, 0), so add x and y to a position in it before clicking there.
captureNoReuse the capture name returned by an earlier screenshot of this computer, so a region is cut from the frame it was measured on. Omit fresh or set it to false. If the capture is no longer held, take a new screenshot without capture and remeasure the region; never reuse the old crop on an unseen frame.
qualityNoJPEG quality, 1 to 100 (72 when not given). A JPEG only: pass format: jpeg with it.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond readOnlyHint, it discloses many behavioral traits an agent could not infer: caching, that a cached frame can predate a click, that a fresh capture is refused on a suspended computer, and that a saved frame is downscaled and not in click coordinates. These are exactly the operational traps an agent needs to know.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is dense but front-loaded, leading with what is returned before moving to fresh/capture and coordinate mapping. The final sentence is somewhat run-on, but every sentence carries operational meaning rather than filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With 8 parameters, a nested region object, and no output schema, the description still covers the return shape (image plus capture name and size), caching, coordinate mapping, and the suspended-computer case. It is close to complete; only minor gaps remain about how the capture name should be surfaced for reuse.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is already 100%, so the baseline is 3, but the description adds cross-cutting meaning not in the schema: full-size capture pixels are the coordinates used by click, drag and scroll, and cropped or scaled pictures include a mapping. This adds value beyond the per-parameter descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence states it returns a picture of the screen as an image with its capture name and size, which clearly anchors the resource and action. It is specific about the operation and the coordinate semantics, though it never explicitly names a sibling or contrasts itself with anything else, so ambiguity with other tools is minimal but not addressed.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives concrete conditions: fresh by default, pass capture to crop a previously measured frame, and pass fresh:false on a suspended computer to get the last saved frame. These are real when-to-use rules, but there is no explicit statement of when NOT to use this tool versus alternatives, so it stops short of 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

scrollScrollAInspect

Turn the wheel. With no coordinate it scrolls whatever is under the pointer; with one it scrolls what is at that point.

NameRequiredDescriptionDefault
xNoLeave x and y out to act where the pointer already is. Both or neither — half a coordinate is refused rather than completed with a zero.
yNo
amountNoWheel clicks.
contextNoAnswer the desktop's windows, and which one has focus, as they stand just after the action — what list_windows would say, without a second call — and, when the focused window is Chromium, the page on screen: its URL, title and the interactive elements visible in it, each with the point to click. Read at once, so a window still opening may not be listed yet. If they cannot be read the action still happened, and the answer says why.
directionYes
modifiersNoKeys held down for the duration of the action.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full disclosure burden; it usefully explains that omission of coordinates means 'act where the pointer already is', which is real behavioral content about target selection. It says nothing about the action being an input/mutation on the remote desktop, about the amount of movement, held modifiers, or what comes back — those live only in the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, zero filler, with the core action front-loaded and the conditional targeting rule immediately after. Nothing could be cut without losing meaning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 7-parameter input-interaction tool with no annotations and no output schema, the description covers only target selection; amount, modifiers and the rich context/return-behavior option are left entirely to the schema. The schema is rich enough to carry most of that, but the absence of any safety or return-shape framing in the description leaves a gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 71%, so the schema already documents amount, context, modifiers and computer_id in detail; the description's contribution is the no-coordinate vs. with-coordinate targeting rule for x/y. That rule is slightly at odds with the schema's 'both or neither' constraint (the description says 'with one'), which introduces a small ambiguity rather than resolving it.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a concrete physical action and its resource ("Turn the wheel" / scroll), which is enough to separate it from click, drag, move_mouse and press_key without opening the schema. It stops short of naming any sibling, so the differentiation is implicit rather than explicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The two clauses describe targeting behavior (pointer position vs. explicit point), which is a usage hint, but there is no guidance on when to choose scroll over alternatives such as press_key with Page Down, and no exclusions or prerequisites such as which window must have focus.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_computer_secretsReplace a computer's secret bindingsA
Destructive
Inspect

Replace the WHOLE list of secrets a computer is bound to — not a merge: any binding left out is removed, and secrets: [] removes every binding. Each entry names a secret id and exactly one of env (the environment variable it is delivered under) or file (delivered as /run/mandala-secrets/user/files/) — at most 32 secrets, 8 of them as files, none twice and no variable or file name twice — and is recorded at that secret's latest revision unless it names revision_id, which must be the revision the computer holds now (any other revision is refused). A binding's revision is what the computer last received, never a pin: naming it only says this change keeps the value the running computer already has, so the change does not stop it being suspended. Only ids, revisions and names are sent and answered — values are NEVER shown or set here. The new bindings reach the guest at its NEXT START OR RESTART: a running computer keeps what it booted with until then, and a suspended one resumes with its old values. Every start and restart delivers each secret's latest value. Separately, when a secret's value is replaced on a running computer: a secret bound as a FILE has that file rewritten in place within seconds; one bound as an ENVIRONMENT VARIABLE, on an image that supports it, reaches new shells within seconds, and every exec — plain or with desktop: true — runs with the bound variables as they are at that moment, so the next exec sees the new value; programs already running — the desktop session among them — keep the value they started with until a restart (older images wait for the restart). A file newly bound or renamed waits for the restart either way. Binding a computer that has NO secrets yet requires it to be STOPPED: that first binding is refused with 409 while the computer is running or suspended, because a computer started without secrets cannot receive them until it starts again, and a restart does not do that. Start it afterwards to deliver them. Send version from get_computer_secrets to change only the list you read: if it changed since, this is refused with 409 and nothing changes. Also 409 while a delivery to the computer is in progress. After a change that drops a secret or moves one to another revision, a running computer cannot be suspended or memory-snapshotted until it restarts. Owners and members only; Linux computers only, and binding one for the first time needs a template whose image can receive secrets.

NameRequiredDescriptionDefault
secretsYesThe complete new list. Every binding not in it is removed; [] removes them all.
versionNoThe `version` a read answered. Sent, the change is refused (409) if the list changed since; omitted, it replaces whatever is there.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already flag destructiveHint=true, and the description adds substantial context beyond that: omitted bindings are removed, empty list removes all bindings, revision IDs are not pins, new bindings only apply at next start/restart, and 409 conditions are enumerated. These details materially help an agent avoid unintended destructive changes.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The critical replacement semantics are front-loaded and the density is justified by the operation's complexity. However, the description is a single long block with some repeated delivery-timing explanations, so it is informative but not maximally scannable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description still explains that only ids, revisions, and names are sent and answered, and it covers permissions, delivery timing, 409 failure modes, first-binding restrictions, and platform limitations. An agent has enough information to call the tool correctly and understand its operational impact.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description still adds value by clarifying constraints not present in the schema, notably the limit of 8 file-bound secrets and the 'no duplicate variable or file name' rule, plus the revised meaning of `revision_id`. It reinforces env/file exclusivity but mostly complements rather than duplicates the structured fields.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource — 'Replace the WHOLE list of secrets a computer is bound to' — and immediately distinguishes the operation from a merge. An agent can clearly tell this apart from sibling tools like get_computer_secrets and set_secret without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit usage conditions: use `version` from get_computer_secrets to make a read-modify-write safe, first-time binding requires a stopped computer, and the tool is limited to owners/members on Linux. It also explains what happens when prerequisites fail with 409, leaving little to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_computer_sshSwitch SSH on or off for a computerA
Idempotent
Inspect

Turn SSH on or off for a computer. On, the computer runs an SSH server reachable only through the platform jump host, accepting the keys of every owner and member of the account, except keys added through an API key or connected app on another account, and keys of a member whose seat is suspended; off, the server stops and open SSH sessions are closed. No restart either way. Owners and members only.

NameRequiredDescriptionDefault
enabledYestrue to switch SSH on, false to switch it off.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With only idempotentHint in annotations, the description carries the burden and delivers: reachability only via jump host, which keys are accepted and the explicit exclusions (API-key/connected-app keys on another account, suspended-seat members), that turning off stops the server and kills open sessions, and that there is no restart. This is unusually rich for a mutation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded and there is no filler, but the middle is one very dense run-on sentence packing key-eligibility exceptions. The information earns its place; the prose could be broken up for scannability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation with no output schema, the description covers effects, reversibility expectations (sessions closed, no restart), and permissions. Nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and both parameters are documented in-schema, including the use_computer default for computer_id. The description adds no parameter-level detail beyond on/off semantics, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb (turn on/off) and resource (SSH for a computer), with the scope of the toggle stated immediately. An agent can distinguish this from sibling get_computer_ssh (read SSH state) and the ssh-key tools without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Adds an authorization prerequisite ('Owners and members only'), which is real usage guidance, but never states when to prefer this over get_computer_ssh or how it relates to add_ssh_key/remove_ssh_key. Usage is implied rather than routed.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

set_secretStore or replace a secret by nameA
Destructive
Inspect

Make a name hold a value: create the secret if the scope has no secret by that name, or replace its value if it has — the one to reach for when either will do. It reads the scope first and replaces against the revision it read; names match ignoring ASCII case, as the platform keeps them unique. If the secret is created or replaced by someone else between the read and the write, it reads again and tries again, up to 3 times. The value is NEVER shown back. Owners only. A new name counts against the account's limits on secrets held and created (list_secrets reports both). Every start and restart delivers each secret's latest value. Separately, when a secret's value is replaced on a running computer: a secret bound as a FILE has that file rewritten in place within seconds; one bound as an ENVIRONMENT VARIABLE, on an image that supports it, reaches new shells within seconds, and every exec — plain or with desktop: true — runs with the bound variables as they are at that moment, so the next exec sees the new value; programs already running — the desktop session among them — keep the value they started with until a restart (older images wait for the restart). A file newly bound or renamed waits for the restart either way. NOT safe to repeat blind when the answer is lost: list_secrets says whether the change landed.

NameRequiredDescriptionDefault
nameYesWhat the secret is called, e.g. OPENAI_API_KEY. Up to 60 characters, unique in its scope. This is a label, not where the value lands: set_computer_secrets names the variable or file.
valueYesThe value, as text: 1 to 4096 bytes of UTF-8. Sent to the platform once, encrypted there, and never shown again — not in this tool's answer, not by any other tool, not by any route.
workspace_idNoThe scope to look in, and to create in. Leave it out for the account-wide secrets.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the idempotentHint=false / destructiveHint=true annotations: read-modify-write with optimistic concurrency and up to 3 retries, case-insensitive name matching, value never returned by any route, quota consumption, and detailed propagation semantics for file- vs env-bound secrets on a running computer. The "NOT safe to repeat blind" note reinforces rather than contradicts the non-idempotent annotation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded correctly with the core verb+resource in sentence one, but the body balloons: the file/environment binding propagation paragraph is tangential to invoking an upsert, and "never shown again" duplicates the value field's schema text. Much of the length is useful, but it is longer than the task warrants.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists and the annotations only cover safety, yet the description supplies everything an agent needs: authorization scope, retry/conflict behavior, quota effects, and how to confirm the change landed via list_secrets. Nothing material for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents name/value/workspace_id; baseline is 3. The description adds genuine meaning on top — names match ignoring ASCII case, and the platform keeps them unique — which helps the caller reason about collisions beyond what the field descriptions state.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence states a precise verb+resource: create the secret if the name is absent, replace its value if present — an upsert. It also marks itself as the tool to pick over the narrower create/replace siblings ("the one to reach for when either will do"), so an agent can distinguish it without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear routing (prefer it when either create or replace would work), a prerequisite ("Owners only"), and a verification path via list_secrets. It stops short of naming create_secret/replace_secret explicitly as the alternatives it is contrasted against, so the selection guidance is strong but not fully explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

snapshot_holdingsWhat a computer would leave behindA
Read-only
Inspect

How many snapshots a computer has, what they weigh, and the fingerprint that names that exact set. Read this before purging snapshots with delete_computer: the fingerprint is what binds the purge to the snapshots you were shown, so one that arrived after you looked cannot be swept up in it.

NameRequiredDescriptionDefault
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

readOnlyHint=true already establishes the safe-read profile. The description adds genuinely new behavioral context beyond the annotation: the fingerprint acts as an optimistic-concurrency token binding the eventual purge to exactly the snapshots observed, so late-arriving snapshots are excluded. That is valuable and non-obvious. Return shape and error behavior are still unstated.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with what is returned and followed by the reason to call it. No filler; the 'what they weigh' phrasing is colorful but compact. Every sentence carries information an agent needs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description must describe the return contents, and it does: count, sizes, and fingerprint. Combined with the read-only annotation and the stated pre-purge workflow, an agent has enough to call and interpret this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There is a single parameter (computer_id) at 100% schema coverage, and the schema already documents that it defaults to the computer selected via use_computer. The description mentions only 'a computer' generically, adding no syntax, default, or format detail beyond the schema. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific resource and output: snapshot count, their sizes ('what they weigh'), and a fingerprint identifying that set. This is clearer than the opaque name 'snapshot_holdings' or the poetic title. However, it never distinguishes itself from the sibling list_snapshots, which an agent could easily confuse it with.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit precondition: 'Read this before purging snapshots with delete_computer,' naming both the trigger action and the tool involved. That is strong routing guidance. It does not, however, say when NOT to use it or clarify the relationship to list_snapshots, so it falls short of full alternative coverage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

snapshot_scheduleRead or set the nightly snapshotAInspect

When the platform takes this computer's automatic snapshot. Reading takes no arguments; setting takes an hour. There is deliberately no "last run" here — snapshots carry real capture times, and that is what a freshness check should read. This says when they are TAKEN and not how long they survive: get_retention is the other half, and it is what tells you whether the snapshots this schedule takes will still be there next month.

NameRequiredDescriptionDefault
setNoOmit to read the current schedule. Include to replace it.
clearNoRemove the schedule entirely.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations the description carries the burden, and it does disclose a genuinely non-obvious behavior: there is deliberately no 'last run' field, and capture times are the correct freshness signal. It also scopes itself ('says when they are TAKEN, not how long they survive'). It stops short of disclosing that `set` replaces the existing schedule and `clear` removes it entirely, so the mutation-safety profile is left to the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose is front-loaded in the opening sentence and the guidance follows cleanly. The get_retention pointer is slightly redundant and editorially padded ('that is what a freshness check should read', 'will still be there next month'), but nothing is off-topic.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 3-parameter, no-output-schema, no-annotation tool the description covers purpose, both modes, and the conceptual boundary with get_retention. It omits any note on the write semantics of `set`/`clear`, which is the main remaining gap an agent would want before mutating the schedule.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all three parameters (including the nested set object, tz/hour/minute/enabled) are already fully documented, giving a baseline of 3. The description only adds that setting requires an hour, which the schema already marks as required; it contributes no extra syntax or format detail.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first sentence names the specific resource — the platform's automatic snapshot schedule for this computer — and the title frames both modes (read/set). It explicitly distinguishes itself from the closely-named sibling `get_retention`, so an agent can tell the two apart without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states the two invocation modes and their cost ('Reading takes no arguments; setting takes an hour') and routes the agent to the alternative with the condition that selects it: `get_retention` answers how long snapshots survive. Explicit when-to-use plus a named alternative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

start_computerStart a computerBInspect

Boot a computer, or resume a suspended one — a resume restores the saved session, same processes and windows, in about a second. A resumed guest's clock is set to the current time within a few seconds, best effort through its guest agent (one whose agent does not answer keeps the old time until NTP corrects it), and the desktop panel's clock can show the old time for up to a minute after that.

NameRequiredDescriptionDefault
computer_idNoWhich computer. Defaults to the one selected with use_computer.
resume_onlyNoResume a saved session only, never boot. On a suspended computer it resumes as usual; on a stopped computer with no saved session it SUCCEEDS WITHOUT BOOTING anything, so read get_computer afterwards to see which happened.
idempotency_keyNoOptional. Omit it on a first attempt: a fresh key is sent for you, and an answer that is lost names it. Pass the key such an answer named to send the SAME call again without it being done twice — the platform answers with the first call's result, or says it is still running. After a 5xx that names no operation_id, send the same call again with the same key: nothing may have been done, and the platform either carries it out (the key was released) or answers idempotency_outcome_unknown. After idempotency_outcome_unknown, or a 5xx that names an operation_id, the key is spent (resending with it answers idempotency_outcome_unknown): read get_computer (and get_operation when the error named an operation_id: succeeded means it happened, running means wait on it, pending alone is no reason to wait), and if the step did not take effect, send the call again with a new key, or none. Keys last 24 hours; the same key with different arguments is refused.

TDQS

B3.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden, and it does add real behavioral detail: resume restores the saved session with the same processes and windows in about a second, and the guest clock is corrected best-effort via the guest agent with visible panel lag. But it omits core operational facts — required prior state, whether the call blocks or returns an operation, what to call afterwards (wait_for_computer/get_computer) — and spends most of its words on clock minutiae rather than the primary outcome.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is a single front-loaded sentence, which is good, but more than half its length is a nested parenthetical about guest-agent clock correction and panel lag — detail of marginal value for selecting or invoking the tool, and it crowds out the operational facts that matter more.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema and no annotations, and while all three parameters are documented in the schema, the description leaves gaps an agent would care about: whether the call blocks, how it relates to wait_for_computer and get_computer, and what the boot path (as opposed to resume) does. Adequate but not complete for a mutation-style lifecycle tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so computer_id, resume_only, and idempotency_key are fully documented in the schema, including the important resume_only success-without-boot caveat. The description adds no parameter-level meaning at all, so the baseline of 3 is correct.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening clause names a specific verb and resource ("Boot a computer, or resume a suspended one") and immediately distinguishes the two modes, so an agent can tell it apart from suspend_computer/stop_computer/restart_computer without opening a schema. It does not, however, explicitly name any sibling or draw the boundary against restart_computer, which is the closest confusion risk.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description never states when to choose this tool over restart_computer, create_computer, or use_computer, nor what state the computer must be in. The only usage-ish content is the boot-vs-resume distinction, which is implied rather than framed as guidance, and the real conditional logic (resume_only succeeding without booting) lives in the schema, not here.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

stop_computerStop a computerAInspect

Shut a computer down: the guest is asked, and given up to 45 seconds to do it; a guest still up after that is forced off by the platform, so an ordinary stop always ends stopped and can take about 83 seconds to answer. Configure the MCP caller to allow at least 95 seconds; caller cancellation is still honored. On a suspended computer this discards the saved session, and the next start is a fresh boot. The disk is kept. force skips the asking and the 45-second wait and pulls the power at once.

NameRequiredDescriptionDefault
forceNoPull the power at once instead of asking, the way holding the button in does. Anything the guest had not written to disk is lost. It is rarely needed: an ordinary stop already forces the computer off if the guest has not shut down within 45 seconds, so `force` only saves those 45 seconds, and it takes from the guest the chance to write its data first. Leave it out unless the user wants the computer off immediately.
computer_idNoWhich computer. Defaults to the one selected with use_computer.
idempotency_keyNoOptional. Omit it on a first attempt: a fresh key is sent for you, and an answer that is lost names it. Pass the key such an answer named to send the SAME call again without it being done twice — the platform answers with the first call's result, or says it is still running. After a 5xx that names no operation_id, send the same call again with the same key: nothing may have been done, and the platform either carries it out (the key was released) or answers idempotency_outcome_unknown. After idempotency_outcome_unknown, or a 5xx that names an operation_id, the key is spent (resending with it answers idempotency_outcome_unknown): read get_computer (and get_operation when the error named an operation_id: succeeded means it happened, running means wait on it, pending alone is no reason to wait), and if the step did not take effect, send the call again with a new key, or none. Keys last 24 hours; the same key with different arguments is refused.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does it well: it discloses the guaranteed outcome ('always ends stopped'), the worst-case latency (~83 seconds, allow 95), cancellation semantics, that power is pulled by the platform after 45s, that a suspended machine's saved session is discarded and the next start is a fresh boot, and that the disk survives.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is front-loaded with the shutdown sequence and the timeout requirement, which are the two facts an agent needs before calling. The final sentence duplicates the force parameter's schema description and could be trimmed without loss.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 3-optional-parameter mutation tool with no annotations and no output schema, the description supplies everything an agent needs: duration, timeout budget, outcome guarantee, force trade-off, and the suspended-machine edge case. Nothing material about the call's effect is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the force parameter's schema text already explains the 45-second trade-off and data-loss risk, so the description's closing sentence largely restates it. computer_id defaulting via use_computer and the idempotency_key protocol are handled entirely in the schema, not the description. Baseline 3 is right when the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The definition opens with a concrete verb and resource ('Shut a computer down') and immediately scopes the operation: graceful ask, 45s grace, forced power-off after. 'The disk is kept' implicitly distinguishes it from delete_computer, and the suspended-session note separates the outcome from suspend/restart semantics.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit operational guidance for the caller (allow at least 95 seconds, cancellation is honored) and states the condition for force ('Leave it out unless the user wants the computer off immediately'). It never names siblings like suspend_computer or restart_computer as alternatives, so routing between lifecycle tools is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

suspend_computerSuspend a computerAInspect

Write the guest's RAM to disk and give the host its memory back. A pause, not a stop: start_computer resumes the same session. A computer that holds secrets suspends only on a host that seals saved sessions (its memory is encrypted on the way to disk); elsewhere, and while its secrets are still being delivered, it is refused with 409. After a change to its secret bindings that dropped a secret or moved one to another revision while it ran, it cannot be suspended until it restarts, since its memory may still hold the old value.

NameRequiredDescriptionDefault
computer_idNoWhich computer. Defaults to the one selected with use_computer.
idempotency_keyNoOptional. Omit it on a first attempt: a fresh key is sent for you, and an answer that is lost names it. Pass the key such an answer named to send the SAME call again without it being done twice — the platform answers with the first call's result, or says it is still running. After a 5xx that names no operation_id, send the same call again with the same key: nothing may have been done, and the platform either carries it out (the key was released) or answers idempotency_outcome_unknown. After idempotency_outcome_unknown, or a 5xx that names an operation_id, the key is spent (resending with it answers idempotency_outcome_unknown): read get_computer (and get_operation when the error named an operation_id: succeeded means it happened, running means wait on it, pending alone is no reason to wait), and if the step did not take effect, send the call again with a new key, or none. Keys last 24 hours; the same key with different arguments is refused.

TDQS

A4.3/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, this description carries the full burden and does so well beyond the name: it discloses the pause-vs-stop semantics, the exact refusal condition (409 for secrets on hosts without sealed sessions), the temporary refusal while secrets are still being delivered, and the persistent refusal after secret bindings changed (memory may hold the old value). These are non-obvious failure modes an agent could not infer from the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four sentences, front-loaded with the core semantic (RAM to disk, resumable) before edge cases. It is dense and the third sentence's parenthetical/conditional stacking ('elsewhere, and while its secrets are still being delivered, it is refused with 409') is slightly hard to parse, but every sentence conveys distinct, load-bearing information with no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-annotation, no-output-schema mutation tool, the description is largely complete on behavior and failure modes, and idempotency/retry handling is covered in the schema. The one gap is the success path's return shape – it never says what a successful suspend yields (an operation id or computer state), which an agent with no output schema would need.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% – computer_id's default via use_computer and the elaborate idempotency_key protocol are both fully documented in the schema itself. The description adds no parameter-level detail beyond that, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource with an unusually precise mechanism ('Write the guest's RAM to disk and give the host its memory back') and immediately disambiguates from the sibling stop_computer with 'A pause, not a stop: start_computer resumes the same session.' An agent can distinguish this from stop_computer, restart_computer and start_computer without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete conditions: it is refused with 409 when the computer holds secrets and the host does not seal saved sessions, and it cannot run at all after a secret binding change that dropped or moved a secret. It also names start_computer as the resume path. It does not explicitly contrast suspend with stop_computer in terms of when to prefer each, so it stops short of full when/when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

test_webhookSend a test deliveryAInspect

Queue one signed delivery of a synthetic webhook.test event through the ordinary path, so it is signed, retried and recorded exactly as a real one. The answer is the delivery record, ACCEPTED rather than finished: the endpoint has not been called yet when this returns. Read what it said back with list_webhook_deliveries a little later — a first attempt goes out within seconds, and a failed one is retried after 30 seconds. A disabled subscription is refused; enable it first with update_webhook.

NameRequiredDescriptionDefault
webhook_idYesThe subscription id — `whk-` and sixteen hex characters.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden and does so: it discloses the asynchronous ADD/ACCEPTED return semantics (endpoint not yet called), the retry timing (30s), and the disabled-subscription refusal precondition. This is exactly the behavioral context an agent needs to avoid misinterpreting the response.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core purpose is front-loaded in the first clause, and every sentence carries distinct information (async semantics, verification path/timing, precondition). It is dense with em-dash asides but appropriately sized for a tool with non-obvious async behavior.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description compensates by explaining what is returned (the delivery record, ACCEPTED not finished) and how to verify the eventual outcome via list_webhook_deliveries. Nothing an agent needs to call and interpret this tool correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% for the single webhook_id parameter, including the `whk-` + 16 hex format, so the schema already documents it fully. The description adds no additional format or constraint detail beyond what the schema provides, making the baseline 3 correct.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Queue) and resource (one signed delivery of a synthetic webhook.test event) and clarifies it takes the ordinary path so real signing/retry/recording applies. It directly addresses what distinguishes it from siblings like list_webhook_deliveries and update_webhook.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes follow-up to list_webhook_deliveries, states timing (first attempt within seconds, retry after 30s), and gives the precondition that a disabled subscription is refused and must be enabled with update_webhook first. When-to-use, when-to-check-results, and exclusions are all covered.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

type_textType textAInspect

Type a string into whatever has keyboard focus: literal text, 1 to 400 characters. For Enter, Tab or a shortcut, use press_key. Plain ASCII is typed as US-layout key events, about 12 ms a character, so 400 characters take about five seconds. Text containing any other character — accents, CJK, emoji — is typed WHOLE and in order by one guest helper: its ASCII as the same key presses and the rest by GTK Unicode composition. That works in Chromium (GTK3) and Xfce Terminal on a Linux X11 desktop; Firefox, GTK4 apps, native Wayland apps and Windows are unsupported for non-ASCII text, and such text is checked and refused before any key is pressed. Tab and newline are sent as keys and CRLF as one Return; a bare CR and other control characters are refused. The answer says which way it was typed. It confirms the keys were sent, not that the application accepted them: check with a screenshot before relying on it. For longer text, or non-ASCII text in an application this cannot type into, paste_text puts it on the clipboard and pastes it in one step.

NameRequiredDescriptionDefault
textYesThe characters to type, at most 400. Longer text goes in several calls, or through write_file or write_clipboard.
contextNoAnswer the desktop's windows, and which one has focus, as they stand just after the action — what list_windows would say, without a second call — and, when the focused window is Chromium, the page on screen: its URL, title and the interactive elements visible in it, each with the point to click. Read at once, so a window still opening may not be listed yet. If they cannot be read the action still happened, and the answer says why.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so thoroughly: ~12 ms/char timing, one-helper Unicode composition path, refusal of unsupported text before any key is pressed, Tab/newline/CRLF/bare-CR handling, and the critical caveat that success means keys were sent, not accepted, with a recommendation to verify via screenshot. This is far beyond what structured fields provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core action and size limit before the behavioral detail, and nearly every sentence conveys operational information. It is dense and long (~200 words) but justified by the breadth of environment and control-character caveats, so only minor trimming is possible.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a keyboard-input tool with no output schema and no annotations, the description covers everything an agent needs: supported/unsupported environments, size limits, control-character behavior, the meaning of success, and alternative tools. Nothing required to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so text, context and computer_id are already documented in the schema; baseline 3 applies. The description restates the 1-400 character bound and suggests write_file/write_clipboard for longer input, but adds no syntax or meaning beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (type) and resource (a string into whatever has keyboard focus) with an explicit size range, and immediately distinguishes itself from siblings by naming press_key and paste_text. An agent can select it correctly without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use-elsewhere routing: press_key for Enter/Tab/shortcuts, and paste_text for longer or non-ASCII-unsupported text. It also names the exact environments where non-ASCII typing works (Chromium GTK3, Xfce Terminal on X11) and where it does not (Firefox, GTK4, Wayland, Windows), so the agent knows when to switch tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_computerRename or resize a computerAInspect

Change a computer's name, its size, its idle window, its browser proxy, its egress proxy, or its end time. The platform refuses these in combination on purpose — a resize needs the computer stopped and the others do not, so one request cannot honour both without applying half of it. A SUSPENDED computer counts as stopped for a resize, and its saved desktop cannot survive one: the vCPU count and the memory size are part of the saved state, so it is discarded and the next start is a cold boot. Resume it and finish what is open before resizing, or say so before you do it.

NameRequiredDescriptionDefault
cpuNoNeeds the computer stopped.
nameNo
ram_mbNoNeeds the computer stopped.
disk_gbNoNeeds the computer stopped. Disks grow only.
ends_atNoWhen the computer stops by itself: at that time its host stops it, as stop_computer would, and its disk is kept; get_computer's ends_at says when, and is gone once it has fired or been cleared. It fires once. A host that cannot keep an end time answers 409 with reason unsupported. An RFC 3339 time in the future, replacing any end time it has; null clears it. Send this ON ITS OWN, and not beside ends_in_hours.
computer_idNoWhich computer. Defaults to the one selected with use_computer.
egress_proxyNoSends ALL of the computer's outbound TCP through a proxy — exec, terminals, package managers and browsers alike — taken on its host, so nothing inside the computer can opt out. There is no bypass list. It FAILS CLOSED: when the proxy is down or refuses, or its credentials have not reached the host yet (get_computer then says its egress proxy is waiting for credentials), the connection fails and nothing is sent directly. UDP to the internet and ICMP are dropped (QUIC falls back to TCP; NTP and other UDP stop working). DNS lookups are NOT proxied; they go to the platform's resolver. Connections open through the proxy are closed when the setting changes. A host that cannot take it yet — or cannot take an https:// one, or one naming credentials — answers 409 with reason unsupported; one that cannot put it into effect now answers 503, and nothing is changed unless that error says the new setting was stored. Replaces the setting whole; null removes it and the computer's traffic goes directly again. To change the server of the same proxy, start from the egress proxy get_computer returns and copy its credentials_secret_id to keep it: leaving it out removes the credentials, and the proxy then refuses every connection. Do not carry credentials_secret_id to a different server unless the user says those credentials are for that server. Send this ON ITS OWN — never beside name, a resize, idle_suspend_min or browser_proxy. A running computer has it when the answer arrives; a stopped or suspended one is given it before it starts. After any other 5xx that names no operation_id, send the setting again with the SAME idempotency_key (not a new one or none): the platform most likely refused it before sending it anywhere. After a 5xx that names an operation_id, or no answer, it may or may not have taken effect: call get_computer, and if it does not show the setting you sent, or its egress proxy names credentials and is still waiting for them after a few seconds, send the setting again — with a new idempotency_key, or none, after a 5xx that names an operation_id; with the key the answer named after no answer at all.
browser_proxyNoSends the computer's browsers (Chromium, Chrome, Firefox) through a proxy; nothing else on it uses the proxy, so exec and a terminal go out directly. Linux only. Replaces the setting whole; null removes it. To change the bypass of the same proxy, start from get_computer's browser_proxy and copy its credentials_secret_id to keep it: leaving it out removes the credentials, and the proxy then refuses the browsers. Do not carry credentials_secret_id to a different server: those credentials belong to the proxy they were set for; send a new server without it unless the user says those credentials are for that server. Send this on its own. A running computer has it within seconds — wait_for_computer with until="guest" before opening a browser that must use it — and a stopped or suspended one is given it as it starts. A browser already open picks it up at its next start.
ends_in_hoursNoWhen the computer stops by itself: at that time its host stops it, as stop_computer would, and its disk is kept; get_computer's ends_at says when, and is gone once it has fired or been cleared. It fires once. A host that cannot keep an end time answers 409 with reason unsupported. Hours from now, fractions allowed, replacing any end time it has; null clears it. Send this ON ITS OWN, and not beside ends_at.
idempotency_keyNoOptional. Omit it on a first attempt: a fresh key is sent for you, and an answer that is lost names it. Pass the key such an answer named to send the SAME call again without it being done twice — the platform answers with the first call's result, or says it is still running. After a 5xx that names no operation_id, send the same call again with the same key: nothing may have been done, and the platform either carries it out (the key was released) or answers idempotency_outcome_unknown. After idempotency_outcome_unknown, or a 5xx that names an operation_id, the key is spent (resending with it answers idempotency_outcome_unknown): read get_computer (and get_operation when the error named an operation_id: succeeded means it happened, running means wait on it, pending alone is no reason to wait), and if the step did not take effect, send the call again with a new key, or none. Keys last 24 hours; the same key with different arguments is refused.
idle_suspend_minNoMinutes untouched before the host suspends it, at most 10080 (a week). 0 disables idle suspend and pressure eviction, up to the plan's limit on computers that never suspend (a 402 beyond it). null returns it to the host's own window. Send this on its own.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With zero annotations the description carries the full burden and does it well: it discloses that a resize discards the saved desktop state because vCPU and memory are part of it, that the next start is therefore a cold boot, and that SUSPENDED counts as stopped for resize purposes. That is exactly the destructive-consequence and precondition context annotations would otherwise supply.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the field list, then the combination rule, then the consequence. Dense but almost every sentence contributes; the closing 'or say so before you do it' is the one slightly cloudy phrase.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an 11-parameter, unannotated, output-schema-less mutation tool this is well covered: preconditions, state-loss consequences, and combination rules are all present, and the remaining machinery (idempotency, per-field send-on-its-own rules, return semantics) is documented in the schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 91%, so the baseline is 3, but the description adds cross-parameter semantics the schema does not state at the top level: which fields are mutually exclusive with a resize and why. It does not touch computer_id's default or idempotency_key, which the schema already documents.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

A specific verb (change) on a specific resource (a computer) with the mutable fields enumerated: name, size, idle window, browser proxy, egress proxy, end time. An agent can tell at a glance that this is the single mutation entry point rather than stop_computer, restart_computer, or set_computer_secrets.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a real precondition: resizes need the computer stopped while the other fields do not, and the platform deliberately refuses the combination. It also advises resuming and finishing open work before a resize. It stops short of naming the sibling calls to make first (stop_computer/suspend_computer), so the routing is implied rather than explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_public_urlChange a public URL’s port or accessA
Idempotent
Inspect

Point a public URL at another port, switch it between public and private, or both. The label is the URL and does not change — delete it and create another for a new name. Fields you leave out are kept; name at least one.

NameRequiredDescriptionDefault
portNoA new port for the URL to serve, 1 to 65535 except 22, which is the computer’s own SSH. The app must listen on 0.0.0.0:<port>, not 127.0.0.1.
accessNo`public`: anyone with the link can open it; unavailable on trials. `private`: an account API key as `Authorization: Bearer` (workspace-scoped keys must match the computer), or browser sign-in through the dashboard Open button.
url_idYesThe public URL’s id — `pu-` and sixteen hex characters.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the idempotent annotation, the description discloses important behavior: omitted fields are preserved and at least one updatable field must be supplied. It does not detail permission requirements or error behavior, but the key mutation semantics are covered.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three concise sentences, front-loads the core action, and every sentence adds useful information without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a moderately simple update tool with a fully documented schema and no output schema, the description is nearly complete. It covers purpose, partial-update behavior, and the fixed-label constraint, though it omits return/error expectations.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents each parameter well. The description adds useful cross-parameter semantics: unspecified fields remain unchanged, and the caller must provide at least one of the optional update fields.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names the specific mutation (changing port and/or access) and the resource (a public URL). It also distinguishes this from rename-like behavior by stating the label cannot change and that a new name requires delete/create.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly sets the context for updating an existing public URL and explains the alternative path for changing the name. It does not explicitly name create_public_url or delete_public_url as siblings, but the decision guidance is otherwise clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_webhookChange a webhook subscriptionA
Idempotent
Inspect

Change the endpoint, the description, the filters, or whether it is enabled. Fields you leave out are kept as they are; name at least one. A new url is checked exactly as on create. enabled: true clears a disable the platform imposed for failures and starts fresh; enabled: false stops deliveries and records that you chose to. While the account’s plan includes no webhooks, enabled: true (and a new url) is refused with 402. The secret does not change — rotate_webhook_secret is for that.

NameRequiredDescriptionDefault
urlNoA new endpoint, checked exactly as on create: https, at most 2048 characters, no credentials, public address.
eventsNoEvent types to deliver: window.opened, window.closed, window.focused, window.blurred, clipboard.changed, process.exited, computer.idle, computer.ready, computer.started, computer.stopped, computer.suspended. Omit to keep the current filter; send [] to clear it to every type. file.changed is never delivered to a webhook. An unknown type is refused by the platform with the current list.
enabledNoWhether deliveries are made.
computersNoComputer ids to deliver for, up to 64. Omit to keep the current filter; send [] to clear it to every computer the key can see. Not checked against your computers — a subscription may name a computer you are about to create.
webhook_idYesThe subscription id — `whk-` and sixteen hex characters.
descriptionNoFree text for the listing, up to 200 characters.

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations supply only idempotentHint=true, so the description carries the behavioral load and does so well: it discloses partial-update retention, that a new url is validated exactly as on create, that enabled:true clears a platform-imposed disable and starts fresh while enabled:false records the user's choice, that the plan-without-webhooks case returns 402, and that the secret is untouched. No contradiction with the idempotent annotation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four dense sentences, front-loaded with the mutable fields and then the partial-update rule before the edge cases. Every clause carries information — validation, defaults, error codes, or the secret exception — with no restatement of the tool name or filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no output schema and a single weak annotation, the description covers the full decision space: what can change, what happens to omitted fields, validation behavior, the enable/disable side effects, the 402 plan gate, and the secret boundary. An agent has everything needed to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3, but the description adds real meaning beyond the schema for `enabled` (its schema text is merely 'Whether deliveries are made', while the description explains the platform-imposed-disable clearing and the 402 refusal). It adds less for url/events/computers/description, which the schema already documents in depth.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb and resource plus the exact mutable surface ('Change the endpoint, the description, the filters, or whether it is enabled'), so the agent knows precisely what this tool touches. It also names the sibling it is not (rotate_webhook_secret), which cleanly separates it from other webhook operations.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when-to-use semantics: 'Fields you leave out are kept as they are; name at least one' defines the partial-update contract, and 'The secret does not change — rotate_webhook_secret is for that' routes the agent to the alternative tool. Defaults for omitted fields and the plan-gated 402 refusal are stated outright rather than left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

use_computerSelect a computerA
Idempotent
Inspect

Bind a computer to this session, so every later call can leave computer_id out. Answers with its status and screen resolution.

NameRequiredDescriptionDefault
computer_idYesThe id from list_computers.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare idempotent/destructive hints; the description adds genuinely new behavioral context by disclosing that the binding is session-scoped and persistent across later calls, and that the response carries status and screen resolution (valuable since there is no output schema). It does not state permission requirements or behavior when the computer is stopped/absent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences: the primary effect (session binding) is front-loaded, followed by the return payload. No filler or restated boilerplate.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter, no-output-schema tool this covers what an agent needs: the state change, its scope, and the response contents. Minor gaps remain around failure modes (invalid/stopped computer, effect on prior binding).

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the schema already explains computer_id is 'The id from list_computers.' The description adds no format, validation, or sourcing detail beyond that, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific action (bind a computer to this session) plus its downstream effect (later calls can omit computer_id) and what it returns. This clearly separates it from list_computers/get_computer, which read computer data without establishing session context.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description makes the usage context clear: you call it to establish a session-level binding so subsequent calls can omit computer_id. It does not name explicit alternatives (e.g. passing computer_id per call) or when-not conditions, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

waitWaitAInspect

Pause before looking again — for a page that is still painting or an application that is still starting. Capped at 30 seconds, because a wait here is a held HTTP request and a longer one would not return, it would fail.

NameRequiredDescriptionDefault
contextNoAnswer the desktop's windows, and which one has focus, as they stand just after the action — what list_windows would say, without a second call — and, when the focused window is Chromium, the page on screen: its URL, title and the interactive elements visible in it, each with the point to click. Read at once, so a window still opening may not be listed yet. If they cannot be read the action still happened, and the answer says why.
secondsNo
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full behavioral burden, and it does disclose a real trait: a hard 30-second cap and the reason (a longer wait is a held HTTP request that would fail, not return). It stops short of describing what the call returns or whether it blocking-polls, but the cap rationale is genuinely beyond the structured data.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tightly written sentences, front-loaded with the action and its use case, and the cap rationale packed into the second. No filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no annotations and no output schema, the description should ideally explain what a wait returns (e.g., whether it surfaces refreshed desktop state). The context parameter hints at this, but the description itself leaves the return side of the contract unstated for a tool whose whole point is observing change.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 67%, with the rich 'context' description living in the schema itself. The description only reinforces the seconds maximum ('Capped at 30 seconds'); it adds no syntax or format detail beyond what the schema already carries, so the baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action (pause) and the scenarios that motivate it (page still painting, application still starting), which is clear enough for an agent to recognize. It does not, however, distinguish itself from the many other wait-family siblings such as wait_for_computer, wait_for_operation, or wait_for_event.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear context for when to reach for this tool ('for a page that is still painting or an application that is still starting'). It stops short of naming alternatives or exclusions, which matters here given the crowded wait_* sibling set.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

wait_for_computerWait for a computer to be readyA
Idempotent
Inspect

Poll until the computer is running, or until the software inside it answers. Use "guest" before exec, files or windows, and before expecting a screenshot to show a desktop rather than a boot screen; on Linux "guest" also waits until the desktop session is logged in, so exec with desktop: true is not refused as having no desktop session; on a computer with secrets bound, "guest" also waits until they have reached the desktop, so a command run next sees them, on one whose browser proxy is being set or removed it waits until its browsers have the change, and on one whose egress proxy is waiting for its credentials it waits until they arrive, since every connection the computer opens meanwhile is closed. Reports progress while it waits, so a client that sends a progressToken and sets resetTimeoutOnProgress can hold the request open; a client that cannot should lower timeout_s and call again rather than watch its own default timeout cancel the wait.

NameRequiredDescriptionDefault
untilNo"running" is the hypervisor reporting the VM up. "guest" is the software inside it answering, which is what exec and a painted desktop actually need — its desktop session logged in on Linux, and, on a computer with secrets bound, its secrets delivered, on one with a browser proxy, its browsers holding it, and on one with an egress proxy that names credentials, its host holding them. So "guest" here waits for more than waitForGuest in the SDKs, which returns once the guest agent answers.guest
timeout_sNo
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A3.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only cover idempotency and non-destructiveness; the description goes well beyond them. It discloses progress reporting, the progressToken/resetTimeoutOnProgress contract, and the fallback for clients that cannot hold the request open — exactly the operational context a polling tool needs. It also flags the hidden side effects of waiting (secrets delivered, browser proxy applied, egress credentials held).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded and every sentence carries real information, but the second sentence is a single run-on chain of proxy, secret and session clauses that is hard to parse. The progressToken paragraph is dense and could be split for readability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a polling tool with no output schema and no return-value documentation, the description never says what a successful wait yields or whether an expired timeout surfaces as an error, a state value, or a partial result. It covers the guest-state preconditions well but leaves the terminal outcome underspecified.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 67%: the 'until' enum already carries a rich description and computer_id is documented in the schema, so the description largely restates the guest-vs-running distinction rather than adding new semantics. timeout_s has no schema description and the description only mentions lowering it, never its default, bounds, or whether the timeout is client- or server-side.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence gives a specific verb and resource — 'Poll until the computer is running, or until the software inside it answers' — and distinguishes the two wait states clearly. It does not, however, differentiate itself from similarly named siblings such as wait, wait_for_operation, wait_for_event or wait_for_file_change, which an agent must disambiguate on its own.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit conditional guidance is given: use 'guest' before exec, files or windows, and before a screenshot that should show a desktop rather than a boot screen. The Linux desktop-session and secret-delivery caveats further refine when the wait is required. It stops short of saying when 'running' is sufficient or when this tool is preferable to the other wait_* siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

wait_for_eventWait for something to happenAInspect

Block until the computer reports something, instead of screenshotting in a loop to find out whether it has. This is the tool that replaces polling: a window opening, a background command exiting, the desktop coming up, the machine going idle or changing power state. Types are window.opened, window.closed, window.focused, window.blurred, clipboard.changed, file.changed, process.exited, computer.ready, computer.idle, computer.started, computer.stopped, computer.suspended, and the list grows — pass none to wait for the next thing of any kind. It returns everything that happened up to and including the match, in order, so the answer is what the computer did rather than one fact out of it. Nothing is lost between calls: this server holds the stream open across turns, so a wait that times out has missed nothing and calling again picks up exactly where it left off. That is why the timeout is short — waiting again is free. Do not use it to wait for a click to land or a page to paint: neither is an event, and a screenshot is still how you find out what the screen looks like.

NameRequiredDescriptionDefault
pidNoOnly a process.exited for this pid — the one exec with background: true handed you. Without it a wait for process.exited ends on whichever background command finishes first, which on a computer running several is usually not yours.
limitNo
sinceNoA cursor from an earlier call, to start from there instead of from where this session last read. You do not normally need it — with no cursor at all you are handed everything you have not already been given.
typesNoWait for any of these. Omit to wait for the next event of any kind. A type this computer cannot emit is refused at once rather than waited on — a guest with no window watcher will never send a window.* and this says so instead of spending your timeout.
timeout_sNoHow long to block. Capped below the 60s request timeout most MCP clients ship, because a call that outlives that is cancelled rather than answered late. Nothing is missed by a short wait: call again.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well past the annotations (destructiveHint=false, idempotentHint=false): it discloses the timeout cap rationale (below the 60s MCP client request timeout so calls aren't cancelled), that no events are lost across calls because the server holds the stream open, that the result is ordered and cumulative up to the match, and that unemittable types are rejected immediately rather than consuming the timeout. These are exactly the non-obvious behaviors an agent needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core contract and organized as mechanism, event list, return shape, stream persistence, then exclusions. Dense and nearly every sentence earns its place, though the long inline event enumeration and the 'the list grows' aside make it longer than strictly necessary.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With six optional parameters, no output schema, and a blocking/long-poll style call, the description covers return shape (ordered, everything up to and including the match), timeout semantics, cross-call continuity, and error behavior for unsupported types. Nothing material is left for the agent to guess.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 83%, so much of the parameter meaning is already structured. The description still adds useful framing — passing no types waits for anything, and the short timeout is safe because re-calling resumes exactly where the last read ended — though the limit parameter is never mentioned and the timeout rationale overlaps the schema text.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource+mechanism: block until the computer reports an event, explicitly contrasting with screenshotting in a loop. The enumeration of concrete event types (window.opened, process.exited, computer.idle, ...) makes the resource unambiguous and separates it from siblings like screenshot, poll_events, wait_for_computer, and wait_for_file_change.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

States the positive case (replaces polling, pass no types for anything) and an explicit exclusion with the remedy: do not use it for a click landing or a page painting, use a screenshot instead. That is a named when-not plus an alternative, which is the top of the scale.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

wait_for_file_changeWait for a file to changeA
Destructive
Inspect

Block until something is created, changed or deleted anywhere under a directory in the guest, instead of running ls in a loop to find out whether it has. This is how you wait for a build to write its output, a download to land, or a script to produce a file. It nominates the directory on this computer's event stream, waits until the guest is genuinely watching it, and only then waits for a change — so a timeout from this tool means nothing changed, never "nothing was watching yet". The nomination sticks: up to 4 trees stay watched across your turns, so a second call on the same path is instant and a change that happens between two of your turns is still waiting for you. Nominate the NARROWEST directory you care about. A home directory under a build is thousands of changes a second, and what you get back for one of those is a single "too much changed" marker rather than the events. It reports changes, not contents: read_file and exec are still how you find out what is in a file. A rename inside the tree arrives as a delete and a create, and nothing is announced about what was already there when you nominated it — list the directory for that.

NameRequiredDescriptionDefault
pathYesAn absolute directory in the guest, watched all the way down. Not a file and not a glob — name the directory and filter the changes yourself. A trailing slash or a . segment is cleaned away, and the cleaned form is what the events carry.
limitNo
sinceNoA cursor from an earlier call, to start from there instead of from where this session last read. You do not normally need it.
timeout_sNoHow long this call may take in total, attaching and arming included — not time spent watching, which is less and is reported back. Capped below the 60s request timeout most MCP clients ship. A call that spends it all arming says so rather than reporting a quiet directory, and nothing is missed by a short wait: the tree stays watched between calls, so call again.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations (idempotentHint=false, destructiveHint=true) by disclosing the nomination/arming model, that a timeout means nothing changed rather than nothing was watching, that up to 4 trees stay watched across turns making repeat calls instant, event coalescing under load, and rename-as-delete+create semantics. These are exactly the non-obvious traits an agent needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded in the very first clause and almost every sentence carries distinct information about semantics an agent would otherwise get wrong. It is dense as a single unbroken block rather than segmented, so it is slightly harder to scan than optimal for its length.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema and a subtle async tool, the description still conveys what comes back (events, not contents), the failure modes (timeout, coalesced marker), and cross-call state persistence. Nothing an agent needs to invoke and interpret this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 80% and the schema documents path, since, timeout_s, and computer_id, so the baseline is 3; however the description adds real meaning by explaining that timeout_s covers attaching and arming rather than pure watching, and by stressing directory-narrowing as the core selection criterion. It does not clarify the undocumented `limit` parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb (block/wait) and resource (a create/change/delete anywhere under a directory in the guest), and explicitly contrasts it with the naive alternative ('instead of running ls in a loop'). An agent can distinguish it from read_file, exec, and the various wait_for_* siblings without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives concrete when-to-use scenarios (waiting for a build to write output, a download to land, a script to produce a file) and an explicit when-not ('read_file and exec are still how you find out what is in a file'), plus a directive to nominate the narrowest directory because a busy tree yields only a 'too much changed' marker. Nothing about selection is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

wait_for_operationWait for a lifecycle operation to finishA
Read-onlyIdempotent
Inspect

Poll a lifecycle operation until it is final. Answers once it has succeeded; a failed one is an error carrying error.code and the platform's sentence (resize_not_applied is a move that landed at the old size: the computer has moved, and update_computer finishes the resize). succeeded means the platform finished its step, not that the desktop has booted: wait_for_computer is still the wait for a desktop that answers. Most operations are already final when their call answers, so this is for a clone (running until its disk is copied) or a move. Reports progress while it waits, so a client that sends a progressToken and sets resetTimeoutOnProgress can hold the request open; get_operation reads it if the wait runs out.

NameRequiredDescriptionDefault
timeout_sNoHow long to wait before handing back and letting you poll.
operation_idYesThe operation_id a lifecycle tool answered: a create, a clone, a start, stop, suspend or restart, a resize, a snapshot restore, or a move.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnly/idempotent/non-destructive), and the description layers on non-obvious behavior: a failed operation returns an error with error.code and the platform sentence, resize_not_applied has a specific 'moved at old size' meaning finished by update_computer, and 'succeeded' does not mean the desktop has booted. It also discloses progress reporting via progressToken/resetTimeoutOnProgress.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and scope are front-loaded in the first sentence, and most sentences carry distinct facts. However, the nested parenthetical on resize_not_applied ('is a move that landed at the old size: the computer has moved, and update_computer finishes the resize') is dense and slows comprehension of an otherwise tight definition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description does explain the success/error contract and progress behavior, and points to get_operation for polling. It stops short of describing the shape of a successful answer, which is the one remaining gap for a tool whose whole purpose is returning a terminal result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the schema already documents operation_id (including which lifecycle tools produce it) and timeout_s. The description only alludes to timeout behavior ('if the wait runs out') without adding syntax or format beyond the schema, so the baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb+resource: 'Poll a lifecycle operation until it is final.' It explicitly distinguishes itself from siblings by naming wait_for_computer ('still the wait for a desktop that answers') and get_operation ('reads it if the wait runs out'), so an agent can route correctly without opening other schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states when NOT to bother: 'Most operations are already final when their call answers, so this is for a clone ... or a move.' It names the fallback (get_operation) and the condition that triggers it ('if the wait runs out'), giving explicit when/when-not/alternative guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

watch_buildWatch a build until it finishesA
Read-only
Inspect

Follow a build to its end and report what happened. Streams the platform's own progress — each event is sent only when something actually moved — and logs each one as it arrives, so a long build is visibly alive rather than indistinguishable from a hang. A build that FAILED is a normal answer here, not an error: read status and the failed step. Attaching to a build that has already finished is fine and returns immediately. Needs an account-wide key: a key confined to a workspace is refused (403).

NameRequiredDescriptionDefault
build_idYesThe id build_template returned.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the readOnlyHint/openWorldHint annotations: explains streaming semantics (events only when something actually moved, so a long build looks alive), clarifies that a FAILED build is a normal result and not an error, and discloses a concrete auth constraint (account-wide key required; workspace-scoped key returns 403).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core action, then adds only sentences that earn their place: liveness semantics, the failed-build-is-not-an-error caveat, the already-finished case, and the key requirement. No filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description carries the return-value burden and does so by naming `status` and the failed step. Combined with the auth constraint and streaming behavior, an agent has everything needed to call and interpret it.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the sole parameter (build_id) is already documented as the id returned by build_template. The description adds no syntax or format meaning beyond the schema, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource with scope: 'Follow a build to its end and report what happened.' This distinguishes it from snapshot siblings like get_build and list_builds, which fetch state rather than following to completion.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear usage context: use it to follow a build to its end, and notes that attaching to an already-finished build returns immediately, so calling it 'late' is safe. It does not explicitly name get_build as the alternative for just checking status, so it falls short of full when/when-not routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

whoamiWho this credential isA
Read-onlyIdempotent
Inspect

Who the API key this server runs with belongs to: the person (id, email, name), the account it acts on (id, name, plan, status: active or suspended), the role it acts with now (owner, member or viewer), the workspace it is confined to (null for the whole account), and the key itself (id, name, prefix, manage_keys: whether it may manage API keys, expires_at: when it stops working, null for never, and computer_ids: the only computers it may reach, null for every computer its scope reaches). An expired key is refused with 401 API key expired; a person mints a new one. For a key confined to a workspace the email, both names and the plan are null: the platform withholds them from a key that may be in the hands of an end customer. Needs no permission and any role; a suspended account can call it. No arguments.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnly/idempotent annotations, the description discloses expired-key 401 behavior, permission-free access, suspended-account availability, and workspace-confined null fields withheld for end-customer keys. It also explains manage_keys, expires_at, and computer_ids semantics, which is substantial behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded and every sentence carries useful information, including field semantics and edge cases. It is dense and somewhat run-on, but not padded with redundant claims.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema and no parameters, the description must explain the returned identity structure and does so completely: person, account, role, workspace, key details, and confidentiality/null rules. Nothing an agent needs to interpret the response is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, and the description explicitly confirms 'No arguments.' That is the right level of parameter information for a no-arg schema, matching the baseline of 4 for zero parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific identity-introspection purpose: who the API key belongs to, then enumerates person, account, role, workspace, and key. It is clearly distinct from siblings like get_account or list_api_keys because it describes the credential's effective identity and scope in one call.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the purpose, and the description adds invocation context such as 'Needs no permission and any role; a suspended account can call it.' However, it does not explicitly say when to choose whoami over get_account or list_api_keys, and no alternatives or exclusions are named.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

window_actionAct on a windowAInspect

Focus, raise, minimize, maximize, unmaximize, close, move or resize one window. The reply is the window afterwards, not an acknowledgement — the window manager places the frame and applications snap to their own grid, so a move to 300,200 routinely lands at 305,229. Believe the response, not the request. On a Wayland desktop a tiled window cannot be moved or resized — float it first — and an action the compositor refuses is a 400. Prefer focus over raise: raising without focusing gives a window that is visibly in front and silently not receiving keystrokes. A 504 is neither a refusal nor a report that nothing happened unless its structured response explicitly says the request was not dispatched: an absent or ambiguous explanation leaves the action possibly already applied. An uncertain outcome is not permission to repeat it — the next call is list_windows, which says what the desktop is now, not this one again. Least of all for close, which cannot be undone.

NameRequiredDescriptionDefault
xNoRequired for move, with y: -32768 to 32767.
yNoRequired for move, with x: -32768 to 32767.
widthNoRequired for resize, with height: 1 to 32767.
actionYes
heightNoRequired for resize, with width: 1 to 32767.
window_idYesFrom list_windows, e.g. "0x2600003".
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and does much of it: it discloses that the reply is post-action window state rather than an ack, that the WM may snap coordinates (300,200 landing at 305,229), that a refused compositor action returns 400, that 504 is ambiguous, and that close is irreversible. That is strong coverage, but placement/origin-relative coordinate caveats and permission requirements for acting on other users' windows remain unstated.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The action enumeration is front-loaded and the critical semantics (believe the response, don't retry on ambiguous outcomes, close is irreversible) land early. It runs long at seven sentences and some rhetorical phrasing ('Least of all for close') costs more space than it returns, but no sentence is pure filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, and the description compensates by explaining the return value directly ('The reply is the window afterwards, not an acknowledgement'). Combined with the 400/504 error taxonomy, the retry-on-ambiguity rule, and the idempotency warning for close, an agent has enough to call this correctly and recover safely from failure.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 86%, so fields like x/y/width/height are already documented, but the description adds real meaning beyond the schema: coordinates are requests the window manager may not honor exactly, and move/resize are unavailable on Wayland tiled windows. That is authoritative param behavior the schema does not convey.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb list (focus, raise, minimize, maximize, unmaximize, close, move, resize) applied to a single, clearly scoped resource ('one window'). The action list maps directly onto the enum, and the paired sibling list_windows is named, so an agent can distinguish this from desktop-listing tools without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit routing guidance: 'Prefer focus over raise' with the reason (raise-without-focus leaves a window visible but not receiving keystrokes), the Wayland constraint that a tiled window must be floated before move/resize, and the recovery path ('the next call is list_windows'). When-to-use, when-not, and the alternative are all stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

write_clipboardPut text on the desktop's clipboardAInspect

Puts text on the computer’s desktop clipboard, ready to paste. This leaves it on the clipboard and touches nothing on screen — follow it with press_key and keys ["ctrl","v"] to get the text into whatever has focus. Those are two separate key NAMES in the array, not one string "ctrl+v", which press_key would reject as an unknown key. Use this rather than the setsid/xclip/base64 recipe through exec: it is one call, it is confirmed, and it cannot be broken by a quote in the text. It requires a Linux desktop image with its desktop’s clipboard tool installed — xclip on X11, wl-clipboard (wl-paste/wl-copy) on Wayland images such as Omarchy — and is refused on Windows. An image without that tool gets a 400 that names it and never clears; changing runtime state or retrying cannot fix that image dependency. Unlike read_clipboard this DRIVES the computer, so a suspended one is resumed to serve it and that resume consumes running capacity. At most 64 KiB of text goes in — half what comes out, because the text crosses to the guest inside a single command argument. Empty text ("") CLEARS the clipboard, and is the only way to: do it after pasting a secret, since otherwise the desktop keeps holding it. The platform confirms the write by reading the selection back before it answers, so a success here means the desktop is holding your text rather than that a command ran; a refusal saying the desktop did not take it means something else claimed the clipboard in that instant, and sending it again works. Not every refusal here is one of those, and the answer says which it is rather than leaving you to match on the sentence: a computer that is not running is a 409 that start_computer fixes and that retrying never will, while a guest agent still inside its boot window is worth another attempt. A desktop that is not answering is deliberately left unclassified — it can equally be a guest still coming up or a session nobody is logged into — so bound your attempts there instead of looping.

NameRequiredDescriptionDefault
textYesThe text to put on the clipboard. At most 64 KiB of UTF-8. "" clears the clipboard.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden; it discloses platform requirements, refusal behavior, capacity limits, clipboard clearing semantics, write confirmation via readback, and the side effect of resuming a suspended computer. These are substantive behavioral traits beyond the schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Core action and follow-up usage are front-loaded, and most of the length is justified by the lack of annotations and the complexity of error semantics. It is still dense and long, with several edge-case clauses that could be tightened, so not a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no annotations, no output schema, and two parameters, the description covers the important prerequisites, failure modes, capacity constraints, clearing behavior, and platform limitations needed to call the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents both parameters including the 64 KiB limit and "" clearing behavior. The description adds some rationale about the single-command-argument limit but does not add much parameter-level meaning beyond the schema, so the high-coverage baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: puts text on the desktop clipboard and leaves it there. It contrasts with read_clipboard and the exec/xclip recipe, but does not distinguish itself from the sibling paste_text, so sibling differentiation is incomplete.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly says to follow with press_key using separate "ctrl" and "v" key names, why not to use exec/xclip, when empty text should be used after pasting a secret, and how to interpret specific refusal classes. This gives clear when/how/alternatives guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

write_filePut a file into the guestAInspect

Write a file inside the computer. Paths must be absolute — the guest agent inherits whatever working directory it was started in, so a relative path resolves somewhere you did not name. By default a file already at the path is replaced. Pass overwrite: false to create the file only if nothing is there: a path that is taken is refused and that attempt writes nothing — retrying does not change that. Incomplete contents are never published at the path, but a failure while publishing or answering can leave the COMPLETE file there: after any error, read the path before retrying or overwriting, since what is there may be your own upload. A refusal saying this computer’s host cannot do a create-only write, and a 503 on one, mean nothing was sent — but neither means the path is free. overwrite: false is for Linux computers; a Windows computer refuses it. A suspended computer is resumed to take the write, which consumes running capacity, unless no_wake is set.

NameRequiredDescriptionDefault
pathYesAbsolute path inside the guest, e.g. /home/user/Desktop/notes.txt.
contentYesThe file contents.
no_wakeNotrue: do not resume a computer that is not running — refuse instead (409), so nothing is resumed and no running capacity is consumed. Use it to look at a suspended computer’s files only if it is already awake. false (the default) resumes a suspended computer to answer, which consumes running capacity.
encodingNobase64 for anything that is not text.utf8
overwriteNotrue (the default) replaces a file already at the path. false creates the file only if nothing is there, and refuses without writing anything when the path is taken.
computer_idNoWhich computer. Defaults to the one selected with use_computer.

TDQS

A4.2/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and does so thoroughly. It discloses default replacement, create-only refusal semantics, partial-write behavior, error recovery guidance, Windows vs Linux restrictions, and the capacity cost of resuming a suspended computer unless no_wake is set.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The purpose is front-loaded and most sentences carry useful operational detail. The description is dense as a single paragraph and could be more scannable, but it avoids empty filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a six-parameter write tool with no annotations and no output schema, the description covers the important invocation hazards: path resolution, overwrite behavior, partial failures, platform limits, and suspend/wake semantics. It does not describe the response shape or size limits, which are secondary but not fully covered.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents every parameter. The description still adds meaning beyond the schema, especially the absolute-path rationale, retry implications of overwrite:false, host capability refusals, and the operational cost of waking a suspended computer.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: "Write a file inside the computer." That makes the core action clear. However, it does not distinguish this tool from the sibling write_file_chunk, so an agent must infer whether to use whole-file writes or chunked writes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives clear usage context for overwrite, no_wake, platform restrictions, and error retry behavior. It does not explicitly route between this tool and alternatives such as write_file_chunk, so it falls short of full when/when-not/alternative guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

write_file_chunkStage a resumable file chunkAInspect

Linux with python3 only. Stage up to 256 KiB in one chunk of a file up to 2 GiB. Supply raw bytes as base64, in order, keeping path, upload_id, size, overwrite and source contents unchanged. The final chunk publishes atomically. After any error call get_file_upload and continue from its offset; never guess or restart blindly. An empty chunk at offset=size retries publication. Call cancel_file_upload after completion or to abandon staging. Staging consumes guest disk until cancelled, with no expiry. May resume a suspended computer and consume running capacity. A 404 from an older host means resumable upload is not available on it: do not resend the chunk through write_file, which is neither atomic nor resumable. For large local files prefer the SDK or CLI, avoiding model-context transfers.

NameRequiredDescriptionDefault
pathYesAbsolute path inside the guest.
sizeYes
offsetYes
no_wakeNotrue: do not resume a computer that is not running — refuse instead (409), so nothing is resumed and no running capacity is consumed. Use it to look at a suspended computer’s files only if it is already awake. false (the default) resumes a suspended computer to answer, which consumes running capacity.
overwriteNo
upload_idYesA fresh random 32-character lowercase hex ID; retain it to resume. Never reuse for different contents.
computer_idNoWhich computer. Defaults to the one selected with use_computer.
content_base64Yes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so: it discloses the platform prerequisite (Linux with python3), that staging consumes guest disk with no expiry until cancelled, that it may resume a suspended computer and consume running capacity, and that a 404 from an older host means the feature is unavailable. These are exactly the side effects and preconditions an agent needs before calling a write tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Dense but nearly every sentence carries a distinct rule (limits, ordering, atomic publish, error recovery, cleanup, capacity cost, host compatibility). It is slightly back-loaded — the platform prerequisite leads while the 'prefer SDK/CLI' guidance trails — but there is no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an 8-parameter, unannotated, no-output-schema mutation tool, the description covers limits, ordering, idempotent publish retry, error recovery, cleanup, disk/capacity costs and host compatibility. The one remaining gap is the shape of a successful response (whether it returns the new offset), which it only implies by pointing at get_file_upload after errors.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 50% (path, upload_id, computer_id, no_wake are documented in-schema; size, offset, overwrite, content_base64 are not). The description compensates well: it explains that content_base64 holds raw base64 bytes capped at 256 KiB, that offset/size bound the 2 GiB file and drive ordered appends and the offset=size retry, and that path/upload_id/overwrite must stay unchanged across chunks. Minor residual ambiguity about whether offset must equal the current staged length.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Stage up to 256 KiB in one chunk of a file up to 2 GiB') plus the atomic-publish semantics of the final chunk. It implicitly separates itself from write_file (neither atomic nor resumable), get_file_upload (error recovery) and cancel_file_upload (cleanup), so an agent can route correctly without opening sibling schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit operational rules: send chunks in order with path/upload_id/size/overwrite/source contents unchanged, retry publication via an empty chunk at offset=size, call cancel_file_upload on completion or abandonment, and on any error call get_file_upload and continue from its offset rather than restarting. It also names the fallback path (SDK/CLI for large local files) and the anti-pattern (do not resend through write_file).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 5 tool updatesv0.21.0
    • Changedcreate_computer2 fields changed
      • addedInput schema / properties / ends_at
        Added value: +{
        +  "description": "When the computer stops by itself: at that time its host stops it, as stop_computer would, and its disk is kept; get_computer's ends_at says when, and is gone once it has fired or been cleared. It fires once. A host that cannot keep an end time answers 409 with reason unsupported. An RFC 3339 time at least 10 minutes and at most 366 days from now, e.g. \"2026-11-01T18:00:00Z\". Give this or ends_in_hours, not both.",
        +  "type": "string"
        +}
      • addedInput schema / properties / ends_in_hours
        Added value: +{
        +  "description": "When the computer stops by itself: at that time its host stops it, as stop_computer would, and its disk is kept; get_computer's ends_at says when, and is gone once it has fired or been cleared. It fires once. A host that cannot keep an end time answers 409 with reason unsupported. Hours from now, fractions allowed (0.5 is half an hour); the platform turns it into ends_at. Give this or ends_at, not both.",
        +  "exclusiveMinimum": 0,
        +  "type": "number"
        +}
    • Addedcreate_credential_gateway_binding
    • Addeddelete_credential_gateway_binding
    • Addedlist_credential_gateway_bindings
    • Changedupdate_computer2 fields changed
      • addedInput schema / properties / ends_at
        Added value: +{
        +  "description": "When the computer stops by itself: at that time its host stops it, as stop_computer would, and its disk is kept; get_computer's ends_at says when, and is gone once it has fired or been cleared. It fires once. A host that cannot keep an end time answers 409 with reason unsupported. An RFC 3339 time in the future, replacing any end time it has; null clears it. Send this ON ITS OWN, and not beside ends_in_hours.",
        +  "type": [
        +    "string",
        +    "null"
        +  ]
        +}
      • addedInput schema / properties / ends_in_hours
        Added value: +{
        +  "anyOf": [
        +    {
        +      "exclusiveMinimum": 0,
        +      "type": "number"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "When the computer stops by itself: at that time its host stops it, as stop_computer would, and its disk is kept; get_computer's ends_at says when, and is gone once it has fired or been cleared. It fires once. A host that cannot keep an end time answers 409 with reason unsupported. Hours from now, fractions allowed, replacing any end time it has; null clears it. Send this ON ITS OWN, and not beside ends_at."
        +}
  2. 1 tool updatev0.19.0
    • Changedstop_computer1 field changed
      • changedInput schema / properties / force / description
        Previous value: -"Pull the power at once instead of asking, the way holding the button in does. Anything the guest had not written to disk is lost. It is rarely needed: an ordinary stop already forces the computer off if the guest has not shut down within 20 seconds, so `force` only saves those 20 seconds, and it takes from the guest the chance to write its data first. Leave it out unless the user wants the computer off immediately."New value: +"Pull the power at once instead of asking, the way holding the button in does. Anything the guest had not written to disk is lost. It is rarely needed: an ordinary stop already forces the computer off if the guest has not shut down within 45 seconds, so `force` only saves those 45 seconds, and it takes from the guest the chance to write its data first. Leave it out unless the user wants the computer off immediately."
  3. 14 tool updatesv0.18.0
    • Changedclick4 fields changed
      • addedInput schema / properties / x / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / x / minimum
        Added value: +-9007199254740991
      • addedInput schema / properties / y / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / y / minimum
        Added value: +-9007199254740991
    • Changedcreate_computer3 fields changed
      • addedInput schema / properties / cpu / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / disk_gb / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / ram_mb / maximum
        Added value: +9007199254740991
    • Changeddrag8 fields changed
      • addedInput schema / properties / from_x / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / from_x / minimum
        Added value: +-9007199254740991
      • addedInput schema / properties / from_y / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / from_y / minimum
        Added value: +-9007199254740991
      • addedInput schema / properties / to_x / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / to_x / minimum
        Added value: +-9007199254740991
      • addedInput schema / properties / to_y / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / to_y / minimum
        Added value: +-9007199254740991
    • Changedexec1 field changed
      • addedInput schema / properties / env / propertyNames
        Added value: +{
        +  "type": "string"
        +}
    • Changedget_agent_thread1 field changed
      • addedInput schema / properties / before_turn / maximum
        Added value: +9007199254740991
    • Changedmouse_button4 fields changed
      • addedInput schema / properties / x / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / x / minimum
        Added value: +-9007199254740991
      • addedInput schema / properties / y / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / y / minimum
        Added value: +-9007199254740991
    • Changedmove_computer3 fields changed
      • addedInput schema / properties / cpu / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / disk_gb / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / ram_mb / maximum
        Added value: +9007199254740991
    • Changedmove_mouse4 fields changed
      • addedInput schema / properties / x / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / x / minimum
        Added value: +-9007199254740991
      • addedInput schema / properties / y / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / y / minimum
        Added value: +-9007199254740991
    • Changedread_execution_output4 fields changed
      • removedInput schema / properties / stderr_offset / $ref
        Removed value: -"#/properties/stdout_offset"
      • addedInput schema / properties / stderr_offset / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / stderr_offset / minimum
        Added value: +0
      • addedInput schema / properties / stderr_offset / type
        Added value: +"integer"
    • Changedscreenshot4 fields changed
      • addedInput schema / properties / region / properties / height / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / region / properties / width / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / region / properties / x / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / region / properties / y / maximum
        Added value: +9007199254740991
    • Changedscroll4 fields changed
      • addedInput schema / properties / x / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / x / minimum
        Added value: +-9007199254740991
      • addedInput schema / properties / y / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / y / minimum
        Added value: +-9007199254740991
    • Changedset_computer_secrets1 field changed
      • addedInput schema / properties / version / maximum
        Added value: +9007199254740991
    • Changedupdate_computer3 fields changed
      • addedInput schema / properties / cpu / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / disk_gb / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / ram_mb / maximum
        Added value: +9007199254740991
    • Changedwait_for_event1 field changed
      • addedInput schema / properties / pid / maximum
        Added value: +9007199254740991
  4. 9 tool updatesv0.17.2
    • Changedcancel_file_upload1 field changed
      • changedInput schema / properties / no_wake / description
        Previous value: -"true: do not resume a computer that is not running — refuse instead (409), so nothing is resumed and nothing is charged for a resume. Use it to look at a suspended computer’s files only if it is already awake. false (the default) resumes a suspended computer to answer, which is charged."New value: +"true: do not resume a computer that is not running — refuse instead (409), so nothing is resumed and no running capacity is consumed. Use it to look at a suspended computer’s files only if it is already awake. false (the default) resumes a suspended computer to answer, which consumes running capacity."
    • Changedcreate_computer1 field changed
      • changedInput schema / properties / disk_gb / description
        Previous value: -"The template's own disk is a FLOOR, not a default — read it from list_templates. A smaller number is raised to it silently and the account is charged the raised figure, so asking for less than the template needs spends more of the plan's disk pool than the number here suggests and can be refused outright."New value: +"The template's own disk is a FLOOR, not a default — read it from list_templates. A smaller number is raised to it silently and the raised figure counts against storage limits, so asking for less than the template needs spends more of the plan's disk pool than the number here suggests and can be refused outright."
    • Changedcreate_public_url1 field changed
      • changedInput schema / properties / access / description
        Previous value: -"`public` (the default): ANYONE WITH THE LINK can open it. `private`: only a request carrying an API key of this account as `Authorization: Bearer` can, and the key never reaches the app."New value: +"`public`: ANYONE WITH THE LINK can open it. Omitted access defaults to public on paid plans and private on trials; trials cannot request public access. `private`: an account API key as `Authorization: Bearer` (workspace-scoped keys must match the computer), or browser sign-in through the dashboard Open button. The key never reaches the app."
    • Changedget_file_upload1 field changed
      • changedInput schema / properties / no_wake / description
        Previous value: -"true: do not resume a computer that is not running — refuse instead (409), so nothing is resumed and nothing is charged for a resume. Use it to look at a suspended computer’s files only if it is already awake. false (the default) resumes a suspended computer to answer, which is charged."New value: +"true: do not resume a computer that is not running — refuse instead (409), so nothing is resumed and no running capacity is consumed. Use it to look at a suspended computer’s files only if it is already awake. false (the default) resumes a suspended computer to answer, which consumes running capacity."
    • Changedlist_snapshots1 field changed
      • changedInput schema / properties / include_unfinished / description
        Previous value: -"Also return deletions that began and did not finish. They are not usable — their state is \"deleting\" and nothing can be restored or cloned from one — but they still hold objects and are still billed, so this is the flag to set when the question is about storage rather than about what can be restored. It is also the flag to set when following a deletion: without it a snapshot stuck half-deleted is hidden, and a poll watching for the row to go cannot tell that from one that finished."New value: +"Also return deletions that began and did not finish. They are not usable — their state is \"deleting\" and nothing can be restored or cloned from one — but they still hold objects and still count against storage, so this is the flag to set when the question is about storage rather than about what can be restored. It is also the flag to set when following a deletion: without it a snapshot stuck half-deleted is hidden, and a poll watching for the row to go cannot tell that from one that finished."
    • Changedread_file1 field changed
      • changedInput schema / properties / no_wake / description
        Previous value: -"true: do not resume a computer that is not running — refuse instead (409), so nothing is resumed and nothing is charged for a resume. Use it to look at a suspended computer’s files only if it is already awake. false (the default) resumes a suspended computer to answer, which is charged."New value: +"true: do not resume a computer that is not running — refuse instead (409), so nothing is resumed and no running capacity is consumed. Use it to look at a suspended computer’s files only if it is already awake. false (the default) resumes a suspended computer to answer, which consumes running capacity."
    • Changedupdate_public_url1 field changed
      • changedInput schema / properties / access / description
        Previous value: -"`public`: anyone with the link can open it. `private`: only a request carrying an API key of this account as `Authorization: Bearer` can."New value: +"`public`: anyone with the link can open it; unavailable on trials. `private`: an account API key as `Authorization: Bearer` (workspace-scoped keys must match the computer), or browser sign-in through the dashboard Open button."
    • Changedwrite_file1 field changed
      • changedInput schema / properties / no_wake / description
        Previous value: -"true: do not resume a computer that is not running — refuse instead (409), so nothing is resumed and nothing is charged for a resume. Use it to look at a suspended computer’s files only if it is already awake. false (the default) resumes a suspended computer to answer, which is charged."New value: +"true: do not resume a computer that is not running — refuse instead (409), so nothing is resumed and no running capacity is consumed. Use it to look at a suspended computer’s files only if it is already awake. false (the default) resumes a suspended computer to answer, which consumes running capacity."
    • Changedwrite_file_chunk1 field changed
      • changedInput schema / properties / no_wake / description
        Previous value: -"true: do not resume a computer that is not running — refuse instead (409), so nothing is resumed and nothing is charged for a resume. Use it to look at a suspended computer’s files only if it is already awake. false (the default) resumes a suspended computer to answer, which is charged."New value: +"true: do not resume a computer that is not running — refuse instead (409), so nothing is resumed and no running capacity is consumed. Use it to look at a suspended computer’s files only if it is already awake. false (the default) resumes a suspended computer to answer, which consumes running capacity."
  5. 9 tool updatesv0.15.0
    • Addedcancel_agent_run
    • Changedcreate_webhook1 field changed
      • changedInput schema / properties / url / description
        Previous value: -"Where to POST. https:// only, no username or password, resolving to a public address. A port other than 443 is fine."New value: +"Where to POST. https:// only, at most 2048 characters, no username or password, resolving to a public address. A port other than 443 is fine."
    • Addeddelete_agent_thread
    • Changedexec1 field changed
      • changedInput schema / properties / env / description
        Previous value: -"Environment for this command, as {NAME: \"value\"}. Use it instead of writing FOO=bar in front of the command: a prefix assignment is shell syntax, so a value holding a space, a quote, a newline or a $ has to be quoted correctly by you and is silently truncated or re-parsed when it is not, while this reaches the process whole and unquoted. It also keeps a secret out of the command line, which is world-readable in the guest's ps and, for a background command, comes back to you inside every exec_poll answer. The variables are added on top of the guest's login profile rather than replacing it, so PATH and the rest are still there, and they apply to this command only — including with desktop: true. Names must not be empty or contain \"=\"."New value: +"Environment for this command, as {NAME: \"value\"}. Use it instead of writing FOO=bar in front of the command: a prefix assignment is shell syntax, so a value holding a space, a quote, a newline or a $ has to be quoted correctly by you and is silently truncated or re-parsed when it is not, while this reaches the process whole and unquoted. It also keeps a secret out of the command line, which is world-readable in the guest's ps and, for a background command, comes back to you inside every exec_poll answer. The variables are added on top of the guest's login profile rather than replacing it, so PATH and the rest are still there, and they apply to this command only — including with desktop: true. Names must not be empty or contain \"=\". At most 64 entries, each at most 4096 bytes counted as NAME=value in UTF-8; past either nothing runs."
    • Addedget_agent_run
    • Addedget_agent_thread
    • Addedlist_agent_runs
    • Addedlist_agent_threads
    • Changedupdate_webhook1 field changed
      • changedInput schema / properties / url / description
        Previous value: -"A new endpoint, checked exactly as on create: https, no credentials, public address."New value: +"A new endpoint, checked exactly as on create: https, at most 2048 characters, no credentials, public address."
  6. 3 tool updatesv0.14.0
    • Addedcancel_file_upload
    • Addedget_file_upload
    • Addedwrite_file_chunk
  7. 113 tool updatesv0.13.1
    • First observedadd_ssh_key
    • First observedbuild_template
    • First observedcheck_template
    • First observedclick
    • First observedclone_computer
    • First observedclone_snapshot
    • First observedcreate_computer
    • First observedcreate_public_url
    • First observedcreate_secret
    • First observedcreate_snapshot
    • First observedcreate_webhook
    • First observedcreate_workspace
    • First observedcursor_position
    • First observeddelete_artifact
    • First observeddelete_computer
    • First observeddelete_public_url
    • First observeddelete_result
    • First observeddelete_secret
    • First observeddelete_snapshot
    • First observeddelete_webhook
    • First observeddelete_workspace
    • First observeddrag
    • First observedexec
    • First observedexec_kill
    • First observedexec_poll
    • First observedget_account
    • First observedget_activity
    • First observedget_activity_results
    • First observedget_artifact
    • First observedget_build
    • First observedget_computer
    • First observedget_computer_secrets
    • First observedget_computer_ssh
    • First observedget_credits
    • First observedget_desktop_url
    • First observedget_execution
    • First observedget_operation
    • First observedget_result
    • First observedget_retention
    • First observedget_secret
    • First observedget_template
    • First observedget_template_schema
    • First observedget_usage
    • First observedget_webhook
    • First observedget_workspace
    • First observedlist_activities
    • First observedlist_api_keys
    • First observedlist_builds
    • First observedlist_computers
    • First observedlist_directory
    • First observedlist_moves
    • First observedlist_operations
    • First observedlist_public_urls
    • First observedlist_secrets
    • First observedlist_sizes
    • First observedlist_snapshots
    • First observedlist_ssh_keys
    • First observedlist_templates
    • First observedlist_webhook_deliveries
    • First observedlist_webhooks
    • First observedlist_windows
    • First observedlist_workspace_members
    • First observedlist_workspaces
    • First observedmouse_button
    • First observedmove_computer
    • First observedmove_computer_to_workspace
    • First observedmove_mouse
    • First observedopen_url
    • First observedpaste_text
    • First observedpoll_events
    • First observedpress_key
    • First observedpublish_artifact
    • First observedpublish_template
    • First observedread_artifact
    • First observedread_clipboard
    • First observedread_execution_output
    • First observedread_file
    • First observedread_result_output
    • First observedread_signals
    • First observedremove_ssh_key
    • First observedrename_workspace
    • First observedreplace_secret
    • First observedrestart_computer
    • First observedrestore_snapshot
    • First observedretain_execution_output
    • First observedretire_template
    • First observedrotate_webhook_secret
    • First observedscreenshot
    • First observedscroll
    • First observedset_computer_secrets
    • First observedset_computer_ssh
    • First observedset_secret
    • First observedsnapshot_holdings
    • First observedsnapshot_schedule
    • First observedstart_computer
    • First observedstop_computer
    • First observedsuspend_computer
    • First observedtest_webhook
    • First observedtype_text
    • First observedupdate_computer
    • First observedupdate_public_url
    • First observedupdate_webhook
    • First observeduse_computer
    • First observedwait
    • First observedwait_for_computer
    • First observedwait_for_event
    • First observedwait_for_file_change
    • First observedwait_for_operation
    • First observedwatch_build
    • First observedwhoami
    • First observedwindow_action
    • First observedwrite_clipboard
    • First observedwrite_file

TDQS

B3.2/5.0

Scored across 125 tools

Disambiguation2/5

At 125 tools there are many adjacent clusters: get_activity and list_activities have effectively the same description, and the execution/result/artifact reading tools plus snapshot/clone/restore and move_computer/move_computer_to_workspace require careful discrimination. Individual descriptions are unusually detailed and often prevent misselection, but the set still presents multiple near-duplicate surfaces.

Naming Consistency3/5

Most names are snake_case and many follow verb_noun (get_computer, create_snapshot, delete_webhook), but the pattern is not uniform: screenshot, exec, wait, click and mouse_button are noun/action-only, while window_action and snapshot_schedule use other shapes. Still readable, but not a predictable convention throughout.

Tool Count1/5

125 tools is an extreme surface for one server, far beyond the 3-15 well-scoped range. Even acknowledging the platform's breadth (computers, snapshots, templates, builds, secrets, webhooks, SSH, public URLs, agents, executions, artifacts, activities, credits, usage), the count imposes heavy selection cost.

Completeness3/5

Most resources have broad CRUD/lifecycle coverage, but notable gaps remain: descriptions reference run_agent, run_agent_chat and start_agent_run, yet no tool starts an agent run, and workspace member listing has no invite/remove/role-change counterpart. API key mint/revoke is explicitly omitted by design.

Maintenance

ActivityActive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    Exposes Anthropic's computer-use action surface (screenshot, click, move, keyboard, clipboard, batch) against a persistent desktop display via MCP stdio protocol. Enables AI agents to control a virtual desktop environment through natural language instructions.
    24
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Cross-platform desktop automation MCP server that lets AI agents capture screenshots, run OCR with UI-element classification, control mouse/keyboard, and launch programs on Linux, macOS, and Windows.
    20
    1
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables controlling your own Linux desktop machines from any MCP-capable LLM client, with opt-in agent capabilities for shell, filesystem, processes, screenshots, system info, and input injection.
    1
    MIT