This document is a navigation aid for autonomous agents working on the WineBot codebase.
WineBot is a containerized Windows application runtime (Wine 10.0) with an X11 display stack, controlled via a Python FastAPI.
| Layer | Components | Description |
|---|---|---|
| Control | api/ |
FastAPI server, Input Broker, Policy enforcement. |
| Orchestration | docker/entrypoint.sh |
Startup sequence, Xvfb/Openbox launch, Supervisor loop. |
| Automation | automation/ |
Python/AHK scripts for recording, tracing, and interacting with Wine. |
| Tools | scripts/ |
Shell helpers for local management (winebotctl) and diagnostics. |
| Policies | policy/ |
Formal mandates for development, security, and visual style. |
| Path | Purpose | Key Symbols |
|---|---|---|
api/server.py |
Main API entrypoint. Mounts routers. | app, lifespan |
api/core/broker.py |
Input Control Policy state machine. | InputBroker, ControlMode |
policy/visual-style-and-ux-policy.md |
Mandates "Cyber-Industrial Dark" UI and A11y. | |
api/routers/*.py |
API endpoints by category. | /health, /input, /recording |
docker/entrypoint.sh |
Container boot logic. Handles Xvfb, Openbox, Wine init. | Xvfb, wineserver, tint2 |
docker/openbox/rc.xml |
Window Manager config. Controls input focus/decorations. | <applications>, <mouse> |
scripts/bin/ |
Primary user-facing tools (winebotctl, run-app.sh). |
|
scripts/diagnostics/ |
System validation suite (diagnose-master.sh, health-check.sh). |
diagnose-master.sh |
scripts/setup/ |
Installation and fix logic (install-theme.sh, fix-wine-input.sh). |
|
automation/bin/ |
Standalone automation tools (x11.sh, screenshot.sh). |
|
automation/examples/ |
Demo and verification scripts (notepad_create_and_verify.py). |
|
tests/ |
Pytest suite. | test_policy.py, test_api.py |
archive/status/ |
Archived project status reports. |
| Variable | Default | Purpose |
|---|---|---|
WINEBOT_RECORD |
profile-dependent (0 headless, 1 interactive) |
Enable session recording (ffmpeg). |
WINEBOT_INPUT_TRACE |
profile-dependent (1 in compose defaults) |
Enable X11 input event logging. |
WINEBOT_INPUT_TRACE_WINDOWS |
profile-dependent (1 in compose defaults) |
Enable Windows-side (AHK) input logging. |
WINEBOT_INPUT_TRACE_NETWORK |
0 |
Enable VNC proxy logging. |
API_TOKEN |
(None) | Secure API access key. |
VNC_PASSWORD |
(None) | Password for x11vnc. |
SCREEN |
1280x720x24 |
Xvfb display resolution. |
WINEBOT_SHUTDOWN_GUARD_TTL_SECONDS |
120 |
Duplicate shutdown guard window. |
WINEBOT_LOG_FOLLOW_ACQUIRE_TIMEOUT_SECONDS |
0.05 |
Timeout acquiring log-follow stream slot. |
Docker Desktop has been removed. Docker Engine v29.6.1 runs inside WSL2
Ubuntu; use explicit WSL commands from Windows:
wsl -d Ubuntu docker <args>
wsl -d Ubuntu docker compose <args>Do not run bare docker from Windows PowerShell unless you know the user's
PowerShell profile loaded the local proxy functions. Use docker compose, not
docker-compose. See docs/DOCKER_ENGINE_ON_WSL2.md.
# Rapid local feedback (Watch mode)
./scripts/bin/dev-watch.sh
# UI/UX Policy Compliance
wsl -d Ubuntu docker compose -f compose/docker-compose.yml --profile interactive --profile test run --rm test-runner pytest tests/e2e/test_ux_quality.py
# Unit tests
wsl -d Ubuntu docker compose -f compose/docker-compose.yml --profile interactive --profile test run --rm test-runner scripts/ci/test.sh# 1. Edit config
scripts/winebotctl config set KEY VALUE
# 2. Apply (Restarts container)
scripts/winebotctl config applyscripts/winebotctl input trace start --layer windows
scripts/winebotctl input trace events --source client --limit 50- Enable traces:
WINEBOT_INPUT_TRACE=1etc. - Check
logs/input_events_*.jsonlin session dir. - Run
scripts/diagnose-input-suite.shinside container.
Agents should use the following API patterns for reliable control.
Performs a mouse click at specific coordinates.
Payload:
{
"x": 100,
"y": 100,
"button": 1,
"window_title": "Notepad",
"relative": true
}Features:
- Validation: Clicks are validated against the current
SCREENresolution to prevent out-of-bounds errors. - Window Targeting: Providing
window_titleorwindow_idlogs the target for better traceability. - Relative Clicking: If
relative: true, coordinates are calculated relative to the specified window's top-left corner. - Non-blocking: The call is asynchronous and will not stall the system during execution.
GET /health: Use this to verify system readiness. Checksecurity_warningfor potential exposure.GET /health/invariants: Use this to verify runtime lifecycle/control/config invariants.- mDNS Discovery: WineBot broadcasts
_winebot-session._tcp.local.. Agents on the same network can discover instances automatically.
To ensure system stability and reliability, agents must adhere to the following constraints:
- Avoid UI Feedback Loops: Do not programmatically click on transient UI elements like Toast notifications or status badges. This can lead to non-deterministic state transitions.
- Action Throttling: Enforce a minimum "Politeness" delay of at least 100ms between discrete API actions (e.g., clicks or keypresses) to allow the Wine/X11 stack to settle.
- Graceful Termination: Always attempt to call
POST /lifecycle/shutdownbefore exiting to ensure video artifacts are finalized and resources are reaped. - Least Privilege: Do not attempt to modify files outside of
/wineprefixor/artifacts. Theappsandautomationdirectories are mounted as Read-Only for safety.
# Check keyboard injection works
scripts/winebotctl input key "test" --window-title "Notepad"
# Check trace layers
scripts/winebotctl input trace status --layer x11
scripts/winebotctl input trace status --layer windows
# Run full diagnostic suite (requires interactive mode)
scripts/diagnostics/diagnose-input-suite.sh
# Run 5-layer trace bisect
scripts/diagnostics/diagnose-input-trace.sh --layers x11,windows
# Analyze keyboard latency
python3 scripts/diagnostics/analyze-trace-latency.py --mode keyboardThe Wine desktop shell (explorer.exe /desktop) intercepts X11 keyboard events.
The /input/key endpoint uses AHK Send by default, bypassing this barrier.
Verify the backend in the response: {"backend": "ahk", "status": "sent"}.
If key events arrive at X11 but not Windows:
# Enable Windows trace
POST /input/trace/windows/start
# Send a test key
POST /input/key {"keys": "Test", "window_title": "Notepad"}
# Query Windows trace for the key
GET /input/events?source=windows&origin=agent&limit=50
# Look for key_down/key_up events with matching trace_id# Start all trace layers
scripts/diagnostics/diagnose-input-trace.sh --layers x11,windows
# Send several keystrokes
scripts/winebotctl input key "test1"
scripts/winebotctl input key "test2"
# Analyze latency
python3 scripts/diagnostics/analyze-trace-latency.py --mode keyboardSee docs/tracing.md for the full trace event schema and cross-layer correlation guide.
WineBot has two distinct window ID systems that do not map to each other:
| System | Source | Example | Used By |
|---|---|---|---|
| X11 Window IDs | xdotool search --name "Title" |
23068673 (decimal) |
/input/mouse/click, xdotool key, GET /health/windows |
| Wine HWNDs | AHK WinExist("Title") |
0x160034 (hex) |
/input/key (AHK backend) via native title matching |
Rule: When calling /input/key with a window_title, the AHK backend uses
AHK's native WinActivate/WinWaitActive with the title string — NOT the X11 ID.
This is correct because X11 window IDs are not AHK HWNDs and cannot be used
with ahk_id.
When calling /input/mouse/click, the xdotool backend uses X11 window IDs,
which ARE correct for X11-level operations.
To discover window titles:
GET /health/windows # Returns X11 IDs and titles for all windowsTo target a specific window in a script, use its title (visible in the window list), not its numeric ID. The API resolves the title to the correct system internally.
In scripts and agents that use both mouse and keyboard:
- Get window list via
GET /health/windows— titles are the source of truth - Mouse clicks: Use
window_titlefrom the window list (xdotool resolves to X11 ID) - Keyboard input: Use the same
window_title(AHK resolves by Wine title matching) - Dialogs: After launching a dialog (Save As, Open), switch window_title to the
dialog's title. Example:
"Save As"not"Notepad"after Ctrl+S opens the save dialog.
See docs/known-limitations.md for the full catalog of platform constraints
including comdlg32 dialog keyboard limitations, AHK Send character escaping rules,
/run/python Linux vs Windows behavior, and tool selection guidance.