---
title: Anthropic
description: The computer toolset for Claude — one tool entry, one handler, and your own loop.
---

`@raster/anthropic` maps Claude's computer-use toolset onto the machine API. It is not an agent
framework and does not own a loop: you keep your own conversation, call `handle` on the
`tool_use` blocks you get back, and send the results.

```bash
npm install @raster/anthropic @anthropic-ai/sdk
```

## The shape

```ts
import Anthropic from "@anthropic-ai/sdk";
import { Client } from "@raster/sdk";
import { computerUse } from "@raster/anthropic";

const machine = await new Client().machines.create({ size: "standard" });
await machine.waitForDesktop();

const adapter = computerUse(machine);
```

`adapter.tool` is the `tools[]` entry to send. No beta header is needed for this version.

```ts
const model = new Anthropic();
const messages = [{ role: "user", content: task }];

for (let turn = 0; turn < 24; turn++) {
  const response = await model.beta.messages.create({
    model: "claude-opus-5",
    max_tokens: 16_000,
    tools: [adapter.tool],
    messages,
  });

  if (response.stop_reason === "refusal") break;
  messages.push({ role: "assistant", content: response.content });
  if (response.stop_reason !== "tool_use") break;

  // every computer action in this message, in order.
  const results = await adapter.handleAll(response);
  messages.push({ role: "user", content: results });
}
```

| Prop | Type | Default | Description |
| - | - | - | - |
| `tool` | `BetaComputerToolset20260801` | - | The tools[] entry to send. |
| `owns` | `(block) => boolean` | - | Whether a content block belongs to this adapter. |
| `handle` | `(block) => Promise<BetaToolResultBlockParam>` | - | Perform one computer action. |
| `handleAll` | `(message) => Promise<BetaToolResultBlockParam[]>` | - | Perform every computer action in one assistant message, in order. |

Options: `maxWaitSeconds` (how long a `wait` action may block; the protocol's own ceiling is 300)
and `sleep`, overridable so a test does not spend real time sleeping.

## Order matters, and so does stopping

`handleAll` performs the actions in the order the model emitted them and **stops at the first
failure**. The actions queued behind it are answered as not executed rather than applied to the
wrong window — a click that failed usually means the screen is not what the model thought.

## Two members are withheld

The adapter declares `zoom` and `cursor_position` as disabled rather than accepting and failing
them. Teaching a model that a tool exists and then wasting a turn on discovering it does not work
is worse than saying so up front.

- **`zoom`** would need server-side image cropping, which the machine API does not do. The model
  can screenshot at full resolution instead.
- **`cursor_position`** has no read-only pointer query on the guest, and moving the pointer to
  find out where it is defeats the question.

## Adding a shell

The toolset covers the GUI. One canonical tool from the SDK gives the model a shell without a
terminal window, and the definition is passed through as-is rather than restated:

```ts
const generic = machine.tools.generic();
const execTool = generic.definitions.find((d) => d.name === "terminal_exec")!;

const tools = [
  adapter.tool,
  { name: execTool.name, description: execTool.description, input_schema: execTool.input_schema },
];
```

Your own tools are yours to handle. `adapter.owns(block)` tells the two apart, and the adapter
does not touch anything it does not own — which is the point of it not being a framework:

```ts
const results = await adapter.handleAll(response);

for (const block of response.content) {
  if (block.type !== "tool_use" || block.toolset_name) continue; // not the computer toolset
  const result = await generic.execute(block.name, block.input);
  results.push({
    type: "tool_result",
    tool_use_id: block.id,
    is_error: result.is_error,
    content: result.content.map((part) =>
      part.type === "text"
        ? { type: "text", text: part.text }
        : { type: "image", source: { type: "base64", media_type: "image/png", data: part.data } },
    ),
  });
}
```

## Failures reach the model

An action that fails comes back as a tool result with `is_error` and a sentence, not as a thrown
exception. A model that is told the click landed outside the display can take another screenshot;
one that gets nothing stares at an unchanged screen.

## Cleaning up

```ts
await machine.close(); // releases the input lease and closes the session
```

A working example lives at `packages/anthropic/examples/phase-one-proof.ts`.
