riftbound-agent · MIT open source

MIT-licensed open source

Nobody has taught an AI to hold a trading card game’s response timing. We are trying.

Public research on card-game AI stops where the opponent starts acting on your turn. This project is building the bounded version of what comes after that — and it is open, so you can check every line of it.

Why this is hard, and why almost nobody has done it

Board games are perfect information. The position is on the table, so it can be searched. Card games break that on the first move: the deck is random and the opponent’s hand is hidden, so “the current position” is not one thing.

The second barrier is the one that decides which games get solved. It is whether the opponent can act on your turn. Hearthstone is where public research has got furthest, not only because the card pool is smaller, but because the opponent mostly cannot interrupt you — and because the shipped implementation is itself the one correct rules engine, so a researcher never has to reinterpret the rules to get an environment.

On the Magic side there is no such thing. The closest references are community-built: MTG’s Forge, a long-maintained unofficial rules engine, and Yu-Gi-Oh’s ygo-agent, which can train only because ygopro-core exists underneath it. Recent benchmarks on both games — MTG-Causal-RL and PTCG-Bench — show LLM agents can play a non-zero game, and neither shows a reliable one. Both put a bounded set of archetypes into a fixed observation space to compare methods: a research benchmark, not a world you can self-play inside.

Riftbound sits on the hard side. It has a chain, it passes priority and focus, it has reaction timing — the position changes in between the other player’s actions. Attempts exist: there is at least one open Riftbound simulator with tree-search bindings, and it takes chain resolution head-on rather than avoiding it.

What none of them carries is a conformance suite — a way to check, clause by clause, that the timing implemented is the timing the rules describe, and to say which parts are not implemented at all. Without that, “illegal” and “not modelled” are the same answer. For playing, that is fine; both mean you cannot do it. For anything that is going to learn from the environment or cite it as evidence, it is the difference between a result and a guess.

So the barrier was never that models are not clever enough. The barrier is that somebody has to turn the rules into a program first.

The bet: bounded, and allowed to say it does not know

You do not have to model every card. In practice a format leans on a fraction of what is printed, and the honest engineering translation of that is a bounded scope: implement the mechanics that are actually reached, and mark the rest as not modelled.

That only works under one condition. The system has to be allowed to answer unsupported — and that answer has to be a first-class result, not a swallowed failure. The moment abstention is treated as something to paper over, a bounded scope quietly becomes a system pretending to cover everything, which is worse than not building it.

So the division of labour is fixed: the program owns the mechanical layer and the model reasons inside what that leaves. Not the rules translated into a prompt so a model can read them — the rules executed, so there is a space it cannot argue its way out of.

Exactly where it is today

The goal above is stated at full size. This part is stated exactly, and the two are not the same thing. Every line here is checked by a conformance suite in the repository; if the suite changes, this page is wrong.

What made us build a kernel at all

3 / 46 Legend breakdowns that survived an audit against real play unchanged — run before the kernel existed.

The project started as a derived knowledge base: every entry written from card text and game mechanics rather than summarised from someone else’s guide, which makes entries cheap to regenerate and, on their own, unproven. So all 46 were checked against established play. Three needed no changes.

The most useful catch was not a Legend at all. A ban-list substitution routine swapped a card that hands a rune to every player unconditionally for one that only pays out to whoever holds the point — same domain, same currency, entirely legal, and it would have funded the opponent in a deck that concedes the early board on purpose. A player outside the project found it before any internal check did.

That audit is the reason the kernel exists. Derivation from card faces holds up. The moment the question becomes what a deck is actually trying to do, or what is mechanically legal right now, it stops holding — and the mechanical half of that cannot be derived, only executed.

The line we are aiming at

Go AI is worth its funding because it beats every human. A trading card game is not that shape, and a superhuman player would not be worth much even if someone built one. The line here is deliberately different and, in its own way, harder:

Not to beat people. To teach them correctly — to be able to say what a deck is doing, show what that claim rests on, and stop at the point where it genuinely does not know.

Learning to play turns out to be the easy half. The hard half is building, reading a format, and knowing what to swap when a card is banned — which is exactly where our own substitution routine failed, on a deck it had every legal reason to be confident about. That failure is the shape of the problem, not an embarrassment to be tidied away.

Whether this ever grows into a full rules engine or a learning system, we do not know. What it is accumulating in the meantime — structured state, executable conformance cases, an evidence trail — is the groundwork either of those would need.

What would actually help

This is too slow for one person, and the parts that are missing are the parts that need people who know either the game or the engineering. Nothing here needs permission to start — fork it, break it, or open an issue.

Break a derivation
The substitution bug was found by a player who knew a deck better than the routine did. That is still the highest-value contribution available, and it needs no code.
Write mechanics into the kernel
Typed operations and conformance cases, each tied to an official clause. This is the bottleneck: rule-ification is the whole barrier, and it parallelises.
Port the method to another game
Nothing in the approach is Riftbound-specific. A second game is the real test of whether any of this generalises.

What it is not

A rules engine, an AI agent, and a trained player model are three different things. This project began as the second and has since written a bounded piece of the first. It is not the third, and does not pretend to be: there is no complete state machine, no full card-effect engine, no self-play data and no trained policy.

It also does not play. All of it sits in the preparation phase — building, understanding, practising, reviewing. An authoritative rules engine, including an official digital client if one ever ships, would make this more useful rather than redundant: that engine serves play, this serves preparation.

Riot’s Digital Tools Policy is open to deck managers and educational tools, and explicit that it does not pre-approve automated rule execution or gameplay simulators. That boundary shaped the design before ambition did: every play suggestion waits on a human to confirm it. It is built for research and educational use, and using it during an event is against tournament rules.