ADRs
ADR 0060 — Documentation lives under `docs/`, code under `apps/` and `packages/` — separation by convention
  • Date: 2026-06-18
  • Status: Accepted (codifies existing convention; rejects collocation alternatives)

Context

A recurring contributor / maintainer question: why does each Studio tool have its documentation in docs/<tool>/ and its code in apps/web/src/dev-tools/studio/<tool>/? Could the two be collocated under the same folder?

The question is legitimate. Three alternatives exist:

  1. Separation (current). docs/<tool>/ + apps/web/src/dev-tools/studio/<tool>/. Linked by naming convention.
  2. Collocation A — docs inside code. apps/web/src/dev-tools/studio/<tool>/{*.tsx, docs/*.md}. One folder per tool, everything inside.
  3. Collocation B — code inside docs. docs/<tool>/{*.md, code/*.tsx}. Not buildable — Next.js / Vite expect code under apps/ or packages/. Rejected outright.

ADR 0058 (Studio tools documentation pattern) settled the file shape; this ADR settles the location.

Decision

Documentation stays in docs/; code stays in apps/ and packages/. The two are linked by naming convention (docs/<tool>/apps/web/src/dev-tools/studio/<tool>/), not by colocation.

Layout

arno/
├── docs/
│   ├── _index.md                      # top-level navigator
│   ├── glossary.md                    # cross-tool vocabulary
│   ├── architecture.md                # C4 diagrams
│   ├── testing-standard.md            # test-layer standard
│   ├── adr/                           # decision records
│   ├── kernel/                        # shared kernel docs
│   ├── layers/                        # 12 .md files
│   ├── nav-bar/                       # 12 .md files
│   ├── punta/                         # 12 .md files
│   └── ...
├── apps/web/src/dev-tools/studio/
│   ├── _index.md                      # umbrella + dependency graph
│   ├── README.md                      # human-facing intro
│   ├── layers/                        # .tsx, .css, .test.ts ONLY
│   ├── nav-bar/                       # .tsx, .css, .test.ts ONLY
│   ├── punta/                         # .tsx, .css, .test.ts ONLY
│   └── ...
└── packages/
    └── foundation/                    # design tokens, etc.

The link

The convention is mechanical: a tool named <tool> has its code under apps/web/src/dev-tools/studio/<tool>/ and its docs under docs/<tool>/. The Studio umbrella (apps/web/src/dev-tools/studio/_index.md) is the single canonical map of which <tool> names exist. CI check (scripts/check-doc-completeness.ts) enforces both directions:

  • A tool with code but no docs → CI fails.
  • A doc folder with no corresponding code folder → CI fails (unless explicitly marked <scaffolding>).

Why separation, not collocation

Industry precedent

Every major monorepo we benchmarked follows the same separation:

ProjectDocs locationCode location
React (Meta)docs/ (separate react.dev repo for site; in-repo READMEs)packages/react/
Vue.jsdocs/ (separate vuejs/docs repo)packages/
Next.jsdocs/packages/next/
Astrodocs/packages/astro/
TypeScriptdoc/src/
Bundocs/src/
Storybookdocs/ (separate site repo)code/

The pattern is overwhelming. Contributors arrive expecting separation; collocation would be the surprise.

Build pipeline simplicity

Next.js scans apps/web/src/**/*.{ts,tsx,js,jsx,mdx} for routes and modules. Markdown files inside the source tree must be excluded from build (or they become accidental routes). Separation avoids the exclusion entirely:

  • apps/web/src/dev-tools/studio/<tool>/ is pure code. Next.js builds it.
  • docs/<tool>/ is pure prose. Next.js never touches it.

Lang-check (scripts/check-language.ts), spell-check, and any future doc linter scan docs/**/*.md with a single glob. Collocation would require nested globs (apps/web/src/**/docs/**/*.md) that are harder to maintain and slower to run.

GitHub UI

GitHub's repository browser renders the top-level docs/ folder prominently. A reader landing on the repo sees docs/ next to apps/ and packages/. The intent is legible at a glance.

With collocation, the docs are buried under apps/web/src/dev-tools/studio/<tool>/docs/. A reader must dig four levels to find them. The signal that "this project documents itself" is lost.

Cross-tool comparison

Reviewing the docs surface for consistency is mechanical with separation:

ls docs/                              # lists all documented surfaces
diff docs/punta/contract.md docs/dito/contract.md   # compare two tools' contracts side-by-side

With collocation:

find apps/web/src/dev-tools/studio -type d -name docs   # finds them but requires globs

The convenience of ls docs/ over find ... is small per use; large over a year.

CI scope

The lang-check workflow runs on pull_request with paths: ['docs/**']. If docs move into the code tree, the path filter must change to paths: ['apps/web/src/dev-tools/studio/**/docs/**']. Functional but uglier. The separation keeps CI rules readable.

Where collocation IS allowed

The separation rule applies to Studio tools and project-wide ARNO docs. Three carve-outs:

  1. Per-package READMEs. A packages/foundation/README.md is allowed and expected — it documents the package's public API and is published with npm if we ever publish.
  2. Inline JSDoc + type comments. These ARE the code. They live in *.ts / *.tsx files and document symbols at definition time. Not subject to this ADR.
  3. .claude/ agent docs. The agent orchestration system has its own internal docs under .claude/. Those are operational state, not architectural docs. Not subject to this ADR.

Anything outside these three carve-outs follows the separation rule.

Consequences

Positive

  • Industry-standard layout. Contributors arrive expecting the shape we ship.
  • Clean build pipeline. No exclusion globs needed.
  • Trivial cross-tool review. ls docs/ is the surface.
  • Lang-check / spell-check simple. One glob.
  • GitHub UI cooperation. The docs/ folder is prominent.

Negative

  • Two folders touched per tool change. Every PR that touches studio/<tool>/ also touches docs/<tool>/. Slightly more git add per PR.
  • Rename is two git mv calls. Mitigated by mechanical script if it becomes painful.
  • Onboarding question. "Where are the docs?" — answered once per contributor. Trivial.

Risk: docs out of sync with code

The biggest failure mode is code outpacing docs. With separation, a stale doc is in a separate folder and easy to overlook. Mitigation:

  • The CI check (scripts/check-doc-completeness.ts) fails when a tool has code but no docs.
  • The Danger soft-warning (planned) flags PRs that touch studio/<tool>/ but not docs/<tool>/.
  • Each tool's migration.md requires a contract-version bump on contract change, which forces a doc edit.

Alternatives considered

Collocation A — docs inside code (studio/<tool>/{*.tsx, docs/*.md})

Pros: one folder per tool; rename = one git operation; immediate proximity for the developer working inside the code folder.

Cons: breaks Next.js build assumptions; requires path-glob exclusions; loses GitHub UI prominence; loses ls docs/ convenience; loses lang-check single-glob simplicity; diverges from industry default.

Rejected. The "one folder per tool" benefit is real but small. The cumulative cost across build / CI / review / discovery is larger.

Collocation B — code inside docs (docs/<tool>/{*.md, code/*.tsx})

Cons: unbuildable. Next.js / Vite scan apps/ and packages/ for entry points; code under docs/ would be invisible.

Rejected outright.

Symlinks

docs/<tool>apps/web/src/dev-tools/studio/<tool>/docs/. Or vice versa.

Cons: symlinks break on Windows; git's handling of symlinks across platforms is fragile; IDE search doubles results; pre-commit hooks frequently see symlinks as untracked.

Rejected. Not worth the cross-platform risk.

References

  • Industry comparison cited above.
  • Related ADRs: 0058 (canonical file set), 0059 (naming chord), 0061 (layerTypeOf shared dispatch).
  • Rules.md §"Studio tools — documentation pattern" §"Code folders" — the prose form that points here.