The oracle is the engine | Wanderhold Blog

The oracle is the engine

When I started building Wanderhold I assumed the oracle was going to be the simple part. You roll a number, you read a result, and you write the scene. The dice tell you what happens, AI as a tool writes how it happens, and you play it out. On paper that seemed like the least of my problems, like the piece I could knock out in an afternoon.

It turned out to be the second hardest thing in the whole engine to get right, and it is also the exact piece where most AI-assisted solo play quietly falls apart.

What a flat oracle produces

My first implementation was about as simple as it sounds. I built a weighted d100 table, rolled against it, took the result category, and handed that straight to the model with a prompt asking for a scene. Roll, get a bucket, write it up. But the number of inputs and outputs matter - location, pacing, weather, conflict, etc.

The scenes it produced were arbitrary. Not random in the good way, the way a surprising complication is random, but arbitrary in the way that means the scene had no relationship to anything else going on in the campaign. An event would fire, and then the model would dress it up with whatever atmosphere it decided fit in the moment. The next session a different, equally unrelated event would fire, and it would get dressed up too. The world was not reacting to my character so much as it was generating a sequence of incidents that happened around me.

The individual scenes were not even bad. Read in isolation the prose was perfectly fine, sometimes genuinely good. The trouble was that nothing accumulated. What the model wrote in Act Two Scene 1 did not build on what it wrote in Act One, because the oracle feeding it had no memory of session one to build on. The campaign had a history, and the oracle simply did not know that history existed.

Three sessions of this and I could start to get my hands around the problem. I was playing in a world that did not respond to me. Things were happening around my character rather than because of anything he had done, and that gap is the difference between an actual game with a campaign that pulls you back in and one that no one would bother playing.

What the oracle actually needs to do

The mistake underneath all of this was that I had been treating the oracle as an elaborate random number generator, and and ultimately it needs to have more of a plan and be more responsive.

A random number generator gives you unpredictability, and that is genuinely useful, but it is not the thing that makes solo play work. What an oracle needs to give you is a world that responds to your character's situation in a way that feels grounded and earned. You can get unpredictability out of a coin flip. You cannot get a coherent world response out of a coin flip, no matter how many times you flip it, because the coin does not know anything.

For the response to matter it has to actually know some things. It has to know what kind of mission this is, what the character is trying to accomplish, and what is still unresolved from earlier in the campaign. A flat table knows none of that, and so it cannot do anything except hand back a result for a generic prompt, and leave the rest to improvisation.

So the real architecture question was never "what should the tables contain." It was how to give the oracle enough context to produce a grounded response, without turning the start of every session into a data-entry exercise where the player has to feed the engine all that context by hand.

The staged pipeline

What I landed on runs in stages, and the important part is that each stage is constrained by the ones before it. Nothing rolls against a generic table. Every roll happens inside a space that the previous rolls have already narrowed down.

Mission type rolls first, but it does not roll against some universal list of mission types. It is scoped to the world the player is in, so it draws from that world's mission matrix instead of a generic list. A mission frames many things, but its just one piece of the story.

The objective rolls next, inside whatever mission type came up. It is scoped again, so the objective gets drawn from the set that makes sense for the mission and the character's current situation, rather than from everything the world could theoretically throw at you. Not every objective is available to every character in every circumstance, and that constraint is doing some real work.

Then a story archetype gets selected, and this is the piece that determines the structure of the session. The archetype is like a blueprint, and it decides which beats the mission will hit, what kind of pressure it builds toward, and the shape of the complication curve as things escalate. Two sessions with the same mission and objective type, but different archetypes, will come out structurally different. One could be a slow tightening story and the other a sharp and surprising narrative reversal, even though they started from the same roll.

Below that, each individual scene beat has its own look-up. The complication for a scene rolls against the tone that is currently active rather than against a flat danger table. A thematic axis is chosen that will run underneath the full session's prose and give it something to be about.

Only once all of that is assembled does the prose layer get involved at all. By the time the model is asked to write anything, it is handed a mission with a specific shape, an objective that fits the character, a scene structure, an active tone, and a theme, among other things. The writing is the last step, not the first, and that ordering is most of the point. The AI is generating specific narrative - it's like I've given it Lego instructions and access to any piece it wants to use, and it puts it all together.

The same rolls, two different sessions

Here is the part that made it click for me, and it is easiest to see with a worked example.

Take two players in the same world, roll the same mission type, and imagine they roll identically at every stage of the pipeline. Same numbers, top to bottom. The oracle hands them the same scaffold: mission type, objective, story archetype, and beats all identical. On the structural level the two missions are twins, and that is by design, since the oracle is scoped to the world and the roll rather than to the person playing.

Now make one of them a fresh recruit on her first assignment and the other a veteran ten missions deep, carrying a trail of unresolved threads, a rival who keeps turning up, and a few past choices that went badly. The scaffold is still identical, but the scenes that get written are not close. The writing model is handed a lot more than the roll. It gets the character's own sheet (their traits, values, and background) and the campaign's accumulated state: the threads still open from earlier missions, the people already met, the decisions already made. The veteran hits the same beat as the recruit, and it reads like a different story, because the model is writing that beat into a specific history instead of a blank one.

None of that divergence is the model improvising differently between the two runs, and the distinction matters more than it looks. The structure is fixed by the oracle and the personal texture is fixed by state the engine has been holding onto the whole time, both of which I can design, test, and rely on, rather than something I am hoping the model lands consistently on its own.

Why this matters across a whole campaign

Chat-based AI play does not have an oracle layer at all. The model is improvising the world's response to your character at every step, and inside a single session that is usually fine. A model stays coherent within its context window, and one session generally fits inside one context window, so the improvisation holds together for as long as the conversation lasts.

The trouble shows up across a campaign. The model's improvisation in session eight has no real structural relationship to its improvisation in session two, so the world slowly stops making sense. Groups that were established as cautious start acting reckless, the consequences of earlier decisions quietly stop mattering, and the whole thing loses the thread that was supposed to be holding it together. It is the same context-collapse problem that makes solo campaigns fail, just relocated into the AI's memory instead of yours.

The oracle, and it's tight connection to a saved player framework, is what keeps that from happening. It is not the piece that makes the campaign unpredictable, but the piece that keeps the world's response to the player coherent as the campaign gets longer. The randomness still happens (and it needs to!) but it happens inside a space the oracle has already constrained. That way the results stack up into something continuous instead of drifting apart.

The weak oracle problem

A flat oracle gives the prose model almost nothing real to work with, and a good model will compensate for that the only way it can, improvise more. The more it improvises to fill the gap though, the further it wanders from whatever logic the campaign had already established.

A strong oracle gives the model something specific instead: a mission with a real shape, an objective that fits this character at this moment, and a scene structure built to create a particular kind of pressure. The model's job then is to take that specificity and render it in vivid prose, which happens to be the thing these models are genuinely excellent at.

So the difference between a campaign you remember months later and one you closed the tab on halfway through is usually not the AI's prose quality at all. It is whether the oracle underneath was handing the AI something real to write about in the first place.


I mentioned in an earlier post that I would eventually write up the full oracle architecture, and this is the start of that. There is quite a bit more going on under the hood, including the specific weighting on each stage, exactly how the thematic axis gets selected, and how the complication system escalates, and I will get into that in a follow-up with some interactive diagrams I have been putting together.

The short version is that the oracle ended up being the engine rather than a feature bolted onto it, and most of the rest of the system is built to run well inside the structure it provides. If you want to see it working in an actual campaign instead of a blog post, you can start a free one at playwanderhold.com/create.

No spam. No selling your address. Unsubscribe any time. 5900 Balcones Drive, Ste 4000, Austin TX 78731.

Ready to try it? Start your first campaign for free.

Free to start. No credit card.