Rule precedence — platform vs repo vs personal
A developer runs under three layers of rules at once. This page is the single answer to "which one wins?" — so a repo's CLAUDE.md, a personal preference, and the org standard never silently contradict each other.
The three layers
| Layer | Where it lives | Scope | Owns |
|---|---|---|---|
| 1. Platform (org) | the bewith plugin (agents/skills/commands/policies/hooks) + autonomy/defaults.yaml | every developer, every repo | the standards + the hard floors |
| 2. Repo | the repo's CLAUDE.md, git-hooks/config.env, .claude/ overrides at the repo root | one repo | repo-specific extensions + overrides |
| 3. Personal (per-machine) | ~/.bewith/config.json (role, language, notify, …) + ~/.claude/settings.json | one developer, one machine | personal preferences |
This maps onto Anthropic's CLAUDE.md hierarchy (enterprise/system → project → user): the plugin is the org/system layer (it provides the generic rules globally via name-shadowing), the repo CLAUDE.md is the project layer, and ~/.claude + ~/.bewith are the user layer.
The two-axis model
Precedence is not a single ordering. It depends on whether the rule is a tunable preference or a hard floor:
Axis A — tunable preferences: most-local wins
Personal > Repo > Platform-default. The platform ships a sensible default; the repo can override it for its context; the developer can override it for themselves.
Examples:
- Conversation language (personal) — a developer sets Hebrew; it overrides the English default. (Artifacts stay English regardless — that's a floor, see Axis B.)
- Role (personal) —
devvsproductfilters which capabilities surface. defaultMode: acceptEdits(personal/repo) — opt in to fewer prompts.- Stricter lint /
REQUIRE_CU_ID=true(repo) — a repo tightens a default viagit-hooks/config.env.
Axis B — hard floors: the platform is a floor nobody can lower
For governance and safety, the platform wins. A repo or a personal setting may make a floor stricter, never looser.
Examples of floors (cannot be disabled by any CLAUDE.md or personal setting):
- The mandatory policies —
auth-touch,payment-change,schema-migrationrequire a human + the owning expert agent. no-master-edit, dangerous-git/bash blocks, the session-guard collision block.- Pre-push lint/typecheck/tests, branch-name-check, file-size, the CI gate, branch protection.
- Secrets handling and the Definition of Done gates.
- Artifacts are always English (a repo or personal language preference changes conversation, not written artifacts).
The one test
Is this a preference or a floor? Preference → the most-local layer wins. Floor → the platform wins, and local layers can only tighten it.
Why floors can't be loosened locally
Because the floors are enforced by code, not prose. A repo CLAUDE.md that says "skip tests on this repo" cannot beat the pre-push test hook; a personal setting can't disable the auth-touch policy. The model reads CLAUDE.md (it can be talked around); the git hooks, PreToolUse blocks, CI, branch protection, and the policy engine run regardless of what any prose says. That is the point of the enforcement tiers — the deterministic layers are immune to a persuasive prompt or a well-meaning local override.
The one structured exception: autonomy. autonomy/defaults.yaml explicitly separates Hard Floor items (never overridable) from configurable ones. A developer's user-override.yaml may loosen a configurable item — and only a configurable item. The Hard Floor list is the canonical floor for autonomy decisions.
Worked resolutions
| Situation | Layer that wins | Why |
|---|---|---|
| Developer prefers Hebrew chat | Personal | preference (Axis A) |
Repo needs REQUIRE_CU_ID=true | Repo | tightens a default (Axis A — stricter is fine) |
Repo CLAUDE.md: "commit straight to master here" | Platform | floor (Axis B) — no-master-edit + branch protection ignore it |
| Personal setting tries to skip the auth policy | Platform | floor (Axis B) — the policy engine + agent-guard still fire |
| Repo wants a stricter file-size limit than the default | Repo | tightening a floor is allowed (Axis B) |
user-override.yaml loosens a configurable autonomy gate | Personal | allowed — it's configurable, not Hard Floor |
How a session resolves it (order of reading)
- The platform loads via the plugin (standards + floors).
- The repo
CLAUDE.md+git-hooks/config.envrefine it (the git hooks read the repo'sconfig.envfirst, then the platform default). - The personal
~/.bewith/config.json/~/.claude/settings.jsonapply the developer's preferences. - For every action, the deterministic floors (hooks / PreToolUse / CI / policy engine) run last and unconditionally — they are not subject to layers 2–3 except to be made stricter.
See also
consumption-model.md— how the platform federates into repos (name-shadowing, references-not-copies).enforcement-tiers.md— where each rule fires (Tier 0 opt-in → Tier 5 branch protection); why floors are code, not prose.autonomy-model.md— Hard Floor vs configurable vs never-ask; the canonical floor for autonomy.repo-migration.md— onboarding a repo, where the repo layer is authored.