Building a Local-First Agent Framework in Rust (Part 0): Preface

Share
Building a Local-First Agent Framework in Rust (Part 0): Preface

Table of Contents

Preface: Why I Am Building This

A few months ago, in April 2026, I wrote about reviving the avatar system from Yogurting, the game I worked on more than twenty years ago, and a project I still believe helped define me. The revival project started with old proprietary binary files, no source code, and a lot of vaguely remembered details about how our engine worked in 2005. With Claude Code and a handful of local agents, I spent about ten weekends building importers, exporters, visual debuggers, and Godot tools until the old characters could stand, move, swap clothing, and live again inside a modern engine. It was a fun weekend detour from my ordinary daily work, but it did not end there. That project changed how I think about coding agents.

This post is also available on Medium. If you’re a paid Medium member and happen to read it there, it helps fund my next cup of coffee. Much appreciated ☕️😄

Before then, I mostly understood coding agents as faster programming partners. Useful, often impressive, but sometimes strange. After the Yogurting work, the shape became more specific. The agent was fast at generating code, but code generation speed was rarely the deciding factor. The difficult parts came when the system needed better context: what the broken mesh looked like in Godot, how the skeleton was supposed to bend, why a sword embedded in an NPC's spine was technically consistent but visually wrong.

The work kept returning to the same loop. The agent made a change. I ran the exporter again, opened Godot, inspected the result, described what was wrong, and asked the agent for the next correction. Sometimes the instruction was mechanical: swap quaternion order, reverse face winding, negate this axis. Sometimes it was judgment: this seam is better but still too visible, this attachment is now technically fixed but no longer looks intentional. The agent could move quickly once I gave it direction, but much of that direction had to come from outside the agent.

That outside part started to bother me, but not in the simple sense of "the agent could not see." Claude can see images if I paste them into the conversation. The problem was that the feedback loop depended on me doing that translation every time. Copy the screenshot. Explain what changed. Point out the part that still looked wrong. Run the exporter again. Open Godot again. Paste another image. Some of that could be improved by writing Godot-side tools that hand screenshots, scene trees, logs, and asset metadata to a cloud assistant. That would help, and even a local model would need the same tools eventually.

So the real question was not just visibility. It was the shape of the workflow.

To make things worse, I do not think game development has a settled AI-assisted process yet. For ordinary backend software, there are enough examples, conventions, tests, and reference architectures that a coding assistant can be useful even when the tool underneath changes. Designing harnesses for agents is one of the obvious topics right now, and it is relatively easy to imagine them for domains with stable workflows. Game development is less settled. We may be able to generate some simple or typical games with a few "clicks" these days. However, a commercial-level game, where the creator's intention and taste are woven through the work, is a different story. The work mixes code, assets, editor state, visuals, timing, taste, and iteration. A useful flow today might depend on a particular model behavior or product feature, and the same flow can become invalid when the tool changes next month.

That uncertainty matters because finding the workflow will require a lot of trial and error. I want to be able to try strange things. Let the agent inspect a scene. Let it propose a board layout. Let it run a script, fail, inspect the log, and try again. Let it make ten bad attempts at an asset pipeline before one good pattern appears. If every experiment carries the background fear of unexpected token consumption, I will naturally become more conservative. That is a bad fit for this stage. The point is to be audacious enough to discover the workflow, not to optimize each prompt as if the path is already known.

There is also a more personal reason, and it may be the most honest one. I still want to be in the process. I do not want a black box that occasionally produces a result I like. I want to understand the loop, the tools, the memory, the failures, and the places where the model is guessing. Claude Code, Codex, and other tools are useful, but they hide a lot by design, and they change quickly. That is fine when the task is inside a stable software practice. It is harder when the practice itself is what I am trying to discover.

That is where the local constraint starts to make sense. I want to make a game using a local agent and local LLM models not because local models are already better, but because they make the experiment bounded and inspectable. No cloud model as the hidden brain. No remote tool that only works when an API key and a billing account are available. No hesitation before running another trial. A local agent should read the project, inspect the state, use tools, remember what happened, ask before doing risky things, and help build a playable game. The first version does not need to be magical. It just needs to be honest: a small framework where I can understand every moving part.

That is where abcb begins.

At first, this sounds like a strange detour. If the goal is to make a game, why start by writing an agent framework in Rust? Why not use Claude Code, Codex, or one of the open-source frameworks already available such as OpenCode? I still think those are the right tools for many jobs. But for this project, I wanted to see and make the mechanism directly. I wanted to build a small agent loop from scratch, not because every tool should be handmade, but because the design space is still unclear and I want to understand the full process while I am exploring it.

Local models add another reason to build the framework myself. They have capability gaps that commercial frontier models often hide. They return prose when I asked for JSON. They wrap structured output in markdown fences, or fail to wrap it consistently. They misunderstand tool schemas. They are slower, smaller, and more fragile. Those flaws are not only obstacles. They are useful pressure. If the loop only works when the model is excellent, then it is not much of a loop. A local-first framework has to check, verify, recover, and adapt instead of assuming the model will behave.

Rust became part of the experiment for the same reason.

I have wanted to learn Rust for a while, but I do not think it is desirable to learn a programming language only through LeetCode-style problems. They teach syntax, and they are useful for learning the grammar, but they do not force many real decisions. An agent framework does. It has state that lives across turns. It has errors that matter. It has a boundary between pure logic and I/O. It has traits, dynamic dispatch, async HTTP, file storage, logs, approval policies, and later, maybe, a daemon talking to an editor. It is small enough to hold in one head, but real enough that the design decisions have consequences.

That combination is the point of this series. I am not only building an agent framework, and I am not only learning Rust. I am using the framework to make Rust's decisions visible. When a session owns its messages instead of borrowing them, that is a Rust lesson and an agent-framework lesson at the same time.

The Yogurting project keeps this grounded. It reminded me how much game development depends on human eyes. Code can be correct and still feel wrong. A model can parse a file and still place a sword in the spine. An animation can be mathematically valid and visually broken. If I want an agent that helps make games, I need to build toward that reality from the beginning. The agent has to live near the project, near the files, near the tools, near the evidence. Eventually it should live near the editor.

For now, I am starting with a command-line tool. Before the agent can work inside Godot, it has to be able to talk to a model, call a tool, remember what happened, and ask before doing something dangerous. That is enough for a first artifact. It is also enough to learn a lot of Rust.

My bigger hope is still the game. A game built with a local agent, local models, and a framework I understand because I built it. This is not the shortest route to that goal, but it feels like the route that will teach me the most.

So this is where I am starting: not with the game yet, but with the loop. If that sounds like a useful detour, you're welcome to join me.

To Chapter 1: Introduction: Building the Loop