Chapter 12: The Capstone (Building a Game)
Can Nanocode actually build something?
The “Zero Code Challenge”: build a classic Snake game using Python and Pygame. The rule—you are not allowed to write a single line of Python. You can only speak to the agent in English.
![]() |
Aside: This demo involves many API calls. If you hit rate limits (HTTP 429), the agent will retry automatically. For long sessions, consider using a local model via Ollama to avoid limits entirely. |
Step 1: Preparation
From your project root (the directory containing nanocode.py and .env), create a working directory for the game:
1 mkdir -p snake_game
2 cp nanocode.py snake_game/
3 cp .env snake_game/
4 cd snake_game
If you’re using the book’s code repository, copy from ch11 instead:
1 mkdir -p snake_game
2 cp resources/code/ch11/nanocode.py snake_game/
3 cp .env snake_game/
4 cd snake_game
Install Pygame:
1 pip install pygame
![]() |
Aside: On Windows, this should work out of the box. On macOS, you may need to install SDL libraries first: |
Step 2: The Architect (Plan Mode)
Start the agent. We begin in plan mode because we want a blueprint before we lay bricks.
1 python nanocode.py
The Prompt:
1 Build a classic Snake game using Pygame. Include a score counter and Game Over screen with a restart option. Put ALL code in ONE file: snake.py. Write the plan in PLAN.md.
The agent will use write_file to create PLAN.md. Read it. It should outline the Snake class, the Food class, and the game loop—all in a single file.
If it looks good, approve it.
Step 3: The Builder (Act Mode)
Switch to act mode:
1 /mode act
The Prompt:
1 Implement the plan in snake.py. All code in one file.
Watch the terminal:
1 → Writing snake.py
The agent is generating code based on the context it stored in PLAN.md.
Step 4: The Reality Check
Before running the game, bump the timeout. Open nanocode.py and change timeout=30 to timeout=300 in RunCommand.execute()—the default 30 seconds isn’t enough to actually play a game. (This is the one exception to the Zero Code Challenge.)
The Prompt:
1 Run the game with: python snake.py
The agent executes run_command. A window pops up. You play Snake.
If it crashes: LLMs are non-deterministic. Your agent might produce a bug on the first try. If the game crashes with an error like AttributeError: 'Snake' object has no attribute 'draw', don’t fix it yourself. Let the agent see the stderr.
The Prompt:
1 The game crashed. Read the error and fix it.
The agent will read the traceback, use read_file to find the bug, use edit_file to patch it, and run it again.
Step 5: The Pivot (Feature Creep)
The game works, but it’s ugly. The snake is just green squares. Let’s stress-test the agent’s ability to refactor.
The Prompt:
1 The game looks boring. Make the snake change color as it eats food, increase speed every 5 points, and search the web for 'cool retro game color palettes' to apply.
The agent should:
- Use
search_webto find color palettes - Use
read_fileto understand the current rendering logic - Use
edit_fileto inject the new features - Run the game to verify
What Goes Wrong
Your results will differ from mine—LLMs are non-deterministic. But here’s what typically happens, and what to watch for.
Common failures on the first run:
ModuleNotFoundError: No module named 'pygame'— the agent forgot you need to install it, or it ran the script in a different environment. Tell it to runpip install pygamefirst.AttributeErroron a method the agent defined but misspelled in the call site. The agent fixes these quickly once it sees the traceback.- Off-by-one errors in collision detection. The snake walks through walls or dies one pixel too early. These take 2-3 iterations of edit-run-fix.
The typical session arc:
In my tests, the agent usually gets a working (but ugly) game in 2-4 iterations. The first write produces something that crashes. The second or third fix gets it running. The feature creep step (color changes, speed ramps) adds another 3-5 iterations as the agent reads its own code, makes surgical edits, and verifies each change.
By the end, the conversation is 15-20 rounds deep. If you’re using Claude, watch the compaction trigger—around round 12-15 you’ll see “(Compacting conversation…)” as the token count approaches the 75% threshold. After compaction, the agent loses some detail about early rounds but keeps working. This is the system from Chapter 9 earning its keep.
Where the agent struggles:
Pygame’s coordinate system and event loop are tricky. The agent sometimes writes code that renders correctly but doesn’t handle keyboard input properly, or that draws the snake in the wrong order so the head appears behind the body. These are the kind of bugs a human spots instantly but the agent can’t see—it has no visual feedback, only stdout and stderr. If the game runs without errors but looks wrong, you’ll need to describe the visual bug: “The snake renders backwards—the head should be at the front.”
The point isn’t perfection on the first try. It’s that the agent converges—write, run, read the error, fix, repeat—using every tool we built across eleven chapters.
Wrapping Up
Plan, implement, crash, debug, fix, run again—that’s every chapter earning its keep.
So where does it go from here?
Epilogue
The whole thing is about 750 lines of Python. No framework. nanocode.py is yours. Do whatever you want with it:
- Git integration that auto-commits after green tests
- Screenshot-based debugging for frontend work (Claude can read images)
- Voice input via Whisper so you can talk instead of type
- MCP for connecting to external services your team already uses
Production agents like Claude Code, Cursor, and Copilot do more than this—streaming responses, parallel tool execution, tree-sitter parsing, sandboxed execution environments, multi-file context windows spanning thousands of files. The gap between 750 lines and 750,000 is real. But the architecture is the same: a brain, a loop, tools, memory, and a safety harness. Now you know what’s behind the curtain.
The models will keep getting better. The harness—the loop, the tools, the safety checks—that part is engineering. And that part isn’t going anywhere.
