Skip to main content

daytona-claude-toolsets

Daytona sandbox drivers for the Anthropic SDK's computer and browser toolsets (computer_toolset_20260801, browser_toolset_20260801). Hand one to client.beta.messages.tool_runner and Claude drives a desktop or a Chromium that runs in an isolated Daytona sandbox, while your API keys, the model loop and the toolset stay in your process.

  • DaytonaComputer (and AsyncDaytonaComputer): the sandbox desktop, through Daytona's Computer Use API.
  • DaytonaBrowser: Chromium inside the sandbox, driven over the Chrome DevTools Protocol with Playwright through a signed Daytona preview URL.

Every member of both toolsets is implemented, including the browser members that are off by default (read_console, read_network, javascript_exec, file_upload).

Installation

pip install daytona-claude-toolsets             # DaytonaComputer
pip install 'daytona-claude-toolsets[browser]'  # + DaytonaBrowser (Playwright client only; no local browser)

Set your keys in the environment:

export DAYTONA_API_KEY="..."    # https://app.daytona.io/dashboard/keys
export ANTHROPIC_API_KEY="..."

Quickstart

Computer. The SDK requires a confirm callable while type, key or hold_key is enabled. This one approves everything, which is only reasonable for a throwaway sandbox:

from anthropic import Anthropic
from daytona_claude_toolsets import DaytonaComputer

with DaytonaComputer(confirm=lambda context: True) as computer:
    for message in Anthropic().beta.messages.tool_runner(model="claude-sonnet-5-5", max_tokens=4096, tools=[computer], messages=[{"role": "user", "content": "Open a terminal, run date, and tell me the output."}]):
        print(message)

Browser. Pass a url_policy; see Safety:

from anthropic import Anthropic
from daytona_claude_toolsets import DaytonaBrowser

with DaytonaBrowser(url_policy=my_policy) as browser:
    for message in Anthropic().beta.messages.tool_runner(model="claude-sonnet-5-5", max_tokens=4096, tools=[browser], messages=[{"role": "user", "content": "Open example.com and tell me the page heading."}]):
        print(message)

With no sandbox argument, each driver creates a sandbox from Daytona's default snapshot, which ships the desktop and Chromium, and deletes it when the with block exits.

Sandbox lifecycle

How On close()
Owned (default) DaytonaComputer(create_params=CreateSandboxFromSnapshotParams(...)), or no arguments deleted (on_close="stop" stops it instead)
Borrowed DaytonaComputer(sandbox) with a running Sandbox left running; DaytonaBrowser stops the Chromium it started

close() is idempotent and safe after a failed construction: a sandbox created before the failure is still removed. Sandboxes the drivers create always carry the label created-by=daytona-claude-toolsets, so a leftover one can be found and removed by it; create_params.labels adds your own labels but cannot change that one. Keyword arguments the drivers don't define (confirm, configs, url_policy, file_policy, tool_configs) go to the SDK unchanged.

Daytona auto-stops an idle sandbox, and counts only interactions made through the SDK — not traffic through a preview URL, which is how DaytonaBrowser reaches Chromium. It therefore refreshes the sandbox's activity itself while the browser is in use, so a long browsing session is not stopped underneath it. The refresh counts the waiting a member is about to do, not only the gap between calls, so the sandbox is never left unheard from for more than 45 seconds and one on Daytona's shortest auto-stop interval (one minute) stays up — unless you raise navigation_timeout past that interval, when a single navigation can outlast it. It never changes the sandbox's auto-stop interval, so a borrowed sandbox keeps the lifecycle you configured.

AsyncDaytonaComputer takes the same arguments through await AsyncDaytonaComputer.create(...), for AsyncAnthropic. There is no async browser driver yet.

What's implemented

DaytonaComputer

Members How
screenshot, zoom Computer Use screenshots. zoom crops the real screen and scales the crop up to a screenshot's size.
left_click, right_click, middle_click, double_click (plain), mouse_move, cursor_position Native Computer Use mouse API; plain single/double clicks use double and work on older daemons too.
triple_click, clicks with modifiers, left_mouse_down, left_mouse_up, left_click_drag (including modifier chords), scroll (all directions, including modifier chords) Native Computer Use mouse API; migrated options are capability-probed and require a sandbox with native mouse hold endpoints. A click, drag or scroll chord holding a non-modifier key token uses XTest instead.
type One native Computer Use keyboard call, including tabs; capability-probed and requires the native keyboard hold endpoints.
key key takes xdotool-style names (Return, Page_Up, ctrl+s, exclam, single characters) and space-separated sequences. Named Daytona keys go through the native keyboard press; verified-correct numpad digits, decimal, equal and lock are capability-probed, while numpad Enter and operators use their KP_* X keysyms because daemon 0.222.1's native press emits the wrong characters. A single character with no named key is typed; modifier-only chords (super, ctrl+alt) and keysyms with no Daytona key name (XF86…) use XTest.
hold_key Native keyboard down, in-process sleep, and reverse-order up; capability-probed. An exotic keysym with no Daytona key name uses XTest.
wait sleeps in your process
  • Coordinates off the screen are refused with an error, never clamped.
  • Scaling: owned sandboxes run at 1280×800 (resolution=). A larger screen is scaled into max_screenshot_size (default 1920×1200), and the model's coordinates are scaled back.
  • Freshness: a screenshot waits settle_delay (0.3 s) after the last input.
  • Bounds: wait and hold_key take 0–30 s, key repeats 1–100, scroll 1–50 notches.

DaytonaBrowser

Members How
navigate URL, back, forward or reload. A bare host gets https://. Every scheme other than http(s) and about:blank is refused, including javascript:, view-source:, data: and file:.
read_page, find, get_page_text, scroll_to, form_input JavaScript in an isolated world, which shares the DOM but not the page's globals, so pages can neither read nor rewrite the ref_N element references. find is keyword matching over role, name and attributes, not a semantic search.
screenshot, zoom CDP Page.captureScreenshot. zoom re-renders the region at a higher scale, so its detail is real.
clicks, hover, mouse_move, left_click_drag, left_mouse_down/up, scroll, type, key, hold_key Playwright mouse and keyboard. Modifier chords are held during clicks, and ref targets are scrolled into view first.
new_tab, list_tabs, switch_tab, close_tab Pages of one browser context. Popups become tabs, and every member honours tab_id.
read_console, read_network Entries collected per tab since the last read (up to 1,000 each)
javascript_exec CDP Runtime.evaluate in the page's own world, stopped after 10 s
file_upload CDP DOM.setFileInputFiles with paths inside the sandbox; see Files
wait 0–30 s, pumping page events

The browser_state report lists every tab (at most 100) with exactly one active. It carries tab_opened for new tabs and popups, download started/completed/failed with the source URL, refused page-started navigations, and dismissed dialogs, and it never raises. Native alert/confirm/prompt dialogs are dismissed and reported, so none can hang a tab. beforeunload is accepted, so the navigation the model asked for goes ahead.

Safety

Before running either toolset, read "Running a browser toolset safely" / "Running a computer toolset safely" in the Anthropic SDK's toolset guides (browser-toolset.md, computer-toolset.md) and the browser use tool docs. What the model sees on a page or screen steers what it does next. How this package covers the guide's checklist:

  1. URL policy. Pass url_policy. Nothing is checked without one, and the SDK ships no policy.
  2. Request interception. The driver applies the same url_policy to every request a page makes (with member=None), with service workers blocked so they can't bypass it. A page-started navigation it refuses reaches the model as "A navigation was refused." WebSocket handshakes go through the same policy on their own hook (a refused one is closed before it reaches the network). Playwright follows a redirect without routing it again, so interception sees first hops only; the driver therefore asks the policy once more about the address a page actually landed on. For navigate that refuses the call; for a navigation a click or a script started, the tab is taken back to a blank page before the next member runs and the model is told the navigation was refused. A sub-resource's redirect chain and the requests and sockets a shared worker makes are still outside it. Each intercepted request also makes a round trip to your process, which slows heavy pages. Allow the CDNs a site needs, or pages render without them.
  3. Egress. The sandbox's network is the backstop. Daytona applies your organization's network tier. On tiers that allow it, set domain_allow_list, network_allow_list or network_block_all in create_params. Chromium also runs with Local Network Access checks on.
  4. Files. Uploads are refused unless you pass a DaytonaFilePolicy, and BetaLocalFilePolicy is refused because it checks paths on your machine, not in the sandbox. Downloads stay in the sandbox.
  5. Approval. Gate consequential members with confirm. The SDK requires it for javascript_exec and file_upload, and for the computer's type, key and hold_key. javascript_exec runs in the page's own world, so an enabled one is the model acting as the page: it reads whatever the page can, and the URL policy does not contain it — that policy decides which addresses may be opened and requested, not what a script may touch in a page already open. It stays disabled unless you enable it in configs.
  6. Isolation. Each driver gets its own sandbox by default. Chromium starts with a fresh profile, a scrubbed environment (env -i) and its own sandbox on (off only when the sandbox user is root). Its debugging port listens on loopback inside the sandbox, and is one the kernel chose: the driver reads it back from DevToolsActivePort in that fresh profile, so on a borrowed sandbox it can never attach to a browser someone else started.

How the browser is reached: the driver connects through a signed preview URL for the debugging port only, never the sandbox-wide preview token, which would also reach the sandbox's toolbox and terminal. The URL expires two minutes after it is issued; an established connection outlives that. close() revokes it. It never appears in logs or error text, and member errors are fixed phrases (The navigation failed (net::ERR_NAME_NOT_RESOLVED).) with no URLs, paths or exception text.

Files

from daytona_claude_toolsets import DaytonaBrowser, DaytonaFilePolicy

browser = DaytonaBrowser(
    configs={"file_upload": {"enabled": True}},
    confirm=my_confirm,
    file_policy=DaytonaFilePolicy(upload_roots=["/home/daytona/uploads"], expose_download_paths=True),
)

Upload paths are sandbox paths. The policy admits absolute paths under a root, with .. refused. The driver then resolves each one inside the sandbox, following symlinks, and checks the resolved path against the roots again. A file policy of your own declares no roots to re-check against, so there a path that resolves to somewhere else is refused outright — a link planted in an upload directory cannot carry the upload out of it. Resolving and uploading are two steps, not one — the toolbox API hands back a path, not a handle to hold — so anything else running in the sandbox that can write to the upload directory could swap a checked file in between; keep that directory writable only by you. Files API document_ids are refused. Downloads are saved to browser.download_dir in the sandbox (created 0700, outside the upload roots). The model sees a download's path only with expose_download_paths=True. Treat downloaded files as untrusted.

Limitations

  • Computer platform floor: migrated members (triple/multi-click, modifier clicks/drags/scrolls, horizontal scroll, left_mouse_down/up, hold_key, type, and native-routed numpad digits/decimal/equal/lock) need a sandbox on a Daytona version with the native mouse/keyboard hold endpoints. Older sandboxes return a ToolError telling you to recreate the sandbox. XTest remains for numpad Enter/operators, exotic keysyms without a Daytona key name and mouse click/drag/scroll chords holding a non-modifier key token.
    • A sandbox created from a custom or older image may run an older daemon than the default snapshot does: daytonaio/sandbox:latest came up on daemon 0.217.0, where the capability probe gets a 404 and every migrated member returns that ToolError. Use the default snapshot (create_params omitted, or CreateSandboxFromSnapshotParams()) unless you have a reason not to.
  • Browser: frames are not traversed by read_page/find/get_page_text. find is keyword-based. A dropped CDP connection is not re-established, so build a new DaytonaBrowser. Use it from one thread, outside an asyncio event loop (Playwright's sync API).
  • Both: the default sandbox user's login shell is /bin/sh, so a terminal the model opens has no line editing (ctrl+a arrives as ^A).

Examples

Script What it does
examples/run_computer.py Model-driven desktop task (default: open a terminal and run date)
examples/run_browser.py Model-driven browser task with an example URL policy (ALLOWED_DOMAINS)
examples/exercise_computer.py No model: every computer member against a real sandbox, results and refusals asserted
examples/exercise_browser.py No model: every browser member against pages served inside a real sandbox

Development

python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
pytest                               # unit tests (offline, Daytona and Playwright mocked)
python examples/exercise_computer.py # live checks (need DAYTONA_API_KEY)
python examples/exercise_browser.py
ruff check . && black --check . && mypy daytona_claude_toolsets

License

Apache-2.0

Metadata

Release files for daytona-claude-toolsets 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for daytona-claude-toolsets 0.1.0
File Size Uploaded
daytona_claude_toolsets-0.1.0.tar.gz 61.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for daytona-claude-toolsets 0.1.0
File Interpreter ABI Platform
daytona_claude_toolsets-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 123.0 kB

Release files / daytona_claude_toolsets-0.1.0.tar.gz

Download URL daytona_claude_toolsets-0.1.0.tar.gz
Size 61.8 kB
Tags Source
SHA-256 checksum
How to use checksums
c5e24b1de37a21e981bbc8ae833bb1b24fde14f9929669d8106bb81ee0eec2ee
BLAKE2b-256 checksum
How to use checksums
7d3d7538abd91a01f2282d15283126c3af1c63dfae4b173e2672169e893efa88
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Release files / daytona_claude_toolsets-0.1.0-py3-none-any.whl

Download URL daytona_claude_toolsets-0.1.0-py3-none-any.whl
Size 61.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
99c96d0abb9e87917edc8e9fa49d3e6aa09ade2c3dc0317fd4e4f20fbee93a9d
BLAKE2b-256 checksum
How to use checksums
577723cb4ea97caf35527ca39be22f81e69a1ce2c62944c0c44103173bafa36a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 7, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page