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:
- 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. - 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~/.claudefrom 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 nestedclaude/indirection. - Flatter. One less directory level for every reference;
src/apothem/agents/foo.mdrather thanclaude/agents/foo.mdeverywhere. - Install script is simpler.
install.{sh,ps1}symlinks or copies the root's content to~/.claude; no per-file path arithmetic to strip a leadingclaude/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 undersrc/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) listssrc/apothem/agents/,commands/,src/apothem/skills/, etc. as its payload directly. - Recursive-case is handled by
.gitignore, not by relocation. The published tree never carriesplans/; 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 tosrc/apothem/agents/and other ecosystem directories. ADRs live atdocs/adr/NNNN-*.mdper 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.