@dennisrongo/skills 0.6.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 +1 -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 +20 -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
|
@@ -107,6 +107,7 @@ node bin/claude-skills.js list
|
|
|
107
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". |
|
|
108
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. |
|
|
109
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. |
|
|
110
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". |
|
|
111
112
|
|
|
112
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.
|
|
@@ -60,6 +60,17 @@ Versions are resolved at scaffold time, never hard-pasted into the skill. Before
|
|
|
60
60
|
3. Quote the resolved versions back to the user before generating, so they can object.
|
|
61
61
|
4. Prefer the latest **stable** Next.js (App Router GA from 13.4; resolve current).
|
|
62
62
|
5. Default to **pnpm** if `pnpm` is present, otherwise **npm**. Match `packageManager` in `package.json`.
|
|
63
|
+
6. Concrete resolution command when context7 is unavailable: `npm view <pkg> version` (e.g. `npm view next version`; `npm view next-auth dist-tags` — plain `npm view next-auth version` returns the latest *stable*, which may still be v4; never scaffold v4). Never write a version you did not just resolve this session — no versions from memory, no `latest`/`^latest`, no invented numbers.
|
|
64
|
+
7. **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:
|
|
65
|
+
- NextAuth **v4 patterns are POISON here**: `authOptions` export, `getServerSession`, `NEXTAUTH_*` env vars, an options object in the `[...nextauth]` route. v5 is `const { handlers, auth, signIn, signOut } = NextAuth(config)` in `src/auth.ts`, with `AUTH_*` env vars.
|
|
66
|
+
- App Router signatures that changed across majors — e.g. in Next 15 `params`/`searchParams` are **Promises** in dynamic route segments and Route Handler contexts; check the resolved major before writing `params.id`. In `'use client'` pages read route params with `useParams()` from `next/navigation`, not the `params` prop.
|
|
67
|
+
- RTK Query / Redux Toolkit option names (`fetchBaseQuery` options, `providesTags`/`invalidatesTags` shapes) and the Prisma client API for the resolved major.
|
|
68
|
+
- Tailwind majors: v4 dropped the `tailwind.config.ts`-first setup for CSS-first config (`@import "tailwindcss"` + `@tailwindcss/postcss`); v3 uses `tailwind.config.ts` + `postcss.config.js`. Emit exactly one style — the one matching the resolved major — never a mix.
|
|
69
|
+
- Zod majors: v4 moved/renamed APIs (top-level `z.email()`, reworked error customization). A v3-only signature against a resolved v4 is a hallucination — check the installed types under `node_modules/zod`.
|
|
70
|
+
- Prisma majors: the `generator` block shape and default client output location changed across majors. After `prisma generate`, confirm the actual import path from what was generated — don't assume `@prisma/client` from memory.
|
|
71
|
+
- The shadcn CLI is `npx shadcn@latest` (`init` / `add`); the old `shadcn-ui` package name is dead.
|
|
72
|
+
|
|
73
|
+
If you are not certain a symbol exists in the resolved version, verify it (read the installed types under `node_modules/<pkg>/`, or check docs) **before** writing code that depends on it.
|
|
63
74
|
|
|
64
75
|
### Step 2 — Gather inputs (ask once, in one batch)
|
|
65
76
|
|
|
@@ -85,6 +96,7 @@ Use the **templates in [`references/templates/`](references/templates/)** as the
|
|
|
85
96
|
- Create directories before files. On Windows shell use PowerShell `New-Item -ItemType Directory -Force`.
|
|
86
97
|
- Do **not** run `create-next-app` to bootstrap — write files directly from templates so the layout matches [`references/folder-layout.md`](references/folder-layout.md). Use `npm`/`pnpm install` after `package.json` is written.
|
|
87
98
|
- Initialize shadcn/ui by writing `components.json` from [`references/templates/components-json.md`](references/templates/components-json.md) and `src/components/ui/` components incrementally as needed (button, input, form, label, dialog, toast, etc.) — don't blanket-install every Radix primitive.
|
|
99
|
+
- If a generator IS run (`shadcn` CLI, `prisma init`, or `create-next-app` at the user's insistence) and its output differs from this skill's layout: **the framework wins on file locations it mandates** (`middleware.ts` placement, `app/` conventions, `prisma/schema.prisma`), **this skill wins on everything the framework doesn't mandate** (redux layout, route groups, `_components`/`_hooks`). Reconcile deliberately and list every deviation in your report — never force the skill layout over a framework requirement, never silently abandon the skill's patterns.
|
|
88
100
|
|
|
89
101
|
### Step 4 — Database setup
|
|
90
102
|
|
|
@@ -97,6 +109,7 @@ After `package.json` and `prisma/schema.prisma` are written:
|
|
|
97
109
|
- **Never run `prisma db push` against a production-shaped database.** Use migrations.
|
|
98
110
|
- **Never run `prisma migrate reset` without explicit user confirmation** — it drops the DB.
|
|
99
111
|
5. Generate `AUTH_SECRET` for the user: `pnpm exec auth secret` (Auth.js CLI) or `openssl rand -base64 32`. Put it in `.env.local` (NOT `.env.example`).
|
|
112
|
+
6. Order is load-bearing: `prisma generate` MUST run before `pnpm typecheck` / `pnpm build` — the `@prisma/client` types don't exist until generated. If typecheck explodes with missing Prisma types, you skipped or mis-ordered this step; run generate, don't start rewriting imports.
|
|
100
113
|
|
|
101
114
|
### Step 5 — Verify and report
|
|
102
115
|
|
|
@@ -104,6 +117,8 @@ After `package.json` and `prisma/schema.prisma` are written:
|
|
|
104
117
|
- `pnpm lint`. Must exit 0.
|
|
105
118
|
- `pnpm test` (Vitest) if any tests were generated. Must exit 0.
|
|
106
119
|
- `pnpm build`. Must succeed.
|
|
120
|
+
- **A scaffold that hasn't built is not delivered.** Paste the actual proof lines in your report (Next's `✓ Compiled successfully`, Vitest's `Tests N passed`). 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.
|
|
121
|
+
- **CLI failure protocol** (applies to `pnpm install`, `prisma migrate`, `pnpm build`, etc.): 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 a broken base, and do not re-run the identical command hoping for a different result.
|
|
107
122
|
- Reply with a short summary: project path, versions chosen, route groups, env vars to set (especially `AUTH_SECRET` and `DATABASE_URL`), next steps (`pnpm dev`, log in with the seeded test user if Credentials was chosen).
|
|
108
123
|
|
|
109
124
|
## Project layout (canonical)
|
|
@@ -302,7 +317,7 @@ For feature `{{Feature}}` in route group `{{Group}}` (e.g. `(app)`):
|
|
|
302
317
|
- `_components/{{Feature}}Form.tsx` — `'use client'`, uses `useForm` + `zodResolver`, wraps `<UnsavedChangesWarning>`, dispatches create/update mutation on submit.
|
|
303
318
|
7. **Tests**: `tests/unit/{{feature}}.schema.test.ts` (Zod schema valid + invalid). Optional handler test that mocks `db` and `auth`.
|
|
304
319
|
|
|
305
|
-
After generating: `pnpm typecheck && pnpm test && pnpm build`.
|
|
320
|
+
After generating: `pnpm typecheck && pnpm test && pnpm build`. Apply the Step-5 proof-and-failure protocol — paste the green lines; the same step failing twice = stop and surface the verbatim error.
|
|
306
321
|
|
|
307
322
|
### Mode 3 — `add-api-slice`
|
|
308
323
|
|
|
@@ -315,10 +330,27 @@ For domain `{{domain}}` (e.g. `customers`):
|
|
|
315
330
|
5. Add the Prisma model(s) and migrate if needed.
|
|
316
331
|
6. **Do not** create a new `createApi(...)`. One base `api`, many injected slices.
|
|
317
332
|
|
|
318
|
-
After generating: `pnpm typecheck && pnpm build` must pass.
|
|
333
|
+
After generating: `pnpm typecheck && pnpm build` must pass — Step-5 proof-and-failure protocol applies.
|
|
319
334
|
|
|
320
335
|
## Verification checklist before reporting "done"
|
|
321
336
|
|
|
337
|
+
Run this as a **mechanical pass over the generated tree** — grep, don't recall. The forbidden list is easy to hold at file 1 and forgotten by file 30; do not answer any item from memory of what you intended to write. Start with this grep block — every command must return nothing:
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
grep -rn "'use server'" src/ # Server Actions
|
|
341
|
+
grep -rn "export default async function" src/app --include='page.tsx' # async pages
|
|
342
|
+
grep -rn "from '@/lib/db'" src/app --include='*.tsx' # DB access outside route.ts
|
|
343
|
+
grep -rn "fetch(" src/app src/components --include='*.tsx' # inline fetch in components
|
|
344
|
+
grep -rn "serializableCheck: false\|@ts-ignore\|as any" src/redux src/app/api
|
|
345
|
+
grep -rn "moment" src/ package.json # date-fns only
|
|
346
|
+
grep -rn "NEXTAUTH_\|getServerSession\|authOptions\|next-auth/next" src/ .env.example # NextAuth v4 leaking in
|
|
347
|
+
grep -rn "styled-components\|@emotion" src/ package.json # CSS-in-JS in a Tailwind project
|
|
348
|
+
grep -rn "localStorage\|sessionStorage" src/ # any token/session hit is a bug
|
|
349
|
+
grep -rn "dangerouslySetInnerHTML" src/ # zero on a fresh scaffold
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
A hit means fix it and re-run the grep — never rationalize it away. Then the full checklist:
|
|
353
|
+
|
|
322
354
|
- [ ] `pnpm install` succeeds.
|
|
323
355
|
- [ ] `pnpm exec prisma generate` succeeds.
|
|
324
356
|
- [ ] `pnpm exec prisma migrate dev --name init` succeeds (or the user confirmed they ran it manually).
|
|
@@ -330,7 +362,8 @@ After generating: `pnpm typecheck && pnpm build` must pass.
|
|
|
330
362
|
- [ ] Every `route.ts` file in `src/app/api/**` (except `[...nextauth]`) calls `await auth()` or `await requireSession()`.
|
|
331
363
|
- [ ] No `'use server'` directive anywhere. Grep: `grep -rn "'use server'" src/` returns nothing.
|
|
332
364
|
- [ ] No `async function .*Page` in any `page.tsx`. Pages are sync `'use client'`.
|
|
333
|
-
- [ ] No `serializableCheck: false`, `@ts-ignore`, `as any` in `src/redux/**` or `src/app/api
|
|
365
|
+
- [ ] No `serializableCheck: false`, `@ts-ignore`, `as any` in `src/redux/**` or `src/app/api/**` (covered by the grep block above).
|
|
366
|
+
- [ ] Exactly one `createApi(` in the codebase (the base `api`). Grep: `grep -rn "createApi(" src/` shows one hit.
|
|
334
367
|
- [ ] `middleware.ts` exists at project root; its `config.matcher` excludes `/api/auth` (NextAuth handles its own routes).
|
|
335
368
|
- [ ] `src/auth.ts` and `src/auth.config.ts` both exist. `auth.config.ts` has no `@/lib/db` import (Edge-safe).
|
|
336
369
|
- [ ] `.env` is **not** committed; `.env.example` is. `AUTH_SECRET` is **not** in `.env.example` (it's documented as required, with instructions to generate it).
|
|
@@ -32,6 +32,9 @@ If the feature is large, fuzzy, or still in discovery — defer to [`grill-with-
|
|
|
32
32
|
Rules:
|
|
33
33
|
|
|
34
34
|
- **One question at a time.** Wait for the answer before the next one. Use `AskUserQuestion` with 2–4 concrete options and a recommended pick first.
|
|
35
|
+
- **A question earns its slot only if different answers lead to different designs.** Before asking, name (to yourself) what changes per answer. If every answer leads to the same next step, don't ask it — generic checklist questions burn the user's patience without buying design information.
|
|
36
|
+
- ❌ "Should this endpoint be secure and handle errors gracefully?" — every answer is "yes"; nothing about the design forks.
|
|
37
|
+
- ✅ "When an order loses priority, do we keep the history of who set it and when?" — "yes" needs an audit table, "no" is two columns. The answer picks the schema.
|
|
35
38
|
- **Explore the codebase instead of asking** when the answer is already there. If a similar feature, entity, controller, or migration exists, read it before asking the user how a related thing should work.
|
|
36
39
|
- **Sharpen fuzzy language.** When the user says "account", ask: "Customer or User? Those are different things here." When they say "cancel", ask whether that means soft-delete, hard-delete, or a status transition.
|
|
37
40
|
- **Probe with concrete scenarios.** Invent edge cases that force the user to be precise. "What happens if the user submits twice while the first request is still in flight?"
|
|
@@ -114,7 +117,8 @@ Whether you drafted one plan or chose between two, the presented plan must inclu
|
|
|
114
117
|
- Whether a backfill is required and how it's gated.
|
|
115
118
|
- **Always end with:** "Migration file will be generated. No SQL, no `dotnet ef database update`, no `ExecuteSql*` calls will be run — the user runs the migration themselves."
|
|
116
119
|
6. **Pattern reuse table.** Two columns: "New code I'm about to write" and "Existing example it follows" with a path. If a row has no existing example, justify the new pattern.
|
|
117
|
-
7. **
|
|
120
|
+
7. **Validation signal per step.** Every build step names the observable signal that proves it done at plan time — a named test going green, `dotnet build` exiting 0, a `curl` returning the expected body. A step whose completion can't be observed isn't a step, it's a hope — split it or attach a signal before presenting.
|
|
121
|
+
8. **Open questions** still unresolved, if any. If there are any, loop back to Phase 1 — do not exit plan mode with open questions.
|
|
118
122
|
|
|
119
123
|
If Design It Twice ran, end the plan with: **"Considered alternative: `<approach B name>`. Rejected because `<one-line reason>`."** This lets the user redirect to B with a single sentence if they disagree.
|
|
120
124
|
|
|
@@ -126,6 +130,8 @@ Enter Plan Mode (`EnterPlanMode`) to present. Then exit with `ExitPlanMode` and
|
|
|
126
130
|
|
|
127
131
|
Build in the order that gives you the fastest feedback loop.
|
|
128
132
|
|
|
133
|
+
**The plan is a hypothesis about the codebase.** When execution contradicts it — the pattern Phase 2 found doesn't cover this case, the library API has a different shape, the file the plan modifies doesn't exist — stop. Do not improvise silently and keep typing. Re-plan the remaining steps against what you just learned, tell the user what deviated and why, and re-present via plan mode if the change is material (different files, different schema, a new dependency). A small deviation (a helper's actual name, a slightly different signature) just gets a one-line note in the Phase 6 report.
|
|
134
|
+
|
|
129
135
|
**If the feature adds or changes an API endpoint, follow TDD:**
|
|
130
136
|
|
|
131
137
|
1. **Locate the test class.** For each API change, search for an existing test class that already covers that controller / service / use-case. Common patterns:
|
|
@@ -153,6 +159,7 @@ Build in the order that gives you the fastest feedback loop.
|
|
|
153
159
|
- **Minimal comments.** Default to no comments. Only add one when the *why* is non-obvious (a workaround, a non-trivial invariant, 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.
|
|
154
160
|
- **Match formatting.** Use the project's brace style, naming, file headers, `using` placement. Don't reformat unrelated code.
|
|
155
161
|
- **No dead code.** Don't commit commented-out lines or "for future use" stubs.
|
|
162
|
+
- **Build to the plan, nothing more.** Done means the approved plan's acceptance criteria. No unrequested config options, no defensive layers the plan didn't ask for, no speculative extension points. Improvements you notice mid-build are findings for the Phase 6 report, not work to do.
|
|
156
163
|
|
|
157
164
|
### Phase 5 — Migrations (generate only, never execute)
|
|
158
165
|
|
|
@@ -207,7 +214,10 @@ When appending:
|
|
|
207
214
|
## Anti-patterns
|
|
208
215
|
|
|
209
216
|
- ❌ Skipping Phase 1 and going straight to "let me read the code and start building" — the whole point of this skill is the grill.
|
|
217
|
+
- ❌ Asking grill questions whose answers all lead to the same design. Every question must fork the design.
|
|
210
218
|
- ❌ Exiting plan mode while open questions remain. Loop back instead.
|
|
219
|
+
- ❌ Improvising silently when the codebase contradicts the plan. Stop, re-plan the remainder, tell the user what deviated.
|
|
220
|
+
- ❌ Gold-plating the build: config options, abstraction layers, or "robustness" the plan never called for.
|
|
211
221
|
- ❌ Writing production code before the test it makes pass (when the feature touches an API).
|
|
212
222
|
- ❌ Creating `FooServiceTests2.cs` because `FooServiceTests.cs` already exists. Always append.
|
|
213
223
|
- ❌ Inventing a new pattern for something the codebase already has a pattern for. If you can't find the precedent, ask before forking.
|
|
@@ -54,6 +54,26 @@ Categorize each comment so the author knows what's required vs optional:
|
|
|
54
54
|
|
|
55
55
|
Lead with the *why*, not just the *what*. "This will deadlock if two callers hit it simultaneously" is more useful than "use a lock here".
|
|
56
56
|
|
|
57
|
+
Same finding, badly and well:
|
|
58
|
+
|
|
59
|
+
- ❌ `blocking: add error handling to fetchUser (api/user.ts:42)` — no failure scenario, no consequence; unverifiable reflex.
|
|
60
|
+
- ✅ `blocking: fetchUser (api/user.ts:42) rejects on 404 but ProfilePage (pages/profile.tsx:18) never catches — a deleted user's profile renders blank with an unhandled rejection. Fix: catch and render not-found.`
|
|
61
|
+
|
|
62
|
+
## Evidence rules
|
|
63
|
+
|
|
64
|
+
A claim about code you haven't opened this session is a hypothesis — verify it or label it as one.
|
|
65
|
+
|
|
66
|
+
- **Read beyond the hunk.** Before flagging anything, `Read` the full enclosing function (the whole file when 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.
|
|
67
|
+
- **`blocking` carries a burden of proof:** one concrete failure-scenario sentence (*this input/state → this wrong outcome*). Can't write it? Demote to `suggestion`, or raise it as a `question`.
|
|
68
|
+
- **Grep before claiming absence.** "Dead code" / "unused" / "never called" / "duplicated elsewhere" require a repo-wide `Grep` for the identifier first — cite the search in the finding.
|
|
69
|
+
- **Quote verbatim.** Error messages, test output, and load-bearing identifiers go into findings exactly as they appear; paraphrase loses the token that matters.
|
|
70
|
+
- **Zero findings is a valid verdict.** A task with nothing wrong gets a clean *Approve* — never pad Blockers or Suggestions to look thorough. Thoroughness is what you checked, not what you wrote.
|
|
71
|
+
- **User framing is input, not conclusion.** "The backend part is fine, just look at the UI" does not exempt the backend — review every task fully.
|
|
72
|
+
|
|
73
|
+
## Scope discipline
|
|
74
|
+
|
|
75
|
+
A finding must belong to the task (`#NNN`) whose diff introduced it. Pre-existing code that's merely *visible* in the diff context is out of scope — unless the task made it worse (e.g. added a second caller to an already-unsafe function; that's in scope). If you notice a pre-existing issue worth mentioning, note it in one line outside the verdict ("pre-existing, not introduced by #123") — never block a task for code its commits didn't touch.
|
|
76
|
+
|
|
57
77
|
## What to look for
|
|
58
78
|
|
|
59
79
|
### Correctness
|
|
@@ -117,7 +137,7 @@ Performance + Readability usually fold into Design — only spawn a dedicated le
|
|
|
117
137
|
- The per-task diff (commits from this `#NNN` only — not the whole branch).
|
|
118
138
|
- The inferred task intent from step 4.
|
|
119
139
|
- **One** lens with its checklist verbatim from [What to look for](#what-to-look-for).
|
|
120
|
-
- Instructions: "Find issues only in your lens. Categorize each as `blocking` / `suggestion` / `question` / `nit
|
|
140
|
+
- Instructions: "Find issues only in your lens. Read the full enclosing function before flagging — hunk-only findings are not reportable. Only flag code this task's commits introduced or worsened; pre-existing issues are out of scope. Categorize each as `blocking` / `suggestion` / `question` / `nit`; a `blocking` must state a one-sentence concrete failure scenario. Cite `file:line` for every finding. Lead each with the *why*. If no findings, say 'no findings' explicitly — do not pad. Report in ≤500 words."
|
|
121
141
|
2. **Critique round.** Read all lenses side by side, then:
|
|
122
142
|
- **Challenge every `blocking`** against context from the other lenses. Demote to `suggestion` or drop if it's defused by another lens's evidence.
|
|
123
143
|
- **Surface contradictions** as `question` items the user adjudicates (e.g. Correctness flags missing null guard; Security found the caller validates).
|
|
@@ -170,6 +190,10 @@ End with a one-line roll-up: e.g. `Overall: 2 approve, 1 request changes, 1 unsc
|
|
|
170
190
|
- ❌ Reflexively requesting tests without saying what they should cover
|
|
171
191
|
- ❌ Drive-by style nits that derail the substantive discussion
|
|
172
192
|
- ❌ "I would have done it differently" without a concrete reason
|
|
193
|
+
- ❌ Flagging from the diff hunk alone — read the enclosing function first; the guard is often just outside the hunk
|
|
194
|
+
- ❌ Blocking a task for a pre-existing issue its diff didn't introduce or worsen — note it in one line, out of verdict
|
|
195
|
+
- ❌ A `blocking` with no concrete failure scenario — if you can't write "this input → this wrong outcome", it isn't blocking
|
|
196
|
+
- ❌ Padding a clean task with speculative findings — zero findings is a valid Approve
|
|
173
197
|
- ❌ Collapsing multiple tasks into one verdict — each `#NNN` is independent and should stand or fall on its own
|
|
174
198
|
- ❌ Silently ignoring commits with no task reference — surface them in the `unscoped` bucket
|
|
175
199
|
- ❌ Convening the lens council on a 20-line task. Single-pass it.
|
package/skills/ship-it/SKILL.md
CHANGED
|
@@ -20,7 +20,8 @@ Do **not** auto-trigger when the user is asking about diff-level code quality, D
|
|
|
20
20
|
|
|
21
21
|
- **Recommend, don't refactor.** This is an audit. Never edit code unprompted. After the report, ask per-blocker whether the user wants a fix drafted.
|
|
22
22
|
- **Evidence is mandatory.** Every PASS must cite `file:line`. "I checked, it looks fine" is not a PASS — that's a GAP labelled `couldn't verify`.
|
|
23
|
-
- **
|
|
23
|
+
- **Name the probe.** Every PASS also names the exact check that produced its evidence — the grep pattern + path, the file you read, or the command you ran. If you didn't run a probe for an item, it's GAP labelled `not checked` — never PASS. A result you didn't observe doesn't exist.
|
|
24
|
+
- **N/A needs a reason grounded in the scope.** The justification must derive from an observed fact about *this* scope, with the probe that established it (e.g. *"no files under `migrations/` in the diff (`git diff --stat`) → migrations N/A"*) — never a guess from the project type. Don't fabricate gaps for categories that don't apply.
|
|
24
25
|
- **Stay in your lane.** Don't re-do `code-review`'s work. If the user asks about DRY / dead code / test coverage, defer.
|
|
25
26
|
|
|
26
27
|
## Workflow
|
|
@@ -40,6 +41,8 @@ Echo the scope back in one line before starting Phase 2 (*"Auditing branch `feat
|
|
|
40
41
|
|
|
41
42
|
For each category: state the criterion in one line, search the codebase for evidence, mark PASS / GAP / N/A. Use `Grep` and `Read` aggressively; spawn an `Explore` sub-agent for any category where the search would take more than 3 queries.
|
|
42
43
|
|
|
44
|
+
Record each probe as you run it — the report cites them. A probe is a specific `Grep` pattern + path, a `Read` of a named file, or a command with its observed output. A sub-agent's result counts as a probe only if the sub-agent names its own probes and citations; "the agent said it's fine" is not evidence. Where a check depends on the user (dashboards, runbooks, rollout plans), record their answer as the probe (*"user confirmed: alert added to Grafana billing board"*) — an unanswered question stays GAP.
|
|
45
|
+
|
|
43
46
|
#### 1. Logging
|
|
44
47
|
|
|
45
48
|
**What good looks like:** Structured logs (JSON or key=value), correlation / request IDs propagated, levels used correctly (`error` ≠ `info`), no secrets / tokens / PII in log output, errors logged with stack + context, not just the message.
|
|
@@ -118,12 +121,17 @@ Group findings into four buckets. Order matters — blocking first.
|
|
|
118
121
|
- **<category>:** <one-line problem> — `<file:line>`
|
|
119
122
|
|
|
120
123
|
## N/A
|
|
121
|
-
- **<category>:** <one-line reason>
|
|
124
|
+
- **<category>:** <one-line reason grounded in the scope> (probe: `<what established it>`)
|
|
122
125
|
|
|
123
126
|
## Passing
|
|
124
|
-
- **<category>:** <one-line evidence> — `<file:line>`
|
|
127
|
+
- **<category>:** <one-line evidence> — `<file:line>` (probe: `<grep pattern / file read / command>`)
|
|
125
128
|
```
|
|
126
129
|
|
|
130
|
+
Same PASS, written badly and well:
|
|
131
|
+
|
|
132
|
+
- ❌ `**Logging:** structured logging in place — src/billing/` — no line, no probe; unverifiable, could have been written without looking.
|
|
133
|
+
- ✅ `**Logging:** new invoice paths log via structured logger with request ID — src/billing/invoice.ts:31 (probe: grep -n "logger\." src/billing/ → 6 call sites, all pass ctx.reqId)` — anyone can rerun the probe and land on the same line.
|
|
134
|
+
|
|
127
135
|
**Blocking = any one of:**
|
|
128
136
|
- Secrets in code / logs / committed config.
|
|
129
137
|
- Missing authz on a new endpoint or screen.
|
|
@@ -145,8 +153,8 @@ After the report, ask: *"Want me to draft fixes for the blocking items, or stop
|
|
|
145
153
|
|
|
146
154
|
**Claude:**
|
|
147
155
|
1. Echoes scope: *"Auditing `feat/billing-v2` against `main` — 14 files changed."*
|
|
148
|
-
2. Walks the 10 categories, citing `file:line` per finding.
|
|
149
|
-
3. Reports: 2 blocking (missing authz on `POST /api/v2/invoices
|
|
156
|
+
2. Walks the 10 categories, citing `file:line` per finding and the probe that produced it.
|
|
157
|
+
3. Reports: 2 blocking (missing authz on `POST /api/v2/invoices` — `no tenant predicate in routes/invoices.ts:24-51, read top-to-bottom`; no rollback for the `currency_code NOT NULL` migration), 4 should-fix, 1 N/A (local-first storage — *"no client-side store in scope: `grep -rl 'localStorage\|indexedDB' src/billing/` → 0 hits, server-only module"*), 3 passing with probes named.
|
|
150
158
|
4. Asks whether to draft fixes for the blockers.
|
|
151
159
|
|
|
152
160
|
### Example 2: Module-scoped audit
|
|
@@ -167,6 +175,8 @@ After the report, ask: *"Want me to draft fixes for the blocking items, or stop
|
|
|
167
175
|
## Anti-patterns
|
|
168
176
|
|
|
169
177
|
- ❌ Marking a category PASS without a `file:line` citation. "Looks fine" is a GAP labelled `couldn't verify`.
|
|
178
|
+
- ❌ PASS on vibes — a PASS with no named probe (the grep / read / command that produced the evidence) is a GAP labelled `not checked`.
|
|
179
|
+
- ❌ N/A from a guess about the project type. Derive it from the scope and name the probe: *"no schema files in this diff (`git diff --stat`) → migrations N/A"*.
|
|
170
180
|
- ❌ Inventing GAPs in N/A categories. A server-only service genuinely has no local-first storage layer — say so and move on.
|
|
171
181
|
- ❌ Reviewing diff quality (DRY, dead code, missing tests) under the ship-it banner. Defer to `code-review`.
|
|
172
182
|
- ❌ Editing code mid-audit. The report comes first, then the user picks what to fix.
|
|
@@ -46,6 +46,20 @@ SQL changes are particularly sensitive because they often run against production
|
|
|
46
46
|
|
|
47
47
|
Lead each finding with the *why*. "This swallows the original error and surfaces a misleading permission denial" beats "add `;THROW;`".
|
|
48
48
|
|
|
49
|
+
## Pattern hit ≠ finding
|
|
50
|
+
|
|
51
|
+
The 17 checks are pattern matches. A ripgrep hit is a **candidate** — before reporting it, `Read` the whole procedure/batch it sits in; severity depends on context the pattern can't see. Concrete demotions:
|
|
52
|
+
|
|
53
|
+
- `WITH (NOLOCK)` hit, but the proc is a read-only reporting proc with no `INSERT`/`UPDATE`/`DELETE` → **WARN** at most, not BLOCKER (check #13 blocks only when the same proc writes the tables it dirty-reads).
|
|
54
|
+
- `DECLARE @retry` with no `WHILE @retry` in sight → check for a `GOTO`-label retry loop consuming it before flagging; only report when nothing reads the variable.
|
|
55
|
+
- New `CREATE TABLE` with no index, but it's a static lookup/config table seeded with a handful of rows in the same diff → **WARN** with a one-line reason, not BLOCKER (the deadlock incident needs growth under concurrent writes).
|
|
56
|
+
|
|
57
|
+
Every reported finding must:
|
|
58
|
+
1. **Quote the offending SQL verbatim** — the exact line(s) from the file, not a paraphrase. Severity turns on exact tokens.
|
|
59
|
+
2. For `BLOCKER` / `WARN`: state the concrete production incident in one sentence (*this state → this outcome*, e.g. "first deadlock under load → SP silently gives up, rows never written"). If you can't write that sentence after reading the full proc, demote one level.
|
|
60
|
+
|
|
61
|
+
Zero findings is a valid outcome — a clean diff gets a clean report. Never stretch INFO items into WARNs to fill sections; thoroughness is the 17 checks you ran, which the report shows.
|
|
62
|
+
|
|
49
63
|
## What to check
|
|
50
64
|
|
|
51
65
|
Use ripgrep for detection. The patterns below are starting points — adapt to the actual diff text.
|
|
@@ -148,6 +162,7 @@ Use ripgrep for detection. The patterns below are starting points — adapt to t
|
|
|
148
162
|
## Blockers (<N>)
|
|
149
163
|
|
|
150
164
|
### B1. <short title> — `path/to/file.sql:<line>`
|
|
165
|
+
**Evidence:** `<offending SQL fragment, quoted verbatim>`
|
|
151
166
|
**Why:** <root cause / production consequence — one line>
|
|
152
167
|
**Fix:** <concrete recommendation — one line>
|
|
153
168
|
|
|
@@ -156,6 +171,7 @@ Use ripgrep for detection. The patterns below are starting points — adapt to t
|
|
|
156
171
|
## Warnings (<N>)
|
|
157
172
|
|
|
158
173
|
### W1. <short title> — `path/to/file.sql:<line>`
|
|
174
|
+
**Evidence:** `<offending SQL fragment, quoted verbatim>`
|
|
159
175
|
**Why:** ...
|
|
160
176
|
**Fix:** ...
|
|
161
177
|
|
|
@@ -220,6 +236,10 @@ End with the offer. Wait for the user's choice.
|
|
|
220
236
|
- ❌ Suggesting autofixes for `BLOCKER` items without asking. SQL deploys to production; user confirmation gates the change.
|
|
221
237
|
- ❌ Listing a `nit` when there's a `BLOCKER` next to it. Lead with severity.
|
|
222
238
|
- ❌ Hand-wavy findings without `file:line`.
|
|
239
|
+
- ❌ Reporting a raw ripgrep hit without reading the surrounding procedure. A pattern match is a candidate; the proc's full context sets the severity (see [Pattern hit ≠ finding](#pattern-hit--finding)).
|
|
240
|
+
- ❌ Paraphrasing the offending SQL instead of quoting it verbatim. `WITH (NOLOCK)` vs `READPAST`, `@retry` vs `@retryCount` — the exact token is the finding.
|
|
241
|
+
- ❌ A `BLOCKER` with no one-sentence production-incident scenario. Can't name the incident? It's a `WARN`.
|
|
242
|
+
- ❌ Padding a clean diff with stretched findings. Zero findings is a valid report.
|
|
223
243
|
- ❌ Inventing antipatterns not in [What to check](#what-to-check). This is a fixed catalog — extending it is a `write-a-skill` change, not a per-run improvisation.
|
|
224
244
|
- ❌ Running on non-SQL files. The skill is `.sql`-scoped; mixed diffs route to `code-review` for the non-SQL parts.
|
|
225
245
|
- ✅ Diff-scoped scan for modified files, full scan for new files, findings categorized + cited + offered as fixes.
|
|
@@ -125,11 +125,21 @@ If the user pushes back, revise and re-present. Do not partial-implement against
|
|
|
125
125
|
|
|
126
126
|
Walk the plan one step at a time. For each step:
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
0. **Re-anchor.** Re-read the `Goal` section and this step's validation criterion from `Plan` before touching anything. Thirty seconds of re-reading is what keeps turn 20 aligned with turn 1 — drift is silent and this is the only cheap defense.
|
|
129
|
+
1. **Make the smallest change that completes the step.** No drive-by refactors, no "while I'm here" fixes, no batched edits across multiple steps. Done means the step's criterion, nothing more — improvements you notice (missing validation, refactor opportunity, extra config) go into `Risks` as findings, not into the diff.
|
|
129
130
|
2. **Validate immediately.** Run the test, build, type-check, lint, curl the endpoint, or load the page — whichever signal is appropriate for that step. If there's no automated signal at all, say so explicitly in `Progress`; don't pretend there is one.
|
|
130
|
-
3. **Tick the checkbox** with a
|
|
131
|
+
3. **Tick the checkbox** with evidence that is an **observed artifact from this turn** — a pasted output line, an exit code, a status code. A claim is not evidence.
|
|
132
|
+
- ❌ `tests pass` — an assertion; nothing was observed.
|
|
133
|
+
- ✅ `dotnet test → Passed! 42 passed, 0 failed, 0 skipped` — pasted from output you just saw.
|
|
134
|
+
If you didn't run it this turn, you can't tick it.
|
|
131
135
|
4. **Re-emit the full per-turn output** before moving to the next step.
|
|
132
136
|
|
|
137
|
+
When a command fails:
|
|
138
|
+
|
|
139
|
+
- Read the **full** error output — the load-bearing detail is usually in the last lines you'd skim past.
|
|
140
|
+
- Change exactly one thing based on what the error says, then retry once.
|
|
141
|
+
- Two failures on the same step = stop. Add the verbatim error to `Risks` and surface to the user. Never retry verbatim, and never continue as if the command succeeded — a result you didn't observe is not a result.
|
|
142
|
+
|
|
133
143
|
When a validation fails:
|
|
134
144
|
|
|
135
145
|
- Do not move on.
|
|
@@ -160,6 +170,9 @@ When every checkbox is ticked:
|
|
|
160
170
|
- ❌ Convening the inspection council for a 3-file task. Ceremony for its own sake. Inline reads are the default — escalate only when the inspection set genuinely spans multiple layers.
|
|
161
171
|
- ❌ Spawning the inspection sub-agents serially instead of in parallel — one message, N `Agent` calls. Serial defeats the context-protection rationale.
|
|
162
172
|
- ❌ Letting a sub-agent slice overlap with another's. If two slices would re-read the same files, merge them first.
|
|
173
|
+
- ❌ Ticking a checkbox with claimed evidence (`tests pass`) when the command wasn't run this turn. Evidence is pasted observation, not memory or assertion.
|
|
174
|
+
- ❌ Retrying a failed command verbatim, or proceeding as if it succeeded. Read the error, change one thing, retry once; twice failed = `Risks` + stop.
|
|
175
|
+
- ❌ Gold-plating a step: extra config options, defensive layers, speculative hooks the plan didn't call for. Findings go to `Risks`; the diff stays the size of the step.
|
|
163
176
|
- ✅ Same six headers every turn, one step at a time, one validation per step, assumptions tracked explicitly until confirmed or killed.
|
|
164
177
|
|
|
165
178
|
## Examples
|
|
@@ -43,6 +43,8 @@ The user does **not** want hard-coded Cargo / npm versions baked into the skill.
|
|
|
43
43
|
3. Pin the Rust edition to `2021` unless the user asks otherwise.
|
|
44
44
|
4. Quote the resolved versions back to the user before generating, so they can object.
|
|
45
45
|
5. Default to **npm** unless `pnpm` or `bun` is present and the user prefers it.
|
|
46
|
+
6. Concrete resolution commands when context7 is unavailable: `npm view @tauri-apps/api version`, `cargo search <crate> --limit 1`, or WebFetch `https://crates.io/api/v1/crates/<crate>` (`max_stable_version`). Never write a version you did not just resolve this session — no versions from memory, no invented numbers.
|
|
47
|
+
7. **Tauri 1.x is poison.** Training data is full of v1 patterns that look plausible and fail on v2. Never emit: `import { invoke } from '@tauri-apps/api/tauri'` (the v2 path is `@tauri-apps/api/core`), a `tauri.allowlist` or top-level `tauri` key in `tauri.conf.json` (v2 uses `app` / `bundle` / `plugins` + `capabilities/*.json`), or v1 plugin names/APIs. If you are not certain a conf key, capability permission string, or plugin API exists in Tauri 2, verify it against the installed schema (`node_modules/@tauri-apps/cli/config.schema.json`; valid permission strings appear in `src-tauri/gen/schemas/` after the first build) or the plugin's docs **before** writing code that depends on it. Capability `permissions` entries use the short plugin name (`dialog:allow-open`, `fs:allow-read-file`) — never a `tauri-plugin-` prefix. Note that `cargo check` compiles `tauri-build`, which validates `tauri.conf.json` and `capabilities/*.json` — a schema or unknown-permission error there is a JSON problem; fix the conf/capability file against the schema, don't edit Rust code to appease it.
|
|
46
48
|
|
|
47
49
|
### Step 2 — Gather inputs (ask once, in one batch)
|
|
48
50
|
|
|
@@ -71,14 +73,17 @@ Use the **templates in [`references/templates/`](references/templates/)** as the
|
|
|
71
73
|
- Create directories before files. On Windows shell use PowerShell `New-Item -ItemType Directory -Force`.
|
|
72
74
|
- Do **not** run `create-tauri-app` to bootstrap — write the files directly from templates so the layout matches the conventions in [`references/folder-layout.md`](references/folder-layout.md). Use `npm install` after `package.json` is written, then `cargo fetch` from `src-tauri/` to seed the Cargo cache.
|
|
73
75
|
- For icons, run `npx @tauri-apps/cli icon <path-to-source.png>` once a source image exists, or generate a 1024×1024 placeholder with `sharp` if the user wants. Do **not** commit a placeholder square as the final icon — surface it as a TODO.
|
|
76
|
+
- If a generator IS run (`create-tauri-app` at the user's insistence, `npx @tauri-apps/cli icon`, `tauri signer generate`) and its output differs from this skill's layout: **Tauri wins on file locations it mandates** (`src-tauri/` shape, `capabilities/`, `gen/`, icon paths), **this skill wins on everything Tauri doesn't mandate** (the `commands/`/`state/`/`storage/`/`platform/` module split, frontend hooks layout). Reconcile deliberately and list every deviation in your report — never force the skill layout over a framework requirement, never silently abandon the skill's patterns.
|
|
74
77
|
|
|
75
78
|
### Step 4 — Verify and report
|
|
76
79
|
|
|
77
80
|
- Run `npm install` (or chosen PM).
|
|
78
|
-
- Run `cd src-tauri && cargo build` — must exit 0. (Don't run `tauri dev` in CI — it opens a window.)
|
|
81
|
+
- Run `cd src-tauri && cargo build` — must exit 0. (Don't run `tauri dev` in CI — it opens a window.) If a full `cargo build` is prohibitively slow in this environment, `cargo check` is the minimum acceptable bar — state which one you ran.
|
|
79
82
|
- Run `cd src-tauri && cargo test` — must exit 0 if any tests were generated.
|
|
80
|
-
- Run `npm run build` (frontend) — must exit 0.
|
|
83
|
+
- Run `npm run build` (frontend) — must exit 0. `cargo check` + `npm run build` together are the floor; a full `tauri build` is optional (slow).
|
|
81
84
|
- Optionally run `npm run tauri build -- --debug` if the user wants a debug bundle; skip in CI by default since it's slow.
|
|
85
|
+
- **A scaffold that hasn't compiled is not delivered.** Paste the actual proof lines in your report (cargo's `Finished` profile line, `test result: ok`, Vite's `✓ built in ...`). 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.
|
|
86
|
+
- **CLI failure protocol** (applies to `npm install`, `cargo build`/`check`/`test`, `npm run build`): read the full error output — for cargo, fix the **first** error; later ones are usually cascade. 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 a broken base, and do not re-run the identical command hoping for a different result.
|
|
82
87
|
- Reply with a short summary: project path, versions chosen, plugins wired, bundle identifier, next steps (e.g. "fill in the macOS `Info.plist` usage descriptions for any permissions you'll request", "generate updater keys with `npx tauri signer generate`", "run `npm run tauri dev`").
|
|
83
88
|
|
|
84
89
|
## Project layout (canonical)
|
|
@@ -236,6 +241,9 @@ Every one of these is forbidden in generated code. Rationale for each is in [`re
|
|
|
236
241
|
3. `src-tauri/Cargo.toml` (with target-specific deps + release profile), `src-tauri/build.rs`, `src-tauri/tauri.conf.json`, `src-tauri/Info.plist`, `src-tauri/entitlements.plist`, `src-tauri/capabilities/default.json`.
|
|
237
242
|
4. `src-tauri/icons/` — placeholder 1024×1024 PNG **only** if the user hasn't supplied one. Surface as TODO; tell them to run `npx @tauri-apps/cli icon icons/icon.png`.
|
|
238
243
|
5. `src-tauri/src/main.rs`, `src-tauri/src/lib.rs`, `src-tauri/src/error/mod.rs`, `src-tauri/src/state/mod.rs`, `src-tauri/src/storage/mod.rs`, `src-tauri/src/commands/mod.rs` + `src-tauri/src/commands/system.rs`, `src-tauri/src/platform/{mod,traits,macos,windows,linux,wrappers}.rs`, `src-tauri/src/settings/{mod,defaults,storage,commands}.rs`.
|
|
244
|
+
|
|
245
|
+
**Checkpoint:** run `npm install` then a first `cd src-tauri && cargo check` here, before optional modules — errors localize to the core tree, and this check runs `tauri-build`, which validates `tauri.conf.json` + `capabilities/*.json` and generates `src-tauri/gen/schemas/` (the authority for valid permission strings). Fix any conf/capability error now, per the Step-4 failure protocol, before writing more capability entries.
|
|
246
|
+
|
|
239
247
|
6. Optional: `src-tauri/src/encryption/mod.rs`, `src-tauri/src/tray.rs`, `src-tauri/src/commands/<more>.rs` based on user answers.
|
|
240
248
|
7. `src-tauri/tests/common/mod.rs` + at least one integration test file (e.g. `system_test.rs`) so CI has something real to run.
|
|
241
249
|
4. `npm install`.
|
|
@@ -261,7 +269,7 @@ For command `{{command}}` (snake_case) in module `commands/{{domain}}.rs`:
|
|
|
261
269
|
- Export the hook. Do **not** call `invoke()` inline in a component.
|
|
262
270
|
4. **Test**: add an integration test in `src-tauri/tests/{{domain}}_test.rs` that exercises the command's underlying function (the `#[tauri::command]` itself is hard to call without a full Tauri context — test the inner function).
|
|
263
271
|
|
|
264
|
-
After generating: `cd src-tauri && cargo build && cargo test` then `npm run build` from the project root.
|
|
272
|
+
After generating: `cd src-tauri && cargo build && cargo test` then `npm run build` from the project root. Apply the Step-4 proof-and-failure protocol — paste the green lines; the same step failing twice = stop and surface the verbatim error.
|
|
265
273
|
|
|
266
274
|
### Mode 3 — `add-module`
|
|
267
275
|
|
|
@@ -275,7 +283,7 @@ For module `{{module}}` (snake_case):
|
|
|
275
283
|
6. Add a `#[cfg(test)]` `mod tests { ... }` block at the bottom of `mod.rs` covering pure logic (no Tauri context required).
|
|
276
284
|
7. Add a `src-tauri/tests/{{module}}_test.rs` integration test if the module has cross-cutting behavior.
|
|
277
285
|
|
|
278
|
-
After generating: `cd src-tauri && cargo build && cargo test
|
|
286
|
+
After generating: `cd src-tauri && cargo build && cargo test` — Step-4 proof-and-failure protocol applies.
|
|
279
287
|
|
|
280
288
|
## NuGet... wait, this is Tauri. Cargo + npm packages (resolve latest stable at scaffold time)
|
|
281
289
|
|
|
@@ -320,6 +328,22 @@ Look these up at scaffold time — do not hand-paste versions:
|
|
|
320
328
|
|
|
321
329
|
## Verification checklist before reporting "done"
|
|
322
330
|
|
|
331
|
+
Run this as a **mechanical pass over the generated tree** — grep, don't recall. The Eliminate list is easy to hold at file 1 and forgotten by file 30. Start with this grep block; every command must return nothing:
|
|
332
|
+
|
|
333
|
+
```bash
|
|
334
|
+
grep -rn "cfg!(target_os" src-tauri/src --include='*.rs' | grep -v "src/platform/" # platform checks outside platform/
|
|
335
|
+
grep -rn "@tauri-apps/api/tauri" src/ # v1 import path (v2 is /core)
|
|
336
|
+
grep -n "allowlist\|systemTray" src-tauri/tauri.conf.json # v1 config schema leaking in (v2: capabilities/, app.trayIcon)
|
|
337
|
+
grep -rn "tauri::api::" src-tauri/src --include='*.rs' # v1 Rust API paths (v2 moved these to plugins)
|
|
338
|
+
grep -rnE "pub (api_key|token|secret)\w*: String" src-tauri/src/ # plaintext secret fields (must be EncryptedApiKey)
|
|
339
|
+
grep -rn "localStorage.setItem\|sessionStorage.setItem" src/ # tokens/secrets in web storage
|
|
340
|
+
grep -n "\"devtools\": true" src-tauri/tauri.conf.json # devtools enabled in release config
|
|
341
|
+
grep -rn "std::fs::" src-tauri/src/commands/ # raw fs in command bodies
|
|
342
|
+
find src-tauri/src -name "*.backup" -o -name "*.orig" -o -name "*.temp" # WIP artefacts
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
A hit means fix it and re-run the grep — never rationalize it away. Then the full checklist:
|
|
346
|
+
|
|
323
347
|
- [ ] `npm install` succeeds.
|
|
324
348
|
- [ ] `cd src-tauri && cargo build` exits 0.
|
|
325
349
|
- [ ] `cd src-tauri && cargo test` exits 0 (if tests were generated).
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: think-like-fable
|
|
3
|
+
description: An operating manual for rigorous reasoning — how to read the real request beneath the words, decompose into independently-checkable pieces, spend effort where the risk lives, verify by re-derivation instead of plausibility, label known vs. guessed, attack your own conclusion, and communicate answer-first. Apply it to the task at hand; it changes HOW you work, not WHAT you do. Use this skill whenever the user says "think like fable", "/think-like-fable", "be rigorous", "think hard about this", "reason carefully", "are you sure?", "double-check that", "don't guess", or hands you a high-stakes decision, a tricky analysis, a root-cause question, or anything where a confident wrong answer is worse than a slow right one — even if they don't name the skill. Do not load it for trivial mechanical edits or casual questions.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Think Like Fable
|
|
7
|
+
|
|
8
|
+
A senior operator's manual for a sharp junior. Not a rulebook to satisfy — a way of working to inhabit. Load it, then do the actual task under these disciplines. Every section is: the procedure, one example of it working, and the failure it prevents.
|
|
9
|
+
|
|
10
|
+
## When to use this skill
|
|
11
|
+
|
|
12
|
+
- The user says "think like fable", "/think-like-fable", "be rigorous", "think hard about this", "reason carefully", "are you sure?", "double-check that", or "don't guess".
|
|
13
|
+
- The task is a high-stakes decision, root-cause analysis, architecture call, security judgment, or data-loss-adjacent change — anywhere a confident wrong answer costs more than a slow right one.
|
|
14
|
+
- Another skill or agent prompt says to apply this manual to its work.
|
|
15
|
+
|
|
16
|
+
Do **not** load it for trivial mechanical edits, casual questions, or tasks another skill already governs end-to-end — this manual composes *under* task skills, it doesn't replace them.
|
|
17
|
+
|
|
18
|
+
## 1. Read what the request is actually asking
|
|
19
|
+
|
|
20
|
+
**Procedure:** Before answering, write one sentence: "The user needs ___ so that ___." If you can't fill the second blank, you don't understand the request yet. Check the literal ask against the inferred goal — when they diverge, serve the goal and say you did. Look for the question behind the question: a "how do I X" often means "I'm stuck on Y and think X will fix it."
|
|
21
|
+
|
|
22
|
+
**Example:** "How do I increase the connection pool size?" — literal ask: a config value. Actual need: their app is timing out. The right answer names the config *and* says "if you're seeing timeouts, pool exhaustion is usually a symptom — check for unclosed connections first."
|
|
23
|
+
|
|
24
|
+
**Prevents:** Perfectly executing the wrong task. The junior failure is answering the words; the expensive failure is the user discovering three exchanges later that you solved a question they didn't have.
|
|
25
|
+
|
|
26
|
+
## 2. Break the problem into independently checkable pieces
|
|
27
|
+
|
|
28
|
+
**Procedure:** Decompose so each piece has its own pass/fail test that doesn't depend on the other pieces being right. If two pieces can only be verified together, the cut is wrong — recut. Order pieces so the ones that would invalidate the others come first. A decomposition where step 5 can silently absorb an error from step 2 is a narrative, not a decomposition.
|
|
29
|
+
|
|
30
|
+
**Example:** "Why is this endpoint slow?" → (a) is it actually slow — measure; (b) is time in the DB, the app, or the network — one timer each; (c) within the winner, which call — profile. Each answer is checkable alone, and (a) can kill the whole investigation in one step.
|
|
31
|
+
|
|
32
|
+
**Prevents:** The chain-of-plausibility, where five individually-reasonable steps compound into a confident conclusion nothing ever tested.
|
|
33
|
+
|
|
34
|
+
## 3. Put the effort where the risk lives
|
|
35
|
+
|
|
36
|
+
**Procedure:** Before working, ask: "If this answer is wrong, which part is most likely to be the wrong part — and how bad is being wrong there?" Effort follows that product, not difficulty and not interest. The risky part is usually a boundary (auth, money, data deletion, concurrency, an interface you didn't write), an assumption everything downstream leans on, or the one claim you can't check. Say out loud which part got the scrutiny.
|
|
37
|
+
|
|
38
|
+
**Example:** A 200-line PR: 180 lines of UI layout, 20 lines changing a retry loop around a payment call. The 20 lines get 80% of the review. A double-charged customer costs more than a misaligned button.
|
|
39
|
+
|
|
40
|
+
**Prevents:** Uniform effort — polishing what's easy to check while the load-bearing assumption ships unexamined.
|
|
41
|
+
|
|
42
|
+
## 4. Verify by re-deriving, not by recognizing
|
|
43
|
+
|
|
44
|
+
**Procedure:** For any load-bearing claim, reconstruct it from ground truth through an independent path: run the code, re-do the arithmetic from the inputs, open the file, quote the doc. "It sounds right" and "I've seen this pattern" are recognition, not verification — recognition is exactly what fails on the cases that matter. A claim about code you haven't opened is a hypothesis and must be labeled as one. A result you didn't observe is "not run", never "passed".
|
|
45
|
+
|
|
46
|
+
**Example:** "This function is O(n²) because of the nested loop." Re-derive: open it — the inner loop runs over a fixed 3-element list. It's O(n). The pattern-match was confident and wrong.
|
|
47
|
+
|
|
48
|
+
**Prevents:** Plausible fabrication — the failure mode where fluency substitutes for evidence and the error is invisible precisely because the prose reads well.
|
|
49
|
+
|
|
50
|
+
## 5. Separate known from guessed, and label it out loud
|
|
51
|
+
|
|
52
|
+
**Procedure:** Every substantive claim carries one of three tags, in the text, not in your head: **verified** (I checked, here's how), **inferred** (follows from X, which I checked), **assumed** (unverified; if wrong, Y breaks). Never let an assumption silently upgrade itself by being repeated. When the whole answer hangs on one assumption, lead with it.
|
|
53
|
+
|
|
54
|
+
**Example:** ❌ "The webhook fails because the secret rotated." ✅ "The webhook fails on signature validation (verified — log line quoted below). The likeliest cause is a rotated secret (assumed — I can't see your dashboard; if the secret matches, look at clock skew next)."
|
|
55
|
+
|
|
56
|
+
**Prevents:** Confidence laundering — a guess stated in the same register as a fact, which the reader has no way to discount until it fails in production.
|
|
57
|
+
|
|
58
|
+
## 6. Attack your own conclusion before handing it over
|
|
59
|
+
|
|
60
|
+
**Procedure:** Once you have an answer, switch sides. Spend one honest pass asking: what evidence would prove this wrong, and did I actually look for it? What's the strongest alternative explanation, and why specifically is it worse? If you can't name a way your answer could be wrong, you haven't understood it — every real conclusion has a failure condition. Cheapest test: does the answer survive the most mundane explanation (typo, cache, wrong environment, stale data) being true instead?
|
|
61
|
+
|
|
62
|
+
**Example:** Conclusion: "the race condition is in the cache layer." Attack: if it were, the bug would also appear in the read-only path — does it? Check. It doesn't. Conclusion downgraded, actual cause found in the writer's lock ordering.
|
|
63
|
+
|
|
64
|
+
**Prevents:** First-hypothesis anchoring — where all subsequent effort collects support for the initial guess instead of testing it.
|
|
65
|
+
|
|
66
|
+
## 7. Communicate answer → reasoning → risk, in that order
|
|
67
|
+
|
|
68
|
+
**Procedure:** First sentence: the answer, decision-ready ("Yes, ship it", "It's the lock ordering in `flush()`", "Don't use library X"). Then the reasoning that earns it, shortest complete path only. Then the risk: what would change this answer, what you didn't check, what to watch for. Never make the reader excavate the conclusion from a chronology of your process.
|
|
69
|
+
|
|
70
|
+
**Example:** ❌ "First I looked at the logs, then I noticed…, which led me to…" ✅ "The crash is a null deref in `parse_header` on empty payloads (verified with a repro). Reasoning: … Risk: I only tested v2 payloads; if v1 traffic still exists, verify that path separately."
|
|
71
|
+
|
|
72
|
+
**Prevents:** Burying the lede — the reader skims, grabs a mid-paragraph detail as the takeaway, and acts on the wrong thing.
|
|
73
|
+
|
|
74
|
+
## 8. The mistakes that look like competence and aren't
|
|
75
|
+
|
|
76
|
+
Each of these *feels* like doing a good job. That's what makes them dangerous.
|
|
77
|
+
|
|
78
|
+
- **Thoroughness theater.** Ten findings where two matter. Exhaustiveness reads as rigor but is its absence — rigor is ranking. Say which two matter. Zero findings is a valid result.
|
|
79
|
+
- **Fluent overclaiming.** Polished prose at a fixed confidence level regardless of evidence. Calibration, not eloquence, is the skill. An expert's "I don't know, but here's how to find out" beats a fluent guess.
|
|
80
|
+
- **Premature agreement.** Adopting the user's framing ("since the cache is the problem…") as a conclusion. Their framing is input, not evidence — it's often where the bug hides, because it's the one thing they've stopped questioning.
|
|
81
|
+
- **Complexity as signal.** Reaching for the sophisticated explanation because it displays skill. Mundane causes are the base rate: check the typo before theorizing the distributed-systems failure.
|
|
82
|
+
- **Silent scope repair.** The task as specified has a hole; you patch it with a reasonable choice and don't mention it. The choice may be fine — the silence is the defect. Name every hole you filled.
|
|
83
|
+
- **Momentum completion.** Finishing because you've invested, when a mid-course finding meant the plan should change. Sunk work is not evidence the direction was right.
|
|
84
|
+
- **Deference to your own prior output.** Treating what you said earlier in the session as established fact. Your earlier claims have the same epistemic status as anyone's: whatever the evidence gave them.
|
|
85
|
+
|
|
86
|
+
## The self-test — run on every answer before sending
|
|
87
|
+
|
|
88
|
+
1. **Did I answer the question they needed, not just the one they typed?** (Can I state the need behind the ask in one sentence?)
|
|
89
|
+
2. **Which claim, if wrong, breaks this answer — and did I verify *that one* by re-deriving it, not recognizing it?**
|
|
90
|
+
3. **Is every unverified assumption labeled in the text, or is at least one guess wearing a fact's clothes?**
|
|
91
|
+
4. **Did I genuinely try to break this conclusion — can I name the observation that would prove it wrong?**
|
|
92
|
+
5. **Is the answer in the first sentence, and the risk stated at the end — or does the reader have to excavate both?**
|
|
93
|
+
|
|
94
|
+
Any "no" — fix it before sending. All five "yes" on a wrong answer is still possible; the test buys diligence, not certainty. Say so when the stakes warrant it.
|
|
95
|
+
|
|
96
|
+
## Anti-patterns
|
|
97
|
+
|
|
98
|
+
- ❌ Loading this skill and then narrating it ("Per section 4, I will now verify…") — inhabit the discipline silently; the user sees the *product* of it, not citations to it.
|
|
99
|
+
- ❌ Running the self-test as a checkbox ritual and passing everything — the test only works adversarially; a pass you didn't try to fail is not a pass.
|
|
100
|
+
- ❌ Applying full rigor to a trivial ask — a one-line factual question doesn't need a risk section. Depth scales with stakes (section 3 applies to the manual itself).
|
|
101
|
+
- ✅ Do the user's actual task under these disciplines and let the output show it: answer first, claims tagged, the riskiest part visibly the most scrutinized.
|
|
@@ -115,6 +115,30 @@ The description is the **only** field Claude reads when deciding whether to cons
|
|
|
115
115
|
|
|
116
116
|
The most common failure mode is **under-triggering** (Claude doesn't load the skill when it should). Err on the side of *more* trigger phrases — three is the floor, not the ceiling.
|
|
117
117
|
|
|
118
|
+
## Write for the weakest reader
|
|
119
|
+
|
|
120
|
+
The skill will be executed by whatever model loads it — often a smaller one. A top-tier model fills gaps with judgment; a weak one fills them with confident garbage. Encode the judgment explicitly. Preempt these predictable failure modes:
|
|
121
|
+
|
|
122
|
+
1. **Ungrounded claims.** If the skill has the model assert facts about code (reviews, audits, explainers), add evidence gates — name the exact check that licenses each kind of assertion. Include the rule verbatim: *a claim about code the model hasn't opened is a hypothesis and must be labeled as one.*
|
|
123
|
+
- ❌ "Flag unused exports." — the model flags whatever it doesn't recognize.
|
|
124
|
+
- ✅ "Flag an export as unused only after a repo-wide grep for its name returns no callers outside its own file. Read the whole function before judging it, not just the diff hunk."
|
|
125
|
+
2. **Severity inflation / padding.** Report-producing skills need burden-of-proof rules and an explicit *"zero findings is a valid outcome"* clause — otherwise weak models invent findings to look thorough.
|
|
126
|
+
- ❌ "Be rigorous about severity." — everything still gets marked critical.
|
|
127
|
+
- ✅ "A `blocker` must name a concrete failure scenario in one sentence (`user does X → wrong Y`). No scenario → demote to `suggestion`. Zero blockers is a valid result."
|
|
128
|
+
3. **Confabulated success.** Any skill that runs commands needs: *a result you didn't observe is "not run", never "passed"* — plus a failure protocol: read the error, change exactly one thing, retry once; two failures = stop and surface to the user.
|
|
129
|
+
- ❌ "Run the tests and fix any failures." — the model may report "tests pass" without running them.
|
|
130
|
+
- ✅ "Run the test command and quote its summary line in your report. If you did not run it, write `tests: not run`."
|
|
131
|
+
4. **Contrastive examples beat rules.** Weak models imitate examples more than they follow rules. Every rule that matters should carry a ❌/✅ pair — the *same* output done badly and well — with one line on why the ✅ wins. A rule without an example is a suggestion.
|
|
132
|
+
5. **Forking questions.** Interview-style skills need: *a question earns its slot only if different answers lead to different next steps.*
|
|
133
|
+
- ❌ "Should this be robust and user-friendly?" — every answer leads to the same next step; it's filler.
|
|
134
|
+
- ✅ "Postgres or SQLite?" — each answer changes the migration step that follows.
|
|
135
|
+
6. **Re-anchoring.** Multi-turn skills need a cheap ritual — or the executing model drifts from the objective as context grows.
|
|
136
|
+
- ❌ A 9-step workflow with no checkpoint — by step 6 the model is optimizing the wrong thing.
|
|
137
|
+
- ✅ "Before each step, restate the goal in one line. If the step doesn't serve it, stop."
|
|
138
|
+
7. **Context budget.** Every line of the skill is loaded into the executing model's window. Density over coverage — a 600-line skill degrades the very model it's trying to help. Cut before you split; split into `references/` before you exceed ~150 lines.
|
|
139
|
+
|
|
140
|
+
When reviewing a draft, simulate the weakest reader: for each instruction ask "could this be followed *wrong* while technically complying?" If yes, tighten it with a check, a threshold, or an example.
|
|
141
|
+
|
|
118
142
|
## When to add scripts or reference files
|
|
119
143
|
|
|
120
144
|
Default to a single `SKILL.md`. Only escalate when:
|
|
@@ -136,6 +160,9 @@ Before showing the draft to the user:
|
|
|
136
160
|
- [ ] Workflow steps are imperative and verifiable, not vibes ("Verify X exists", not "Be careful")
|
|
137
161
|
- [ ] At least one concrete example
|
|
138
162
|
- [ ] Anti-patterns section names plausible wrong behaviors, not strawmen
|
|
163
|
+
- [ ] Each rule that matters carries a ❌/✅ pair of the same output done badly and well
|
|
164
|
+
- [ ] Each assertion the skill asks the model to make has an evidence gate — the exact check that licenses it
|
|
165
|
+
- [ ] Report-producing skills state "zero findings is a valid outcome"; command-running skills state "a result you didn't observe is 'not run', never 'passed'"
|
|
139
166
|
- [ ] No time-sensitive info (specific dates, "as of 2026", model version numbers) unless load-bearing
|
|
140
167
|
- [ ] File is under ~150 lines; longer content is split into `references/`
|
|
141
168
|
- [ ] If targeting the library repo, README table row is added in alphabetical order
|
|
@@ -178,6 +205,8 @@ Before showing the draft to the user:
|
|
|
178
205
|
- ❌ Writing a vague description like "Helps with commits." — Claude won't trigger it. Always include explicit trigger phrases.
|
|
179
206
|
- ❌ Inventing trigger phrases the user didn't confirm — ask, don't guess.
|
|
180
207
|
- ❌ Padding `SKILL.md` with motivational prose. Every line should change Claude's behavior; if removing it changes nothing, cut it.
|
|
208
|
+
- ❌ Delegating judgment to the executing model ("use discretion", "be careful", "apply good judgment") — name the check, the threshold, and the fallback instead.
|
|
209
|
+
- ❌ Stating a load-bearing rule without a ❌/✅ pair — weak models imitate examples, not prose.
|
|
181
210
|
- ❌ Hard-coding model names, package versions, or dates that will rot. Resolve at runtime when possible.
|
|
182
211
|
- ❌ Putting executable behavior in `SKILL.md` prose when a 10-line script would be deterministic and cheaper.
|
|
183
212
|
- ❌ For library skills: drafting the SKILL.md but forgetting to update the README table — the skill is invisible to anyone browsing the repo.
|