Hello Curious Coders,
Before we talk about building the next layer of an application with Claude, it helps to name a problem you can feel before you can see it.
You’re three or four hours into a session. The early replies were sharp. Claude understood your architecture, named your modules correctly, followed the conventions you set up. Then, somewhere around the next big chunk of work, things drift. A function you defined in module A gets re-invented in module B. A decision you wrote down stops being honored. The model is not getting worse. It’s just running out of room.
This is the same conveyor belt from a few posts back, and now we have to manage it.
The Conveyor Belt, Mid-Session
The context window is a conveyor belt of words. As the conversation moves forward, new tokens climb on at one end and older ones slide off the other. The model can only act on what is still on the belt. Everything that fell off is gone.
“As we use more and more context, some of the bits of our conversation are going to fall off the end of the conveyor belt. And when that happens, you get behavior that we call hallucinating.”
– Bruce Tate
That reframes hallucination. It is not a model defect. It is a context problem that looks like a model problem. The model is filling in plausible answers because the anchors are no longer there.
🎯 Join Groxio's Newsletter
Weekly lessons on Elixir, system design, and AI-assisted development — plus stories from our training and mentoring sessions.
We respect your privacy. No spam, unsubscribe anytime.
Three Moves and a Habit
When the belt fills up, you have three options: let it ride, compact, or clear. The choice is a judgment call about how much of the current conversation is still worth carrying.
You let it ride when the conversation is healthy and the task is small.
You reach for /compact when the chat holds useful decisions buried under too much noise. Compaction keeps the shape of the work without every token that produced it.
/clear is for when the existing context is more liability than asset, especially before a large task or after the conversation has accumulated false starts you don’t want the model to keep reinterpreting.
The important detail is what happens after /clear. You don’t just start asking for code again. You prime the new context. In the Word Games project, Bruce clears the conversation, then asks Claude to read the architecture document and identify the next phase from the established workflow: research, plan, implement, and QA. That gives the model the durable shape of the project before any new work begins.
A clean belt is only useful if the first thing you put back on it is the truth.
Where Does Game State Live?
Here is the question that quietly decides your architecture: where does the state of an in-progress game actually live?
The wrong answer is “in a GenServer, because Elixir.” A GenServer per game looks elegant for about ten minutes. Then you realize the game state also has to be in the LiveView so the user can see it. Now you have two copies, drifting against each other every time a process restarts or a socket reconnects.
The right answer for this application is the LiveView itself. The LiveView already holds the assigns for the user’s screen. The game state is a value the LiveView constructs, reduces with each guess, and converts into a render. No second copy, no sync.
“We want one single source of truth at every layer of the application.”
– Bruce Tate
That sentence does more architectural work than it looks like. The database is the source of truth for what was saved. The LiveView is the source of truth for what is in progress. The functional core owns the rules of the game itself. Each layer owns exactly one thing.
Two Kinds of Context
Once state is settled, the Phoenix context layer divides cleanly in two.
The database-backed context is the boring kind, and that’s a feature. Listing dictionaries, fetching a daily puzzle, recording a finished session: plain Ecto wrapped behind a function-level API. Claude builds it well because the pattern is everywhere in its training data.
The game-backed context is where uncertainty enters the system. A user types a guess. The context validates it against the right dictionary, hands it to the functional core, and surfaces the new render. Validation does not belong in the core, because pure functions should not load dictionaries. It belongs in the context, where the impure world meets the pure one.
That is what makes this layer interesting. The context becomes the boundary. It speaks the vocabulary of the core and exposes that vocabulary to the LiveView, which never reaches past it.
One Discipline, Two Surfaces
The conveyor belt and the layered architecture are the same problem seen from two angles. The conversation needs you to manage what is visible: compact, clear, prime, and keep decisions in documents the model can re-read. The application needs you to give each layer one job and one source of truth. Both rules say the same thing. Confusion accumulates unless you resolve it deliberately.
Once you see this, agentic development becomes less mysterious. Instead of hoping the model remembers and the architecture stays clean, you are building a system that can be resumed.
In the next module, we bring in tooling that gives Claude more visibility into the live system: Tidewave, IEX awareness, runtime introspection. The discipline stays the same. The information available gets sharper.
See you in the next chapter.
🤖 Manage Context With Structured Oversight
This comes from Bruce's AI Agents course — the anti-vibe-coding curriculum. Learn when to compact, when to clear, and how the Ask → Plan → Agent framework keeps long AI sessions from drifting without losing architecture decisions. Available via monthly subscription — try it for one month.
— Paulo & Bruce