Developer ReferenceTemplate Authoring

Template Authoring

Templates define the schema for every entity type in StudioBrain. Each template is a markdown file with YAML frontmatter that declares all fields, their types, defaults, and structure. Creating a new template automatically creates a new entity type — no code changes required.

Template File Format

Templates live at _Templates/Standard/{TYPE}_TEMPLATE.md. The file name must follow the pattern {UPPERCASE_TYPE}_TEMPLATE.md.

A template has two parts:

  1. YAML frontmatter (between --- delimiters): Declares all fields with their types and default values.
  2. Markdown body (below the frontmatter): Provides the default markdown content structure with section headings and placeholder text that serves as instructions for both human authors and AI generation.

Template Walkthrough: CHARACTER_TEMPLATE

Here is a simplified excerpt from the Character template showing the key patterns:

---
# METADATA
template_version: "2.0"
id: "[snake_case_name]"
entity_type: "character"
created_date: "[YYYY-MM-DD]"
last_updated: "[YYYY-MM-DD]"
status: "active"
 
# PRODUCTION STATUS TRACKING
production_status:
  general: "concept"
  game_uefn: "none"
  tv_showrunner: "none"
  notes: ""
 
# PRIMARY IMAGE
primary_image: ""
 
# BASIC IDENTITY
name: "[Generate Full Name]"
nickname: "[Generate Nickname]"
age: "18"
gender: "[male/female/non-binary]"
species: "human"
 
# TEMPORAL INFORMATION
birth_year: null
death_year: null
key_dates: []
current_age_reference_year: 1998
 
# PHYSICAL DESCRIPTION
height: "[Height in feet/inches]"
build: "[slim/average/muscular/heavyset]"
hair_color:
  name: ""
  hex: ""
eye_color:
  name: ""
  hex: ""
distinguishing_features:
  - "[Unique physical feature 1]"
  - "[Unique physical feature 2]"
 
# LOCATION & MOVEMENT
primary_location: "[Reference existing location ID]"
secondary_locations:
  - "[Secondary location 1]"
 
# RELATIONSHIPS
faction: "[Faction affiliation or independent]"
family:
  - "[Relationship]: [Person name/description]"
friends:
  - "[Friend name/description]": "[relationship_type]"
enemies: []
 
# PERSONALITY & PSYCHOLOGY
personality_traits:
  - "[Core trait 1]"
  - "[Core trait 2]"
fears:
  - "[Primary fear]"
motivations:
  - "[Primary motivation]"
secrets:
  - "[Hidden secret 1]"
defining_moment_summary: "[Brief summary of pivotal life event]"
 
# SKILLS & ABILITIES
primary_skills:
  - "[Main skill 1]"
secondary_skills:
  - "[Secondary skill 1]"
special_abilities: []
 
# STORY INTEGRATION
story_function:
  - "[Role in narrative]"
inventory_items:
  - "[Item 1]"
associated_brands:
  - "[Brand name 1]"
job:
  - "[Reference existing Job name 1]"
narrative_importance: "[main/major/minor]"
 
# AI GENERATION HELPERS
ai_profile_description: "[Visual description for AI]"
ai_voice_style: "[Speaking style description]"
ai_bio_summary: "[2-3 sentence bio]"
dialogue_samples:
  - "[Example line 1]"
  - "[Example line 2]"
---
 
# [Character Full Name]
 
## Background
 
[2-3 paragraphs describing the character's background...]
 
## Personality
 
[1-2 paragraphs describing personality...]
 
## Defining Moment
 
[1-2 paragraphs describing the pivotal life event...]
 
## Dialogue & Speech Patterns
 
[Description of how they speak...]
 
### Example Dialogue
 
> "[Greeting line]"
 
> "[Emotional response line]"
 
## Relationships
 
**[Category]**: [Description...]
 
## Story Role
 
[Function in the narrative...]

Field Types

The type system is inferred from the default values in the template YAML. The type generator (generate_types.py) reads these defaults to determine TypeScript types.

YAML DefaultInferred TypeTypeScriptZod Schema
"" or "placeholder"stringstringz.string()
0 or 42numbernumberz.number()
true or falsebooleanbooleanz.boolean()
nullnullable stringstring | nullz.string().nullable()
[]string arraystring[]z.array(z.string())
["item1", "item2"]string arraystring[]z.array(z.string())
Nested object (key: value)object{ key: type }z.object({ ... })

String Fields

name: "[Generate Full Name]"     # String with placeholder instruction
gender: "[male/female/non-binary]" # String with allowed values hint
status: "active"                   # String with default value

Number Fields

age: "18"                         # Stored as string, parsed as needed
founded: 1987                     # Integer
population: 0                     # Integer with zero default

Boolean Fields

is_active: true
is_deceased: false

Array Fields

# Simple string array
personality_traits:
  - "[Core trait 1]"
  - "[Core trait 2]"
 
# Empty array (items added by user)
special_abilities: []
enemies: []

Nested Objects

# Object with named sub-fields
production_status:
  general: "concept"
  game_uefn: "none"
  tv_showrunner: "none"
  notes: ""
 
# Object with color data
hair_color:
  name: ""
  hex: ""
 
# Object with multiple sub-objects
skin_tone:
  palette: ""
  base: ""
  midtone: ""
  shadow: ""
  highlight: ""

Reference Fields

Fields that reference other entities use the target entity’s ID as a string value. The cross-reference system recognizes these patterns:

# Single reference
primary_location: "[Reference existing location ID]"
faction: "[Faction affiliation]"
 
# Array of references
secondary_locations:
  - "[Secondary location 1]"
  - "[Secondary location 2]"
associated_brands:
  - "[Brand name 1]"
job:
  - "[Reference existing Job name 1]"

Entity Types Reference

StudioBrain ships with 16 entity templates. Each defines a different content type.

Entity TypeTemplate FilePrefixDescription
characterCHARACTER_TEMPLATE.mdCH_Characters, NPCs, players
locationLOCATION_TEMPLATE.mdLOC_Places, buildings, landmarks
districtDISTRICT_TEMPLATE.mdDST_City areas, neighborhoods, zones
brandBRAND_TEMPLATE.mdBR_Companies, products, services
factionFACTION_TEMPLATE.mdFAC_Organizations, gangs, governments
itemITEM_TEMPLATE.mdITM_Game items, weapons, consumables
jobJOB_TEMPLATE.mdJOB_Occupations, roles, positions
questQUEST_TEMPLATE.mdQST_Missions, objectives, tasks
campaignCAMPAIGN_TEMPLATE.mdCMP_Story arcs, campaigns
eventEVENT_TEMPLATE.mdEVT_World events, incidents
dialogueDIALOGUE_TEMPLATE.mdDLG_Conversation trees, scripts
timelineTIMELINE_TEMPLATE.mdTL_Historical entries, chronology
assemblyASSEMBLY_TEMPLATE.mdASM_Modular entity assemblies
style_bibleSTYLE_BIBLE_TEMPLATE.mdSTY_Visual style guides
universeUNIVERSE_TEMPLATE.mdUNI_World-building, lore

File and Folder Structure

Entities are stored in folders named after their entity ID:

Characters/
  rex_marshall/
    CH_rex_marshall.md        # Main entity file
    images/
      portrait.png
      concept_art.jpg
    audio/
      voice_sample.mp3
    data/
      stats.json

Locations/
  downtown_plaza/
    LOC_downtown_plaza.md
    images/
      aerial_view.png

Brands/
  double_dip_dog_sauce/
    BR_double_dip_dog_sauce.md
    images/
      logo.png

The file prefix (CH_, LOC_, BR_, etc.) is defined per entity type in the EntityFieldMappings service.

Required Metadata Fields

Every template must include these metadata fields:

template_version: "2.0"        # Template format version
id: "[snake_case_name]"         # Unique entity identifier
entity_type: "character"        # Must match template type
created_date: "[YYYY-MM-DD]"   # ISO date
last_updated: "[YYYY-MM-DD]"   # ISO date
status: "active"                # active, archived, draft

The production_status block is optional but recommended for tracking workflow:

production_status:
  general: "concept"           # concept, in_progress, needs_work, narrative_done, art_done, complete
  game_uefn: "none"            # none, planned, in_progress, review, published, live
  tv_showrunner: "none"        # none, planned, in_progress, review, episode, current, archived
  notes: ""

AI Generation Sections

Templates can include fields specifically for AI context:

# AI GENERATION HELPERS
ai_profile_description: "[Visual description from profile image]"
ai_voice_style: "[Speaking style/vocal characteristics]"
ai_bio_summary: "[Concise 2-3 sentence bio for AI context]"
dialogue_samples:
  - "[Example line showing personality]"

These fields are consumed by the AI service’s Enhanced Context Builder to generate content that matches the entity’s established characteristics.

Rules Files

Rules files at _Rules/{TYPE}_RULES.md define validation and generation rules for each entity type. They use the same YAML frontmatter + markdown format.

Rule Structure

Each rule has these fields:

rules:
  - id: "char_name_required"
    category: "validation"
    priority: "high"
    validation_type: "required_field"
    applies_to: "name"
    description: "Character name is required"
 
  - id: "char_age_range"
    category: "validation"
    priority: "medium"
    validation_type: "range"
    applies_to: "age"
    min: 18
    max: 85
    description: "Character age must be between 18 and 85"
 
  - id: "char_personality_count"
    category: "generation"
    priority: "high"
    validation_type: "min_count"
    applies_to: "personality_traits"
    min_count: 3
    description: "Characters should have at least 3 personality traits"

Rule Fields

FieldTypeDescription
idstringUnique rule identifier
categorystringvalidation, generation, consistency, style
prioritystringhigh, medium, low
validation_typestringrequired_field, range, min_count, regex, reference_exists, custom
applies_tostringField name this rule validates
descriptionstringHuman-readable explanation

Available Rule Files

FileEntity TypePurpose
CHARACTER_RULES.mdcharacterName, age, traits, relationships
LOCATION_RULES.mdlocationCoordinates, district refs, atmosphere
DISTRICT_RULES.mddistrictPopulation, faction control
BRAND_RULES.mdbrandIndustry, market position
FACTION_RULES.mdfactionMembers, territory, hierarchy
ITEM_RULES.mditemRarity, pricing, stats
JOB_RULES.mdjobSalary, skills, employer
DIALOGUE_RULES.mddialogueVoice consistency, line format
CONTENT_RULES.md(all)General content quality
GENERATION_RULES.md(all)AI generation constraints
IMAGE_GENERATION_RULES.md(all)Image generation styles
STORY_RULES.md(all)Narrative consistency
TIMELINE_RULES.mdtimelineDate validation, ordering
UNIVERSE_RULES.mduniverseLore consistency
VOICE_GENERATION_RULES.md(all)Voice/audio generation
WORLD_LORE_RULES.md(all)World-building consistency

Rules API

Rules are managed through the REST API:

GET    /api/rules                      # List all rule files
GET    /api/rules/{type}               # Get parsed rules
POST   /api/rules/{type}               # Add new rule
PUT    /api/rules/{type}/{rule_id}     # Update rule
DELETE /api/rules/{type}/{rule_id}     # Delete rule
POST   /api/rules/validate/{type}     # Validate entity against rules

Automatic Type Generation

Running npm run generate:types or npm run dev triggers the Python script CityBrainsStoryBuilder/backend/generate_types.py, which:

  1. Reads all _Templates/Standard/*_TEMPLATE.md files
  2. Parses the YAML frontmatter
  3. Infers TypeScript types from default values
  4. Generates three files:

src/types/generated/entities.ts — TypeScript interfaces:

export interface EntityBase {
  entity_type: string;
  entity_id: string;
  name: string;
  fields: Record<string, any>;
  markdown_body?: string;
  created_at?: string;
  updated_at?: string;
}
 
export interface Character extends EntityBase {
  age?: string;
  gender?: string;
  faction?: string;
  personality_traits?: string[];
  primary_location?: string;
  // ... all fields from template
}

src/types/generated/schemas.ts — Zod validation schemas:

import { z } from 'zod';
 
export const CharacterSchema = z.object({
  entity_type: z.literal('character'),
  entity_id: z.string(),
  name: z.string(),
  age: z.string().optional(),
  gender: z.string().optional(),
  personality_traits: z.array(z.string()).optional(),
  // ... runtime validation for all fields
});

src/types/generated/mappings.ts — Type utilities:

export const ENTITY_TYPES = [
  'character', 'location', 'district', 'brand',
  'faction', 'item', 'job', 'quest', 'campaign',
  'event', 'dialogue', 'timeline', 'assembly',
  'style_bible', 'universe'
] as const;
 
export type EntityType = typeof ENTITY_TYPES[number];

Importing Generated Types

Always import from the barrel export:

// Correct
import { Character, Location, CharacterSchema } from '@/types';
 
// Wrong -- don't import from generated/ directly
import { Character } from '@/types/generated/entities';
 
// Wrong -- don't create local interfaces
interface Character { ... }

Adding a New Entity Type

Creating a new entity type requires only one step: create the template file.

  1. Create _Templates/Standard/MYENTITY_TEMPLATE.md:
---
template_version: "2.0"
id: "[snake_case_name]"
entity_type: "myentity"
created_date: "[YYYY-MM-DD]"
last_updated: "[YYYY-MM-DD]"
status: "active"
 
production_status:
  general: "concept"
  game_uefn: "none"
  tv_showrunner: "none"
  notes: ""
 
primary_image: ""
name: "[Entity Name]"
custom_field_one: ""
custom_field_two: []
custom_nested:
  sub_field_a: ""
  sub_field_b: 0
---
 
# [Entity Name]
 
## Description
 
[Describe this entity...]
 
## Details
 
[Additional details...]
  1. Run npm run generate:types to produce TypeScript interfaces and Zod schemas.

  2. The new entity type is immediately available:

    • GET /api/entity/myentity lists entities
    • POST /api/entity/myentity creates entities
    • import { MyEntity } from '@/types' provides the TypeScript interface
    • The frontend dynamically renders edit forms based on the template schema

No backend code changes, no database migrations, no frontend component creation.

Template Versioning

The template_version field tracks the template format. When you update a template (add fields, change structure), bump the version. The backend’s FrontmatterValidator can detect version mismatches and offer to migrate entity files to the new format.

template_version: "2.0"   # Current format version

Existing entities with older template versions continue to work. Missing fields get default values from the template. Removed fields are preserved in the entity’s fields JSON but not validated.