Glyphoxa provides two types of commands for controlling NPC agents during a live TTRPG session:
- Slash commands – typed into Discord’s chat bar (e.g.,
/session start). These are registered as Discord Application Commands with autocomplete, modals, and permission checks. - Voice commands – spoken aloud by the DM into the voice channel. The voice command filter intercepts the DM’s speech-to-text output before it reaches the NPC routing pipeline, executing orchestrator actions in real time.
All slash commands that modify session state or NPC behaviour require the DM role (configured via dm_role_id in the bot config). If dm_role_id is left empty, all users are treated as DMs – useful during development.
Table of Contents
⚡ Slash Commands
/session
Manage voice sessions. The DM starts a session to connect Glyphoxa to a voice channel, enabling NPC agents to listen and speak.
/session start
Start a voice session in the DM’s current voice channel.
/session start
| Parameter | Type | Required | Description |
|---|---|---|---|
| (none) | – | – | The bot joins whichever voice channel you are currently in. |
Permissions: DM role required.
Behaviour:
- The DM must be in a voice channel when invoking this command.
- If a session is already active, the command fails with the existing session ID.
- On success, the bot joins the voice channel and responds with the session ID, campaign name, and channel link.
Example output:
Session started!
Session ID: abc123-def456
Campaign: Lost Mines of Phandelver
Channel: #tavern-voice
/session stop
Stop the active voice session.
/session stop
| Parameter | Type | Required | Description |
|---|---|---|---|
| (none) | – | – | – |
Permissions: DM role required.
Behaviour:
- If no session is active, the command fails with a message.
- On success, the bot disconnects from the voice channel and reports the session ID and total duration.
Example output:
Session abc123-def456 stopped.
Duration: 1h23m45s
/session recap
Show a recap of the current or most recent session, including an AI-generated summary of the transcript.
/session recap
| Parameter | Type | Required | Description |
|---|---|---|---|
| (none) | – | – | – |
Permissions: DM role required.
Behaviour:
- If no session data is available, prompts you to start a session first.
- Retrieves the session transcript and, if an LLM summariser is configured, generates a narrative summary. Falls back to a raw chronological transcript if summarisation is unavailable or fails.
- Responds with a rich embed containing:
- Campaign name, session ID, status (Active / Ended)
- Who started the session, duration, voice channel
- List of NPCs (with mute state)
- Transcript entry count
- AI-generated summary or raw transcript
Example output (embed):
Session Recap
Campaign: Lost Mines Status: Active Session ID: abc123
Started By: @DungeonMaster Duration: 45m30s Channel: #tavern
NPCs:
- Grimjaw
- Elara (muted)
Transcript Entries: 127
[AI-generated narrative summary of the session...]
/npc
Manage NPC agents during an active session. All subcommands require an active session and the DM role.
/npc list
List all NPCs with their current mute status.
/npc list
| Parameter | Type | Required | Description |
|---|---|---|---|
| (none) | – | – | – |
Permissions: DM role required.
Behaviour:
- Returns a rich embed listing each NPC with a speaker icon (unmuted) or muted icon, their display name, and internal ID.
Example output (embed):
NPC Agents
🔊 Grimjaw (ID: grimjaw-001)
🔇 Elara (ID: elara-002)
/npc mute
Mute a specific NPC. A muted NPC stops responding to player speech.
/npc mute name:<npc_name>
| Parameter | Type | Required | Description |
|---|---|---|---|
name | String | Yes | NPC name (autocomplete-enabled). |
Permissions: DM role required.
Behaviour:
- Uses autocomplete to suggest active NPC names as you type.
- If the NPC is not found, responds with an error.
- On success, confirms the NPC has been muted.
/npc unmute
Unmute a previously muted NPC, allowing it to respond to player speech again.
/npc unmute name:<npc_name>
| Parameter | Type | Required | Description |
|---|---|---|---|
name | String | Yes | NPC name (autocomplete-enabled). |
Permissions: DM role required.
/npc speak
Make an NPC speak pre-written text in its own TTS voice, bypassing the LLM entirely. This is the puppet mode slash command variant – the DM writes the words, and the NPC’s voice says them.
/npc speak name:<npc_name> text:<text>
| Parameter | Type | Required | Description |
|---|---|---|---|
name | String | Yes | NPC name (autocomplete-enabled). |
text | String | Yes | The exact text for the NPC to speak aloud. |
Permissions: DM role required.
Behaviour:
- The text is synthesised using the NPC’s configured TTS voice and enqueued in the audio mixer.
- A transcript entry is recorded with the NPC as the speaker.
- The LLM is not involved – the NPC says exactly what you typed.
Example:
/npc speak name:Grimjaw text:Welcome to my tavern, adventurers!
Response:
Grimjaw is speaking: "Welcome to my tavern, adventurers!"
/npc muteall
Mute all NPCs at once.
/npc muteall
| Parameter | Type | Required | Description |
|---|---|---|---|
| (none) | – | – | – |
Permissions: DM role required.
Behaviour:
- Mutes every active NPC and reports the count.
- Useful for cutting off all NPC chatter during narration or a dramatic moment.
Example output:
Muted 4 NPC(s).
/npc unmuteall
Unmute all NPCs at once.
/npc unmuteall
| Parameter | Type | Required | Description |
|---|---|---|---|
| (none) | – | – | – |
Permissions: DM role required.
Example output:
Unmuted 4 NPC(s).
/entity
Manage campaign entities (NPCs, locations, items, factions, quests, lore). Entities are the persistent world-knowledge that NPC agents draw upon during conversations.
/entity add
Add a new entity via a Discord modal form.
/entity add
| Parameter | Type | Required | Description |
|---|---|---|---|
| (none – opens a modal) | – | – | – |
Permissions: DM role required.
Behaviour:
- Opens a modal with four fields:
| Modal Field | Required | Max Length | Description |
|---|---|---|---|
| Name | Yes | 100 | Entity name (e.g., “Gundren Rockseeker”). |
| Type | Yes | 20 | One of: npc, location, item, faction, quest, lore. |
| Description | No | 2000 | Free-text description of the entity. |
| Tags | No | 200 | Comma-separated tags (e.g., “ally, phandalin, quest-giver”). |
- On submit, validates the entity type and creates the entity in the store.
Example output:
Entity created!
Name: Gundren Rockseeker
Type: npc
ID: ent_abc123
/entity list
List all entities, optionally filtered by type.
/entity list [type:<entity_type>]
| Parameter | Type | Required | Description |
|---|---|---|---|
type | String (choice) | No | Filter by entity type. Choices: NPC, Location, Item, Faction, Quest, Lore. |
Permissions: DM role required.
Behaviour:
- Returns a rich embed with up to 25 entities (Discord embed field limit).
- Each entity shows its name, type, truncated description, and tags.
- The footer shows the total entity count.
/entity remove
Remove an entity by name, with a confirmation prompt.
/entity remove name:<entity_name>
| Parameter | Type | Required | Description |
|---|---|---|---|
name | String | Yes | Entity name (autocomplete-enabled, searches across all types). |
Permissions: DM role required.
Behaviour:
- Autocomplete suggests entity names as you type, showing the type in parentheses.
- After selecting an entity, a confirmation embed appears with Cancel and Confirm Remove buttons.
- Removal is permanent and cannot be undone.
/entity import
Import entities from a YAML or JSON file attachment.
/entity import
| Parameter | Type | Required | Description |
|---|---|---|---|
| (file attachment) | Attachment | Yes | Attach a .yaml, .yml, or .json file to the command message. |
Permissions: DM role required.
Behaviour:
- Maximum file size: 10 MB.
- YAML files are parsed as Glyphoxa campaign format (via
entity.LoadCampaignFromReader). - JSON files are parsed as Foundry VTT export format (via
entity.ImportFoundryVTT). - Reports the number of entities successfully imported.
Example output:
Import complete. 42 entities imported from campaign.yaml.
/campaign
Manage the active campaign configuration.
/campaign info
Display metadata about the currently loaded campaign.
/campaign info
| Parameter | Type | Required | Description |
|---|---|---|---|
| (none) | – | – | – |
Permissions: DM role required.
Behaviour:
- Shows an embed with: campaign name, game system, total entity count, and a breakdown of entities by type (NPC, Location, Item, Faction, Quest, Lore).
Example output (embed):
Campaign Info
Name: Lost Mines System: D&D 5e Total Entities: 42
Entity Breakdown:
npc: 12
location: 8
item: 15
faction: 3
quest: 4
/campaign load
Load a campaign from a YAML file attachment. Requires no active session.
/campaign load
| Parameter | Type | Required | Description |
|---|---|---|---|
| (file attachment) | Attachment | Yes | Attach a campaign YAML file (.yaml or .yml). |
Permissions: DM role required.
Behaviour:
- If a session is currently active, the command fails – stop the session first with
/session stop. - Only YAML format is accepted for campaign files (not JSON).
- Maximum file size: 10 MB.
- Parses the campaign YAML and imports all entities into the store.
Example output:
Campaign loaded!
Name: Curse of Strahd
System: D&D 5e
Entities imported: 67
/campaign switch
Switch to a different campaign configuration. Requires no active session.
/campaign switch name:<campaign_name>
| Parameter | Type | Required | Description |
|---|---|---|---|
name | String | Yes | Campaign name (autocomplete-enabled from available campaigns). |
Permissions: DM role required.
Behaviour:
- If a session is active, the command fails – stop the session first.
- Autocomplete suggests available campaign names from the configuration.
/feedback
Submit post-session feedback via a modal form. Available to any user after at least one session has been run.
/feedback
| Parameter | Type | Required | Description |
|---|---|---|---|
| (none – opens a modal) | – | – | – |
Permissions: Any user (no DM role required). A session must have been run previously.
Behaviour:
- Opens a modal with five fields:
| Modal Field | Required | Range | Description |
|---|---|---|---|
| Voice latency | Yes | 1-5 | Rate voice response speed (1 = terrible, 5 = great). |
| NPC personality | Yes | 1-5 | Rate how well NPCs stayed in character. |
| Memory accuracy | Yes | 1-5 | Rate how well NPCs remembered past events. |
| DM workflow | Yes | 1-5 | Rate the overall DM workflow experience. |
| Comments | No | up to 1000 chars | Free-text feedback. |
- On submit, saves the feedback and responds with the average rating.
Example output:
Thank you for your feedback! Average rating: 4.3/5
Session: abc123-def456
🎙️ Voice Commands
Voice commands are spoken aloud by the DM during a live session. The voice command filter runs on the DM’s speech-to-text output before it reaches the NPC routing pipeline, so these phrases are intercepted and never forwarded to NPC agents.
Voice commands are case-insensitive and only processed for the configured DM user.
| Spoken Phrase | Pattern | Action | Example |
|---|---|---|---|
mute <name> | ^mute\s+(.+)$ | Mutes the named NPC. | “Mute Grimjaw” |
<name>, be quiet | ^(.+?),?\s+be\s+quiet$ | Mutes the named NPC (natural speech variant). | “Grimjaw, be quiet” |
unmute <name> | ^unmute\s+(.+)$ | Unmutes the named NPC. | “Unmute Elara” |
everyone, stop | ^everyone,?\s+stop$ | Mutes all NPCs at once. | “Everyone, stop” |
everyone, continue | ^everyone,?\s+continue$ | Unmutes all NPCs at once. | “Everyone, continue” |
<name>, say <text> | ^(.+?),?\s+say\s+(.+)$ | Makes the named NPC speak the given text (puppet mode). | “Grimjaw, say welcome to my tavern” |
Notes:
<name>is matched against active NPC names (case-insensitive).- The comma after the NPC name is optional (e.g., both “Grimjaw be quiet” and “Grimjaw, be quiet” work).
- Patterns are tested in order from top to bottom; the first match wins.
- If the named NPC is not found, the command fails silently (logged as a warning).
🎠Puppet Mode
Puppet mode lets the DM speak as an NPC – the DM’s words come out in the NPC’s voice, bypassing the LLM entirely. This is useful when:
- The DM wants precise control over what an NPC says (e.g., reading boxed text, delivering a dramatic monologue).
- An NPC needs to say something the AI might not generate on its own (plot-critical revelations, specific item descriptions).
- The DM wants to override the AI’s response in the moment.
How It Works
There are three ways to use puppet mode:
1. Slash Command: /npc speak
Type the exact text you want the NPC to say:
/npc speak name:Grimjaw text:The treasure lies beneath the old well.
The text is synthesised using the NPC’s configured TTS voice and played into the voice channel. A transcript entry is recorded with the NPC as the speaker.
2. Voice Command: <name>, say <text>
Speak the command aloud during a live session:
“Grimjaw, say the treasure lies beneath the old well”
The DM’s spoken phrase is intercepted by the voice command filter, and the captured text is fed through the NPC’s TTS. The DM’s original speech is not forwarded to any NPC agent.
3. Routing Override: SetPuppet
The orchestrator’s SetPuppet(speaker, npcID) API forces all subsequent utterances from a given speaker to be routed to a specific NPC, bypassing normal address detection. This is a lower-level mechanism used programmatically:
- Set override:
orchestrator.SetPuppet("dm-user-id", "grimjaw-001")– all DM speech now routes to Grimjaw. - Clear override:
orchestrator.SetPuppet("dm-user-id", "")– returns to normal address detection.
The routing priority order is:
- Explicit name match (NPC name spoken in the utterance)
- DM puppet override (
SetPuppet) - Last-speaker continuation
- Single-NPC fallback
- No match (error)
Puppet Mode vs. Normal AI Responses
| Aspect | Normal Mode | Puppet Mode (/npc speak or voice say) |
|---|---|---|
| Text source | LLM generates the response | DM provides the exact text |
| Voice | NPC’s configured TTS voice | NPC’s configured TTS voice (same) |
| Transcript | Recorded as NPC speech | Recorded as NPC speech (same) |
| Conversation history | LLM response added to context | Puppet text added to context |
| Latency | STT + LLM + TTS pipeline | TTS only (faster) |
📊 Dashboard
The session dashboard is a live-updating Discord embed that displays real-time metrics for the active session. It is automatically posted to the text channel when a session starts and updated every 10 seconds.
Information Displayed
The dashboard embed includes:
| Field | Description |
|---|---|
| Campaign | Name of the active campaign. |
| Session ID | Unique identifier for the current session. |
| Duration | Elapsed time since session start (updates live). |
| Active NPCs | Count of active NPCs, with muted count if any are muted (e.g., “4 (2 muted)”). |
| Utterances | Total number of processed player utterances. |
| Errors | Total pipeline errors encountered. |
| Pipeline Latency | P50 and P95 latencies for each pipeline stage (when data is available): |
|  | - STT – Speech-to-text latency |
|  | - LLM – Language model inference latency |
|  | - TTS – Text-to-speech synthesis latency |
|  | - Total – End-to-end speech-to-speech latency |
| Memory Entries | Number of transcript entries stored in the session memory. |
Lifecycle
- Created when
/session startis run. The embed is posted as a new message in the text channel. - Updated in place every 10 seconds by editing the same message (no chat spam).
- Finalized when
/session stopis run. The embed colour changes from green to red, the footer changes to “Session ended”, and updates stop.
Embed Appearance
During an active session – green sidebar (#2ECC71), footer reads “Live session”, timestamp updates with each refresh.
After session ends – red sidebar (#E74C3C), description reads “Session has ended.”, footer reads “Session ended”.
Pipeline Latency Format
Latency values are computed from a rolling window of recent samples (default: last 100 observations per stage) and displayed as:
STT: p50=45.2ms p95=120.8ms
LLM: p50=230.1ms p95=510.3ms
TTS: p50=85.7ms p95=190.2ms
Total: p50=380.5ms p95=820.1ms
đź”— See Also
- npc-agents.md – NPC agent configuration, voice settings, and personality authoring.
- configuration.md – Bot configuration reference (
token,guild_id,dm_role_id, campaign YAML format). - getting-started.md – Quick-start guide for setting up Glyphoxa and running your first session.