-
Notifications
You must be signed in to change notification settings - Fork 1
Watcher Engine Architecture
VAC34 edited this page Jul 30, 2026
·
1 revision
Prompt drainage + target automation subsystem. Queues prompts, monitors target app state (Electron/web/any Win32 window), auto-sends when target idle.
+------------------------------------------------------------------+
| Watcher Engine (engine.py) |
| +------------------+ +------------------+ +--------------+ |
| | State Machine | -> | Probes & Hooks | ->| SendIntent | |
| | DISARMED→ARMED→ | | (Win32 + CDP) | | Generator | |
| | WATCHING→SENDING | +------------------+ +--------------+ |
| +------------------+ |
+------------------------------------------------------------------+
v
+------------------------------------------------------------------+
| Queue (queue.py) | Sender (sender.py) |
| - Per-target queue_key | - CDP Runtime.evaluate |
| - FIFO item backlog | - Win32 key injection |
| - Pinned queue_key on arm | - Read-back verify |
+------------------------------------------------------------------+
[DISARMED] ← (error/panic/max_sends)
|
| arm(target, queue_key)
v
[ARMED] —→ (agent seen busy) —→ [WATCHING]
^ |
| (send completed) | (agent idle + settle_ms)
+———————— <— [SENDING] ————————+
- DISARMED — inactive, no probes polling, no items processing
- ARMED — bound to target window + queue_key. Waiting for target activity.
- WATCHING — target observed busy (LLM generating). Waiting for idle + settle.
- SENDING — SendIntent dispatched. Waiting for injection confirmation.
Why CDP: Electron apps (VS Code, Claude Desktop, ChatGPT, Obsidian) don't process Win32 messages. Chromium's IPC ignores PostMessageW — characters drop silently.
-
discover()— queryhttp://127.0.0.1:<port>/json/listfor page targets - WebSocket JSON-RPC connection per page
-
Runtime.evaluate+Input.dispatchKeyEventfor text injection - Read-back verify — insert text, read field value via DOM query, only Submit on match
- Non-blocking timeouts (3s default)
For non-Electron target apps.
-
GetForegroundWindow()+ title regex match → target detection - Caret + focus monitoring → injection only when input field active
-
combine()— aggregate multi-probe states into single bool (is_target_active, is_target_busy, is_blocked)
-
id— UUID -
text— prompt text -
skill— wrapper skill name -
line— source line number (for live-text tracking)
-
item_id,text,queue_key,skill— encapsulated for sender
- Pending — in backlog
- In-Flight — SendIntent dispatched to sender
- Sent — confirmed by sender, removed from queue
- Failed — increments consecutive_failures, retry up to max_failures (3)
On arm(target, queue_key), key is pinned. Switches project/silo mid-session → watcher still drains correct queue.
| Parameter | Default | Purpose |
|---|---|---|
settle_ms |
2500 | Quiet time after target idle before sending |
min_gap_ms |
4000 | Min delay between consecutive sends |
max_sends |
25 | Max prompts per armed session (auto-disarm) |
max_failures |
3 | Consecutive failures → disarm with error |
panic() |
— | Emergency stop: disarm + cancel all in-flight |
Prompt wrappers applied before dispatch.
{
"name": "Code Review",
"prefix": "/review",
"template": "Review:\n\n{text}",
}Variables: {text}, {timestamp}, {project}.
-
Alt+C— queue current editor line (block-anchored) -
Alt+Shift+C— Queue Master (all silos overview) - Set default skill in Settings
- Watcher dialog: arm/disarm, pick target, configure probes
FastPrompter Wiki — Built with SAIPEN Protocol | GitHub Repo