computer-use
Provides a JSON-RPC computer use runtime for macOS, exposing 7 MCP tools (observe/act/inspect/session/cancel/trace) as image content blocks so external agents like Claude Code, Pi, OpenCode, or Codex CLI can capture screenshots and drive the desktop with clicks, keys, and typing while enforcing session locking, stale-frame protection, and trace redaction server-side.
README
computer-use
A model-agnostic, vision-first Computer Use runtime for macOS (macOS 14+).
External agents (Claude Code, Pi, OpenCode, Codex CLI, or any model) drive the desktop through a small JSON-RPC surface: capture screenshots, act on them with clicks/keys/typing, and stay safe behind session locking, stale-frame protection, and trace redaction. The runtime has no model dependency — it never calls an LLM. The loop is always: agent observes → agent decides → runtime executes.
+----------------+ JSON-RPC 2.0 +-------------------+ line-JSON +---------+
| agent (Pi, | <===============> | cu-daemon | <===========> | cubridge|
| OpenCode, ...) | ~/.computer-use | sessions, locking, | Unix pipe | Swift: |
| via SDK / MCP | /runtime.sock | stale-frame, trace | | SCK |
+----------------+ +-------------------+ | capture |
| cu-runtime · cu-driver-macos +---------+
What's inside
| Component | Where | Purpose |
|---|---|---|
cu CLI |
crates/cu-cli | daemon lifecycle, session, observe/act, traces |
| Daemon | crates/cu-daemon | JSON-RPC 2.0 over a Unix socket (current-user only) |
| Runtime | crates/cu-runtime | sessions, control lock, action queue, stabilizer, pause/resume/takeover/stop |
| macOS driver | crates/cu-driver-macos | capture, mouse, keyboard, displays, clipboard, permissions |
| Swift bridge | crates/cu-driver-macos/swift | ScreenCaptureKit + clipboard + AX (the only Swift in the project) |
| Trace recorder | crates/cu-trace | session JSONL traces with redaction |
| TypeScript SDK | packages/sdk-typescript | ComputerUseClient for Node agents |
| MCP Server | packages/mcp-server | 7 tools (observe/act/inspect/session/cancel/trace) as image content blocks |
| Pi Extension | packages/pi-extension | 4 tools with real image content blocks + 8 slash commands, abort + lifecycle |
| OpenCode adapter | packages/opencode-adapter | companion CLI (cu-opencode) + official MCP config for OpenCode |
| Inspector | apps/cu-inspector | minimal local dashboard (http://127.0.0.1:8420) |
Quick start
# 1. build
cargo build --release
# 2. grant permissions once (see docs/permissions.md):
# System Settings → Privacy & Security → Screen Recording → add cubridge
# 3. start the daemon
cu daemon start
# 4. drive it
cu doctor
cu observe --include-image --image-out /tmp/screen.jpg # first observe auto-creates a session
cu move 500 400
cu click 500 400
cu type "hello" # text is redacted in traces
cu session stop # only the client that started the session may stop it
Sessions are created on first use. The first observe/act from any
client auto-starts a session when none is active (the CLI resolves the active
session first and only starts when the daemon reports SESSION_NOT_FOUND).
The daemon records who started it — every client sends its identity
(client_id / client_name / client_instance_id) with session start, and
session status returns the owner. Ownership matters: a session may be
stopped by the client that created it (a second client trying to use it gets
CONTROL_LOCKED under the default policy — see the Pi extension's
COMPUTER_USE_EXISTING_SESSION_POLICY).
Type actions are redacted by default: traces record text_redacted: true
and a character count, never the text itself. To log full text (e.g. a
development environment you trust), run the daemon with dev mode on — see
Trace redaction.
The four tools (any agent)
| Tool | Purpose |
|---|---|
computer_observe |
Capture the screen → frame_id + image + metadata |
computer_act |
Execute actions on a frame (click, move, type, key, scroll, drag, wait) |
computer_inspect |
Crop a region of a stored frame (vision detail, no DOM/XPath/OCR) |
computer_session |
Start / status / pause / resume / takeover / release / stop |
Plus trace inspection (trace_list, trace_get, trace_export,
trace_replay) and runtime introspection (health, permissions, displays,
pointer, active-application).
Everything the runtime enforces — frame staleness, coordinates in bounds, pause, takeover, session state, the control lock — is enforced server-side, not by the client, so every adapter gets the same guarantees.
Security model
- Socket: Unix domain socket at
~/.computer-use/runtime.sock, mode0700— only your user can connect. - Sessions: one active session at a time (control lock). The first
client request auto-creates a session; the creator is recorded as its
owner and is the only client that stops it. A session owned by another
client is refused with
CONTROL_LOCKED(the Pi extension can opt intoattachmode to use, but never stop, a foreign session). Every observe/act carries asession_id. Actions on a stale, paused, taken-over, or stopped session are rejected with a specific error code. - Control tokens (capability):
session startreturns a session's control token exactly once (256-bit random). Knowing a session ID does not grant control — every mutating operation (pause / resume / takeover / release / stop, act, cancel) requires the token (CONTROL_TOKEN_REQUIREDwithout it,INVALID_CONTROL_TOKENwhen wrong), while read-only calls (status,observe,inspect) need none and never repeat the token. The daemon stores only a SHA-256 hash, never logs it, andstopor a daemon restart invalidates it. The SDK and CLI keep the token in per-session credential files (0600) and inject it automatically into the calls they own. Existing sessions default toreject: a client that finds a session it does not own must not silently attach —read_only(observe-only) andattach_with_token(caller supplies the token) are explicit opt-ins. - Stale frames: acting on anything but the session's current frame is
rejected (
STALE_FRAME) under the defaultstrictpolicy; thevisual_matchpolicy (envCOMPUTER_USE_STALE_POLICY) additionally allows an older frame whose content still matches the live screen. Live visual comparison + app-change + age backstop always run on top. - Bounds: actions outside the display are rejected (
OUT_OF_BOUNDS). - Redaction:
typerecords{ text_redacted: true, character_count }in traces; full text only under an explicit opt-in. - Takeover: a human can grab the mouse at any time; the session flips to
user_takeoverand the runtime refuses further actions.resumecannot bypass it — the agent mustreleasefirst (USER_TAKEOVER_ACTIVE). - See docs/protocol.md for the full error table and docs/permissions.md for the permission gotchas (including the "rebuild cubridge → re-grant Screen Recording" one).
Trace redaction
Default: on. cu daemon start runs with redaction. To record full typed text
in traces (development only):
COMPUTER_USE_TRACE_DEV_MODE=1 cu daemon start
Each trace entry keeps redaction: { text_redacted, character_count } so you
can audit what happened without exposing secrets.
Trace recording policy (COMPUTER_USE_TRACE_MODE): best_effort (default —
a trace write failure degrades the trace and computer.act reports
trace: {degraded: true, warnings}), required (session start / act fail if
the trace cannot be recorded), or disabled (no recorder).
Layout
~/.computer-use/
├── runtime.sock # JSON-RPC socket (0700)
├── bin/cubridge # compiled Swift bridge
├── frames/ # captured frames (per session, named s_<id>_<n>.jpg)
├── traces/ # s_<id>.jsonl session traces
└── daemon.log
Tests
cargo test --workspace # 175 tests (Rust: core, driver, runtime, daemon protocol, ownership matrix)
cargo test -p cu-daemon --test integration -- --ignored # live security-matrix test
pnpm install && pnpm -r build && pnpm -r test # 80 tests: SDK (33), Pi (14), OpenCode adapter (23), MCP (10)
./scripts/smoke.sh # automated smoke: gates + Pi/OpenCode wiring snapshots
Real-environment acceptance (needs a logged-in GUI session, Screen Recording + Accessibility permissions, daemon running, no active session):
node scripts/pi-host-acceptance.mjs # Pi extension, real code, real daemon/screen — 31 checks
node scripts/opencode-mcp-acceptance.mjs # real computer-use-mcp binary over stdio, real daemon/screen — 17 checks
node scripts/ownership-scenario-a.mjs # ownership: MCP-owned session vs. the Pi extension — 6 checks
See docs/acceptance-manual.md for the full manual checklists (Pi 20 steps, OpenCode 14 steps, ownership A/B/C) and the results recorded during the round-2 and round-3 acceptance runs.
Documentation
- docs/architecture.md — components, threads, data flow
- docs/protocol.md — JSON-RPC surface, methods, error codes, session behavior (auto-create, ownership, cancel)
- docs/permissions.md — Screen Recording / Accessibility setup & troubleshooting
- docs/acceptance-manual.md — Pi (20 steps) + OpenCode (14 steps) manual acceptance checklist, with round-2 and round-3 results
- docs/uninstall.md — clean removal
- packages/sdk-typescript/README.md
- packages/mcp-server/README.md
- packages/pi-extension/README.md
- packages/opencode-adapter/README.md
License
MIT (see LICENSE).
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。