deskpilot
Desktop control for agents on Hyprland. Inspect a window, target an accessibility element or a screenshot point, and click, scroll or type while you keep working.
A local demo app, operated by Deskpilot with its real cursor and click feedback. Static image | 60 fps video | Recording and source
| What you need | What deskpilot gives you |
|---|---|
| Find a control | Live accessibility trees with element IDs, or a window screenshot with recorded coordinates |
| Send input | Click, scroll, hover, drag, type, key chords and private paste |
| Work out of sight | Launch your own native Wayland apps on an agent's hidden workspace |
| Reduce round trips | CLI and MCP actions, plus a sequence of known steps in one batch |
Install
uv tool install deskpilot
The first input action builds and loads the plugin for your running Hyprland. Run deskpilot plugin load to
prepare it ahead of time. The build needs the tools listed under Requirements.
For Claude Code, install the agent skill:
/plugin install deskpilot --marketplace cjber/deskpilot
For MCP clients, run deskpilot mcp over stdio. In Claude Code:
claude mcp add deskpilot -- deskpilot mcp
Quickstart
List your windows, then replace WINDOW below with one address from the output:
deskpilot windows
deskpilot elements WINDOW
In an app with an accessibility tree, choose a control from the output and replace ELEMENT with its ID:
deskpilot click WINDOW --element ELEMENT
Deskpilot asks the app for that element's current position before clicking. Prefer the full SNAPSHOT:e27 form
from the reported snapshot and element ID, so a newer tree cannot reuse an old ID accidentally.
For an app without a tree, capture its window:
deskpilot shot WINDOW
Read the image at the printed path, then click a point in that image with
deskpilot click WINDOW X Y --shot SHOT_ID, replacing X, Y and SHOT_ID with the point and printed shot ID.
A resized window or a point outside the recorded window is refused. Take a fresh shot to verify the result;
use wait-for WINDOW --changed SHOT_ID when the app needs time to draw it.
More actions and targeting rules | Accessibility and popup handling
Chain known actions
Send a JSON array through a file or stdin to run up to 32 steps in one CLI process or MCP request:
deskpilot batch WINDOW --final-shot <<'JSON'
[
{"action": "key", "combo": "ctrl+a"},
{"action": "type", "text": "Hello from deskpilot"}
]
JSON
This example replaces text in the target app's current field. Run it only after inspecting that field.
Supported steps are click, move, scroll, drag, key, type and paste. Element IDs and shot IDs work
on the corresponding pointer steps. --final-shot returns a capture after all steps succeed.
The entire request is validated before input starts. Each step rechecks the pinned window and uses the same refusals as a single action. A failure stops the batch and reports the completed steps and failing index; earlier actions stay done. Other agents and the user can act between steps.
Work on your own hidden window
Set an agent name and launch a native Wayland app of your own:
export DESKPILOT_AGENT=demo
deskpilot launch APP
Replace APP with an installed app and use the window it reports. Add --hidden to actions on those windows,
including batch; hidden keys and text also need --window. deskpilot stop closes your agent's apps.
deskpilot show intentionally brings the agent workspace into view for you to watch or step in.
For an existing unfocused native window, deskpilot adopt ADDRESS explicitly hands only that exact window to
the agent. deskpilot release ADDRESS returns it without closing its shared application.
Hidden actions preserve your view, pointer and focus and only reach windows that agent launched or adopted. XWayland targets are refused hidden. For browser tasks, use fastbrowse.
For a private desktop with separate profiles, clipboard and X server, put --session before every command,
starting with DESKPILOT_AGENT=NAME deskpilot --session launch APP. End it with deskpilot --session stop.
Hidden-window behaviour, adoption and private desktops
Your input stays yours
The plugin sends input to the target client directly where supported. Some clients, including XWayland, require a seat-based route that briefly holds input, restores your pointer and focus, and replays intervening user input. A private paste preserves your clipboard; apps that cannot receive one are refused.
--take-pointer, --take-focus and --show explicitly take your pointer, focus or view.
Input routes and their limits explains the client-specific behaviour.
Requirements
- Hyprland, with
hyprctlonPATH. 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'shyprlandpackage),libxcb,libxkbcommonandcairo. grimfor screenshots.wl-clipboardforclipboard.- For
--take-pointer: write access to/dev/uinput, usually through theinputgroup or a udev ACL. Check withtest -w /dev/uinput. - Python 3.12 or later and
uv.
Documentation and contributing
- Command guide: actions, screenshots, accessibility, MCP and error codes.
- Input routing: dedicated seats, keymaps, agent cursors and hidden windows.
- Live calibration: isolated input checks and cleanup verification.
- Contributing: setup, checks and bug reports.
- Security: report a vulnerability privately.
- Changelog: changes by release.
Metadata
Release files for deskpilot 0.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| deskpilot-0.7.0.tar.gz | 1.5 MB | Without provenance | Details for deskpilot-0.7.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| deskpilot-0.7.0-py3-none-any.whl | Python 3 | none | any | Details for deskpilot-0.7.0-py3-none-any.whl |
Total release size: 1.7 MB
Release files / deskpilot-0.7.0.tar.gz
| Download URL | deskpilot-0.7.0.tar.gz |
|---|---|
| Size | 1.5 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f331f4a3b56b6e2dac72e7c864a22b68bea021d6e2def770c0e2841722b27c93
|
|
BLAKE2b-256 checksum How to use checksums |
28b23f6dec3fd15bf6c14e4d2bc4d3b7867d90c0fc66dec8ac5aeae353d61639
|
| 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":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / deskpilot-0.7.0-py3-none-any.whl
| Download URL | deskpilot-0.7.0-py3-none-any.whl |
|---|---|
| Size | 128.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5d7103beb69e8705741a6586730b218913a914c80d13f30ba2077d9a5f0b1f24
|
|
BLAKE2b-256 checksum How to use checksums |
ffbc1810d3e81d8e29b267d9b81c46f41b9fd40740bcaa2060a676a7e4a442e5
|
| 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":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for deskpilot 0.7.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.