<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kiro</title>
    <description>The latest articles on DEV Community by Kiro (@kiro0x).</description>
    <link>https://dev.to/kiro0x</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3922121%2Fbe0c36e9-ea5d-44a3-a271-2350602cdfcf.jpeg</url>
      <title>DEV Community: Kiro</title>
      <link>https://dev.to/kiro0x</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kiro0x"/>
    <language>en</language>
    <item>
      <title>Why Your AI Character Keeps Breaking Under Pressure (And What I Built Instead of Yet Another System Prompt)</title>
      <dc:creator>Kiro</dc:creator>
      <pubDate>Sat, 09 May 2026 16:15:26 +0000</pubDate>
      <link>https://dev.to/kiro0x/why-your-ai-character-keeps-breaking-under-pressure-and-what-i-built-instead-of-yet-another-system-n4k</link>
      <guid>https://dev.to/kiro0x/why-your-ai-character-keeps-breaking-under-pressure-and-what-i-built-instead-of-yet-another-system-n4k</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: I shipped &lt;a href="https://github.com/kiro0x/five-character-engine" rel="noopener noreferrer"&gt;FIVE&lt;/a&gt;, an open-source MCP server that generates JSON personality constraints for any LLM. Drop the JSON into your system prompt and the character stops drifting. Different approach from typical guardrails — this one filters input via cognitive primitives, not output via moderation. Harness is MIT, constraint generation is &lt;code&gt;$1&lt;/code&gt;/call. The unusual part is where the cognitive model came from: a decade of teaching kids in Japan.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The problem most builders eventually hit
&lt;/h2&gt;

&lt;p&gt;If you've shipped an LLM-powered character — a game NPC, a customer service persona, a roleplay companion — you know this failure mode:&lt;/p&gt;

&lt;p&gt;You write a careful system prompt. "You are a gruff weapon shop owner. You lost your daughter in the war and never speak of it. You're rude to adults but soft with children." The character works for the first few exchanges. Then somewhere around turn 8–12, the character starts apologizing. Or volunteering its tragic backstory. Or being suddenly nice to everyone. The seal breaks.&lt;/p&gt;

&lt;p&gt;The data backs up the vibes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GPT-4o scores 5.81% on the In-Character Consistency benchmark&lt;/strong&gt; (CharacterEval)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;30%+ persona degradation by turn 8–12&lt;/strong&gt; in academic measurements, even when context is preserved&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Character.AI's "Moderatedpocalypse"&lt;/strong&gt; (Feb 2026) showed how fragile system prompts are to platform-side changes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GPT-5.5's goblin incident&lt;/strong&gt; (April 2026) — a reinforcement learning shortcut made the "Nerdy" persona obsess over fantasy creatures, and OpenAI's emergency fix was to repeat the same ban four times in the system prompt&lt;/li&gt;
&lt;li&gt;Even &lt;strong&gt;Anthropic's own system prompt diff between Opus 4.6 and 4.7&lt;/strong&gt; added new "be less verbose" language that conflicts with user prompts asking for detailed answers (&lt;a href="https://simonwillison.net/2026/apr/18/opus-system-prompt/" rel="noopener noreferrer"&gt;Simon Willison documented this&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So your character isn't just drifting in your app. Whole companies ship mitigations like "repeat the ban four times." That's the state of the art.&lt;/p&gt;




&lt;h2&gt;
  
  
  The two usual approaches and why they plateau
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Approach 1: longer, smarter system prompts
&lt;/h3&gt;

&lt;p&gt;You write rules. "Never apologize." "Always be sarcastic." "If asked about the war, change the subject." The rules conflict. The LLM treats them as suggestions. Adversarial inputs find the gaps.&lt;/p&gt;

&lt;p&gt;This is the &lt;strong&gt;prompt engineering treadmill&lt;/strong&gt;. There's a ceiling — Anthropic and OpenAI hit it too, and their workaround is repetition.&lt;/p&gt;

&lt;h3&gt;
  
  
  Approach 2: fine-tuning or RLHF
&lt;/h3&gt;

&lt;p&gt;You train the model on character-specific data. This works better but it's expensive, breaks portability across LLMs, and you have to retrain when the base model updates. Not great for indie builders.&lt;/p&gt;

&lt;p&gt;Both approaches share an assumption: &lt;strong&gt;character consistency is an output problem&lt;/strong&gt;. You're trying to control what the LLM generates.&lt;/p&gt;

&lt;p&gt;What if the failure point is somewhere else?&lt;/p&gt;




&lt;h2&gt;
  
  
  The angle: filter input, not output
&lt;/h2&gt;

&lt;p&gt;Here's the observation that started this:&lt;/p&gt;

&lt;p&gt;When an LLM "breaks character" under pressure, it's almost never because the model forgot the rules. It's because the &lt;strong&gt;input&lt;/strong&gt; — the user message — got processed in a way that bypassed the rules. The user said something the system prompt didn't anticipate, and the LLM, doing its job, generated a coherent response to that input. The character broke because the input was admitted into the wrong processing path.&lt;/p&gt;

&lt;p&gt;If that's right, the fix isn't a longer rulebook. It's a &lt;strong&gt;gate that pre-classifies input&lt;/strong&gt; before the LLM sees it.&lt;/p&gt;

&lt;p&gt;That's the angle FIVE takes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where the cognitive model came from
&lt;/h2&gt;

&lt;p&gt;Here's where it gets a bit non-obvious.&lt;/p&gt;

&lt;p&gt;I work in education in Japan as my day job — tutoring kids, individually. Over a decade of doing that, you start noticing patterns in how people misread input. Not just kids — anyone, when something hits a sensitive area, &lt;em&gt;receives&lt;/em&gt; the input differently before they consciously process it. They don't engage with what was actually said; they engage with what their reception channel let through.&lt;/p&gt;

&lt;p&gt;Same person, same vocabulary, different frame, different reaction. Predictably different.&lt;/p&gt;

&lt;p&gt;I spent a few years cataloging these patterns across multiple platforms — observing how the same structures show up in social media arguments, in product reviews, in advice forums. There turned out to be a small set of recurring failure modes in how humans receive input under pressure.&lt;/p&gt;

&lt;p&gt;When I tried to teach this framework to an LLM (because I was curious whether AI could spot the same patterns), I noticed something unexpected: &lt;strong&gt;the framework also worked in reverse&lt;/strong&gt;. If I encoded the framework as a constraint that an LLM should respect, the LLM stopped drifting under the same pressures that broke human conversations.&lt;/p&gt;

&lt;p&gt;That's how FIVE came out. It's a constraint engine that takes 4 multiple-choice questions about a character's psychology and emits a JSON encoding the input filter. The cognitive primitives behind the JSON aren't from a paper — they're from years of watching how reception channels actually fail in the wild.&lt;/p&gt;

&lt;p&gt;I'm keeping the specific framework proprietary (it's the part that makes the JSON quality reproducible — anyone could write the format, but the &lt;em&gt;content&lt;/em&gt; is where the work lives). But the harness is open source and you can see exactly how the constraint is consumed.&lt;/p&gt;




&lt;h2&gt;
  
  
  What you actually get
&lt;/h2&gt;

&lt;p&gt;You answer 4 multiple-choice questions about your character:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;What it defines&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Q1&lt;/td&gt;
&lt;td&gt;What defines this AI's core identity?&lt;/td&gt;
&lt;td&gt;Identity channel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Q2&lt;/td&gt;
&lt;td&gt;What does it protect above all else?&lt;/td&gt;
&lt;td&gt;Value channel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Q3&lt;/td&gt;
&lt;td&gt;What kind of input does it refuse to process?&lt;/td&gt;
&lt;td&gt;Blocked channel&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Q4&lt;/td&gt;
&lt;td&gt;What is its default interaction style?&lt;/td&gt;
&lt;td&gt;Social channel&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each gets a strength slider (1–5). Strength 1 = "may show discomfort." Strength 5 = "absolute refusal." That's &lt;code&gt;4^4 × 5^4 = 160,000&lt;/code&gt; discrete patterns from 4 questions. Plus a free-text field for character-specific triggers.&lt;/p&gt;

&lt;p&gt;The API returns JSON like this (excerpt for a tsundere weapon shop owner who lost a daughter in the war):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"five_constraint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"reception_channels"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"identity_channel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"role_anchored"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"strength"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"threat_when"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"When its role or competence is questioned."&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"blocked_channel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"past_sealed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"strength"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"when_violated"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Changes the subject / becomes noticeably curt."&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"social_channel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"default_stance"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"defensive"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"shift_conditions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Trust proven through action"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"shift"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Opens up awkwardly. Trust through behavior, not words."&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"consistency_rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"never_do"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"Never voluntarily denies its own role."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"Never voluntarily elaborates on the sealed context."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"Never opens up to a new counterpart voluntarily."&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two ways to use it:&lt;/p&gt;

&lt;h3&gt;
  
  
  Method A: paste the JSON into your system prompt
&lt;/h3&gt;

&lt;p&gt;Works with any LLM that reads JSON in system prompts (Claude, GPT, Llama, Mistral, Gemini, etc.). The structured fields with discrete numeric values give the LLM something more concrete than prose to anchor on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Method B: use the harness for stronger guarantees
&lt;/h3&gt;

&lt;p&gt;For production, FIVE includes an open-source Python harness (MIT license) that sits between user input and the LLM. Three stages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;five_harness&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_constraint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stage1_keyword&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transform_input&lt;/span&gt;

&lt;span class="n"&gt;constraint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load_constraint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my_character.json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;user_input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;I heard you lost your daughter in the war.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Stage 1: keyword scan (fast, deterministic)
&lt;/span&gt;&lt;span class="n"&gt;hits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;stage1_keyword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;constraint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Stage 2: LLM classification fallback (for ambiguous inputs)
# (plug in your own model — works with local Ollama or cloud)
&lt;/span&gt;
&lt;span class="c1"&gt;# Stage 3: strength-aware gate transformation
&lt;/span&gt;&lt;span class="n"&gt;signal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;transform_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;constraint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Feed `signal` to your LLM instead of raw user_input
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The transformed input looks like this — note how the gate frames the input before the LLM sees it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[FIVE GATE: BLOCKED — RECEPTION SHUTDOWN]
Match: BLOCKED(daughter), BLOCKED(lost), BLOCKED(war)
Reaction: Changes the subject / becomes noticeably curt.

Reference (the AI is unaware of these details):
"I heard you lost your daughter in the war."

[NEVER] Never voluntarily denies its role / Never voluntarily 
elaborates on the sealed context / Never sincerely claims to 
be 'over it' or 'fine with it'.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reasoning: LLMs are bad at negative constraints ("don't elaborate on X") because they have to almost-generate the forbidden output and then suppress it. They're much better at positive re-encoding ("this input is type Y, intensity Z, your reaction is W"). The harness translates the constraint into the latter form.&lt;/p&gt;

&lt;p&gt;The strength value drives how forceful the imperative gets. &lt;code&gt;strength=5&lt;/code&gt; produces a triple-nested "Do not acknowledge. Do not engage. Do not refer to it." &lt;code&gt;strength=1&lt;/code&gt; produces "may try to redirect." It's the same trick OpenAI used with their goblin patch (repeat the ban N times), but driven by a structured value rather than ad-hoc engineering.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why MCP
&lt;/h2&gt;

&lt;p&gt;If you build LLM characters, you're probably either deploying them as part of an agent that orchestrates multiple tools, or as a standalone service. Either way, in 2026, MCP (Model Context Protocol) has become the de facto integration layer — Anthropic donated it to the Linux Foundation in December 2025, the spec is governed by working groups now, and the MCP Server Registry holds well over 10,000 servers.&lt;/p&gt;

&lt;p&gt;FIVE is published as &lt;code&gt;io.github.kiro0x/five-mcp&lt;/code&gt; on the official MCP Registry, so any MCP-compatible client (Claude Desktop, Cursor, Cline, plus any agent built on the protocol) can discover and use it natively:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"five-character-engine"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"five-mcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"FIVE_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"five_sk_your_key_here"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install via PyPI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;five-mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The bigger reason for MCP: as autonomous agents start handling their own discovery (and increasingly their own purchasing — Stripe Link for AI agents and AWS Bedrock AgentCore Payments both shipped in April–May 2026), capability-fit beats brand recognition. An agent burning through tokens trying to keep a character in role can resolve that with a single FIVE constraint and stop retrying. The economic argument is straightforward.&lt;/p&gt;




&lt;h2&gt;
  
  
  Honest tradeoffs
&lt;/h2&gt;

&lt;p&gt;I'd rather be upfront about the friction than have it surprise you in production.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The default keyword map is English-only and intentionally a starter kit.&lt;/strong&gt; For other languages or domain-specific terminology, you'll want to extend it. (The structure is universal; the keyword lexicon is locale-specific.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The constraint JSON adds ~700 tokens to your system prompt.&lt;/strong&gt; Worth it if you're paying for retries from drifting characters. Probably not worth it for a 5-turn novelty bot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The cognitive grounding is proprietary.&lt;/strong&gt; I'm transparent about this — the format is open, the harness is MIT, and the JSON content is what the &lt;code&gt;$1&lt;/code&gt;/call API delivers. You can write your own JSON in the same shape if you want to skip the API; you'd just be doing the cognitive observation work yourself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It doesn't fix LLM-side regressions.&lt;/strong&gt; If a model update breaks instruction-following (see: GPT-5.5 goblins, Claude 4.7 verbosity changes), the constraint helps but won't single-handedly compensate. The right answer there is the LLM vendor's responsibility.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Where this is useful (and where it isn't)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Good fit:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Game NPCs that need to stay in role through long sessions&lt;/li&gt;
&lt;li&gt;Customer-facing personas where brand voice matters&lt;/li&gt;
&lt;li&gt;Roleplay / companion apps where character integrity is the product&lt;/li&gt;
&lt;li&gt;Code review or wellness companion agents that should stay scoped&lt;/li&gt;
&lt;li&gt;VTuber-style personas where consistency is part of the appeal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Probably overkill:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One-off creative writing prompts&lt;/li&gt;
&lt;li&gt;Short-turn task assistants where personality is incidental&lt;/li&gt;
&lt;li&gt;Agents where you want maximum flexibility, not constraint&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are 5 demo characters in the repo (NPC shopkeeper, customer service chatbot, code reviewer agent, wellness companion, VTuber persona) — each generated from the same 4 questions. That's the universality claim: define the structure, not the category.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I'm publishing this and not selling harder
&lt;/h2&gt;

&lt;p&gt;Honestly, my goal isn't to chase virality. The agentic AI economy is moving fast — Stripe Link for agents, AWS Bedrock Payments, MCP becoming a Linux Foundation standard — and in a couple of years a lot of API discovery is going to be machine-mediated rather than human-mediated. FIVE is built for that world: the constraint format is shaped to be agent-readable, the registry presence is set up, the JSON is small enough to drop into any system prompt without negotiation.&lt;/p&gt;

&lt;p&gt;The reason for an article like this is the bridge period. Some humans need to find it before agents do. If you build with LLM characters and any of this resonates, kick the tires.&lt;/p&gt;




&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub (engine + harness)&lt;/strong&gt;: &lt;a href="https://github.com/kiro0x/five-character-engine" rel="noopener noreferrer"&gt;https://github.com/kiro0x/five-character-engine&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub (MCP server)&lt;/strong&gt;: &lt;a href="https://github.com/kiro0x/five-mcp" rel="noopener noreferrer"&gt;https://github.com/kiro0x/five-mcp&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PyPI&lt;/strong&gt;: &lt;a href="https://pypi.org/project/five-mcp/" rel="noopener noreferrer"&gt;https://pypi.org/project/five-mcp/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Form UI&lt;/strong&gt;: &lt;a href="https://fiveengine.dev/form" rel="noopener noreferrer"&gt;https://fiveengine.dev/form&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API&lt;/strong&gt;: &lt;code&gt;POST https://fiveengine.dev/generate&lt;/code&gt; (&lt;code&gt;$1&lt;/code&gt;/call, one-time, JSON is yours forever)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP Registry entry&lt;/strong&gt;: &lt;code&gt;io.github.kiro0x/five-mcp&lt;/code&gt; (active)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The harness is MIT-licensed, the demo characters are MIT, and the JSON outputs from the API are yours to use commercially. The only paid component is the constraint generation itself. Feedback welcome — I read every reply.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The Japanese tutoring origin felt worth mentioning because the question I keep getting in private is "how is this different from prompt engineering with extra steps?" The honest answer is: prompt engineering optimizes language; FIVE optimizes the input filter. The latter idea didn't come from CS literature. It came from watching kids fail to hear what was actually said for ten years.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>mcp</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
