How it works
Messages accumulate in a buffer
Incoming messages are added to a per-channel ring buffer (up to
maxBufferSize messages). Each buffer entry includes the author, content, timestamp, and — if the message is a reply — the referenced message.Evaluation is triggered
A dynamic timer fires after
defaultInterval milliseconds of inactivity. If the buffer has more messages, the interval is shortened. If a configured trigger word is detected, evaluation is forced immediately.Haiku classifies the batch
The classifier (
claude-haiku-4-5 by default) reads the buffer snapshot and returns one of: respond, chime-in, moderate, or ignore. Around 80% of evaluations result in ignore, which means Sonnet never runs for that batch.Sonnet generates the response
When the classification is not
ignore, the responder (claude-sonnet-4-6 by default) generates a reply targeted at the relevant messages. It can use the WebSearch tool and will signal this with a 🔍 reaction on the trigger message.The bot always overrides an
ignore classification when it is directly @mentioned in one of the buffered messages.Trigger words
Trigger words cause an immediate evaluation regardless of the timer. When any message in the buffer contains a trigger word,evaluateNow() fires without waiting.
Daily budget
SetdailyBudgetUsd to cap how much the triage system spends per day per guild. Once the cap is reached, evaluations are paused until the daily window resets. A throttled alert (at most once per hour) is posted to moderationLogChannel when the cap is hit.
0 or omit the key to disable the budget gate.
Channel inclusion and exclusion
Control which channels participate in triage:| Config key | Behavior |
|---|---|
channels | Allowlist — if non-empty, only these channel IDs are evaluated. An empty array means all channels. |
excludeChannels | Denylist — these channel IDs are always skipped, even if listed in channels. |
ai.blockedChannelIds are also excluded from triage.
Moderation response mode
When the classifier returnsmoderate, the responder generates a moderation-appropriate message and posts a structured embed to moderationLogChannel.
moderationResponse to false to suppress in-channel responses for moderation events while still logging to the mod channel.
The moderation log embed includes the recommended action (warn, timeout, kick, ban, or delete), the violated rule, the channel, and the flagged message content. Protected role members (admins, moderators) are skipped automatically.
Streaming
By default, triage uses non-streaming mode — the responder waits for a complete response before sending anything to Discord. Enable streaming to start sending partial output as it arrives.Debug footer
WhendebugFooter is true, each triage response includes an embed showing per-invocation AI usage stats.
Status reactions
The bot adds emoji reactions to the trigger message to signal what stage of evaluation it is in:| Emoji | Meaning |
|---|---|
| 👀 | Classification in progress |
| 💬 | Generating a response |
| 🧠 | Generating a response with thinking tokens enabled |
| 🔍 | Web search in progress (stays after response is sent) |
statusReactions to false.
Full config reference
| Config key | Default | Description |
|---|---|---|
enabled | true | Enable or disable the triage system |
defaultInterval | 3000 | Base evaluation timer in milliseconds |
maxBufferSize | 30 | Maximum messages held per channel buffer |
triggerWords | ["volvox"] | Words that force an immediate evaluation |
classifyModel | claude-haiku-4-5 | Model used for the classifier step |
classifyBudget | 0.05 | Per-invocation spend cap for the classifier (USD) |
respondModel | claude-sonnet-4-6 | Model used for the responder step |
respondBudget | 0.2 | Per-invocation spend cap for the responder (USD) |
thinkingTokens | 1024 | Extended thinking token budget for the responder (0 to disable) |
streaming | false | Stream partial response output to Discord |
tokenRecycleLimit | 20000 | Token count at which the CLI process is recycled |
contextMessages | 10 | Number of historical messages fetched from Discord for context |
timeout | 30000 | Evaluation timeout in milliseconds |
moderationResponse | true | Send in-channel responses for moderation classifications |
channels | [] | Allowlisted channel IDs (empty = all channels) |
excludeChannels | [] | Denylisted channel IDs |
debugFooter | true | Attach an AI usage stats embed to responses |
debugFooterLevel | verbose | Footer detail level (verbose or compact) |
moderationLogChannel | — | Channel ID for moderation audit embeds and budget alerts |
statusReactions | true | Add emoji reactions to show evaluation progress |
dailyBudgetUsd | 10 | Daily spend cap per guild in USD (0 to disable) |