use-cases

Solo TTRPG Automation, Revisited: What Changed and Why

Solo TTRPG Automation, Revisited: What Changed and Why
7 min read
Marko Krišković

TL;DR — I rebuilt my AI-powered solo D&D workflow from scratch using new ByteChef features. The Rules Adjudication loop is gone, replaced by a Rules Agent tool. Character sheets are isolated using Knowledge Base tags. OpenRouter replaces per-provider model connections. Data Tables replace janky Data Storage initialization. And streamChat means I no longer need a separate Chat Component to get responses into the conversation. The result is simpler, faster, and more extensible.

A few months ago I published a breakdown of how I automated solo D&D play using ByteChef's AI Agent. The core idea was agentic modularization: splitting game management across specialized agents so no single model gets overwhelmed, and characters can't metagame each other's knowledge.

The workflow worked. But it was also complicated in ways that didn't need to be. Since then, ByteChef has shipped a handful of features that let me redesign the whole thing to be cleaner, more maintainable, and more powerful. This post walks through what changed and why.


Retrospective thoughts on the Old Workflow

The original design had four sequential stages: character inclusion detection, intent generation, a rules adjudication loop, and narrative generation. The rules loop was the most complex part. A dedicated Intent Questions agent would generate clarifying questions, pass them to a Rules Lawyer agent backed by a vector-embedded rulebook, and loop until no questions remained. Results were stored in Neo4j. Character narratives were collected into Data Storage and then assembled by a Chat Component at the end.

It worked, but it had real pain points:

  • The rules loop added latency and complexity even on simple turns where no adjudication was needed
  • Data Storage had to be initialized in a separate workflow — unintuitive and easy to break
  • Neo4j required external setup and maintenance
  • Every model needed its own provider connection. Switching models meant reconfiguring components
  • Combining all responses into Chat Component step felt like plumbing that shouldn't need to exist

The new workflow addresses all of these.


What Changed

AI Agents as Tools

The biggest structural change is that the Rules Lawyer is now a tool inside the Character Intent Agent, not a separate workflow stage.

Character Intent Agent structure in ByteChef, showing Rules Agent as a tool

ByteChef now supports nesting any number of AI Agents as tools inside another agent. The Intent Agent calls the Rules Agent only when it actually needs a ruling. This has two compounding benefits:

  • First, it eliminates unnecessary latency. On a simple turn where no mechanical question arises, the Rules Agent is never invoked.
  • Second, it dramatically simplifies the workflow graph. The old loop: generates questions, answers questions, checks for remaining questions, repeats until no longer out of questions. It all collapses into a single tool call when needed.

This pattern is also extensible in ways the loop wasn't. I could add a Combat Agent that only handles combat math, a Lore Agent backed by a campaign wiki, or a Social Agent that tracks NPC relationships. Each would be available as a tool, invoked only when relevant, keeping the main agent's context lean. The more specialized your agents, the less context each one carries on every execution. This means fewer mistakes and lower token costs.

OpenRouter as the Provider

Previously, each model provider needed its own connection and component. Switching a character from Claude to Gemini meant reconfiguring components. Trying a new model meant setting up a new provider entirely.

The new workflow uses OpenRouter throughout, which ByteChef now supports natively. OpenRouter is a single connection that routes to hundreds of models across dozens of providers. The Character Dialogue agent uses Gemini 2.5 Flash Lite. The Joint Response agent uses GLM-4-32b. Swapping either is a one-field change.

More interestingly, the model can be defined per character in the Data Table. If you want your Wizard played by Claude and your Rogue played by Mistral, you can store that in the character record and the workflow picks it up dynamically. Any AI roleplayer knows that different models have different tendencies! Some are more cautious, some more dramatic. That variance can actually make characters' actions more distinct.

Knowledge Base Tagging

In the original workflow, keeping character knowledge isolated required careful engineering around which data each agent received. It worked, but it relied on prompt discipline.

The new workflow uses ByteChef's Knowledge Base tagging to enforce isolation at the retrieval layer. Each character's sheet is uploaded as a document and tagged with that character's ID. The Intent Agent's RAG is configured to only retrieve documents matching the current character's tag. The agent literally cannot see another character's sheet!

This makes the no-metagaming guarantee structural rather than prompt-based. Characters make far fewer mistakes playing their role because there's no chance of cross-contamination.

Data Tables

The old workflow used Data Storage to track mutable game state like HP and spell slots. The problem was that Data Storage had to be initialized in a separate workflow before the session started. That was not a very practical thing and it feels unintuitive to how ByteChef should work. You could use inputs instead, but those can't be updated.

Data Tables replace this entirely. A Data Table is ByteChef's built-in structured store, a simple spreadsheet you can read and write from any workflow. I put each character's name, current HP, and MP (chakra points, in my campaign) as rows. After the Intent Agent resolves a turn, an updateRecord step writes the new values back.

A showing of what Data Table looks like

This is cleaner in two ways. A Data Table is a place designed for data initialization. The table exists and persists without any setup workflow. And the update history is kept automatically, so you can see exactly how a character's HP changed across the session.

The Data Table could also be used more creatively: tracking remaining arrows, bardic inspiration uses, concentration spells, food rations, etc. Anything that changes during a session and needs to be remembered.

Alternatively, updateRecord could be a tool inside the Intent Agent itself, so the character only updates stats when the action actually warrants it, rather than every turn unconditionally.

Chat Response

In the old workflow, each character's narrative response was stored in Data Storage, then a final Chat Component collected them all and assembled a single string to return to the conversation. It was plumbing.

The new workflow eliminates this in two steps.

The entire workflow which now fits in a single picture

The Character Dialogue Agent uses Chat Memory, which means its responses are stored in the conversation history automatically. The Joint Response Agent: reads that history, weaves the individual character narratives into a single cohesive scene, and returns it.

Crucially, the Joint Response Agent uses the streamChat action rather than the regular chat action. This streams the response directly into the chat interface without needing a separate component to pass it through. The tradeoff is that streamChat doesn't return output you can pipe into another component — but for a final narrative response, that's fine.


What's Next?

This sub-project isn't finished. A few ideas I'm still working through:

Per-character memory vs. shared memory. Right now characters share conversation memory through the Joint Response Agent. What I actually want is each character maintaining their own memory of events, plus a shared party memory for things everyone witnessed. A speak, whisper, and think tool model could handle this. speak writes to shared memory, whisper to its and another character's memory, think to the character's private memory only.

Voice. ElevenLabs is integrated in ByteChef, and each character could have a distinct voice profile. The workflow could generate audio for each character's dialogue. The gap right now is that ByteChef doesn't support playing audio natively in the chat interface. However, the workaround idea is embedding the chat on an external page that retrieves and plays the generated audio. The same page could display generated images for scenes or character portraits.

More specialized agent tools. A dedicated Combat Agent for mechanical resolution. A Lore Agent for world knowledge. A Social Agent for NPC relationship tracking. Each would be a tool the Intent Agent calls only when relevant, keeping the main execution path fast.

The workflow is already usable as-is. But the ceiling for how far this can go is a lot higher than where it sits today.


The original workflow breakdown is here if you want to compare the two architectures side by side. If you build something with this pattern, especially if you take it in a different direction, I'd love to hear about it!


Subscribe to the ByteChef Newsletter

Get the latest guides on complex automation, AI agents, and visual workflow best practices delivered to your inbox.