@epicparty/skills 0.0.0-stage → 0.1.0

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.
Files changed (39) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE +27 -0
  3. package/README.md +109 -2
  4. package/bin/cli.mjs +175 -0
  5. package/lib/transform.mjs +185 -0
  6. package/package.json +37 -4
  7. package/skills/architect/DESIGN-IT-TWICE.md +46 -0
  8. package/skills/architect/HTML-REPORT.md +126 -0
  9. package/skills/architect/SKILL.md +101 -0
  10. package/skills/babysit/SKILL.md +164 -0
  11. package/skills/code-review/SKILL.md +111 -0
  12. package/skills/copy/COPY.md +142 -0
  13. package/skills/copy/SKILL.md +87 -0
  14. package/skills/deliver/SKILL.md +259 -0
  15. package/skills/diagnose/SKILL.md +114 -0
  16. package/skills/diagnose/scripts/hitl-loop.template.sh +44 -0
  17. package/skills/explore/SKILL.md +78 -0
  18. package/skills/grill/SKILL.md +75 -0
  19. package/skills/implement/SKILL.md +132 -0
  20. package/skills/implement/TDD.md +131 -0
  21. package/skills/implement/TEST-VALUE.md +114 -0
  22. package/skills/outdated/SKILL.md +125 -0
  23. package/skills/research/SKILL.md +115 -0
  24. package/skills/router/BOARD.md +157 -0
  25. package/skills/router/DECISIONS.md +71 -0
  26. package/skills/router/GIT.md +70 -0
  27. package/skills/router/GLOSSARY-FORMAT.md +48 -0
  28. package/skills/router/SKILL.md +251 -0
  29. package/skills/setup/SKILL.md +99 -0
  30. package/skills/ship/SKILL.md +132 -0
  31. package/skills/to-pr/SKILL.md +88 -0
  32. package/skills/to-story/SEAMS.md +51 -0
  33. package/skills/to-story/SKILL.md +79 -0
  34. package/skills/to-story/SPLITTING.md +53 -0
  35. package/skills/to-story/STORIES.md +179 -0
  36. package/skills/triage/SKILL.md +179 -0
  37. package/skills/upgrade/SKILL.md +139 -0
  38. package/skills/writing-for-agents/SKILL-MECHANICS.md +24 -0
  39. package/skills/writing-for-agents/SKILL.md +88 -0
@@ -0,0 +1,126 @@
1
+ # HTML report
2
+
3
+ <!-- upstream: mattpocock/skills skills/engineering/improve-codebase-architecture/HTML-REPORT.md -->
4
+
5
+ The area scan's report is a single self-contained HTML file, written where [`SKILL.md`](./SKILL.md) § 5 says. Tailwind and Mermaid both come from CDNs. Mermaid handles graph-shaped diagrams reliably; hand-built divs and inline SVG handle the more editorial visuals (mass diagrams, cross-sections). Mix the two: don't lean on Mermaid for everything, it'll start to look generic.
6
+
7
+ ## Scaffold
8
+
9
+ ```html
10
+ <!doctype html>
11
+ <html lang="en">
12
+ <head>
13
+ <meta charset="utf-8" />
14
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
15
+ <title>Architecture review for {{repo name}}</title>
16
+ <script src="https://cdn.tailwindcss.com/3.4.17"></script>
17
+ <script type="module">
18
+ import mermaid from "https://cdn.jsdelivr.net/npm/mermaid@11.4.1/dist/mermaid.esm.min.mjs";
19
+ mermaid.initialize({ startOnLoad: true, theme: "neutral", securityLevel: "loose" });
20
+ </script>
21
+ <style>
22
+ /* small custom layer for things Tailwind doesn't cover cleanly:
23
+ dashed seam lines, hand-drawn-feeling arrow heads, etc. */
24
+ .seam { stroke-dasharray: 4 4; }
25
+ .leak { stroke: #dc2626; }
26
+ .deep { background: linear-gradient(135deg, #0f172a, #1e293b); }
27
+ </style>
28
+ </head>
29
+ <body class="bg-stone-50 text-slate-900 font-sans">
30
+ <main class="max-w-5xl mx-auto px-6 py-12 space-y-12">
31
+ <header>...</header>
32
+ <section id="candidates" class="space-y-10">...</section>
33
+ <section id="top-recommendation">...</section>
34
+ </main>
35
+ </body>
36
+ </html>
37
+ ```
38
+
39
+ ## Header
40
+
41
+ Repo name, date, and a compact legend: solid box = module, dashed line = seam, red arrow = leakage, thick dark box = deep module. No introduction paragraph. Straight into the candidates.
42
+
43
+ ## Candidate card
44
+
45
+ The diagrams carry the weight. Prose is sparse, plain, and uses the terms of [`SEAMS.md`](../to-story/SEAMS.md) without ceremony.
46
+
47
+ Each candidate is one `<article>`:
48
+
49
+ - **Title**: short, names the deepening (e.g. "Collapse the Order intake pipeline").
50
+ - **Badge row**: recommendation strength (`Strong` = emerald, `Worth exploring` = amber, `Speculative` = slate), plus a tag for the dependency category from `SEAMS.md` (`in-process`, `local stand-in`, `remote but owned`, `truly external`).
51
+ - **Files**: monospaced list, `font-mono text-sm`.
52
+ - **Before / After diagram**: the centrepiece. Two columns, side by side. See patterns below.
53
+ - **Problem**: one sentence. What hurts.
54
+ - **Solution**: one sentence. What changes.
55
+ - **Wins**: bullets, ≤6 words each. e.g. "Tests hit one interface", "Pricing logic stops leaking", "Delete 4 shallow wrappers".
56
+ - **ADR callout** (if applicable): one line in an amber-tinted box.
57
+
58
+ No paragraphs of explanation. If the diagram needs a paragraph to be understood, redraw the diagram.
59
+
60
+ ## Diagram patterns
61
+
62
+ Pick the pattern that fits the candidate. Mix them. Don't make every diagram look the same. Variety is part of the point.
63
+
64
+ ### Mermaid graph (the workhorse for dependencies / call flow)
65
+
66
+ Use a Mermaid `flowchart` or `graph` when the point is "X calls Y calls Z, and look at the mess." Wrap it in a Tailwind-styled card so it doesn't feel parachuted in. Style with classDef to colour leakage edges red and the deep module dark. Sequence diagrams work well for "before: 6 round-trips; after: 1."
67
+
68
+ ```html
69
+ <div class="rounded-lg border border-slate-200 bg-white p-4">
70
+ <pre class="mermaid">
71
+ flowchart LR
72
+ A[OrderHandler] --> B[OrderValidator]
73
+ B --> C[OrderRepo]
74
+ C -.leak.-> D[PricingClient]
75
+ classDef leak stroke:#dc2626,stroke-width:2px;
76
+ class C,D leak
77
+ </pre>
78
+ </div>
79
+ ```
80
+
81
+ ### Hand-built boxes-and-arrows (when Mermaid's layout fights you)
82
+
83
+ Modules as `<div>`s with borders and labels. Arrows as inline SVG `<line>` or `<path>` elements positioned absolutely over a relative container. Reach for this when you want the "after" diagram to feel like one thick-bordered deep module with greyed-out internals, since Mermaid won't render that with the right weight.
84
+
85
+ ### Cross-section (good for layered shallowness)
86
+
87
+ Stack horizontal bands (`h-12 border-l-4`) to show layers a call passes through. Before: 6 thin layers each doing nothing. After: 1 thick band labelled with the consolidated responsibility.
88
+
89
+ ### Mass diagram (good for "interface as wide as implementation")
90
+
91
+ Two rectangles per module: one for interface surface area, one for implementation. Before: interface rectangle is nearly as tall as the implementation rectangle (shallow). After: interface rectangle is short, implementation rectangle is tall (deep).
92
+
93
+ ### Call-graph collapse
94
+
95
+ Before: a tree of function calls rendered as nested boxes. After: the same tree collapsed into one box, with the now-internal calls shown faded inside it.
96
+
97
+ ## Style guidance
98
+
99
+ - Lean editorial, not corporate-dashboard. Generous whitespace. Serif optional for headings (`font-serif` works well with stone/slate).
100
+ - Colour sparingly: one accent (emerald or indigo) plus red for leakage and amber for warnings.
101
+ - Keep diagrams ~320px tall so before/after sits comfortably side by side without scrolling.
102
+ - Use `text-xs uppercase tracking-wider` for module labels inside diagrams, so they read as schematic, not as UI.
103
+ - The only scripts are the Tailwind CDN and the Mermaid ESM import. The report is otherwise static: no app code, no interactivity beyond Mermaid's own rendering.
104
+
105
+ ## Top recommendation section
106
+
107
+ One larger card. Candidate name, one sentence on why, anchor link to its card. That's it.
108
+
109
+ ## Tone
110
+
111
+ Plain English, concise, but the architectural nouns and verbs come straight from [`SEAMS.md`](../to-story/SEAMS.md). Concision is not an excuse to drift.
112
+
113
+ **Use exactly:** module, interface, implementation, depth, deep, shallow, seam, adapter, leverage, locality.
114
+
115
+ **Never substitute:** component, service, unit (for module) · API, signature (for interface) · boundary (for seam) · layer, wrapper (for module, when you mean module).
116
+
117
+ **Phrasings that fit the style:**
118
+
119
+ - "Order intake module is shallow: interface nearly matches the implementation."
120
+ - "Pricing leaks across the seam."
121
+ - "Deepen: one interface, one place to test."
122
+ - "Two adapters justify the seam: HTTP in prod, in-memory in tests."
123
+
124
+ **Wins bullets** name the gain in glossary terms: *"locality: bugs concentrate in one module"*, *"leverage: one interface, N call sites"*, *"interface shrinks; implementation absorbs the shallow modules"*. Don't write *"easier to maintain"* or *"cleaner code"*, because those terms aren't in the glossary and don't earn their place.
125
+
126
+ No hedging, no throat-clearing, no "it's worth noting that…". If a sentence could be a bullet, make it a bullet. If a bullet could be cut, cut it. If a term isn't in `SEAMS.md`, reach for one that is before inventing a new one.
@@ -0,0 +1,101 @@
1
+ ---
2
+ name: architect
3
+ description: Recommends how to architect a feature — where its seams go, which modules it extends or adds, how each is tested — or judges a design you bring. On request, scans a named area for modules worth deepening. Use when planning how something should be built, or when asked for an architecture review.
4
+ metadata:
5
+ pack: epicparty/skills
6
+ version: 0.1.0
7
+ ---
8
+
9
+ # Architect
10
+
11
+ An architect's judgement on demand. Bring a feature, a brief, a story, or a design of your own, and get one **recommendation**: where the seams go, which modules the work extends or adds, what sits behind each seam, and how it is tested — with the alternatives weighed and the decisions only the user can make named as theirs.
12
+
13
+ It reads what the work touches, not the whole codebase. A scan for refactors happens only when it is asked for, over an area the user names (§ 5).
14
+
15
+ Two vocabularies carry every recommendation:
16
+
17
+ - **The architecture's** — [`SEAMS.md`](../to-story/SEAMS.md): module, interface, depth, seam, adapter, leverage, locality, and its principles — the deletion test, "the interface is the test surface", "one adapter is a hypothetical seam, two are a real one". Use those terms exactly; never "component", "service", "API" or "boundary" for a module — a framework's own construct, such as a React component, keeps its name.
18
+ - **The domain's** — the glossary, which names the modules worth naming, and the ADRs and standards, which hold decisions this skill does not re-litigate. `/ep`'s [`DECISIONS.md`](../router/DECISIONS.md) says where they live.
19
+
20
+ ## 1. Frame the question
21
+
22
+ Name what is being designed, in the glossary's words: the outcome, and — when the user brought one — the design under judgement. Then read what bounds it:
23
+
24
+ - **The work** — the `/ep-explore` brief, the issue and its comments, or the conversation. With no brief and code you have not read this session, run [`/ep-explore`](../explore/SKILL.md) first. When the request already names the design and the files it lands in, its locate step (§ 3) is enough.
25
+ - **The modules it touches** — each one's interface, its callers, and the tests at its seam today.
26
+ - **The rules in the area** — the ADRs and the project standards the agent files route those paths to. A project with none of these gets one line saying so.
27
+
28
+ Done when you can say, in one sentence each, what the work must do, which modules it lands in, and which rules bind it.
29
+
30
+ ## 2. Weigh the options
31
+
32
+ Most features have two or three honest shapes. Lay them out side by side:
33
+
34
+ - **Extend or add.** Does the behaviour belong behind an existing module's interface, or does it earn a module of its own? Run the **deletion test** on any new module: if deleting it would only move complexity back into its callers, it earns its place; if the complexity would vanish, it is a pass-through.
35
+ - **The seam.** Where the feature is tested and swapped — the highest existing seam first, a new one only where something varies across it. Name each dependency's category from `SEAMS.md`, since that decides the adapters and how the seam is tested.
36
+ - **The interface.** What callers must know — every invariant, ordering and error mode, not only the signature. Where its shape is the open question — several callers, no obvious entry point — follow [`DESIGN-IT-TWICE.md`](./DESIGN-IT-TWICE.md).
37
+ - **The rules.** A shape that contradicts an ADR or a standard stays on the table only when the friction is real enough to reopen the rule, and the conflict is said out loud — _"contradicts ADR 0007, but worth reopening because…"_.
38
+
39
+ A design the user brought is one of the options, judged by the same tests. Say what holds in it, what to change and why, before offering another.
40
+
41
+ Done when every option names its modules, its seams and its cost, and each rejected one has the reason it lost.
42
+
43
+ ## 3. Recommend
44
+
45
+ One recommendation, opinionated — the user wants a strong read, not a menu. Where parts of two options combine well, recommend the hybrid.
46
+
47
+ ```md
48
+ ## Architecture: {the feature}
49
+
50
+ **Your design:** {only when the user brought one: what holds, what to change, and why}
51
+
52
+ **Recommendation:** {one or two sentences: the shape}
53
+
54
+ | Module | Change | Interface | Seam and tests |
55
+ | --- | --- | --- | --- |
56
+ | {the glossary's name where it has one, else the code's} | extend / new / deepen | {what callers must know} | {seam, dependency category, adapters, the test level} |
57
+
58
+ **Why this shape:** {leverage and locality, in SEAMS.md terms}
59
+
60
+ **Rejected:** {each option and the reason it lost}
61
+
62
+ **Decisions for you:** {each call that is the user's to make, with the answer you recommend}
63
+
64
+ **Worth an ADR:** {a decision that passes DECISIONS.md's three-part test, or "none"}
65
+ ```
66
+
67
+ Done when every module the work touches has a row, and every call that is the user's sits under **Decisions for you**.
68
+
69
+ ## 4. Hand on
70
+
71
+ The recommendation is advice until the user takes it.
72
+
73
+ - **Decisions still open** — ask the items of **Decisions for you** one at a time, the way `/ep` `## Working rules` says, each with its recommendation first. [`/ep-grill`](../grill/SKILL.md) only when the user asks, or an answer opens decisions you could not list.
74
+ - **Agreed** — [`/ep-to-story`](../to-story/SKILL.md) writes the story with these seams, and names them as agreed. An issue that already exists takes them into its `## Implementation Decisions` and `## Testing Decisions`.
75
+ - **An ADR the user accepts** — written per [`DECISIONS.md`](../router/DECISIONS.md#writing-an-adr): here, once the user accepts it.
76
+
77
+ Done when the user has answered **Decisions for you**, and taken the recommendation or changed it.
78
+
79
+ ## 5. Scan an area, on request
80
+
81
+ <!-- upstream: mattpocock/skills skills/engineering/improve-codebase-architecture/SKILL.md -->
82
+
83
+ When the user asks for refactors rather than a design — "where should we deepen X", "review the architecture of Y" — scan **the area they name**. With no area named, ask for one — unless the whole codebase is small enough to read in one sitting: then scan it, and say so.
84
+
85
+ **Weight what changes.** Deepening pays off by making future changes easier, so walk back a good stretch of the area's history (`git log --oneline -- <area>`) for its **hot spots**, and let them pull your attention first.
86
+
87
+ Dispatch a subagent with a fresh context to walk the area — brief it with the area, both vocabularies and the questions below, and have it return candidates — or walk it yourself where subagents are unavailable. It notes where it feels **friction**:
88
+
89
+ - Understanding one concept means bouncing between many small modules.
90
+ - A module is **shallow** — its interface nearly as complex as its implementation.
91
+ - Pure functions were extracted for testability, but the real bugs hide in how they are called — no **locality**.
92
+ - Tightly coupled modules leak across their seams.
93
+ - Code is untested, or hard to test through its current interface.
94
+
95
+ Apply the deletion test to each suspect, and keep the ones where deletion would concentrate complexity. A bug the walk turns up goes under **Found in passing**, for [`/ep-diagnose`](../diagnose/SKILL.md). A scan that finds nothing worth deepening says so, and writes no report.
96
+
97
+ Report the candidates as one self-contained HTML file outside the checkout — `<dir>/architecture-review-<timestamp>.html`, where `<dir>` is the session's scratch directory where the harness names one, else `$TMPDIR`, `/tmp`, or `%TEMP%` on Windows. Open it where there is a desktop, and give the user the absolute path. [`HTML-REPORT.md`](./HTML-REPORT.md) has the scaffold, each card's fields, the diagram patterns and the tone. End with a **top recommendation**, propose no interfaces yet, and ask which candidate to explore.
98
+
99
+ The chosen candidate then runs § 1 to § 4 as a design. **A candidate the user rejects with a load-bearing reason** earns an ADR offer — _"Want me to record this as an ADR, so later reviews do not suggest it again?"_ — when a future reviewer would need that reason to avoid re-suggesting it.
100
+
101
+ Done when the report is open, every candidate has its card, and the user has the question.
@@ -0,0 +1,164 @@
1
+ ---
2
+ name: babysit
3
+ description: Sweeps an open PR toward merged. Use when a PR needs watching, a red check fixed, or a merge once its gate is clear.
4
+ metadata:
5
+ pack: epicparty/skills
6
+ version: 0.1.0
7
+ ---
8
+
9
+ # Babysit
10
+
11
+ A feature is finished when it is **merged**, not when it is written. This skill carries it the rest of the way.
12
+
13
+ One invocation is one **sweep**: get the work onto a PR, read that PR's state, give every open finding a disposition, push the fixes, then merge if the gate is clear. A sweep over a PR that gained nothing since the last one ends in a no-op report, so sweeps are cheap to repeat — by hand, or on a `/loop` tick.
14
+
15
+ The PR lives on GitHub. Reach it with whatever this session has wired up — the `gh` CLI, GitHub MCP tools, whatever is available. The steps below name what to read and write, not which tool does it.
16
+
17
+ ## 1. Pin the target
18
+
19
+ The argument is a PR number; with no argument, the current branch. Either way, resolve it to one PR and find out whether that PR exists yet.
20
+
21
+ Done when you have the PR's number, or know the branch hasn't got one.
22
+
23
+ ## 2. Open the PR, if the feature hasn't got one
24
+
25
+ Skip this step when the PR already exists — which is the usual case, since a sweep is normally the second thing to happen to a branch.
26
+
27
+ Otherwise the branch needs a PR before there is anything to babysit. Opening one is its own job with its own rules — the title, the reviewer-facing body, the suite report, the board — and they live in [`/ep-to-pr`](../to-pr/SKILL.md). Read `skills/to-pr/SKILL.md` and follow it, then come back with the PR number.
28
+
29
+ Done when the PR exists and you have its number.
30
+
31
+ ## 3. Read the PR's state
32
+
33
+ One read, covering all of:
34
+
35
+ - **head SHA** — every judgement in this sweep is against it
36
+ - **state, draft flag, mergeability, review decision**
37
+ - **checks on that head SHA**, each with whether it gates the merge
38
+ - **review threads with their resolved state** — a plain `gh pr view --comments` flattens threads and drops resolution, so reach for the GraphQL `reviewThreads { isResolved }` field or a tool that reports it. Re-litigating a thread someone already resolved is noise on their PR.
39
+ - **PR-level comments** — where bots post their bug reports
40
+
41
+ Done when you can name the head SHA, the failing checks, and the unresolved threads.
42
+
43
+ ## 4. Collect the findings
44
+
45
+ A **finding** is anything asking for a change: a failing check that gates the merge, an unresolved review thread, a bug a bot reported in a PR comment, a conflict with the base.
46
+
47
+ - For a failing check, read the failure — `gh run view <run-id> --log-failed` or the equivalent job-log call. A job name tells you which suite broke, never why.
48
+ - Reproduce test, type, and lint failures locally with the command the failing job ran — its log names it, and the workflow file holds it. Running anything else reproduces something other than what CI saw. A failure you can't reproduce is one you can't confirm fixed.
49
+ - **Advisory failures are reported, never chased.** A check is advisory when branch protection doesn't require it, or when its step carries `continue-on-error`. Where you can't tell what's required, treat every failing check as gating and let the exception be argued out loud.
50
+ - A gating failure that also reproduces on the default branch isn't this PR's. Say so once in the thread with the evidence and carry it as reported.
51
+
52
+ Done when every finding points at a concrete log excerpt or diff line, or is dismissed with a stated reason.
53
+
54
+ ## 5. Give every finding a disposition
55
+
56
+ Three dispositions, one per finding:
57
+
58
+ - **Fix** — the finding is correct and the change serves the PR's goal, even where it grows the diff, or it is a **small fix** (`/ep` `## Vocabulary`).
59
+ - **Push back** — the finding is wrong, already handled elsewhere, or asks for work this PR never claimed. Reply in the thread with the reasoning and leave it unresolved: overruling a reviewer is the reviewer's call.
60
+ - **Defer** — correct, but it serves another goal and is larger than a small fix. Say so in the thread reply and add it to the PR body under **Found in passing**; the user decides whether it becomes a story.
61
+
62
+ Weigh a human reviewer above a bot — bots flag style they lack the context to judge. Correctness outranks both: a bot that finds a real bug gets a fix.
63
+
64
+ Done when the finding list has no undispositioned entries.
65
+
66
+ ## 6. Fix, validate, push
67
+
68
+ Route the work through the project's standards the same way the original change would be: the agent files and what they route each path to ([`/ep-implement` § 3](../implement/SKILL.md#3-route-the-standards)). A babysit fix is held to the bar of the code it lands in.
69
+
70
+ A conflict with the base is fixed first, by a rebase onto `origin/<base>` (`/ep`'s [`GIT.md`](../router/GIT.md) `## Catching up with the default branch`). The other fixes are then written against the base they will land on, and one suite run covers them all.
71
+
72
+ Validate before pushing, per the **Full suite** setting ([Settings](#settings)). Under **CI runs it**, the push is what runs it, and step 9 reads the result. Under any other option, run what it names for what the PR touches — the suite is yours to run, because nothing else will.
73
+
74
+ Commit per `GIT.md` `## Commits`, and push to the PR's head branch — after a rebase, with the pinned lease that `GIT.md` gives. Where the PR body carries a suite report, update it to name the commit you just validated — a report against an older commit says nothing about the one that will merge.
75
+
76
+ Done when your work is committed, the push landed, and `git status` shows nothing of yours left behind.
77
+
78
+ ## 7. Answer the threads you touched
79
+
80
+ For each fixed finding, reply in its thread naming the commit that addressed it, then resolve the thread. Resolution is GraphQL-only — the `resolveReviewThread` mutation against the thread's id, since REST exposes no equivalent:
81
+
82
+ ```bash
83
+ gh api graphql -f query='mutation($id:ID!){ resolveReviewThread(input:{threadId:$id}){ thread { isResolved } } }' -F id=<thread-id>
84
+ ```
85
+
86
+ The thread is the reviewer's only window into what you did; a fix nobody is told about reads as an ignored comment, and that is how a PR stalls. Pushed-back and deferred threads stay unresolved — you replied, the reviewer decides.
87
+
88
+ Done when every fixed finding has a reply and a resolved thread, and every other finding has a reply.
89
+
90
+ ## 8. Review the diff
91
+
92
+ **Ours, on the first sweep and after every push.** Run [`/ep-code-review`](../code-review/SKILL.md) against the merge-base (`git merge-base HEAD origin/<base>`), passing it the issue the PR closes as its spec, on the first sweep, and on later sweeps only when you pushed. An unchanged diff yields an unchanged review, so re-running it spends tokens to learn nothing. Feed its findings back through step 5. A Standards finding is usually a fix. A Spec finding that names a missing requirement means the feature isn't done — report it and stop short of the gate.
93
+
94
+ **External, rarely, for a substantial change.** An **external review** comes from a reviewer outside this session — a review bot installed on the repository — and its quota is small. The **External reviewers** setting lists the reviewers enabled, how to request each, and the most reviews each one gives a PR; read it the first time a PR is substantial, per [Settings](#settings). Our review carries most PRs; an external one is the exception:
95
+
96
+ - **Substantial** means the diff changes architecture or core logic: a module boundary, a schema or migration, auth and permissions, a shared package other code depends on, the rules of a domain flow. Copy, styling, docs and test-only changes are not substantial.
97
+ - **Requested without asking** when the user asked for an external review, or for a deep or deeper review.
98
+ - **Otherwise asked once.** For a substantial change, ask the user once per PR whether they want an external review, and from which reviewer when more than one is enabled. Record the answer in the PR body, so a later sweep reads it rather than asking again. A change that is not substantial gets no ask. Under [`/ep-deliver`](../deliver/SKILL.md) nobody is there to answer, so a substantial change gets its external review without asking, within the caps.
99
+ - **One big review of each kind.** Request it once our review's findings are fixed and pushed, so it reads the shape that will merge. A later push earns another only when that push is substantial on its own — a rebase whose conflicts touched architecture or core logic, for example — and only within that kind's cap.
100
+ - **A security review** is for a change to auth, permissions or secrets themselves, not to code beside them. Spend its cap by how sensitive the code is: a later push earns another only when it touches that code again.
101
+
102
+ A later sweep reads its findings at step 3 and dispositions them at step 5 like any other bot.
103
+
104
+ Done when the current diff has had our review, the PR's external review is settled — requested, not wanted, or not earned — and every finding raised carries a disposition.
105
+
106
+ ## 9. The merge gate
107
+
108
+ Take a fresh read **after** your last push — a gate judged on state from before it is a gate judged on the wrong commit — and merge when all of these hold on the current head SHA:
109
+
110
+ - open, not a draft, no conflicts with the base
111
+ - every gating check has run **on that head SHA** and passed; a pass inherited from before your push is a **stale green**, and merging on one merges untested code
112
+ - no check still running
113
+ - no unresolved thread, and no reviewer sitting on changes-requested
114
+ - every **open question** in the PR body has an answer — a call you made *for* the user is theirs to take while the diff is open, and this merge is what closes that window
115
+ - the PR's external review is settled (step 8), and every external review requested has landed; merging while one is still running throws away quota you spent
116
+ - code-review findings fixed or dispositioned
117
+ - where the **Full suite** runs locally, the PR body's suite report names **this** head SHA — that report is the only evidence the merging commit was ever tested
118
+
119
+ Then merge the way the **Merge strategy** setting says ([Settings](#settings)), and delete the branch:
120
+
121
+ ```bash
122
+ gh pr merge <pr-number> --rebase --delete-branch # --squash or --merge per the setting
123
+ ```
124
+
125
+ `/ep`'s [`GIT.md`](../router/GIT.md) `## Merging` says what each strategy leaves on the default branch. Where a merge queue is enabled, this enqueues the PR rather than merging it — that is success; report it as queued and let the queue's own gate run.
126
+
127
+ Merging is the one irreversible act in the sweep. With the gate clear, take it — a merged PR is the whole point. With any part of it unclear, report and leave the PR open.
128
+
129
+ ## 10. Report
130
+
131
+ State, in a few lines: the PR, the head SHA you ended on, each finding with its disposition, what you pushed, check status, and either the merge result or the precise gate condition that stopped it. Name what you left for a human.
132
+
133
+ A merged PR is not yet a shipped one. [`/ep-ship`](../ship/SKILL.md) runs these sweeps and then follows the merge into production.
134
+
135
+ ## Guardrails
136
+
137
+ - **The PR's history is append-only, except for a rebase onto the base.** Review fixes land as new commits, because amend and force-push move ground the reviewer is standing on. A conflict with the base is the one rewrite: rebase onto `origin/<base>` by `/ep`'s [`GIT.md`](../router/GIT.md) `## Catching up with the default branch`, and never merge the base into the branch.
138
+ - **Checks are evidence.** Make the code satisfy them, and leave workflow files, required-check settings, and `continue-on-error` flags as they are — editing the gate to pass it forfeits the only signal the PR has.
139
+ - **Reviews get answered.** Dismissing a review or approving the PR yourself is the human's call, in every case.
140
+ - **The story's goal is the PR's scope, and a small fix rides along.** A finding the goal needs is a fix, and so is a **small fix**. A larger finding that serves another goal is deferred under **Found in passing**, and the user decides whether it becomes a story.
141
+
142
+ ## Settings
143
+
144
+ This skill reads two settings `/ep` `## Settings` defines — **Full suite** at § 6 and **Merge strategy** at § 9 — and one of its own, **External reviewers** at § 8. It runs, merges and requests what they name, so it asks for each one that is missing. Each `###` heading below is one setting: its topic, its question, and its options. `/ep-setup` reads the same headings to ask every setting up front.
145
+
146
+ 1. **The settings home.** The `## Agent skills` block of the root `AGENTS.md` — or `CLAUDE.md`, whichever the project has — names where `ep-*` settings live and in what form. With neither file present, first ask which to create, recommending `AGENTS.md`, which most agents read. With no such line, ask the user where to keep them, the default first:
147
+ - **`docs/agents/<topic>.md`** (default) — one Markdown file per topic, one `##` heading per setting, named as the setting. Other headings in the file are the project's own notes.
148
+ - **One file** — at a path the user names.
149
+ - **Another form** — as the user describes it.
150
+
151
+ Write their answer as one line in that block, creating the block when it is missing — for the default, `` `ep-*` settings: `docs/agents/<topic>.md`, one heading per setting. ``
152
+ 2. **The setting.** Read it at the settings home. Present: use it, and ask nothing.
153
+ 3. **Missing.** Ask its question below, recommended answer first, with the follow-up its option needs. Write the answer at the settings home, tell the user where it went and that they can edit it there or through `/ep-setup`, then continue.
154
+
155
+ ### External reviewers
156
+
157
+ Topic `reviewers`. Question: *Which review bots outside this session may be asked to review a substantial PR, and how often?*
158
+
159
+ | Option | Follow-up | Recommend when |
160
+ | --- | --- | --- |
161
+ | **These reviewers** | One row per reviewer and kind — normal or security — with the PR comment that requests it, the most requests per PR, and any rule its trigger needs | A review bot has posted on the repository's recent PRs (`gh pr list --state merged --limit 20 --json comments,reviews`) |
162
+ | **None** | — | No review bot is installed: step 8 runs our review alone |
163
+
164
+ A reviewer the setting does not list is never requested. Enabling one means installing it on the repository first, then adding its row.
@@ -0,0 +1,111 @@
1
+ ---
2
+ name: code-review
3
+ description: Reviews code on two axes, Standards and — when given a spec — Spec. Use before opening a PR, or when asked to review a branch, a commit range, working changes or a few files.
4
+ metadata:
5
+ pack: epicparty/skills
6
+ version: 0.1.0
7
+ ---
8
+
9
+ # Code Review
10
+
11
+ Two-axis review of a piece of code:
12
+
13
+ - **Standards** — does the code conform to the project's documented standards? Always runs.
14
+ - **Spec** — does the code faithfully deliver what it was meant to? Runs when a **spec** is passed in.
15
+
16
+ Both axes run as **parallel sub-agents**, so neither pollutes the other's context, then this skill aggregates their findings.
17
+
18
+ **Invoking this skill is the user asking for them**, so spawn them without a separate ask. The isolation is the point: an axis that has read the other's findings anchors on them. Running both inline is a fallback to report as one, never the default.
19
+
20
+ ## 1. Pin the code
21
+
22
+ Take the first that fits:
23
+
24
+ - **Files the user named** — read whole; there is no diff and no commit list.
25
+ - **A commit, tag, or range the user named** — `git diff <ref>...HEAD`.
26
+ - **Uncommitted changes**, when the user asked for working changes or the branch has no commits of its own — `git diff HEAD`.
27
+ - **The branch** — the default: the merge-base with the default branch, `git merge-base HEAD origin/<default>`, the default from `git symbolic-ref refs/remotes/origin/HEAD`, or `gh repo view --json defaultBranchRef` where that is unset. This is what a branch review means and what `/ep-implement` and `/ep-babysit` ask for.
28
+
29
+ Capture a diff once — three-dot, so the comparison is against the merge-base and not against whatever else has landed since — and note its commits with `git log <fixed-point>..HEAD --oneline`. Confirm the ref resolves (`git rev-parse`) and the diff is non-empty before going further. A bad ref should fail here, not inside two sub-agents.
30
+
31
+ Done when you have the code to review — a non-empty diff with its commits, or the named files.
32
+
33
+ ## 2. Take the spec
34
+
35
+ The **spec** is whatever the caller or the user passed to say what the code should do: an issue, a PR, a file, or plain text. This skill never searches for one.
36
+
37
+ - **An issue** — fetch it with its comments (`gh issue view <n> --comments` on GitHub). The comments matter as much as the body — they carry decisions that never got written up.
38
+ - **A PR, a file or text** — read it as given.
39
+ - **Nothing** — the review is Standards only. Say so in one line of the report — *Spec skipped: no spec given; name one to check it* — and ask nothing.
40
+
41
+ Done when you hold the spec, or know the review is Standards only.
42
+
43
+ ## 3. Gather the standards sources
44
+
45
+ The project documents its rules in its agent files and the documents they route to. Collect the ones that actually govern the diff rather than passing all of them:
46
+
47
+ - **`AGENTS.md` or `CLAUDE.md`, root to leaf** — the root file, then the nearest one to each changed path. The nested ones override for their subtree.
48
+ - **The routed standards** — every document those files route the touched paths to, followed to the specific file for the touched code.
49
+ - **The commit rules** — subjects and scopes, wherever the project states them. Under a rebase merge every commit reaches the default branch as itself, so each one is reviewed.
50
+ - **The domain glossary and its ADRs** — where `/ep`'s [`DECISIONS.md`](../router/DECISIONS.md) says the project keeps them. The diff should speak the domain's words, and a rename of an established term is a finding.
51
+
52
+ **Skip what tooling already enforces.** The formatter, linter and typechecker the project's scripts run already gate their rules. A review finding about a rule the gate would have caught spends the reviewer's attention on something a command already answers.
53
+
54
+ The Standards axis also carries the **smell baseline** — the flat reference at the foot of this file. Step 4 pastes it into the sub-agent verbatim, so have it to hand.
55
+
56
+ Done when you have the `AGENTS.md` chain, the routed standards for every touched path, and the baseline ready to paste.
57
+
58
+ ## 4. Spawn both sub-agents in parallel
59
+
60
+ **Standards sub-agent** — give it the diff command, the commit list, the standards files from step 3 by path, and the smell baseline **pasted in full**, since it has no other access to it. The brief:
61
+
62
+ > Report, per file or hunk: (a) every place the diff violates a documented standard — cite the standard by file and rule; (b) any baseline smell — name it and quote the hunk. Mark documented-standard breaches as hard findings and baseline smells as judgement calls. A documented project standard overrides the baseline. Skip anything the formatter, linter or typechecker enforces. Under 400 words.
63
+
64
+ **Spec sub-agent** — give it the diff command or the files, the commit list, and the spec — for an issue, its body **and comments**. The brief:
65
+
66
+ > Report: (a) requirements the spec asks for that are missing or partial — check every numbered user story and every acceptance criterion; (b) behaviour in the code the spec never asked for, which is scope creep; (c) requirements that look implemented but look wrong. Quote the spec line for each finding. Under 400 words.
67
+
68
+ Skip the Spec sub-agent when step 2 holds no spec.
69
+
70
+ Done when both sub-agents have returned, or the Spec axis is recorded as skipped with its reason.
71
+
72
+ ## 5. Aggregate
73
+
74
+ Present the two reports under `## Standards` and `## Spec`, verbatim or lightly cleaned. Keep them separate — **merging or reranking them across axes is what this structure exists to prevent**.
75
+
76
+ End with one line: the finding count per axis, and the worst finding *within each axis*. Do not pick a single winner across the two.
77
+
78
+ A **Spec finding that names a missing requirement means the feature is not done.** It goes back to `/ep-implement`, not into a PR thread.
79
+
80
+ Done when both axes are reported and every finding is attributable to a standard or a spec line.
81
+
82
+ ## The smell baseline
83
+
84
+ Fowler's code smells (_Refactoring_, ch.3). They apply even where the project documents nothing, and two rules bind them:
85
+
86
+ - **The project overrides.** A documented standard always wins; where it endorses something the baseline would flag, suppress the smell.
87
+ - **Always a judgement call.** Each smell is a labelled heuristic ("possible Feature Envy"), never a hard violation.
88
+
89
+ Each smell reads *what it is* → *how to fix*; match it against the diff:
90
+
91
+ - **Mysterious Name** — a function, variable, or type whose name doesn't reveal what it does or holds. → rename it; if no honest name comes, the design's murky.
92
+ - **Duplicated Code** — the same logic shape appears in more than one hunk or file in the change. → extract the shared shape, call it from both.
93
+ - **Feature Envy** — a method that reaches into another object's data more than its own. → move the method onto the data it envies.
94
+ - **Data Clumps** — the same few fields or params keep travelling together (a type wanting to be born). → bundle them into one type, pass that.
95
+ - **Primitive Obsession** — a primitive or string standing in for a domain concept that deserves its own type. → give the concept its own small type.
96
+ - **Repeated Switches** — the same `switch`/`if`-cascade on the same type recurs across the change. → replace with polymorphism, or one map both sites share.
97
+ - **Shotgun Surgery** — one logical change forces scattered edits across many files in the diff. → gather what changes together into one module.
98
+ - **Divergent Change** — one file or module is edited for several unrelated reasons. → split so each module changes for one reason.
99
+ - **Speculative Generality** — abstraction, parameters, or hooks added for needs the spec doesn't have. → delete it; inline back until a real need shows.
100
+ - **Message Chains** — long `a.b().c().d()` navigation the caller shouldn't depend on. → hide the walk behind one method on the first object.
101
+ - **Middle Man** — a class or function that mostly just delegates onward. → cut it, call the real target direct.
102
+ - **Refused Bequest** — a subclass or implementer that ignores or overrides most of what it inherits. → drop the inheritance, use composition.
103
+
104
+ ## Why two axes
105
+
106
+ A change can pass one and fail the other:
107
+
108
+ - Follows every standard, implements the wrong thing → **Standards pass, Spec fail.**
109
+ - Does exactly what the issue asked, breaks the project's conventions → **Spec pass, Standards fail.**
110
+
111
+ Reporting them separately stops either from masking the other.