@dennisrongo/skills 0.5.0 → 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/README.md +2 -0
- package/package.json +1 -1
- package/skills/_template/SKILL.md +8 -0
- package/skills/code-review/SKILL.md +25 -4
- package/skills/codebase-explainer/SKILL.md +13 -6
- package/skills/conventional-commits/SKILL.md +10 -3
- package/skills/diagnose/SKILL.md +31 -0
- package/skills/dotnet-onion-api/SKILL.md +40 -3
- package/skills/grill-with-docs/SKILL.md +19 -3
- package/skills/handoff/SKILL.md +11 -1
- package/skills/improve-codebase-architecture/SKILL.md +11 -1
- package/skills/nextjs-app-router/SKILL.md +36 -3
- package/skills/plan-and-build/SKILL.md +11 -1
- package/skills/pr-review/SKILL.md +25 -1
- package/skills/ship-it/SKILL.md +15 -5
- package/skills/sql-review/SKILL.md +253 -0
- package/skills/task-executor/SKILL.md +15 -2
- package/skills/tauri-2-app/SKILL.md +28 -4
- package/skills/think-like-fable/SKILL.md +101 -0
- package/skills/write-a-skill/SKILL.md +29 -0
package/README.md
CHANGED
|
@@ -104,8 +104,10 @@ node bin/claude-skills.js list
|
|
|
104
104
|
| [`plan-and-build`](./skills/plan-and-build/SKILL.md) | Plan-first feature builder. Grills the user about the feature (à la `grill-with-docs`) until the design is unambiguous, detects the project's stack and conventions, presents a plan, and gates on `ExitPlanMode` approval before writing any code. When Phase 3 hits a genuine design fork (service-layer vs. CQRS, new table vs. nullable columns, sync vs. background job, etc.) and Phase 2 didn't settle it, runs **Design It Twice**: two parallel sub-agents each draft the BEST plan for one side of the named axis, then an inline debate names three wins for each and recommends one — the user sees a single recommended plan with a one-line "considered alternative" note so they can redirect with one sentence. Skipped when an existing pattern in the repo already dictates the approach. Builds TDD-first with NUnit when a .NET API changes — appending to the matching test class if one already exists rather than forking a parallel one — reuses existing patterns, keeps comments minimal, and generates EF Core / migration files **without ever** running `dotnet ef database update` or any DDL/SQL against the user's database. Triggers on "build/add/implement a feature", "/plan-and-build", or a pasted feature spec. |
|
|
105
105
|
| [`pr-review`](./skills/pr-review/SKILL.md) | Structured review of a local branch, **grouped per `#NNN` task** referenced in commit messages, prioritized correctness → design → tests → security → performance → readability, with categorized feedback (`blocking` / `suggestion` / `question` / `nit` / `praise`). On non-trivial tasks, convenes a **per-task lens council**: parallel `Explore` sub-agents through distinct lenses (correctness / design / security / tests) on that task's diff only, followed by an **adversarial critique round** that demotes false-positive blockers when another lens defuses them, surfaces contradictions as `question` items for the user, and promotes findings raised by multiple lenses independently. Small tasks skip the council. The council never crosses task boundaries — each `#NNN` gets its own verdict. Triggers on "review my PR", "review the diff", "review my branch", or `/pr-review`. |
|
|
106
106
|
| [`ship-it`](./skills/ship-it/SKILL.md) | Pre-launch **operational-readiness** gate for a feature, release, or branch — the complement to [`code-review`](./skills/code-review/SKILL.md). Walks a fixed 10-category checklist (logging, error handling, telemetry, feature flags, migrations, rollback strategy, secrets, local-first storage, auth, update strategy) against the named scope and produces a structured report with PASS / GAP / N/A per item — every PASS backed by a `file:line` citation, every GAP labelled `no evidence found at <path>`, every N/A justified in one line. The final verdict groups findings as **Blocking** (secrets in code, missing authz on a new endpoint, destructive migration without rollback, no way to disable the change in prod) / **Should-fix** / **N/A with reason** / **Passing**, then asks per-blocker whether to draft a fix. **Never edits code unprompted** and **forces scope before auditing** — a PR, a flag, a release tag, or a module — so the output stays actionable. Distinct from `code-review` (diff quality) and `pr-review` (branch / per-task review): `ship-it` is the operational gate that catches what diff-level reviews don't surface. Triggers on "is this ready to ship?", "ship-it check", "production checklist", "pre-launch checklist", "release readiness", or `/ship-it`. |
|
|
107
|
+
| [`sql-review`](./skills/sql-review/SKILL.md) | Pre-commit SQL code review for uncommitted `.sql` changes (staged + unstaged). Detects 17 antipattern classes that map to **real production incident causes** — `sp_send_dbmail` in CATCH blocks (masks the real exception as a misleading permission denial), broken retry patterns (`@retry` declared without a surrounding `WHILE` loop), swallowing CATCH blocks (no `THROW`/`RAISERROR`/log), **new tables created without a primary key or any index** (the silent perf-then-deadlock killer), parameter-vs-column type mismatches (8152 truncation risk), `EXEC()` string concatenation without `sp_executesql` parameters (SQL injection), `NOLOCK` inside transactional write paths, `UPDATE`/`DELETE` without `WHERE`, cursors without `READ_ONLY FORWARD_ONLY LOCAL`, hardcoded environment values (emails, server names, paths, linked servers), cross-DB references like `msdb.dbo.*`, missing `SET NOCOUNT ON`, missing `GRANT EXECUTE` on `CREATE PROC`, `BEGIN TRANSACTION` outside `TRY`/`CATCH` with `XACT_STATE` handling, and vestigial control-flow comments hinting at refactor leftovers (e.g. `-- end while loop` with no `WHILE`). **Scope-aware** — full-file scan for new files, diff-only scan for modified files so legacy antipatterns in untouched parts of a large SP don't flood the report. Categorizes findings as `BLOCKER` / `WARN` / `INFO` with `file:line` citations and per-finding fix recommendations. **Never edits SQL unprompted** — produces the report, then asks per fix. Distinct from [`code-review`](./skills/code-review/SKILL.md), which carries the general best-practice catalog without SQL-specific patterns. Triggers on `/sql-review`, "review my SQL", "review the SQL diff", "lint the SQL", "check my SQL changes", "SQL pre-commit check", or "audit my stored proc". |
|
|
107
108
|
| [`task-executor`](./skills/task-executor/SKILL.md) | Disciplined execution loop for a single, already-defined task — Understand → Inspect → Plan → Execute incrementally → Validate after every change → Track assumptions → Update progress. Forces a strict per-turn output format with six fixed sections (**Goal** / **Current understanding** / **Files to inspect** / **Plan** / **Progress** / **Risks** / **Assumptions**) so the work stays legible and resumable instead of devolving into ad-hoc edits across turns. When the inspection working set spans multiple layers (controller + service + persistence + tests), Phase 2 convenes an **inspection council**: parallel `Explore` sub-agents — one per layer slice — each map their area and return `file:line`-cited findings on existing patterns, wiring points, and sibling test classes; the main session aggregates the results into `Current understanding` so the working context window stays free for the strict per-turn output the executional phase keeps emitting. Small inspection sets (≤ ~5 files, one layer) skip the council and read inline. Enters Plan Mode after inspection and gates on `ExitPlanMode` approval before writing any code; every plan step is then one logical change followed by an immediate validation (test, build, type-check, curl, page load) before the next checkbox ticks. Assumptions are tracked explicitly until confirmed by code or the user — and promoted into `Current understanding` or killed, never silently carried. Composes downward from [`plan-and-build`](./skills/plan-and-build/SKILL.md) (which interviews the user to design the feature) and routes back to it when the user invokes this skill on a fuzzy spec. Triggers on `/task-executor`, "Work on task: …", or any concrete, already-defined task handed to Claude for execution. |
|
|
108
109
|
| [`tauri-2-app`](./skills/tauri-2-app/SKILL.md) | Scaffold a new Tauri 2 desktop app (Rust backend + TypeScript/React frontend) using a thin-frontend / rich-Rust-backend architecture with modular `commands/`, `state/`, `storage/`, `platform/` traits, `error/` macros, single-instance + updater plugins wired correctly, capability JSON per window, encrypted secrets at rest, `spawn_blocking` for sync work, and typed frontend command hooks — while forbidding common pitfalls (committed `.backup`/`.orig`/`.temp` files, plaintext API keys in `settings.json`, tokens in `localStorage`, `cfg!(target_os)` in command bodies instead of trait-based platform code, hand-rolled date math instead of `chrono`, raw `std::fs` bypassing capability checks, blocking I/O inside async commands, missing `windows_subsystem = "windows"` in `main.rs`, `devtools: true` in release, hardcoded bundle identifiers / updater pubkeys / CDN URLs). Three modes — full project scaffold, add-a-command end-to-end, add-a-Rust-module slice. Resolves Cargo + npm versions at scaffold time (not hard-coded). |
|
|
110
|
+
| [`think-like-fable`](./skills/think-like-fable/SKILL.md) | An operating manual for rigorous reasoning, written as a senior operator handing their craft to a sharp junior — applied to whatever task is at hand rather than replacing it. Eight disciplines, each with the procedure, a worked example, and the failure it prevents: read the need behind the literal ask, decompose into **independently checkable** pieces, spend effort where the risk lives (not where the work is easy or interesting), verify load-bearing claims by **re-deriving** them instead of recognizing them ("a claim about code you haven't opened is a hypothesis"), tag every claim **verified / inferred / assumed** in the text, attack your own conclusion before handing it over, and communicate answer → reasoning → risk in that order. Names the seven mistakes that look like competence and aren't (thoroughness theater, fluent overclaiming, premature agreement, complexity as signal, silent scope repair, momentum completion, deference to your own prior output) and ends with a five-question self-test to run on every answer before sending. Triggers on "think like fable", "/think-like-fable", "be rigorous", "are you sure?", "don't guess", or any high-stakes analysis where a confident wrong answer is worse than a slow right one. |
|
|
109
111
|
| [`write-a-skill`](./skills/write-a-skill/SKILL.md) | Author a new Claude Code skill — interview-driven scaffolding that produces a properly-structured `SKILL.md` (trigger-rich YAML description, "When to use", workflow, examples, anti-patterns), drops it in the right location (library `skills/`, project `./.claude/skills/`, or global `~/.claude/skills/`), updates the README skills table when extending this library, and runs a review checklist focused on the failure mode that matters most — under-triggering descriptions. Triggers on "create/write/add a skill", "/write-a-skill", or a pasted SKILL.md URL with "one like this". |
|
|
110
112
|
|
|
111
113
|
Run `skills list` to see this list with install status, or browse [`skills/`](./skills) directly.
|
package/package.json
CHANGED
|
@@ -32,3 +32,11 @@ Step-by-step guidance for Claude on how to handle the task.
|
|
|
32
32
|
## Notes
|
|
33
33
|
|
|
34
34
|
Any caveats, edge cases, or things to watch out for.
|
|
35
|
+
|
|
36
|
+
<!-- Author reminders (delete before shipping):
|
|
37
|
+
- Description carries 3+ concrete trigger phrases — it's the only field Claude reads to decide.
|
|
38
|
+
- Give every rule that matters a ❌/✅ pair (same output done badly, then well).
|
|
39
|
+
- Any assertion the skill asks for needs an evidence gate — name the check that licenses it.
|
|
40
|
+
- Report-producing skills: state "zero findings is a valid outcome".
|
|
41
|
+
-->
|
|
42
|
+
|
|
@@ -22,6 +22,16 @@ If you find issues, **do not start editing**. Produce the findings report first.
|
|
|
22
22
|
|
|
23
23
|
This rule overrides any general "be helpful, fix it" instinct. A drive-by refactor mid-review collapses the user's mental model of what changed.
|
|
24
24
|
|
|
25
|
+
## Evidence rules
|
|
26
|
+
|
|
27
|
+
A claim about code you haven't opened this session is a hypothesis — verify it or label it as one.
|
|
28
|
+
|
|
29
|
+
- **Read beyond the hunk.** Before flagging anything, `Read` the full enclosing function — and the whole file when it's small. Most false "missing null check" / "unhandled error" findings dissolve when you see the guard 10 lines above the hunk, or the caller that validates. A finding based only on diff-hunk context is not reportable.
|
|
30
|
+
- **Grep before claiming absence.** "Dead code", "unused", "never called", "duplicated elsewhere" each require a repo-wide `Grep` for the identifier first. Cite the search in the finding: *"no callers found (`grep -rn 'buildQuery' src/`)"*.
|
|
31
|
+
- **Quote, don't paraphrase.** Failing test output, error messages, and load-bearing identifiers go into findings verbatim (trimmed). A paraphrased error message loses the exact token that matters.
|
|
32
|
+
- **Zero findings is a valid outcome.** Never invent findings to appear thorough — thoroughness is measured by what you checked, and the report already lists that (build, tests, lenses run). An empty Blockers section with a green build is a good report.
|
|
33
|
+
- **User framing is input, not conclusion.** "The auth part is fine, just check the parser" does not exempt the auth part. Weight attention toward the ask, but never skip a category on the user's say-so.
|
|
34
|
+
|
|
25
35
|
## Workflow
|
|
26
36
|
|
|
27
37
|
1. **Snapshot the diff.** Run in parallel:
|
|
@@ -38,7 +48,7 @@ This rule overrides any general "be helpful, fix it" instinct. A drive-by refact
|
|
|
38
48
|
- `Cargo.toml` → `cargo build`, `cargo test`
|
|
39
49
|
- `Makefile` → check for `test` / `build` targets first
|
|
40
50
|
- Monorepo (`turbo.json`, `nx.json`, `pnpm-workspace.yaml`) → use the orchestrator
|
|
41
|
-
4. **Run tests, then build.** Tests first (faster signal). If tests pass, run the build. Capture output. If a command doesn't exist or fails to start, note it and continue — don't fabricate a green result.
|
|
51
|
+
4. **Run tests, then build.** Tests first (faster signal). If tests pass, run the build. Capture output. If a command doesn't exist or fails to start, note it and continue — don't fabricate a green result. A result you didn't observe is **not run** (report ⚠️ not detected), never "passed".
|
|
42
52
|
5. **Review.** Decide single-pass vs. lens council (see [Lens council](#lens-council-for-non-trivial-diffs)):
|
|
43
53
|
- **Single-pass (inline)** when the diff is small and tightly scoped — roughly: < 100 lines changed, < 5 files, no security-sensitive paths (auth, crypto, input validation, file/SQL/shell sinks). Walk the priority list yourself; faster on trivial changes.
|
|
44
54
|
- **Lens council** otherwise. Spawn parallel `Explore` sub-agents — one per lens — then run an adversarial critique round before reporting.
|
|
@@ -59,13 +69,20 @@ These rules govern the fix-application phase only — they don't change the repo
|
|
|
59
69
|
|
|
60
70
|
## Categories
|
|
61
71
|
|
|
62
|
-
- **`blocking`** — must fix before ship: bug, broken contract, security hole, build/test failure, missing migration, hard-coded secret.
|
|
72
|
+
- **`blocking`** — must fix before ship: bug, broken contract, security hole, build/test failure, missing migration, hard-coded secret. **Burden of proof:** a `blocking` finding must include a one-sentence concrete failure scenario (*this input/state → this wrong outcome*). If you cannot write that sentence, demote to `suggestion`.
|
|
63
73
|
- **`suggestion`** — would improve the code; user can take or leave. DRY consolidations, dead-code removal, missing error handling on non-critical paths.
|
|
64
74
|
- **`nit`** — style/preference; never blocks.
|
|
65
|
-
- **`praise`** — something done well
|
|
75
|
+
- **`praise`** — something done well, cited to a specific `file:line` (*"the retry wrapper at `http.ts:40` is exactly right for this flaky API"*). Generic filler ("nice clean code!") is worse than omitting the section. Include one only when it's genuine.
|
|
66
76
|
|
|
67
77
|
Lead each finding with the *why*. "This swallows the exception so a failure here is silently lost" beats "add error handling".
|
|
68
78
|
|
|
79
|
+
Same finding, written badly and well:
|
|
80
|
+
|
|
81
|
+
- ❌ **B1. Add error handling to `fetchUser`** — `api/user.ts:42`. *(No failure scenario, no consequence, one citation — reads as a reflex; the reviewer can't verify it or weigh it.)*
|
|
82
|
+
- ✅ **B1. Unhandled rejection on deleted user** — `api/user.ts:42`. **Why:** `fetchUser` rejects on 404, but `ProfilePage` (`pages/profile.tsx:18`) never catches — visiting a deleted user's profile renders a blank page with an unhandled rejection. **Fix:** catch in `ProfilePage` and render the not-found state.
|
|
83
|
+
|
|
84
|
+
The ✅ names the trigger, the concrete consequence, and both `file:line` sites — verifiable without re-deriving it.
|
|
85
|
+
|
|
69
86
|
## What to look for
|
|
70
87
|
|
|
71
88
|
Priority order — review top-to-bottom, stop wasting tokens on lower categories once a higher one is on fire.
|
|
@@ -162,7 +179,7 @@ Performance (§5), readability (§7), and style (§8) usually roll into Design
|
|
|
162
179
|
1. **Spawn in parallel.** Send a **single message** with N `Agent` calls (`subagent_type=Explore`). Each lens gets:
|
|
163
180
|
- The full diff (or the slice relevant to its files when the diff is huge).
|
|
164
181
|
- **One** lens with its checklist verbatim from [What to look for](#what-to-look-for).
|
|
165
|
-
- Instructions: "Find issues **only in your lens.** Categorize each as `blocking` / `suggestion` / `nit
|
|
182
|
+
- Instructions: "Find issues **only in your lens.** Read the full enclosing function before flagging — hunk-only findings are not reportable. Categorize each as `blocking` / `suggestion` / `nit`; a `blocking` must state a one-sentence concrete failure scenario. Cite `file:line` for every finding. Lead each finding with the *why*. If your lens has no findings, say 'no findings' explicitly — do not pad. Report in ≤500 words."
|
|
166
183
|
2. **Collect findings.** Each agent returns its list. Don't publish yet.
|
|
167
184
|
3. **Critique round.** Read all lenses side by side, then do an adversarial pass before the report:
|
|
168
185
|
- **Challenge every `blocking`** — "is this actually exploitable / actually a bug / would this actually break in production?" Demote to `suggestion` or drop if the answer is no when you read the surrounding code.
|
|
@@ -257,6 +274,10 @@ End with the offer. Wait for the user's choice. Apply only the approved set, the
|
|
|
257
274
|
- ❌ DRY-ing prematurely — calling out three similar lines as duplication when the right call is to leave them. Note the pattern; flag only when the abstraction is clearly warranted.
|
|
258
275
|
- ❌ Padding the report with style nits when there are correctness blockers.
|
|
259
276
|
- ❌ Hand-wavy findings without `file:line`.
|
|
277
|
+
- ❌ Flagging from the diff hunk alone. Read the enclosing function first — the guard is often 10 lines above the hunk.
|
|
278
|
+
- ❌ Claiming "unused" / "dead" / "duplicated elsewhere" without a repo-wide grep for the identifier.
|
|
279
|
+
- ❌ A `blocking` with no concrete failure scenario. Can't write "this input → this wrong outcome"? It's a `suggestion`.
|
|
280
|
+
- ❌ Inventing findings on a clean diff to look thorough. Zero findings + green build is a valid, complete report.
|
|
260
281
|
- ❌ Convening the lens council on a 15-line diff. Single-pass it.
|
|
261
282
|
- ❌ Spawning the lens agents serially instead of in parallel — one message, N agents.
|
|
262
283
|
- ❌ Skipping the critique round and publishing the raw union of lens findings. False-positive blockers erode trust fast.
|
|
@@ -41,21 +41,25 @@ If an `ONBOARDING.md` already exists, this is **refresh mode**: read it first, t
|
|
|
41
41
|
Spawn `subagent_type=Explore` calls in a **single message** so they run concurrently. Brief each agent self-containedly — it has no conversation context. Default fan-out:
|
|
42
42
|
|
|
43
43
|
- **System overview** — what this project actually does, key domains, top-level modules, public-facing surfaces (HTTP routes / CLI commands / exported APIs).
|
|
44
|
-
- **Dependency map** — top-level prod deps only (skip dev/test/types). For each: what it does *in this codebase* (not generic), and the load-bearing call site (`file:line`). If a dep is genuinely non-obvious (niche library, internal fork, name that doesn't reveal its purpose), the agent MAY check `context7` (or any docs-MCP server available in the environment) for a one-line "what is this library" — `context7__resolve-library-id` → `context7__query-docs`. Skip the lookup for well-known libraries (React, Express, Prisma, etc.) — the *generic* description is what we're trying to avoid; what matters is how it's used *here*.
|
|
44
|
+
- **Dependency map** — top-level prod deps only (skip dev/test/types). For each: what it does *in this codebase* (not generic), and the load-bearing call site (`file:line`). If a dep is genuinely non-obvious (niche library, internal fork, name that doesn't reveal its purpose), the agent MAY check `context7` (or any docs-MCP server available in the environment) for a one-line "what is this library" — `context7__resolve-library-id` → `context7__query-docs`. Skip the lookup for well-known libraries (React, Express, Prisma, etc.) — the *generic* description is what we're trying to avoid; what matters is how it's used *here*. The "how it's used here" line requires a call site the agent actually opened. If no call site is found, the row reads **"declared but no usage found"** — that's a finding (candidate for removal), not a gap to paper over with a guess from the package name.
|
|
45
45
|
- **Startup flow** — entry point → bootstrap → config loading → server start. A numbered sequence with `file:line` per step.
|
|
46
|
-
- **Auth flow** — login/session/token handling, middleware/guards, user model, where authorization decisions are made. If none, the agent must say "no auth detected" explicitly so Step 3 doesn't fabricate one.
|
|
47
|
-
- **Important files** — the 5–15 files a new contributor *must* know about, each with a one-line "why it matters."
|
|
46
|
+
- **Auth flow** — login/session/token handling, middleware/guards, user model, where authorization decisions are made. This section must be a **traced code path** — a middleware/guard/session check the agent read this session, cited `file:line` — never an inference from an auth library appearing in the manifest. If none, the agent must say "no auth detected" explicitly AND state what was searched (e.g. "grepped for middleware, `session`, `jwt`, `[Authorize]`, guards — no hits") so Step 3 doesn't fabricate one.
|
|
47
|
+
- **Important files** — the 5–15 files a new contributor *must* know about, each with a one-line "why it matters." A file earns its slot by being load-bearing, and the agent names the evidence per file: imported widely (roughly how many importers), owns a core domain concept, or is an entry point. "Looks important" is not evidence.
|
|
48
48
|
|
|
49
49
|
Each agent reports back in ≤300 words with `file:line` citations. Don't ask Explore to read entire files — ask for the specific answer plus citations.
|
|
50
50
|
|
|
51
51
|
### 3. Synthesize ONBOARDING.md
|
|
52
52
|
|
|
53
|
-
Write the artifact to `docs/ONBOARDING.md` if a `docs/` directory exists, otherwise `ONBOARDING.md` at repo root.
|
|
53
|
+
Write the artifact to `docs/ONBOARDING.md` if a `docs/` directory exists, otherwise `ONBOARDING.md` at repo root.
|
|
54
|
+
|
|
55
|
+
**No-fabrication gate:** every claim in the file traces to a probe run this session — a file an agent read, a grep it ran. If a claim can't name its probe, it's a hypothesis: verify it or omit it. Never fill a section by inference from framework conventions ("Next.js apps usually…").
|
|
56
|
+
|
|
57
|
+
Sections, in this order:
|
|
54
58
|
|
|
55
59
|
1. **Read this first** — 3–7 bullets max. The minimum a fresh contributor needs to not be dangerous.
|
|
56
60
|
2. **System overview** — 1–3 paragraphs. What it does, who it serves, the dominant architectural shape.
|
|
57
61
|
3. **Startup flow** — numbered, with `file:line` per step.
|
|
58
|
-
4. **Auth flow** — same shape, or a one-liner "No authentication layer — this is X" if the agent confirmed none.
|
|
62
|
+
4. **Auth flow** — same shape, or a one-liner "No authentication layer — this is X (searched: middleware, session/token handling, guards)" if the agent confirmed none.
|
|
59
63
|
5. **Dependency map** — table: `Dependency | What it does here | Key call site`.
|
|
60
64
|
6. **Important files** — bulleted list with `file:line` and a one-line "why it matters."
|
|
61
65
|
7. **Project glossary** *(optional)* — only if `CONTEXT.md` exists or domain terms surfaced repeatedly during exploration.
|
|
@@ -97,7 +101,10 @@ If making this teammate-accessible would help, mention `ShareOnboardingGuide`
|
|
|
97
101
|
- ❌ Generic framework descriptions ("This is a Next.js app."). Call out what makes THIS codebase non-obvious — the custom session helper, the funky background job runner, the legacy module that traps newcomers.
|
|
98
102
|
- ❌ Listing every dependency including dev/test/types. Prod + top-level only.
|
|
99
103
|
- ❌ "Important files" with 40 entries. 5–15 is the budget. If you can't pick, you don't understand the codebase yet — Explore more.
|
|
100
|
-
- ❌ Inventing an auth flow when there isn't one. If the agent reports no auth, the section says "No authentication layer
|
|
104
|
+
- ❌ Inventing an auth flow when there isn't one. If the agent reports no auth, the section says "No authentication layer" plus what was searched. That's load-bearing information for a future reader.
|
|
105
|
+
- ❌ Auth described from the manifest instead of the code. ❌ "Uses NextAuth for authentication" because `next-auth` sits in `package.json` vs. ✅ "Requests hit `middleware.ts:8` → `auth()` from `lib/auth.ts:12`; unauthenticated users redirect at `middleware.ts:19`." Trace the path or write "none detected (searched: …)".
|
|
106
|
+
- ❌ Papering over a dependency with no found call site. "Declared but no usage found" goes in the table verbatim — it's a finding.
|
|
107
|
+
- ❌ Important files picked by vibes. Each entry names its evidence: import count, domain concept owned, or entry-point role.
|
|
101
108
|
- ❌ Reading whole source files into the main context. Sub-agents return summaries with `file:line` citations — trust them.
|
|
102
109
|
- ❌ Claims without `file:line` citations. A claim the next reader can't verify rots fast.
|
|
103
110
|
- ❌ Hard-coded dates ("as of November 2025") in the file body. Git history is the timestamp.
|
|
@@ -46,7 +46,7 @@ Before composing the message, gather two pieces of context from the repo.
|
|
|
46
46
|
1. Run `git rev-parse --abbrev-ref HEAD` to get the current branch name.
|
|
47
47
|
2. Take the last `/`-separated segment of the branch (so `feature/12345-fix_this_bug` becomes `12345-fix_this_bug`).
|
|
48
48
|
3. If that segment starts with one or more digits followed by `-`, `_`, or end-of-string, those leading digits are the ticket number.
|
|
49
|
-
4. If no leading numeric ID is found, **omit `#<ticket>` from the message entirely** — do not invent one and do not prompt the user for it.
|
|
49
|
+
4. If no leading numeric ID is found, **omit `#<ticket>` from the message entirely** — do not invent one, do not guess one from conversation context, do not reuse a stale number mentioned earlier in the session, and do not prompt the user for it. The branch name is the only source of truth for the ticket.
|
|
50
50
|
|
|
51
51
|
Examples:
|
|
52
52
|
|
|
@@ -81,6 +81,11 @@ How to decide:
|
|
|
81
81
|
3. Breaking changes get a `!` after the type / scope (e.g., `#12345 (API) feat!: drop support for Node 16`) and a `BREAKING CHANGE:` footer.
|
|
82
82
|
4. Inner `type(scope)` is optional and usually redundant once `(PROJECT)` is present. Only use it when it adds real specificity beyond the project tag (e.g., `#12345 (API) fix(auth): ...` when "auth" narrows further than "API").
|
|
83
83
|
5. Body explains the *why*, not the *what*. Wrap at 72 chars.
|
|
84
|
+
6. The description states **what changed** at the level a reader scanning a changelog needs; the *why* goes in the body. A description that only restates the type ("fix bug") carries no information — rewrite it.
|
|
85
|
+
- ❌ `fix: fix bug in login`
|
|
86
|
+
- ✅ `fix: reject expired refresh tokens instead of issuing new access tokens`
|
|
87
|
+
7. The type must match the **diff**, not the user's phrasing. The user saying "quick fix" while the staged diff adds a new endpoint means `feat`, not `fix`. Determine the type from `git diff --staged` output you actually read this session — never from the conversation summary or the user's wording alone.
|
|
88
|
+
8. If the staged diff contains two unrelated changes (e.g., an auth bug fix plus a new export page), say so and suggest splitting into two commits — do not paper over it with a vague umbrella description like `chore: various updates`.
|
|
84
89
|
|
|
85
90
|
## Workflow
|
|
86
91
|
|
|
@@ -89,7 +94,7 @@ When the user asks for a commit message:
|
|
|
89
94
|
1. Get the current branch with `git rev-parse --abbrev-ref HEAD` and extract the ticket number per the rules above.
|
|
90
95
|
2. Inspect the staged diff: `git diff --cached` (or `git diff` if nothing is staged).
|
|
91
96
|
3. From the changed file paths, determine the project tag — or decide to omit it.
|
|
92
|
-
4. Categorize the change into one of the types.
|
|
97
|
+
4. Categorize the change into one of the types — based on the diff you just read, not on how the user described the work.
|
|
93
98
|
5. Write a concise description.
|
|
94
99
|
6. If the change is non-trivial, add a body explaining the rationale.
|
|
95
100
|
7. Flag breaking changes explicitly.
|
|
@@ -131,6 +136,8 @@ BREAKING CHANGE: clients reading `user.email` must update to `user.email_address
|
|
|
131
136
|
- ❌ `Fix: Bug in login page.` (capitalized, trailing period)
|
|
132
137
|
- ❌ `feat: added the ability to export CSV files` (past tense)
|
|
133
138
|
- ❌ `#12345 (CLIENT) feat: added export.` (past tense + trailing period)
|
|
134
|
-
- ❌ Inventing a ticket number when the branch doesn't have one
|
|
139
|
+
- ❌ Inventing a ticket number when the branch doesn't have one — or guessing one from conversation context
|
|
140
|
+
- ❌ `fix: quick fix per request` when the staged diff adds a new endpoint (type from the user's phrasing, not the diff — should be `feat`)
|
|
141
|
+
- ❌ `chore: various updates` covering two unrelated changes — flag the split instead
|
|
135
142
|
- ❌ Forcing a `(PROJECT)` tag when the diff doesn't actually map to API / CLIENT / CONSOLE / DB
|
|
136
143
|
- ✅ `#12345 (CLIENT) feat: add CSV export`
|
package/skills/diagnose/SKILL.md
CHANGED
|
@@ -70,6 +70,11 @@ Confirm:
|
|
|
70
70
|
- [ ] The failure is reproducible across multiple runs (or, for non-deterministic bugs, reproducible at a high enough rate to debug against).
|
|
71
71
|
- [ ] You have captured the exact symptom (error message, wrong output, slow timing) so later phases can verify the fix actually addresses it.
|
|
72
72
|
|
|
73
|
+
**Quote error text verbatim — never paraphrase.** The load-bearing token is usually the exact column name, status code, or line number, and paraphrase loses it. The difference between what the error says and what you remember it saying is where diagnosis dies.
|
|
74
|
+
|
|
75
|
+
- ❌ "some kind of null error in the billing code"
|
|
76
|
+
- ✅ `NullReferenceException at BillingService.cs:84 in HandleSubscriptionEvent` — the `:84` is what distinguishes hypothesis 2 from hypothesis 4.
|
|
77
|
+
|
|
73
78
|
Do not proceed until you reproduce the bug.
|
|
74
79
|
|
|
75
80
|
## Phase 3 — Hypothesise
|
|
@@ -82,6 +87,22 @@ Each hypothesis must be **falsifiable**: state the prediction it makes.
|
|
|
82
87
|
|
|
83
88
|
If you cannot state the prediction, the hypothesis is a vibe — discard or sharpen it.
|
|
84
89
|
|
|
90
|
+
**Evidence gate.** A claim about code you haven't opened this session is a hypothesis, not evidence. Cite `file:line` only for lines you actually read; "X is never called" only after you grepped for callers. Label everything else as unverified.
|
|
91
|
+
|
|
92
|
+
### Mundane first
|
|
93
|
+
|
|
94
|
+
Exotic hypotheses (framework bug, compiler bug, race condition) are almost always wrong. Before ranking any of them above a boring cause, eliminate the boring ones — each is a 30-second check:
|
|
95
|
+
|
|
96
|
+
- **Is the code you're reading the code that's running?** Stale build artifact, uncompiled change, cached bundle, old container image. Add a marker log and confirm it appears in the output.
|
|
97
|
+
- **Right branch, right env, right database?** Check `git branch`, the connection string, the env vars actually loaded.
|
|
98
|
+
- **Did the input actually reach the function?** Log at the entry point before theorising about the logic inside.
|
|
99
|
+
- **Typo / off-by-one / wrong variable** in the most recently changed lines (`git diff`).
|
|
100
|
+
- **Config not loaded** — the setting exists but the process never read it.
|
|
101
|
+
|
|
102
|
+
When the behavior makes no sense, you are looking at the wrong code, the wrong process, or the wrong environment — not at an exotic bug.
|
|
103
|
+
|
|
104
|
+
**The user's diagnosis is hypothesis #1, not the conclusion.** If the user says "it's probably the cache layer" or "should be a quick fix", rank it, state its falsifiable prediction, and test it like the others. Never skip falsification because the user sounded sure — confident framing is not evidence.
|
|
105
|
+
|
|
85
106
|
### Decision gate: inline vs. hypothesis council
|
|
86
107
|
|
|
87
108
|
- **Inline (skip the council)** when the cause is obvious from one read: a typo in the diff that introduced the bug, a one-file change with a clear root cause, a trivial null/undefined at an obvious site. Form 1–2 hypotheses directly.
|
|
@@ -123,8 +144,14 @@ Tool preference:
|
|
|
123
144
|
|
|
124
145
|
**Perf branch.** For performance regressions, logs are usually wrong. Instead: establish a baseline measurement (timing harness, `performance.now()`, profiler, query plan), then bisect. Measure first, fix second.
|
|
125
146
|
|
|
147
|
+
**When a probe command fails:** read the full error output — don't skim it. Change exactly one thing based on what it says, retry once. Two failures on the same probe = stop and report; never retry verbatim, never proceed as if it ran, never report an observation you didn't see.
|
|
148
|
+
|
|
149
|
+
**Stop-digging rule.** After ~3 probe cycles that neither confirm nor falsify the leading hypothesis, stop probing it. Go back to Phase 3 with the evidence gathered so far and re-rank — probes that keep coming back ambiguous usually mean the hypothesis is wrong, not that it needs one more probe. Tunneling on hypothesis #1 is the failure mode this rule breaks.
|
|
150
|
+
|
|
126
151
|
## Phase 5 — Fix + regression test
|
|
127
152
|
|
|
153
|
+
**The accepted hypothesis must explain EVERY observed symptom.** A hypothesis that explains 2 of 3 symptoms is a different bug or an incomplete cause. Before writing the fix, walk the symptom list from Phase 2 and check each one off against the hypothesis — an unexplained symptom means back to Phase 3, not "probably unrelated".
|
|
154
|
+
|
|
128
155
|
**Minimal comments.** Default to no comments in the fix or the regression test. Add one only when the *why* is non-obvious — a workaround for a specific upstream bug (with a link), a subtle invariant the code relies on, a domain rule that isn't visible from the names. Never write block headers, never restate *what* the next line does, never leave `// TODO` without an issue link. One short line max — no multi-line comment blocks. Names carry the *what*; comments earn their place only when they carry *why*.
|
|
129
156
|
|
|
130
157
|
Write the regression test **before the fix** — but only if there is a **correct seam** for it.
|
|
@@ -157,6 +184,10 @@ Required before declaring done:
|
|
|
157
184
|
|
|
158
185
|
- Jumping to a fix before building a feedback loop — you're guessing, not diagnosing.
|
|
159
186
|
- A single hypothesis becomes "the cause" without falsification — anchoring.
|
|
187
|
+
- Adopting the user's "it's probably X" as fact. It's hypothesis #1 — rank it and falsify it like the rest.
|
|
188
|
+
- Ranking a race condition or framework bug above "stale build" before checking the boring causes.
|
|
189
|
+
- Citing `file:line` for code never opened this session, or asserting "never called" without grepping.
|
|
190
|
+
- Accepting a hypothesis that explains most symptoms. Most is not all; the remainder is a different bug or the real cause.
|
|
160
191
|
- Running the hypothesis council for a one-line typo bug. Ceremony for its own sake. Inline 1–2 hypotheses is fine when the cause is staring at you.
|
|
161
192
|
- Spawning defender sub-agents serially instead of in parallel — one message, N agents.
|
|
162
193
|
- A defender that returns "could not find supporting evidence" gets ranked anyway. If the code doesn't back the hypothesis, drop it.
|
|
@@ -42,6 +42,17 @@ The user explicitly does **not** want a hard-coded `<TargetFramework>` baked int
|
|
|
42
42
|
3. If unsure which is the current LTS, fetch the latest .NET support policy via context7 (`mcp__plugin_context7_context7__resolve-library-id` → `query-docs` for ".NET release schedule" / "dotnet support policy") or WebFetch `https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-core`. Quote the version you picked back to the user before generating.
|
|
43
43
|
4. Pin EF Core, ASP.NET Core, and `Microsoft.Extensions.*` package versions to the **latest stable for that TFM** — look them up via context7 (`Microsoft.EntityFrameworkCore`, `Microsoft.AspNetCore.Authentication.JwtBearer`, etc.) rather than guessing. Never hand-paste a version you don't have a source for.
|
|
44
44
|
5. State the chosen TFM and package versions in your reply before writing files, so the user can object before scaffolding.
|
|
45
|
+
6. Concrete resolution commands when context7 is unavailable: `dotnet package search <PackageId> --take 1` or WebFetch `https://api.nuget.org/v3-flatcontainer/<package-id-lowercase>/index.json` (last non-preview entry = latest stable). Never write a version string you did not just resolve this session — no versions from memory, no wildcards, no invented numbers.
|
|
46
|
+
|
|
47
|
+
**API-drift guard.** The version you resolved in this step decides the API shape — training-data memory is the least trustworthy source in this workflow. Highest-risk hallucination zones:
|
|
48
|
+
|
|
49
|
+
- EF Core APIs across majors (e.g. `HasCheckConstraint` moved into `ToTable(t => t.HasCheckConstraint(...))` in EF7; query/interceptor APIs get renamed between majors).
|
|
50
|
+
- Hosted-service and `Host` builder idioms — `Host.CreateApplicationBuilder` (post-.NET 7) vs the older `CreateDefaultBuilder` callback style; don't mix the two.
|
|
51
|
+
- TFM defaults: newer TFMs flip `<Nullable>` / `<ImplicitUsings>` behavior — templates must match the resolved TFM, not a remembered one.
|
|
52
|
+
- OpenAPI/Swagger: .NET 9+ templates dropped Swashbuckle for built-in `Microsoft.AspNetCore.OpenApi` (`AddOpenApi()` / `MapOpenApi()`). Pick the approach matching the resolved TFM; never wire both.
|
|
53
|
+
- Test stack majors: xunit v3 ships as the `xunit.v3` package with different runner wiring than `xunit` 2.x; AutoMapper 13+ self-registers (no `.Extensions.Microsoft.DependencyInjection` package). Match templates to what you resolved, not to package names from memory.
|
|
54
|
+
|
|
55
|
+
If you are not certain a symbol exists in the resolved version, verify it (context7 docs lookup, or read the restored package surface under `~/.nuget/packages/`) **before** writing code that depends on it.
|
|
45
56
|
|
|
46
57
|
### Step 2 — Gather inputs (ask once, in one batch)
|
|
47
58
|
|
|
@@ -66,11 +77,16 @@ Use the **templates in `references/templates/`** as the source of truth for file
|
|
|
66
77
|
- Create directories before files. On Windows shell use PowerShell `New-Item -ItemType Directory -Force`.
|
|
67
78
|
- After scaffolding, run `dotnet sln add` for every project and `dotnet build` to verify the solution compiles. Report build output to the user.
|
|
68
79
|
- Do **not** run `dotnet new` to create the projects — write the `.csproj` and `.cs` files directly from templates so the layout matches exactly.
|
|
80
|
+
- If a `dotnet new` template IS run anyway (user's insistence): **the SDK wins on formats it owns** (`.sln` contents, `obj/`/`bin/` artifacts), **this skill wins on everything else** — overwrite template boilerplate with the skill's templates, keep this skill's project split and folder names. Reconcile deliberately and list every deviation in your report; never silently abandon the skill's patterns, never fight the SDK on formats it owns.
|
|
69
81
|
|
|
70
82
|
### Step 4 — Verify and report
|
|
71
83
|
|
|
72
|
-
- Run `dotnet build` from the solution root. If it fails, fix and rebuild — never leave a broken scaffold.
|
|
84
|
+
- Run `dotnet build` from the solution root. If it fails, fix the **first** error (later errors are usually cascade) and rebuild — never leave a broken scaffold.
|
|
73
85
|
- Run `dotnet test` if any test project exists.
|
|
86
|
+
- Do **not** run `dotnet ef migrations add` or `dotnet ef database update` yourself unless the user confirmed a reachable database — report the migration command as a next step instead. The delivery bar is the build gate, not the migration.
|
|
87
|
+
- Known failure signature: `NETSDK1045` ("The current .NET SDK does not support targeting …") means the TFM you picked outruns the installed SDK — re-run `dotnet --list-sdks` and re-pin to the highest installed LTS; do not install a new SDK unprompted.
|
|
88
|
+
- **A scaffold that hasn't compiled is not delivered.** Paste the actual proof lines in your report (`Build succeeded.` / `0 Error(s)`, and the `Passed! - Failed: 0` test summary). Never report success from memory of the steps you intended, and never report partial success as success — if something is red, say exactly what is red.
|
|
89
|
+
- **CLI failure protocol** (applies to `dotnet new`, `dotnet sln add`, `dotnet build`, `dotnet test`): read the full error output, change exactly one thing, retry once. If the same step fails twice, stop scaffolding and surface the verbatim error to the user — do not keep generating files on top of a broken base, and do not re-run the identical command hoping for a different result.
|
|
74
90
|
- Reply with a short summary: solution path, projects created, TFM chosen, package versions, next steps (e.g. "run `dotnet ef migrations add Initial -p src/{{Solution}}.Infrastructure -s src/{{Solution}}.Api`").
|
|
75
91
|
|
|
76
92
|
## Solution layout (canonical)
|
|
@@ -143,6 +159,9 @@ Every one of these is forbidden in generated code. See [`references/anti-pattern
|
|
|
143
159
|
3. `src/{{Solution}}.Application/` (csproj + assembly marker + `Common/` with `IUserContext`, `Result<T>` if requested, `IUnitOfWork` port, `IRepository<T>` port).
|
|
144
160
|
4. `src/{{Solution}}.Infrastructure/` (csproj + `Persistence/AppDbContext.cs` + `Persistence/EntityConfigurations/` folder + `Persistence/UnitOfWork.cs` + `Auth/UserContext.cs` + `DependencyInjection.cs` with `AddInfrastructure`).
|
|
145
161
|
5. `src/{{Solution}}.Api/` (csproj + `Program.cs` + `Extensions/` folder + `Middlewares/ExceptionHandlerMiddleware.cs` + `Controllers/BaseController.cs` + `appsettings.json`/`appsettings.Development.json`).
|
|
162
|
+
|
|
163
|
+
**Checkpoint:** `dotnet sln add` items 1–5 and `dotnet build` now, before generating workers and tests — a failure here localizes to the core projects; a failure after the full tree does not. Apply the Step-4 failure protocol at this checkpoint too.
|
|
164
|
+
|
|
146
165
|
6. `src/{{Solution}}.Workers.<Name>/` per worker requested.
|
|
147
166
|
7. `tests/{{Solution}}.UnitTests/` (csproj + xUnit + NSubstitute + AutoFixture).
|
|
148
167
|
8. `tests/{{Solution}}.IntegrationTests/` (csproj + `Microsoft.AspNetCore.Mvc.Testing` + `Testcontainers.MsSql`) — only if user asked for it.
|
|
@@ -173,7 +192,7 @@ For entity `{{Feature}}` (e.g. `Customer`):
|
|
|
173
192
|
|
|
174
193
|
Template for the full slice is in [`references/templates/feature-slice.md`](references/templates/feature-slice.md).
|
|
175
194
|
|
|
176
|
-
After generating: `dotnet build` then `dotnet test`. Both must pass.
|
|
195
|
+
After generating: `dotnet build` then `dotnet test`. Both must pass — apply the Step-4 proof-and-failure protocol (paste the green lines; the same step failing twice = stop and surface the verbatim error).
|
|
177
196
|
|
|
178
197
|
### Mode 3 — `add-worker`
|
|
179
198
|
|
|
@@ -223,11 +242,29 @@ Look these up via context7 — do not hand-paste versions:
|
|
|
223
242
|
- `Testcontainers.MsSql` (integration tests only)
|
|
224
243
|
- `Microsoft.AspNetCore.Mvc.Testing` (integration tests only)
|
|
225
244
|
|
|
245
|
+
## Final self-audit (mechanical — grep, don't recall)
|
|
246
|
+
|
|
247
|
+
The **Eliminate** list is easy to hold at file 1 and forgotten by file 30. After generating and before the final build, grep the generated tree — every command must return nothing:
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
grep -rn "Thread.Sleep\|while (true)" src/ # polling-loop workers
|
|
251
|
+
grep -rnE "catch\s*(\(\s*Exception[^)]*\))?\s*\{\s*\}" src/ # swallowed exceptions
|
|
252
|
+
grep -rn "ExpandoObject\|DataRow\|SqlDataAdapter" src/ # sproc-era / reflection data access
|
|
253
|
+
grep -rn "GetService<" src/*/Program.cs # hosted services booted by hand
|
|
254
|
+
grep -rn "Newtonsoft" src/ # unless a dependency demanded it
|
|
255
|
+
grep -rln "public async Task" src/ | xargs grep -Ln "CancellationToken" # async surface with no ct anywhere
|
|
256
|
+
grep -rn "System.Data.Entity\|\"EntityFramework\"" src/ # EF6 leaking into an EF Core solution
|
|
257
|
+
grep -rn "CreateDefaultBuilder" src/ # mixed host-builder idioms
|
|
258
|
+
grep -rn "/// <summary>" src/ # XML doc blocks on internal members
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
A hit means fix it and re-run the grep — never rationalize it away or report it as acceptable.
|
|
262
|
+
|
|
226
263
|
## Verification checklist before reporting "done"
|
|
227
264
|
|
|
228
265
|
- [ ] `dotnet build` exits 0.
|
|
229
266
|
- [ ] `dotnet test` exits 0 (if tests were generated).
|
|
230
|
-
- [ ] No `.csproj` references violate the ONION rule
|
|
267
|
+
- [ ] No `.csproj` references violate the ONION rule. Concrete check: `grep "ProjectReference" src/*/*.csproj` — Domain shows zero hits, Application references only Domain, Api/Workers never reference each other.
|
|
231
268
|
- [ ] No file contains any pattern from the **Eliminate** list.
|
|
232
269
|
- [ ] `Program.cs` is under ~50 lines (everything else is in extension methods).
|
|
233
270
|
- [ ] Domain project's `.csproj` has zero `<ProjectReference>` entries.
|
|
@@ -29,10 +29,12 @@ If the user wants to build *after* grilling, hand off to `plan-and-build` and le
|
|
|
29
29
|
## Core principles
|
|
30
30
|
|
|
31
31
|
- **One question at a time.** Always use `AskUserQuestion` with 2–4 concrete options and a recommended pick first (matches the convention used by [`plan-and-build`](../plan-and-build/SKILL.md)). Never stack three questions in one message — the user can only think clearly about one branch of the design tree at a time.
|
|
32
|
-
- **
|
|
32
|
+
- **Every question must fork the design.** A question earns its slot only if different answers lead to different designs or documents. If every answer leads to the same next step, don't ask it — you're performing rigor, not applying it.
|
|
33
|
+
- **Explore before asking.** If the answer is in the code, read it. Don't ask the user what `OrderService.Cancel` does when you can open the file. Ask only the questions the code can't answer. A claim about code you haven't opened this session is a **hypothesis** — label it one ("I suspect `Cancel` soft-deletes; confirming…") and read the file before building a question or an objection on it.
|
|
33
34
|
- **Terminology rigor.** Surface conflicts between the user's words and the glossary on the spot. Challenge vague or overloaded terms with the canonical alternative. If the user says "account", check whether the glossary distinguishes `Customer` from `User` — and force a choice.
|
|
34
35
|
- **Probe with concrete scenarios.** Invent edge cases that make abstract language fail. "What happens when two users press *Cancel* on the same order within 50ms?"
|
|
35
|
-
- **Contradiction surfacing.** When stated intent contradicts what the code already does, name the discrepancy explicitly and ask which wins. Don't paper over it.
|
|
36
|
+
- **Contradiction surfacing.** When stated intent contradicts what the code already does, name the discrepancy explicitly and ask which wins. Don't paper over it. An objection must cite the specific thing it conflicts with — the `CONTEXT.md` term, the ADR number, or the `file:line` you read this session. If you can't name the conflict, you don't have an objection. Zero real conflicts is a valid, reportable outcome — don't invent friction to look rigorous.
|
|
37
|
+
- **Fold on preference, not on facts.** If the user's answer contradicts a documented decision or code you've cited, present the conflict once more with the citation. If they still overrule you, defer and record their call. Capitulating the moment the user pushes back — while the cited evidence still stands — is as bad as stonewalling.
|
|
36
38
|
- **In-the-moment doc updates.** The moment a fuzzy term resolves, write the glossary entry into `CONTEXT.md`. Don't batch — batched updates get dropped.
|
|
37
39
|
- **No code.** This skill writes only to `CONTEXT.md`, `CONTEXT-MAP.md`, and `docs/adr/*.md`. Never edit source files, never run migrations, never run tests. If the conversation reveals a code-level bug, note it and stop — that's a separate task.
|
|
38
40
|
|
|
@@ -76,6 +78,11 @@ Use `AskUserQuestion`. Lead with the recommendation, append "(Recommended)" to i
|
|
|
76
78
|
|
|
77
79
|
If the user goes off-piste or picks "Other", absorb their answer, restate it in canonical terms, and continue.
|
|
78
80
|
|
|
81
|
+
A forking question vs. a checklist question:
|
|
82
|
+
|
|
83
|
+
- ❌ "Should we handle errors if the payment API fails?" — every answer is "yes"; the design doesn't move. Don't ask it.
|
|
84
|
+
- ✅ "When the payment API fails mid-checkout, does the order persist as `PaymentPending` (new status + retry worker) or roll back entirely (no schema change)?" — answer A adds a status and a background job, answer B adds nothing. The answers diverge, so the question earns its slot.
|
|
85
|
+
|
|
79
86
|
## Phase 3 — Update docs in-flight
|
|
80
87
|
|
|
81
88
|
As decisions crystallise, write them immediately. Two artefacts only.
|
|
@@ -112,6 +119,11 @@ Create an ADR only when **all** of:
|
|
|
112
119
|
|
|
113
120
|
If any one of those is missing, don't write an ADR. A glossary entry or a code comment is enough.
|
|
114
121
|
|
|
122
|
+
Calibration:
|
|
123
|
+
|
|
124
|
+
- ❌ "Add an index on `Orders(CustomerId)`" — reversed in one migration, obvious from the query plan, no seriously-considered alternative. No ADR; it's just code.
|
|
125
|
+
- ✅ "Webhook delivery becomes at-least-once via queue" — consumers must be idempotent forever (hard to reverse), sync was the obvious default (non-obvious), and outbox / sync-with-retries were genuinely weighed (real trade-offs). Write the ADR.
|
|
126
|
+
|
|
115
127
|
#### ADR template
|
|
116
128
|
|
|
117
129
|
Drop into `docs/adr/NNNN-short-title-kebab.md`, numbered sequentially after the highest existing ADR:
|
|
@@ -147,7 +159,7 @@ Keep ADRs immutable once accepted. If the decision changes, write a new ADR that
|
|
|
147
159
|
|
|
148
160
|
Stop grilling when **any** of these are true. Don't pad the conversation.
|
|
149
161
|
|
|
150
|
-
- Further questions stop changing the design — the next question's answer wouldn't move a file or change a name.
|
|
162
|
+
- Further questions stop changing the design — the next question's answer wouldn't move a file or change a name. Operational check: **if the last two answers changed nothing** — no glossary entry, no renamed term, no design fork — the interview is done; summarise and move to crystallisation. Don't stop after two questions because the surface looks calm, and don't grill past the point where answers stop moving files.
|
|
151
163
|
- All terms in the user's spec have a matching `CONTEXT.md` entry (existing or just-added) and no contradictions remain.
|
|
152
164
|
- The user explicitly signals "good enough" — accept it, but quickly note any genuinely open questions you can see.
|
|
153
165
|
- The conversation has revealed that the right next step is **not** to grill further but to prototype, diagnose, or pick a different scope. Say so and stop.
|
|
@@ -163,6 +175,10 @@ When you stop, produce a short closing summary:
|
|
|
163
175
|
|
|
164
176
|
- Asking three questions in one message. One at a time, with options.
|
|
165
177
|
- Asking the user something the codebase already answers. Read first, ask second.
|
|
178
|
+
- Asking questions whose every answer leads to the same next step. If the answer can't fork the design, cut the question.
|
|
179
|
+
- Raising an objection that cites nothing. Name the `CONTEXT.md` term, ADR, or `file:line` it conflicts with — or drop it. "No conflicts found" is a valid result.
|
|
180
|
+
- Folding on first pushback while the cited evidence still stands. Restate the conflict once with the citation, then defer.
|
|
181
|
+
- Asserting what code does without having read it this session. Unread-code claims are hypotheses — say so.
|
|
166
182
|
- Letting a vague term ("account", "user", "delete", "cancel", "process") slide because the user used it confidently.
|
|
167
183
|
- Adding code, tests, or migrations during this skill. Out of scope.
|
|
168
184
|
- Writing an ADR for a decision that's easily reversed, obvious from the code, or had no real alternative.
|
package/skills/handoff/SKILL.md
CHANGED
|
@@ -107,6 +107,11 @@ Read `.claude/handoffs/<this-filename>.md` first.
|
|
|
107
107
|
|
|
108
108
|
The **Next Session Prompt** is the most important section — it's what the user pastes into the new chat to bootstrap continuity. Write it so a fresh Claude with no prior context can act on it immediately.
|
|
109
109
|
|
|
110
|
+
A prompt that survives a fresh session vs. one that doesn't:
|
|
111
|
+
|
|
112
|
+
- ❌ "**Goal:** Continue working on auth. **Then:** finish the remaining fixes." — which file? what's broken? what command shows it? Every answer lives in the dead session.
|
|
113
|
+
- ✅ "**Goal:** Make `linkAccount` merge OAuth identities instead of erroring. **Start by reviewing:** `src/auth/link.ts` (the `linkAccount` stub at line 42), `src/auth/__tests__/link.test.ts`. **Then:** implement the merge branch for the `existing-verified-email` case; run `pnpm vitest run src/auth -t linkAccount` — currently failing with `Error: account already exists`." — names the file, the failing test, the exact command, and the next action.
|
|
114
|
+
|
|
110
115
|
## Workflow
|
|
111
116
|
|
|
112
117
|
1. **Scan the current conversation** for: the stated objective, files you've read or edited, decisions made (and the reasoning), commands run, errors hit, and open threads.
|
|
@@ -115,13 +120,16 @@ The **Next Session Prompt** is the most important section — it's what the user
|
|
|
115
120
|
4. **Pick the filename** — today's date + short slug.
|
|
116
121
|
5. **Create `.claude/handoffs/` if missing**, then write the file with the Write tool.
|
|
117
122
|
6. **Write the memory pointer** to the auto-memory directory and index it in `MEMORY.md`.
|
|
118
|
-
7. **
|
|
123
|
+
7. **Run the zero-context self-test.** Re-read the Next Session Prompt as if you knew nothing about this conversation: does it name the exact files, the exact command to run, the current failing state, and the immediate next action? If answering any of those requires this conversation, the hand-off is not done — fix it before reporting.
|
|
124
|
+
8. **Report back**: tell the user the file path, the slug, and quote the Next Session Prompt so they can copy it without opening the file.
|
|
119
125
|
|
|
120
126
|
## Verifying before you write
|
|
121
127
|
|
|
122
128
|
- If you reference a file path, confirm it exists (or that you created it this session).
|
|
123
129
|
- If you reference a command, make sure it's the one that actually works in this repo (check `package.json`, `Makefile`, etc.).
|
|
124
130
|
- If a decision in the conversation was reversed later, record the final decision — not the abandoned one.
|
|
131
|
+
- **Exact artifacts, never paraphrases.** Commands verbatim and runnable (`pnpm vitest run src/auth -t linkAccount`, not "run the auth tests"). Failing test names copied from actual runner output. Branch name from `git branch --show-current`. Uncommitted-state description from actual `git status` output — never from memory of what you think you edited.
|
|
132
|
+
- If tests were failing when work stopped, re-run them now and quote the exact failure. "Some tests failing" forces the next session to rediscover which — that's the context loss this skill exists to prevent.
|
|
125
133
|
|
|
126
134
|
## Examples
|
|
127
135
|
|
|
@@ -147,6 +155,8 @@ The new session reads the referenced hand-off file first, confirms files still e
|
|
|
147
155
|
- Dumping the entire conversation transcript — hand-off is a synthesis, not a log.
|
|
148
156
|
- Forgetting the memory pointer — without it, the next session won't know the hand-off exists unless the user remembers to paste the prompt.
|
|
149
157
|
- Skipping the **Next Session Prompt** section — that's the single highest-value piece of the doc.
|
|
158
|
+
- Quoting commands, test names, or branch names from memory instead of from actual output. `git status`, `git branch --show-current`, and the test runner are the sources of truth.
|
|
159
|
+
- Shipping a Next Session Prompt that fails the zero-context self-test — if understanding any part of it requires this conversation, it's a summary, not a hand-off.
|
|
150
160
|
|
|
151
161
|
## Notes
|
|
152
162
|
|
|
@@ -59,15 +59,23 @@ Then use the Agent tool with `subagent_type=Explore` to walk the codebase. Don't
|
|
|
59
59
|
|
|
60
60
|
Apply the **deletion test** to anything you suspect is shallow: would deleting it concentrate complexity, or just move it? A "yes, concentrates" is the signal you want.
|
|
61
61
|
|
|
62
|
+
**Evidence gates — both must hold before anything becomes a candidate:**
|
|
63
|
+
|
|
64
|
+
- **Friction must be observed, not theoretical.** Cite the pain: the awkward call sites (`file:line`), the shotgun-surgery pattern ("these 4 files change together — check `git log --oneline -- <dir>`"), the test that needs 40 lines of setup to exercise one branch. "This could be cleaner" with no cited pain is not a candidate.
|
|
65
|
+
- **Read before ruling.** A claim about a module you haven't opened this session is a hypothesis. Before ruling on the deletion test, read the module **and at least 2 of its call sites**. The operational form of the test: if every caller could call the layer below directly with no loss of clarity, the module fails — it's a pass-through. If deleting it would smear real logic (validation, ordering, error translation) across its callers, it passes.
|
|
66
|
+
|
|
62
67
|
### 2. Present candidates
|
|
63
68
|
|
|
64
69
|
Present a numbered list of deepening opportunities. For each candidate:
|
|
65
70
|
|
|
66
71
|
- **Files** — which files/modules are involved
|
|
67
72
|
- **Problem** — why the current architecture is causing friction
|
|
73
|
+
- **Evidence** — the observed friction, cited: the call sites you read (`file:line`), the co-changing files, the awkward tests. No citation, no candidate.
|
|
68
74
|
- **Solution** — plain English description of what would change
|
|
69
75
|
- **Benefits** — explained in terms of locality and leverage, and also in how tests would improve
|
|
70
76
|
|
|
77
|
+
**Zero candidates is a valid outcome.** A healthy codebase produces a short or empty list. Report "no deepening opportunities found — here's what I checked" rather than padding the list with theoretical refactors to appear thorough.
|
|
78
|
+
|
|
71
79
|
**Use `CONTEXT.md` vocabulary for the domain, and [LANGUAGE.md](LANGUAGE.md) vocabulary for the architecture.** If `CONTEXT.md` defines "Order," talk about "the Order intake module" — not "the FooBarHandler," and not "the Order service."
|
|
72
80
|
|
|
73
81
|
**ADR conflicts**: if a candidate contradicts an existing ADR, only surface it when the friction is real enough to warrant revisiting the ADR. Mark it clearly (e.g. _"contradicts ADR-0007 — but worth reopening because…"_). Don't list every theoretical refactor an ADR forbids.
|
|
@@ -94,7 +102,7 @@ Side effects happen inline as decisions crystallize:
|
|
|
94
102
|
|
|
95
103
|
**Claude:**
|
|
96
104
|
1. **Explore.** Reads `CONTEXT.md` (sees `Order`, `OrderLine`, `Cart`) and `docs/adr/0004-validation-pipeline.md`. Spawns Explore on `src/orders/validation/` and finds 11 single-function modules (`validateSku.ts`, `validateQty.ts`, …) each called from one place in `OrderIntake`.
|
|
97
|
-
2. **Candidates.** Presents one numbered candidate: "Collapse the `validate*` cluster into a deep `OrderIntakeValidator` module — current shallow validators have interface nearly as complex as implementation; the real bugs hide in how `OrderIntake` *composes* them, where no test exercises the seam." Files / Problem / Solution / Benefits. Notes: does not contradict ADR-0004 (which is about *when* to validate, not *how* to compose validators).
|
|
105
|
+
2. **Candidates.** Presents one numbered candidate: "Collapse the `validate*` cluster into a deep `OrderIntakeValidator` module — current shallow validators have interface nearly as complex as implementation; the real bugs hide in how `OrderIntake` *composes* them, where no test exercises the seam." Files / Problem / Evidence (the `OrderIntake` call site read, plus the two `validate*` modules opened for the deletion test) / Solution / Benefits. Notes: does not contradict ADR-0004 (which is about *when* to validate, not *how* to compose validators).
|
|
98
106
|
3. **Grilling.** User picks the candidate. Walks the design tree: dependency category (in-process, [DEEPENING.md](DEEPENING.md) §1), seam placement (one external seam at `OrderIntakeValidator`, internal validators stay private), test surface (assert at `validate(order) → Result<Order, ValidationError[]>`, delete the 11 per-function tests). Adds `OrderIntakeValidator` to `CONTEXT.md`.
|
|
99
107
|
|
|
100
108
|
### Example 2: A candidate that contradicts an ADR — but worth reopening
|
|
@@ -106,6 +114,8 @@ Side effects happen inline as decisions crystallize:
|
|
|
106
114
|
## Anti-patterns
|
|
107
115
|
|
|
108
116
|
- ❌ Proposing a refactor without applying the **deletion test** — leads to suggestions that just move complexity instead of concentrating it.
|
|
117
|
+
- ❌ Ruling on the deletion test from a module's name or the file listing. Read the module and ≥2 call sites first; until then it's a hypothesis, not a candidate.
|
|
118
|
+
- ❌ Manufacturing candidates from theoretical concerns: ❌ _"`OrderMapper` could be more flexible"_ (no cited pain) vs. ✅ _"`OrderMapper`'s 3 call sites each re-wrap its output (`intake.ts:41`, `sync.ts:88`, `api.ts:120`) — the seam is in the wrong place."_ The first pads the list; the second names the friction.
|
|
109
119
|
- ❌ Naming things "FooHandler" / "BarService" / "BazManager" when `CONTEXT.md` already names the concept. Use the domain term.
|
|
110
120
|
- ❌ Introducing a port + adapter for a dependency with only one implementation. **One adapter = hypothetical seam.**
|
|
111
121
|
- ❌ Re-litigating an ADR without explicit cause. ADRs are decisions the skill should _not_ reopen unless the constraint that drove them is gone.
|