DEV Community

Cover image for Rulebook Oracle — a TTRPG agent that answers only from its Sanity Knowledge Base
Karl Louise Rito
Karl Louise Rito

Posted on

Rulebook Oracle — a TTRPG agent that answers only from its Sanity Knowledge Base

Sanity Challenge Path One Submission

This is a submission for the Sanity Challenge, Path One: Ship an Agent That Queries Real Content

What I Built

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

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

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.

Demo

Try it live: https://rulebook-oracle.netlify.app — open the chat and try:

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

Code

GitHub: Karllouise-code/sanity-rulebook-oracle

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

How I Used Sanity

  1. Structured content: three document types — ruleSection, errataItem, faqItem. The errata schema captures changeType (clarify / override) and effectiveDate — that's what makes "who wins when sources conflict?" decidable by data, not by guesswork.
  2. Seed: a transactional, createOrReplace-based script upserts the 57 documents into the production dataset (idempotent).
  3. Sanity Context → Knowledge Base: the KB indexes the three document types and follows the ruleRef references, so errata and FAQs stay linked to the rule section they change. Sanity consolidated the 57 docs into 13 topical entries.
  4. Context MCP endpoint: the agent connects to the rulebook-oracle MCP endpoint (Knowledge Base mode) over HTTP with a Bearer org token. It discovers initial_context (the KB outline), knowledge_base_search (content-aware, ranked), and knowledge_base_read, 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:
  5. The agent loop (astro-app/src/lib/rules-agent.ts): picks the relevant entry paths via knowledge_base_search (falling back to an outline-score heuristic), reads them, and completes the answer only from those entries. changeType: 'override' 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.

Sanity Project Details

Top comments (0)