3.6 KiB
Veskslop Phase 0 spikes
Timeboxed proof-of-concept scripts, not production code. Project direction lives in ../AGENTS.md.
Setup
pnpm install
Current query policy
- Every command sent to the client is spaced by a random 500–2800 ms and serialized through one
queue (
src/pacing.ts). - Identical concurrent reads are coalesced (
dedupe), and state reads are cache-only. DEBUG=1logs every command and its delay.
Spikes
0. QR login / token acquisition — src/qr-login.ts
pnpm poc:qr
TOKEN_FILE=/path/to/token DEBUG=1 pnpm poc:qr
Connects to wss://remote-auth-gateway.discord.gg/?v=2, renders the approval QR directly in the
terminal, waits for a phone scan, exchanges the login ticket and writes the token to
poc/.token (mode 600, gitignored; override with TOKEN_FILE). No existing token required.
If Discord responds with an hCaptcha challenge, the script prints the challenge and prompts for a
HCAPTCHA_KEY (or takes it from the environment).
1. Vesktop control bridge — src/control-bridge.ts
The MCP daemon. Exposes Streamable HTTP and forwards tool calls over the JSON-lines protocol on
Vesktop's control socket (default $XDG_RUNTIME_DIR/vesktop.sock, override with VESKSLOP_SOCKET).
pnpm control:bridge # http://127.0.0.1:8788/mcp
VESKSLOP_SOCKET=... MCP_PORT=... pnpm control:bridge
Tools: get_state (cache-only), send_message, read_messages (coalesced), send_dm.
Vesktop side lives in this repo:
src/main/ipcSocket.ts— parses JSON lines{ id, command, data }and forwards them throughsendRendererCommand.src/renderer/ipcCommands.ts— handlers that use official client interactions (sendMessage,openPrivateChannel, guild/channel/message stores).
Protocol commands: ping, state:get, message:send, message:read, dm:send.
2. Mock Vesktop — src/mock-vesktop.ts
VESKSLOP_SOCKET=/tmp/veskslop-mock.sock pnpm control:mock
Stands in for the real Vesktop process so the bridge can be developed without Electron/Xvfb.
3. Live DM test — src/test-dm.ts
TEST_DM_USER_ID=... pnpm poc:dm
Talks to a real running Vesktop's control socket and sends one paced DM. The only sanctioned live-send target is user zzib (provide their user ID).
Verified
- QR login works end-to-end; the token in
.tokencame from a phone scan. - MCP bridge path:
initialize,tools/list,get_state,send_message,read_messages,send_dmall round-trip correctly through the mock. - Pacing observed live: consecutive commands reached the mock 592 ms, 1862 ms and 1439 ms apart — inside the 500–2800 ms window.
Deferred (not testable in this container)
- Real renderer handlers against a live Discord session (needs Electron + display).
- Headless display strategy (Xvfb/offscreen) and client lightening.
- Token injection into the official client.
- Voice join/leave and audio/video pipelines (need a voice channel; ffmpeg/PipeWire absent).
- Remote client auth over LAN/Tailscale and the web debug UI.
Findings
- Official
discord.jsis bot-only (/gateway/bot→ 401 with a user token), anddiscord.js-selfbot-v13is archived — do not build on either. The core is the real Vesktop client, puppeted through its own interactions. - MCP SDK
1.30.0stateless Streamable HTTP works as used here. - Vesktop's existing
sendRendererCommand/onIpcCommandbus is enough to puppet interactions; the socket only needed a JSON-lines framing and a command map. - pnpm 11: this folder is its own workspace root; build approvals live in
pnpm-workspace.yaml(allowBuilds).