Files
Veskslop-t/poc

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=1 logs 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). This is the puppet account's token. 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).

The headless client consumes this file on startup via VESKSLOP_TOKEN_FILE (default <DATA_DIR>/token, see ../AGENTS.md → Auth persistence).

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 through sendRendererCommand.
  • 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

pnpm poc:dm
TEST_DM_CONTENT="hello" pnpm poc:dm

Talks to a real running Vesktop's control socket and sends one paced DM. Defaults to the only sanctioned live-send target, user zzib (TEST_DM_USER_ID overrides).

Verified

  • QR login works end-to-end; the token in .token came from a phone scan.
  • MCP bridge path: initialize, tools/list, get_state, send_message, read_messages, send_dm all 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.js is bot-only (/gateway/bot → 401 with a user token), and discord.js-selfbot-v13 is archived — do not build on either. The core is the real Vesktop client, puppeted through its own interactions.
  • MCP SDK 1.30.0 stateless Streamable HTTP works as used here.
  • Vesktop's existing sendRendererCommand/onIpcCommand bus 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).