Skip to main content

pctr

Element-based Windows UI Automation CLI for AI agents.

Instead of screenshotting and guessing pixel coordinates, pctr finds controls by their name / control type / automation id and acts on them. Window moves, DPI changes, and layout shifts don't break your script.

Built on pywinauto (UI Automation) with pyautogui / pydirectinput for raw mouse and keyboard input. On top of UIA it also offers OCR (Windows.Media.Ocr) and YOLO-World open-vocabulary detection for text and objects that aren't exposed as controls.

pctr driving by element name: enumerating windows, mapping virtual desktops, dumping the control tree, filling a field, then reading it back with OCR

Driven entirely by pctr itself - list windows, map virtual desktops, dump a control tree, set a field, read it back with OCR, screenshot it, and YOLO-World detect. Recorded with OBS, which pctr also piloted.

Install

pip install pctr             # core (UIA + OCR)
pip install "pctr[vision]"   # + ultralytics, for `pctr look`
pip install "pctr[mcp]"      # + MCP SDK, for the MCP server
pip install "pctr[all]"      # everything

Windows only.

MCP server

pctr ships a Model Context Protocol server so MCP clients (Claude Desktop, Cursor, opencode, ...) can drive the Windows desktop directly:

pip install "pctr[mcp]"

Add it to your client config (stdio):

{ "mcpServers": { "pctr": { "command": "pctr-mcp" } } }

(or "command": "python", "args": ["-m", "pctr.mcp_server"])

Tools exposed: pctr_windows, pctr_tree, pctr_find, pctr_click, pctr_set, pctr_type, pctr_keys, pctr_hotkey, pctr_focus, pctr_wait, pctr_shot, pctr_ocr, pctr_ocrfind, pctr_ocrclick, pctr_look, pctr_desktop.

Or run/manage it from the CLI:

pctr mcp status                                          # SDK + server state
pctr mcp start --transport streamable-http --port 8765   # background HTTP server
pctr mcp restart | pctr mcp stop
pctr mcp help

stdio runs in the foreground (what a client spawns); sse / streamable-http run in the background, reachable at http://127.0.0.1:8765/mcp (or …/sse).

Commands

Command What it does
pctr windows [--filter RE] [--process PID] List top-level windows (pid=… | title).
pctr tree --title RE [--depth N] [--limit N] Dump the UIA control tree of a window.
pctr find --title RE [--name RE] [--limit N] [--nth N] List matching elements.
pctr click --title RE --name RE [--method auto|invoke|mouse] [--dbl] Click an element.
pctr set --title RE --name RE --text S Set a field via the UIA ValuePattern (exact, instant).
pctr type [--title RE --name RE] --text S [--delay 0.03] [--chunk 1] Send keystrokes (see notes).
pctr keys --keys "{ENTER}" Send a global key combo (pywinauto syntax).
pctr hotkey --keys ctrl+s Send a modifier combo (prefer this over keys "^s").
pctr focus --title RE Bring a window to the foreground.
pctr wait --title RE --name RE [--timeout S] Wait until an element exists.
pctr shot [--title RE] --out PATH Screenshot the screen or a window.
pctr size Print primary screen size as WxH.
pctr desktop <action> Virtual desktops: list / windows / where / on-current / next / prev / new / close / move-window.
pctr move --x N --y N / down / up / hold --ms N Raw mouse control (--direct for games).
pctr drag --start x,y --end x,y [--duration S] Drag between two points.
pctr keydown / keyup --key a / keyhold --key w --ms 1500 Hold keyboard keys (--direct for games).
pctr ocr [--title RE] [--lang TAG] OCR the screen/window; list words with boxes.
pctr ocrfind --text RE [--lang TAG] OCR then list matches with click centers (single words).
pctr ocrclick --text RE [--nth N] [--lang TAG] OCR then click a word.
pctr look --for "a dog" [--title RE] [--conf X] YOLO-World detect objects by text prompt.
pctr lookclick --for "a dog" [--nth N] Detect then click the top match.
pctr mcp <start|stop|restart|status|help> Manage the MCP server (stdio or background http/sse).
pctr skill [--install] / pctr setup Print/install the agent skill + an AGENTS.md section.

Global flags: --json (machine-readable output) and --file FILE (run a batch of commands from a file).

Common filters: --title (regex), --name (regex), --control-type (Button, Edit, Pane, MenuItem, …), --auto-id, --nth, --process.

click, set, wait accept any selector - --name is not required. tree/find require a window selector (--title or --process).

The loop

pctr tree  --title "Notepad" --limit 60      # see what's clickable
pctr click --title "Notepad" --name "^File$"
pctr set   --title "Notepad" --name "Text Editor" --text "hello"

JSON output

Add --json (global, or per-command) for machine-readable output from windows, tree, find, ocr, ocrfind, look, and desktop:

pctr windows --json
# [{"hwnd":1234,"pid":5678,"title":"Untitled - Notepad"}, ...]

pctr desktop list --json
# [{"index":0,"guid":"ae37…","current":true,"windows":11}, ...]

pctr look --for "a car" --json
# [{"label":"a car","conf":0.86,"x":512,"y":300,"box":[400,220,620,380]}, ...]

Progress and warnings go to stderr, so stdout stays valid JSON.

Batch files

pctr --file script.txt          # one command per line; # comments and blanks skipped
pctr --json --file script.txt   # --json applies to every line

Stops on the first failing line and reports its line number.

Virtual desktops

pctr desktop list                       # desktops (#index, guid, [current], window count)
pctr desktop windows --desktop 1        # windows on desktop #1
pctr desktop where --title "App"        # which desktop a window is on
pctr desktop on-current --title "App"   # True / False
pctr desktop next | prev | new | close  # switch (moves the active desktop)
pctr desktop move-window --title RE --to N
  • Switching uses the standard Win+Ctrl hotkeys and moves the active desktop (you included). Add --direct if a game has focus.
  • Cross-desktop control: UIA actions (click --method invoke, set) reach windows on another desktop without switching (accessibility layer, not screen input). Raw mouse/keys only affect the active desktop.
  • move-window is blocked on Windows 11 (third-party MoveWindowToDesktop returns Access denied); it works on Windows 10.

Exit codes

  • 0 success, 1 no match / window not found, 2 usage/validation error.
  • Errors print one error: … line - no tracebacks.

Notes

  • Prefer set (ValuePattern) over type for text fields - it can't drop or reorder characters. type's element path uses pywinauto type_keys, which interprets { } + ^ % ~ ( ) as key syntax, so it is not literal.
  • Global type / keys go to the OS-focused window - pctr focus first.
  • Prefer pctr hotkey --keys ctrl+s over keys "^s"; the ^ modifier is fragile through shells.
  • ocrfind/ocrclick match one word at a time (Windows OCR tokenizes words).
  • look reads its model from --model or the PCTR_YOLO_MODEL env var; progress bars go to stderr so stdout stays parseable.
  • Qt apps expose a rich tree including embedded webviews. Electron apps expose only the window frame (use focus + global keys, or drive them over CDP).
  • Games ignore synthetic input - pass --direct to mouse/key commands and focus the game first.

License

MIT

Metadata

Release files for pctr 0.3.5

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pctr 0.3.5
File Size Uploaded
pctr-0.3.5.tar.gz 28.6 kB Details

Built distribution (wheel)

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

Total release size: 56.7 kB

Release files / pctr-0.3.5.tar.gz

Download URL pctr-0.3.5.tar.gz
Size 28.6 kB
Tags Source
SHA-256 checksum
How to use checksums
7a6adec5846c49e0f7ab137151dcd650faee7986fd1ff40e5eb2af6f122238e6
BLAKE2b-256 checksum
How to use checksums
baa0b9843efc276ecea1a09fbbff102270aa08579ccc35dd8ef4dd721b7666ff
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.11

Release files / pctr-0.3.5-py3-none-any.whl

Download URL pctr-0.3.5-py3-none-any.whl
Size 28.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a000554c9f8483cdf959e64d02b31d0df484e914ea3b55d95689fe5a1c4ad350
BLAKE2b-256 checksum
How to use checksums
efba563f98453e9ef56894fa20349a4b1c12d43284ea3f3c0f987dbc47cf4a07
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.11

Release history Release notifications | RSS feed

0.5.0

2 release files

0.4.0

2 release files

This release

0.3.5 This release

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

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