Skip to content

ADR-0004: Mirror Layout — Repo Root IS Claude Code Adapter Content

Status

Accepted

Context

Scope. This ADR documents the layout decision made when the project was the dotfiles distribution of .claude (the Claude Code adapter). The mirror-layout invariant captured here is now the foundation on which the harness-agnostic adapter package (src/apothem/harnesses/<harness>/) projects the same shared corpus into every other supported AI tool's native configuration directory.

The published ecosystem is structurally a dotfiles-style distribution of .claude (the Claude Code adapter destination) plus the supporting repo hygiene layer (LICENSE, README, CHANGELOG, CI workflows, validators, schemas, tests). Two layouts are admissible per Spec §2.1:

  1. Mirror layout (Option A). Repo root is the Claude Code adapter's .claude/ content (src/apothem/agents/, src/apothem/skills/, commands/, CLAUDE.md, etc. live at the root), with repo-meta files (README.md, LICENSE, .github/, etc.) alongside. The install script symlinks or copies content into ~/.claude.
  2. Nested layout (Option B). A top-level claude/ (or .claude/) folder contains the ecosystem; repo-meta lives at the actual root; the install script targets ~/.claude from the nested subdirectory.

The choice ratifies for every downstream consumer — install script structure, validator path-roots, plugin-manifest payload paths, documentation cross-references, IDE-extension discovery patterns. Reversing the layout post-publication is a breaking change for every operator who has cloned, every CI integration that has wired path expectations, and every plugin marketplace listing that has registered against a path shape.

Decision

Mirror layout (Option A). Repo root IS the Claude Code adapter's .claude/ content.

Rationale:

  • Idiomatic for dotfiles publication. Public dotfiles repos uniformly ship with the dotfiles content at the repo root (.bashrc, .vimrc, etc. live at the top); a contributor cloning the repo expects to find the ecosystem at the root, not under a nested claude/ indirection.
  • Flatter. One less directory level for every reference; src/apothem/agents/foo.md rather than claude/agents/foo.md everywhere.
  • Install script is simpler. install.{sh,ps1} symlinks or copies the root's content to ~/.claude; no per-file path arithmetic to strip a leading claude/ prefix.

The recursive-case constraint (the operator's harness-config root — e.g. ~/.claude/ for Claude Code — IS the project being developed in this repo) is resolved by gitignoring the harness-internal plans/ directory (e.g. ~/.claude/plans/ for Claude Code) per ADR-0001, rather than physically relocating the suite folder. The ecosystem ships with plans/ gitignored at the root; the operator's local working tree may carry plans (the discipline applies recursively), but the published tree never does.

Consequences

  • Repo root is dense with ecosystem content. A casual visitor to the repo sees src/, scripts/, tests/, docs/, examples/, assets/, packaging/, plugins/, LICENSES/, CLAUDE.md, .claude/, and .claude-plugin/ at top level — the package source and its convention surface live under src/apothem/. The README's structure-diagram section is the navigation aid.
  • Install script surface is small. install.{sh,ps1} operates on the repo root; no manifest of "which subdirectory to copy" is needed.
  • Plugin manifests reference paths from repo root. The plugin manifest at .claude-plugin/plugin.json (per ADR-0007) lists src/apothem/agents/, commands/, src/apothem/skills/, etc. as its payload directly.
  • Recursive-case is handled by .gitignore, not by relocation. The published tree never carries plans/; the operator's local tree may, exactly as the discipline prescribes for any project. The ecosystem dogfoods its own discipline.
  • The docs/ directory lives at the repo root (this file's location), parallel to src/apothem/agents/ and other ecosystem directories. ADRs live at docs/adr/NNNN-*.md per the convention this ADR's existence demonstrates.

Alternatives Considered

  • Nested layout (Option B). Rejected: extra indirection without publication benefit; non-idiomatic for dotfiles. The only argument for nesting is "keep ecosystem content visually separated from repo-meta", which is solved by directory naming conventions rather than nesting.
  • Hybrid layout (some content nested, some at root). Rejected: produces the worst of both layouts — contributors must learn which files live where, and the install script needs a manifest. The whole-repo-is-the-payload symmetry of the mirror layout is the simpler invariant.

Amendment — 2026-05-14

The claude-code adapter's install.py no longer generates or installs a CLAUDE.md into the harness config root. The propagation manifest entry for templates/CLAUDE.md was retired and the adapter's materializer.py was removed. CLAUDE.md remains an operator-owned file: the apothem governance surface reaches Claude Code through the propagated rules/ tree and the SessionStart hook, not through an adapter-rendered CLAUDE.md. The original mirror-layout decision (repo root IS the adapter content, and the repo's own CLAUDE.md ships via the dotfiles clone path) is unchanged — this amendment records only that adapter-driven CLAUDE.md propagation was subsequently retired.


Cross-references: ADR-0001, ADR-0007, Spec §2.1.