Skip to main content

deskpilot

Desktop control for agents on Hyprland. An agent takes a screenshot of a window, picks a point in it, and clicks or types there, in any app: native Wayland, XWayland and Wine programs such as the Battle.net launcher and games.

The user keeps their own pointer and keyboard focus. Clicks, scrolls and keys run inside the compositor through the deskpilot Hyprland plugin: in one step it holds the user's mouse input, delivers the event to the target window through the user's own seat, then puts the pointer back where it was, applying any mouse motion the user made meanwhile. Only pointer focus moves, so keyboard focus stays on the user's window and the target is not raised, even with focus_on_activate set. Wayland, XWayland and Wine clients all receive the press as a real click. The plugin refuses a click when another window covers the point.

An agent cursor shows where deskpilot acts: cua-driver's overlay arrow glides to each point, drawn above every window and separate from the user's pointer. Without cua-driver on PATH, or with DESKPILOT_CURSOR=off, actions run without it.

Keys sent to a window (--window) go to that window only, with each stroke complete before focus returns, and the user's modifiers never leak into them. X11 apps take keys only from the window with X input focus, so an XWayland target gets X focus for each stroke and sees a focus-in and focus-out around it; Hyprland's own focus does not move.

--take-pointer and --take-focus use a virtual input device made with /dev/uinput instead, which the compositor treats as real hardware. Tools that synthesize input another way, such as xdotool (XTest) or wtype (the virtual keyboard protocol), are ignored by some clients: Battle.net drops xdotool clicks, and a game drops wtype keys.

Requirements

  • Hyprland, with hyprctl on PATH. Version 0.57's Lua dispatchers and the older string ones both work.
  • The plugin build tools: a C++26 compiler, make, Hyprland's headers (pkg-config hyprland, shipped with Arch's hyprland package), libxcb and libxkbcommon.
  • Optional: cua-driver for the agent cursor.
  • grim for screenshots.
  • For --take-pointer, --take-focus and keys without --window: write access to /dev/uinput, usually through the input group or a udev ACL. Check with test -w /dev/uinput.
  • Python 3.12 or later and uv.

Install

uv tool install deskpilot

The agent skill, which teaches an agent the steps below, installs in Claude Code with:

/plugin install deskpilot --marketplace cjber/deskpilot

Use

deskpilot windows                         # every window: address, class, title, geometry, whether on screen
deskpilot shot battle.net.exe             # screenshot; prints its id, image path and scale
deskpilot click battle.net.exe 920 367 --shot ID    # a point in that screenshot
deskpilot type "/reload" --window wow.exe --delay 0.12
deskpilot key ctrl+a --window kitty
deskpilot wait-for wow.exe --timeout 120

A window is named by its address, its class, or a substring of its class or title. A name that matches more than one window is an error listing them, so a click never lands on a guessed window.

shot captures the window itself, so a window on top does not show in it, and saves it under an id. move, click and scroll take pixels in the shot named by --shot, or the window's latest one, whatever scale it was taken at. A window resized since that shot is refused, as is a point outside the window. Pass --scale 1 to give window pixels instead.

A window on a hidden workspace or scrolled off its monitor is reported as "visible": false, and shot, move, click and scroll refuse it rather than move the user's view. --show focuses it to bring it on screen first.

The first action that needs the plugin builds and loads it for the running Hyprland, so it comes back by itself after Hyprland restarts or upgrades. deskpilot plugin load does the same ahead of time.

move only shows the agent cursor. Pass --take-pointer to move, click or scroll to move the user's own pointer there and press through the input device instead, for a hover the app must see.

A shell started before Hyprland restarted keeps a stale HYPRLAND_INSTANCE_SIGNATURE. deskpilot then talks to the one instance whose socket answers, and with several live instances it stops and names them.

key and type without --window press keys into whatever has focus. --take-focus focuses the window and leaves it focused, for an app that ignores keys while unfocused.

Games read keys once per frame, so type into them with --delay 0.1 or more: each key is held that long, with the same gap before the next.

Clicks, scrolls and keys from several agents at once run one after another in the order they arrive, so one type is never interleaved with another's keys. Up to 32 wait behind the running one; past that an action is refused.

MCP

deskpilot mcp serves the same actions over stdio: windows, focus, shot (returns the image and its shot id), click, move, scroll, key, type_text and wait_for. click, move and scroll take shot, show and take_pointer; key and type_text take take_focus. It keeps one input device and one agent cursor open for the session.

claude mcp add deskpilot -- deskpilot mcp

Limits

  • Text is typed on a US layout; a character that layout cannot type is an error rather than skipped.
  • Hyprland plugins load only into the exact Hyprland they were built against, so deskpilot plugin load builds one per Hyprland commit and plugin source under ~/.local/share/deskpilot, and replaces a loaded build of other source.
  • Each CLI action that uses the input device opens a new one and waits about a second for libinput to add it. The MCP server avoids that wait.
  • Hyprland only, Linux only.

Development

AGENTS.md has the checks, the layout and the rules a change must keep, and CONTRIBUTING.md how to report a bug or send a change.

Metadata

Release files for deskpilot 0.2.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 deskpilot 0.2.0
File Size Uploaded Provenance Actions
deskpilot-0.2.0.tar.gz 103.6 kB Without provenance Details for deskpilot-0.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for deskpilot 0.2.0
File Interpreter ABI Platform Actions
deskpilot-0.2.0-py3-none-any.whl Python 3 none any Details for deskpilot-0.2.0-py3-none-any.whl

Total release size: 143.6 kB

Release files / deskpilot-0.2.0.tar.gz

Download URL deskpilot-0.2.0.tar.gz
Size 103.6 kB
Tags Source
SHA-256 checksum
How to use checksums
7ae82cfa0753c96158808d2e183b290423b5a7756cd1a16cfa3a8c2bffb99b02
BLAKE2b-256 checksum
How to use checksums
09c9ed05557cbadc9fdf8bd4781b2e8445f53cbcda10f18efa0ecf58a65c85d9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.18 {"installer":{"name":"uv","version":"0.12.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / deskpilot-0.2.0-py3-none-any.whl

Download URL deskpilot-0.2.0-py3-none-any.whl
Size 40.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7014c989f7e4da8c14537cc87639d2e11fb401203b1a0735524caec3748e4756
BLAKE2b-256 checksum
How to use checksums
1d8ba289015132c3db28e9c0eb2bd8ca6891a3843c02c0b7f5860fdb27cbc1a5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.18 {"installer":{"name":"uv","version":"0.12.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for deskpilot 0.2.0

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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