Experiment: drive a use.computer macOS sandbox with AppleScript and
watch the screen change. A one-page local tool: type what the Mac should do, Claude writes the
AppleScript, the sandbox runs it, the screenshot refreshes. Not an agent: one prompt, one script, one run.
npm start # http://localhost:3000 — the sandbox is created on the first request
The page embeds the gateway’s noVNC viewer, so you watch the script run live and can click and
type in the Mac yourself. Next to it: the generated script, stdout, stderr and the exit code.
Ctrl+C deletes the sandbox. Design and plan:
docs/specs, docs/plans.
Before the web app came a set of sandbox E2E scenarios that establish how the VMs behave. Each one:
create sandbox → dismiss the screen-recording prompt → screenshot → run an AppleScript block via
osascript → verify → screenshot.
Scenario file (tests/e2e/) |
What it proves |
|---|---|
prompt-dismiss |
Every fresh sandbox shows a screen-recording prompt; dismissScreenRecordingPrompt() clicks Allow and it stays gone |
gui-textedit |
Launch an app, put text in a document, one window on screen |
gui-safari |
open location loads a real page, so the VM has network |
gui-finder-desktop |
Finder scripting creates a file and opens a window on the Desktop |
gui-keystroke |
activate makes the app frontmost; System Events keystroke and SDK keyboard.hotkey both reach it |
gui-dialog |
display dialog from an SSH-run script shows on screen and gives up on its own |
npm install
.env (gitignored):
USE_COMPUTER_API_KEY=uc_live_...
USE_COMPUTER_RESERVATION_ID=... # an active Mac mini reservation; the code never reserves
ANTHROPIC_API_KEY=sk-ant-... # for the web app's AppleScript generation
npm start # the web app
npm run test:unit # pure functions, no network
npm run test:int # SandboxSession + the /api/run path with real Claude and a real sandbox
npm run test:e2e # sandbox scenarios, ~3 min, writes test-results/<scenario>/*.jpg
npm run test:e2e:web # Playwright drives the page against a real server
See testing.md for details.
use-computer-sdk 0.1.13, macOS 15.4.1)lume, uid 501, console session.UserNotificationCenter. While it is up: apps launched with AppleScript activate come updismissScreenRecordingPrompt() in src/sandbox.ts clicks its Allow buttonactivate, keystrokes and screenshots behave like a normalcreate().osascript over SSH works, including app automation and UI scripting. tell application "TextEdit" and System Events keystroke run with no permission prompt, so Automation andsandbox.keyboard.hotkey("cmd+n") works too.takeCompressed() sends no parameters andtakeScreenshot() callsGET /v1/sandboxes/{id}/screenshot/compressed?format=jpeg&quality=80 directly.display dialog works from SSH without tell application "System Events". The dialogosascript process, which appears in uiTree() with one window while it is up.https://example.com in about 2 s,make new file at desktop and open (path to desktop) behave as on a normal Mac.ephemeral: true sandboxes are deleted about 2 min after the last activity.sandbox.keepalive()), so SandboxSession runs its ownsandbox.vncUrl points at a small noVNC page onX-Frame-Options or CSP, so an <iframe> gives a live, interactive viewtoken is the account API key, so this is forstop_reason: "refusal", category cyber). The request opts into server-side fallbacksfallbacks: "default" with the server-side-fallback-2026-07-01 beta), so the API re-runs aclaude-opus-4-8; the page shows which model wrote the script.