diff --git a/convention/progressive-disclosure.md b/convention/progressive-disclosure.md
new file mode 100644
index 0000000..095f88c
--- /dev/null
+++ b/convention/progressive-disclosure.md
@@ -0,0 +1,61 @@
+---
+type: convention
+title: Progressive Disclosure for Codebase Navigation
+summary: A working convention for AI agents (and developers) navigating large codebases without pre-reading everything. Answers "how do I get oriented efficiently without burning context on files I don't need?"
+tags:
+ - type/convention
+ - domain/software-engineering
+ - domain/ai-agents
+scope: global
+last_updated: 2026-06-27
+---
+
+# Progressive Disclosure for Codebase Navigation
+
+Context is finite. Loading everything upfront wastes it on irrelevant files and crowds out the work. Progressive disclosure is the discipline of loading only what you need, when you need it — oriented by routing files, not by exploration.
+
+## Core Principles
+
+**1. Start local.**
+Begin with only the files present in the current working directory or immediate task scope. Do not recursively load parent directories, adjacent modules, or the full project tree before doing anything. Most tasks are resolvable from immediate context.
+
+**2. Routing files over exploration.**
+Each directory should have a routing file (e.g., `CLAUDE.md`, `.claude.md`, `README.md`) that explains the directory's purpose, what the key artifacts are, and which files to read next for specific needs. When uncertain, read the routing file — not the directory contents at large.
+
+**3. Retrieve context selectively.**
+When a gap appears (something is referenced but not locally defined), open only the one file the routing file points to for that gap. Resolve one gap at a time. Do not open several files speculatively to "just see what's there."
+
+**4. Stop when clarity is achieved.**
+Do not continue loading files once you have enough to proceed. The test is: "Can I do the next step?" — not "Do I understand the whole system?" Over-navigation is as costly as under-navigation; it just fails more slowly.
+
+**5. Prefer structured artifacts over prose.**
+When both a structured format (JSON, schema, type definitions, AST) and a descriptive format (markdown, comments) exist, reach for the structured one first. It answers questions faster and wastes fewer tokens.
+
+## Patterns
+
+**Layer-by-layer access.** Structure context access in tiers: (1) immediate local files always loaded, (2) routing file consulted on uncertainty, (3) specific referenced file fetched to resolve the gap, (4) deeper documentation fetched only when the card/reference file is insufficient. Each layer has a budget; never skip straight to the deep layer.
+
+**Routing file as the interface contract.** A good routing file names its directory's purpose, lists the key files with a one-line description of what each resolves, and explicitly names what to avoid (generated files, legacy files, large media). When a directory lacks a routing file, creating one is the highest-leverage documentation contribution.
+
+**Explicit gap identification.** Before opening any new file, name the gap: "I need to know X, which is referenced in Y." This prevents reflexive navigation. If you can't name what you're looking for, you're not ready to look.
+
+**Format preference by information density.** Structured formats (`.json`, `.rb`, type signatures, schema files) answer "what is this shaped like?" in fewer tokens than prose explanations. Reach for them first when the question is structural. Reach for prose when the question is intent or rationale.
+
+## Anti-Patterns
+
+- **Loading entire directories at session start** — wastes context on irrelevant files; the right file often becomes clear only after the first tool call
+- **Recursive exploration without a named gap** — "let me just look around" is expensive and rarely necessary; explore with a question in mind
+- **Reading markdown when a schema exists** — prose descriptions of structure are slower to parse and more ambiguous than the structure itself
+- **Fetching multiple context files simultaneously** — resolving several gaps at once compounds uncertainty; resolve sequentially so each fetch is informed by the previous result
+- **Skipping the routing file and guessing** — directory contents look similar across projects; routing files encode the conventions specific to this one; guessing wastes turns
+- **Treating "I don't know where X is" as license to read everything** — it's license to check the nearest routing file, then ask if still unclear
+
+## Exceptions
+
+**New project orientation.** On first entry to an unfamiliar project, a single broader read of the top-level routing file and directory listing is warranted. This is a bounded exception — one pass to identify the routing layer, then progressive disclosure applies.
+
+**Small projects / flat layouts.** When the entire project is 5–10 files with no routing layer, loading all of them upfront is cheaper than the overhead of the progressive discipline. Apply PD proportionally to project size.
+
+**Explicit search tasks.** "Find every place X is used" requires breadth-first access by definition. Progressive disclosure governs orientation and feature work; it doesn't apply to grep-style search tasks where the goal is coverage.
+
+**When routing files are absent or stale.** If a project has no routing files, invest in creating them before doing deep work. If routing files are stale, update them as part of the task. The convention only works if the routing layer is maintained.
diff --git a/convention/sandi-metz-code-philosophy.md b/convention/sandi-metz-code-philosophy.md
new file mode 100644
index 0000000..c74eb9f
--- /dev/null
+++ b/convention/sandi-metz-code-philosophy.md
@@ -0,0 +1,79 @@
+---
+type: convention
+title: Sandi Metz Code Philosophy
+summary: Distills Sandi Metz's POODR and 99 Bottles principles into actionable rules for OO design. Answers "how should I structure this code, and when is abstraction appropriate?"
+tags:
+ - type/convention
+ - domain/software-design
+scope: global
+last_updated: 2026-06-27
+---
+
+# Sandi Metz Code Philosophy
+
+A philosophy of designing for change, not for cleverness. The goal is code that is easy to change later — which requires keeping objects isolated, messages explicit, and abstractions earned.
+
+## Core Principles
+
+**1. Make the change easy, then make the easy change.**
+Before adding behavior, ask whether the current structure makes the change easy. If not, restructure first. This separates the two kinds of work and prevents mixed-purpose commits that are hard to reason about.
+
+**2. Duplication is cheaper than the wrong abstraction.**
+Only extract when you have three real, concrete examples and can name the concept precisely. A vague name is a signal the abstraction isn't ready. Wrong abstractions attract more wrong code; tolerate duplication until the pattern is genuinely clear.
+
+**3. Every method/function does one thing.**
+If you need "and" to describe what it does, split it. Metz's rule: ≤5 lines in Ruby. Adapted for other languages: ≤10 lines in JS. Single-purpose methods compose cleanly; multi-purpose methods resist change.
+
+**4. Classes have one reason to change (Single Responsibility).**
+A class that changes for two different reasons is two responsibilities tangled together. Separate them so a change in one domain can't break an unrelated feature.
+
+**5. Design messages first, classes second.**
+Objects are defined by the messages they respond to, not the data they hold. Start by deciding what message you need to send and what you need back — the class structure follows from that.
+
+**6. Open for extension, closed for modification.**
+`if`/`switch`/`case` chains that dispatch on type or ID violate this: each new case requires editing existing code. Replace with a registry (plain hash/object) so adding a case is data, not code change.
+
+**7. Depend on abstractions, not concretions (Dependency Injection).**
+Inject collaborators explicitly rather than instantiating them inside methods. This makes tests trivial (pass a fake) and keeps modules decoupled from each other's concrete implementations.
+
+## The Enumerated Rules (Sandi Metz's Actual Rules)
+
+These are the four specific limits Metz published — meant to be followed strictly until you fully internalize why:
+
+1. Classes: ≤100 lines
+2. Methods: ≤5 lines (Ruby; adapt proportionally to language)
+3. Method parameters: ≤4 (and prefer keyword/named args)
+4. Controllers: instantiate only one object
+
+Breaking any of these is a smell worth investigating, not a veto — but the burden of proof is on the break.
+
+## Patterns
+
+**Shameless Green first.** When starting a new feature, get to passing tests as fast as possible. Duplication is explicitly acceptable at this stage. Refactor *after* green, not before — premature abstraction when the shape is uncertain locks in the wrong structure.
+
+**Flocking Rules for refactoring.** When pulling duplication into an abstraction: (1) find the most similar things, (2) find the smallest difference, (3) remove only that difference. One transformation at a time; stay green throughout. Big leaps break the test-feedback loop and introduce risk.
+
+**Composition over inheritance.** Prefer `has-a` to `is-a`. Inheritance locks two classes into a hierarchy that's expensive to exit. Composition keeps the relationship explicit and replaceable.
+
+**Law of Demeter: only talk to immediate neighbors.** `a.b.c.d` is a tell — you're coupled to the entire chain. Ask the immediate collaborator for what you need; let it traverse its own graph.
+
+## Anti-Patterns
+
+- **Class or method name has "And" or "Manager"** → multiple responsibilities; split it
+- **`obj.foo.bar.baz` chains** → Law of Demeter violation; you're coupled to internal structure
+- **`case`/`if` switching on type or id** → Open/Closed violation; use a registry
+- **Extracting an abstraction from one or two examples** → wrong abstraction in the making
+- **Instantiating dependencies inside methods** → untestable; inject instead
+- **Silent catch blocks or swallowed errors** → violates single responsibility of error handling
+- **Inheriting from a class just to share code** → composition violation; extract a module/mixin or shared object instead
+- **Subtype that changes exceptions or return types** → Liskov Substitution violation; callers can't safely substitute
+
+## Exceptions
+
+**Language/runtime adaptation.** The 5-line rule is for Ruby's expressive syntax. In JS/TS, 10 lines is a reasonable target. In Go with explicit error returns, a stricter reading breaks everything. Apply the *spirit* (single purpose, fits on a screen) proportionally.
+
+**Shameless Green is time-limited.** Duplication is acceptable while finding the shape. Once you have three examples and a name, the refactor is overdue.
+
+**Performance-critical paths.** Clean composition sometimes adds allocation or indirection at hot paths. Profile first; don't preemptively break good design for speculative speed.
+
+**Pragmatic team calibration.** If your team hasn't read POODR, enforce the enumerated rules mechanically first — they create the right pressure without requiring philosophical buy-in upfront.
diff --git a/howto/airtable-mcp-setup.md b/howto/airtable-mcp-setup.md
new file mode 100644
index 0000000..f231187
--- /dev/null
+++ b/howto/airtable-mcp-setup.md
@@ -0,0 +1,148 @@
+---
+type: howto
+title: "Airtable MCP Setup Guide"
+summary: Integrate the Airtable MCP server into a Claude Code project using project-local scope. Enables Claude Code to read and write Airtable data while keeping token overhead zero in unrelated projects.
+tags:
+ - type/howto
+ - tool/airtable
+ - tool/claude-code
+ - tool/mcp
+ - domain/dev
+scope: global
+last_updated: 2026-06-27
+update_note: experience-driven
+---
+
+# Airtable MCP Setup Guide
+
+This guide sets up the Airtable MCP server in a Claude Code project using **project-local scope** — so MCP only loads when you're working in this project, not every session. Use it whenever you're starting a new project that reads or writes Airtable data via Claude Code.
+
+## Prerequisites
+
+- [ ] Claude Code CLI installed and working (`claude --version`)
+- [ ] Airtable Personal Access Token (PAT) with `data.records:read` scope minimum; add write scopes if the project needs CRUD
+- [ ] PAT stored in an environment variable (e.g. `AIRTABLE_PAT` in `~/.zshrc`) — do not hardcode
+- [ ] `npx` available (ships with Node.js)
+
+## Steps
+
+### Step 1: Add Airtable MCP at project-local scope
+
+From the project root, register the MCP server with project-local scope:
+
+```bash
+claude mcp add --scope local --transport stdio airtable \
+ --env AIRTABLE_API_KEY=${YOUR_PAT_ENV_VAR} \
+ -- npx -y airtable-mcp-server
+```
+
+Replace `YOUR_PAT_ENV_VAR` with the actual environment variable name holding your PAT.
+
+**Why project-local scope?** MCP servers consume Claude tokens whether or not they're being used. Global scope means Airtable MCP loads in every project session. Local scope (`--scope local`) keeps it isolated to this project directory and stores the config privately (outside version control).
+
+**Expected result:** Command exits cleanly. Verify:
+
+```bash
+claude mcp list
+# airtable should appear in the list
+```
+
+### Step 2: Configure permissions in .claude/settings.local.json
+
+Create or update `.claude/settings.local.json` to lock down which operations Claude Code can perform:
+
+```json
+{
+ "permissions": {
+ "allow": [
+ "mcp__airtable__describe_table",
+ "mcp__airtable__list_tables",
+ "mcp__airtable__list_records",
+ "mcp__airtable__get_record",
+ "WebFetch(domain:airtable.com)",
+ "WebFetch(domain:support.airtable.com)"
+ ],
+ "deny": [
+ "mcp__airtable__create_record(base_id:YOUR_PROD_BASE_ID:*)",
+ "mcp__airtable__update_record(base_id:YOUR_PROD_BASE_ID:*)",
+ "mcp__airtable__delete_record(base_id:YOUR_PROD_BASE_ID:*)"
+ ]
+ }
+}
+```
+
+Replace `YOUR_PROD_BASE_ID` with the actual production base ID (format: `appXXXXXXXXXXXXXX`).
+
+**Key points:**
+- `allow` — explicitly permit read operations and Airtable docs access
+- `deny` — block write/update/delete on the production base by base ID
+- Development/sandbox base: gets full CRUD by default (not in deny list)
+- `settings.local.json` is private and should be in `.gitignore`
+
+**Expected result:** File created. On next Claude Code session, write attempts to the production base will be blocked.
+
+### Step 3: Add project-assets reference doc
+
+Create `docs/reference/project-assets.md` to track discovered table IDs and field conventions — Airtable table IDs change if tables are recreated, so document them as you find them:
+
+```markdown
+# Project Assets Reference
+
+## Airtable Configuration
+
+### Bases
+- **Dev base ID**: `appXXXX` (full CRUD — safe to experiment)
+- **Prod base ID**: `appXXXX` (READ-ONLY — live data)
+
+### Tables
+
+| Table Name | Table ID | Description |
+|------------|----------|-------------|
+| *TBD* | *TBD* | *TBD* |
+
+### Common field patterns
+- `*_id` — record ID fields
+- `*_at` — timestamp fields
+- `*_status` — status/state fields
+```
+
+**Expected result:** Living reference doc that grows as you explore the base.
+
+## Verification
+
+Run these checks at the end of setup:
+
+```bash
+# 1. Confirm env var is set
+echo $YOUR_PAT_ENV_VAR
+
+# 2. Confirm MCP is registered
+claude mcp list
+
+# 3. In a Claude Code session: ask Claude to list all tables in the dev base
+# Expected: tables appear without a permission prompt
+
+# 4. In a Claude Code session: ask Claude to create a record in the prod base
+# Expected: blocked by permissions in settings.local.json
+```
+
+## Gotchas
+
+**"Airtable MCP not available" in session**
+- Check env var is exported in shell profile, not just set: `export AIRTABLE_PAT=...`
+- Restart terminal after adding the variable; Claude Code inherits the shell environment at launch
+
+**"Permission denied" on dev base writes**
+- Double-check the deny rule: it should reference the prod base ID only
+- If you accidentally put the dev base ID in deny, remove it from `settings.local.json`
+
+**PAT scope errors**
+- PAT must have `data.records:read` for reads; add `data.records:write` for create/update/delete
+- Regenerate the PAT in Airtable → Account → Developer Hub if scopes need updating
+
+**npx slow on first run**
+- `npx -y airtable-mcp-server` downloads the package on first use; subsequent runs use the cache
+
+## Related
+
+- [[vault-conventions]] — frontmatter and tag taxonomy for this vault
diff --git a/howto/design-mode-workflow.md b/howto/design-mode-workflow.md
new file mode 100644
index 0000000..8266b4c
--- /dev/null
+++ b/howto/design-mode-workflow.md
@@ -0,0 +1,168 @@
+---
+type: howto
+title: "Design Mode Workflow"
+summary: Run the design-mode iterative design replication workflow to extract a design system from an existing site and use it as a constraint for building new UIs. Produces three foundation artifacts — reference HTML, style guide, and Tailwind config.
+tags:
+ - type/howto
+ - tool/tailwind
+ - domain/design
+ - domain/dev
+scope: global
+last_updated: 2026-06-27
+---
+
+# Design Mode Workflow
+
+Use this when you want to replicate an existing design's visual language and encode it as reusable tokens for building new UIs. The workflow runs inside the `design-mode` project. Suitable for any project where you've identified a target design to draw from.
+
+## Prerequisites
+
+- [ ] `design-mode` project cloned and accessible
+- [ ] Target site accessible in browser (for CSS extraction)
+- [ ] Screenshot of target design saved locally
+- [ ] Local dev server available (`python -m http.server` or VS Code Live Server) — needed for Tailwind dynamic imports in Phase 1
+
+## The Flow
+
+```
+Target Design (inspiration)
+ ↓
+[1] Extract CSS ──→ Raw styles to assets/raw-styles.txt
+ ↓
+[2] /design-to-html ──→ Produces 3 foundation artifacts:
+ │ • reference.html (validation)
+ │ • style-guide.md (for humans)
+ │ • tailwind.config.js (for machines)
+ ↓
+[3] Iterate ──→ 2-3 rounds until reference matches target
+ ↓
+[4] /componentize ──→ Style base components (future capability)
+ ↓
+[5] /design ──→ Uses config + components + style guide for creative freedom
+```
+
+## Steps
+
+### Step 1: Create project folder
+
+```bash
+mkdir -p projects/[name]/assets
+```
+
+**Expected result:** Per-project directory ready to hold all artifacts for this design.
+
+### Step 2: Extract CSS from target site
+
+Open the target site in browser DevTools. Use VisBug or the Computed Styles panel to capture design token values (colors, spacing, fonts, border radii). Save the raw dump:
+
+```
+projects/[name]/assets/raw-styles.txt
+```
+
+Optionally compress the raw output first:
+
+```bash
+python tools/compress-styles.py
+```
+
+**Expected result:** A condensed CSS values file that `/design-to-html` can parse efficiently.
+
+### Step 3: Run /design-to-html
+
+Provide the command with:
+- Screenshot of the target design
+- Path to the extracted CSS file
+
+The command produces three artifacts in the project folder:
+
+| Artifact | Purpose |
+|----------|---------|
+| `reference.html` | Pixel-accurate validation page — compare side-by-side with screenshot |
+| `style-guide.md` | Human-readable intent and patterns — when/why to use each token |
+| `tailwind.config.js` | Machine-readable theme tokens — single source of truth for all design values |
+
+**Expected result:** Three files written to `projects/[name]/`.
+
+### Step 4: Iterate until reference matches target
+
+Compare `reference.html` side-by-side with your target screenshot. Run `/design-to-html` again with corrections until the match is satisfying — typically 2–3 rounds. Each iteration refines all three artifacts in sync.
+
+**Expected result:** `reference.html` visually matches the target close enough that differences are not visible at a glance.
+
+### Step 5: Build new UIs with /design
+
+Once the foundation artifacts are stable, use `/design` for new UI work:
+
+```
+/design [description of the UI you want to build]
+```
+
+The command uses `tailwind.config.js` (tokens) + `style-guide.md` (usage intent) as constraints, giving creative freedom within the established design language.
+
+For component work, `/componentize` (future capability) styles base components so they inherit config tokens automatically.
+
+**Expected result:** New UI output that looks consistent with the extracted design system without manually specifying colors or spacing.
+
+## Validation Checkpoints
+
+| Step | Checkpoint |
+|------|------------|
+| `reference.html` | Side-by-side with target: can you spot differences? |
+| `style-guide.md` | Generate content WITHOUT reference in context — does it match? |
+| `tailwind.config.js` | Drop into a project; do components render correctly? |
+| Styled components | Look right with theme tokens applied? |
+| Final build | Resize browser — is responsive behavior correct? |
+
+## Tailwind Config: Two-Phase Approach
+
+**Phase 1 — Design iteration (dynamic import):** HTML files import the config at runtime via ES modules. No build step; config changes apply instantly to all HTML files.
+
+```html
+
+
+```
+
+Requires a local dev server (browser module imports don't work over `file://`).
+
+**Phase 2 — Production (CLI build):** When ready to ship, compile to static CSS:
+
+```bash
+npx tailwindcss -c tailwind.config.js -o dist/styles.css --minify
+```
+
+Replace the CDN script tags with ``. Default to Phase 1 during design; switch to Phase 2 only at production handoff.
+
+## Commands Reference
+
+| Command | Purpose |
+|---------|---------|
+| `/design-to-html` | Screenshot + CSS → three foundation artifacts |
+| `/design` | Description + theme → new UI (uses config + style guide) |
+| `/componentize` | Style base components using theme tokens (future) |
+| `python tools/compress-styles.py` | Compress raw CSS before passing to design-to-html |
+
+## Project Files
+
+| File | Purpose |
+|------|---------|
+| `CLAUDE.md` | Pipeline overview for Claude Code sessions |
+| `process-guide.md` | Quick reference (source of this howto) |
+| `style-guide-template.md` | Template for style guides |
+| `tailwind-config-template.js` | Template for Tailwind config |
+| `tools/compress-styles.py` | CSS compression tool |
+| `projects/[name]/` | Per-project artifact folder |
+
+## Tips
+
+- **Config is palette, style guide is instructor** — config says *what* values exist; style guide says *when and why* to use them
+- **One viewport at a time** — get desktop tokens right first, then handle responsive
+- **Test without reference** — if the style guide can't reproduce the look when used alone (without reference.html in context), it's incomplete
+- **Tokens are viewport-agnostic** — colors/fonts/spacing don't change at breakpoints; layout does
+- **Avoid over-fitting** — the goal is theme inspiration, not pixel-perfect cloning of every element
+
+## Related
+
+- [[vault-conventions]] — frontmatter and tag taxonomy for this vault
diff --git a/reference/agent-orchestration-cookbook.md b/reference/agent-orchestration-cookbook.md
new file mode 100644
index 0000000..f56a59d
--- /dev/null
+++ b/reference/agent-orchestration-cookbook.md
@@ -0,0 +1,225 @@
+---
+type: reference
+subtype: cookbook
+title: Agent Orchestration Cookbook
+summary: Concrete implementation examples for multi-agent orchestration — prompt templates, token budgets, error recovery, and common gotchas. Companion to the patterns hub.
+tags:
+ - type/reference
+ - domain/ai-agents
+ - domain/orchestration
+scope: global
+last_updated: 2026-06-27
+related:
+ - reference/agent-orchestration-patterns
+---
+
+# Agent Orchestration Cookbook
+
+**Purpose**: Concrete examples, prompt templates, and gotchas for implementing the patterns in [[reference/agent-orchestration-patterns]].
+
+## Phase Templates
+
+### Phase 1 — Inventory Agent Prompt
+
+```markdown
+Discover all [items] matching [criteria].
+
+Use filesystem commands only (ls, find, glob) — do NOT read file contents.
+
+Return JSON:
+{
+ "items": [
+ {
+ "name": "[identifier]",
+ "source_path": "...",
+ "target_path": "...",
+ "output_path": "reports/[name].md"
+ }
+ ],
+ "count": N
+}
+```
+
+Key constraint: **no file reading** in inventory. Just paths. Keeps agent context small (~200 token return).
+
+### Phase 2 — Specialist Agent Prompt
+
+```markdown
+Process these [N] [item type]: [name1, name2, ...]
+
+For each item:
+1. Read source: {source_path}
+2. Read target: {target_path}
+3. [Transform / analyze / validate]
+4. Write audit to: {output_path}
+
+Decision criteria:
+- Clear action needed → execute → status: "updated"
+- No change needed → skip → status: "skipped"
+- Ambiguous / risky → don't modify → status: "ambiguous" + reason
+
+Return JSON array:
+[{"name": "...", "status": "updated|skipped|ambiguous", "changes": [...], "reason": "..."}]
+```
+
+Spawn all specialist agents **in a single message** for parallel execution.
+
+### Phase 3 — Consolidation Agent Prompt
+
+```markdown
+Read all reports in [output_dir]/*.md
+Treat missing reports as errors.
+
+Generate:
+## Summary
+- Total: X | Updated: Y | Skipped: Z | Ambiguous: W | Errors: E
+
+## Needs Review
+[For each ambiguous item: name + reason + options]
+
+## Errors
+[For each error: name + what failed]
+
+## Cleanup
+[List temp files ready for removal after user approval]
+```
+
+### Phase 4 — Cleanup (Main Conversation)
+
+Run directly — no agent needed. Simple bash: `rm -rf reports/[task]/`
+
+---
+
+## Token Budget Examples
+
+### 12-Item Migration (3 Specialists)
+
+| Phase | Main Context Δ | Agent Contexts |
+|---|---|---|
+| Inventory | +200 tokens | ~25K (1 agent) |
+| Processing (3 × 4 items) | +600 tokens (3 × 200) | ~90K (3 × 30K) |
+| Consolidation | +300 tokens | ~27K (reads 12 reports) |
+| Cleanup | +100 tokens | 0 |
+| **Total main** | **~1,200 tokens** | — |
+| **Total agents** | — | **~142K tokens** |
+
+Naive (main reads 12 components directly): ~60K+ tokens in main, no isolation.
+
+### Batching Math
+
+```
+Tool tax per agent: ~20–25K tokens (fixed)
+Work per item: ~5K tokens (variable)
+
+20 items, 1:1: 20 × (25K + 5K) = 600K tokens
+20 items, batched: 4 × (25K + 25K) = 200K tokens ← 67% savings
+```
+
+The "2-of-3 similarity rule" for grouping: items share input format + transformation + output format → batch together.
+
+---
+
+## Error Recovery Patterns
+
+### Resilient Batch (Pseudocode)
+
+```python
+results = []
+for agent in batch:
+ result = await agent.complete()
+ if result.ok:
+ results.append(result.data)
+ else:
+ results.append({
+ "item": agent.item,
+ "status": "error",
+ "error": result.error_message
+ })
+# All results — success and failure — go to consolidation
+```
+
+### Manifest-Based Recovery
+
+For long-running or interruptible orchestrations, write a manifest after each batch:
+
+```json
+{
+ "task": "migration",
+ "started": "2026-06-27T10:00:00Z",
+ "batches": [
+ {"id": 1, "status": "complete", "items": ["a", "b", "c"]},
+ {"id": 2, "status": "in_progress", "items": ["d", "e"]}
+ ],
+ "pending": ["f", "g", "h"]
+}
+```
+
+Recovery agent reads manifest → skips completed → resumes from `in_progress`.
+
+### Idempotent Processing
+
+Add a check-before-modify guard in every specialist prompt:
+
+```markdown
+Before modifying {target_path}:
+1. Check if transformation already applied (e.g., look for marker X).
+2. If already present → skip → status: "already_done"
+3. If not present → proceed.
+```
+
+Safe to re-run without double-processing.
+
+---
+
+## Common Gotchas
+
+| Gotcha | Symptom | Fix |
+|---|---|---|
+| Agent IDs not returned programmatically | Can't resume from code | Use manifest files for continuity instead of `resume` |
+| Rate limits with large parallel batches | API errors mid-batch | Cap parallel agents at 5–8; batch sequentially |
+| Verbose agent responses bloating main context | Main context grows despite delegation | Enforce JSON-only return; write prose to files |
+| Inventory agent reads files "to check" | Inventory takes 10× longer | Explicitly prohibit file reading in inventory prompt |
+| Ambiguous items silently skipped | Work lost, no trace | Require `status: "ambiguous"` + `reason` field in return schema |
+| Re-running overwrites completed work | Duplicate or corrupted output | Add idempotency check (see above) |
+
+---
+
+## Structural Variations
+
+### When to Use Sequential vs. Parallel Specialists
+
+| Condition | Pattern |
+|---|---|
+| Items have dependencies (A must finish before B) | Sequential |
+| Cost is the primary constraint | Sequential |
+| Items are independent; speed matters | Parallel |
+| Failures must be isolated from each other | Parallel |
+
+### Nesting Depth
+
+Keep agents **flat** — peers, not hierarchies. Nested agents (agent spawns agent spawns agent) compound overhead and complicate error tracing. The only valid hierarchy is: main → specialists → (optional) consolidator.
+
+### When Not to Use Agents
+
+- Task requires fewer than 3 tool calls → use tools directly.
+- Single file read + simple edit → use tools directly.
+- Items depend heavily on shared mutable state → agents are the wrong primitive.
+
+---
+
+## Glossary
+
+| Term | Definition |
+|---|---|
+| Tool Tax | Fixed ~20–25K token overhead per agent before any work is done |
+| Specialist | An agent that processes multiple similar items, paying tool tax once |
+| Batch | Group of agents spawned in parallel (5–8 max to respect rate limits) |
+| Manifest | JSON file tracking completed/pending/failed items for recovery |
+| Flattened | Orchestration where agents are peers at one level, not nested |
+| Idempotent | Safe to re-run — check-before-modify prevents double-processing |
+
+---
+
+## Related
+
+- [[reference/agent-orchestration-patterns]] — decision framework, core principles, anti-patterns table
diff --git a/reference/agent-orchestration-patterns.md b/reference/agent-orchestration-patterns.md
new file mode 100644
index 0000000..a1217af
--- /dev/null
+++ b/reference/agent-orchestration-patterns.md
@@ -0,0 +1,150 @@
+---
+type: reference
+subtype: pattern/framework
+title: Agent Orchestration Patterns
+summary: Principles and decision framework for coordinating multiple AI subagents without exhausting the main context window. Answers "when to delegate and how to structure it."
+tags:
+ - type/reference
+ - domain/ai-agents
+ - domain/orchestration
+scope: global
+last_updated: 2026-06-27
+related:
+ - reference/agent-orchestration-cookbook
+---
+
+# Agent Orchestration Patterns
+
+**Purpose**: When should you spawn agents vs. use tools directly, and how do you structure multi-agent work to keep token costs under control?
+
+## Core Principle
+
+Agents are **disposable contexts**: each subprocess starts fresh, does its work, writes output to files, then disappears. Only the minimal return value lands in the main conversation. Heavy file reading happens in agent context — never in main context.
+
+## Decision Framework
+
+```
+How many items?
+ │
+ ├─ 1–3 ──────────────────────► Direct tools only
+ │ Tool tax > benefit
+ │
+ ├─ 4–10 ─────────────────────► Single specialist agent
+ │ Can batch by type? ──► Yes: 1 agent handles all
+ │ No: 2–3 typed agents
+ │
+ ├─ 11–30 ────────────────────► 2–4 specialist agents
+ │ Speed critical? ─────────► Parallel specialists
+ │ Cost critical? ─────────► Sequential specialists
+ │
+ └─ 30+ ──────────────────────► Specialists + phase rotation
+ └─ Re-evaluate: is agent pattern right here?
+```
+
+### Parallelism vs. Cost Tradeoff
+
+| Approach | Relative Cost | Speed | Best When |
+|---|---|---|---|
+| 1 agent per item | Very high (N × tool tax) | Fast | Never — this is an anti-pattern |
+| Batched specialists (5–8/agent) | Low | Medium | Default choice |
+| Sequential specialist | Lowest | Slow | Cost-critical, interruptible tasks |
+| Parallel specialists | Medium | Fast | Speed-critical, failures must isolate |
+
+## The Patterns
+
+### 1. Disposable Context
+**When**: Any time you need to read N files and process them.
+**Why**: Each agent's file reads vanish when the agent finishes; only the return value (200–400 tokens) stays in main context.
+**Anti-example**: Main conversation reads 20 files → context grows to 100K+ tokens and never shrinks.
+
+### 2. Minimal Prompt, File-Specified Paths
+**When**: Always.
+**Why**: Agents read what they need; do not pre-load them with full project context.
+**Rule**: Prompt = task description + paths + decision criteria + return schema. No more.
+
+```
+Update {component} with Alpine.js.
+- Source: {jsx_path}
+- Target: {erb_path}
+- Audit: {audit_path}
+Decision: clear→update, ambiguous→skip+note, no-op→skip
+Return: {"status": "updated|skipped|ambiguous", "changes": [...]}
+```
+
+### 3. State via Files, Not Memory
+**When**: Agents need to share data or pass results forward.
+**Why**: Agents cannot communicate directly; files are the coordination bus.
+**Pattern**: Each agent writes `reports/{item}.md`; a consolidation agent reads `reports/*.md`.
+
+### 4. Single-Message Parallel Spawn
+**When**: You want agents to run concurrently.
+**Why**: Multiple Task tool calls in one message → parallel. Separate messages → sequential.
+**Rule**: Prepare all agent prompts, then issue all Task calls in a single message.
+
+### 5. Batch by Similarity (2-of-3 Rule)
+**When**: Deciding how to group items across specialists.
+**Why**: Similar items share setup cost; the "tool tax" (~20–25K tokens) is paid once per agent.
+**Rule**: Items are similar enough to batch if they share 2 of 3: input format, transformation logic, output format.
+**Batch size**: 5–8 items per specialist (avoids rate limits; keeps per-agent context manageable).
+
+### 6. Four-Phase Structure
+**When**: Any multi-item orchestration task.
+
+| Phase | Who | What | Returns |
+|---|---|---|---|
+| Inventory | Agent (haiku) | Discovery only — no file reading | JSON item list |
+| Processing | Specialist agents (sonnet) | Read, transform, write reports | Minimal JSON status |
+| Consolidation | Agent (sonnet) | Read all reports, generate summary | Executive summary |
+| Cleanup | Main conversation (direct tools) | `rm`, `mv` | — |
+
+## Model Selection
+
+| Task | Model |
+|---|---|
+| Inventory, file discovery | haiku |
+| Simple transforms, mechanical | haiku |
+| Analysis, code generation | sonnet (default) |
+| Architecture decisions | sonnet |
+
+## Anti-Patterns
+
+| Anti-Pattern | Problem | Fix |
+|---|---|---|
+| 1 agent per item | N × tool tax; 20 items = 550K tokens | Batch 5–8 items per specialist |
+| Main reads all files | Context grows monotonically; no recovery | Delegate reads to agents |
+| Over-sharing context in prompt | Wasted tokens on unused info | Paths + instructions only |
+| Verbose agent responses | Bloats main context with detail | Return JSON status; write detail to files |
+| Skip consolidation phase | User must parse N raw responses | Always run a summary agent |
+| Silent failure on error | Items silently lost | Log errors, continue batch, report in summary |
+
+## Error Handling Rules
+
+1. Let other agents in the batch **complete** — don't abort on one failure.
+2. Return structured error: `{"item": "X", "status": "error", "error": "reason"}`.
+3. Consolidation agent treats missing reports as errors.
+4. Report failures in summary; let the user decide on retry.
+5. Design for **idempotency** — re-running a specialist should be safe (check-before-modify).
+
+## Context Budget Reference
+
+| Component | Tokens |
+|---|---|
+| System tools (fixed overhead) | ~15–20K |
+| CLAUDE.md / project files | ~3–5K |
+| Agent prompt | ~1–2K |
+| **Minimum per agent** | **~20–25K** |
+
+**20-item example**:
+- Naive (1:1): 20 agents × 30K = **600K tokens**
+- Batched (4 specialists × 5 items): 4 × 37K = **148K tokens** (75% reduction)
+
+## Known Limitations
+
+- Task tool does **not** return agent IDs programmatically (visible in UI only).
+- No API to list active/completed agents.
+- `resume` parameter requires manual ID tracking — not suitable for automated orchestration.
+- **Workaround**: track progress via manifest files; design for idempotency.
+
+## Related
+
+- [[reference/agent-orchestration-cookbook]] — concrete walkthroughs, token budgets, error recovery patterns
diff --git a/vault-conventions.md b/vault-conventions.md
index d599d76..3189e17 100644
--- a/vault-conventions.md
+++ b/vault-conventions.md
@@ -128,6 +128,64 @@ Pre-migration notes use **legacy flat tags** (`plan`, `research`, `log`, etc.)
facet-namespaced forms coexist during incremental migration (ADR-013). Do not "fix" old notes on
sight without a migration plan. New notes must use facet-namespaced tags from creation.
+## Note Types (Authoring Guide)
+
+This section defines the three primary note types used for durable, evergreen knowledge. For the `type/` tag vocabulary and full type list, see [Note Types (`type/` facet)](#note-types-type-facet) above.
+
+### convention
+**Question this answers:** "When I encounter [situation X], what rule or pattern should I follow, and why?" A convention is a repeatable rule, principle, or decision framework meant to guide repeated choices in a specific context.
+**Value gate:** Longevity (still relevant in 6-12 months?) + Reusability (applies beyond the project that produced it?)
+**Mutability:** stable knowledge
+**Template:** (not yet created)
+**Sub-templates:** none
+
+### reference
+**Question this answers:** "What are the established rules, structures, setup requirements, or role definitions I need to know to [make decisions | integrate with a system | understand who does what]?" A reference note is authoritative lookup material that supports decision-making or implementation.
+**Value gate:** Longevity (still relevant in 6-12 months?) + Reusability (applies beyond the project that produced it?)
+**Mutability:** stable knowledge (except API integration refs, which may need `last_reviewed` date)
+**Template:** (not yet created)
+**Sub-templates:** pattern/framework, API integration, role definitions, design rules, navigation/index
+
+### howto
+**Question this answers:** "How do I accomplish [specific, repeatable task]?" A howto covers concrete, actionable steps — setup, configuration, deployment, migration, or troubleshooting. The reader wants to DO the thing, not understand it theoretically.
+**Value gate:** Longevity (still relevant in 6-12 months?) + Reusability (applies beyond the project that produced it?)
+**Mutability:** stable knowledge, but experience-driven updates apply — when a session executes the procedure and finds a discrepancy, update the note rather than relying on a review date.
+**Template:** (not yet created)
+**Sub-templates:** none
+
+**Note on directories:** The standard directories for these types are `convention/`, `reference/`, and `howto/` at the vault root. These directories do not yet exist; notes of these types currently live at the vault root until directory structure is established.
+
+## Standard Frontmatter Schema
+
+All notes use this frontmatter block. Type-specific additions are noted inline.
+
+```yaml
+---
+type: [convention|reference|howto]
+title: [Human-readable title]
+summary: [1-2 sentences answering "what question does this note answer?"]
+tags:
+ - type/[convention|reference|howto]
+ - domain/[field] # e.g., domain/rails, domain/ai-agents, domain/design
+ - tool/[tool] # if tool-specific; omit if not
+ - client/[client] # if client-specific; omit if general
+ - project/[project] # if project-specific; omit if general
+scope: [global|project|client]
+last_updated: YYYY-MM-DD
+# For mutable facts (API integration refs, billing rates):
+# last_reviewed: YYYY-MM-DD
+---
+```
+
+**Field notes:**
+- `type` — machine-readable; mirrors the `type/` tag. Required.
+- `title` — human-readable display name. Required.
+- `summary` — 1-2 sentences that answer the note's core question. Used by Graphify and SessionStart injection. Required; never defer.
+- `tags` — at minimum `type/` and `scope/` are required (see Tag Taxonomy above). Add `domain/`, `tool/`, `client/`, `project/` as applicable.
+- `scope` — `global` (applies across all work) or `project` (specific to one client/project). Required.
+- `last_updated` — date of last substantive edit. Required.
+- `last_reviewed` — optional; add only for mutable facts (API integration refs, billing rates, role definitions that change).
+
## Related
- [[CLAUDE]]