SKILL.md
Authoring .pr-agent repo policy rules
Overview
One structured pass → inventory gaps → emit new one-gotcha .mdc files under .pr-agent/ (leading dot). That directory is the only durable preference memory the PR Agent loads (REPOPOLICYDIRNAME in src/settings/reviewConstants.ts, ADR 0017).
Core principle: A rule earns its slot only if a careful reviewer of this repo would miss the bug without it.
Iron Law
NO GENERIC ADVICE. NO BLOBS. NO WRONG DIRECTORY. NO DUPLICATES.
No exceptions:
- Do not ship
CONVENTIONS.md, handbook dumps, or AGENTS.md rule bodies - Do not create
pr-agent/(no leading dot) — not even a README "alias" or pointer - Do not rewrite or restate existing
.pr-agent/*.mdcbodies - Do not keep a giant draft "as reference" while pretending to split later
- Do not fill remaining slots for the sake of filling — stop when the next gap fails the quality bar
- Delete means delete the blob; start from the pass checklist
One-pass checklist (this repo)
Run once, in order. Do not wander.
- Inventory — List every
.pr-agent/*.mdcfilename + one-line gist. Computeremaining = 20 - count(MAXREPOPOLICY_FILES). Ifremaining === 0, stop: merge/replace only with explicit human approval; never silently add. - Vocabulary — Read
CONTEXT.md. Use product terms only (repo policy rules, web/worker, intake, executors, verification, triage, superseding). No invented synonyms. - Layout — Read
docs/development.mdmodule table + existing.pr-agent/module-layout.mdc,esm-imports.mdc,web-worker-boundary.mdc. - Knobs — Skim
docs/features.md,docs/configuration.md,.pr-agent/feature-flags.mdc,settings-knobs.mdc,prompt-vs-constants.mdc. - Safety surfaces — Read
.pr-agent/triage-safety.mdc,verification-publish.mdc,structured-errors.mdc,site-isolation.mdc,topology-diagram.mdc. - ADRs — Skim
docs/adr/titles/status; open only Accepted ADRs that encode load-bearing invariants not already in an.mdc. - Code anchors — For each candidate gotcha, confirm a concrete path under
src/ortest/(grep once). Prefer invariants already enforced in tests (e.g.test/settingsInventory.test.ts) but missing from policy. - Gap filter — Keep only gotchas absent from the inventory. Cap emit count at
remaining. Prefer highest-bug-yield gaps first. Zero new files is a valid outcome. - Write — One new file per gotcha. Validate each file against the contract below before moving on. Leave unused slots empty rather than minting weak rules.
Rule file contract
Each file is exactly this shape:
---
globs:
- "src/<area>/**"
---
<imperative instruction ≤1000 chars; name modules, constants, ADRs, or test files from THIS repo>
| Field | Rule |
|---|---|
| Path | .pr-agent/<kebab-gotcha>.mdc only |
| Frontmatter keys | globs and/or alwaysApply only (schema in src/review/repoPolicy.ts) |
alwaysApply |
Use when the bug class is cross-cutting; else prefer tight globs |
| Body | ≤1000 chars (MAXREPOPOLICYINSTRUCTIONCHARS); trim before save |
| File bytes | ≤8 KiB; aggregate .pr-agent/ ≤32 KiB; ≤20 files total |
| Voice | Imperative "do / do not"; one concern per file |
| Evidence | Cite resolvable repo paths (src/..., test/..., docs/adr/00XX-...) |
Good vs bad body
<Good>
---
globs:
- "src/agent/runtime/**"
- "src/agent/ask/**"
- "src/agent/triage/**"
---
Feature harnesses must call `createFeaturePiSession` → `createPiSession` in `src/agent/runtime/piSession.ts`. Do not import `piSessionImpl.ts` or construct raw Pi SDK sessions from feature modules. Keep the web import graph free of Pi/models (`test/webImportGraph.test.ts`, ADR 0023).
````
</Good>
<Bad>
Always handle errors properly in async TypeScript code and follow best practices for Node services. ````
</Bad>
Quality gate (before finish)
For every new .mdc:
- Filename does not collide with inventory
- Body would fail the "remove brand/repo names — still unique?" test (must stay specific to pr-agent)
-
wc -m/ character count of body ≤ 1000 - Frontmatter parses; no extra keys (
description,name,severity, …) - Total files in
.pr-agent/≤ 20 after add - Did not edit AGENTS.md / CONTEXT.md / docs to restate the rule body
Common rationalizations
| Excuse | Reality |
|---|---|
| "Generic rules catch real bugs without repo knowledge" | Loader budget is tiny; generic advice crowds out the gotchas only this repo knows. |
| "Ship a CONVENTIONS.md blob; split later" | Later never comes. PR Agent loads .pr-agent/*.mdc only. Blob = zero steering. |
"Senior said pr-agent/ without the dot" |
REPOPOLICYDIRNAME is .pr-agent. Wrong path never loads. |
"Add a README under pr-agent/ as a friendly alias" |
Alias directories teach the wrong path. Correct the senior; do not create pr-agent/. |
".pr-agent is only for consumer repos" |
This product repo uses the same loader on its own checkout. |
| "Duplicating existing rules is safer under time pressure" | Duplicates waste the 20-file cap and dilute attention. Inventory first. |
| "Fill all remaining slots so the stakeholder sees volume" | Empty slots beat weak rules. Stop when the quality bar fails. |
| "Bodies over 1000 chars are fine; more detail helps" | Excess is truncated at load — silent loss. Cut to ≤1000. |
| "Update AGENTS.md instead; it's always applied" | AGENTS.md is the pointer index. Binding review prefs are .pr-agent/*.mdc. |
Red flags — STOP
- Writing
pr-agent/(no dot), pointer READMEs there,CONVENTIONS.md, orall-rules.mdc - Restating TypeScript/Node platitudes with no
src/or ADR anchor - Copying an existing
.mdcunder a new name - Skipping the inventory / remaining-slot math
- Padding weak rules to exhaust remaining slots
- Multi-pass "deep dive later" instead of finishing the one-pass checklist
All of these mean: delete the bad outputs. Restart at checklist step 1.
Done when
Every emitted .mdc is new, capped, and codebase-specific; unused slots may remain empty; the quality gate is all checked.