DEV Community

DerekWang
DerekWang

Posted on

The system lives in your files, not your prompts

AI Harness Engineering · Essay One · derek wang (derekwang85)


Ask a senior engineer where "the system" lives and they'll point at the code, or the org chart. After shipping enough AI-governed projects, I'd point somewhere else: the system lives in the files that fence in what a model is allowed to generate. The longer I watch teams steer language models, the surer I am that the difference between a project that drifts and one that holds a line is decided here, in a file the model reads before it writes anything.

This is the first layer of the idea I call the constraint pyramid. I'll keep it grounded in the one shape I've actually shipped more than once.

Prompts are memory. Files are architecture.

The mistake I made first, and that most teams still make, is trying to govern an AI with better prompts. "Just tell it the constraints in the chat." A prompt is a memory, not an architecture. It sits in a context window, one refresh from being washed away, one regeneration from being quietly ignored. You can't verify that the model obeyed it, and the same prompt produces different results across models and contexts. Prompt engineering buys you a conversation, not a system.

A file is the opposite. The model's output is bounded by what it can read, and a file it is told to read before every generation is not a suggestion the model has to remember to honor — it's ground truth the model hits before it produces a single line. Write your boundaries once, into a README that gates the project, and you've turned a hope into a constraint.

That shift — from words-in-chat to rules-in-files — is the whole premise of this series.

Five layers, one skeleton

The pyramid is a name for the set of files, arranged as five layers, where each layer answers one question and translates the one above it:

Strategy      —— README / constitution  : what this is, its boundaries
   ↕
Architecture  —— ADR set                : where the limits are, what won't be revisited
   ↕
Contracts     —— spec + runbook         : what exactly must be delivered
   ↕
Gates         —— pre-submit checks      : what is not allowed to become code
   ↕
Implementation— constrained output      : the model's work, fenced in from above
Enter fullscreen mode Exit fullscreen mode

Read top to bottom, it moves from "why" to "how," each layer narrowing the space the layer below is allowed to work in. Read bottom to top, it's the audit trail: every line of generated code should be traceable up through a gate, a contract, an architecture decision, and finally a strategic intent. Constraint flows down; accountability flows up.

The layer names aren't the point — in different projects this same skeleton is called a README, a constitution, a skill set. What holds is the arrangement: fewer, heavier files at the top; more, freer output at the bottom.

Not all constraints weigh the same

The skeleton alone doesn't make the system work. What makes it executable is a second dimension I had to learn the hard way: constraint strength, in three tiers.

  • L1 — hard constraints, enforced by code and gates. A pre-submit script that fails a build over a naming violation isn't a request; it's a wall. Schema, shared DTOs, dependency files, the gate script itself all live here, and the model is not allowed to touch them.

  • L2 — architecture constraints, carried by accepted ADRs and file layout. They don't fail a build, but they define what "following the design" even means; changing one requires a new ADR, not a silent edit.

  • L3 — execution suggestions, the loose end. Runbook steps, skill definitions, checklist guidance — the model may improve on these, but it has to record what it changed.

The whole game is making sure the model knows which tier a rule sits in. Without that distinction, an AI treats every file as polite advice and rewrites whatever it likes — and then the constraint system exists only on paper. A rule placed too hard chokes the system on trivia; a rule placed too soft is decoration. The pyramid earns its keep precisely by letting you put each rule where it belongs.

What actually happened at 636 lines

This isn't a diagram I drew on a whiteboard. In a real project — the AI-generated operations system I refer to throughout this series — the strategy file started at two vague lines: "an issue-tracking system, Java backend, Vue frontend." No module boundaries, no naming rules. The model's output drifted weekly: controllers called TicketController in one file and TicketApi in another, business logic shoved into controllers in one module and into services in the next. After a few weeks each style looked correct in isolation, and unifying them stopped being a bug fix and became a rewrite — heavier than starting over, because now we had baggage.

So I stopped editing the prompt and started editing the file. Over the life of the project that README grew to 636 lines [ORIGINAL DATA] — module boundaries, path conventions, naming, layering, each rule pinned down one by one. When the model read it before every generation, the week-to-week style drift that had been a constant nearly vanished. The model didn't follow the rules because I asked nicely. It followed them because the rules were the file it was told to read first.

That's the whole difference between constraint and lecture. A lecture says "please write consistently." A constraint says "you can only write inside this boundary." The first one a model tunes out; the second one it can't miss.

Constraints go down. Deviations come back up.

One more piece, because people leave it out: the pyramid is not a one-way funnel. The model doesn't only obey constraints — its output should change them.

When generated code keeps violating a naming rule, that rule escalates from a soft suggestion to a gate check. When a gate keeps catching the same error, it's a sign the contract layer is missing a step, so you add the step. When a rule fights you no matter how it's phrased, that usually means the boundary itself is wrong — which becomes a new ADR, and sometimes a revision to the strategy document itself. Deviation flows up; the constraints get sharper for it. A healthy constraint system isn't rigid, it's alive — it has a return channel, a trace of what previous projects taught it, so it doesn't re-learn the same lesson in week four. I'll open that mechanism properly in a later essay.

Nothing defends a wall that's never checked

I can steelman the skeptic easily: files rot too. A README that says one thing while the code does another is worse than none, because it sells you the illusion of governance. I've watched teams paste a six-hundred-line spec, feel safe, and drift all the same.

The only honest defense is uncomfortable: the system has to be run, not written. A gate that never executes is a wish. An ADR nobody maps back to the code is a diary. The pyramid works only when its layers are wired to one another and fired in the pipeline. The moment it degrades into static documentation, it deserves exactly what it replaced.

The first thing to try today is the smallest possible version: find the place your model reads before every generation. If it's a chat, move it to a file — a file that says what the project is, its module boundaries, and its naming rules. Two lines is a start; six hundred is a system. Then sort every rule you currently carry in your head into one of the three tiers, and let the model see the difference.

In the next piece I'll show you the top layer — how to write the project's constitution before the code, so an AI is willing to live under it and, just as important, stops flattering you while it does.


Top comments (0)