Campaign AI Agent System

Purpose

Define how the AI agent behaves as a Game Master and Narrator during campaign turns: role separation, instruction composition, context assembly, and the current Daggerheart-first extension seams. This document extends Campaign AI Orchestration with the behavioral layer: what the agent is taught, how context is budgeted, and how contributors add game-system-specific intelligence.

Output Channel Model

The agent speaks through three output channels. Each maps to a distinct role: | Channel | Role | Purpose | |———|——|———| | Tool calls (dice, scene, interaction tools) | Game Master | Adjudicate rules, resolve mechanics, manage authoritative game state | | interaction_record_scene_gm_interaction structured content | Narrator | In-character prose, atmosphere, prompts, and consequence beats | | Final model response (OutputText) | Meta / OOC | Conversational reply to the caller, summaries, coordination notes | Channel discipline: The agent must never mix rules text into committed narration, nor embed state-mutating decisions in free-form prose. Tool calls are the sole authority for state changes; committed text is the sole authority for in-character narration. Committed prompt beats are still narrator-owned content: they may ask for player-character action, dialogue, or commitment, but they must not outsource NPC dialogue, NPC choices, or world-outcome authorship to the player.

Beat-Oriented Interaction Authoring

The committed interaction channel is beat-oriented: the agent authors one structured gm_interaction at a time using ordered beats such as fiction, resolution, consequence, guidance, and prompt. It must not reason in terms of separate narration plus frame text. When players should act next, the interaction should end with a prompt beat; when mechanics were resolved this turn, resolution and consequence beats should appear before that handoff prompt; when the GM keeps control, the interaction may omit a prompt beat entirely. A beat is a coherent interaction unit, not a paragraph container: one beat may span multiple paragraphs, and a second beat of the same type is warranted only when the GM is making a distinct move or shifting the information context.

Mechanics-Heavy Turn Discipline

Mechanics-heavy turns require stricter channel discipline than scene-framing turns.

  • Before the agent narrates a claimed capability or permissive fiction, it should verify that the claim fits established scene facts and the acting character’s actual sheet.
  • The committed interaction should make the authoritative mechanical outcome legible to the player whenever HP, Armor, Hope, Stress, Fear, spotlight, or visible countdown pressure changed.
  • resolution and consequence beats are reserved for actual adjudication. Fiction-only turns should stay in fiction plus optional guidance and prompt beats.
  • Player-facing beats should describe game-state changes in table language, not engine language. Internal IDs, enum names, and storage-shaped labels belong in memory or OOC notes, not in the committed beat text.
  • Reference lookup is staged, not automatic. The agent should use short always-on guidance and current state first, then consult the reference corpus only when exact procedure or wording is unclear.
  • Any future critique or coaching behavior must remain out-of-band from the GM lane. The same turn should not mix authoritative adjudication with product self-analysis.

    Instruction Composition

    Agent instructions are markdown files on disk, not Go string literals. This enables iteration without recompilation and A/B testing via directory swap.

    Directory Layout

    data/instructions/
    v1/
      core/
        skills.md           # Core GM operating contract
        interaction.md      # Tool channel discipline, commit rules
        memory-guide.md     # How to manage structured memory
      daggerheart/
        skills.md           # Daggerheart-specific GM guidance
        reference-guide.md  # Reference lookup patterns
      # Additional systems remain future architecture work; this is not yet a
      # generic multi-system runtime contract.
    

    Composition Order

    campaigncontext/instructionset.Loader composes skills guidance in this order:

    1. core/skills.md — universal GM/Narrator contract
    2. {system}/skills.md — game-system-specific guidance (e.g. Daggerheart)
    3. core/memory-guide.md — memory management guidance
    4. {system}/reference-guide.md — system reference lookup patterns core/interaction.md is loaded separately as the prompt renderer’s interaction-contract text so startup can degrade missing fields independently instead of disabling the full prompt path.

      Runtime Override

      FRACTURING_SPACE_AI_INSTRUCTIONS_ROOT points to an alternative instruction directory. Default: embedded data/instructions/v1 via embed.FS.

      Context Assembly Pipeline

      Each turn, the prompt path first collects a typed session brief and then renders the final prompt from that brief plus explicit render policy. The collector is a SessionBriefCollector backed by a ContextSourceRegistry; the renderer is a PromptRenderer chosen by AI startup in internal/services/ai/app. The default renderer still uses BriefAssembler to sort prompt sections by priority and drop low-priority content when the token budget is tight. The core collector now adds a phase guide and context-access map keyed off the typed interaction state so the prompt always tells the agent what phase it is in, what it must know first, and which deeper resources exist before any OpenViking augmentation runs.

      Priority Tiers

      | Priority | Tier | Content | |———-|——|———| | 100 | Critical | Skills contract, interaction state, turn input, authority | | 200 | Important | Campaign metadata, current phase guide, context access map, active scene characters | | 300 | Contextual | All participants, story index or story.md, session recap, character list | | 400 | Supplemental | Full character profiles, reference excerpts, memory.md |

      Token Budgeting

Token estimation uses a byte heuristic (~4 chars per token). Required sections are never dropped. Non-required sections are dropped lowest-priority-first when the assembled brief exceeds the budget.

ContextSource Interface

The generic orchestration collector accepts ContextSource values:

type ContextSource interface {
    Collect(ctx context.Context, sess Session, input PromptInput) (BriefContribution, error)
}

Core sources (campaign metadata, characters, scenes, interaction state) are always present. Today the system-specific sources are Daggerheart-owned and live in internal/services/ai/orchestration/daggerheart/; the composition root registers those sources into the same collector registry. The important invariant is that prompt rendering consumes the typed SessionBrief; it no longer re-parses already rendered prompt text to recover bootstrap or interaction-state facts.

Extension Points

Current System-Specific Seam

The current production game-system seam has two explicit parts:

  1. Daggerheart-specific prompt sources in internal/services/ai/orchestration/daggerheart/
  2. Daggerheart-specific guidance/reference files under data/instructions/v1/daggerheart/ Those seams are real and production-backed today. A second game system would still require explicit architecture work around tool registration, reference corpus ownership, and composition-root wiring; contributors should not assume that dropping in a new {system} folder is enough.

    Modifying Agent Behavior

    Edit the markdown instruction files under data/instructions/v1/. Changes take effect on the next turn without recompilation when using FRACTURING_SPACE_AI_INSTRUCTIONS_ROOT, or on next deploy when using the embedded default instruction set.

    Relationship to Other Docs