Flags
State bits that filter actions and contexts, settable from actions, events, and scripts.
Flags are named booleans that track the current state of a chat. Simple strings: is_thirsty, wears_hat, door_closed. You set them from actions, events, or scripts; you read them from conditions on actions and contexts.
A character with the flag wears_hat set will:
- Have the
wear_hataction filtered out (it's a no-op — they already wear it). - Have the
{{ char }} is wearing a hatcontext render in every prompt.
That's the core loop. Everything else is variations.
Setting and unsetting
A flag is set by including its name. Prefix with ! to unset:
wears_hat # set
!wears_hat # unsetYou can do both in the same effect — e.g. an action that takes off a hat and reveals a hairstyle might set !wears_hat, ponytail_visible.
Enum flags (mutually exclusive)
Some flags are mutually exclusive — a character can be standing OR sitting OR dancing, but not all three. Manually unsetting "all the other poses" every time you change is tedious. Voxta solves this with dot-syntax enum flags:
pose.standing
pose.sitting
pose.dancingSetting pose.dancing automatically unsets pose.standing and pose.sitting. The pose. prefix means "all flags starting with pose. are mutually exclusive."
Unsetting enums
!pose.standing— unsets onlypose.standing. Otherpose.*flags untouched.!pose— unsets allpose.*flags. Useful for resetting a category.
Flag conditions
Conditions are mini JS-like boolean expressions used on actions and contexts.
| Expression | Meaning |
|---|---|
pose.standing | Active only if pose.standing is set. |
!pose.standing | Active only if pose.standing is NOT set. |
pose.standing && !door.closed | Both must hold. |
hold.empty_bottle || hold.empty_glass | Either holds. |
(a || b) && !c | Use parens to group. |
Setting from a script
import { chat } from "@voxta";
export function trigger(e) {
// Set a flag
chat.setFlag('wears_hat');
// Unset
chat.unsetFlag('wears_hat');
// Equivalent:
chat.setFlag('!wears_hat');
// Enum
chat.setFlag('pose.sitting'); // auto-clears pose.standing etc.
// Multiple at once
chat.setFlags('wears_hat', 'pose.standing', '!is_drenched');
// Check
if (chat.hasFlag('wears_hat')) { /* ... */ }
}See Scripting for the full chat-state API.
Expiring flags
Set a flag that auto-clears after a duration:
// Expires after 10 conversation messages
chat.setFlag('cooldown', { messages: 10 });
// Expires after 2 minutes of chat time
chat.setFlag('cooldown', { seconds: 120 });Useful for cooldowns, "just happened" markers, and short-lived emotional states.
Patterns
Once-ever events
Use the Once checkbox on an action — Voxta auto-generates an invisible _action_name flag and an !_action_name condition. Fires once per chat.
State machines
Use enum flags for state machines. state.intro, state.investigation, state.confrontation — only one is set at a time, and transitions are explicit.
Location / slot navigation
A specialization of state machines, common in visual-novel and stage-view scenarios. Use a single enum flag as the "current location" and gate every context, action, and button on it:
Flag set: context_slot_places.lobby (or .backyard, .corridor, etc.)
Context: "{{ user }} is standing in the lobby..." FlagsFilter: context_slot_places.lobby
Button: "Go to backyard" FlagsFilter: context_slot_places.lobby
— fires: setFlags("context_slot_places.backyard", ...)Setting context_slot_places.backyard auto-clears context_slot_places.lobby, the lobby context disappears, the lobby buttons hide, the backyard context appears, the backyard buttons show. One flag, one source of truth for where the user is. See the Stage Editor for the visual side of this pattern.
Looping events
Set a flag from an event, then use since flag <flag> on the same event with a message-count delta. The event fires, sets its own flag, re-arms, fires again.