PalaceBot Wiring
Who talks to whom to make Harry's Bar work: the browser, the PalaceBot server, and Discord. One process serves several Discord servers; each gets its own room at /<roomid>.
The links, one per row
| From → To | Protocol | Carries |
|---|---|---|
| Browser → Apache → palacebot | HTTPS :443 → :3311 | The page and assets, /api/me (am I logged in, and what token do I use for the socket), the OAuth callback. |
| Browser ↔ Apache ↔ palacebot | wss /ws | Everything live: hello, moves, talk, whispers, face/color/prop changes, paint strokes, votes, piece drags; back: welcome, joins, ghosts, balloons, captions, scene and widget state. |
| harryd ↔ palacebot | ws /ws (same host) | Harry's seat: an agent token instead of a login. In: talk, whispers to him, joins and leaves, widget and game events. Out: an enumerated set of calls the server checks (say, whisper, narrate, scene, paint, widgets, games), most of them only while a host has opened the floor. |
| harryd → OpenRouter | HTTPS | One chat completion per turn with tools, sometimes with a PNG of the room attached. Cost comes back per call and is metered against the room's daily budget. Only harryd has this key. |
| Browser → Discord OAuth2 → Browser | HTTPS redirects | One-time login. Discord sends the browser back with a short-lived code. |
| palacebot → Discord REST | HTTPS | Code → access token → user id, then "is this person in the guild and can they see the channel?". The access token is thrown away after that. |
| palacebot ↔ Discord Gateway | wss (outbound) | The bot's live feed: messageCreate, typingStart, guildMemberUpdate. This is how ghosts appear. |
| palacebot → Discord REST (webhook) | HTTPS | Only if a room sets mirrorToDiscord: public room talk posted under the speaker's name. Off by default, since half-conversations were noise for the channel. Whispers, moves and looks never travel here regardless. |
| palacebot → Discord REST (snapshot) | HTTPS | Edits the one pinned message with a fresh PNG of the room, balloons, boards and games included, at most every 20 s and only when something changed. This is the channel's window into the bar. |
| Discord app → palacebot (slash) | Interactions | /palace and /palace-who for anyone; /harry status|on|off|log|reset|play for hosts. Answers are ephemeral. |
| Discord app ↔ #harrys-bar | Discord's own | Ordinary chat. Nothing to install. Lurkers see the pinned picture and the webhook posts. |
Why there is no echo
Room talk goes out through a webhook, and the bot drops every incoming message that has a webhook id or a bot author. So the bot's own posts come back through the Gateway and are ignored.
One head per person
A Discord user id is the key everywhere. Connected on the web: open eyes. Only chatting from Discord: a ghost with eyes closed at a saved seat. Connecting converts the ghost in place.
Harry, the agent process
A second process, harryd, connects to the room server over the same WebSocket as a browser does, with an agent token instead of a login. It receives room events and issues only calls from an enumerated list the server checks; changing the room needs a host to have opened the floor within the last ninety seconds. It alone holds the OpenRouter key; the room server alone holds the Discord token. Whispers between people never reach it, and nothing Harry says goes to Discord except through the pinned picture.
Games run on the server
Wheel of Cheese, hangman, the boards, timers, dice and polls are server code with their state in the scene; Harry can start them and hears about them but never decides an outcome. The game show has its own page: how Wheel of Cheese is wired.