@volter/twin-discord
v0.1.2
Published
Local Discord twin — a faithful, stateful local Discord bot API (REST v10 + the gateway websocket) your real discord.py / discord.js bot talks to unmodified. Channels, messages, slash commands, and a gateway handshake that makes a bot consider itself conn
Readme
@volter/twin-discord
A local Discord twin: the bot API your real discord.py or discord.js bot talks to unmodified.
Both halves a bot needs — the REST v10 API and the gateway websocket — on one port.
bun packages/twin/discord/src/cli.ts serve --port 8080Point the bot at it and it connects: GET /gateway/bot answers with this server's own websocket
URL, so the bot discovers the gateway the same way it discovers Discord's.
What it does
- The gateway handshake.
HELLO→IDENTIFY→READY, with heartbeats acknowledged. A bot library does not consider itself logged in until this completes, so a REST-only twin would leave it retrying forever. - Messages. Post to a channel, read a channel newest-first with
limit, edit, delete. A channel a world never seeded is created on first post: the twin admits the id its consumer believes in. - Events. A message posted through the REST door is dispatched to every connected bot as
MESSAGE_CREATE— so a world puts words in a human's mouth by posting as them (Authorization: User <name>, a header no SDK sends; anything else is the bot), and the bot hears it over the wire. - Slash commands. Bulk overwrite (
PUT .../commands) is the set the bot declared; a shrinking set shrinks. - The bot user. Created on first sight and stable thereafter, so nothing needs seeding to connect.
Coverage
Faithful: the v10 paths above, snowflake ids (decimal strings encoding the world clock), the
{message, code} error shape and the codes a consumer branches on (10003 unknown channel, 10008
unknown message, 50006 empty message, 50035 bad limit).
Not modeled: auth (any bot token is accepted, and a bad token does not 401), rate limits, voice, threads, reactions, interactions beyond command registration, and sharding beyond a single shard.
Reaching it from an app you cannot modify
discord.py hardcodes https://discord.com/api/v10 and builds its own aiohttp session, so it
ignores HTTPS_PROXY. Env-based attachment cannot redirect it. Use the world's reflect front (DNS
plus the session CA — see docs/ATTACH.md), which is the mechanism for exactly this case: a binary
whose HTTP client you do not control.
