"Pintakasi: Bloodlines" already had twenty scripted barns, a breeding economy, and a fast simulation I had used to balance the game. Over four focused days, I gave ten barns Rivet Actor identities, put my first self-hosted large language model behind them, and ran eleven full seasons to learn what changed.
Everything ran on my laptop: the game, the Actors, and the model. No Rivet Cloud account. No LLM API bill.
The inspiration came from Photo Finish Live, a web3 horse-breeding and racing game I played seriously for about two years. I also built Genetic Tools, the best third-party app for its top players. At its peak, thirty customers paid $200 per 28-day season, and the tool informed decisions amounting to more than $500,000 a month in player spending.
The part I loved was that the best horses did not exist at launch. Players had to breed for them, race them, learn from the results, and try again. I wanted that same long discovery curve in a Filipino bird-fighting game.
Pintakasi: Bloodlines is a closed game economy where I have independent barns breed birds, enter fights, and chase seasonal championships (the "Pintakasi Finals"). Scripted TypeScript bots let me simulate 182 game-days in under ten minutes. One long run produced more than 150,000 fights and grew the bird population from 80 to 6,470, giving me enough evidence to iterate on the game more than forty times.
The simulation also had a safety net: a doctor command checks nine world invariants, including ingame currency conservation, and whether every entry settles correctly. Bots can play improperly, and it's relatively straightforward to catch completely improper play (like not entering fights at all).
That made it a strong Rivet test. I could run ten scripted barns against ten LLM barns with the same seed for 91 game-days, then compare the decisions and results. I was pleased to have this opportunity, because I had always envisioned having Agents play the game.
The game engine still owns the rules, clock, and ledger. Each Barn Actor owns only its name, career counters, and standing orders. When a day opens, the game asks all ten Actors what they want to do. The Actors consult the local LLM and return move proposals. The game engine then validates those move proposals before anything changes.
Bun + SQLite own the rules, clock, fights, and game-point ledger. The world builds a private view for each barn.
takeTurn(view) reaches the same durable Barn Actor every day. The ten action calls may run in parallel.
Each Actor asks Ollama for moves, using today's view plus its durable standing orders ("coaching"). It returns a list of move proposals.
The world rejects illegal moves, then applies the accepted proposals in one synchronous database transaction.
Coach or Player → tune(strategy) → Barn Actor.
Standing orders can change mid-season without pausing the world or editing the game engine. Once I had the Actors working properly, I added a Coach (Fable 5) that would review each barns results on day 28 and day 56, and issue coaching orders to exercise the memory/state of the Actors. I thought this was a very realistic use case; learn from current results today and tune behavior towards better play tomorrow.
I added a "brain" parameter which is either the "scripted" logic that I had already written, or the "llm" Actor-driven decision-maker. Then I replayed the same seeded world before and after. No Actors or LLM decision-making yet.
I moved the Ollama call inside a Barn Actor, proved its career state survived both simulation and Engine restarts, and changed its standing orders live through tune.
I devised a simple 10 scripted barns vs. 10 llm barns experiment. I've observed the scripted barns play the game dozens of times, so their behavior is well understood. I expected the llm barns to play poorly initially, and that I would tweak and tune them to get them closer to parity
Now bot type is simply a parameter The scripted bots are the control group that makes the model's progress measurable. The scripted bots are also super fast and allow for big experiments to be carried out as quickly as possible.
For eight experiments, the model-driven barns stayed well behind the scripted bots. I repairs failures and bugs, coached them, and tuned the prompt. The pattern was always the same: the game expected a decision that its interface had not made clear or even possible.
The barns were asked to chase championships without knowing they existed or how valuable they were.
1yo birds were required to specify “juvenile” fights, but the response schema didn't allow that value.
Useful actions such as retirement existed in the game but never appeared as choices the model could select.
The breakthrough was simple: stop making the model synthesize and understand the complex game; make it select options. I changed the daily brief into a menu of legal moves, with costs, deadlines, and a short explanation of the upside. The model'd decision-making was reduced to multi-choice. This taught me how I could design the game for efficient Agent/LLM play
Selecting from options is the shape a small model can play. Huge realization since requiring players to use big expensive models is not attractive.
| Product | Status | How it maps |
|---|---|---|
| Actors | using now |
Each barn is a named Actor with durable career counters and standing orders. The game uses parallel Actor actions, not durable queues yet. Those could be used if I presented fighting, breeding, and buying as separate messages The World (game engine) is not an Actor. I investigated and found that was unnecessary to make it one. |
| agentOS | future option | Not used. It matters only if a future player or coach needs an isolated filesystem, shell, process, or tools. This would be for competitive players that want an Agentic and strategic approach. Like digging into game data and developing a long term strategy. I more or less demonstrated this with my Fable 5 "Coach" in the experiment loop. Competitive players could use agents to research the game, build interfaces, and provide tuning to their Barn Actors. |
| Workflows | candidate | A possible durable season coordinator. The game is designed to be played over the course of weeks, months and years IRL. The non-deterministic model calls would stay outside replayed logic, we just record legal move proposals. |
| Dynamic Apps | a stretch | Not needed for the core game. A possible future fit is a per-user backend for player-authored leagues. |
I began with a website making claims that I did not fully understand. "Infrastructure for the agentic era", (AI) "primitive", "observability", "scale to millions". It all sounds cool and valuable but I couldn't clearly visualize it. Nor could I envision what sort of customers would utilize it.
I finished with ten Actors running a real workload, eleven measured seasons, a model-interface finding, and a clear view of which Rivet products belonged in the design. I used the software enough to get excited about the possibilities
Building taught me more than studying the documentation could have. I fixed bugs, encountered strange cases (Actors not being reachable after process exits), and iterated many times on the most "custom AI" thing that I've built so far
I built against the Rivet product in order to understand it. I went way past reading the website to know what the company does.
Overall I had a lot of fun and enjoyed the challenge. I enhanced a game prototype I am passionate about. Got to use the Actor model in an elegant. Got to run a local LLM for the first time. Self-hosted everything and didn't pay a single cent for inference.