Parallel CUA
README.md
# Parallel CUA
**English** | [简体中文](README.zh-CN.md)
[](LICENSE)
[](https://www.python.org/)
[](https://www.microsoft.com/windows)
[](https://modelcontextprotocol.io)
[](https://github.com/Shinyeiceblue/parallel-cua-mcp)
## The computer is no longer a screenshot for the model — it’s a pair of hands
You already have models that can *see* a screen. What you usually don’t have is a model that can **use** a computer the way a person does: hold `W` and turn the camera at the same time, open a CAD menu it has never seen, find “保存” without a hard-coded pixel, and come back tomorrow already knowing the app.
**Parallel CUA** is a Windows [MCP](https://modelcontextprotocol.io) server built for that.
Most “computer use” stacks still look like this: screenshot → one click → screenshot → one keystroke. Fine for filling a form. Useless when the job is *moving*, *aiming*, and *firing* in the same second — or when the button you need only exists after you learn the software.
This project starts from a different question:
> If an agent is going to operate my PC, it should feel less like a remote control toy — and more like someone sitting at the desk.
### What that actually means here
- **Two hands, not one finger.** Keys stay *held* while the mouse keeps moving. Keyboard, aim, and clicks can run as parallel streams with real timing — not serialized RPC steps.
- **It can look things up.** Unfamiliar app? `research_app` → save a playbook → next time it already knows the shortcuts.
- **It already knows the workshop.** 47 engineering apps (AutoCAD, SOLIDWORKS, KiCad, MATLAB, Revit, CAXA, …) ship with shortcuts and intents like `draw_line` / `extrude` / `run`.
- **It aims like a person.** UIA element names first, OCR text anchors second, coordinates last — plus `human_*` motion with curves, jitter, and pauses.
- **It doesn’t care which agent you use.** MCP for Claude/Cursor/MiMo; OpenAI tools; Anthropic computer-use actions; plain HTTP.
> Games · CAD/EDA/CAE · desktop agents · serious RPA — anywhere “one action at a time” is not enough.
### Three minutes in someone’s day
**11:04 — FPS warm-up**
The agent holds forward, strafes, and keeps the crosshair tracking while clicking fire — three streams at once. Not “press W, wait for tool result, then move mouse.”
**14:20 — A CAD job nobody documented**
Foreground is AutoCAD. `observe_environment` attaches the knowledge base. The request is “draw a line.” It doesn’t guess ribbon pixels — it does `Esc` → `L` → `Enter` like a drafter who has done it a thousand times.
**16:50 — A weird in-house tool**
No UIA names, no memory of this app. The agent screenshots, OCRs the Chinese label `导出 PDF`, clicks the text, types a filename with human pauses, and saves a playbook so tomorrow is boring in the best way.
That’s the point: **not a demo of clicking — a layer that makes agents *operate*.**
---
## Table of contents
- [Why it feels different](#why-it-feels-different)
- [Feature comparison](#feature-comparison)
- [Architecture](#architecture)
- [Quick start](#quick-start)
- [Multi-harness](#multi-harness)
- [Core capabilities](#core-capabilities)
- [Engineering software knowledge base](#engineering-software-knowledge-base)
- [Examples](#examples)
- [Performance](#performance)
- [Tools](#tools)
- [Environment variables](#environment-variables)
- [Development](#development)
- [Security](#security)
- [Limitations](#limitations)
- [Roadmap](#roadmap)
- [License](#license)
---
## Why it feels different
| What usually hurts | What you get instead |
|---|---|
| CUA that does **one action**, then waits | Held-state keys/buttons + multi-stream `parallel` + timed `game_macro` |
| Tap-and-forget injection (pyautogui style) | Windows `SendInput` with an explicit “what is still held down” brain |
| Straight-line robot moves, metronome clicks | `human_*`: bezier paths, overshoot, random pauses, optional typos |
| Unknown software → blind clicking | Research, playbooks, and reuse next session |
| Engineering apps = memorized shortcuts | 47-app KB + `run_engineer_task(intent='draw_line')` |
| Locked to one client | One core: **MCP** + **OpenAI/Anthropic** + **HTTP** |
| Buttons without stable coordinates | **UIA names** → **OCR text** → coordinates |
### The one-liner we actually stand behind
> Not “a tool that can click the screen.”
> A **Windows operation layer** that runs **in parallel**, **learns software**, and **plugs into the agent you already use**.
---
## Feature comparison
| Capability | Typical CUA / Windows-MCP | Parallel CUA |
|---|---|---|
| Screenshot / click / type / scroll | ✅ | ✅ |
| Action model | One-by-one (serial) | **Held-state + parallel streams + timeline macros** |
| Hold W while moving mouse | ❌ | ✅ `hold_keys` + `move_rel` |
| Keyboard / aim / fire streams in parallel | ❌ | ✅ `parallel` |
| Timed concurrent game macros | ❌ | ✅ `game_macro` |
| Scancode injection (Raw Input games) | Rare | ✅ `set_keyboard_mode(vk\|scan\|both)` |
| Human-like input | Rare | ✅ `human_*` |
| Learn unknown software first | ❌ | ✅ `research_app` + playbooks |
| Engineering shortcuts / intents | ❌ | ✅ 47-app KB + `run_engineer_task` |
| UIA element targeting | Partial | ✅ `list_ui_elements` / `click_element` |
| OCR text anchors | ❌ | ✅ `find_text` / `click_text` |
| Multi-agent / multi-protocol | Usually MCP only | ✅ MCP + OpenAI + Anthropic + HTTP |
---
## Architecture
```text
┌─────────────────────────────────────────────────────────────┐
│ AI Harness / Agent │
│ MiMo · Claude · Cursor · OpenAI Agents · Anthropic · LC │
└───────────────┬─────────────────────────────┬───────────────┘
│ MCP (stdio / HTTP) │ HTTP JSON
▼ ▼
┌──────────────────────────┐ ┌──────────────────────────────┐
│ MCP Tool Surface │ │ HTTP Gateway │
│ (61 tools) │ │ /tools /computer /v1/... │
└────────────┬─────────────┘ └───────────────┬──────────────┘
│ Unified Executor │
└───────────────┬─────────────────┘
▼
┌────────────────────────────────────────────┐
│ ConcurrentInputController (SendInput) │
│ held-keys · parallel streams · scancode │
├────────────────────────────────────────────┤
│ HumanDriver │ UIA │ OCR │ Knowledge │
└────────────────────────────────────────────┘
│
▼
Windows Desktop
```
**Layers**
- **Input core** — injection + concurrency only
- **Dialects** — map OpenAI CUA / Anthropic actions to one executor
- **Knowledge** — process match → shortcuts/intents → executable plan
- **Human / UIA / OCR** — pacing, accessibility tree, text anchors
---
## Quick start
### Requirements
- Windows 10 / 11
- Python 3.10+
### Install
```powershell
cd parallel-cua-mcp
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -e .
```
### Run as MCP (stdio)
```powershell
.\.venv\Scripts\python.exe -m parallel_cua serve --transport stdio
```
### MiMo Desktop
Merge into `~/.config/mimocode/mimocode.jsonc` (adjust paths):
```json
{
"mcp": {
"parallel-cua": {
"type": "local",
"command": [
"C:\\path\\to\\parallel-cua-mcp\\.venv\\Scripts\\python.exe",
"-m",
"parallel_cua",
"serve",
"--transport",
"stdio"
],
"environment": {
"PYTHONPATH": "C:\\path\\to\\parallel-cua-mcp\\src"
},
"enabled": true
}
}
}
```
Restart the engine or open a new chat.
### Claude Desktop / Cursor
```json
{
"mcpServers": {
"parallel-cua": {
"command": "C:\\path\\to\\parallel-cua-mcp\\.venv\\Scripts\\python.exe",
"args": ["-m", "parallel_cua", "serve", "--transport", "stdio"],
"env": { "PYTHONPATH": "C:\\path\\to\\parallel-cua-mcp\\src" }
}
}
}
```
Generate configs:
```powershell
.\.venv\Scripts\python.exe -m parallel_cua harness --list
.\.venv\Scripts\python.exe -m parallel_cua harness --name claude_desktop
.\.venv\Scripts\python.exe -m parallel_cua harness --name openai_sdk
```
---
## Multi-harness
| Harness | Protocol | Command |
|---|---|---|
| MiMo / Claude / Cursor / Gemini / Codex | MCP stdio | `serve --transport stdio` |
| Any MCP HTTP client | Streamable HTTP / SSE | `serve --transport streamable-http --port 8000` |
| OpenAI Agents / custom tool loop | HTTP JSON | `serve --transport http --port 8765` |
| Anthropic SDK computer-use | HTTP `/computer` | same, `dialect=anthropic` |
| LangChain / LangGraph | HTTP generic | `POST /tools/call` |
### Schema export
```powershell
python -m parallel_cua tools --format openai
python -m parallel_cua tools --format anthropic
python -m parallel_cua tools --format generic
```
### HTTP endpoints
| Method | Path | Description |
|---|---|---|
| GET | `/health` | Health check |
| GET | `/tools?dialect=openai\|anthropic\|generic\|mcp` | Tool list |
| POST | `/tools/call` | `{"name":"human_click","arguments":{"x":10,"y":20}}` |
| POST | `/computer` | OpenAI / Anthropic action dialects |
| POST | `/v1/chat/completions` | Execute already-chosen `tool_calls` (model stays external) |
Optional auth: set `PARALLEL_CUA_HTTP_TOKEN` and send `Authorization: Bearer <token>`.
### Dialects
- **OpenAI CUA**: `click / type / key / scroll / drag / screenshot / hold_key / wait`
- **Anthropic computer-use**: `left_click / type / key / scroll / left_click_drag / screenshot …`
- **Generic / MCP**: full surface (`hold_keys`, `parallel`, `game_macro`, UIA, OCR, playbooks…)
---
## Core capabilities
### 1. True parallel (games / high-frequency ops)
- `hold_keys` / `hold_mouse` — keep down until `release_*` / `release_all`
- `move_mouse(dx, dy)` — relative aim while keys held
- `parallel(streams)` — thread-level concurrent action streams
- `game_macro(steps)` — timed holds + continuous look + clicks
- `set_keyboard_mode("scan"|"both")` — Raw Input-friendly games
### 2. Human-like input (desktop apps)
- `human_move_to` — bezier + jitter + overshoot
- `human_click` / `human_type` — random hold times, word pauses, optional typos
- `human_think` / `human_glance` — reading pauses and micro-moves
- `human_set_speed` — 0.5 careful → 1.5 hurried
- `run_script` — high-level action scripts
### 3. Learning loop (unknown software)
```text
observe_environment + screenshot
→ get_playbook
→ research_app(name, goal) # Bing first, fetch_page_text
→ save_playbook(steps, shortcuts)
→ human_* operate
→ screenshot verify; release_all if needed
```
Playbooks: `%USERPROFILE%\.parallel-cua\playbooks\`
### 4. UIA element targeting (0.7)
- `list_ui_elements` / `find_element` / `click_element`
- `set_edit_text` / `get_element_text` / `focus_element`
- Prefer Invoke/Toggle patterns, else center click
- Verified on Windows 11 Notepad (`DocumentControl`)
### 5. OCR text anchors (0.8)
- `ocr_region` / `find_text` / `click_text` / `ocr_with_screenshot`
- Windows OCR (`winsdk`), CJK space-insensitive matching
- Typical window-region OCR ~200–300ms
**Suggested order:** UIA → OCR → coordinate click.
### 6. Observation & windows
- `observe_environment` — foreground process/title/rect + engineering shortcuts when known
- `list_windows` / `focus_window` / `window_action` / `open_app`
- `screenshot` — `region` + `scale` (prefer `scale=0.5`)
---
## Engineering software knowledge base
**47 apps** (including Chinese CAD/BIM tools) with shortcuts, workflows, and notes:
| Category | Apps |
|---|---|
| CAD | AutoCAD, CAXA, ZWCAD, GstarCAD, TArch, Rhino |
| MCAD | SOLIDWORKS, Fusion, Inventor, SketchUp, ZW3D, Gstar 3D, FreeCAD, CATIA, NX, Creo, Solid Edge |
| BIM | Revit, Glodon |
| EDA | KiCad, Altium, EAGLE, Multisim, Proteus, LTspice |
| CAE | ANSYS, Abaqus, COMSOL |
| Analysis / 3D / CAM | MATLAB, Origin, LabVIEW, Blender, OpenSCAD, Mastercam |
| Dev / Office | VS Code, PyCharm, Eclipse, Keil, IAR, Jupyter, Excel, Word, PPT, Visio, Project, Acrobat |
Data: [`knowledge/engineering_apps.json`](knowledge/engineering_apps.json)
Fetcher: [`scripts/fetch_engineering_docs.py`](scripts/fetch_engineering_docs.py)
### Intent-level execution
```text
run_engineer_task(intent='save')
run_engineer_task(intent='draw_line', app_id='autocad')
run_engineer_task(intent='run', app_id='matlab')
run_engineer_task(intent='zoom_extents', dry_plan_only=True)
```
Intents: `save` · `undo` · `cancel` · `new` · `open` · `run` · `draw_line` · `extrude` · `zoom_extents` · `rebuild`
Also: `list_engineering_apps` · `match_engineering_app` · `suggest_shortcuts` · `apply_shortcut` · `seed_engineering_playbooks`
---
## Examples
### FPS: move forward while turning left
```text
hold_keys(["w", "shift"])
move_mouse(dx=-80, dy=0)
move_mouse(dx=-80, dy=0)
release_all()
```
### Move + shoot (parallel streams)
```text
parallel(streams=[
[{"type":"hold_keys","keys":["w"],"ms":1000}],
[{"type":"move_rel","dx":50,"dy":0},{"type":"wait","ms":150},
{"type":"move_rel","dx":50,"dy":0},{"type":"wait","ms":150},
{"type":"move_rel","dx":50,"dy":0}],
[{"type":"wait","ms":300},{"type":"click","button":"left"},
{"type":"wait","ms":200},{"type":"click","button":"left"}]
])
```
### game_macro: advance + turn + fire
```text
game_macro(steps=[
{
"duration_ms": 600,
"keys_down": ["w"],
"mouse_rel": {"dx": -200, "dy": 0, "steps": 24},
"clicks": [
{"at_ms": 80, "button": "left"},
{"at_ms": 280, "button": "left"}
]
},
{"duration_ms": 80, "keys_up": ["w"]}
], release_at_end=True)
```
### CAD line (knowledge intent)
```text
run_engineer_task(intent='draw_line', app_id='autocad')
# Esc → wait → l → enter (human pacing)
```
### HTTP (OpenAI-style)
```bash
curl -s http://127.0.0.1:8765/tools/call \
-H "Content-Type: application/json" \
-d '{"name":"screenshot","arguments":{"scale":0.4}}'
curl -s http://127.0.0.1:8765/computer \
-H "Content-Type: application/json" \
-d '{"dialect":"anthropic","action":{"action":"left_click","coordinate":[120,80]}}'
```
---
## Performance
1. **Lock never spans sleep / long I/O** — only held-set updates
Regression: stream A `press` 120ms while stream B finishes in ~11ms (serialized would be ~120ms)
2. **Batched SendInput** — chord downs/ups in one call; `release_all` once
3. **Scancode mode** — default `both` (VK + scancode)
4. **Short waits** — <15ms spin for tighter chords
5. **Counters** — `get_input_stats`
---
## Tools
Currently **61** MCP tools (HTTP generic catalog mirrors them).
<details>
<summary>Expand full list</summary>
**Observe / screenshot**
`screenshot` · `observe_environment` · `get_cursor_pos` · `get_screen_info` · `get_held_state` · `get_input_stats`
**UIA**
`list_ui_elements` · `find_element` · `click_element` · `set_edit_text` · `get_element_text` · `focus_element`
**OCR**
`ocr_region` · `find_text` · `click_text` · `ocr_with_screenshot`
**Basic input**
`click` · `double_click` · `move_mouse` · `drag` · `scroll` · `type_text` · `key` · `hotkey` · `wait` · `ui_shortcut`
**Concurrent / held**
`hold_keys` · `release_keys` · `hold_mouse` · `release_mouse` · `release_all` · `parallel` · `game_macro` · `set_keyboard_mode`
**Human-like**
`human_set_speed` · `human_move_to` · `human_click` · `human_type` · `human_hotkey` · `human_think` · `human_glance` · `human_scroll` · `run_script`
**Windows / apps**
`list_windows` · `focus_window` · `window_action` · `open_app`
**Learning**
`search_web` · `fetch_page_text` · `research_app` · `save_playbook` · `get_playbook` · `list_playbooks` · `find_playbook_for_window`
**Engineering KB**
`list_engineering_apps` · `match_engineering_app` · `suggest_shortcuts` · `seed_engineering_playbooks` · `apply_shortcut` · `list_engineering_intents` · `run_engineer_task`
</details>
---
## Environment variables
| Variable | Default | Description |
|---|---|---|
| `PARALLEL_CUA_DRY_RUN` | off | `1/true/yes/on` — no real input injection |
| `PARALLEL_CUA_KEYBOARD_MODE` | `both` | `vk` / `scan` / `both` |
| `PARALLEL_CUA_HTTP_TOKEN` | empty | HTTP gateway Bearer auth |
---
## Development
```powershell
$env:PARALLEL_CUA_DRY_RUN = "1"
$env:PYTHONPATH = ".\src"
.\.venv\Scripts\python.exe -m tests.test_basic
.\.venv\Scripts\python.exe -m tests.test_concurrency
.\.venv\Scripts\python.exe -m tests.test_agent_layer
.\.venv\Scripts\python.exe -m tests.test_harness
.\.venv\Scripts\python.exe -m tests.test_engineering_kb
.\.venv\Scripts\python.exe -m tests.test_engineer_tasks
.\.venv\Scripts\python.exe -m tests.test_uia
.\.venv\Scripts\python.exe tests\smoke_mcp_client.py
# Real E2E (opens Notepad, injects real input)
.\.venv\Scripts\python.exe tests\e2e_notepad.py
.\.venv\Scripts\python.exe tests\e2e_ocr_simple.py
```
### Layout
```text
parallel-cua-mcp/
├── knowledge/engineering_apps.json
├── scripts/fetch_engineering_docs.py
├── src/parallel_cua/
│ ├── server.py # MCP tools
│ ├── wininput.py # SendInput concurrent core
│ ├── human.py # human-like driver
│ ├── uia.py # UIA elements
│ ├── ocr.py # Windows OCR anchors
│ ├── knowledge.py # engineering KB + intents
│ ├── dialects.py # OpenAI / Anthropic
│ ├── http_api.py # HTTP gateway
│ └── harness.py # client config profiles
└── tests/
```
---
## Security
This service can inject arbitrary OS input:
- Do **not** bind `0.0.0.0` without auth; set `PARALLEL_CUA_HTTP_TOKEN` for remote HTTP
- Do not run unattended with unrestricted model access
- Call `release_all` after holds to avoid stuck keys
- Anti-cheat games may reject injection (expected)
---
## Limitations
- Some anti-cheat titles block injected input
- `type_text` is Unicode injection (chat/forms); use `key`/`hold_keys` for game skills
- Multi-monitor uses virtual-desktop coordinates; DPI follows the system coordinate space
- Engineering KB covers common versions; local menus may differ
- `research_app` needs network (Bing first); offline → local KB/playbooks
---
## Roadmap
- [ ] Vision-assisted control detection (OCR + optional detection → click)
- [ ] More Chinese/vertical engineering packs
- [ ] Record & replay (human ops → game_macro / run_script)
- [ ] Multi-monitor partition ops
- [ ] Optional UIA element selector (Playwright-like)
---
## License
This project is licensed under the [MIT License](LICENSE).
See also: [Changelog](CHANGELOG.md) · [Contributing](CONTRIBUTING.md) · [Security](SECURITY.md)
---
<p align="center">
<sub>For agents that need to actually sit at a Windows desk — two hands, not one click at a time.</sub>
</p>
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues