Messages
Every message type Voxta supports — characters, users, events, notes, secrets, instructions, stories, custom.
A Voxta chat is a stream of typed messages. Most are obvious (user said something, character replied) but several specialized types let scenarios add nuance: hidden context for the AI, hidden notes for the user, narrated events, story beats, instructions.
Message type taxonomy
Each message type has four properties:
- 👁 Char. — visible to the character (i.e. sent to the LLM as part of the prompt).
- 👁 User — visible to you in the chat UI.
- Reply — triggers a follow-up character reply.
- Narrated — in scenarios with a narrator, this gets read out loud.
| Template | Command | Description | 👁 Char | 👁 User | Reply | Narrated |
|---|---|---|---|---|---|---|
{{ char }} | — | First character speaks | ✓ | ✓ | ✓ | — |
{{ user }} | your message | User speaks | ✓ | ✓ | ✓ | — |
{{ scenario_chars.role }} | — | Specific role's character speaks | ✓ | ✓ | ✓ | — |
{{ event }} | /event text | Narrated event | ✓ | ✓ | ✓ | ✓ |
{{ story }} | /story prompt | Story-writer narrated event | ✓ | ✓ | ✓ | ✓ |
{{ note }} | /note text | Silent note | ✓ | ✓ | — | — |
{{ secret }} | /secret text | Hidden from user, AI sees it | ✓ | — | — | — |
{{ instructions }} | /instructions text | Hidden from character, you see it | — | ✓ | — | — |
| — | /noreply text | User message without auto-reply | ✓ | ✓ | — | — |
When to use what
- Note — facts you want both the AI and the user to remember, but that don't need a response. "She has just walked into the room."
- Secret — let the AI in on something the user doesn't know yet. "The detective is lying."
- Instructions — give yourself a reminder visible only to you. Doesn't reach the AI.
- Event — narrate something happening, optionally read aloud by the narrator. Triggers a reply.
- Story — like Event, but the story writer generates the text instead of you typing it. Optional max-tokens / max-sentences caps.
/noreply— say something to the AI without triggering a reply. Useful for one-shot info dumps.
Custom messages
The /message command (or chat.customMessage() from a script) gives you full control:
/message --arg1 "value1" --arg2 --etc -- the message content| Arg | Value | Notes |
|---|---|---|
role | Secret, Note, Instructions, Event, User, Assistant | Message type |
character | "name" | Which character is speaking |
scenario-role | role_name | Specific scenario role |
use-story-writer | boolean | Generate the text instead of using it verbatim |
max-new-tokens | number | Cap generated length |
max-sentences | number | Sentence count cap |
reply | boolean | Trigger a follow-up reply |
narrate | boolean | Read aloud |
expires-after-turns | number | Drop the message from the prompt after N conversation turns |
-- | text | The message body (everything after) |
Expiring messages
A message injected into the chat is permanent by default: it stays in the prompt for the life of the chat. That is right for a plot point and wrong for a status report. If something outside Voxta streams in what is true right now — where a body is, what a game is doing, what a camera sees — every one of those reports piles up, and the model ends up reading a detailed account of a world that moved on twenty minutes ago.
expiresAfterTurns puts a lifespan on a message. After N conversation turns it stops being sent to the model, as
though it had been deleted. The row is kept, so you can still see it in the chat explorer — it is hidden from the
prompt, not erased.
The value counts conversation turns and must be at least 1. It cannot be set on a story or a character message:
those are what the user came for, not per-turn context.
You can set it from anywhere a message is created:
# On /note, /secret and /instructions — options first, then -- , then the text
/secret --expires-after-turns 2 -- {{ char }} is sitting on the couch, watching TV.
# On /message, alongside its other arguments
/message --role Note --expires-after-turns 5 -- The engine is overheating.// From a script
chat.secret('Standing by the window.', { expiresAfterTurns: 2 });A client can also set expiresAfterTurns on the sendMessage it sends, which applies to whichever of those
commands the message carries. An expiry spelled out on the command itself wins over the one on the message.
/note, /secret and /instructions only read arguments when the text starts with --. Anything else is
taken as the message, verbatim — so a secret that reads she paused -- then left still says exactly that.
Examples
Story-writer secret, short
/message --role Secret --use-story-writer --max-new-tokens 200 --max-sentences 2 -- Then something incredible happens!The story writer generates 2 sentences of secret content extending "Then something incredible happens!"
Speak as a specific character
/message --character "Catherine" -- Hi! It's me, Catherine!Forces a message attributed to Catherine regardless of normal turn order.
Speak as a scenario role
/message --scenario-role "main" -- I'm this story's main character.A note, no narration
/message --role Note --narrate false -- A loud noise is heard in the distance.From scripts
All message types are available via chat.* in scripts:
chat.note('A loud noise');
chat.secret('The detective is lying');
chat.instructions('Remember this for later');
chat.event('A door slams');
chat.story('A long-form description');
chat.userMessage('Where are we going?');
chat.characterMessage('To the garden');
chat.roleMessage('detective', 'Right behind you');
chat.customMessage({
role: 'Secret',
text: 'Generated by story writer',
useStoryWriter: true,
maxNewTokens: 50,
maxSentences: 2,
triggerReply: false,
narrate: false,
});
// Transient context — gone from the prompt after 3 turns
chat.secret('The room smells of smoke.', { expiresAfterTurns: 3 });See Scripting for context.