6.3 KiB
Communication
This document describes the trigger rules, trust tiers, commands, the trigger log, context, the continuation window, and the response policy.
Trigger rules
A message is a trigger when both conditions are true:
- The author is trusted. Each tier counts as trusted.
- One of these conditions is true:
- The message is a one-to-one DM to the puppet.
- The message mentions the puppet in a guild channel or a group DM.
All other messages are ignored. Untrusted messages do not enter the log at this time. Bots and the puppet's own messages are ignored.
The daemon processes events one at a time. This order matters for continuation windows.
Trust tiers
| Tier | Meaning |
|---|---|
user |
Can trigger the puppet. This is the default tier. |
trusted |
Can trigger the puppet. Future chat commands need this tier. |
admin |
Can manage the trust list and the config. The owner is always an admin. |
The owner controls the trust list. Commands from other users do not change the list.
Commands
The owner sends commands from Discord. In a DM, the text is the command. In a guild or a group DM, mention the puppet first.
| Command | Effect |
|---|---|
whitelist list |
Show the owner and the trusted users with their tiers. |
whitelist add @user [user|trusted|admin] |
Add one or more users. The default tier is user. |
whitelist remove @user |
Remove one or more users from the trust list. |
Notes:
- The owner cannot be removed.
- The command accepts mentions and raw user IDs.
whitelistcommands need the admin tier.- The reply follows the response policy.
Response policy
The policy decides where a reply goes. Sensitive replies go by DM.
| Setting | Meaning | Default |
|---|---|---|
defaultMode |
The mode for normal replies: channel or dm |
channel |
sensitiveCommands |
Commands that always reply by DM | whitelist, config |
overrides |
A per-command mode | empty |
Rules:
- An override wins over the sensitive list. The sensitive list wins over the default mode.
- A DM reply failure does not fall back to the origin channel. The daemon logs the error only.
- Read the policy with
get_puppet_config. Change it withset_puppet_config.
Trigger log
The log has two ring buffers.
| Buffer | Limit | Content |
|---|---|---|
| Trusted | 100 entries | Triggers from trusted users |
| Untrusted | 30 entries | Reserved. No triggers enter this buffer at this time. |
One entry holds these fields:
| Field | Meaning |
|---|---|
id |
The message ID |
channelId |
The channel ID |
guildId |
The guild ID, or absent for a DM |
authorId |
The author user ID |
authorName |
The author username |
content |
The raw message content |
timestamp |
The message timestamp |
trusted |
True for a trusted author |
command |
The parsed command text, when the message looks like a command |
context |
Prior messages. Present on mention triggers. Follow-ups join this list. |
Context
The daemon collects prior messages for a mention trigger. Direct messages do not need context.
- Message limit:
contextMessages, default 15. - Character limit:
contextChars, default 4000. - The lower limit stops the collection.
- Each line holds a time stamp, the author, the message text, and attachment file names.
- Media bodies stay on Discord.
- The trigger message is not part of its own context.
The cache makes the fetch small.
- The daemon reads the newest cached message ID for the channel.
- It fetches messages after that ID. On the first run, it fetches the newest messages.
- It merges the new messages into the cache.
- It assembles the context from the merged list.
The fetch cooldown stops a burst of queries. The setting fetchCooldownSeconds (default 5) is the
minimum gap between two fetches for one channel.
Cache settings:
| Setting | Default |
|---|---|
VESKSLOP_CACHE_DIR |
<tmp>/veskslop-cache |
VESKSLOP_CACHE_MAX_BYTES |
50 MiB |
| Messages per channel | 200 |
Eviction removes the least recently written channel files until the folder fits the size limit.
Continuation window
A user can send a second message right after a request. The second message often adds a missing detail. The daemon appends such messages to the request context.
- Window:
continuationSeconds, default 10. - The window starts at the trigger and resets on each follow-up.
- Only messages from the same author in the same channel count.
- A follow-up does not need a mention.
- A follow-up needs a trusted author.
Action log
The daemon writes a persistent log beside the state file: actions.jsonl. One JSON line holds one
event. The log rotates at the size limit.
| Event | Content |
|---|---|
trigger |
Message ID, channel, guild, author, tier, command, context count |
continuation |
Follow-up message ID and the parent entry ID |
command |
Command text, requester, result |
reply |
Command, mode, target, result, error |
error |
Scope and message |
Secret-looking strings are redacted before the write. Discord token shapes and mfa. strings
become [redacted].
Settings:
| Setting | Default |
|---|---|
VESKSLOP_ACTION_LOG |
<state dir>/actions.jsonl |
VESKSLOP_ACTION_LOG_MAX_BYTES |
5 MiB |
Read the log with the get_action_log MCP tool.
Event flow
- The client receives a
MESSAGE_CREATEgateway event. - The core normalizes the event.
- The core bridge pushes the event to the daemon.
- The daemon queues the event. Events run one at a time.
- The daemon drops a replayed event.
- The daemon applies the trigger rules.
- The daemon collects context for a mention trigger.
- The daemon adds the entry to the log and writes the action log.
- The daemon runs a trusted command and replies through the response policy.
State file
The daemon stores the owner ID, the trust list, and the config in JSON.
- Default path:
poc/.veskslop-state.json. - Override:
VESKSLOP_STATE_FILE. - The trust list is an object: user ID to tier.
- The trigger log is in memory only. The action log is persistent.
How to add a trigger rule or a command
- Add the rule in
poc/src/puppet.ts, inhandleEvent. - Keep the rule small and testable.
- Add a unit test in
poc/src/test-communication.tswhen the rule is pure logic. - Run
pnpm test:commandpnpm test:cache.