ADR-0003: Multi-Surface AI Conventions — CLAUDE.md AND .github/copilot-instructions.md (and Optional Siblings)¶
Status¶
Accepted
Context¶
A modern engineering surface is touched by multiple AI assistants — Claude (chat, Code, Desktop), GitHub Copilot (IDE, Workspace, Pull Request reviews), Cursor, Aider, Windsurf, and others. Each reads its own canonical configuration file and emits suggestions, completions, or full artifacts under that configuration's behavioral floor.
Three plausible postures were available:
- Single-surface deployment — ship only
CLAUDE.md; let every other AI assistant freelance against unstated conventions. - Single-surface in the other direction — ship only
.github/copilot-instructions.md; rely on per-session Claude conversations to inject conventions. - Multi-surface deployment with a coherence contract — ship both mandatory surfaces (
CLAUDE.md+.github/copilot-instructions.md), make optional sibling surfaces opt-in, and enforce mutual coherence on shared claims.
Single-surface deployment in either direction produces the same pathology under different names: silent drift in machine-generated code. When Copilot has no in-repo memory, it accepts the developer's IDE context and freelances against whatever conventions it infers — which may contradict CLAUDE.md without anyone noticing until the divergence surfaces in a PR review or, worse, in production. When CLAUDE.md is absent and only copilot-instructions.md ships, Claude inherits no in-repo memory and rebuilds context from each session's conversational opening — losing the durable behavioral floor the project relies on.
The cost of a missing surface is silent drift; silent drift is the worst kind of defect because it accumulates invisibly. Every machine-generated artifact compounds the divergence; by the time a human reviewer spots the contradiction, the codebase carries weeks of inconsistent conventions.
The coherence contract also addresses a derivative concern: with multiple surfaces, contradictions across surfaces become possible. A repo that ships CLAUDE.md saying "X" and copilot-instructions.md saying "not-X" is worse than a repo that ships only one, because the contributor cannot tell which surface to honor. A coherence enforcement is the mechanical answer.
Decision¶
Ship CLAUDE.md AND .github/copilot-instructions.md as mandatory components of the published ecosystem. Both surfaces MUST be present, both MUST carry the same shared sections (Plans Discipline, AskUserQuestion-equivalent behavior, Authorship Header, Naming, Anti-Patterns, Modal Hierarchy), and both MUST be mutually coherent on those shared sections per Spec §4.7.
Optional sibling surfaces — docs/architecture/agents.md, .cursorrules, .aider.conf.yml, .windsurfrules — are operator-opt-in via AskUserQuestion. For this engagement the operator opted-in to all four (Phase 04B's multi-surface-opt-in.yml); each opted-in surface inherits the coherence contract.
The reconciliation rule is claude-md-wins: when two surfaces are detected as contradicting on a shared claim, CLAUDE.md is the canonical voice and the contradicting surface is rewritten to mirror CLAUDE.md semantics in surface-appropriate framing. A surface-specific override is permitted only with an explicit, in-file <!-- coherence-override: <claim-id> --> marker that points at an ADR explaining the deliberate divergence.
Mechanical enforcement layers:
copilot-instructions-presencevalidator atsrc/apothem/conformity/copilot-instructions-presence-grep.py— asserts.github/copilot-instructions.mdexists, parses, contains every canonical section enumerated in Spec §2.8.2, and begins with the canonical authorship banner.multi-surface-coherencevalidator atsrc/apothem/conformity/multi-surface-coherence-grep.py— parses each surface's canonical sections; asserts shared sections are mutually consistent under a normalized comparator (case-insensitive, whitespace-tolerant, allow lexical paraphrase but require semantic equivalence on the fixture-defined claim list attests/fixtures/multi-surface-claims.yaml).license-author-consistencyvalidator atsrc/apothem/conformity/license-author-consistency-grep.py— asserts the LICENSE's copyright line and the canonical banner's "Copyright (c)" line name the same author.- Pre-commit hooks mirror the validators locally so contradictions are caught before any commit lands.
- Pull-request template checkbox — contributor-facing assertion that no contradiction was introduced between
CLAUDE.mdand.github/copilot-instructions.md. docs/ai-conventions.md— canonical, normative explainer of the discipline; the surfaces in scope, the coherence contract, the reconciliation rule, the surface lifecycle.
Consequences¶
- Plurality-by-deployment-reality is recognized. The ecosystem ships against the actual deployment surface, not a single-channel idealization.
- Silent-drift attack surface is closed. Every shared claim is enforced on every required surface; a missing or contradictory claim fails CI.
- Reconciliation rule provides predictable conflict resolution. When surfaces drift, the rewrite direction is unambiguous (
claude-md-wins); the deliberate-divergence escape hatch (coherence-overridemarker + ADR) preserves the rule while allowing principled exceptions. - Optional surfaces are first-class but opt-in. The operator chooses the deployment scope; the validator scope expands per the opt-in record. Adding a surface is
make ai-surfaces-add <name>; removing is the inverse. - The validator scope grows linearly with surface count. Each opted-in surface is a new participant in the coherence contract; the per-claim presence requirement extends to it.
- The published
.github/copilot-instructions.mdis authored fresh in surface-appropriate framing, not template-stamped fromCLAUDE.md. The two surfaces speak the same disciplines but in different voices: CLAUDE.md is voiced for an autonomous reasoning assistant operating in chat; copilot-instructions.md is voiced for an in-IDE code-completion assistant whose suggestions a developer accepts or rejects. - The ADR (this file) is the canonical pointer to the rationale, the surfaces in scope, the coherence contract, and the reconciliation rule. Future opt-in / opt-out decisions reference this ADR.
Alternatives Considered¶
CLAUDE.mdonly. Rejected: Copilot freelances against unstated conventions; silent drift in machine-generated code accumulates invisibly between PR reviews..github/copilot-instructions.mdonly. Rejected: Claude inherits no in-repo memory; per-session conversational reconstruction loses the durable behavioral floor.- Union-of-all-surfaces with no coherence contract. Rejected: contradictory directives across surfaces become silent failure modes; the contributor cannot tell which surface to honor when they diverge.
- Mandatory
docs/architecture/agents.mdand.cursorrules(alongside the two-surface mandatory base). Rejected: deployment scope is operator-specific; not every operator uses every assistant. The opt-in posture is the right granularity. - Reconciliation rule = "newest surface wins" or "narrowest surface wins" (alternatives to
claude-md-wins). Rejected: both produce ambiguous outcomes when timestamps or scope-narrowness are themselves disputed;claude-md-winsnames a specific source of truth and is therefore unambiguously enforceable.
Cross-references: docs/ai-conventions.md, tests/fixtures/multi-surface-claims.yaml, .github/copilot-instructions.md, CLAUDE.md, Spec §0.6, Spec §2.8, Spec §4.7.