147 lines
6.3 KiB
Markdown
147 lines
6.3 KiB
Markdown
# Decisions
|
|
|
|
This document records the main design decisions and their reasons.
|
|
|
|
## ADR-1: Use the real client
|
|
|
|
**Decision.** Run the real Vesktop client. Do not use a third-party selfbot protocol library.
|
|
|
|
**Reason.** The popular selfbot libraries are archived or deprecated. Stale protocol emulation is a
|
|
ban risk. The real client sends official traffic.
|
|
|
|
## ADR-2: Validated capability layer
|
|
|
|
**Decision.** The core exposes a small, fixed action list. The core validates all input. The core
|
|
returns structured errors. All logic lives in the external daemon.
|
|
|
|
**Reason.** The split gives three properties:
|
|
|
|
- The daemon cannot run arbitrary code in the client.
|
|
- A daemon bug cannot crash the client or send malformed data to Discord.
|
|
- Core patches stay small, so an upstream rebase is easy.
|
|
|
|
**Consequence.** A new capability needs a small core change. The action list is the contract.
|
|
|
|
## ADR-3: CDP is a fallback, not the primary transport
|
|
|
|
**Decision.** The project validated control over Chrome DevTools Protocol. The primary transport is
|
|
the validated core bridge.
|
|
|
|
**Reason.** CDP needs no Vesktop patch. However, CDP evaluates raw code in the page. It bypasses the
|
|
core-side validation and rate limits. The project keeps the probe as a development tool.
|
|
|
|
**Status.** The primary transport is the validated core bridge. The CDP client and the probe stay in
|
|
`poc/` as development tools.
|
|
|
|
## ADR-4: No bespoke client
|
|
|
|
**Decision.** Do not write a new Electron shell for Discord.
|
|
|
|
**Reason.** Vesktop maintains the desktop integration for Vencord, for example settings, themes,
|
|
quick CSS, and the native plugin bridge. A bespoke shell must reimplement that surface. Vesktop
|
|
already does this work.
|
|
|
|
**Consequence.** Keep the patch small and isolated. This approach is cheaper than a new shell.
|
|
|
|
## ADR-5: Two pacing layers
|
|
|
|
**Decision.** The daemon paces all outbound sends with a human-emulation policy (ADR-12). The core
|
|
adds a hard limit of 500 ms between sends and 30 sends per minute.
|
|
|
|
**Reason.** The daemon policy looks human. The core limit is a safety net. A daemon bug cannot cause
|
|
a send flood.
|
|
|
|
## ADR-6: Pin the profile directory
|
|
|
|
**Decision.** `DATA_DIR` is `$VENCORD_USER_DATA_DIR`, else `$VESKSLOP_DATA_DIR`, else
|
|
`<appData>/veskslop`.
|
|
|
|
**Reason.** The Discord session lives in the Electron profile. An app rename or a version update
|
|
must not move the profile. A stable path keeps the login.
|
|
|
|
## ADR-7: Separate token file
|
|
|
|
**Decision.** The QR tool writes the account token to a file. The client seeds the token at startup
|
|
when no session exists.
|
|
|
|
**Reason.** The token file survives a profile reset. It also survives a change in the Discord
|
|
storage format. The recovery path is one QR scan.
|
|
|
|
## ADR-8: Trigger log limits
|
|
|
|
**Decision.** Keep the last 100 triggers from trusted users and the last 30 triggers from untrusted
|
|
users.
|
|
|
|
**Reason.** The limits keep memory small. The trusted limit is larger because those messages matter
|
|
more.
|
|
|
|
## ADR-9: One live test target
|
|
|
|
**Decision.** The only permitted live-send target is user zzib (`177117296140091393`).
|
|
|
|
**Reason.** Tests must not send messages to other users. DMs to zzib are safe and permitted.
|
|
|
|
## ADR-10: Poll command
|
|
|
|
**Decision.** The poll command accepts `|` or `//` as separators, an optional quoted question, and
|
|
many reactions per user. A bare command shows help.
|
|
|
|
**Reason.** The pipe is hard to type on some keyboards. `//` is safe in Discord markdown when it has
|
|
whitespace on both sides, so URLs stay in one piece. Many selections match how people use polls in
|
|
group chats. A bare command gives the user the syntax without a failed poll.
|
|
|
|
## ADR-11: Persistent action log
|
|
|
|
**Decision.** Write triggers, continuations, commands, replies, and errors to a rotating JSONL file.
|
|
Redact token-shaped strings before the write.
|
|
|
|
**Reason.** The in-memory trigger log resets at restart. The action log gives a durable audit trail
|
|
without storing raw credentials.
|
|
|
|
## ADR-12: Human send pacing
|
|
|
|
**Decision.** The first outbound send of a burst waits 30 to 200 ms. Later sends wait 500 to
|
|
2800 ms. A burst ends after a random 5 to 20 seconds of quiet. Reads take a small 100 to 300 ms gap
|
|
and do not reset the burst.
|
|
|
|
**Reason.** A real client sends the first message quickly and then slows down. Reads are not
|
|
visible in the same way and must not consume the send budget. The core hard limit stays as the
|
|
safety net. See [daemon.md](daemon.md).
|
|
|
|
## ADR-13: Web UI on a separate listener
|
|
|
|
**Decision.** The daemon serves the web UI on its own listener (`0.0.0.0:8789`) with no
|
|
authentication. The MCP server stays on localhost. The page is plain HTML, CSS, and JS behind a
|
|
JSON API.
|
|
|
|
**Reason.** Remote control over LAN or Tailscale needs a reachable port. A separate listener keeps
|
|
the MCP surface local. The JSON API is the stable boundary, so a future frontend replaces the page
|
|
without a backend change. No auth fits a private network, but the port must never be exposed to the
|
|
public internet.
|
|
|
|
## ADR-14: Voice joins muted, presence first
|
|
|
|
**Decision.** `voice.join` joins muted. Audio playback is a later feature and unmutes only while
|
|
playing. The bot leaves on its own after the owner or the stay target leaves, plus a delay.
|
|
|
|
**Reason.** A muted bot captures no audio and does not disturb the call. The lifecycle keeps the
|
|
bot from lingering in empty calls. See [voice.md](voice.md).
|
|
|
|
## ADR-15: Nocturne design and the debug shell
|
|
|
|
**Decision.** The web UI follows the Nocturne design system and the 7a debug shell from the design
|
|
handoff (`poc/WebUIMockup.zip`). `poc/public/nocturne.css` carries the token set. The page stays
|
|
plain HTML, CSS, and JavaScript with no build step. The JSON API stays the migration boundary.
|
|
|
|
**Reason.** The owner chose the design direction. Vanilla keeps the no-build constraint. Roadmap
|
|
gaps (TTS, transcript, tool-call tracing, favourites, voice actions) show as marked placeholders so
|
|
the shape of the finished UI is visible while the backend catches up.
|
|
|
|
## ADR-16: Takeover is a read-only gate
|
|
|
|
**Decision.** The Takeover switch is client-side. Off, the composer is locked and the page cannot
|
|
send. On, manual sends are allowed and each one is written to the action log as a `manual` entry.
|
|
|
|
**Reason.** The switch exists to stop accidental use of the bot account, not to model agent
|
|
ownership. The API does not enforce it, so other clients can still send. See [webui.md](webui.md).
|