Files
Veskslop-t/docs/communication.md
T

8.0 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.
speak <text> Speak text into the bot's current voice call. speak stop stops it.
poll ... Start a reaction poll. Paused at this time.
stay @user Planned with the voice backend. Pin the bot to a voice user. See voice.md.

Notes:

  • The owner cannot be removed.
  • The command accepts mentions and raw user IDs.
  • whitelist commands need the admin tier.
  • A bare whitelist or whitelist help shows the help.
  • The reply follows the response policy.

Polls

Paused. POLL_ENABLED is false in poc/src/puppet.ts. The parser, the tests, and the code stay in place. The daemon does not run a poll command.

The poll command posts a message and adds one number emoji per option. Discord users vote by reacting. The poll closes after pollSeconds (default 120) and the daemon posts the result.

Format:

poll "Question" Option 1 // Option 2 [// Option 3 [// Option 4]]
poll Question | Option 1 | Option 2
  • The question can be in quotes. Then the first option follows after the closing quote.
  • Separators are | or //. The // separator needs whitespace on both sides. This keeps URLs such as https://example.com in one piece.
  • A bare poll or poll help shows the help.
  • Options: 2 to 4. Each option is at most 80 characters.

Voting:

  • Emojis: 1️⃣, 2️⃣, 3️⃣, 4️⃣.
  • Multiple reactions per user are allowed. Each reaction counts.
  • Removing a reaction removes that one selection.
  • The puppet's own reactions do not count.
  • Votes do not need a trust tier. Friends can vote.
  • The result message goes to the poll channel.

Examples:

@puppet poll "What country is best" Sweden // Denmark // Madagaskar
@puppet poll Lunch? | Pizza | Sushi

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 with set_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.

  1. The daemon reads the newest cached message ID for the channel.
  2. It fetches messages after that ID. On the first run, it fetches the newest messages.
  3. It merges the new messages into the cache.
  4. 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
voice Voice action, channel, mute
audio Audio action (speak, stop, devices, capture), provider, size
manual Web UI send: mode, channel or user, content length
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

  1. The client receives a MESSAGE_CREATE gateway event.
  2. The core normalizes the event.
  3. The core bridge pushes the event to the daemon.
  4. The daemon queues the event. Events run one at a time.
  5. The daemon drops a replayed event.
  6. The daemon applies the trigger rules.
  7. The daemon collects context for a mention trigger.
  8. The daemon adds the entry to the log and writes the action log.
  9. 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

  1. Add the rule in poc/src/puppet.ts, in handleEvent.
  2. Keep the rule small and testable.
  3. Add a unit test in poc/src/test-communication.ts when the rule is pure logic.
  4. Run pnpm test:comm and pnpm test:cache.