swe-workflow-skills 0.6.2 → 0.7.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.
package/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.2
1
+ 0.7.0
package/catalog.json CHANGED
@@ -218,7 +218,7 @@
218
218
  },
219
219
  {
220
220
  "name": "plan-execution",
221
- "description": "Execute an already-approved plan with discipline — batch tasks into verifiable checkpoints, verify each with fresh evidence before marking it done, log drift, and stop to re-plan when reality diverges from the plan's assumptions. Triggers: execute the plan, implement the approved plan, work through this plan, continue/resume the plan, next phase, checkpoint. NOT for creating plans — 'plan this' / 'break this down' → feature-planning; this skill starts only after a plan exists and is approved.",
221
+ "description": "Execute an already-approved plan with discipline — batch tasks into verifiable checkpoints, verify each with fresh evidence before marking it done, log drift, and stop to re-plan when reality diverges from the plan's assumptions. NOT for creating plans — 'plan this' / 'break this down' → feature-planning; this skill starts only after a plan exists and is approved. Triggers: execute the plan, implement the approved plan, work through this plan, continue/resume the plan, next phase, checkpoint.",
222
222
  "path": "plan-execution/SKILL.md"
223
223
  },
224
224
  {
@@ -323,7 +323,7 @@
323
323
  },
324
324
  {
325
325
  "name": "verification-before-completion",
326
- "description": "Evidence gate before claiming work is done, passing, fixed, or deployed. Use before saying 'done', 'it works', or 'tests pass', or before committing, pushing, or opening a PR. Triggers: is it done, did it work, tests pass, verify, ready to commit, before I push, confirm the fix. Run the proving command fresh and read its output first.",
326
+ "description": "Evidence gate before claiming work is done, passing, fixed, or deployed. Use before saying 'done', 'it works', or 'tests pass', or before committing, pushing, or opening a PR. Run the proving command fresh and read its output first. Triggers: is it done, did it work, tests pass, verify, ready to commit, before I push, confirm the fix.",
327
327
  "path": "verification-before-completion/SKILL.md"
328
328
  },
329
329
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swe-workflow-skills",
3
- "version": "0.6.2",
3
+ "version": "0.7.0",
4
4
  "description": "A curated library of Claude Code Agent Skills covering the full software lifecycle, with orchestrator-routed activation that scales past the skill-listing budget.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,6 +10,36 @@ Help the user make well-reasoned architectural decisions and document them in Ar
10
10
 
11
11
  ## Workflow
12
12
 
13
+ ### Step 0: Inventory What Already Exists
14
+
15
+ If a system is already running, establish what it already provides before
16
+ proposing a new service, module, boundary, or pattern. Map the current state
17
+ **directly** from the codebase — don't infer it from the requirements, the docs,
18
+ or memory. Docs describe the system someone intended; the code is the one you
19
+ have.
20
+
21
+ Cover both:
22
+
23
+ - **Artifacts** — existing services, modules, and seams that already own, or
24
+ could own, the responsibility in question. Search by capability, not just by
25
+ name: the component that does this may be called something else entirely.
26
+ - **Written decisions** — the ADR log, established conventions, and prior audit
27
+ findings. A decision already made and recorded is not yours to re-litigate
28
+ silently; supersede it explicitly or work within it.
29
+
30
+ **Exit condition** — one line, then keep going in the same response:
31
+ *"`<existing component>` already handles `<responsibility>`; it does / does not
32
+ serve this because `<reason>`."*
33
+
34
+ **This step is not a gate on delivering.** Greenfield — nothing built yet, or
35
+ nothing you can reach — closes it in one line: say so and go straight to Step 1.
36
+ When you can't inspect, name what you would check and continue under stated
37
+ assumptions. Never answer a design question with inventory and questions alone;
38
+ carry the options, the recommendation, and the trade-offs in the same reply.
39
+
40
+ This constrains the input, not the choice. A new component is a fine outcome;
41
+ an unexamined one isn't.
42
+
13
43
  ### Step 1: Frame the Decision
14
44
 
15
45
  Identify the exact decision to be made. A good architectural question is specific and scoped:
@@ -26,7 +56,8 @@ If the user's question is too broad, help narrow it by asking:
26
56
 
27
57
  Understand the current state before proposing changes:
28
58
 
29
- - **Current architecture**: What exists today? Read the codebase if available.
59
+ - **Current architecture**: the Step 0 finding — what exists today, established
60
+ from the code rather than assumed. If you can't state it, Step 0 isn't done.
30
61
  - **Quality attributes that matter**: Performance? Scalability? Developer experience? Maintainability? Deployment simplicity?
31
62
  - **Team context**: Team size, expertise, on-call burden
32
63
  - **Growth trajectory**: Expected scale in 6-12 months (not 5 years — YAGNI)
@@ -20,8 +20,14 @@ a PR):
20
20
  !`git diff --stat 2>/dev/null || true`
21
21
 
22
22
  If the summary above is empty or irrelevant to what you were asked to review,
23
- proceed with the code as provided. Before reviewing line-by-line, understand the
24
- big picture:
23
+ proceed with the code as provided.
24
+
25
+ **Called from the pre-commit gate?** When `verification-before-completion` routes
26
+ here before a commit, the review target is `git diff --staged` — the change about
27
+ to be published, not the whole branch. Scope to it, keep the pass proportionate to
28
+ what tripped the gate, and report findings in time to fix them before the commit.
29
+
30
+ Before reviewing line-by-line, understand the big picture:
25
31
 
26
32
  - **What is this code supposed to do?** Read the PR description, linked issue, or ask the user.
27
33
  - **What changed?** If reviewing a diff, understand the scope of changes — run the
@@ -47,6 +53,17 @@ the diff, run three greps before accepting it:
47
53
  exported just to silence the unused-symbol checker).
48
54
  - **Any consumer?** A new schema field, prop, or param that nothing reads or sets is
49
55
  speculative plumbing — the API looks finished but is wired to nothing.
56
+ - **A comment in the wrong place?** For any new comment block of four or more lines,
57
+ ask what it explains. System-level rationale — why the component exists, what was
58
+ rejected, how it relates to other services — belongs in an ADR or architecture doc
59
+ with the comment reduced to a pointer; a local invariant the types can't express
60
+ stays inline; a restatement of the code goes nowhere. The essay-in-a-header rots
61
+ unread and is unfindable by anyone grepping the docs for it.
62
+ - **A reference nobody can resolve?** `Phase 2`, `CP1.3`, `T02`, `finding #17`,
63
+ `checkpoint 3/5` in comments, names, or strings — check whether a **git-tracked**
64
+ document defines it (`git ls-files '*.md' | xargs grep -l`). Anchored, it's a real
65
+ cross-reference. Unanchored, it names a conversation the reader wasn't in: the
66
+ finding is "write the meaning instead of the label".
50
67
  - **Any doc still describing the old shape?** If the diff renames, removes, or adds
51
68
  something a user types or configures — a flag, env var, endpoint, config key,
52
69
  command, script, install step — grep the README and `docs/` for it, old name
@@ -67,8 +84,8 @@ Review the code against these categories, in order of importance. See [reference
67
84
 
68
85
  **Severity levels for findings:**
69
86
 
70
- - 🔴 **Blocker**: Must fix before merge (bugs, security issues, data loss risks) — including a doc the diff makes *wrong* where the doc is an instruction someone follows: install steps, setup commands, the API contract, config keys. A stale instruction fails for the next person, silently, and is worse than no instruction.
71
- - 🟡 **Suggestion**: Should fix, significantly improves quality (principle violations, missing tests, docs the diff leaves incomplete rather than wrong)
87
+ - 🔴 **Blocker**: Must fix before merge (bugs, security issues, data loss risks) — including a doc the diff makes *wrong* where the doc is an instruction someone follows: install steps, setup commands, the API contract, config keys. A stale instruction fails for the next person, silently, and is worse than no instruction. **Secrets or real personal data in the diff are always blockers** — they survive removal in git history, so flag them before the commit, not after.
88
+ - 🟡 **Suggestion**: Should fix, significantly improves quality (principle violations, missing tests, docs the diff leaves incomplete rather than wrong, misplaced comment essays, unanchored internal terminology)
72
89
  - 🔵 **Nit**: Optional improvement (naming, style, minor simplification)
73
90
 
74
91
  ### Step 4: Present Findings
@@ -105,7 +122,7 @@ These are the lenses through which code is examined:
105
122
 
106
123
  **Testability**: Is the code testable? Are there tests? Do tests test behavior or implementation?
107
124
 
108
- **Readability**: Can someone unfamiliar with this code understand it in one reading? Good naming, appropriate comments (why, not what), manageable function length.
125
+ **Readability**: Can someone unfamiliar with this code understand it in one reading? Good naming, manageable function length, and comments that are both *why, not what* and **in the right place** — the why of a system belongs in an ADR the comment points at; the why of a line belongs on the line. Judge "unfamiliar" literally: a reader with the repo and nothing else, who was in none of the conversations that produced it.
109
126
 
110
127
  **Error Handling**: Are errors caught, logged, and handled appropriately? Are error messages helpful? See [references/error-handling.md](references/error-handling.md) for detailed patterns (null safety, exception context, caller-oriented exceptions).
111
128
 
@@ -123,4 +140,5 @@ These are the lenses through which code is examined:
123
140
  - `refactoring` — when the review surfaces code smells worth a structured cleanup
124
141
  - `code-slop-cleanup` — strip AI-slop patterns from the diff before (or instead of) debating them in review
125
142
  - `security-audit` — for a dedicated, deep security pass beyond the review checklist
126
- - `verification-before-completion` — verify the change actually runs before approving, not from the diff alone
143
+ - `verification-before-completion` — verify the change actually runs before approving, not from the diff alone; also the pre-commit gate that routes staged diffs here
144
+ - `architecture-design` — where a system-level rationale found in a comment belongs instead (an ADR)
@@ -21,9 +21,9 @@
21
21
  "prompt": "Can you review the changes in my last git commit?",
22
22
  "expected_output": "Should read the git diff, understand context from surrounding files, and perform a structured review.",
23
23
  "assertions": [
24
- "Runs git diff or git show to read the changes",
25
- "Reads surrounding code for context",
26
- "For any new helper, export, or block, greps the repo beyond the diff for an existing twin, for importers, and for consumers (duplication / dead export / unconsumed surface are invisible in a single hunk)",
24
+ "Names the command that reads the change (git show / git diff HEAD~1) and scopes the review to that commit",
25
+ "Establishes the surrounding code as context for the review rather than judging the hunk in isolation",
26
+ "For any new helper, export, or block, states it will search the repo beyond the diff for an existing twin, for importers, and for consumers (duplication / dead export / unconsumed surface are invisible in a single hunk)",
27
27
  "Follows the structured review format (summary, blockers, suggestions, nits)",
28
28
  "Provides specific file:line references for findings"
29
29
  ]
@@ -89,6 +89,22 @@
89
89
  "Justifies the severity: a wrong instruction is followed and then fails, which is worse than a missing one",
90
90
  "Does NOT approve on 'code is consistent and CI is green' alone"
91
91
  ]
92
+ },
93
+ {
94
+ "id": 4,
95
+ "prompt": "The pre-commit gate routed you here. Review the staged diff: it adds `src/server/dashboard.ts` with a 14-line file-header block explaining why dashboard state lives in a second SQLite file, which tables get wiped on rebuild, and why the read handle stays read-only — the header cites ADR-018. Below that are two query functions, one commented `// Aggregates (Phase 4). Read-only.` The repo has docs/decisions/ADR-018 tracked, but no tracked doc mentions any phase.",
96
+ "pressure": [
97
+ "looks_good"
98
+ ],
99
+ "expected_behavior": "Scopes to the staged diff rather than the whole branch. Flags the 14-line header as misplaced rationale — it duplicates the ADR it cites, so it should shrink to a pointer — and flags 'Phase 4' as unanchored after checking the tracked docs, while correctly leaving the ADR-018 reference alone since that document is tracked. Assigns both as suggestions, not blockers.",
100
+ "assertions": [
101
+ "Scopes the review to the staged diff",
102
+ "Flags the 14-line header as rationale that belongs in the ADR, reduced to a pointer",
103
+ "Checks the tracked docs before judging the terminology rather than assuming",
104
+ "Flags 'Phase 4' as unanchored and recommends writing the meaning",
105
+ "Does NOT flag the ADR-018 reference, which resolves to a tracked document",
106
+ "Rates these as suggestions rather than blockers"
107
+ ]
92
108
  }
93
109
  ]
94
110
  }
@@ -33,8 +33,13 @@ Slop is relative — the same construct is correct in one place and slop in anot
33
33
 
34
34
  - **High**: debug leftovers, silent-failure handlers, stray working files
35
35
  - **Medium**: defensive theater on trusted paths, generic TODOs, unrequested backwards-compat shims, duplication of existing helpers
36
+ - **Medium**: also unanchored internal terminology (`Phase 2`, `CP1.3`, `finding #17`) that no git-tracked doc defines — rewrite to the meaning
36
37
  - **Low**: comment slop, dead weight (unused imports, `=== true`, redundant returns), style inconsistent with the file
37
38
 
39
+ Misplaced rationale — the multi-line header essay explaining a *system* instead of
40
+ the code beneath it — is detected here but **routed, not deleted**: the reasoning
41
+ belongs in an ADR, and deleting it loses something nothing else records.
42
+
38
43
  ### Step 4: Strip — Deletions Only, Production Code Only
39
44
 
40
45
  Apply removals highest severity first. Every edit must be a behavior-preserving deletion (or a trivial inlining a deletion forces). If removing something requires *rewriting* logic around it, that's refactoring — leave it and flag it.
@@ -71,6 +76,8 @@ The biggest slop category — duplication — is created at generation time and
71
76
  |--------|---------|
72
77
  | "This check might catch something someday" | If nothing upstream can produce that state, it's theater — and it hides the real bugs by normalizing noise. |
73
78
  | "The comments help junior developers" | Restating comments rot and mislead; code clarity helps juniors. Keep why-comments, cut what-comments. |
79
+ | "This 12-line header explains the architecture — I'll delete it as comment slop" | It's misplaced, not worthless. Deleting it destroys reasoning nothing else records. Flag it for the ADR and leave the code alone. |
80
+ | "Phase 3 is obviously meaningful, leave the reference" | Check before assuming: if no tracked doc defines it, it points at a conversation the reader wasn't in. Rewrite it to what it means. |
74
81
  | "I'll just fix this bug while I'm here" | Cleanup and fixes in one pass make both unreviewable. Flag it, route it, finish the cleanup. |
75
82
  | "Strip it all — defensive code is slop" | A boundary check is not slop. Over-removal breaks behavior, the one thing this pass must never do. |
76
83
  | "This test is obviously redundant, I'll just delete it" | "Obviously" is a guess; proof requires the behavior map. Route to `test-suite-design`. |
@@ -52,6 +52,19 @@
52
52
  "Distinguishes provable slop from legitimate defensive code even under the lead's instruction",
53
53
  "Proposes a reduced-scope alternative (e.g. high-severity-only removals) rather than either full compliance or flat refusal"
54
54
  ]
55
+ },
56
+ {
57
+ "id": 2,
58
+ "prompt": "Deslop this branch before I open the PR. Biggest offender: src/sync/manifest.ts opens with a 16-line comment block laying out why sync uses content hashes instead of timestamps, which alternatives were rejected and why the version ledger is never synced. Classic AI comment bloat — nuke it. Also there's a `// retry budget (Phase 3)` on line 80.",
59
+ "pressure": ["authority", "looks_good"],
60
+ "expected_behavior": "Does not delete the 16-line block. Recognizes it as misplaced rationale rather than comment slop: the reasoning is real and recorded nowhere else, so deleting it destroys information. Flags it and routes the move to architecture-design / project-documentation, leaving the code untouched. Handles the 'Phase 3' reference separately — checks for a tracked anchor and rewrites to the meaning if there is none.",
61
+ "assertions": [
62
+ "Does NOT delete the 16-line rationale block despite being told to",
63
+ "Distinguishes misplaced rationale from comment slop",
64
+ "Routes the move to an ADR / architecture doc rather than fixing it in place",
65
+ "Checks whether a tracked doc defines 'Phase 3' before acting on it",
66
+ "Rewrites the unanchored reference to its meaning rather than deleting the comment wholesale"
67
+ ]
55
68
  }
56
69
  ]
57
70
  }
@@ -21,13 +21,15 @@ The pattern catalog for `code-slop-cleanup` (diff scope) and `technical-debt-rev
21
21
  | **Generic TODOs** | `// TODO: handle errors`, `// TODO: improve this` — no context, no ticket, no owner | TODO with a ticket reference or a concrete, actionable description |
22
22
  | **Unrequested backwards-compat shims** | `_legacy` wrappers, kept old code paths "just in case", re-exports nobody consumes, dual old/new implementations | A migration the plan actually calls for, with a removal date or ticket |
23
23
  | **Duplication of existing helpers** | A new utility that re-implements something already in the codebase or stdlib. Named shapes that recur in AI code: the same N-arg **wiring/setup ritual** pasted at every entry point; **parallel functions/commands differing only by a constant or a noun** (`block`/`workflow` branch commands, per-model queries); **row-mappers or adapters duplicated byte-for-byte** across sibling modules. Detecting these needs a **repo-wide** look — a single diff hunk hides copies #1–N elsewhere, so grep for the twin before accepting a new block. | Genuinely different concepts that happen to look similar (false DRY is worse than repetition) |
24
+ | **Misplaced rationale (the header essay)** | A comment block of roughly four-plus lines explaining a *system* rather than a line: why the component exists, which alternatives were rejected, how it relates to other services, the whole trade-off behind a design. Often opens a file and often cites an ADR it is busy duplicating. The tell is that the comment would read correctly as a section of an architecture doc, with nothing tying it to the code beneath it. The fix is a *move* — rationale to the ADR/architecture doc, a one-line pointer left behind (`// Triage state lives in a separate writable DB; see ADR-018.`) — so the reasoning survives where it can be found and reviewed. **A move is not a deletion: during slop cleanup, flag it and route (see the routed table below); never delete the block outright,** which would destroy reasoning nothing else records. | A genuinely local invariant that happens to need several lines to state — why *this* comparison must be `date(col) >= date(?)`, a consequence the caller cannot see, a boundary condition the types don't express. Length is not the test; whether it explains the code below it is. Also: file headers the project's own convention mandates, and generated-doc blocks. |
25
+ | **Unanchored internal terminology** | `Phase 2`, `Fase 4`, `CP1.3`, `checkpoint 3/5`, `T02`, `P2-E08`, `finding #17`, `Sprint 4` in comments, identifiers, or strings, where **no git-tracked document defines the term**. It names a plan, chat, or scratchpad the reader has no access to. Check, don't assume: `git ls-files '*.md' \| xargs grep -l "P2-E08"`. Fix by rewriting to the meaning — `// Dashboard aggregates (Phase 4). Read-only.` → `// Dashboard aggregates. Read-only.` — which usually *improves* the sentence, since the label carried no information. | The term **is** defined in a tracked doc (an execution plan under `docs/`, an ADR, a roadmap): then it's a real cross-reference and removing it loses information. Prefer making the pointer explicit. Also: issue/PR numbers on a public tracker, and version tags. |
24
26
  | **Unconsumed surface / speculative plumbing** | Exports with no importers anywhere (the `_`-prefix + `export` tell — exported only to silence the unused-symbol checker); a fully-built, unit-tested module never wired into any path; a schema field validated but never read, a prop threaded through layers but never set, a param carried "for symmetry" but unused, a value computed but never surfaced. The API *looks* finished; nothing calls it. | A library/package's genuine public API; params required by an interface/callback signature; a documented extension point with a near-term, named consumer landing in the same change |
25
27
 
26
28
  ## Low severity — cosmetic residue
27
29
 
28
30
  | Pattern | Tells | When it's NOT slop |
29
31
  |---------|-------|--------------------|
30
- | **Comment slop** | Comments restating the code (`// increment counter`), section dividers, agent narration ("Here we now handle…"), docstrings repeating the signature, journal comments, a **changelog / version-history block embedded in source** (belongs in CHANGELOG/ADR), a **stale comment describing a scheme the code no longer implements** (actively misleading, worse than none) | Why-comments on non-obvious decisions; consequence warnings; docstrings on public API the project mandates |
32
+ | **Comment slop** | Comments restating the code (`// increment counter`), section dividers, agent narration ("Here we now handle…"), docstrings repeating the signature, journal comments, a **changelog / version-history block embedded in source** (belongs in CHANGELOG/ADR), a **stale comment describing a scheme the code no longer implements** (actively misleading, worse than none) | Why-comments on non-obvious decisions *about the code they sit on*; consequence warnings; docstrings on public API the project mandates. Where the why concerns the system rather than the line, see **Misplaced rationale** above — that one is moved, not deleted |
31
33
  | **Dead weight** | Unused imports/params/variables, `return undefined`, `=== true`, `Promise.all` around a single promise, unreachable branches | Parameters required by an interface/callback signature; re-exports that are the module's public API |
32
34
  | **Style inconsistency** | Naming, formatting, or idiom that doesn't match the surrounding file (e.g. `fetchData` in a file that uses `getX` everywhere) | The file itself is inconsistent and the new code follows the project-level convention |
33
35
 
@@ -37,6 +39,7 @@ These are slop, but this catalog's consumers don't fix them in place:
37
39
 
38
40
  | Pattern | Tells | Route to |
39
41
  |---------|-------|----------|
42
+ | **Misplaced rationale (the header essay)** | See the medium table above. Detection is in scope here; the fix isn't. | `architecture-design` (the ADR the rationale belongs in) or `project-documentation` (an existing architecture doc). Deleting the block during cleanup would lose reasoning nothing else records — flag it, name the destination, leave the code alone. |
40
43
  | **Test-file slop** | Redundant/duplicate tests, trivial asserts (`expect(true)`), asserting on the mock, implementation-mirroring tests | `test-suite-design` (Pruning Test Slop) — deleting a test is never behavior-neutral for the safety net; it needs behavior-map judgment. **Never delete a test during diff cleanup.** |
41
44
  | **Type slop** | `any`/`unknown` to silence the checker, casts papering over mismatches, single-implementer interfaces "for testing", overly broad types (`env: object` then `type: ignore` to reach a field), **stale `type: ignore` matching no current error**, a **declared strict gate (`mypy strict`, `--max-warnings 0`) sitting on N errors** because nobody runs it | `technical-debt-review` (type debt) — usually cross-file; fixing it changes signatures. Running the gate green is the `verification-before-completion` "done" step |
42
45
  | **Config/scaffolding slop** | Config keys and feature flags nothing reads, orphan `.env` entries, checked-in generated files, half-finished TODO scaffolds | `technical-debt-review` (config/scaffolding debt) — proving "unread" needs repo-wide tracing |
@@ -8,6 +8,33 @@ allowed-tools: Read, Grep, Glob, Write, Edit
8
8
 
9
9
  Design configuration that is safe, auditable, and easy to change. Most configuration problems (hardcoded secrets, production config in dev, feature flags with no off-switch) come from not designing the system upfront.
10
10
 
11
+ ## Step 0: Inventory What Already Exists
12
+
13
+ Before introducing a new environment variable, secret, feature flag, or
14
+ constant, establish what the project already defines. Inspect the current state
15
+ **directly** — grep the tree; don't infer it from the requirements or memory.
16
+
17
+ Cover both:
18
+
19
+ - **Artifacts** — existing key names *and* the values themselves. Search for the
20
+ literal value, not just the name: the same timeout or limit is often already
21
+ hardcoded in two places, and adding a third is the common failure.
22
+ - **Written decisions** — config conventions, naming schemes, `.env.example`,
23
+ and prior audit findings that already govern where things live.
24
+
25
+ **Exit condition** — one line, then keep going in the same response:
26
+ *"`<existing key>` already carries `<value>`; it does / does not serve this
27
+ because `<reason>`."*
28
+
29
+ **This step is not a gate on delivering.** Greenfield — nothing configured yet,
30
+ or nothing you can reach — closes it in one line: say so and go straight to
31
+ Step 1. When you can't inspect, name what you would check and continue under
32
+ stated assumptions. Never answer with inventory and questions alone; produce the
33
+ configuration design in the same reply.
34
+
35
+ This constrains the input, not the choice. A new key is a fine outcome; an
36
+ unexamined one isn't — and a duplicated value will drift.
37
+
11
38
  ## Step 1: Identify All Configuration Needed
12
39
 
13
40
  List every piece of configuration the feature or service requires:
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: data-modeling
3
3
  description: "Design database schemas, relationships, indexes, and migration strategies — relational and document stores. Triggers: data model, schema design, ER diagram, database schema, table design, foreign key, index strategy, normalization, denormalization, migration plan, document model, partition key."
4
- allowed-tools: Read, Grep, Glob, Write, Edit
4
+ allowed-tools: Read, Grep, Glob, Write, Edit, Bash
5
5
  ---
6
6
 
7
7
  # Data Modeling
@@ -10,6 +10,36 @@ Guide the user through designing data models that are normalized, consistent, an
10
10
 
11
11
  ## Workflow
12
12
 
13
+ ### Step 0: Inventory What Already Exists
14
+
15
+ If any database exists, establish what it already holds before proposing a
16
+ single new table, column, or index. Inspect the current schema **directly** —
17
+ don't infer it from the requirements, the ORM models, or memory. Dump it from
18
+ the live database where you can reach one, otherwise read the migration history
19
+ end to end.
20
+
21
+ Cover both:
22
+
23
+ - **Artifacts** — existing tables, columns, and indexes that hold, or could
24
+ hold, the fact in question. Grep for the concept by name and by synonym; the
25
+ right table is often named for a different concern than the one you're serving.
26
+ - **Written decisions** — ADRs, schema conventions, and prior audit findings
27
+ that already constrain the shape.
28
+
29
+ **Exit condition** — one line, then keep going in the same response:
30
+ *"`<existing table>` already stores `<fact>`; it does / does not serve this
31
+ because `<reason>`."*
32
+
33
+ **This step is not a gate on delivering.** Greenfield — no database yet, or none
34
+ you can reach — closes it in one line: say so and go straight to Step 1. When
35
+ you can't inspect (no repo access, a conversational answer), name what you would
36
+ check and continue under stated assumptions. Never answer a schema request with
37
+ inventory and questions alone; produce the model in the same reply.
38
+
39
+ This constrains the input, not the choice. A new table is a fine outcome; an
40
+ unexamined one isn't — and a second home for the same fact is duplication
41
+ however well it's named.
42
+
13
43
  ### Step 1: Understand the Domain
14
44
 
15
45
  Before touching schemas, understand the business domain:
@@ -14,6 +14,35 @@ Design the technical structure of frontend applications — component hierarchy,
14
14
 
15
15
  ## Workflow
16
16
 
17
+ ### Step 0: Inventory What Already Exists
18
+
19
+ In an existing codebase, establish what the app already provides before adding a
20
+ new component, hook, store, or token. Search the shared surfaces **directly** —
21
+ `components/`, `hooks/`, `lib/`, the token file, and each feature's public
22
+ `index.ts` — rather than inferring from the design or from memory.
23
+
24
+ Cover both:
25
+
26
+ - **Artifacts** — existing components, hooks, stores, and tokens that already
27
+ cover, or nearly cover, the need. Search by behavior, not just by name: the
28
+ component you want often exists under a different label.
29
+ - **Written decisions** — established conventions, the design system's rules,
30
+ and prior audit findings.
31
+
32
+ **Exit condition** — one line, then keep going in the same response:
33
+ *"`<existing component/hook>` already covers `<behavior>`; it does / does not
34
+ serve this because `<reason>`."*
35
+
36
+ **This step is not a gate on delivering.** Greenfield — a new app, or a codebase
37
+ you can't reach — closes it in one line: say so and go straight to Step 1. When
38
+ you can't inspect, name what you would check and continue under stated
39
+ assumptions. Never answer with inventory and questions alone; produce the
40
+ architecture in the same reply.
41
+
42
+ This constrains the input, not the choice. A new component is a fine outcome; an
43
+ unexamined one isn't — a near-duplicate of an existing one is how design systems
44
+ rot.
45
+
17
46
  ### Step 1: Design the Component Hierarchy
18
47
 
19
48
  Start from the UI design (or the screen spec from `ui-ux-design`) and decompose into components:
@@ -26,6 +26,26 @@ Identify:
26
26
  - **Why did it change?** (feature, bugfix, refactor, dependency update)
27
27
  - **Is this one logical change or multiple?** If multiple, suggest splitting into separate commits.
28
28
 
29
+ **This step is not a gate on writing the message.** Read the diff **and** draft in
30
+ the **same response** — "write me a commit message" is a request for a message, and
31
+ someone who says the changes are staged has already authorized the read. Never open
32
+ with a request to go run a command and come back, and **never close with one
33
+ either**: "if you'd rather I do this properly, let me read the diff and return" is
34
+ the same round-trip moved to the end, and it tells the developer the message you
35
+ just handed them was the inferior option.
36
+
37
+ **The diff is the basis, not an optional cross-check.** When you genuinely cannot
38
+ read it, still deliver the message, and carry the requirement forward as a stated
39
+ gap rather than an offer: *"Drafted from your description — check it against
40
+ `git diff --staged` before committing, since the scope line depends on what's
41
+ actually in there."* That is a deferred requirement. "Want me to look?" is not.
42
+
43
+ **Brevity applies to the message, not to the judgment.** However short the message,
44
+ the scope call above still ships with it: say whether this looked like one logical
45
+ change, and name the split if it wasn't. That's the part the developer can't
46
+ recover from the diff themselves — it's the reason they asked you rather than
47
+ writing the line by hand.
48
+
29
49
  ### Step 2: Write the Commit Message
30
50
 
31
51
  Use the Conventional Commits format — see [references/conventions.md](references/conventions.md):
@@ -41,13 +61,50 @@ Use the Conventional Commits format — see [references/conventions.md](referenc
41
61
  **The subject line** (first line):
42
62
  - Type: `feat`, `fix`, `refactor`, `test`, `docs`, `chore`, `perf`, `ci`, `build`
43
63
  - Scope: The module, component, or area affected (optional but recommended)
44
- - Description: Present tense, lowercase, no period, under 50 characters
64
+ - Description: Present tense, lowercase, no period, **72 characters total** including
65
+ the `type(scope):` prefix — the commitlint default, and what keeps `git log --oneline`
66
+ readable in an 80-column terminal. (The older 50-char rule predates Conventional
67
+ Commits: a `fix(skills): ` prefix spends 13 characters before you write a word.)
45
68
  - It should complete the sentence: "If applied, this commit will..."
46
69
 
47
- **The body** (optional but valuable for non-trivial changes):
48
- - Explain WHY this change was made, not WHAT changed (the diff shows what)
49
- - Include context that isn't obvious from the code
50
- - Wrap at 72 characters
70
+ Where a tool generates the changelog (release-please, changesets, semantic-release),
71
+ **this line is the changelog entry** a consumer reads at upgrade time — and on a
72
+ squash-merge repo, that means the **PR title** is. Write it for the person deciding
73
+ whether to upgrade, not for yourself: `fix(api): reject expired tokens on refresh`
74
+ tells them something; `fix(api): address review feedback` is true and useless. The
75
+ type prefix picks the changelog section too, so a mislabeled type hides the entry or
76
+ files it under the wrong heading.
77
+
78
+ **The body** — governed by one test:
79
+
80
+ > **Delete any sentence a reader could reconstruct from the diff.**
81
+
82
+ The diff is attached to the message. Every line spent restating it is a line the
83
+ reviewer must read to discover it says nothing, which is why over-long messages
84
+ make review *worse*, not more thorough. What survives the test is what the diff
85
+ cannot show:
86
+
87
+ - **Why now** — the trigger, the bug report, the constraint that forced it
88
+ - **What was rejected** — the approach you didn't take, and what ruled it out
89
+ - **The non-obvious consequence** — what this breaks, enables, or quietly changes
90
+ - **Why nobody noticed** — for bugs, often the most valuable sentence in the message
91
+
92
+ And what fails it: file-by-file enumerations, "renamed X to Y", "added a test for
93
+ Z", restating the type signature, narrating the steps you took.
94
+
95
+ Length follows from that, not from the size of the change:
96
+
97
+ | Change | Body |
98
+ |---|---|
99
+ | Mechanical — rename, format, dep bump, generated file, typo | **None.** The subject is the whole message. |
100
+ | Ordinary — a feature or fix whose reasoning is visible in the code | A sentence or two, or none. |
101
+ | Subtle — a non-obvious bug, a rejected alternative, a surprising constraint | However long the reasoning actually is. |
102
+
103
+ A long message is not a failure. An *unearned* long message is. Do not compress a
104
+ message that carries real reasoning just to make it short — that loses the only
105
+ part worth keeping.
106
+
107
+ Wrap at 72 characters.
51
108
 
52
109
  **The footer** (optional):
53
110
  - Reference issues: `Closes #123`, `Fixes #456`
@@ -58,13 +115,35 @@ Commit types are not just style — in automated release flows they drive the ve
58
115
  `fix` → PATCH, `feat` → MINOR, `feat!`/`BREAKING CHANGE:` → MAJOR. A mislabeled type
59
116
  mis-versions the next release (see `release-management`).
60
117
 
61
- ### Step 3: Validate
118
+ ### Step 3: Validate — Re-read the Message You Just Wrote
62
119
 
63
- Before committing, check:
120
+ Not a checklist to nod at: **read the drafted message back against the rules
121
+ above, line by line, before you commit.** These constraints are trivially easy to
122
+ state and trivially easy to skip — a subject line drifts past its limit, a
123
+ body accumulates a restatement paragraph, and nothing ever catches it because the
124
+ message is never re-read.
125
+
126
+ - [ ] **Read the subject as a stranger.** Does it name the behavior change on its own?
127
+ That's the real test; 72 characters is the ceiling, not the goal. Over it, cut
128
+ words — and if it can't be cut, ask whether it's more than one change.
129
+ - [ ] **Apply the recoverability test to each body sentence.** Could the reader
130
+ get this from the diff? Then delete it. Whatever's left is the message.
64
131
  - [ ] Is this a single logical change? (If not, split it)
65
- - [ ] Does the subject line describe the behavior change, not the implementation?
132
+ - [ ] Does the subject describe the behavior change, not the implementation?
66
133
  - [ ] Would someone understand why this commit exists 6 months from now?
67
134
  - [ ] Are related issue numbers referenced?
135
+ - [ ] Does the message use vocabulary a reader can resolve? Phase names,
136
+ checkpoint IDs, and task codes belong in a commit only when a tracked
137
+ document defines them — otherwise write what they mean.
138
+
139
+ Then **invoke `verification-before-completion`** — committing is publishing, and
140
+ that skill owns the publish gate.
141
+
142
+ **Exit condition** — name it, by name, in the response where you commit:
143
+ *"Invoking `verification-before-completion` on the staged diff before this commit."*
144
+
145
+ Don't substitute your own reading of the diff for the call. Knowing roughly what
146
+ that gate looks for is precisely what makes skipping it feel harmless.
68
147
 
69
148
  ## Workflow: PR Descriptions
70
149
 
@@ -95,6 +174,14 @@ Use the template at [templates/pull-request.md](templates/pull-request.md). Key
95
174
 
96
175
  The PR description should let a reviewer understand the change without reading every line of code first.
97
176
 
177
+ The same recoverability test governs here, and it bites hardest on **Changes**:
178
+ that section is for the handful of changes a reviewer would otherwise miss, not a
179
+ transcription of the file list they can already see. If a bullet only names a file
180
+ and what obviously happened to it, cut the bullet. **Why**, **How**, and the
181
+ reviewer notes are where a PR description earns its length — a reviewer who reads
182
+ three paragraphs of restatement before reaching the one real trade-off is worse
183
+ off than one who read nothing.
184
+
98
185
  ### Step 3: Self-Review
99
186
 
100
187
  Before requesting review, invoke `verification-before-completion` — opening a PR
@@ -141,6 +228,30 @@ See [references/conventions.md](references/conventions.md) for branch naming con
141
228
  - **DRY**: If you're writing the same commit message pattern repeatedly, you might be making commits too granular or too broad.
142
229
  - **Functional Independence**: Each PR should be independently deployable when possible. Avoid PRs that depend on other unmerged PRs.
143
230
 
231
+ ## Rationalizations to Reject
232
+
233
+ | Excuse | Reality |
234
+ |--------|---------|
235
+ | "A thorough message is better than a short one" | Thorough about the *reasoning*, yes. Thorough about what the diff already shows is padding the reviewer has to read past to find the reasoning. |
236
+ | "The subject needs all of this to be clear" | If the change can't be named in 72 characters, that's usually a signal it's more than one change. Split it, or move the detail to the body. |
237
+ | "I'll list the changes so reviewers know what to look at" | They have the diff and the file list. Point at the *non-obvious* change; enumerating the rest buries it. |
238
+ | "This is a big change, so it needs a big message" | Length tracks unrecoverable reasoning, not lines touched. A 2,000-line mechanical rename needs one line. |
239
+ | "Documenting the decision here saves writing an ADR" | A commit message is the worst place to look up a decision — nobody greps git log. Write the ADR (`architecture-design`) and reference it. |
240
+ | "The phase/task ID gives it traceability" | Only if a tracked doc defines it. Otherwise it traces to a conversation the reader wasn't in. |
241
+ | "I'll just commit and fix the message later" | Amending after a push rewrites history others have pulled. The message is part of the commit, not a follow-up. |
242
+ | "I should read the diff before I can write anything" | Read it *and* draft, in the same reply. Asking the developer to run a command and come back is a round-trip they didn't ask for — and if you truly can't read it, a drafted message with a stated assumption is more useful than a question. |
243
+
244
+ ## Red Flags — Stop and Re-Read
245
+
246
+ - You wrote the body without re-reading the subject line's character count.
247
+ - A body paragraph could be reconstructed by anyone with the diff open.
248
+ - The message enumerates files or functions that changed.
249
+ - You're about to commit without having read `git diff --staged` this session.
250
+ - The message contains a phase, checkpoint, task code, or finding number, and no
251
+ tracked document defines it.
252
+ - You're writing a commit body for a rename, a formatting pass, or a dep bump.
253
+ - Your reply to "write me a commit message" contains no commit message.
254
+
144
255
  ## Cross-Skill References
145
256
 
146
257
  - `release-management` — cutting the release these commits accumulate into: semver, changelog, tagging, publishing
@@ -4,12 +4,12 @@
4
4
  {
5
5
  "id": 1,
6
6
  "prompt": "I just finished implementing a user notification feature. I've staged all changes. Write a good commit message for me.",
7
- "expected_output": "Should read the staged diff first, then write a Conventional Commits formatted message with type, scope, subject, and body explaining why.",
7
+ "expected_output": "Should read the staged diff and deliver the drafted message in the same reply — not ask the developer to run a command and come back, and not close by offering to redo it properly once the diff is read. Conventional Commits format, subject within 72 characters including the type(scope): prefix, and a body only where the change carries reasoning the diff cannot show. The scope judgment ships with the message: whether this is one logical change, and the split if it isn't. RUN THIS CASE AT k>=3: the base model is bimodal on this prompt — observed 6/6 and 1/6 on identical input in consecutive k=1 runs, sometimes drafting and sometimes asking for the diff, which is the very behavior under test. A single sample cannot support a lift claim either way.",
8
8
  "assertions": [
9
- "Runs git diff --staged to read the actual changes",
9
+ "Establishes the actual staged changes as the basis for the message (naming git diff --staged as what it must read) rather than writing from the feature description alone",
10
10
  "Uses Conventional Commits format (type(scope): description)",
11
- "Subject line is under 50 characters",
12
- "Body explains WHY, not just WHAT",
11
+ "Subject line is within 72 characters including the type(scope): prefix",
12
+ "Writes a body only if the change carries reasoning the diff cannot show; for an ordinary change it says no body is needed rather than padding one (per the skill's body ladder)",
13
13
  "Checks if the staged changes are a single logical unit",
14
14
  "If multiple logical changes, suggests splitting into separate commits"
15
15
  ]
@@ -19,7 +19,7 @@
19
19
  "prompt": "I need to write a PR description for a branch that adds Stripe payment integration. The branch has 12 commits including some WIP and fix-typo commits. We're using a standard PR template.",
20
20
  "expected_output": "Should read the branch diff and commit log, suggest squashing the WIP commits, then write a structured PR description.",
21
21
  "assertions": [
22
- "Reads git log and diff for the branch",
22
+ "Names the git log / git diff commands that establish the branch's scope, or works from the branch state given",
23
23
  "Suggests cleaning up the 'WIP' and 'fix-typo' commits via rebase/squash",
24
24
  "Writes a complete PR description with What/Why/How/Testing sections",
25
25
  "Links to the relevant issue or task",
@@ -56,6 +56,38 @@
56
56
  "Treats opening the PR as a completion claim (invokes or defers to verification-before-completion)",
57
57
  "Does NOT tick the 'Documentation updated' checklist item without having verified it"
58
58
  ]
59
+ },
60
+ {
61
+ "id": 2,
62
+ "prompt": "Staged: a pure rename of `getUserData` to `fetchUserProfile` across 23 files, plus the prettier reformat that came with it. No behavior change. Write me a really thorough commit message — I want the reasoning fully documented for the team so nobody wonders later.",
63
+ "pressure": [
64
+ "authority",
65
+ "looks_good"
66
+ ],
67
+ "expected_behavior": "Applies the recoverability test rather than the request for thoroughness: a mechanical rename has no unrecoverable reasoning, so the subject line is the whole message. Writes no body (or at most one line naming why the rename happened, if that isn't visible), and explains why padding it would make review worse rather than complying with 'thorough'.",
68
+ "assertions": [
69
+ "Writes a subject line within 72 characters including the type(scope): prefix",
70
+ "Does NOT produce a multi-paragraph body for a mechanical rename",
71
+ "Does not enumerate the 23 files or restate what the diff shows",
72
+ "Explains that length tracks unrecoverable reasoning, not lines touched",
73
+ "Considers whether the reformat should be split into its own commit"
74
+ ]
75
+ },
76
+ {
77
+ "id": 3,
78
+ "prompt": "Here's the fix: the markdown filter returned a plain str while Jinja runs with autoescape on, so every tag it produced got escaped back into the page. It only showed up in multi-paragraph fields because plain-text bullets hit the single-<p> unwrap and had nothing left to escape. I also pinned markdown-it to html=False, since marking the output safe without that would let imported JSON data inject HTML. Keep the commit message short — one line, we don't need an essay.",
79
+ "pressure": [
80
+ "authority",
81
+ "time"
82
+ ],
83
+ "expected_behavior": "Resists over-correcting into terseness. This change carries reasoning the diff cannot show — why the bug was invisible, and why the html=False pin is load-bearing for security — so the body earns its length. Pushes back on 'one line' and writes the body, while still keeping the subject tight and cutting anything the diff already shows.",
84
+ "assertions": [
85
+ "Writes a body rather than complying with the one-line request",
86
+ "Keeps the 'why nobody noticed' explanation (the single-<p> unwrap)",
87
+ "Keeps the security rationale for the html=False pin",
88
+ "Still holds the subject line to the length rule",
89
+ "Does not pad the body with restatement of the diff"
90
+ ]
59
91
  }
60
92
  ]
61
93
  }