@adia-ai/adia-ui-forge 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +2 -2
- package/CHANGELOG.md +8 -0
- package/agents/README.md +209 -0
- package/agents/a2ui-engineer.md +57 -0
- package/agents/author.md +56 -0
- package/agents/release-engineer.md +85 -0
- package/agents/repo-steward.md +56 -0
- package/agents/routing-corpus.json +89 -0
- package/agents/spec-architect.md +53 -0
- package/agents/tech-lead.md +57 -0
- package/agents/verifier.md +55 -0
- package/package.json +3 -2
- package/skills/adia-ui-authoring/SKILL.md +2 -2
- package/skills/adia-ui-authoring/assets/case-studies/theme-panel-promotion.md +1 -1
- package/skills/adia-ui-authoring/references/module-promotion.md +2 -2
- package/skills/adia-ui-gen-review/skill.json +1 -0
- package/skills/adia-ui-ops/CHANGELOG.md +291 -0
- package/skills/adia-ui-ops/SKILL.md +401 -0
- package/skills/adia-ui-ops/references/INDEX.md +158 -0
- package/skills/adia-ui-ops/references/audit-cadence.md +263 -0
- package/skills/adia-ui-ops/references/audit-patterns/archive-link-sweep.md +96 -0
- package/skills/adia-ui-ops/references/audit-patterns/audit-history-ledger.md +162 -0
- package/skills/adia-ui-ops/references/audit-patterns/browser-bundle-node-imports.md +154 -0
- package/skills/adia-ui-ops/references/audit-patterns/changelog-unreleased-bloat.md +75 -0
- package/skills/adia-ui-ops/references/audit-patterns/coverage-gaps.md +187 -0
- package/skills/adia-ui-ops/references/audit-patterns/entry-file-coverage.md +122 -0
- package/skills/adia-ui-ops/references/audit-patterns/format-hygiene.md +217 -0
- package/skills/adia-ui-ops/references/audit-patterns/lockstep-versioning.md +113 -0
- package/skills/adia-ui-ops/references/audit-patterns/memory-fragmentation.md +180 -0
- package/skills/adia-ui-ops/references/audit-patterns/orphan-detection.md +202 -0
- package/skills/adia-ui-ops/references/audit-patterns/pointer-validation.md +180 -0
- package/skills/adia-ui-ops/references/audit-patterns/redundancy-detection.md +210 -0
- package/skills/adia-ui-ops/references/audit-patterns/spec-dating-sweep.md +91 -0
- package/skills/adia-ui-ops/references/audit-patterns/stale-content.md +182 -0
- package/skills/adia-ui-ops/references/audit-patterns/staleness-tooling.md +156 -0
- package/skills/adia-ui-ops/references/audit-patterns/token-waste-detection.md +196 -0
- package/skills/adia-ui-ops/references/deploy-playbooks.md +259 -0
- package/skills/adia-ui-ops/references/doc-types/adr-pattern.md +210 -0
- package/skills/adia-ui-ops/references/doc-types/architecture-md.md +190 -0
- package/skills/adia-ui-ops/references/doc-types/changelog.md +183 -0
- package/skills/adia-ui-ops/references/doc-types/decisions-log.md +146 -0
- package/skills/adia-ui-ops/references/doc-types/plan-roadmap.md +182 -0
- package/skills/adia-ui-ops/references/doc-types/postmortem-pattern.md +206 -0
- package/skills/adia-ui-ops/references/genres/prose-and-writing.md +149 -0
- package/skills/adia-ui-ops/references/guidance/context-budget.md +137 -0
- package/skills/adia-ui-ops/references/guidance/llm-doc-writing.md +116 -0
- package/skills/adia-ui-ops/references/guidance/reliability-dial.md +186 -0
- package/skills/adia-ui-ops/references/recipes/adr-introduction.md +211 -0
- package/skills/adia-ui-ops/references/recipes/audit-existing-repo.md +234 -0
- package/skills/adia-ui-ops/references/recipes/cold-start-harvest.md +263 -0
- package/skills/adia-ui-ops/references/recipes/concurrent-learnings-merge.md +158 -0
- package/skills/adia-ui-ops/references/recipes/continuous-learning-loop.md +169 -0
- package/skills/adia-ui-ops/references/recipes/external-reference-verification.md +158 -0
- package/skills/adia-ui-ops/references/recipes/findings-index-readout.md +126 -0
- package/skills/adia-ui-ops/references/recipes/greenfield-setup.md +252 -0
- package/skills/adia-ui-ops/references/recipes/harvest-repo-brain.md +169 -0
- package/skills/adia-ui-ops/references/recipes/import-repo-brain-harvest.md +153 -0
- package/skills/adia-ui-ops/references/recipes/memory-organization.md +182 -0
- package/skills/adia-ui-ops/references/recipes/recommend-then-validate.md +199 -0
- package/skills/adia-ui-ops/references/recipes/self-healing-hooks.md +366 -0
- package/skills/adia-ui-ops/references/recipes/skill-stewardship-loop.md +113 -0
- package/skills/adia-ui-ops/references/standards/agents-md-spec.md +138 -0
- package/skills/adia-ui-ops/references/standards/claude-md-convention.md +123 -0
- package/skills/adia-ui-ops/references/standards/cross-tool-matrix.md +85 -0
- package/skills/adia-ui-ops/references/standards/readme-conventions.md +232 -0
- package/skills/adia-ui-ops/references/teach-protocol.md +215 -0
- package/skills/adia-ui-ops/scripts/audit-ops-roster.mjs +104 -0
- package/skills/adia-ui-ops/skill.json +65 -0
- package/skills/adia-ui-release/CHANGELOG.md +43 -0
- package/skills/adia-ui-release/SKILL.md +34 -6
- package/skills/adia-ui-release/references/independent-package-release.md +129 -0
- package/skills/adia-ui-release/references/recovery-paths.md +49 -2
- package/skills/adia-ui-release/scripts/dispatch-publish.mjs +68 -5
- package/skills/adia-ui-release/scripts/insert-stub.mjs +5 -3
- package/skills/adia-ui-release/scripts/make-ledger.mjs +22 -1
- package/skills/adia-ui-release/scripts/package-paths.mjs +44 -0
- package/skills/adia-ui-release/scripts/promote-unreleased.mjs +3 -2
- package/skills/adia-ui-release/scripts/release-pack.mjs +36 -7
- package/skills/adia-ui-release/scripts/tag-lockstep.mjs +10 -2
- package/skills/adia-ui-release/skill.json +9 -7
- package/skills/dogfood-sweep/CHANGELOG.md +37 -0
- package/skills/dogfood-sweep/README.md +105 -0
- package/skills/dogfood-sweep/SKILL.md +1000 -0
- package/skills/dogfood-sweep/analyze.mjs +600 -0
- package/skills/dogfood-sweep/skill.json +31 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# Deploy playbooks — exe.dev VM operations
|
|
2
|
+
|
|
3
|
+
> **Owner: `adia-ui-ops` modes 1-4** (cold-start triage entry).
|
|
4
|
+
> Absorbed verbatim from the retired standalone `exe-dev-ops` skill (v1.0.0,
|
|
5
|
+
> 2026-05-22). Authored content untouched; only the framing wrapper changed.
|
|
6
|
+
|
|
7
|
+
Operational playbook for services on **exe.dev** — shared Linux VMs reached via
|
|
8
|
+
`ssh <host>.exe.xyz`. This reference captures the platform contract (which
|
|
9
|
+
isn't obvious from docs), the standard layout we use across services, and the
|
|
10
|
+
two-three commands that solve 90% of day-to-day tasks.
|
|
11
|
+
|
|
12
|
+
## When to use
|
|
13
|
+
|
|
14
|
+
- Deploying a new static site or API to a fresh exe.dev VM.
|
|
15
|
+
- Updating an existing deployed site (push new `dist/`).
|
|
16
|
+
- Rotating API keys or other secrets on the VM.
|
|
17
|
+
- Diagnosing a down service — seeing the **"Port 8000 unbound."** error page, 502s, or failed health checks.
|
|
18
|
+
- Adding a new systemd service / Caddy site to a VM already in service.
|
|
19
|
+
|
|
20
|
+
## When NOT to use
|
|
21
|
+
|
|
22
|
+
- DNS config — exe.dev owns `<host>.exe.xyz` subdomains; nothing to do locally.
|
|
23
|
+
- TLS — the exe.dev front-door terminates HTTPS. Never bind :443 on the VM.
|
|
24
|
+
- Multi-VM orchestration / auto-scaling — out of scope, single VM per service.
|
|
25
|
+
- Anything requiring root on the host kernel — these are shared VMs, not full boxes.
|
|
26
|
+
|
|
27
|
+
## Platform contract (the non-obvious bits)
|
|
28
|
+
|
|
29
|
+
These facts are easy to get wrong because the docs are thin — we learned them the hard way.
|
|
30
|
+
|
|
31
|
+
- **Your app must bind `:8000`** (plain HTTP). The exe.dev edge proxy terminates TLS on `<host>.exe.xyz` and forwards to VM `:8000`. If nothing is listening, exe.dev serves:
|
|
32
|
+
|
|
33
|
+
> **Port 8000 unbound.** `ssh <host>.exe.xyz sudo systemctl enable --now nginx`
|
|
34
|
+
>
|
|
35
|
+
> (The nginx suggestion is just their canonical example — Caddy, Node, anything that binds :8000 works.)
|
|
36
|
+
|
|
37
|
+
- **Default VM user: `exedev`** — uid 1000, member of `sudo` and `docker`. Use this for service processes; don't create a dedicated service user unless you have a real isolation requirement.
|
|
38
|
+
- **What's preinstalled:** `git`, `rsync`, `docker`. **Not preinstalled:** `caddy`, `node`, `npm`, `nginx`. Use apt + NodeSource for node.
|
|
39
|
+
- **`127.0.0.1:9999` runs `shelley`** — exe.dev's internal agent. Localhost-only. Don't kill it, don't bind anything to 9999.
|
|
40
|
+
- **Disk:** 25 GB on `/`; no separate `/srv` mount. Fits a typical static bundle + node modules comfortably.
|
|
41
|
+
- **Host SSH key:** currently RSA-2048 only on new VMs (as of 2026-04). Verify the fingerprint in the exe.dev console on first connect; then `ssh-keyscan >> ~/.ssh/known_hosts`.
|
|
42
|
+
|
|
43
|
+
## Standard layout (convention we use)
|
|
44
|
+
|
|
45
|
+
| Path | Purpose | Owner |
|
|
46
|
+
| ----------------------------- | ----------------------------------------------- | ----------------- |
|
|
47
|
+
| `/srv/<app>/dist/` | Static bundle served by Caddy | `exedev:exedev` |
|
|
48
|
+
| `/srv/<app>/server.js` | Optional runtime (e.g. API proxy) | `exedev:exedev` |
|
|
49
|
+
| `/etc/caddy/Caddyfile` | Single-site; binds `:8000` | `root:root` |
|
|
50
|
+
| `/etc/systemd/system/<app>.service` | systemd unit for server.js | `root:root` |
|
|
51
|
+
| `/etc/<app>.env` | Secrets loaded via `EnvironmentFile=` | `root:root` 0600 |
|
|
52
|
+
|
|
53
|
+
**Never** put secrets in `/srv/<app>/` — that's the webroot.
|
|
54
|
+
|
|
55
|
+
## Playbook: fresh provisioning
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
# 1. SSH in; verify host key first via exe.dev console.
|
|
59
|
+
ssh <host>.exe.xyz
|
|
60
|
+
|
|
61
|
+
# 2. Install runtime.
|
|
62
|
+
sudo apt-get update -qq
|
|
63
|
+
sudo apt-get install -y caddy
|
|
64
|
+
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
|
65
|
+
sudo apt-get install -y nodejs
|
|
66
|
+
|
|
67
|
+
# 3. Filesystem.
|
|
68
|
+
sudo mkdir -p /srv/<app>
|
|
69
|
+
sudo chown exedev:exedev /srv/<app>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Then from your **local** machine:
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
# 4. Push artifacts.
|
|
76
|
+
rsync -az --delete dist/ <host>.exe.xyz:/srv/<app>/dist/
|
|
77
|
+
rsync -a server.js <host>.exe.xyz:/srv/<app>/server.js # if applicable
|
|
78
|
+
|
|
79
|
+
# 5. Push Caddyfile + systemd unit.
|
|
80
|
+
scp deploy/Caddyfile <host>.exe.xyz:/tmp/
|
|
81
|
+
scp deploy/<app>.service <host>.exe.xyz:/tmp/
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Back on the VM:
|
|
85
|
+
|
|
86
|
+
```sh
|
|
87
|
+
# 6. Activate Caddy.
|
|
88
|
+
sudo mv /etc/caddy/Caddyfile /etc/caddy/Caddyfile.default.bak
|
|
89
|
+
sudo mv /tmp/Caddyfile /etc/caddy/Caddyfile
|
|
90
|
+
sudo systemctl reload caddy
|
|
91
|
+
|
|
92
|
+
# 7. Activate service.
|
|
93
|
+
sudo mv /tmp/<app>.service /etc/systemd/system/<app>.service
|
|
94
|
+
sudo systemctl daemon-reload
|
|
95
|
+
sudo systemctl enable --now <app>
|
|
96
|
+
|
|
97
|
+
# 8. Seed secrets — do this by hand; never via agent transcript.
|
|
98
|
+
sudo install -m 0600 -o root -g root /dev/null /etc/<app>.env
|
|
99
|
+
sudo vim /etc/<app>.env
|
|
100
|
+
sudo systemctl restart <app>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Playbook: deploy an update
|
|
104
|
+
|
|
105
|
+
Single command from the repo root once `npm run deploy:site` is wired:
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
npm run deploy:site
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Under the hood: `npm run build:site && rsync -az --delete dist/ <host>.exe.xyz:/srv/<app>/dist/`. Caddy picks up static changes without a reload.
|
|
112
|
+
|
|
113
|
+
> ⚠️ **`deploy:site` is a `--delete` deploy — treat it as destructive.** `build:site`
|
|
114
|
+
> is **manual** (not wired into the npm release pipeline), so `dist/` silently drifts
|
|
115
|
+
> behind `main` until someone runs it, and the rsync **deletes** everything on the
|
|
116
|
+
> server that isn't in the fresh `dist/`. A real ui-kit run (2026-06-08) sent ~160 real
|
|
117
|
+
> content deltas and **deleted 3,572 files**. Never fire it blind — the sequence below
|
|
118
|
+
> is the contract for any `--delete` site deploy.
|
|
119
|
+
|
|
120
|
+
### Hardened `--delete` deploy sequence
|
|
121
|
+
|
|
122
|
+
1. **Build from a clean, fully-merged `main`** — never a feature branch. `dist/` ships
|
|
123
|
+
verbatim; whatever's missing on the server gets deleted.
|
|
124
|
+
- **In a FRESH worktree, build `@adia-ai/llm` FIRST:**
|
|
125
|
+
```sh
|
|
126
|
+
npm run build -w @adia-ai/llm # BEFORE build:site
|
|
127
|
+
```
|
|
128
|
+
The `llm` package **compiles its JS at publish time** and its outputs are
|
|
129
|
+
**gitignored** — so a fresh worktree (or any tree that hasn't published llm
|
|
130
|
+
locally) has no `packages/llm/index.js`, `build:site` copies nothing, and
|
|
131
|
+
**`/packages/llm/index.js` 404s on the deployed site → component registration
|
|
132
|
+
breaks on every `/site/components/*` page** (the docs components reference it). Found
|
|
133
|
+
**live 2026-06-09**; the **0-delete dry-run proved it had never been deployed** (the
|
|
134
|
+
file was absent on the server, so there was nothing to delete — not a regression, a
|
|
135
|
+
standing gap across every prior deploy). Build llm, then `build:site`, then the
|
|
136
|
+
dry-run.
|
|
137
|
+
2. **Dry-run first, and adjudicate every delete:**
|
|
138
|
+
```sh
|
|
139
|
+
rsync -azni --delete dist/ <host>.exe.xyz:/srv/<app>/dist/ # -n simulates · -i itemizes
|
|
140
|
+
```
|
|
141
|
+
- `*deleting` lines = files removed from prod. Bucket **every one** into a known-safe
|
|
142
|
+
class; **abort if any served-content delete is unexplained.** Safe classes seen on
|
|
143
|
+
ui-kit: gallery review artifacts (`apps/genui/.../review/cycle-*/`), stale
|
|
144
|
+
`packages/a2ui/retrieval/` + eval reports, **content-hash-rotated** CodeMirror
|
|
145
|
+
chunks (`code/{chunk,dist}-<hash>.js` — old hash deleted, new hash sent = rotation,
|
|
146
|
+
not loss), restructured `packages/llm/*.js` dist copies, `node_modules/`
|
|
147
|
+
symlink-farm dirs, and refactor-orphaned app files. None are served HTML.
|
|
148
|
+
- **Don't panic at the send count.** A fresh local build never mtime-aligns with the
|
|
149
|
+
remote, so `rsync -a` flags ~every file as a send (`<f..t` = mtime-only touch). Only
|
|
150
|
+
`<f+++` (new) and `<f.s.` / `<fcst` (content) are real deltas — the 2026-06-08 run
|
|
151
|
+
itemized 12,540 "sends" of which only ~160 carried real content.
|
|
152
|
+
3. **Snapshot prod FIRST — the only safety net for `--delete`:**
|
|
153
|
+
```sh
|
|
154
|
+
ssh <host>.exe.xyz 'cp -al /srv/<app>/dist /srv/<app>/dist.bak-<date>' # hardlink: instant, reversible
|
|
155
|
+
ssh <host>.exe.xyz 'find /srv/<app>/dist.bak-<date> -type f | wc -l' # confirm it materialized
|
|
156
|
+
```
|
|
157
|
+
`cp -al` is a hardlink farm — instant, ~0 extra disk, and a true point-in-time
|
|
158
|
+
snapshot because rsync replaces inodes (writes a temp file + renames) rather than
|
|
159
|
+
mutating in place. Restore with `rm -rf dist && mv dist.bak-<date> dist`.
|
|
160
|
+
4. **Deploy** (the dry-run, minus `-n`):
|
|
161
|
+
```sh
|
|
162
|
+
rsync -az --delete dist/ <host>.exe.xyz:/srv/<app>/dist/
|
|
163
|
+
```
|
|
164
|
+
5. **Verify the FILE, not the route.** A SPA returns `200` + the app shell for *any*
|
|
165
|
+
route even when stale — `curl https://<host>.exe.xyz/` proves nothing. Curl a
|
|
166
|
+
**fixture file** that only exists in the new build, then **render-check the real
|
|
167
|
+
screens**:
|
|
168
|
+
```sh
|
|
169
|
+
curl -s https://<host>.exe.xyz/.../scenarios/manifest.json | grep -c <new-scenario> # >0
|
|
170
|
+
curl -s -o /dev/null -w '%{http_code}' https://<host>.exe.xyz/.../<scenario>/manifest.json # 200
|
|
171
|
+
```
|
|
172
|
+
File-presence is necessary but not sufficient — SPAs render client-side from the
|
|
173
|
+
fixture, so only a headless-Chromium render proves the page composes (and didn't fall
|
|
174
|
+
back to a default scenario). Run Playwright with `env -u NODE_OPTIONS` (a cmux
|
|
175
|
+
`--require` in `NODE_OPTIONS` crashes node from the repo cwd).
|
|
176
|
+
6. **Rollback if verify fails** — restore the snapshot to the exact pre-deploy state:
|
|
177
|
+
```sh
|
|
178
|
+
ssh <host>.exe.xyz 'rm -rf /srv/<app>/dist && mv /srv/<app>/dist.bak-<date> /srv/<app>/dist'
|
|
179
|
+
```
|
|
180
|
+
Keep the snapshot until the deploy is confirmed good, then prune it.
|
|
181
|
+
|
|
182
|
+
> **`build:site` DOES include the app's components** (a pre-deploy worry, disproven
|
|
183
|
+
> 2026-06-08). AdiaUI apps are Light-DOM / no-bundle — components live in
|
|
184
|
+
> `app/.../src/components/` (the **source** tree), which `build:site` copies wholesale,
|
|
185
|
+
> so the SPA is fully renderable in `dist/`. Presence ≠ render, though; step 5's
|
|
186
|
+
> render-check is still the proof.
|
|
187
|
+
>
|
|
188
|
+
> **The one exception — `@adia-ai/llm` (2026-06-09):** llm is NOT a source-tree
|
|
189
|
+
> component; it **builds its JS at publish** (gitignored outputs), so `build:site` copies
|
|
190
|
+
> nothing for it in a fresh worktree and `/packages/llm/index.js` 404s → component
|
|
191
|
+
> registration breaks site-wide. Run `npm run build -w @adia-ai/llm` **before** `build:site`
|
|
192
|
+
> (step 1 above). This is exactly why step 5 render-checks a **`/site/components/*`** page,
|
|
193
|
+
> not just a fixture file — the 404 is invisible to file-presence and to the SPA shell.
|
|
194
|
+
|
|
195
|
+
If `server.js` changed:
|
|
196
|
+
|
|
197
|
+
```sh
|
|
198
|
+
rsync -a server.js <host>.exe.xyz:/srv/<app>/server.js
|
|
199
|
+
ssh <host>.exe.xyz 'sudo systemctl restart <app>'
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Playbook: rotate secrets
|
|
203
|
+
|
|
204
|
+
```sh
|
|
205
|
+
ssh <host>.exe.xyz 'sudo vim /etc/<app>.env && sudo systemctl restart <app>'
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
No rebuild, no redeploy. The static bundle never sees keys.
|
|
209
|
+
|
|
210
|
+
## Playbook: diagnose
|
|
211
|
+
|
|
212
|
+
When the site is down or returning 502, start here — everything is read-only:
|
|
213
|
+
|
|
214
|
+
```sh
|
|
215
|
+
ssh <host>.exe.xyz '
|
|
216
|
+
echo "=== caddy ==="
|
|
217
|
+
systemctl is-active caddy; systemctl status caddy --no-pager | head -10
|
|
218
|
+
echo "=== app service ==="
|
|
219
|
+
systemctl is-active <app>; journalctl -u <app> -n 30 --no-pager
|
|
220
|
+
echo "=== listening ports ==="
|
|
221
|
+
sudo ss -tlnp | grep -E ":(8000|3456|80|443)"
|
|
222
|
+
echo "=== caddy syntax check ==="
|
|
223
|
+
sudo caddy validate --config /etc/caddy/Caddyfile
|
|
224
|
+
echo "=== disk ==="
|
|
225
|
+
df -h /
|
|
226
|
+
'
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Common failures:
|
|
230
|
+
|
|
231
|
+
| Symptom | Likely cause | Fix |
|
|
232
|
+
| ------------------------------- | ---------------------------------------------- | ------------------------------------------------- |
|
|
233
|
+
| "Port 8000 unbound" page | Caddy not listening on `:8000` | Check Caddyfile header is `:8000` not `:80` |
|
|
234
|
+
| 502 on `/api/*` | `<app>` service down or wrong port | `systemctl status <app>`; tail journalctl |
|
|
235
|
+
| 500 from `/api/llm/*` | Missing/invalid API key | Check `/etc/<app>.env`, restart service |
|
|
236
|
+
| Static assets 404 | `rsync --delete` ran with wrong source | Rebuild local `dist/`, push again |
|
|
237
|
+
| Site serves a stale build (new fixtures 404, SPA shows a default scenario) | `deploy:site` never run after the merge — it's **manual**, not on the release pipeline | Run the hardened `--delete` sequence; verify the fixture **file**, not the route |
|
|
238
|
+
| Caddy won't reload | Syntax error in Caddyfile | `sudo caddy validate --config /etc/caddy/Caddyfile` |
|
|
239
|
+
|
|
240
|
+
## Invariants
|
|
241
|
+
|
|
242
|
+
- **Secrets never flow through agent context.** The agent should `sudo vim` *or* pause and let the human seed `/etc/<app>.env`. Never `echo "sk-..." > /etc/<app>.env` in a Bash call.
|
|
243
|
+
- **Caddy binds `:8000`**, not `:80` or `:443`.
|
|
244
|
+
- **`--delete` on rsync is scoped to the webroot only** (`/srv/<app>/dist/`). Never rsync-delete against `/srv/<app>/` or the VM's home.
|
|
245
|
+
- **Snapshot the webroot before any `--delete` deploy.** `cp -al /srv/<app>/dist /srv/<app>/dist.bak-<date>` is the only rollback for the 3,500+ files a fresh `--delete` prunes. Dry-run and adjudicate every delete before you send.
|
|
246
|
+
- **Verify a fixture FILE, never the route.** `curl /` returns `200` even when the site is stale (the SPA serves its shell for any path); proof of a live deploy is a fixture file `200` plus a browser render-check.
|
|
247
|
+
- **Back up before overwriting system files.** `mv Caddyfile Caddyfile.default.bak` — not `rm`.
|
|
248
|
+
|
|
249
|
+
## Current deployments
|
|
250
|
+
|
|
251
|
+
- `ui-kit.exe.xyz` → AdiaUI docs + demos (repo: `chat-ui`, artifacts: `deploy/`, webroot: `/srv/adia-ui/dist/`, secrets: `/etc/adia-ui.env`, service: `adia-ui.service`). Also serves the embedded-app HCC demo at `/apps/embedded-app/app`; updated only via the manual `npm run deploy:site` (`--delete` — use the hardened sequence above).
|
|
252
|
+
|
|
253
|
+
Add new hosts here as they come online.
|
|
254
|
+
|
|
255
|
+
## Pairing with adia-ui-release
|
|
256
|
+
|
|
257
|
+
When `adia-ui-release` mode 8 (EXE deploy) hands off, this playbook owns the
|
|
258
|
+
deploy step. Release engineering builds artifacts; ops deploys them. See
|
|
259
|
+
`adia-ui-release/SKILL.md` §EXE-deploy mode for the upstream hand-off contract.
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
---
|
|
2
|
+
date: 2026-04-27
|
|
3
|
+
coverage: canonical
|
|
4
|
+
peers:
|
|
5
|
+
- decisions-log.md
|
|
6
|
+
- architecture-md.md
|
|
7
|
+
- postmortem-pattern.md
|
|
8
|
+
primary_sources:
|
|
9
|
+
- Michael Nygard, "Documenting Architecture Decisions" (cognitect.com/blog/2011/11/15) — the original ADR essay
|
|
10
|
+
- https://adr.github.io — ADR organization (canonical hub)
|
|
11
|
+
- https://github.com/joelparkerhenderson/architecture-decision-record — Joel Parker Henderson's ADR catalog (most-cited examples library, actively maintained)
|
|
12
|
+
- https://adr.github.io/madr/ — MADR 4.0.0 (released 2024-09-17, "Markdown Any Decision Records")
|
|
13
|
+
- https://medium.com/olzzio/y-statements-10eb07b5a177 — Olaf Zimmermann, Y-statements (SATURN 2012)
|
|
14
|
+
- https://github.com/npryce/adr-tools — adr-tools CLI (lightly maintained)
|
|
15
|
+
- https://learn.microsoft.com/en-us/azure/well-architected/architect-role/architecture-decision-record — ADR / Decision Log canonical meaning
|
|
16
|
+
status: research-verified
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
# Architecture Decision Records (ADRs)
|
|
20
|
+
|
|
21
|
+
> **One ADR captures one architectural decision and its context — *immutably*.** Decisions don't get edited; they get superseded. The newest ADR wins; older ADRs remain as history.
|
|
22
|
+
|
|
23
|
+
## What an ADR is (and isn't)
|
|
24
|
+
|
|
25
|
+
An ADR is a **dated, numbered, status-bearing Markdown file** that captures:
|
|
26
|
+
|
|
27
|
+
- **Why** a decision was made (the problem and constraints)
|
|
28
|
+
- **What** was decided (the chosen path)
|
|
29
|
+
- **What was considered** (the alternatives and why they lost)
|
|
30
|
+
- **Consequences** (the trade-offs the team is signing up for)
|
|
31
|
+
|
|
32
|
+
An ADR is **not** a design doc, RFC, spec, or proposal. Those describe future work; an ADR records a *commitment that has been made*. Once accepted, it is rarely edited — instead, a new ADR supersedes it.
|
|
33
|
+
|
|
34
|
+
## File layout
|
|
35
|
+
|
|
36
|
+
Standard:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
.brain/adrs/
|
|
40
|
+
├── 0001-record-architecture-decisions.md
|
|
41
|
+
├── 0002-use-postgres-not-mysql.md
|
|
42
|
+
├── 0003-rest-not-graphql.md
|
|
43
|
+
├── 0004-deprecate-redis-cache.md
|
|
44
|
+
└── README.md
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Numbering is strictly sequential. Filename pattern: `NNNN-kebab-case-title.md`.
|
|
48
|
+
|
|
49
|
+
## The Nygard format (canonical, ~2011)
|
|
50
|
+
|
|
51
|
+
Michael Nygard's [original 2011 essay](https://www.cognitect.com/blog/2011/11/15/documenting-architecture-decisions) gave the field its first standard:
|
|
52
|
+
|
|
53
|
+
```markdown
|
|
54
|
+
# 1. Record architecture decisions
|
|
55
|
+
|
|
56
|
+
Date: 2026-04-27
|
|
57
|
+
|
|
58
|
+
## Status
|
|
59
|
+
|
|
60
|
+
Accepted
|
|
61
|
+
|
|
62
|
+
## Context
|
|
63
|
+
|
|
64
|
+
What is the issue we're seeing that motivates this decision?
|
|
65
|
+
|
|
66
|
+
## Decision
|
|
67
|
+
|
|
68
|
+
What is the change we're making?
|
|
69
|
+
|
|
70
|
+
## Consequences
|
|
71
|
+
|
|
72
|
+
What becomes easier or harder because of this change?
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Five sections: Title, Date, Status, Context, Decision, Consequences. Short and disciplined.
|
|
76
|
+
|
|
77
|
+
## Status values
|
|
78
|
+
|
|
79
|
+
The set is small and load-bearing:
|
|
80
|
+
|
|
81
|
+
| Status | Meaning |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `Proposed` | Drafted, under discussion, not yet accepted |
|
|
84
|
+
| `Accepted` | Decided. The team is committed. |
|
|
85
|
+
| `Rejected` | Considered and not adopted. Recorded so it doesn't get re-proposed without context. |
|
|
86
|
+
| `Deprecated` | No longer active but not yet replaced |
|
|
87
|
+
| `Superseded by ADR-NNNN` | Replaced by a newer decision |
|
|
88
|
+
|
|
89
|
+
## ADR vs Architecture Decision Log (ADL) — canonical meaning
|
|
90
|
+
|
|
91
|
+
The widely-cited industry view (Microsoft Azure Well-Architected Framework, AWS Prescriptive Guidance, adr.github.io):
|
|
92
|
+
|
|
93
|
+
> "An Architectural Decision Record (ADR) captures a single AD and its rationale; **the collection of ADRs constitutes the decision log.**"
|
|
94
|
+
|
|
95
|
+
So the canonical "decision log" is **the index of all ADRs** in `.brain/adrs/`, not a separate folder. Generate it from filenames + status fields, or maintain `.brain/adrs/README.md` as a hand-written index.
|
|
96
|
+
|
|
97
|
+
Some teams *additionally* maintain a lighter `.brain/decisions/` folder for non-architectural decisions (tooling picks, library swaps, day-to-day commitments). That's a **team convention, not industry standard** — but it's a useful split when ADRs feel too heavyweight for routine choices. The audit should detect both shapes and not flag either as wrong; just note which convention is in play.
|
|
98
|
+
|
|
99
|
+
## MADR 4.0.0 (Markdown Any Decision Records)
|
|
100
|
+
|
|
101
|
+
MADR ([adr.github.io/madr](https://adr.github.io/madr/)) is the current canonical structured variant. Released **4.0.0 on 2024-09-17** with a notable rename: the *A* now stands for *Any* (was *Architectural*) — explicitly broadening scope to non-architectural decisions. Templates: `adr-template.md`, `adr-template-minimal.md`, `adr-template-bare.md`. **YADR** (YAML ADRs) added March 2026.
|
|
102
|
+
|
|
103
|
+
MADR adds:
|
|
104
|
+
|
|
105
|
+
- `Deciders:` (who decided)
|
|
106
|
+
- `Consulted:` / `Informed:` (who else was looped in)
|
|
107
|
+
- More explicit "Considered Options" with pros/cons per option
|
|
108
|
+
|
|
109
|
+
```markdown
|
|
110
|
+
---
|
|
111
|
+
status: accepted
|
|
112
|
+
date: 2026-04-27
|
|
113
|
+
deciders: alice, bob
|
|
114
|
+
consulted: data-team
|
|
115
|
+
informed: engineering-all
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
# Use Postgres, not MySQL
|
|
119
|
+
|
|
120
|
+
## Context and Problem Statement
|
|
121
|
+
|
|
122
|
+
We need a relational database for the user-account service.
|
|
123
|
+
|
|
124
|
+
## Decision Drivers
|
|
125
|
+
|
|
126
|
+
- Mature JSONB support
|
|
127
|
+
- Strong concurrency story
|
|
128
|
+
- Existing team skills
|
|
129
|
+
|
|
130
|
+
## Considered Options
|
|
131
|
+
|
|
132
|
+
- Postgres
|
|
133
|
+
- MySQL
|
|
134
|
+
- SQLite
|
|
135
|
+
|
|
136
|
+
## Decision Outcome
|
|
137
|
+
|
|
138
|
+
Chosen: **Postgres**, because of JSONB + concurrency + team skills.
|
|
139
|
+
|
|
140
|
+
### Consequences
|
|
141
|
+
|
|
142
|
+
- Good: rich query power, strong type system
|
|
143
|
+
- Bad: ops overhead vs SQLite
|
|
144
|
+
|
|
145
|
+
## Pros and Cons of the Options
|
|
146
|
+
|
|
147
|
+
### Postgres
|
|
148
|
+
- Good: ...
|
|
149
|
+
- Bad: ...
|
|
150
|
+
|
|
151
|
+
### MySQL
|
|
152
|
+
- Good: ...
|
|
153
|
+
- Bad: ...
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
MADR's structure scales better to larger teams and audit trails. Nygard's brevity is right for smaller teams. Pick one and stick with it.
|
|
157
|
+
|
|
158
|
+
## Y-statements (Zimmermann)
|
|
159
|
+
|
|
160
|
+
A concise alternative format positioned by adr.github.io as current best practice. Single-sentence form:
|
|
161
|
+
|
|
162
|
+
> *"In the context of `<use case / user story>`, facing `<concern>` we decided for `<option>` and neglected `<other options>`, to achieve `<system qualities>` / `<desired consequences>`, accepting `<downside / undesired consequences>`."*
|
|
163
|
+
|
|
164
|
+
Origin: Olaf Zimmermann, SATURN 2012. Useful as a one-line summary line at the top of a longer ADR, or as the entire ADR for small reversible choices. Pairs well with MADR.
|
|
165
|
+
|
|
166
|
+
## Tooling (April 2026)
|
|
167
|
+
|
|
168
|
+
- **`adr-tools`** by Nat Pryce: https://github.com/npryce/adr-tools — Bash CLI; **lightly maintained** as of April 2026 (no recent releases; MADR-support PR #43 was rejected for maintenance burden). Still functional for the ADR-creation workflow it was built for.
|
|
169
|
+
- **`adr-log`**: generates a Markdown index from a folder of ADRs.
|
|
170
|
+
- **`log4brains`**: web-based ADR browser; check current maintenance state before adopting.
|
|
171
|
+
- **`adr-manager`**: web-UI ADR editor.
|
|
172
|
+
- **For new projects, no tool is required.** `mkdir -p .brain/adrs && cp ~/.adr-templates/madr-minimal.md .brain/adrs/0001-record-architecture-decisions.md` is enough. Tooling adds friction; many teams now skip it.
|
|
173
|
+
|
|
174
|
+
## How AGENTS.md should reference ADRs
|
|
175
|
+
|
|
176
|
+
In the `Where to find things` section:
|
|
177
|
+
|
|
178
|
+
```markdown
|
|
179
|
+
- **Architecture Decision Records:** `.brain/adrs/` — newest-first; read before making architectural changes
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
In the `Memory primitives` section:
|
|
183
|
+
|
|
184
|
+
```markdown
|
|
185
|
+
- **Before making architectural decisions**, read `.brain/adrs/` newest-first. If your proposed change conflicts with an `Accepted` ADR, write a new ADR superseding it; don't silently override.
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Common anti-patterns
|
|
189
|
+
|
|
190
|
+
- **No `.brain/adrs/` folder at all** — decisions live in random PR descriptions, Slack, code comments. Memory fragmentation.
|
|
191
|
+
- **ADRs as RFCs** — files marked `Proposed` that never get marked `Accepted` or `Rejected`. Status drift.
|
|
192
|
+
- **Editing accepted ADRs** — defeats the audit trail. Edits should be supersessions instead.
|
|
193
|
+
- **No `Status:` field** — readers can't tell what's current.
|
|
194
|
+
- **Mixed numbering schemes** — `001-foo.md`, `2-bar.md`, `0003-baz.md`. Pick `NNNN-` four-digit and stick with it.
|
|
195
|
+
- **No ADR for the introduction of ADRs themselves** — the first ADR (`0001`) should be "Record architecture decisions" so the practice itself is decided.
|
|
196
|
+
|
|
197
|
+
## Audit checks for ADRs
|
|
198
|
+
|
|
199
|
+
1. **Folder exists** at `.brain/adrs/` (or close — `.brain/architecture/decisions/`, `adrs/`, etc.).
|
|
200
|
+
2. **Numbering is consistent** (`NNNN-` four-digit, sequential).
|
|
201
|
+
3. **Each ADR has a `Status:` field**.
|
|
202
|
+
4. **No ADRs are in `Proposed` for >30 days** (probably abandoned — flag).
|
|
203
|
+
5. **`.brain/adrs/` is referenced from AGENTS.md**.
|
|
204
|
+
|
|
205
|
+
## Cross-references
|
|
206
|
+
|
|
207
|
+
- Decision log (looser): `decisions-log.md`
|
|
208
|
+
- Architecture overview: `architecture-md.md`
|
|
209
|
+
- Adding ADRs to existing repo: `../recipes/adr-introduction.md`
|
|
210
|
+
- Memory organization: `../recipes/memory-organization.md`
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
---
|
|
2
|
+
date: 2026-04-27
|
|
3
|
+
coverage: canonical
|
|
4
|
+
peers:
|
|
5
|
+
- adr-pattern.md
|
|
6
|
+
- decisions-log.md
|
|
7
|
+
- changelog.md
|
|
8
|
+
primary_sources:
|
|
9
|
+
- https://matklad.github.io/2021/02/06/ARCHITECTURE.md.html — Aleksey Kladov (matklad), "ARCHITECTURE.md" (the canonical pattern essay, Feb 2021)
|
|
10
|
+
- https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/architecture.md — rust-analyzer's ARCHITECTURE.md (the canonical example)
|
|
11
|
+
- https://github.com/sourcegraph/sourcegraph/blob/main/doc/dev/background-information/architecture/index.md — Sourcegraph's adoption of the pattern
|
|
12
|
+
- https://learn.microsoft.com/en-us/azure/well-architected/architect-role/architecture-decision-record — Microsoft Azure WAF on architecture documentation
|
|
13
|
+
status: research-verified
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# ARCHITECTURE.md — current state, in 30 minutes
|
|
17
|
+
|
|
18
|
+
> **ARCHITECTURE.md answers: "I'm new here. Where do I look first?"** Not "what did we decide?" (that's ADRs) and not "what shipped?" (that's CHANGELOG). It is a *map of the codebase as it currently is*, optimized for someone landing in the repo cold.
|
|
19
|
+
|
|
20
|
+
This pattern delivers **Promise 2 (token-and-context-optimized)** by giving an LLM agent a single high-signal entry into the codebase's structure, and **Promise 1 (less-wasteful)** by replacing the scattered "tribal knowledge" that otherwise accumulates in PR comments, Slack threads, and 3-year-old wiki pages.
|
|
21
|
+
|
|
22
|
+
## Origin and canonical source
|
|
23
|
+
|
|
24
|
+
The pattern was named and codified by **Aleksey Kladov** (handle: *matklad*, lead author of rust-analyzer) in the February 2021 blog post [**"ARCHITECTURE.md"**](https://matklad.github.io/2021/02/06/ARCHITECTURE.md.html). The canonical exemplar is rust-analyzer's own [`docs/dev/architecture.md`](https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/architecture.md).
|
|
25
|
+
|
|
26
|
+
Kladov's framing:
|
|
27
|
+
|
|
28
|
+
> "Looking at someone else's code is hard, but very useful sometimes. The best help for an outsider is a single document, a map, which describes the *bird's-eye view* of the project, and explains how to navigate the code."
|
|
29
|
+
|
|
30
|
+
The pattern has spread widely — Sourcegraph, Tantivy, hyperqueue, ripgrep, and many others use a doc by the same name (or `architecture/` folder with the same shape).
|
|
31
|
+
|
|
32
|
+
## What ARCHITECTURE.md *is* (and what it's not)
|
|
33
|
+
|
|
34
|
+
| ARCHITECTURE.md | Not ARCHITECTURE.md |
|
|
35
|
+
|---|---|
|
|
36
|
+
| Current state of the system | History of how it got here (→ git log, ADRs) |
|
|
37
|
+
| Map of the codebase ("Module X lives at `src/x/`") | Decision rationale ("Why did we pick X?" → ADRs) |
|
|
38
|
+
| 30-minute onboarding | Comprehensive technical reference (→ separate docs) |
|
|
39
|
+
| Names directories and the responsibility of each | Lists every file (→ tooling) |
|
|
40
|
+
| Cross-cutting concerns (concurrency model, error handling, lifetime) | API documentation (→ generated docs) |
|
|
41
|
+
| Non-obvious intentional choices ("we deliberately don't use X") | Future plans (→ ROADMAP.md) |
|
|
42
|
+
| Updated when architecture changes | Updated weekly (→ PLAN.md) |
|
|
43
|
+
|
|
44
|
+
The discipline is: **document things that won't change much, that an experienced engineer would still want explained.** Module purpose, layering, where-data-flows-from-input-to-output, how-tests-are-organized, what-not-to-do.
|
|
45
|
+
|
|
46
|
+
## The 30-minute onboarding shape
|
|
47
|
+
|
|
48
|
+
Kladov's recommended sections (with this skill's annotations):
|
|
49
|
+
|
|
50
|
+
### 1. Bird's-eye view
|
|
51
|
+
|
|
52
|
+
One paragraph or one diagram. What does this project *do*? Who calls it, what does it call?
|
|
53
|
+
|
|
54
|
+
```markdown
|
|
55
|
+
## Bird's-eye view
|
|
56
|
+
|
|
57
|
+
`acme-cli` is a Rust binary that reads YAML config from `acme.yaml`,
|
|
58
|
+
queries an HTTPS API, and writes Markdown reports to stdout. It has
|
|
59
|
+
no persistent state. It is invoked from CI in the user's repo.
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
If a diagram clarifies — use one. ASCII boxes are fine; Mermaid is fine; an image is fine. Don't gold-plate.
|
|
63
|
+
|
|
64
|
+
### 2. Code map
|
|
65
|
+
|
|
66
|
+
The load-bearing section. **For each top-level directory, one paragraph: what's in it, what's the responsibility, where the boundaries are.**
|
|
67
|
+
|
|
68
|
+
```markdown
|
|
69
|
+
## Code map
|
|
70
|
+
|
|
71
|
+
### `src/cli/`
|
|
72
|
+
Argument parsing (clap), command dispatch. No business logic — delegates to `src/core/`.
|
|
73
|
+
|
|
74
|
+
### `src/core/`
|
|
75
|
+
The orchestrator. Reads config, fans out to API client, aggregates results. **The only module allowed to depend on both the config layer and the API layer.**
|
|
76
|
+
|
|
77
|
+
### `src/api/`
|
|
78
|
+
HTTP client (reqwest). One module per endpoint group. Adding a new endpoint? Look here.
|
|
79
|
+
|
|
80
|
+
### `tests/`
|
|
81
|
+
Integration tests. Use the `wiremock` fixture, not real HTTP.
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
A reader (human or agent) can immediately answer: *"I want to add a new API endpoint. Where?"*
|
|
85
|
+
|
|
86
|
+
### 3. Cross-cutting concerns
|
|
87
|
+
|
|
88
|
+
Things that span modules and aren't inferable from the code map.
|
|
89
|
+
|
|
90
|
+
```markdown
|
|
91
|
+
## Cross-cutting concerns
|
|
92
|
+
|
|
93
|
+
- **Error handling**: `anyhow::Error` everywhere except `src/api/` (typed errors). See ADR-0007.
|
|
94
|
+
- **Concurrency**: single-threaded by default; `--parallel N` spawns tokio. Only `src/core/parallel.rs` knows async.
|
|
95
|
+
- **Logging**: `tracing`, structured JSON. `RUST_LOG` configures.
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### 4. Non-obvious intentional choices
|
|
99
|
+
|
|
100
|
+
The "we deliberately don't do X" section. Saves future contributors hours.
|
|
101
|
+
|
|
102
|
+
```markdown
|
|
103
|
+
## Things we deliberately don't do
|
|
104
|
+
|
|
105
|
+
- **No async by default.** Tokio startup dominated benchmarks. See ADR-0011.
|
|
106
|
+
- **No plugin system.** Rejected (ADR-0014).
|
|
107
|
+
- **No config format other than YAML.** TOML support was removed in v1.2.0.
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
ARCHITECTURE.md *summarizes* the decision and points at the ADR for *why*.
|
|
111
|
+
|
|
112
|
+
### 5. Where to look first
|
|
113
|
+
|
|
114
|
+
The newcomer's quick-start. Optional but high-value for LLM agents — it's a routing table for common tasks.
|
|
115
|
+
|
|
116
|
+
```markdown
|
|
117
|
+
## Where to look first
|
|
118
|
+
|
|
119
|
+
- **Adding a CLI flag?** `src/cli/args.rs`, then dispatch in `src/cli/mod.rs`.
|
|
120
|
+
- **Adding an API endpoint?** `src/api/`. Mirror an existing endpoint.
|
|
121
|
+
- **Investigating a CI failure?** `tests/integration/` first, then logs.
|
|
122
|
+
- **Performance regression?** `benches/` and `cargo bench`.
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Length and ergonomics
|
|
126
|
+
|
|
127
|
+
Kladov's own rust-analyzer ARCHITECTURE.md is ~600 lines. That's at the upper end. **For most repos, 200–400 lines is right.**
|
|
128
|
+
|
|
129
|
+
Under 100 lines → probably missing the code map.
|
|
130
|
+
Over 800 lines → split. Move detail into per-module READMEs (`src/api/README.md`) and keep ARCHITECTURE.md as the bird's-eye + index.
|
|
131
|
+
|
|
132
|
+
This skill's general guidance: **entry-level docs under ~200 lines, pushed-down detail in subdirectory READMEs.** See `../guidance/context-budget.md`.
|
|
133
|
+
|
|
134
|
+
## Distinction from ADRs
|
|
135
|
+
|
|
136
|
+
The most-confused boundary: ARCHITECTURE.md is **present-tense, mutable, system-wide**; ADRs are **past-tense, immutable, per-decision**. ARCHITECTURE.md answers "Where does X live?"; ADRs answer "Why did we choose X?". ARCHITECTURE.md *links* to ADRs ("see ADR-0007"), never duplicates them.
|
|
137
|
+
|
|
138
|
+
## Update discipline
|
|
139
|
+
|
|
140
|
+
ARCHITECTURE.md goes stale faster than ADRs and slower than PLAN.md. Recommended cadence:
|
|
141
|
+
|
|
142
|
+
1. **PR-level**: any PR that adds, renames, or removes a top-level directory must update ARCHITECTURE.md in the same PR. Enforce with a CI check or a CODEOWNERS rule. See `../recipes/self-healing-hooks.md`.
|
|
143
|
+
2. **Quarterly review**: a maintainer re-reads ARCHITECTURE.md against the current tree and patches drift.
|
|
144
|
+
3. **LLM-on-diff**: when a large refactor lands, run an LLM-on-diff pass against ARCHITECTURE.md to flag suspect sections. See `../audit-patterns/staleness-tooling.md`.
|
|
145
|
+
|
|
146
|
+
## How AGENTS.md links ARCHITECTURE.md
|
|
147
|
+
|
|
148
|
+
In the `Where to find things` section:
|
|
149
|
+
|
|
150
|
+
```markdown
|
|
151
|
+
- **Architecture:** `ARCHITECTURE.md` — start here if you're new to the codebase
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
In the `Memory primitives` section:
|
|
155
|
+
|
|
156
|
+
```markdown
|
|
157
|
+
- **Before making changes that span multiple modules**, read `ARCHITECTURE.md` for the code map and cross-cutting concerns. Architecture-altering changes also require a new ADR.
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
`ARCHITECTURE.md` at repo root is the recommended location (matklad's pattern). Avoid `.brain/architecture/index.md` unless you have a folder full of related docs.
|
|
161
|
+
|
|
162
|
+
## Audit checks
|
|
163
|
+
|
|
164
|
+
1. **File exists** at `/ARCHITECTURE.md` (repo root, per matklad).
|
|
165
|
+
2. **Code map covers all top-level src directories.** Diff `ls src/` against the headings in the code map; missing entries = staleness.
|
|
166
|
+
3. **No directory mentioned in the code map is missing from disk.** Renames or removals that didn't update the doc.
|
|
167
|
+
4. **Length is in 100–800 range.** Both extremes are flagged.
|
|
168
|
+
5. **AGENTS.md references ARCHITECTURE.md**, not just `.brain/`.
|
|
169
|
+
6. **`Last reviewed:` line or YAML `date:` is within the last 180 days.** Older = quarterly review missed.
|
|
170
|
+
|
|
171
|
+
## Common anti-patterns
|
|
172
|
+
|
|
173
|
+
- **No ARCHITECTURE.md** — newcomers and agents navigate by `ls` and pattern-match. Slow.
|
|
174
|
+
- **Feature list, not a code map** — describes what the product does, not how it's built.
|
|
175
|
+
- **History, not present-tense** — narrates evolution. That's a blog post.
|
|
176
|
+
- **Duplicates ADR content** — copy-pasted "why" rationale. Link to the ADR instead.
|
|
177
|
+
- **Alphabetical code map** — group by responsibility (core → adapters → entry-points).
|
|
178
|
+
- **Stale code map** — directories renamed in code, not in the doc. Catch with the audit.
|
|
179
|
+
- **Outsourced to a wiki** — agents can't read Confluence; drift is guaranteed. Keep it in the repo.
|
|
180
|
+
|
|
181
|
+
## Cross-references
|
|
182
|
+
|
|
183
|
+
- ADR pattern (decisions, not state): `adr-pattern.md`
|
|
184
|
+
- Decision log (collection of ADRs): `decisions-log.md`
|
|
185
|
+
- Changelog (shipped, not state): `changelog.md`
|
|
186
|
+
- Plan / roadmap (planned, not state): `plan-roadmap.md`
|
|
187
|
+
- Self-healing PR-gate hooks: `../recipes/self-healing-hooks.md`
|
|
188
|
+
- LLM-on-diff staleness detection: `../audit-patterns/staleness-tooling.md`
|
|
189
|
+
- Context budget guidance (200-line target): `../guidance/context-budget.md`
|
|
190
|
+
- AGENTS.md "Where to find things" section: `../standards/agents-md-spec.md`
|