# Architecture ## Purpose Veskslop controls one or more Discord user accounts without a visible client window. It uses the real Vesktop client, so the traffic comes from the official client. ## Parts The system has six parts: 1. **Vesktop core** — the real Vesktop client. It runs headless. It exposes a small capability layer. 2. **Core bridge** — the capability layer. It accepts validated actions and pushes events. 3. **Veskslop daemon** — the external process. It holds all logic. It exposes MCP. 4. **Web UI** — a small browser control surface served by the daemon. See [webui.md](webui.md). 5. **Veskslop agent** — the optional local Go harness. It runs an LLM tool loop against a remote `llama.cpp` and the daemon's MCP tools. See [agent.md](agent.md). 6. **MCP clients** — remote agents and tools. They call the daemon. ``` MCP clients (agents) Web browser (owner) │ Streamable HTTP (MCP) │ HTTP + SSE ▼ ▼ Veskslop daemon ◀───────────────────── web UI listener │ ──── JSON lines over a Unix socket ────▶ Vesktop core │ │ │ QR login, pacing, trigger log, │ validated actions + events │ trust list, MCP tools ▼ │ Discord (official client traffic) ▼ Local state files (.token, .veskslop-state.json) ``` ## Boundary rules The boundary is narrow on purpose. - The core exposes a fixed action list. The list has no general "run this code" action. - The core validates every input. Bad input returns a structured error. The client does not crash. - The core rate limits all outbound actions. A bug in the daemon cannot cause a send flood. - The daemon holds the logic: triggers, trust list, command parsing, the trigger log, and pacing. - The daemon holds no Discord protocol code. These rules keep upstream rebases small. Logic changes do not touch the core. The core changes only when the action list changes. ## Components and status | Component | Location | Status | | --- | --- | --- | | Action protocol | `src/shared/puppetProtocol.ts` | Implemented | | Validated actions | `src/renderer/puppet/actions.ts` | Implemented | | Event push | `src/renderer/puppet/events.ts` | Implemented | | Main bridge | `src/main/puppetBridge.ts` | Implemented | | Core hooks | `src/main/main.ts`, `src/renderer/ipcCommands.ts`, `src/shared/IpcEvents.ts`, `src/preload/VesktopNative.ts` | Implemented | | Daemon (core-bridge transport) | `poc/src/core-client.ts` | Implemented and verified live | | Daemon (CDP transport) | `poc/src/cdp-client.ts` | Kept as a development fallback | | QR login | `poc/src/qr-login.ts` | Implemented and verified live | | Pacing | `poc/src/pacing.ts` | Implemented | | Trigger log and trust list | `poc/src/communication.ts`, `poc/src/puppet.ts` | Implemented and verified live | | Context cache and response policy | `poc/src/message-cache.ts`, `poc/src/puppet.ts` | Implemented and verified with the mock | | Chat commands and polls | `poc/src/puppet.ts`, `poc/src/communication.ts` | Implemented. Poll is paused (`POLL_ENABLED = false`). | | Persistent action log | `poc/src/action-log.ts` | Implemented | | Web UI and JSON API | `poc/src/webui.ts`, `poc/public/` | Nocturne 7a debug shell + roadmap placeholders | | User search | `src/renderer/puppet/actions.ts` (`user.search`) | Implemented | | Voice state reads | `src/renderer/puppet/actions.ts`, `src/renderer/puppet/events.ts` | Implemented | | Voice actions | `src/renderer/puppet/actions.ts`, `poc/src/puppet.ts` | Implemented, mock-verified | | Voice audio (TTS, capture, STT) | `poc/src/audio*.ts`, `poc/src/tts.ts`, `poc/src/capture.ts`, `poc/src/stt.ts` | Implemented, verified live | | Voice video | — | Not started | | Local agent harness | `agent/` | Scaffold implemented and smoke-tested. Daemon push pending. | | Mobile web UI | `poc/public/` | First draft at 390px with four tabs | ## Data flow 1. An agent calls an MCP tool on the daemon. 2. The daemon applies pacing and policy. 3. The daemon sends one JSON-line action to the core bridge. 4. The bridge forwards the action to the renderer. 5. The renderer validates the action and calls the official client. 6. The renderer returns a result or a structured error. 7. The bridge returns the response to the daemon. For inbound messages, the flow goes the other way: 1. The client receives a gateway event. 2. The renderer normalizes the event. 3. The bridge pushes the event to subscribed daemon connections. 4. The daemon applies the trigger rules and updates the log.