Engineering Rules
Engineering Rules
When to use it: always. These are the default rules for writing code on any
project — not a checklist to run at review time. Reach for the page when you need
the reasoning behind one of them, when a rule seems to conflict with a project
convention, or when onboarding a new repo or agent. Where a project's own
CLAUDE.mdsays something more specific, the project wins.
Seven rules. They govern how code gets written, not just how it gets reviewed.
- Do not preserve backward compatibility. Remove obsolete paths instead of adding
compatibility layers, fallbacks, or migrations. - Choose the simplest implementation that fully meets the current requirements.
Avoid speculative abstractions, configuration, and indirection. - Grow the system in layers. Start from the smallest version that works end to end,
and add each new capability on top of a product that already works. Never trade a
working product for unfinished complexity. - Keep components modular and concerns clearly separated.
- Prefer established, well-maintained libraries when they reduce overall complexity
or improve reliability. Do not reimplement common functionality without a clear reason. - Lean on the dependencies already in the project before writing your own
implementation or adding packages. Do not assume a library lacks a capability without
checking its documentation and types. - Make architectural decisions for the long term. Do not accept a stopgap that only
works for now and is meant to be replaced later.
Reading them correctly
Each of these has a misreading that does real damage. The rules are short on purpose;
the corrections are the part that stops them being harmful.
"Migrations" in rule 1 means compatibility shims — dual-write paths, version
branches, adapters kept alive for old callers. It does not mean database schema
migrations. In any project with a migration tool, a schema change without one is a bug.
This distinction is worth writing into the project's own rules file, because the literal
reading is catastrophic and an agent has no way to guess which was meant.
Rules 2 and 7 are not in conflict. Simplest-that-works is about how much you build
now. Long-term architecture is about which direction you build in. You can satisfy both
by building a small thing pointed the right way. An implementation shortcut with a named
ceiling and an upgrade trigger is fine; a stopgap architecture chosen because the right
one felt like work is not.
Rule 1 does not license breaking someone else's running system. Deleting a path only
this codebase calls is cleanup. Deleting a published API, wire format, or on-disk format
that external callers depend on is a breaking change — that needs a decision from the
owner, not a unilateral delete. The rule is about refusing to accumulate compatibility
cruft, not about ignoring consumers who exist.
Rule 2 never applies to safety. Input validation at trust boundaries, authorization,
error handling that prevents data loss, and audit logging are not speculative — they are
the requirement. Cut the abstraction, never the control. See
Security Baseline: NSM Grunnprinsipper & EU Regulation.
The failure mode they prevent
Eagerness, not laziness. Asked for a config loader, an agent returns a plugin system.
Asked for one endpoint, it returns a service layer, a repository interface, and a utils/
package. Everything runs, the tests pass, every line is individually defensible — and the
feature is three times the size it needed to be.
That cost compounds. Every unnecessary abstraction is something a human must read, something
the next agent must hold in context, and something that can break.
Before writing any new construct, stop at the first rung that answers the need:
- Does this need to exist at all?
- Does the codebase already have it?
- Does the standard library?
- Does the platform?
- Does a dependency already installed?
- Can it be one line?
- Only then: write the minimum that works.
Most over-building happens because rung 7 gets reached first. Full version in
The Restraint Principle: YAGNI for Agents.
Where they live
- Globally —
~/.claude-joe/engineering-rules.md, pulled into every session via an
@engineering-rules.mdinclude in the globalCLAUDE.md. Always loaded, because rules
that only apply when something triggers them are not rules. - Per project — copied into the repo's own
CLAUDE.mdabove the project specifics,
with any project-specific exceptions named explicitly next to them. An exception that
isn't written down gets rediscovered as a bug.
See also
- The Restraint Principle: YAGNI for Agents — the decision ladder in full
- Clean Architecture — the modularity and separation-of-concerns rule, worked out
- Security Baseline: NSM Grunnprinsipper & EU Regulation — the controls simplicity never cuts
- Trust but Verify — necessity as a review dimension, not just correctness