--- title: "Character Definition Schema" description: "Canonical schema for playable character definitions covering identity, knowledge, relationships, and presentation" type: design status: draft ticket: "#179" decision_refs: [D-005, D-016, D-027, D-028, D-032, D-034, D-035, D-041, D-065] author: "" created: 2026-02-19 updated: 2026-02-19 --- # Character Definition Schema **Ticket:** #179 | **Priority:** Critical | **Sprint:** 12 **Status:** v0.1 Draft **Blocks:** #180 (Smuggler character build), #181 (Detective character build) **Decisions referenced:** D-005 (single character, asymmetric information), D-016 (internal monologue), D-027 (vertical slice), D-028 (dialogue layers), D-032 (separate monologue pools), D-034 (THE FRIEND), D-035 (tag taxonomy), D-041 (knowledge graph), D-065 (smuggler inventory) --- ## 1. Purpose This document defines the canonical schema for a playable character in v0.1. A playable character is **not just a perspective** — it is a complete starting state that determines what the player sees, who they know, what they understand, and what they can do. Every field in this schema has downstream content implications. Two characters share the same world. Two different schemas produce two different games. --- ## 2. Schema Overview A playable character definition has six top-level sections: | Section | Purpose | |---------|---------| | `identity` | Who this character is in the world | | `starting_knowledge` | What the character knows at session start (KG seed) | | `starting_relationships` | Pre-existing relationships and their initial state | | `access_permissions` | Which dialogue tiers are available at session start | | `skills` | Capability flags affecting gameplay options | | `presentation` | Voice, monologue register, and diegetic evidence display | --- ## 3. Identity ```yaml identity: canonical_id: "pc:{slug}" # e.g., "pc:smuggler", "pc:detective" display_name: "{Name}" # Player-visible name (stub until #180/#181) archetype: "{archetype}" # "smuggler" | "detective" occupation: "{occupation}" # Diegetic job title posting_duration: "{duration}" # How long they've been in Sova Transit District faction: "{faction}" # Institutional affiliation if any lattice_tier: "{tier}" # "civilian" | "professional" | "investigative" description: > 1-2 paragraph description of who this character is in the world, from a fictional universe perspective — not mechanical. Establishes emotional baseline, social position, and what they stand to lose. ``` **Field notes:** - `archetype` is used internally by the engine for monologue pool selection (D-032 hard partition). It is NOT exposed in the UI. Character feels like a person, not a game mechanic. - `lattice_tier` determines which perception overlays are available (D-017). Civilian: no enhanced perception. Professional: diagnostic tools, analytical overlays. Investigative: full analytical suite. - `posting_duration` affects which starting knowledge entries are plausible. A character who arrived 3 days ago cannot know the bar regulars by name. --- ## 4. Starting Knowledge The starting knowledge section defines the Knowledge Graph seed (D-041) — the fact-set the character enters the session with. Facts not listed here are genuinely unknown at session start. ```yaml starting_knowledge: confidence_floor: "{tier}" # Minimum confidence level; see D-041 known_facts: - key: "{fact.key}" # Namespaced fact key (e.g., "contraband.ring_exists") confidence: "{tier}" # KnowsOf | KnowsDetails | KnowsEverything source: "{source}" # "direct" | "secondhand" | "institutional" | "rumor" notes: > Optional. Authoring note on how the character holds this knowledge. unknown_facts: - key: "{fact.key}" notes: > Why this gap exists — what would they need to do to discover it? ``` **Fact key namespaces:** | Namespace | Covers | |-----------|--------| | `contraband.*` | Ring existence, cargo types, supply chain, operational methods | | `location.*` | Specific places, access routes, surveillance gaps | | `investigation.*` | Manifest discrepancies, evidence, case file data | | `relationship.*` | Who knows whom, trust levels, ring membership | | `world.*` | Station geography, shift schedules, institutional structures | | `person.*` | Specific facts about named individuals | **Critical rule:** The unknown_facts section is as important as known_facts. It defines what the character CANNOT react to at session start and bounds what monologue triggers are legal. --- ## 5. Starting Relationships Pre-existing relationships that determine initial RelationshipState (D-075) and AccessTier for every named NPC in the district. NPCs not listed here start at `Unknown` / `public` access. ```yaml starting_relationships: - target: "npc:{canonical_id}" relationship_state: "{state}" # Unknown | Known | Friendly | PersonOfInterest | Hostile access_tier: ["{tiers}"] # public | peer | insider | authority | hostile trust_level: "{level}" # uncertain | reliable | trusted | hostile relationship_type: "{type}" # colleague | friend | superior | contact | adversary known_attributes: name: "{name}" # Whether the character knows the NPC's name role: "{role}" # What role the character assigns to this NPC faction: "{faction}" # Whether the character knows the NPC's affiliation notes: > Short description of the nature of this relationship and how it was established. ``` **Relationship state → access tier mapping (default):** | RelationshipState | Default Access Tier | Override possible? | |-------------------|--------------------|--------------------| | Unknown | public | Yes (authority overrides via badge/credentials) | | Known | public, peer | Yes | | Friendly | peer, insider | No insider without explicit history | | PersonOfInterest | authority (detective) | Yes | | Hostile | hostile | No | **Character-specific overrides:** The smuggler has insider access to ring-member NPCs from session start (shared criminal history). The detective has authority access to institutional NPCs from session start (institutional credentials). These overrides are specified per-relationship, not as a global archetype flag (D-075). --- ## 6. Access Permissions Global access tier capabilities at session start — what the character can unlock through gameplay versus what is structurally inaccessible. ```yaml access_permissions: can_unlock: - tier: "{tier}" condition: "{condition}" # When this tier becomes accessible max_npcs: "{n | unlimited}" # How many NPCs can reach this tier structurally_locked: - tier: "{tier}" reason: > Why this tier is never accessible to this character across the entire v0.1 vertical slice. ``` **v0.1 constraints:** - **Smuggler** can unlock: public (all), peer (Known→Friendly), insider (ring-member NPCs from start; others locked). Cannot unlock: authority (no institutional credentials). - **Detective** can unlock: public (all), authority (any Unknown/Known NPC via credentials), peer (Friendly NPCs only — currently Sera at session start). Cannot unlock: insider (ring dialogue never becomes available, even with investigation progress — the ring locks tighter, not looser, when the detective gets close). This asymmetry is structural, not a content choice. It defines the two-keyhole architecture (D-027). --- ## 7. Skills Capability flags that affect which game verbs are available and how gameplay systems respond. ```yaml skills: lattice_tier: "{tier}" # Copied from identity; determines perception modes (D-017) movement_default: "{stance}" # Default stance from D-053 MovementProfile inventory_slots: {n} # Physical inventory capacity (D-065) evidence_display: "{format}" # "case_file" | "personal_notebook" (D-065) capability_flags: - "{flag}" # e.g., "manifest_access", "authority_credentials", "ring_routes" starting_items: - item_id: "{id}" description: "{description}" leverage_type: "{type}" # "proof" | "access" | "leverage" notes: > What this item proves, enables, or demonstrates. ``` **Capability flags vocabulary:** | Flag | Effect | |------|--------| | `manifest_access` | Can request freight manifests from institutional NPCs | | `authority_credentials` | Badge/identification; unlocks authority tier with Unknown/Known NPCs | | `ring_routes` | Knows smuggling corridors and timing windows | | `ring_membership` | Treated as insider by ring-member NPCs from session start | | `analytical_lattice` | Pattern recognition overlay; flags behavioral anomalies at Careful stance | | `cargo_handling_cert` | Can interact with freight systems without triggering security flags | --- ## 8. Presentation How this character's internal voice, diegetic evidence display, and monologue pool are configured. ```yaml presentation: monologue_pool: "{archetype}" # Hard partition per D-032 ("smuggler" | "detective") evidence_display: "{format}" # Inherited from skills; documented here for content authors voice_register: sentence_length: "{pattern}" # "fragments" | "complete" | "mixed" vocabulary: "{style}" # "concrete/sensory" | "institutional/analytical" emotional_mode: "{mode}" # "feeling-first" | "analysis-first" relationship_mode: "{mode}" # "first-name/relational" | "surname-first/categorical" emotional_baseline: state: "{state}" # One-word summary of starting emotional state description: > 3-5 sentences on the character's psychological starting position. This is the foundation that monologue lines build from. Lines that contradict this baseline are wrong. opening_monologue: lines: - "{line}" # 3-5 authored lines; see D-039 wow moment #1 emotional_payload: > What the player should feel in the first 60 seconds. ``` **Voice register is non-negotiable.** The smuggler thinks in fragments. The detective thinks in complete sentences. The moment an author writes a complete-sentence analysis for the smuggler or a terse fragment for the detective, they've broken the dual-lens contract. The voice register fields in this schema exist so downstream authors never have to re-read the authoring guide — the character build IS the authoring guide. --- ## 9. Schema Validation Rules Before finalizing a character build, validate against these rules: | Rule | Check | |------|-------| | **Knowledge symmetry** | For every `known_fact` about an NPC, that NPC file must have a corresponding `known_attributes` entry in the character's relationship | | **Access tier consistency** | No `insider` access without `ring_membership` or equivalent history | | **Monologue pool** | All authored monologue lines tagged with this character's `archetype` (hard partition) | | **Unknown facts are real** | Every fact in `unknown_facts` must NOT appear in any authored monologue line at session start | | **Opening monologue** | Opening lines must NOT reference facts the character doesn't yet know | | **Inventory items** | All starting items must have corresponding world entities in content files | | **Emotional baseline** | Opening monologue lines must match the character's `emotional_baseline.state` | --- ## 10. Cross-Reference: Downstream Documents | Document | How This Schema Feeds It | |----------|------------------------| | `character-build-smuggler.md` (#180) | Full instantiation of this schema for the smuggler | | `character-build-detective.md` (#181) | Full instantiation of this schema for the detective | | `divergent-starting-knowledge.md` (#182) | Comparison table derived from both builds' `starting_knowledge` sections | | `divergent-relationships.md` (#183) | Comparison table derived from both builds' `starting_relationships` sections | | `npcs/pc-smuggler.yaml` | NPC mode representation when detective is the active player | | `npcs/pc-detective.yaml` | NPC mode representation when smuggler is the active player | | Content packs (#190, #191, #192) | Access tier decisions in this schema determine which content each character sees | | Opening hooks (#299, #300) | Opening monologue section provides the first lines | --- *Ticket #179 — Character definition schema. v0.1 scope. Blocks #180, #181.*