feat(#293): Rex domain-aware code review — handbooks/domain/ Stage 1#294
Conversation
…tage 1
Adds a fourth handbook bucket so Rex can load domain-specific review
notes (GitHub EMU semantics, Stripe webhook validation, SSO SAML claim
shapes) scoped to PRs that touch the domain's code. Trigger lives in
YAML frontmatter at the top of each handbook:
---
paths:
- "scripts/github-emu-migration/**"
- "**/emu-*.{ts,js,py}"
---
ENFORCEMENT: blocking
# Handbook: GitHub EMU migration safety
If `paths:` is absent or empty, the handbook loads always — same shape
as the existing architecture/general buckets (foundational rule with
no path boundary). If present, Rex loads only when the PR diff matches
at least one glob.
The matcher is a self-contained Python script in Rex's prompt — handles
**, *, ?, and {a,b,c} brace alternation correctly. The earlier shell-
case attempt silently failed on both ** (case patterns don't support
globstar) and on {ts,js} (brace expansion happens at command-parse
time, not pattern-match time); tested 8 cases incl. the originally
broken ones before shipping.
Custom-handbooks layer (split-portfolio adopters) gets the same
convention transparently via portfolio_custom_handbooks_dir — no
separate wiring.
Stages 2 (/codify-rule for capturing Rex-misses) and 3 (/enrich-domain
for mining recent PRs) are tracked in the ticket's ACs as follow-up
scope; this MVP is the path-glob discovery foundation those skills
layer on.
- Add handbooks/domain/README.md — operator authoring convention
- Add docs/agdr/AgDR-0037-rex-domain-handbooks.md — design rationale
- Update .claude/agents/code-reviewer.md § 8 — fourth bucket row +
frontmatter-parse section + Python matcher reference
- Update handbooks/README.md — document the new bucket + note why no
framework samples ship under it
Closes #293
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…per review
The first cut invoked python3 once per candidate handbook. In sandboxed
environments where every Bash call surfaces a permission prompt, that's
O(N) prompts in handbook count — and Rex already runs ~6-8 prompts per
review for the surrounding gh/find/printf calls. An adopter with 10
domain handbooks would have seen 10 extra prompts on every review.
Batched shape:
printf '%s\n' "$DIFF_FILES" | python3 /tmp/match_handbooks.py "${DOMAIN_HBS[@]}"
Reads handbook paths from argv, diff from stdin, prints loadable paths
to stdout. One python3 invocation regardless of N. Same matching logic;
the per-handbook should_load() function moved inside the script's main()
loop.
Tested against 4 scenarios (matched + always-load mix, no-match, brace
alternation, empty argv) before commit.
AgDR-0037 § "Consequences" updated with the matcher-invocation-shape
rationale so future readers see why batched rather than naive.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
atlas-apex
left a comment
There was a problem hiding this comment.
Code Review: PR #294
Commit: d25c23330bbc17615dc38737ffe2bbcf4a28829d
Summary
Adds a fourth handbook bucket handbooks/domain/<area>/ with opt-in paths: frontmatter so I (Rex) can load domain-specific review notes scoped to PRs that touch the domain's code. The matcher is a self-contained Python script in my own prompt; this is a meta-PR modifying my agent definition. The amended HEAD batches the matcher to one python3 invocation regardless of handbook count, which keeps per-review permission-prompt surface constant.
I ran the matcher against 18 stress cases locally — 8 from the PR description plus 10 additional edge cases. The core contract is sound. Two soft issues worth flagging (neither blocks merge).
Checklist Results
- Architecture & Design: Pass — fourth-bucket extension is consistent with the path-mirroring discovery convention already established for architecture / general / language. Custom-handbooks layer reused without separate wiring.
- Code Quality: Pass with nits — see "Issues Found" #1 and #2 below.
- Testing: Pass — 8 documented test cases pre-commit; I re-ran them all green + 10 additional edge cases. One edge case (trailing inline YAML comment) under-loads silently, see #1.
- Security: Pass — no secrets, no auth/crypto/user-data paths. Python matcher reads files passed via argv and stdin; no shell injection surface.
- Performance: Pass — the batched refactor is the right shape. O(1) python3 invocations per review regardless of N handbooks.
- PR Description & Glossary: Pass — Glossary has 7 entries covering Rex, domain handbook,
paths:frontmatter, glob-star, brace alternation, custom-handbooks layer, AgDR. - Technical Decisions (AgDR):Pass — AgDR-0037 linked in PR body, covers the four-option comparison (frontmatter / sidecar / config / hard-code), the chosen-option rationale, and the batched-matcher invocation shape in Consequences.
- Adopter Handbooks: Pass — public always-load handbooks evaluated; none triggered findings (this is a docs + prompt PR; no domain/application/migration paths touched).
Issues Found
1. nit — Python matcher: trailing inline YAML comment after a quoted glob is captured literally as part of the glob.
The list-item regex at line 305 of .claude/agents/code-reviewer.md is ^\s*-\s*["\']?(.*?)["\']?\s*$. When the YAML line is:
- "src/foo/**" # foundational rule.*? matches up to the last optional-quote alternative which falls through to the trailing \s*$, capturing src/foo/**" # foundational rule as the glob. The handbook then silently fails to load for any real PR (the bogus regex never matches), which is precisely the failure mode the AgDR's stated principle warns against: "under-loading silently is worse than over-loading visibly."
Verified locally: printf 'src/foo/x.ts\n' | python3 match_handbooks.py edgeG.md returns nothing, where edgeG.md has the line above.
Fix sketch (one-line):
m = re.match(r'^\s*-\s*["\']?([^"\'\s#]+(?:[^"\'#]*[^"\'\s#])?)["\']?\s*(?:#.*)?$', line)Or simpler — strip # ... from line before the regex match. This is the only documented-YAML-feature gap; if you'd rather defer, file a follow-up.
2. nit — **/foo.ts over-matches notfoo.ts at the root because ** translates to .* without a path-boundary anchor.
glob_to_regex('**/important.ts') emits ^.*important\.ts$, which matches both important.ts (correct) and notimportant.ts (incorrect — ** should consume directories + a separator, not arbitrary characters). The prompt documents the semantics as "shell pathname expansion semantics" (line 232), and bash globbing with globstar would not match notimportant.ts.
This is over-loading visibly rather than under-loading silently, which is the right failure direction per the AgDR. The downside: an over-broad load may cite a handbook on PRs where it's irrelevant, which trains operators to ignore the handbook section. Probably fine to ship and refine later if it bites.
Handbook Findings
No public always-load handbook flags fire on this diff:
handbooks/architecture/migration-safety.md(blocking) — N/A (no migration paths in diff).handbooks/architecture/clean-architecture-layers.md(advisory) — N/A (nodomain/,application/,infrastructure/code touched).handbooks/general/commit-message-quality.md(advisory) — both commits have substantive WHY bodies, ticket refs, andCo-Authored-By:lines. Subject lines under 70 chars (the d97fa1b headline gets truncated inghoutput but the actual subject is fine). Pass.
No language handbooks load — no .ts/.py/.go/.rs files changed.
No domain handbooks exist yet (this PR creates the bucket itself).
Suggestions
- AgDR-0037 § Artifacts placeholder. Line 83 still says
PR me2resh/apexyard#XXX — implementation. Fill in#294before merge so the AgDR is self-contained for future archaeology. - AgDR-0037 § Negative bullet 3 wording. Says "Rex silently skips the handbook" on malformed globs. The actual contract (Decision step 4 in the prompt) is to default to always-load with a visible
⚠warning. The AgDR wording is slightly more pessimistic than the implementation. Either tighten the AgDR ("Rex over-loads visibly with a warning") or accept it as describing the worst-case in pathological inputs. - Future-work pointer. The matcher script is embedded inline in the prompt at
.claude/agents/code-reviewer.mdlines 238-322. Next time it changes, a sibling test file at.claude/agents/tests/test_match_handbooks.pywould let CI catch regressions like #1 above. Out of scope for this PR but worth a follow-up ticket. /tmp/match_handbooks.pylifecycle. The discovery loop assumes the script lives at/tmp/match_handbooks.py. The prompt doesn't say how it gets there — the implicit contract is "I write it via Bash heredoc on first use per review." Worth noting once in the prompt so future-me doesn't forget.
Verdict
APPROVED
The refactor to batched matching is the right shape and addresses the per-handbook permission-prompt cost concern as described. The Python matcher is robust across 18 stress cases. The two nits above don't block merge — #1 is a real silent-failure mode but only triggers on a YAML pattern most operators won't write, and #2 is the preferred error direction per the AgDR's own stated principle. Both deserve follow-up tickets if you want to harden the matcher.
I checked the bash discovery loop, the ${PRIV:+...} empty-PRIV expansion, the README.md skip filter, the array assembly, and the empty-array guard. All bash-correct (zsh would choke on the unmatched glob handbooks/domain/*/, but the rest of the prompt's discovery shape already assumes bash semantics).
The AgDR conforms to the framework template, the design-rationale narrative is honest about the parser-surface tradeoff, and the four-option table covers the obvious alternatives.
Reviewed by Rex (Code Reviewer Agent)
Reviewed commit: d25c23330bbc17615dc38737ffe2bbcf4a28829d
Rex reviewed PR #294 (APPROVED) and flagged two real bugs in the prompt I shipped, plus two AgDR doc nits. Fixing all four before merge so the "Rex caught a bug in Rex's own prompt and we shipped it anyway" story doesn't end up in the merge log. 1. Inline-comment regex bug — handbooks with `- "src/foo/**" # comment` captured the comment text as part of the glob and silently failed to match anything. The exact under-loads-silently failure mode AgDR-0037 warns against. Fix: pre-strip ` # ...` tails (YAML's comment rule for whitespace-prefixed `#`) before the list-item regex. 2. `**/foo.ts` over-matched `notfoo.ts` — `**` was translating to `.*` without a path-boundary anchor, so the regex `^.*foo\.ts$` matched any string ending in `foo.ts`. Fix: translate `**/` to `(?:.*/)?` which is bash globstar semantics (zero or more path segments ending in `/`, OR empty for root). `notfoo.ts` no longer matches `**/foo.ts`; `foo.ts` and `src/sub/foo.ts` still do. 3. AgDR-0037 § Artifacts: `#XXX` → `#294` so the AgDR is self- contained for archaeology. 4. AgDR-0037 § Negative bullet 3 wording: previous text said "silently skips" then immediately contradicted itself in the mitigation ("degrades to always-load"). Rewrote to be consistent with the implementation's actual contract — always-load + visible warning, never silent skip. Tested all 8 original cases + 6 new ones (2 for finding 1, 2 for finding 2, plus the original `**/notfoo` regression). All 14 pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
atlas-apex
left a comment
There was a problem hiding this comment.
Code Review (re-review): PR #294 @ 1ed1930e815e1ca30bf1513a4f2cfe9ccf1737e9
Re-reviewing the four fixes from the prior nits at d25c233.
Verification of the four fixes
1. _STRIP_COMMENT inline-comment regex — ✓ verified.
Tested 10 edge cases — whitespace-prefixed #, # without preceding whitespace (literal hash in path), comment-only line, blank line, indented comment, paths: with inline comment, etc. All behave as the doc comment promises. The doc comment correctly calls out the "a literal # in a (rare) quoted glob survives" semantics — accurate for # without preceding whitespace. (Edge edge case: a quoted glob with literal <space>#<space> inside would still get the tail stripped — but that's a path with a space and a hash, which is bizarre enough that YAML quoting issues dominate anyway; not worth handling.)
2. **/ over-match — ✓ verified, regression fixed.
The new (?:.*/)? translation correctly handles all 24 cases I threw at it:
**/foo.tsmatchesfoo.ts,a/foo.ts,a/b/foo.ts,a/b/c/foo.ts✓**/foo.tsdoes NOT matchnotfoo.ts,foo.tsx,a/notfoo.ts✓ ← the regression casesrc/**/foo.tsmatchessrc/foo.ts(zero segments between),src/a/foo.ts,src/a/b/foo.ts✓src/**/foo.tsdoes NOT matchsrcfoo.ts✓- Trailing
**(e.g.scripts/github-emu-migration/**) matches one or many segments ✓ **alone matches anything ✓**.ts(without/) stays permissive via the fallback branch — matches bothfoo.tsanda/b/c.ts, rejectsfoo.txt✓- Brace alternation in
**/context (**/emu-*.{ts,js,py}) correctly excludesnotemu-foo.tsandfoo.rb✓
3. AgDR § Artifacts #XXX → #294. ✓ fixed.
4. AgDR § Negative bullet 3 rewrite — mostly accurate, one sub-claim is still off (nit, below).
Issues Found
None blocking.
Suggestions (nit, optional)
nit: The AgDR § Negative bullet 3 says:
"...The matcher's parse path applies this default at every branch — missing
paths:, emptypaths: [], unterminated frontmatter, and exceptions during file read all fall through toreturn True."
…but the actual OSError branch does the opposite:
try:
with open(hb) as f: lines = f.readlines()
except OSError:
return False # silent skip — contradicts the bullet's claimI verified all six branches:
| Branch | Returns | Matches AgDR claim? |
|---|---|---|
OSError on file open |
False (silent skip) |
No — AgDR claims True |
| Empty file (no lines) | True |
✓ |
No frontmatter (line 1 ≠ ---) |
True |
✓ |
Unterminated frontmatter (no closing ---) |
True |
✓ |
Missing paths: key |
True |
✓ |
Empty paths: [] |
True |
✓ |
In practice, OSError is rare — the discovery loop already gates on [ -f "$hb" ], so this only fires on a race (file deleted between find + open, permission flipped mid-review). But the AgDR's "asymmetry is deliberate" paragraph explicitly argues that under-loading silently is the failure mode to avoid, and this one branch contradicts it.
Two ways to fix in a follow-up (your call):
- Code change: change
except OSError: return Falsetoexcept OSError: return True(with an optionalprint(f"⚠ handbook unreadable, defaulting to always-load: {hb}", file=sys.stderr)so it doesn't degrade silently). - Doc change: scope the AgDR bullet to "exceptions during frontmatter parsing (unterminated, unparseable YAML) — file-read errors are treated as missing handbooks and silently skipped". This is also defensible (a missing file genuinely IS a different case from a malformed file).
Either is fine. The other six branches are correct, the matcher is sound, and the four operator-flagged fixes all work.
nit (related): The contract in step 4 of the prompt says "emit a one-line warning to your review output: ⚠ handbook frontmatter unparseable, defaulting to always-load: <path>" — but the matcher itself prints nothing to stderr. The warning is left implicitly as the agent's responsibility (Rex's prompt has the contract; Rex should surface ⚠ when it sees a degraded-path handbook). Could be tightened by either adding print(f"⚠ ...", file=sys.stderr) inside the matcher, or by surfacing the contract more explicitly in § "Handbook Findings" so the agent knows to emit it. Not load-bearing for v1.
Checklist Results
- ✅ Architecture & Design: Pass
- ✅ Code Quality: Pass — Python matcher is clean, well-commented; doc comment for
_STRIP_COMMENTaccurately describes the rule - ✅ Testing: Pass — operator ran 14 tests locally (8 original + 6 new); I ran 24 glob translations + 10 comment-strip cases + 8 should_load branches and reproduced the operator's results
- ✅ Security: N/A (markdown + docs only)
- ✅ Performance: Pass — batched matcher invocation keeps Bash call count constant; per-review cost is one
python3call regardless of handbook count - ✅ PR Description & Glossary: Pass — glossary covers Rex / domain handbook /
paths:frontmatter / glob-star / brace alternation / custom-handbooks / AgDR - ✅ Technical Decisions (AgDR): Pass — AgDR-0037 covers Options A-D with explicit trade-offs
- ✅ Adopter Handbooks: N/A (no
handbooks/orcustom-handbooks/triggered by this diff)
Verdict
APPROVED — the four fixes from the prior review all land correctly. The remaining nit on AgDR Negative bullet 3 + the matcher-emits-no-warning detail are small enough to ship-then-fix; neither blocks merge. Re-review marker updated.
🤖 Reviewed by Rex (Code Reviewer Agent)
📌 Reviewed commit: 1ed1930e815e1ca30bf1513a4f2cfe9ccf1737e9
Rex's re-review on 1ed1930 flagged that the AgDR's "always-load on degraded paths" claim included exceptions-during-file-read, but the code returns False on OSError (race condition between bash existence check and Python open). The code behavior is correct — a vanished candidate file is more honestly "absent" than "always-load". Tightening the AgDR to call that out explicitly, with the rationale. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
atlas-apex
left a comment
There was a problem hiding this comment.
Code Review: PR #294 (re-review at new HEAD)
Commit: 27052da3b7f1087a210f34812f3b4b99085e7798
Previous approved commit: 1ed1930
Summary
One-line doc clarification in AgDR-0037 § Negative bullet 3 addressing the inconsistency flagged in the prior re-review. The AgDR text now accurately describes the matcher's behavior at every degraded branch.
Diff scope verified
The only change between 1ed1930 (previously APPROVED) and 27052da is a single-bullet rewrite in docs/agdr/AgDR-0037-rex-domain-handbooks.md. No code changes, no surprises.
Bullet wording vs code behavior
Cross-checking the new AgDR text against should_load() in .claude/agents/code-reviewer.md:
| Branch | AgDR says | Code does | Match |
|---|---|---|---|
OSError on open() |
return False (rationale: vanished file is honestly "absent") | except OSError: return False |
✓ |
No frontmatter (line 1 ≠ ---) |
"no frontmatter at all" → return True | if not lines or lines[0].rstrip() != '---': return True |
✓ |
| Unterminated frontmatter | "unterminated frontmatter" → return True | if fm_end is None: return True |
✓ |
Missing paths: key |
"missing paths: key" → return True |
if not globs: return True |
✓ |
Empty paths: [] |
"empty paths: []" → return True |
empty inner → empty globs → if not globs: return True |
✓ |
The rationale for the OSError carve-out is defensible: a file that vanished between the bash existence check and the Python read is genuinely absent from the candidate list; treating it as "always-load" would be silently fabricating a handbook-load. Returning False here is the right call.
Checklist Results
- Architecture & Design: Pass
- Code Quality: Pass (no code change)
- Testing: Pass (no code change; behavior verified by inspection)
- Security: Pass
- Performance: Pass
- PR Description & Glossary: Pass
- Technical Decisions (AgDR): Pass — AgDR-0037 is the artifact being clarified
- Adopter Handbooks: N/A
Issues Found
None.
Suggestions
None — the clarification is surgical and the rationale is sound.
Verdict
APPROVED (posted as comment because GitHub blocks self-approval; approval marker written for the merge gate)
Reviewed by Rex (Code Reviewer Agent)
Reviewed commit: 27052da3b7f1087a210f34812f3b4b99085e7798
…294) * feat(#293): Rex domain-aware code review — handbooks/domain/<area>/ Stage 1 Adds a fourth handbook bucket so Rex can load domain-specific review notes (GitHub EMU semantics, Stripe webhook validation, SSO SAML claim shapes) scoped to PRs that touch the domain's code. Trigger lives in YAML frontmatter at the top of each handbook: --- paths: - "scripts/github-emu-migration/**" - "**/emu-*.{ts,js,py}" --- ENFORCEMENT: blocking # Handbook: GitHub EMU migration safety If `paths:` is absent or empty, the handbook loads always — same shape as the existing architecture/general buckets (foundational rule with no path boundary). If present, Rex loads only when the PR diff matches at least one glob. The matcher is a self-contained Python script in Rex's prompt — handles **, *, ?, and {a,b,c} brace alternation correctly. The earlier shell- case attempt silently failed on both ** (case patterns don't support globstar) and on {ts,js} (brace expansion happens at command-parse time, not pattern-match time); tested 8 cases incl. the originally broken ones before shipping. Custom-handbooks layer (split-portfolio adopters) gets the same convention transparently via portfolio_custom_handbooks_dir — no separate wiring. Stages 2 (/codify-rule for capturing Rex-misses) and 3 (/enrich-domain for mining recent PRs) are tracked in the ticket's ACs as follow-up scope; this MVP is the path-glob discovery foundation those skills layer on. - Add handbooks/domain/README.md — operator authoring convention - Add docs/agdr/AgDR-0037-rex-domain-handbooks.md — design rationale - Update .claude/agents/code-reviewer.md § 8 — fourth bucket row + frontmatter-parse section + Python matcher reference - Update handbooks/README.md — document the new bucket + note why no framework samples ship under it Closes #293 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(#293): batch the domain-handbook matcher — one python3 call per review The first cut invoked python3 once per candidate handbook. In sandboxed environments where every Bash call surfaces a permission prompt, that's O(N) prompts in handbook count — and Rex already runs ~6-8 prompts per review for the surrounding gh/find/printf calls. An adopter with 10 domain handbooks would have seen 10 extra prompts on every review. Batched shape: printf '%s\n' "$DIFF_FILES" | python3 /tmp/match_handbooks.py "${DOMAIN_HBS[@]}" Reads handbook paths from argv, diff from stdin, prints loadable paths to stdout. One python3 invocation regardless of N. Same matching logic; the per-handbook should_load() function moved inside the script's main() loop. Tested against 4 scenarios (matched + always-load mix, no-match, brace alternation, empty argv) before commit. AgDR-0037 § "Consequences" updated with the matcher-invocation-shape rationale so future readers see why batched rather than naive. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(#293): address Rex's findings on the domain-handbook matcher Rex reviewed PR #294 (APPROVED) and flagged two real bugs in the prompt I shipped, plus two AgDR doc nits. Fixing all four before merge so the "Rex caught a bug in Rex's own prompt and we shipped it anyway" story doesn't end up in the merge log. 1. Inline-comment regex bug — handbooks with `- "src/foo/**" # comment` captured the comment text as part of the glob and silently failed to match anything. The exact under-loads-silently failure mode AgDR-0037 warns against. Fix: pre-strip ` # ...` tails (YAML's comment rule for whitespace-prefixed `#`) before the list-item regex. 2. `**/foo.ts` over-matched `notfoo.ts` — `**` was translating to `.*` without a path-boundary anchor, so the regex `^.*foo\.ts$` matched any string ending in `foo.ts`. Fix: translate `**/` to `(?:.*/)?` which is bash globstar semantics (zero or more path segments ending in `/`, OR empty for root). `notfoo.ts` no longer matches `**/foo.ts`; `foo.ts` and `src/sub/foo.ts` still do. 3. AgDR-0037 § Artifacts: `#XXX` → `#294` so the AgDR is self- contained for archaeology. 4. AgDR-0037 § Negative bullet 3 wording: previous text said "silently skips" then immediately contradicted itself in the mitigation ("degrades to always-load"). Rewrote to be consistent with the implementation's actual contract — always-load + visible warning, never silent skip. Tested all 8 original cases + 6 new ones (2 for finding 1, 2 for finding 2, plus the original `**/notfoo` regression). All 14 pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(#293): clarify OSError contract in AgDR-0037 (Rex re-review nit) Rex's re-review on dbffb81 flagged that the AgDR's "always-load on degraded paths" claim included exceptions-during-file-read, but the code returns False on OSError (race condition between bash existence check and Python open). The code behavior is correct — a vanished candidate file is more honestly "absent" than "always-load". Tightening the AgDR to call that out explicitly, with the rationale. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: me2resh <ahmed.abdelaliem@gmail.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
handbooks/domain/<area>/for domain-specific review knowledge (GitHub EMU, Stripe webhooks, SSO SAML, etc.) — the kind of gotchas a code/ticket/framework-rules review can't catch.paths:field of globs). Handbooks withoutpaths:load always (foundational rules); handbooks withpaths:load only when the PR diff matches at least one glob.**(cross-segment),*(within-segment),?, and{a,b,c}brace alternation. Replaces an earlier broken shell-case approach (shellcasepatterns silently fail on both**globstar and{}alternation)./codify-rulefor capturing misses) and 3 (/enrich-domainfor mining recent PRs) tracked in [Feature] Rex domain-aware code review — handbooks/domain/<area>/ glob with diff-match loading + lessons-learned capture #293's ACs as follow-up tickets; this MVP is the foundation.Why
Rex today reviews PRs with code + ticket + framework rules + adopter handbooks. None of those sources carry domain knowledge of the specific component. Concrete miss flagged 2026-05-19: Rex reviewed a GitHub EMU migration script and missed gotchas Copilot caught (EMU enterprises can't access private forks of public repos). Same shape recurs across Stripe webhooks, SSO claim handling, tenant-isolation rules.
Adding a generic handbook in
architecture/orgeneral/for every domain rule pollutes those buckets and burns review tokens on every PR. Thepaths:frontmatter lets domain rules stay narrow without operator config drift — the trigger lives next to the rule.Design rationale and option comparison:
docs/agdr/AgDR-0037-rex-domain-handbooks.md.Testing
The Python matcher was validated against 8 test cases before commit:
paths:key → always load{ts,js,py}matches.ts.py.rbpaths: []empty list → always loadTo verify locally:
Adopter-side smoke (after merge):
Out of scope (deferred)
/codify-ruleand/enrich-domainskills tracked in [Feature] Rex domain-aware code review — handbooks/domain/<area>/ glob with diff-match loading + lessons-learned capture #293's ACs; implemented as separate follow-up tickets so this Stage 1 foundation can land first.Glossary
.claude/agents/code-reviewer.md) — automated first-pass review on every PRhandbooks/domain/<area>/capturing review knowledge about a specific problem domain (EMU migration, Stripe webhooks, etc.)paths:frontmatterpaths: ['scripts/github-emu-migration/**']). Absent or empty → always load**)scripts/**/sync.tsmatchesscripts/a/b/sync.ts). Distinct from*which matches only within one segment{a,b,c})*.{ts,js,py}matches.ts,.js, or.pyfiles)<private>/custom-handbooks/<dim>/...tree introduced in framework #243 for split-portfolio adopters to ship private handbooks alongside the public ones — now getsdomain/<area>/discovery transparentlyCloses #293