@kody/discord
Read and post in Discord servers with a bot token, and read identity and guilds with user OAuth.
AGENTS.md
104 lines · 3.6 KB · Markdown@kody/discord — agent notes
Human setup and intent live in README.md. This file is for
agents: imports, smoke/dryRun snippets, and edge cases. Secrets by name
only — never paste token values. Do not disable live webhooks or jobs.
Secrets / integrations
| Lane | Credential | Default name |
|---|---|---|
| Bot token | User secret | discordBotToken |
| User OAuth | Saved integration | discord |
Override with secretName (bot) or integration (OAuth). Extra accounts:
discord-work / discordBotTokenWork — never hard-code personal aliases.
Import paths
| Export | Import |
|---|---|
| overview | kody:@kody/discord |
| smoke-test | kody:@kody/discord/smoke-test |
| get-me | kody:@kody/discord/get-me |
| list-guilds | kody:@kody/discord/list-guilds |
| fetch-channel | kody:@kody/discord/fetch-channel |
| fetch-channel-messages | kody:@kody/discord/fetch-channel-messages |
| post-message | kody:@kody/discord/post-message |
| edit-message | kody:@kody/discord/edit-message |
| add-reaction | kody:@kody/discord/add-reaction |
| create-thread | kody:@kody/discord/create-thread |
| list-channel-threads | kody:@kody/discord/list-channel-threads |
Prefer static kody:@kody/discord/... imports from execute. Static imports
run in this package's runtime so secret mounts resolve.
Smoke test (read-only)
Bot lane (reads approved discordBotToken):
import smokeTest from 'kody:@kody/discord/smoke-test'
export default async function main() {
return await smokeTest({ lane: 'bot' })
}OAuth lane:
import smokeTest from 'kody:@kody/discord/smoke-test'
export default async function main() {
return await smokeTest({ lane: 'oauth', integration: 'discord' })
}Static identity read (OAuth):
import getMe from 'kody:@kody/discord/get-me'
export default async function main() {
return getMe({ lane: 'oauth', integration: 'discord' })
}dryRun / confirm (mutations)
Mutations (post-message, edit-message, add-reaction, create-thread)
accept dryRun: true (preview payload, no API write). Live writes require
confirm: true after the user approved the exact channel and content.
import postMessage from 'kody:@kody/discord/post-message'
export default async function main() {
return postMessage({
channelId: '1234567890',
content: 'Hello from Kody',
dryRun: true,
})
}Edge cases
- OAuth never grants channel content — use the bot lane for messages/reactions/threads.
- Empty message
contenton an otherwise successful read: enable Message Content on the Bot tab. - Helpers throw
DiscordApiErrorwithmissingScopeandnextStepon 401/403. - OAuth 401/403: reconnect at
/connect/oauth?provider=…&scopes=…. Do not cache raw tokens (7-day expiry). - Bot 401: rotate/save
discordBotToken. Package always sends theBotprefix. - Bot 403 code 50001 Missing Access: bot not in server / cannot see channel — reinstall with
scope=bot. - Bot 403 code 50013 Missing Permissions: grant missing channel permission or privileged intent, then retry.
list-channel-threadsrequires bothchannelIdandguildId.- Discord rate-limits reactions aggressively — add sequentially and honor
retry_afteron HTTP 429. - Only messages posted by the same bot can be edited.
Fork / adapt
- Fork this listing into the caller's account (kody id stays
discord). - Connect their bot secret and/or OAuth integration; approve
discord.com. - Run
./smoke-testfor each lane before treating the copy as ready. - Keep
LICENSE,## Intent, andcommunity-icon.svgintact for community listing.