Trigger Budgets
| Field / Pattern | Limit | Measured as |
|---|
| Mechanical triggers (count) | 4,000 | count |
| Semantic triggers (count) | 500 | count |
Semantic checks per turn (+5 per active quest)a per-turn evaluation budget, not a saved-content cap: the engine checks a trigger's mechanical conditions first and runs its story/action check only when they all pass | 15 | count |
| Per-trigger size (compact JSON) | 10,000 | compact JSON |
| Per-trigger conditions (count) | 5 | count |
| Per-trigger effects (count) | 10 | count |
Trigger condition .text | 1,000 | raw characters |
Trigger condition .value | 100 | JSON-encoded string |
Trigger effect .text | 1,000 | raw characters |
Trigger effect .value | 100 | JSON-encoded string |
Trigger script field | string — size counted toward the per-trigger limit; no separate char cap |
Narrative & Story
| Field / Pattern | Limit | Measured as |
|---|
storySettings.worldBackground | 5,000 | raw characters |
storySettings.questGenerationGuidance | 5,000 | raw characters |
narratorStyle | 2,000 | raw characters |
death.instructions | 4,000 | raw characters |
worldLore (entire section) | 1,000,000 | compact JSON |
worldLore.*.text | 4,000 | raw characters |
storyStarts (entry count) | 101 | count |
storyStarts.* (each entry, compact JSON) | 8,000 | compact JSON |
Catalogs
| Field / Pattern | Limit | Measured as |
|---|
items.*.description | 4,000 | raw characters |
factions.*.basicInfo | 4,000 | raw characters |
factions.*.hiddenInfo | 4,000 | raw characters |
npcTypes.*.description | 8,000 | raw characters |
npcs.* (each entry, compact JSON) | 8,000 | compact JSON |
premadeCharacters (entry count) | 100 | count |
premadeCharacters.* (each, compact JSON) | 20,000 | compact JSON |
premadeCharacters.*.traits (count) | 40 | count |
Geography
| Field / Pattern | Limit | Measured as |
|---|
realms.*.basicInfo | 100,000 | raw characters |
regions.*.basicInfo | 4,000 | raw characters |
regions.*.hiddenInfo | 4,000 | raw characters |
locations.*.basicInfo | 4,000 | raw characters |
locations.*.hiddenInfo | 4,000 | raw characters |
locations.*.areas.*.description | 4,000 | raw characters |
realms (entire section) | 100,000 | compact JSON |
Mechanics Limits
| Field / Pattern | Limit | Measured as |
|---|
traits.*.description and traits.*.traitNarrativeEffects combined | 6,000 | raw characters |
traits (entire section) | 1,750,000 | compact JSON |
locations (entire section) | 2,000,000 | compact JSON |
npcs (entire section) | 2,000,000 | compact JSON |
npcTypes (entire section) | 500,000 | compact JSON |
factions (entire section) | 100,000 | compact JSON |
regions (entire section) | 500,000 | compact JSON |
items (entire section) | 250,000 | compact JSON |
traitCategories (entire section) | 100,000 | compact JSON |
itemSettings (entire section) | 5,000 | compact JSON |
gameModes (entire section) | 100,000 | compact JSON |
gameModes.*.name | 120 | raw characters |
gameModes.*.description | 500 | raw characters |
gameModes.*.instructions | 5,000 | raw characters |
gameModes.*.askTheNarratorPrompt | 1,000 | raw characters |
gameModes.*.npcIntentInstructions | 5,000 | raw characters |
| Entire world config (compact JSON) | 12,500,000 | compact JSON |
abilities (entry count) | 1,500 | count |
abilities.*.description | 2,000 | raw characters |
abilities.*.requirements (array length) | 10 | count |
traits.*.requirements (array length) | 10 | count |
Trait category maxSelections | 40 | count |
abilities.*.bonus | must not exceed skillSettings.maxSkillSuccessLevel (balanced default 999) — Voyage clamps the applied contribution to that cap, so any bonus above it is silently wasted |
AI Instructions Limits
| Field / Pattern | Limit | Measured as |
|---|
Each string leaf under a task (aiInstructions.<task>.<key>) | 5,000 | JSON-encoded string |
Per task (aiInstructions.<task> total, whole task as compact JSON) | 20,000 | compact JSON |
Each string leaf under aiInstructions.generateNPCIntents | 8,000 | JSON-encoded string |
aiInstructions.generateStory total | 30,000 | compact JSON |
aiInstructions.generateNPCIntents total | 40,000 | compact JSON |
aiInstructions.generateNPCDetails total | 26,000 | compact JSON |
aiInstructions.generateNPCUpdates total | 24,000 | compact JSON |
Image Prompts
| Field / Pattern | Limit | Measured as |
|---|
Each imagePromptConfiguration field | 5,000 | raw characters |
imagePromptConfiguration (all fields combined) | 15,000 | raw characters |
Settings Caps
| Field / Pattern | Limit | Measured as |
|---|
combatSettings.damageTypes (entry count) | 40 | count |
combatSettings.damageTypes.* (each) | 60 | raw characters |
itemSettings.itemCategories (entry count) | 40 | count |
itemSettings.itemCategories.* (each) | 60 | raw characters |
itemSettings.itemSlots (slot count) | 60 | count |
itemSettings.itemSlots.*.slot (slot name) | 64 | raw characters |
itemSettings.itemSlots.*.category (slot category) | 60 | raw characters |
itemSettings.currencyName | 64 | raw characters |
attributeSettings.attributeNames (entry count) | 30 | count |
attributeSettings.attributeNames.* (each) | 64 | raw characters |
nameFilterSettings (entire section) | 150,000 | compact JSON |
nameFilterSettings.*.replacements.* (each replacement) | 64 | raw characters |
Hard caps enforced by Voyage Studio's validation. Exceeding any of them makes the wand validator reject the upload. Every figure in the tables above is pulled directly from the live Voyage schema, so they always reflect the currently enforced limits.
#How each limit is measured
The same length can be counted several different ways depending on what is capped, and that difference is usually what makes a document that looks under the limit get rejected. Each limit above carries its own Measured as column, taken from the live schema; that column is the answer for any specific cap.
| Measure | What counts |
|---|
| Raw length | The characters as typed: a newline, quote, or em dash each count as 1, exactly what a plain character counter shows. |
| Pretty-printed JSON (2-space indent) | The whole object serialized with indentation, so keys, quotes, colons, braces, and the indent whitespace all count. Deeply nested entries cost more than their visible text. |
| Compact JSON (no whitespace) | The object serialized without indentation: keys and punctuation count, but not the indent whitespace. |
| JSON-encoded string | The value as it appears quoted in the JSON: the two wrapping quotes count, and each newline, quote, or backslash inside counts as 2 (it is escaped). |
The aiInstructions per-task total is the sneakiest: each instruction key is capped on its own, but the task total measures the whole task object, so the key names and punctuation count on top of your instruction text. A task can sit under every per-key cap and still be over its task total.