Files
Veskslop/AGENTS.md
T

137 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AGENTS.md — Veskslop
## What this is
Veskslop is a **headless Discord client daemon** built on the Vesktop codebase. It runs the **real
Discord web client** (Vencord-patched Vesktop) without a visible window and puppets the client's own
interactions, so traffic and behavior stay as close to the official client as possible.
- an **MCP server** (Streamable HTTP) lets AI agents drive the account;
- multiple user identities are planned (one read-only collector, one full puppet);
- **audio in/out** and **video streaming** come later, using the client's native voice stack
plus PipeWire virtual devices on Linux;
- everything is **local-first**: clients reach it over LAN/Tailscale only.
**Vesktop is a separate project with separate goals.** This repo shares history with it but not
direction.
## Decisions (locked unless the user changes them)
- **Core:** run the actual Vesktop/Discord client (Electron) headless. Do **not** build on
third-party selfbot protocol libraries — the popular ones are archived/deprecated and stale
protocol emulation is a ban risk.
- **Control:** puppet Vesktop's own interactions through its IPC command bus:
`vesktop.sock` (external) → `sendRendererCommand` (main) → renderer handlers that call
Vencord/Discord internals (`sendMessage`, stores, voice actions).
- **MCP:** an external local daemon speaks a JSON-lines protocol over `vesktop.sock` and exposes
Streamable HTTP MCP. It must run without Electron so it is testable standalone.
- **QR login:** our own terminal remote-auth tool (`poc/qr-login.ts`) acquires a user token.
Feeding that token into the headless client is deferred until it can be tested.
- **Accounts:** multiple user tokens. Expected setup is one read-only collector account plus one
full-control puppet account; design for N identities behind one control surface.
- **Network:** bind localhost by default. Remote access is always over LAN/Tailscale — never expose
to the public internet. A client will later authenticate to the proxy for remote control.
- **Audio/video:** use the client's native stack first; PipeWire virtual devices for system audio
piping. ffmpeg is required for non-Opus media and video encoding.
- **GUI:** optional minimal **web debug UI** later. The daemon must never require a visible window;
on servers without a display, a virtual display (Xvfb) will be needed for Electron.
- **Pacing/safety:** all outbound actions are queued and paced.
- **Current policy:** every command sent to the client is spaced by a random **500–2800 ms**,
serialized, with identical in-flight queries coalesced; prefer cached state over queries.
- **Later policy:** human emulation — snappy first action (~30–80 ms), bulk actions randomized,
opt-in risky fast mode, free-account limits by default, ability toggles.
## Auth persistence
- Durable credential: the token file, `VESKSLOP_TOKEN_FILE` (default `<DATA_DIR>/token`, mode 600,
gitignored). It is the **puppet account's** token; zzib is only the DM test target.
- `DATA_DIR` is pinned: `$VENCORD_USER_DATA_DIR`, else `$VESKSLOP_DATA_DIR`, else
`<appData>/veskslop` (`src/main/constants.ts`). It does not depend on the app/product name, so
renames and version bumps do not move the Electron profile where Discord stores the session.
- On startup the preload asks main for the token (sync IPC) and seeds `localStorage.token` before
the client boots, but only when no session exists. `VESKSLOP_FORCE_TOKEN=1` overrides.
- Recovery: if Discord invalidates the session, run `pnpm poc:qr` for a fresh token and update the
token file.
- Discord deletes the stored token when it thinks devtools opened; keep Vesktop's devtools detector
patch (`src/renderer/patches/devtoolsFixes.ts`) so this cannot cause random logouts.
## Headless run (verified 2026-09-11)
The real client has been run with no visible window and successfully driven end-to-end:
```sh
Xvfb :99 -screen 0 1280x720x24 &
DISPLAY=:99 VESKSLOP_HEADLESS=1 \
VESKSLOP_TOKEN_FILE=~/.config/veskslop/token \
electron . --no-sandbox --disable-gpu --disable-dev-shm-usage
```
- A display server is still required; Xvfb works.
- `VESKSLOP_HEADLESS=1` skips the first-launch tour so the main window is created directly.
- The token file is seeded before the client boots (verified: logged in with the puppet account).
- Outbound sends must pass `waitForChannelReady = false` (`sendMessage(channelId, data, false)` in
`src/renderer/ipcCommands.ts`). Otherwise the client's MessageQueue waits forever for channels
that are never opened in a headless session.
- `message:read` is cache-only; channels the client never opened return zero messages. A
fetch-based read (through the client) is still to be added.
## How to proceed
**Current milestone — puppeting bridge (testable without Electron).**
1. Extend Vesktop's `vesktop.sock` server with a JSON-lines request/response protocol (keep the
legacy `run-shortcut` line working).
2. Add renderer handlers for `state:get`, `message:send`, `message:read` via Vencord internals.
3. Build the external MCP daemon (`poc/src/control-bridge.ts`) with a mock Vesktop socket
(`poc/src/mock-vesktop.ts`) so the whole path is testable in this container.
4. Then: voice join/leave handlers, audio pipes, video streaming, token injection, client
lightening, remote client auth.
Anything that needs a display, audio device, or a real client instance is **deferred** until it can
be tested; note it instead of guessing.
## Architecture sketch
```
MCP clients (agents) ──Streamable HTTP──▶ veskSlop control daemon
│ JSON lines over vesktop.sock
▼
Vesktop main process
│ sendRendererCommand()
▼
Discord renderer (Vencord patched)
│ official client actions
▼
Discord
```
## Guardrails for agents working here
- **Never commit tokens, credentials, or `.env` files.** Use environment variables / a local secret store.
- Do not adopt archived/deprecated selfbot libraries. If a library is needed, verify it was pushed
recently before proposing it.
- Do not hardcode Discord limits from memory — verify current free-tier numbers (upload size, stream
resolution, rate limits) at implementation time, and keep them configurable.
- All outbound actions go through the pacing queue; no direct sends.
- Default to conservative limits and opt-in risky features.
- Test against throwaway accounts and private test guilds only.
- **Live send tests:** DMs to user **zzib** (`177117296140091393`) are the only sanctioned real-send
test target.
- Run `pnpm testTypes` and `pnpm lint` before calling work done; `pnpm build` to compile.
## Open questions
- What to strip to lighten the client once the daemon path is stable.
- Voice/video: what the client's native stack can be driven to do without UI interaction.
- Scope and auth model of the future remote proxy client and web debug UI.
- How much of the Vesktop Electron tree gets deleted once the daemon is self-sufficient.
## Dev commands
```sh
pnpm install
pnpm build # esbuild bundle into dist/
pnpm testTypes # tsc --noEmit
pnpm lint
```