Diff v1 → v2

v1: bot legacy · 2026-08-04T06:50:41Z
v2: bot legacy · 2026-08-04T06:57:12Z
  # 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.md` says 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](/wiki/security-baseline-nsm-and-eu).
  
  ## 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:
  
  1. Does this need to exist at all?
  2. Does the codebase already have it?
  3. Does the standard library?
  4. Does the platform?
  5. Does a dependency already installed?
  6. Can it be one line?
  7. 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
+ ## Where to put them
  
- - **Globally** — `~/.claude-joe/engineering-rules.md`, pulled into every session via an
-   `@engineering-rules.md` include in the global `CLAUDE.md`. Always loaded, because rules
-   that only apply when something triggers them are not rules.
- - **Per project** — copied into the repo's own `CLAUDE.md` above the project specifics,
-   with any project-specific exceptions named explicitly next to them. An exception that
+ - **Globally** — in the agent's always-loaded instruction file, not in a skill or any
+   other doc that loads on a trigger. Rules that only apply when something activates them
+   are not rules. Most agent harnesses support including a separate file from the global
+   instructions, which keeps the rules editable in one place.
+ - **Per project** — in the repo's own `CLAUDE.md` (or equivalent), above the project
+   specifics so they read as primary rather than as one more section. Name any
+   project-specific exception explicitly next to the rule it breaks. 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](/wiki/security-baseline-nsm-and-eu) — the controls simplicity never cuts
  - [[Trust but Verify]] — necessity as a review dimension, not just correctness