A minimal Discord bot with a /ping slash command, deployed on Val Town.
Interactions arrive over HTTP — no Gateway connection, no discord.js, no
always-on process.
/pingslash command — replies "Pong!"- One-shot
/setupendpoint registers commands and points Discord at this val (uses Discord'sPATCH /applications/@meAPI — no manual portal config of the interactions URL) - Signed-request verification with native Web Crypto Ed25519 (no npm dep)
AGENTS.md— Claude Code can drive the entire setup end to end- Easily extensible: add commands by editing
lib/discord.tsand the handler ininteractions.ts
The fastest path: tell Claude Code "set up this discord bot" and let
AGENTS.md drive. Manual path:
- Remix this val so you have your own copy.
- Create the Discord app at Discord Developer Portal → New Application. Pick a name, accept terms, create.
- Paste 3 secrets into your val's
environment variables:
DISCORD_APP_ID— General Information → Application IDDISCORD_PUBLIC_KEY— General Information → Public KeyDISCORD_BOT_TOKEN— Bot tab → Reset Token (shown once)
- Run setup — registers
/pingand sets the interactions endpoint:curl -X POST <your-val-url>/setup \ -H "Authorization: Bot <DISCORD_BOT_TOKEN>" - Invite the bot using the URL returned by step 4 (also shown on the val's homepage).
- Type
/pingin any channel where the bot is present → "Pong!"
The val's HTTP homepage (GET /) shows live env-var status and copy-pasteable
commands — open it after remixing.
Discord doesn't have a Slack App Manifest equivalent — there's no URL that creates a pre-configured app from a JSON blob. But Discord's Edit Current Application API lets you set the interactions endpoint programmatically once you have the bot token, and slash commands have always been registerable via API. This template uses both so the user's only portal work is create app + copy 3 values.
discord-bot/
├── interactions.ts # HTTP entry: setup page + Discord webhook + /setup admin
├── AGENTS.md # Claude Code setup script
├── README.md
└── lib/
├── verify.ts # Ed25519 signature verification (Web Crypto)
└── discord.ts # Discord REST helpers + command definitions
Discord POSTs every interaction to /interactions. The handler verifies the
ed25519 signature on (timestamp + body) using DISCORD_PUBLIC_KEY, then
replies inline — slash commands return their response in the same HTTP request
(no follow-up token needed for fast handlers like /ping).
- Add a slash command → add it to
PING_COMMANDSinlib/discord.ts, add a case in theAPPLICATION_COMMANDhandler ininteractions.ts, then re-runPOST /setupto register it. - Long-running command (>3s of work) → respond first with
DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE(type 5), then PATCH the original message via/webhooks/{app}/{token}/messages/@original. Or dispatch to a second HTTP route (early-return pattern, see the Slackbot template). - Change scopes/permissions in
buildInviteUrl()inlib/discord.ts.
This val uses pinned imports to avoid breaking changes:
hono@4.12.0
(Discord API calls use native fetch; signature verification uses native Web
Crypto. No other dependencies.)