← all posts

The AI Doesn't Learn. The Prompt Evolves.

ai-assisted engineering — part 3 of 4

The machine doesn't remember. You remember for it. And that changes how you think about institutional knowledge.


My deployer agent generates production infrastructure for Hetzner Cloud servers. Docker Compose, Terraform configs, Caddy reverse proxies, deployment scripts. I built it over 3 days, 19 commits, 3,200 lines of code. By the time I stopped, the prompt had grown to 919 lines.

Deploys that failed on day 1 succeeded on day 3. The agent got measurably better. But the model didn't change. I was using the same Claude, the same API, the same temperature. What changed was what I learned from watching it fail against real servers, and then writing those lessons into the instructions.

The AI didn't learn anything. I learned, and I encoded it.

anatomy of a critical fix

The Docker platform mismatch is the one that cost me the most time.

I develop on Apple Silicon. Hetzner Cloud servers run AMD64. The AI generated Docker builds without specifying the target platform, because on my machine the default architecture matched the build machine. When I deployed, the containers wouldn't start. The logs showed exec format error, which is the kernel telling you the binary was compiled for the wrong CPU architecture.

The debugging took longer than it should have. The error message doesn't say "wrong platform." It says the executable format is wrong, which could mean a dozen things. I traced it to the architecture mismatch, confirmed with docker inspect, and added three lines to the prompt:

## DOCKER BUILD REQUIREMENTS (MANDATORY)
Hetzner Cloud servers run AMD64 architecture. ALL Docker build commands
MUST specify the platform explicitly. This is NON-NEGOTIABLE.

The agent never made this mistake again. Not because it understood CPU architectures. Because I told it, in capital letters, what to do. The fix was 3 lines. The debugging was an evening.

8 failures, 8 prompt sections

Every ## CRITICAL FIX section in the prompt maps to a real production failure I debugged. The prompt is a sedimentary record. You can read the geological history of things that went wrong.

Failure What happened Prompt fix
Server type casing Hetzner API rejects CX22, requires cx22 Exact strings specified
Docker platform mismatch ARM images on AMD64 server --platform flag mandatory
Bcrypt hash escaping $2b$12$... interpreted by bash Shell escaping rules
ALLOWED_HOSTS quoting Django config needed JSON array format Quoting convention specified
Terraform path resolution Relative paths broke in CI vs local Absolute path rules
Container naming collisions Second deploy silently killed the first Project-prefixed names
Health check ports Port not exposed to host, curl localhost:8000 fails docker exec instead of port exposure
Image cache staleness Docker pulled cached images, ran old code --pull always mandatory

"MUST" appears 50+ times in the prompt. "NON-NEGOTIABLE" appears multiple times. This isn't politeness. It's the accumulated weight of things that broke at 11 PM on a real server.

My agent has 919 lines of instructions. Every CRITICAL FIX section maps to a real server that crashed, a real container that wouldn't start. That's not prompt engineering. That's institutional knowledge in markdown.

the context file outperforms the prompt

The 919-line prompt is general-purpose. It encodes patterns across all projects: how to structure Docker Compose, how to configure Terraform, how to handle deployments. But my booking system needed different things than my infrastructure project.

So I wrote a project-specific context file. prompts/contexts/booking-system.md. 523 lines. 14 known issues with exact symptoms, causes, and fixes. Everything from PostgreSQL enum case sensitivity to Stripe webhook configuration to the auth context using is_superuser instead of a separate role.

The context file made the agent accurate for that specific project in ways the general prompt never could. 919 lines of general-purpose instructions tell the agent how to build infrastructure. 523 lines of project-specific pain tell it how to build this infrastructure without repeating these mistakes.

What I learned: the project-specific file carries more weight than the general prompt. I start with the context file now, not the prompt.

this isn't fine-tuning, and it isn't RAG

I could have fine-tuned a model. I could have built a RAG pipeline. I did neither. Fine-tuning changes the model weights. RAG retrieves from a corpus at query time. Both require infrastructure I didn't want to build.

What I'm doing is simpler. I debug a production failure, I write the fix into a markdown file, and the AI reads that file next time it runs. The model doesn't change. There's no retrieval step. The knowledge lives in plain text, version-controlled in git, readable by humans.

This is a third pattern: prompt evolution as institutional knowledge capture. No infrastructure beyond a text editor. Anyone can read the prompt and understand what the agent knows. But it scales linearly with the human's ability to debug and encode, which is also its ceiling.

Mitchell Hashimoto arrived at the same pattern independently. His Step 5, "harness engineering": "anytime an agent makes a mistake, engineer a solution so it never happens again." His Ghostty project's AGENTS.md is the same artifact as my 919-line prompt, built through the same loop. But he frames it as a defensive measure. I think it's bigger than that. It's a new form of institutional knowledge, one where the knowledge is executable by an AI agent on every run.

David Crawshaw compares agent harness work to "compiler optimizations during the megahertz explosion" — real, but eclipsed by model improvements. His claim is temporal: during rapid model improvement, prompt refinement is a rounding error.

My 8 critical fixes say otherwise. Same model, same API, dramatically different output depending on whether the prompt includes --platform linux/amd64 or not. The model doesn't know your server's CPU architecture. No amount of model improvement changes that. The harness carries the knowledge the model can't learn from training data.

the validate-retry loop

One structural decision mattered more than any individual prompt fix. The agent generates a bundle, a validation script checks it (JSON syntax, Docker Compose validity, Terraform structure, required file presence), and if validation fails, the errors are fed back to the agent with instructions to fix them. Up to 3 attempts.

agent generates bundle validation checks pass ship fail errors fed back ≤ 3 attempts

This converts a generative task into a convergent one. The agent doesn't need to be right on the first try. It needs to converge. The first time I watched it work, the agent generated a Docker Compose file with invalid YAML on attempt 1, got the validation error fed back, and produced a clean file on attempt 2. The loop catches the class of errors that prompt instructions can't prevent: the ones you haven't seen yet.

The validation catches surface errors. The 8 critical fixes in the prompt address the deeper failures that validation can't detect: architecture mismatches, shell escaping, path resolution, cache staleness. Together, they form two layers of defense: structural validation for known categories, and prompt encoding for specific production lessons.

the real bottleneck

If the human is the learning loop, then knowledge capture speed is the bottleneck for AI system quality, not model capability or context window size. How fast can I debug a production failure, identify the root cause, and encode the fix into the prompt?

prompt 919 lines, growing agent generates fails on real server human debugs encodes fix into prompt

My booking system's CLAUDE.md has a meta-instruction: "After ANY correction from the user: update tasks/lessons.md with the pattern." That instruction made the system self-reinforcing. Every correction became a permanent fix. But someone still had to make the correction, identify the pattern, and write it down. The human is always in the loop.

Heinrich (@arscontexta) has pushed this further than anyone. His CLAUDE.md is roughly 2,000 lines, continuously refined. His agent leaves "breadcrumbs" on topic pages, notes about what it learned while traversing a knowledge graph. Future sessions read those breadcrumbs and build on past navigation.

He's already past the single-file model, working toward composable networks of markdown files connected with wikilinks. The progression maps the trajectory: a CLAUDE.md, then a large CLAUDE.md, then a structured knowledge graph. The knowledge outgrows each container.

My 919-line prompt works. But it's approaching a limit. A single file can hold the knowledge of one agent operating in one domain. When the knowledge spans multiple projects, multiple tools, and months of accumulated debugging, a file isn't enough. You need a memory architecture.

Fine-tuning changes the model. RAG retrieves from a corpus. Prompt evolution encodes human judgment directly. It's the third pattern, and the only one where the human is the learning loop.


Prompt evolution captures what one agent learns from one domain. Memory files capture what the AI learned the hard way in one project. But knowledge that spans dozens of projects and hundreds of industry sources doesn't fit in a prompt or a memory file. It needs a memory architecture, and eight independent projects built one in twelve days. Part 4 maps the convergence.


Part 3 of a series on AI-assisted engineering. Part 1: "Your AI Productivity Metric Is a Lie" covers the fix-to-feature ratio. Part 2: "The Most Important File in Your Repository" covers the instruction file pattern. Part 4: "8 Tools in 12 Days" covers the memory layer.

Built in Porto. Data from real repos, real commits, real production servers.