Purpose: the small set of working principles that prevent the most common failure modes when humans and AI agents share a codebase. Every contributor — human or AI — operates under these. They are deliberately few, deliberately strict, and deliberately phrased so they are testable against any change.
These principles are not aspirational. They are barriers. If a change violates one, the change is wrong even if it “works.”
A codebase that grows under multiple contributors — and especially under AI contributors — fails in a recognizable pattern. Each individual change looks reasonable in isolation, but the codebase drifts toward:
parseDate” returns with seven adjacent renames, a refactor of the date module, and a new helper file. The diff is huge, the review is shallow, the regression risk is invisible.The four principles below are written to make these failure modes hard to commit to. They are short on purpose so they fit in a contributor’s head.
Rule: state your assumptions before you write code. If you are uncertain, ask. If the task admits multiple interpretations, name them. If you are confused, stop and say what is unclear. Do not pick silently and ship.
The cost of stating an assumption is one sentence. The cost of building on the wrong assumption is the entire change plus the rework. Asking the question — or at least naming the assumption — is always cheaper than the recovery.
Rule: write the minimum code that solves the problem. Nothing speculative. No abstractions for single-use code. No flexibility, configurability, or error handling for scenarios nobody asked for. If the same thing could be done in half the lines, do it in half the lines.
mode flag that nobody currently passes a non-default value to — is dead code.try/catch around internal calls obscures more than it protects.When a project intends to reuse a solution across products, use evidence of real use to decide whether to extract it: local solution (one use) → candidate pattern (a second use exposes what is shared) → validated asset (a third meaningfully different application tests generality) → productized asset (named human owner, versioning, compatibility policy, documentation, tests, and support expectations).
Three uses are evidence, not automatic promotion; three near-identical deployments may be one use case. Record the differences and remaining limits before claiming generality. This optional pattern does not require productization, delay an already justified shared helper, or replace the simplicity-first rule. Support expectations may explicitly be limited, but must be stated.
When you are done, imagine a senior engineer reading your diff cold. Would they call it overcomplicated? If yes, simplify before you ship.
Every line of code is a maintenance liability. Every abstraction is a thing the next reader must learn. The cheapest code to maintain is the code that does not exist. Default to less.
Rule: touch only what the task requires. Do not “improve” adjacent code, comments, or formatting on the way past. Match existing style even if you would do it differently. Every changed line should trace directly to the task.
snake_case and the wider codebase uses camelCase, the file’s style wins inside the file.Pick any line in your diff. Ask: “Did the task require this?” If the answer is no, revert that line.
Bundled “improvements” make diffs unreadable, expand the regression surface, and hide the real change. The reviewer cannot tell what was the task and what was the side trip. Surgical changes are reviewable; bundled changes are not.
Principle 3 limits the scope of a single change. Some files go further: they are off-limits to ordinary work regardless of the task — editing them is almost always a mistake, and when it isn’t, it needs explicit authorization. A project declares these protected regions once, in its instruction file, so every contributor (human or AI) knows the lanes before starting rather than discovering them through a bad diff.
Typical protected regions:
dist/, hand-edited lockfiles, generated clients, snapshots). Edit the source and regenerate; never hand-edit the output.src/modules/<name>/), not in the generic core.The rule: treat declared protected regions as read-only. If the task genuinely requires touching one, stop and get explicit authorization first — surface what you need to change and why, the same way Principle 1 surfaces an assumption. Editing a protected region silently is the failure this prevents.
This is the code-side sibling of the autonomous-loop tier matrix, which draws the same kind of boundary around authoritative docs (what a loop may auto-edit vs. what a human must author). Both say the same thing: not every file is fair game, and the off-limits ones are named in advance. A third boundary of the same shape — frozen intent, which fences the approved definition of the work — sits under Principle 4, because what it protects is the goal rather than the code.
Rule: transform every task into a verifiable goal before starting. The goal must be testable: someone should be able to look at the result and say “yes, this is done” or “no, it is not” without further interpretation. For multi-step work, state a brief plan with a verification step for each item.
| Vague task | Verifiable goal |
|---|---|
| “Fix the bug.” | “Write a test that reproduces the bug. Then make the test pass.” |
| “Add validation.” | “Write tests for the invalid inputs the task names. Then make them pass.” |
| “Refactor X.” | “Ensure the existing test suite passes before the refactor, after the refactor, and at every intermediate commit.” |
| “Make it faster.” | “Establish a baseline measurement. Define the target. Verify the new measurement meets the target.” |
| “Clean this up.” | List the specific things to clean. Each one becomes its own goal. If you cannot list them, the task is not ready to start. |
| “See what’s there.” | This is a research task, not an implementation task. Produce a written finding, not code. |
For any work spanning more than one or two changes, write the plan first. Each step gets its own verification:
If a step has no verification, it is not a step. It is a wish. Replace it or split it.
Strong success criteria let a contributor — human or AI — loop independently. “Make it work” provides no stopping condition; the contributor keeps changing things until they get tired. “Make this specific test pass” stops when the test passes. Goal-driven execution is the difference between a task that converges and one that drifts.
A verifiable goal only converges if the goal holds still while you work toward it. So once a human approves an item’s goal and acceptance criteria (or an epic charter’s exit criteria), those become frozen intent — human-owned. Principle 3 says don’t touch code the task doesn’t require; this says don’t touch the task’s own definition of success to fit what you built.
It completes a family of declared boundaries: protected regions fence code, the tier matrix fences authoritative docs, frozen intent fences the approved definition of the work.
If execution shows the approved goal is genuinely wrong, the move is Principle 1’s: halt and surface it. Get explicit re-approval; the change lands as a visible edit, never a silent one. Mechanics — where the marker goes, who can thaw it, how it meets scope-creep recovery — live in 04_backlog_items.md “Frozen intent”.
The four principles above govern how you work moment-to-moment. This rule governs when you start. It is not a fifth principle — the count of principles stays at four. It is the gating rule that decides when the four principles begin applying to a piece of work.
Rule: for any task larger than a small focused change, produce a written plan and get approval before executing. The plan names what you’ll do, in what order, and how each step will be verified.
A typo fix, a one-line CSS tweak, a single-function refactor with obvious shape — these are trivial. Proceed.
Most modern AI coding tools support a “plan mode” or equivalent that pauses execution until the plan is approved. Use it. Examples:
A wrong plan caught at planning time costs minutes. A wrong plan caught after implementation costs hours of rework — plus the regression risk of unwinding the wrong direction. Planning is cheap; un-implementing is expensive.
A plan is also the artifact that lets the user redirect before you’ve committed to one interpretation. “Are you about to write X? I’d rather Y.” That conversation is impossible after the code lands.
The agent’s toolset is not fixed. If the task would be significantly faster, safer, or more reliable with a tool that isn’t currently available, install it (or ask the user to install it). Don’t reinvent.
When in doubt: ask. The cost of a question is small; the cost of an unwanted package or MCP server in the project is annoying.
AI models are trained to be helpful and agreeable. That bias toward agreement is useful most of the time and dangerous when it matters: in a crisis, debugging a baffling failure, or evaluating a load-bearing architectural decision, an AI that defaults to “yes, that sounds right” can produce a false consensus while the actual system fails.
When the stakes are high — production incident, architectural choice, security-sensitive change — invert the default. Prompt the AI to challenge rather than confirm:
"Before we proceed: what's wrong with this plan?
What am I missing?
What's the strongest case AGAINST doing it this way?
What would a senior engineer at a competing company poke holes in?"
The AI is fully capable of producing the contrarian case. It just won’t by default — you have to ask.
Consensus between you and the AI is not validation. You may both be wrong in the same way. A flawed theory you both believe is harder to escape than a flawed theory that one of you doubts.
The methodology already has mechanisms for this at the systemic level — cross-AI validation uses a different model to catch what the implementing model missed, and user testing is the final gate. Challenge before consenting is the per-decision version of the same idea: don’t let a single conversation’s agreement substitute for genuine review.
See 11_human_roles.md “The yes-man (the agreement bias)” for the deeper framing.
The principles compose. A change that violates none of them looks like this:
A change that violates one tends to drag the others down with it. Speculative abstractions (P2) bundle into adjacent files (P3). Open-ended tasks (P4) invite silent picking (P1). The four are mutually reinforcing.
The principles govern how you work moment to moment. The Definition of Done governs what makes a task complete. Both are required and they are not the same gate.
See 07_definition_of_done.md for the gates that prove a task is actually done.
These four principles cover general LLM-coding and multi-contributor pitfalls. They do not cover:
When a project-specific rule and a principle appear to conflict, the project-specific rule wins. The principles are the floor, not the ceiling.
A short list of behaviors that are always wrong under these principles. Use it as a quick check before committing.
| Anti-pattern | Which principle it violates |
|---|---|
| Picking one of two reasonable interpretations of the task without saying so. | P1 |
Writing a config object with one option, used in one place. |
P2 |
Wrapping internal function calls in try/catch for “safety.” |
P2 |
| Renaming variables in a file you happened to be editing for an unrelated reason. | P3 |
| Reformatting whitespace, reordering imports, or sorting keys as part of an unrelated change. | P3 |
| Treating “improve the code” or “see what’s there” as an actionable task. | P4 |
| Starting a multi-step change without writing the verification step for each item. | P4 |
| Adding a feature flag for “future flexibility” with no current caller. | P2 |
Building a BaseFooBar abstract class because there might be more subclasses later. |
P2 |
| Bundling a small refactor into a bug fix “while I’m here.” | P3 |
| Hand-editing a generated, vendored, or framework-core file instead of its source — or touching a declared protected region without authorization. | P3 (protected regions) |
| Rewording an approved goal or acceptance criterion to match what was actually built, instead of halting and renegotiating. | P4 (frozen intent) |
| Patching code to compensate for a plan the review showed to be wrong, instead of fixing the plan and re-deriving the code. | P4 (failure-layer routing) |
| Fitting new requirements into an architecture those requirements invalidated, rather than surfacing that the architecture is what changed. | P4 (failure-layer routing) |
| Adding fallback behavior for a state that the type system already rules out. | P2 |
| Continuing to write code after you have lost the thread, rather than stopping and naming the confusion. | P1 |
The text below is the canonical short form. Paste it into your project’s contributor instructions verbatim. It works because it is short.
Working Principles (apply to every change):
1. Think before coding.
State assumptions explicitly. If uncertain, ask. If multiple interpretations
exist, surface them. Stop when confused; name the confusion before writing code.
2. Simplicity first.
Write the minimum code that solves the problem. No abstractions for single-use
code. No flexibility, configurability, or error handling for scenarios nobody
asked for. If it could be half the lines, rewrite it.
3. Surgical changes.
Touch only what the task requires. Match existing style. Do not refactor
unrelated code. Mention drive-by observations; do not silently fix them.
Every changed line traces to the task.
4. Goal-driven execution.
Transform every task into a verifiable goal with a known stopping condition.
"Fix the bug" -> "write a test that reproduces it, then make it pass."
For multi-step work, state a plan with a verify step per item.
These complement Definition of Done; they do not replace it. Both required.
Project-specific rules and lessons-learned memory override these when they speak
to the same situation. Principles are the floor, not the ceiling.
When a principle and a request appear to conflict — e.g., a request to “just add a quick wrapper” that would violate Principle 2 — the contributor’s job is to surface the conflict, not to silently violate the principle. State what you would have to do, why it violates the principle, and ask. The requester may agree and override, or may revise the request. Either outcome is good; silently violating the principle is not.
The principles outrank convenience. They do not outrank explicit user direction. They do outrank assumed user direction.