Repository navigation
feat(computer): cua-driver as a computer driver, its own tools beside computer/v1 - #396
Merged
Merged
Conversation
trycua's cua-driver 0.38.0, from its PyPI wheel, runs on the computer as a daemon, and agents get its own 66 tools beside the computer_* tools, forwarded on each caller's connection. The computer/v1 operations are its desktop-scope calls in a session of the framework's own, computer-ready checks the pinned executable and tools, and the skill leads with cua-driver's own skill pack. The protocol SDK gains forwarded tools, served with their own schemas, and skills with files beside their SKILL.md, which add_skills sends as a stored bundle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…intable keys in the skill Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…'s daemon restarts Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
…t and cancelled requests honest add_skills refuses an env skill file whose path leaves the skill's folder, before anything is stored. The cua-driver driver closes a connection whose request is cancelled in flight, so its reply can't answer the next request; fails input whose reply is lost after it was sent as DeliveryFailed, its outcome unknown; and refuses a click, drag or chord holding a key that isn't a modifier as unsupported. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…simplify the driver - Each caller, told apart by MCP session, and the framework run in an unnamed cua-driver session of their own, stamped as the daemon request's session_id, as cua-driver's own MCP server does. All agents used to share one session, which owns screenshot frames, the agent cursor, config overrides and recordings. cua-driver ends a named session after five idle minutes and refuses every later call in it; the framework's calls ran in the named session "agentenv", so computer/v1 failed after five idle minutes. An unnamed session is started again on its next call. - Each call goes on a connection of its own, as cua-driver's MCP server sends them, which drops the kept connections' resend-after-restart and cancel handling. - driver.py starts the daemon when run as a script, exec'ing the executable computer-ready hashes, with the socket and no-telemetry settings defined once; daemon.sh is gone. - The computer skill builds its opening apart from its sections, and PRINTABLE_KEYS is shared from agentenv_protocol.computer. - The drivers README gains the version-bump steps and says element tokens belong to windows, not sessions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ter, isn't agent-env configuration Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…kill resources as its own MCP server does
- The SDK gains instructions(), what an environment's MCP server tells an agent
when it connects; forwarded_resources() with ForwardedResource, MCP resources
served on another server's behalf; and an output_schema on ForwardedTool,
listed as the tool's outputSchema and not checked here.
- The cua-driver driver serves what cua-driver mcp 0.38.0 serves: its
instructions, its 66 tools with their output schemas (39 declare one), and
its 11 skill resources at skill://cua-driver/, whose text is read from
cua-driver mcp itself. mcp.json pins the instructions, tools and resource
list and replaces tools.json.
- A failed call is answered as cua-driver mcp answers one, structured content
{"code": "tool_invocation_failed", "exit_code": n}, which every tool's output
schema admits, so strict clients still pass the message on.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r_instructions An env marks the plain method that returns its MCP server's instructions with @server_instructions, as it marks its skill with @agent_skill, in place of an instructions() hook. They're read when the SDK builds the app, so a direct create_fastmcp_app(handler, ...) gets them too; an env has at most one such method, and a coroutine is refused at decoration. An app passed to mount keeps its own instructions, as the README says. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lace of forwarded_resources() An env marks each method that serves MCP resources with @resource, as many as it likes, and the URI decides what's served: a fixed URI is one resource; a template such as orders://{order_id} is an MCP resource template whose parts the method takes; a template with listed= serves only the resources listed returns, as MCP lists them, each read through the method with its URI's parts. The cua-driver driver serves cua-driver's 11 skill files with @resource("skill://cua-driver/{file}", listed=...) over mcp.json's list. ForwardedResource and forwarded_resources() are gone. A URI served twice, a listed URI off its template and a method not taking exactly the template's parts are refused; listed resources keep an absent description absent, as cua-driver lists them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
M2.9 of the CUA env epic (FD-4345): cua-driver as a driver you can name in place of the reference driver, FD-4357. It follows the design doc CUA Env M2.9: cua-driver as a Driver, whose seven choices were all decided on 2026-10-29.
An env names
driver = "cua-driver"and its computer runs trycua's cua-driver. Agents get what cua-driver's own MCP server (cua-driver mcp) serves, its instructions, tools and skill resources, beside ourcomputer_*tools and our skill. The framework keeps the samecomputer/v1contract, built on cua-driver.What's in it
The cua-driver driver (
src/agent_env/drivers/envs/cua-driver/, aliascua-driver):Install: cua-driver 0.38.0 from PyPI, in
requirements.txt. Its wheel carries the executable for both Linux arches.The daemon:
driver.py, run as a script, startscua-driver serveas a session-user service once X answers, exec'ing the executablecomputer-readyhashes. It starts in the user's home, listens on/run/agentenv/cua-driver.sock, bypasses approvals, and has telemetry, update checks and the overlay cursor off.What agents see, as
cua-driver mcp0.38.0 serves it (pinned inmcp.json):computer_*tools. Each call is forwarded unchanged, and cua-driver's reply comes back as it sent it. An env narrows the tools with[tools];skill://cua-driver/…, which its instructions point to, served by one@resourcemethod overmcp.json's list, their text read fromcua-driver mcpitself;{"code": "tool_invocation_failed", "exit_code": n}, which every output schema admits.computer/v1: cua-driver's desktop-scope calls (XTest), made in the framework's own session:get_screen_sizeandget_desktop_state;click, with 3 buttons, up to a triple click;drag, from a start to an end point;scroll,type_textandpress_key.There's no pointer or keyboard hold group. Scrolling with keys held, and chords that hold a non-modifier key, are refused as unsupported.
computer-readychecks the executable's sha256 against the value pinned for each arch, and that the daemon lists the toolsmcp.jsonpins. Both are checked until they pass once.Sessions: each caller, told apart by MCP session, and the framework run in an unnamed cua-driver session of their own, as cua-driver's own MCP server gives each client. A caller's call that names a session runs in that one. Element tokens still belong to a window, not a session, so two agents reading one window invalidate each other's tokens for it.
Connections: each call goes on a connection of its own, as cua-driver's own MCP server sends them. A call while the daemon restarts fails as unavailable, and input that couldn't be sent is "not applied". Input whose reply is lost fails as
DeliveryFailedwith its outcome unknown.The skill leads with cua-driver's own skill pack, written offline from the executable's embedded copy, with its 8 other files beside the SKILL.md. A "This computer" section of ours follows.
The protocol SDK:
forwarded_tools()andForwardedToolserve tools on another server's behalf. Each keeps its own schema, annotations and output schema, its arguments pass through untouched, and itsCallToolResultis returned as it is. They're on the card, chosen byserved_toolsand under tool access, like@toolmethods. They need mcp's FastMCP.@resource: marks a method that serves MCP resources; an env may mark several. A fixed URI is one resource; a template such asorders://{order_id}is an MCP resource template whose parts the method takes; a template withlisted=serves only the resourceslistedreturns, each read through the method. The cua-driver driver serves cua-driver's skill files with@resource("skill://cua-driver/{file}", listed=...).@server_instructions: marks the plain method that returns what the env's MCP server tells an agent when it connects (theinstructionsof itsinitializeresult), as@agent_skillmarks its skill. It's read when the SDK builds the app; an app passed tomountkeeps its own.@agent_skillmay return a skill's other files as a third value, andskill/v1'sgetreturns them asfiles.ComputerDriverEnvironment.bundled_skill(): the skill a driver's software ships. The computer skill leads with it.PRINTABLE_KEYSis exported fromagentenv_protocol.computerfor drivers.agent-env:
add_skillssends an env skill that has files as a bundle, stored once per content underagentenv-env-skills/<digest>/in the object store.driversbundle gains thecua-driveralias. A test bundle,tst/integration/computer/cua-driver/, names it.Changed while building
skill/v1couldn't carry.ComputerSettingsis closed, and nothing uses the setting before the bench.name(launch_app's) collided with the forwarding method's own parameter. The tool name is positional-only now.fullon cua-driver alone.agentenv, socomputer_*failed after five idle minutes. An unnamed session is started again on its next call.DeliveryFailed, outcome unknown; an env skill's files must stay in its folder; holding a key that isn't a modifier is refused as unsupported.daemon.shis gone.driver.pystarts the daemon, so the socket and the no-telemetry settings are defined once. The drivers README has the steps for moving to another cua-driver version.cua-driver mcpsends besides tools. A side-by-side check againstcua-driver mcpfound three gaps: its instructions, its tools' output schemas and its skill resources. All three are served now.mcp.jsonreplacestools.json. The resources' text is read fromcua-driver mcprather than pinned, since that would add 266 KB of markdown to every install. A separate check showed the Linux packmcp-configwrites leaves two of the 11 out.Testing
cua-driver ran only on two test VMs in agent-environments-admin: c6i.2xlarge (amd64) and c7g.2xlarge (arm64), each probing its own arch.
tst/unitand the protocol tests, 11,800 passed and 66 skipped, with one Hermes test failing on macOS only, since it reads/proc/self/fd.add_skills' stored bundle;name, and two callers in sessions of their own;fullpassed 47 checks, with 1 not applicable, on both arches.launch_app, read its tree withget_window_state, and clicked "Open Parent" by element token.computer-readyreported "66 tools, as pinned", and the skill came with its 8 files.computer_*call failed with "session has ended".driver.py, the shared keys, the skill's opening): a smoke test on amd64, with the cua-driver tests 2 of 2 and the daemon killed mid-run 3 of 3.cua-driver mcp, on one amd64 computer: the same instructions; all 66 tools the same in description,inputSchema, annotations andoutputSchema; the same 11 resources with the same text; and the same answer to a call in an ended session. Ours adds only the sevencomputer_*tools. The cua-driver tests passed 2 of 2, now also checking the instructions and a resource read.🤖 Generated with Claude Code


Confidence Score: 5/5
The PR appears safe to merge; no new actionable issue was established.Summary
Adds
cua-driveras a computer driver while keeping thecomputer/v1contract.cua-driverfor computer control.Diagram
%%{init: {'theme': 'neutral'}}%% flowchart LR Agent[Agent MCP session] --> SDK[Protocol SDK] SDK --> Forwarded[cua-driver tools] SDK --> Computer[computer_* tools] SDK --> Resources[Skill resources] Forwarded --> Caller[Caller-specific session] Computer --> Framework[Framework session] Caller --> Daemon[cua-driver daemon] Framework --> Daemon Resources --> Upstream[cua-driver MCP server] Upstream --> DaemonReviews (7) · Last reviewed commit: "refactor(protocol): serve an env's MCP r..." · Reviewed by Greptile