<?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: Karl Louise Rito</title>
    <description>The latest articles on DEV Community by Karl Louise Rito (@kalowies_).</description>
    <link>https://dev.to/kalowies_</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F655372%2F10a53e3c-a3f9-439d-b304-edeb9cc196fa.png</url>
      <title>DEV Community: Karl Louise Rito</title>
      <link>https://dev.to/kalowies_</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kalowies_"/>
    <language>en</language>
    <item>
      <title>Rulebook Oracle — a TTRPG agent that answers only from its Sanity Knowledge Base</title>
      <dc:creator>Karl Louise Rito</dc:creator>
      <pubDate>Fri, 02 Oct 2026 08:01:07 +0000</pubDate>
      <link>https://dev.to/kalowies_/rulebook-oracle-a-ttrpg-agent-that-answers-only-from-its-sanity-knowledge-base-2cmg</link>
      <guid>https://dev.to/kalowies_/rulebook-oracle-a-ttrpg-agent-that-answers-only-from-its-sanity-knowledge-base-2cmg</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/sanity-2026-09-16"&gt;Sanity Challenge, Path One: Ship an Agent That Queries Real Content&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Rulebook Oracle&lt;/strong&gt; — a chat agent that answers tabletop-TTRPG rules questions &lt;strong&gt;only&lt;/strong&gt; from a Sanity Context Knowledge Base, exposed over a Context MCP endpoint, with a minimal Astro chat UI running on the Vercel AI SDK.&lt;/p&gt;

&lt;p&gt;It's a "no-flipping-the-rulebook" companion for a homebrew d6 fantasy RPG ("Steeldusk"). I wrote and seeded the rulebook into Sanity: &lt;strong&gt;37 rule sections, 10 errata, 10 FAQs&lt;/strong&gt;. The interesting part is what happens when content contradicts itself: when newer errata &lt;strong&gt;overrides&lt;/strong&gt; the core rulebook, the agent surfaces &lt;em&gt;both&lt;/em&gt; claims side by side, cites every source, and the UI stamps the answer with an &lt;strong&gt;Override&lt;/strong&gt; badge. You always see what is actually in effect, and why.&lt;/p&gt;

&lt;p&gt;None of that works by keyword search alone — the agent reasons across related entries (rule + errata + FAQ that reference each other) and only answers from what it retrieved. Ask it "Can I attack twice if I wield two short swords?" and it explains that the 2025-03-01 errata replaced the original two-attack rule with advantage + the Ambidextrous talent, citing both the rule and the errata.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Try it live: &lt;strong&gt;&lt;a href="https://rulebook-oracle.netlify.app" rel="noopener noreferrer"&gt;https://rulebook-oracle.netlify.app&lt;/a&gt;&lt;/strong&gt; — open the chat and try:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Can I attack twice if I wield two short swords?" → an &lt;strong&gt;Override&lt;/strong&gt; answer citing the errata&lt;/li&gt;
&lt;li&gt;"What happens when my Health hits 0?" → Wounds &amp;amp; Dying, with the death-saves override&lt;/li&gt;
&lt;li&gt;"Does advantage from high ground stack with advantage from a spell?" → a rule + FAQ synergy (advantage never stacks)&lt;/li&gt;
&lt;li&gt;"Is a natural 6 always a hit?" → no — a natural 6 counts as two successes, not an automatic hit&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;GitHub: &lt;a href="https://github.com/Karllouise-code/sanity-rulebook-oracle" rel="noopener noreferrer"&gt;Karllouise-code/sanity-rulebook-oracle&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Monorepo layout: &lt;code&gt;sanity/&lt;/code&gt; (schemas + idempotent seed runner) and &lt;code&gt;astro-app/&lt;/code&gt; (Astro SSR chat + &lt;code&gt;@ai-sdk/mcp&lt;/code&gt; agent loop, deployed to Netlify). The README walks the whole chain: Sanity → Context → MCP → app.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Used Sanity
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Structured content&lt;/strong&gt;: three document types — &lt;code&gt;ruleSection&lt;/code&gt;, &lt;code&gt;errataItem&lt;/code&gt;, &lt;code&gt;faqItem&lt;/code&gt;. The errata schema captures &lt;code&gt;changeType&lt;/code&gt; (&lt;code&gt;clarify&lt;/code&gt; / &lt;code&gt;override&lt;/code&gt;) and &lt;code&gt;effectiveDate&lt;/code&gt; — that's what makes "who wins when sources conflict?" decidable by data, not by guesswork.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Seed&lt;/strong&gt;: a transactional, &lt;code&gt;createOrReplace&lt;/code&gt;-based script upserts the 57 documents into the &lt;code&gt;production&lt;/code&gt; dataset (idempotent).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sanity Context → Knowledge Base&lt;/strong&gt;: the KB indexes the three document types and follows the &lt;code&gt;ruleRef&lt;/code&gt; references, so errata and FAQs stay linked to the rule section they change. Sanity consolidated the 57 docs into 13 topical entries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context MCP endpoint&lt;/strong&gt;: the agent connects to the &lt;code&gt;rulebook-oracle&lt;/code&gt; MCP endpoint (Knowledge Base mode) over HTTP with a Bearer org token. It discovers &lt;code&gt;initial_context&lt;/code&gt; (the KB outline), &lt;code&gt;knowledge_base_search&lt;/code&gt; (content-aware, ranked), and &lt;code&gt;knowledge_base_read&lt;/code&gt;, so it can search, pick relevant entries, and read them — no raw GROQ from the app.
How I Used Sanity — point 5, search-first rather than outline scoring:&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The agent loop&lt;/strong&gt; (&lt;code&gt;astro-app/src/lib/rules-agent.ts&lt;/code&gt;): picks the relevant entry paths via &lt;code&gt;knowledge_base_search&lt;/code&gt; (falling back to an outline-score heuristic), reads them, and completes the answer &lt;em&gt;only&lt;/em&gt; from those entries. &lt;code&gt;changeType: 'override'&lt;/code&gt; becomes the red Override badge. An optional Gemini/OpenAI key summarizes the retrieved entries into natural prose with the citations preserved; otherwise answers are composed deterministically.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Sanity Project Details
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Project ID&lt;/strong&gt;: &lt;code&gt;g2fvri91&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dataset&lt;/strong&gt;: &lt;code&gt;production&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge Base&lt;/strong&gt;: Rulebook Oracle KB (&lt;code&gt;kblX52Exu3S8&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context MCP endpoint&lt;/strong&gt;: &lt;code&gt;rulebook-oracle&lt;/code&gt; (org &lt;code&gt;oeiiciaw8&lt;/code&gt;, Knowledge Base mode)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dashboard&lt;/strong&gt;: &lt;a href="https://www.sanity.io/manage/project/g2fvri91" rel="noopener noreferrer"&gt;https://www.sanity.io/manage/project/g2fvri91&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>sanitychallenge</category>
      <category>sanity</category>
      <category>ai</category>
    </item>
    <item>
      <title>Side Hustle Internship</title>
      <dc:creator>Karl Louise Rito</dc:creator>
      <pubDate>Mon, 05 Jul 2021 17:41:33 +0000</pubDate>
      <link>https://dev.to/kalowies_/side-hustle-internship-162b</link>
      <guid>https://dev.to/kalowies_/side-hustle-internship-162b</guid>
      <description>&lt;p&gt;&lt;a href="https://karllouiserito.hashnode.dev/here-at-side-hustle-internship" rel="noopener noreferrer"&gt;https://karllouiserito.hashnode.dev/here-at-side-hustle-internship&lt;/a&gt;&lt;/p&gt;

</description>
      <category>internship</category>
      <category>html</category>
      <category>css</category>
      <category>learning</category>
    </item>
    <item>
      <title>kobebryant-tribute</title>
      <dc:creator>Karl Louise Rito</dc:creator>
      <pubDate>Thu, 24 Jun 2021 17:55:25 +0000</pubDate>
      <link>https://dev.to/kalowies_/kobebryant-tribute-5dk4</link>
      <guid>https://dev.to/kalowies_/kobebryant-tribute-5dk4</guid>
      <description>&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/karllouiserito/embed/oNZKYBx?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>codepen</category>
    </item>
  </channel>
</rss>
