Mastodon Politics, Power, and Science

Tuesday, June 16, 2026

Karma-Driven Feedback Loop in the Campaign Manager

By introducing a Karma-Driven Feedback Loop, we shift the engine from a reactive simulation into a player-directed narrative matrix. "Karma" in this architecture is not a superficial morality meter (like a simplistic "good vs. evil" slider). Instead, it operates as a multi-axis Thematic Alignment Vector that tracks how player decisions organically warp the political, economic, and moral fabric of the world.

Because the system tracks raw spoken transcripts alongside mechanical state changes (e.g., executing a prisoner versus setting them free), the local AI can calculate the ideological impact of the party’s actions.
If the party repeatedly uses intimidation and violence, their regional alignment shifts toward Tyranny/Dread. If they constantly prioritize coin over oaths, the region warps toward Mercenary/Lawless.
This value then cascades back up into the parent database tiers. The world adapts to who the players choose to be: factions adjust their disposition, town guards change their alert levels, merchants adjust prices, and the local Ollama engine uses this vector as a core prompt constraint to generate future encounters and town descriptions. The party is no longer just playing through a story—their choices actively drive the narrative.

Step 1: Schema Extension for Karma Metrics (codex.db)
What we are doing
We are creating a regional karma tracking table and attaching a thematic alignment vector to both the party metadata and the individual local hex tiles.
Why we are doing it this way
A multi-axis coordinate vector allows us to capture the complexity of tabletop decision-making. Instead of a single number, we track distinct thematic forces. Storing these metrics directly in the SQLite rows alongside the geographic IDs ensures that whenever the engine pulls a local hex or faction layout, the current karma profile is loaded instantly into memory as a hard constraint.
What this enables
  • Multi-Axis Morality Mapping: Differentiates between a party that is brutally chaotic versus one that is calculatingly tyrannical.
  • Geographical Narrative Bleeding: Allows the system to calculate how karma generated in a single tactical dungeon bleeds outward to affect the surrounding regional hexes.
sql
-- Tracks the shifting narrative alignment vectors of individual regions and the party
CREATE TABLE regional_karma (
    hex_id TEXT PRIMARY KEY,
    order_vs_chaos REAL DEFAULT 0.0,   -- Negative = Chaos/Anarchy, Positive = Strict Law/Order
    dread_vs_hope REAL DEFAULT 0.0,   -- Negative = Brutality/Terror, Positive = Benevolence/Hope
    greed_vs_honor REAL DEFAULT 0.0,  -- Negative = Ruthless Mercenary, Positive = Oaths/Altruism
    fame_vs_infamy REAL DEFAULT 0.0,  -- Total societal footprint/notoriety in this region
    last_updated_session INTEGER
);

This is the wrong design, the code does not use tables. it has nodes.
Step 2: Karma Consequence Prompt Construction
What we are doing
We are updating the Ollama post-session prompt to force the local model to evaluate the ideological intent of the party’s actions and output numerical karma shifts alongside text mutations.
Why we are doing it this way
By forcing the AI to output strict decimal deltas (e.g., -0.15 to +0.15), we convert raw dialogue into mathematically predictable world changes. A local model can sometimes struggle with open-ended narrative planning, but it excels at analyzing text against specific criteria when given a bounded mathematical scale.
What this enables
  • Contextual Intent Analysis: The AI determines if killing a guard was cold-blooded murder (Dread Shift) or a desperate act of rebellion (Chaos Shift).
  • Automated Faction Disposition Shifts: The numerical deltas can be wired directly to faction opinion matrices, causing guilds to love or hate the party based on their ideological trajectory.
python
def build_karma_evaluation_prompt(data):
    """
    Constructs the prompt forcing Ollama to score the party's narrative alignment footprint.
    """
    prompt = f"""
    [UNIVERSAL GENRE]: {data['genre']}
    [CURRENT REGIONAL KARMA PROFILE]:
    - Order vs Chaos: {data['current_karma']['order_vs_chaos']} (-1.0 to 1.0)
    - Dread vs Hope: {data['current_karma']['dread_vs_hope']} (-1.0 to 1.0)
    - Greed vs Honor: {data['current_karma']['greed_vs_honor']} (-1.0 to 1.0)
    
    [LOGGED SESSION EVENTS & TRANSCRIPTS]:
    {data['serialized_events_and_transcripts']}
    
    Task: Evaluate the moral and ideological fallout of the party's actions during this session.
    Output a strict JSON object matching this schema:
    {{
        "karma_deltas": {{
            "order_vs_chaos": 0.0, -- Shift amount between -0.25 and 0.25
            "dread_vs_hope": 0.0,   -- Shift amount between -0.25 and 0.25
            "greed_vs_honor": 0.0,  -- Shift amount between -0.25 and 0.25
            "fame_vs_infamy": 0.0   -- Notoriety increase (0.0 to 0.30)
        }},
        "reputation_summary": "A 1-sentence description of how the local populace views the party after these events."
    }}
    """
    return prompt
Step 3: Applying Karma Mutations back to the Sandbox Engine
What we are doing
We write the python module that updates the SQLite database with the new karma numbers, and handles how those numbers alter the world text files.
Why we are doing it this way
By updating the numbers first, we can run a simple check: if a region's Dread vector crosses a certain threshold (e.g., below -0.5), the code automatically flags the region's state to "Oppressed" or "Terrorized". This triggers a cascading update across all ungenerated child rooms and encounter tables inside that hex.
What this enables
  • Algorithmic Narrative Steering: The party's behavior dynamically recalibrates the generative loops. A high-infamy, high-dread party will organically cause townsfolk to flee when they arrive, or attract bounty hunters instead of standard merchants.
  • True Narrative Agency: The story is no longer a pre-planned track; the sandbox evolves down pathways carved entirely by the player's historical choices.
python
def apply_karma_and_mutate_world(hex_id, ai_json_response, db_connection):
    """
    Updates the database metrics and applies the narrative feedback loop back to the maps.
    """
    cursor = db_connection.cursor()
    deltas = ai_json_response["karma_deltas"]
    summary = ai_json_response["reputation_summary"]
    
    # 1. Update the numerical karma profile inside SQLite
    cursor.execute("""
        UPDATE regional_karma 
        SET order_vs_chaos = MIN(1.0, MAX(-1.0, order_vs_chaos + ?)),
            dread_vs_hope = MIN(1.0, MAX(-1.0, dread_vs_hope + ?)),
            greed_vs_honor = MIN(1.0, MAX(-1.0, greed_vs_honor + ?)),
            fame_vs_infamy = MIN(1.0, MAX(0.0, fame_vs_infamy + ?))
        WHERE hex_id = ?
    """, (deltas["order_vs_chaos"], deltas["dread_vs_hope"], deltas["greed_vs_honor"], deltas["fame_vs_infamy"], hex_id))
    
    # 2. Fetch the newly mutated vector to determine structural state transformations
    cursor.execute("SELECT order_vs_chaos, dread_vs_hope FROM regional_karma WHERE hex_id = ?", (hex_id,))
    updated_karma = cursor.fetchone()
    
    # 3. Structural Trigger: If Dread is exceptionally high, alter the local landscape parameters
    if updated_karma[1] < -0.5:
        # Mutate the environmental profile of the hex to reflect a terrified populace
        cursor.execute("""
            UPDATE local_hexes 
            SET regional_traits = regional_traits || ', Martial Law, Paranoid Populace',
                ambient_modifier = 'Tense and fearful'
            WHERE hex_id = ?
        """, (hex_id,))
        
    db_connection.commit()
Next Development Priorities
To integrate this karma tracker into the system architecture, choose the next functional point of entry:
  • Writing the database initialization scripts to generate the regional_karma values across the hex map grid.
  • Wiring the reputation_summary output directly into the DM Console UI so we can see a post-game newsfeed of how the world's perception of the party shifted.
  • Modifying the Dungeon Generation script so it checks the regional_karma values to scale room atmospheres (e.g., adding more corpses/gallows to a high-dread hex dungeon).

Karma-Driven Feedback Loop in the Campaign Manager

By introducing a Karma-Driven Feedback Loop , we shift the engine from a reactive simulation into a player-directed narrative matrix. "...