@iceinvein/agent-skills 0.1.37 → 0.1.39
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/package.json +1 -1
- package/skills/bounded-context-auditor/SKILL.md +15 -3
- package/skills/bounded-context-auditor/skill.json +1 -1
- package/skills/codebase-architecture/SKILL.md +4 -4
- package/skills/codebase-architecture/skill.json +1 -1
- package/skills/cognitive-load-auditor/SKILL.md +11 -9
- package/skills/cognitive-load-auditor/skill.json +1 -1
- package/skills/cohesion-analyzer/SKILL.md +1 -1
- package/skills/cohesion-analyzer/skill.json +1 -1
- package/skills/composability-auditor/SKILL.md +5 -5
- package/skills/composability-auditor/skill.json +1 -1
- package/skills/contract-enforcer/SKILL.md +5 -5
- package/skills/contract-enforcer/skill.json +1 -1
- package/skills/coupling-auditor/SKILL.md +2 -2
- package/skills/coupling-auditor/skill.json +1 -1
- package/skills/cover-letter/SKILL.md +18 -20
- package/skills/cover-letter/skill.json +7 -2
- package/skills/cover-letter-audit/SKILL.md +20 -20
- package/skills/cover-letter-audit/skill.json +7 -2
- package/skills/cover-letter-persona/SKILL.md +13 -13
- package/skills/cover-letter-persona/skill.json +7 -2
- package/skills/cover-letter-rewrite/SKILL.md +18 -16
- package/skills/cover-letter-rewrite/skill.json +7 -2
- package/skills/cover-letter-write/SKILL.md +25 -20
- package/skills/cover-letter-write/skill.json +7 -2
- package/skills/cqs-auditor/SKILL.md +19 -47
- package/skills/cqs-auditor/skill.json +1 -1
- package/skills/demeter-enforcer/SKILL.md +5 -5
- package/skills/demeter-enforcer/skill.json +1 -1
- package/skills/dependency-direction-auditor/SKILL.md +1 -1
- package/skills/dependency-direction-auditor/skill.json +1 -1
- package/skills/design-review/SKILL.md +6 -2
- package/skills/design-review/skill.json +1 -1
- package/skills/error-strategist/SKILL.md +3 -3
- package/skills/error-strategist/skill.json +1 -1
- package/skills/event-design-reviewer/SKILL.md +3 -3
- package/skills/event-design-reviewer/skill.json +1 -1
- package/skills/evolution-analyzer/SKILL.md +4 -3
- package/skills/evolution-analyzer/skill.json +1 -1
- package/skills/gestalt-reviewer/SKILL.md +8 -4
- package/skills/gestalt-reviewer/skill.json +1 -1
- package/skills/idempotency-guardian/SKILL.md +6 -6
- package/skills/idempotency-guardian/skill.json +1 -1
- package/skills/improve-my-codebase/CATALOGUE-FIELDS.md +2 -2
- package/skills/improve-my-codebase/SKILL.md +68 -27
- package/skills/improve-my-codebase/skill.json +1 -1
- package/skills/index.json +33 -33
- package/skills/integration-pattern-auditor/SKILL.md +2 -2
- package/skills/integration-pattern-auditor/skill.json +1 -1
- package/skills/magpie/README.md +3 -5
- package/skills/magpie/SKILL.md +39 -536
- package/skills/magpie/package.json +1 -1
- package/skills/magpie/references/critic.md +58 -0
- package/skills/magpie/references/peer-review.md +84 -0
- package/skills/magpie/references/specialists.md +391 -0
- package/skills/magpie/scripts/__tests__/helper.test.ts +40 -0
- package/skills/magpie/scripts/__tests__/skill-lint.test.ts +116 -28
- package/skills/magpie/scripts/__tests__/status-cmd.test.ts +13 -0
- package/skills/magpie/scripts/helper.js +24 -13
- package/skills/magpie/scripts/status-cmd.ts +10 -1
- package/skills/magpie/skill.json +2 -1
- package/skills/module-secret-auditor/SKILL.md +8 -5
- package/skills/module-secret-auditor/skill.json +1 -1
- package/skills/port-adapter-auditor/SKILL.md +3 -3
- package/skills/port-adapter-auditor/skill.json +1 -1
- package/skills/rams-design-audit/SKILL.md +4 -2
- package/skills/rams-design-audit/skill.json +1 -1
- package/skills/seam-finder/SKILL.md +2 -2
- package/skills/seam-finder/skill.json +1 -1
- package/skills/simplicity-razor/SKILL.md +4 -4
- package/skills/simplicity-razor/skill.json +1 -1
- package/skills/temporal-coupling-detector/SKILL.md +2 -2
- package/skills/temporal-coupling-detector/skill.json +1 -1
- package/skills/terse/SKILL.md +12 -7
- package/skills/terse/skill.json +1 -1
- package/skills/type-driven-designer/SKILL.md +8 -8
- package/skills/type-driven-designer/skill.json +1 -1
- package/skills/unidirectional-flow-enforcer/SKILL.md +2 -2
- package/skills/unidirectional-flow-enforcer/skill.json +1 -1
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cover-letter-rewrite
|
|
3
3
|
description: >
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
cover letter", "this cover letter sounds AI", "make this less generic", "make
|
|
12
|
-
this more specific", or shares a letter and asks for edits.
|
|
4
|
+
Use when the user asks to rewrite, improve, humanize, fix, or tighten an
|
|
5
|
+
existing cover letter ("this sounds AI", "make it less generic"), or shares
|
|
6
|
+
a letter asking for edits. Audit-driven targeted revision that preserves the
|
|
7
|
+
applicant's voice where it works; focus passes via --focus
|
|
8
|
+
humanize|align|tighten|structure|tone. Emits markdown, DOCX, and PDF. NOT
|
|
9
|
+
for writing from scratch (cover-letter-write) or score-only feedback
|
|
10
|
+
(cover-letter-audit).
|
|
13
11
|
argument-hint: "<letter-file> [--resume <file>] [--jd <file|url|text>] [--focus humanize|align|tighten|structure|tone] [--length short|standard|long] [--out <dir>]"
|
|
14
12
|
---
|
|
15
13
|
|
|
@@ -24,11 +22,12 @@ targeting the weakest category (or the user's --focus).
|
|
|
24
22
|
- **Rewrite**: user has a draft they like the bones of. Keep their voice,
|
|
25
23
|
fix specific issues.
|
|
26
24
|
- **Write**: user has resume + JD and nothing else, or the existing letter is
|
|
27
|
-
so generic it would be easier to start fresh (audit score below
|
|
28
|
-
multiple critical
|
|
25
|
+
so generic it would be easier to start fresh (audit score below 60, the
|
|
26
|
+
"Rewrite" band in cover-letter-audit's rating table, with multiple critical
|
|
27
|
+
issues).
|
|
29
28
|
|
|
30
29
|
If the user asks to "improve" or "fix" a letter, default to rewrite. If the
|
|
31
|
-
letter scores below
|
|
30
|
+
letter scores below 60 with fabrication or complete topic drift, suggest a
|
|
32
31
|
fresh `/cover-letter write` instead.
|
|
33
32
|
|
|
34
33
|
## Inputs
|
|
@@ -50,6 +49,7 @@ Flags:
|
|
|
50
49
|
- `--out <dir>` (default `./cover-letters/`).
|
|
51
50
|
- `--preserve-voice` (stricter; forbid changes outside the flagged issues).
|
|
52
51
|
- `--diff` (emit a unified diff between original and rewrite alongside files).
|
|
52
|
+
- `--show-audit` (print the full before/after audit reports instead of the one-line score summaries).
|
|
53
53
|
|
|
54
54
|
If resume or JD is missing and would be needed for the requested focus,
|
|
55
55
|
either ask for it or proceed with a caveat (for example, `--focus humanize`
|
|
@@ -149,8 +149,9 @@ Actions:
|
|
|
149
149
|
delivering results" becomes "Shipped three products to production in the
|
|
150
150
|
last two years" (or similar; use real resume content).
|
|
151
151
|
- Remove em-dashes; replace with period or comma or parentheses.
|
|
152
|
-
- Add burstiness
|
|
153
|
-
|
|
152
|
+
- Add burstiness to the level the audit scores for: at least one short
|
|
153
|
+
sentence (under 10 words) AND one long sentence (over 20 words) per
|
|
154
|
+
paragraph, with sentence-length standard deviation >= 5.
|
|
154
155
|
- Raise TTR: replace repeated nouns and verbs with synonyms the applicant
|
|
155
156
|
would actually use.
|
|
156
157
|
- Cut hedging and throat-clearing ("I would like to", "I believe", "it is
|
|
@@ -229,8 +230,9 @@ Actions:
|
|
|
229
230
|
### align focus
|
|
230
231
|
|
|
231
232
|
The JD lists "experience with Kafka" as a must-have. The original letter
|
|
232
|
-
doesn't mention it. The resume lists "migrated order
|
|
233
|
-
event sourcing (2M events/day)". Rewrite adds a single
|
|
233
|
+
doesn't mention it. The resume lists, under the Shopify role, "migrated order
|
|
234
|
+
service to Kafka-backed event sourcing (2M events/day)". Rewrite adds a single
|
|
235
|
+
clause (every fact in it, including the employer, traces to the resume):
|
|
234
236
|
|
|
235
237
|
**Before:**
|
|
236
238
|
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cover-letter-rewrite",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Audit-driven targeted rewrite of an existing cover letter. Focus modes: humanize, align, tighten, structure, tone; preserves voice where it already works",
|
|
5
5
|
"author": "iceinvein",
|
|
6
6
|
"type": "prompt",
|
|
7
|
-
"tools": [
|
|
7
|
+
"tools": [
|
|
8
|
+
"claude",
|
|
9
|
+
"cursor",
|
|
10
|
+
"codex",
|
|
11
|
+
"gemini"
|
|
12
|
+
],
|
|
8
13
|
"files": {
|
|
9
14
|
"prompt": "SKILL.md"
|
|
10
15
|
},
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cover-letter-write
|
|
3
3
|
description: >
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
cover letter", "cover letter for <role>", or shares a resume and job description
|
|
12
|
-
together. Even if the user phrases it as "make me a cover letter" or "help me
|
|
13
|
-
apply to X", trigger this skill.
|
|
4
|
+
Use when the user asks to write, draft, or generate a cover letter ("write
|
|
5
|
+
cover letter", "cover letter for <role>", "make me a cover letter"), or
|
|
6
|
+
shares a resume and job description together wanting an application letter.
|
|
7
|
+
Generates a letter from resume + JD (each as PDF, DOCX, markdown/MDX, URL, or
|
|
8
|
+
pasted text), aligned to resume evidence and human-sounding, emitting
|
|
9
|
+
markdown, DOCX, and PDF. NOT for scoring an existing letter
|
|
10
|
+
(cover-letter-audit) or revising one (cover-letter-rewrite).
|
|
14
11
|
argument-hint: "--resume <file> --jd <file|url|text> [--length short|standard|long] [--out <dir>]"
|
|
15
12
|
---
|
|
16
13
|
|
|
@@ -122,7 +119,8 @@ For each gap (must-have with no resume evidence), decide:
|
|
|
122
119
|
Check `~/.config/cover-letter/active-persona`. If a persona is active and the
|
|
123
120
|
user did not override with `--tone`, load that persona JSON.
|
|
124
121
|
|
|
125
|
-
Without a persona, use these defaults
|
|
122
|
+
Without a persona, use these defaults (these mirror the "Mid / default"
|
|
123
|
+
values in cover-letter-persona's schema; that file is the source of truth):
|
|
126
124
|
|
|
127
125
|
| Setting | Default |
|
|
128
126
|
|---------|---------|
|
|
@@ -133,7 +131,7 @@ Without a persona, use these defaults:
|
|
|
133
131
|
| Passive voice cap | 10% |
|
|
134
132
|
| Readability | Flesch grade 8-10 |
|
|
135
133
|
|
|
136
|
-
If the JD signals a clear tone (a startup posting that uses "
|
|
134
|
+
If the JD signals a clear tone (a startup posting that uses "y'all" and
|
|
137
135
|
emoji wants casual; a law firm posting that uses "the Firm" and
|
|
138
136
|
"heretofore" wants formal), nudge the defaults one step toward that tone
|
|
139
137
|
unless a persona explicitly locks them.
|
|
@@ -187,8 +185,8 @@ Writing rules the draft must follow:
|
|
|
187
185
|
|
|
188
186
|
Before writing files, run the audit checks inline:
|
|
189
187
|
|
|
190
|
-
1. Word count within target band (default 250-400)
|
|
191
|
-
2. No AI phrases from the list in `cover-letter-audit` (50+ phrases)
|
|
188
|
+
1. Word count within the declared target band (default 250-400; `--length short|standard|long` = 180/300/420 targets — tell the audit which band applies)
|
|
189
|
+
2. No AI phrases from the list in `cover-letter-audit` (50+ phrases). If cover-letter-audit is not installed alongside this skill, at minimum reject the filler openers from Writing principle 6 and generic AI verbs ("leveraged", "spearheaded", "delve", "resonated")
|
|
192
190
|
3. Sentence length std dev >= 5 (burstiness proxy)
|
|
193
191
|
4. Passive voice <= persona cap (default 10%)
|
|
194
192
|
5. Every claim traceable to a resume bullet
|
|
@@ -201,14 +199,20 @@ revisions in one line.
|
|
|
201
199
|
|
|
202
200
|
### Step 7: Emit outputs
|
|
203
201
|
|
|
204
|
-
Write markdown first. Derive DOCX and PDF from it.
|
|
202
|
+
Write markdown first. Derive DOCX and PDF from it. Name the files with the
|
|
203
|
+
suite's slug convention: `<company>-<role>-<YYYY-MM-DD>.<ext>` (lowercase,
|
|
204
|
+
hyphenated), in `./cover-letters/` unless `--out` overrides.
|
|
205
205
|
|
|
206
206
|
```bash
|
|
207
|
-
# from
|
|
208
|
-
pandoc
|
|
209
|
-
pandoc
|
|
207
|
+
# from --out dir (default ./cover-letters/)
|
|
208
|
+
pandoc acme-platform-engineer-2026-07-18.md -o acme-platform-engineer-2026-07-18.docx
|
|
209
|
+
pandoc acme-platform-engineer-2026-07-18.md -o acme-platform-engineer-2026-07-18.pdf --pdf-engine=weasyprint
|
|
210
210
|
```
|
|
211
211
|
|
|
212
|
+
After emitting, write `~/.config/cover-letter/last-run.json` with
|
|
213
|
+
`{resume, jd, letter_path, persona, length_band, date}` so audit/rewrite can
|
|
214
|
+
resolve inputs when the user gives no paths.
|
|
215
|
+
|
|
212
216
|
PDF engine fallback order:
|
|
213
217
|
|
|
214
218
|
1. `weasyprint` (best typography out of the box)
|
|
@@ -222,8 +226,9 @@ install (`brew install weasyprint` on macOS) would unlock the PDF.
|
|
|
222
226
|
### Step 8: Report
|
|
223
227
|
|
|
224
228
|
One terse summary: file paths, self-audit score, any acknowledged gaps. If the
|
|
225
|
-
self-audit score is below
|
|
226
|
-
humanize` (or whichever
|
|
229
|
+
self-audit score is below 80 (under Strong per cover-letter-audit's rating
|
|
230
|
+
table), suggest `/cover-letter rewrite <file> --focus humanize` (or whichever
|
|
231
|
+
category scored lowest).
|
|
227
232
|
|
|
228
233
|
## Handling edge cases
|
|
229
234
|
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cover-letter-write",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Generates a cover letter from a resume and job description. Outputs markdown, DOCX, and PDF; enforces human prose, maps every claim to a resume bullet, and covers top JD requirements without keyword stuffing",
|
|
5
5
|
"author": "iceinvein",
|
|
6
6
|
"type": "prompt",
|
|
7
|
-
"tools": [
|
|
7
|
+
"tools": [
|
|
8
|
+
"claude",
|
|
9
|
+
"cursor",
|
|
10
|
+
"codex",
|
|
11
|
+
"gemini"
|
|
12
|
+
],
|
|
8
13
|
"files": {
|
|
9
14
|
"prompt": "SKILL.md"
|
|
10
15
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cqs-auditor
|
|
3
|
-
description: Use when functions both mutate state and return values, when calling a "getter" has hidden side effects, when it's unclear whether
|
|
3
|
+
description: Use when functions both mutate state and return values, when calling a "getter" has hidden side effects, when it's unclear whether a call is safe to retry or cache, or when tests must verify both a return value and a state change. Trigger on "is it safe to call this twice?", "why does reading this value change the system?", or when designing read/write boundaries. NOT for stack/queue pop(), iterator next(), or builder methods returning this.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# CQS Auditor
|
|
@@ -72,7 +72,7 @@ function logMetric(name: string, value: number): void {
|
|
|
72
72
|
- Unsafe to retry (second call will have different effect)
|
|
73
73
|
- Unsafe to cache (what changes between calls?)
|
|
74
74
|
- Testing must verify both aspects, making tests complex
|
|
75
|
-
- Examples: `getOrCreateUser(email)`, `
|
|
75
|
+
- Examples: `getOrCreateUser(email)`, `saveAndReturnId()`, `processAndReturn()` (note: `pop()` and `next()` are the accepted exceptions, see Guard Rails)
|
|
76
76
|
|
|
77
77
|
```typescript
|
|
78
78
|
// ❌ Mixed — mutation + return (violation)
|
|
@@ -101,14 +101,14 @@ Mark functions as violations if they:
|
|
|
101
101
|
|
|
102
102
|
- **Return a value AND mutate state** — the caller can't tell if they're calling for the return or the effect
|
|
103
103
|
- **Hide mutations in getters** — a function named `getValue()` shouldn't call `emit()` or `increment()` or `write to cache`
|
|
104
|
-
- **Return
|
|
104
|
+
- **Return domain data from a command** — a bare success/failure signal from a command is acceptable (see Guard Rails), but returning domain data means callers now depend on the mutation for reads
|
|
105
105
|
- **Accumulate side effects scattered across the call** — side effect happens in database, side effect in cache, side effect in event bus, all in one function
|
|
106
106
|
|
|
107
107
|
### 3. Classify Violation Severity
|
|
108
108
|
|
|
109
109
|
Not all violations are equally bad. Rank them:
|
|
110
110
|
|
|
111
|
-
**Concealed
|
|
111
|
+
**Concealed command** (most dangerous: a command disguised as a query)
|
|
112
112
|
- Function looks like a getter (named `get*()`, `fetch*()`, `compute*()`)
|
|
113
113
|
- Caller expects only a return value, no side effects
|
|
114
114
|
- But the function has hidden mutations (logs, caches, increments, notifies)
|
|
@@ -116,7 +116,7 @@ Not all violations are equally bad. Rank them:
|
|
|
116
116
|
- Example: `getNextSequenceId()` increments the database counter
|
|
117
117
|
|
|
118
118
|
```typescript
|
|
119
|
-
// ❌ Concealed
|
|
119
|
+
// ❌ Concealed command — looks like a getter, has a side effect
|
|
120
120
|
function getNextOrderId(): string {
|
|
121
121
|
const id = database.incrementAndFetch("order_seq"); // ← hidden mutation
|
|
122
122
|
return id;
|
|
@@ -170,20 +170,9 @@ function getUser(id: string): User {
|
|
|
170
170
|
|
|
171
171
|
For each violation, extract it into separate query and command functions:
|
|
172
172
|
|
|
173
|
-
#### Example 1: Concealed
|
|
173
|
+
#### Example 1: Concealed Command
|
|
174
174
|
|
|
175
|
-
**Before:**
|
|
176
|
-
```typescript
|
|
177
|
-
// ❌ Concealed query — looks safe, has hidden side effect
|
|
178
|
-
function getNextOrderId(): string {
|
|
179
|
-
const id = database.incrementAndFetch("order_seq");
|
|
180
|
-
return id;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// Caller thinks it's safe to cache:
|
|
184
|
-
const id = getNextOrderId(); // Returns "ORD001"
|
|
185
|
-
const id2 = getNextOrderId(); // Caller expects same? Nope, now "ORD002"
|
|
186
|
-
```
|
|
175
|
+
**Before:** the `getNextOrderId()` snippet from Section 3: a getter that silently increments the sequence.
|
|
187
176
|
|
|
188
177
|
**After:**
|
|
189
178
|
```typescript
|
|
@@ -204,24 +193,7 @@ const latest = getLatestOrderId(); // Just reads
|
|
|
204
193
|
|
|
205
194
|
#### Example 2: Bundled Command-Query
|
|
206
195
|
|
|
207
|
-
**Before:**
|
|
208
|
-
```typescript
|
|
209
|
-
// ⚠️ Mixed — returns user, also creates if missing
|
|
210
|
-
function getOrCreateUser(email: string): User {
|
|
211
|
-
let user = database.findByEmail(email);
|
|
212
|
-
if (!user) {
|
|
213
|
-
user = { email, id: generateId(), createdAt: now() };
|
|
214
|
-
database.insert(user);
|
|
215
|
-
eventBus.emit("user.created", { email });
|
|
216
|
-
}
|
|
217
|
-
return user;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// Caller:
|
|
221
|
-
const user = getOrCreateUser("alice@example.com");
|
|
222
|
-
// Is alice new or existing? Function doesn't say.
|
|
223
|
-
// Testing: must mock database.insert, eventBus.emit, and verify return.
|
|
224
|
-
```
|
|
196
|
+
**Before:** the `getOrCreateUser()` snippet from Section 3: find, create-if-missing, and return in one call. The caller can't tell whether the user is new or existing, and tests must mock the insert, the event emit, and verify the return.
|
|
225
197
|
|
|
226
198
|
**After:**
|
|
227
199
|
```typescript
|
|
@@ -246,12 +218,12 @@ if (!user) {
|
|
|
246
218
|
|
|
247
219
|
// Or with a single operation at a higher level:
|
|
248
220
|
function ensureUserExists(email: string): { user: User; isNew: boolean } {
|
|
249
|
-
|
|
250
|
-
if (
|
|
251
|
-
return { user, isNew: false };
|
|
221
|
+
const existing = getUserByEmail(email);
|
|
222
|
+
if (existing) {
|
|
223
|
+
return { user: existing, isNew: false };
|
|
252
224
|
}
|
|
253
|
-
|
|
254
|
-
return { user
|
|
225
|
+
createUser(email);
|
|
226
|
+
return { user: getUserByEmail(email)!, isNew: true };
|
|
255
227
|
}
|
|
256
228
|
```
|
|
257
229
|
|
|
@@ -264,19 +236,19 @@ For each violation found:
|
|
|
264
236
|
```
|
|
265
237
|
CQS: [function name]
|
|
266
238
|
Location: [file:line]
|
|
267
|
-
Type: [concealed
|
|
239
|
+
Type: [concealed command / bundled command-query / incidental side effect]
|
|
268
240
|
Mutation: [what state changes]
|
|
269
241
|
Return: [what it returns]
|
|
270
242
|
Risk: [caching implications / retry implications / testing complexity]
|
|
271
243
|
Fix: [specific split into query + command, or rename to be honest]
|
|
272
244
|
```
|
|
273
245
|
|
|
274
|
-
Example 1: Concealed
|
|
246
|
+
Example 1: Concealed Command
|
|
275
247
|
|
|
276
248
|
```
|
|
277
249
|
CQS: getNextOrderId
|
|
278
250
|
Location: src/orders/service.ts:42
|
|
279
|
-
Type: concealed
|
|
251
|
+
Type: concealed command
|
|
280
252
|
Mutation: database sequence "order_seq" incremented
|
|
281
253
|
Return: next sequence ID (string)
|
|
282
254
|
Risk: caller caches result thinking it's side-effect-free; second call gets different ID; caching breaks
|
|
@@ -292,7 +264,7 @@ CQS: getOrCreateUser
|
|
|
292
264
|
Mutation: database insert (if user doesn't exist), eventBus.emit("user.created")
|
|
293
265
|
Return: User object (existing or newly created)
|
|
294
266
|
Risk: testing must verify both database state and return value; retry semantics unclear (idempotent on read, not on create)
|
|
295
|
-
Fix: split into getUserByEmail(email): User | null (query) and createUser(email):
|
|
267
|
+
Fix: split into getUserByEmail(email): User | null (query) and createUser(email): void (command); caller composes them
|
|
296
268
|
```
|
|
297
269
|
|
|
298
270
|
Example 3: Incidental Side Effect
|
|
@@ -309,7 +281,7 @@ CQS: getUser
|
|
|
309
281
|
|
|
310
282
|
## Interaction Model
|
|
311
283
|
|
|
312
|
-
Decision engine. When reviewing code, the agent classifies functions as queries, commands, or mixed. It prioritizes concealed
|
|
284
|
+
Decision engine. When reviewing code, the agent classifies functions as queries, commands, or mixed. It prioritizes concealed commands (most dangerous), then bundled command-queries, then incidental side effects. For each violation, it recommends a specific split or honest renaming. It provides before/after examples showing how to separate the concerns. It doesn't refactor entire codebases — it focuses on public interfaces and functions that cross module boundaries.
|
|
313
285
|
|
|
314
286
|
## CQS at System Level: CQRS
|
|
315
287
|
|
|
@@ -350,7 +322,7 @@ CQRS is useful at architectural scale (multiple services, expensive infrastructu
|
|
|
350
322
|
| Splitting but sharing mutable state | Splitting `getOrCreateUser` into `getUser` + `createUser` is good. But if both functions mutate a shared cache, you've only moved the problem. Ensure each function's mutations are isolated. |
|
|
351
323
|
| Applying CQS to every private method | Focus on public boundaries. Private helpers can be more pragmatic. |
|
|
352
324
|
| Treating CQRS as a prerequisite for CQS | CQRS is an architectural pattern for large systems. CQS is a function-level principle. Apply CQS first; CQRS only if your system needs it. |
|
|
353
|
-
| Ignoring concealed
|
|
325
|
+
| Ignoring concealed commands | A function named `getBalance()` that increments a counter is a bug waiting to happen. Concealed commands are the most dangerous violation. |
|
|
354
326
|
| Returning void from commands that fail | If a command can fail, return an error code or throw an exception. Don't return `void` and hide the failure in a side effect (writing to a log that no one checks). |
|
|
355
327
|
|
|
356
328
|
## Cross-References
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cqs-auditor",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Meyer-inspired Command-Query Separation: classify functions as commands or queries, detect mixed violations, separate side effects from return values",
|
|
5
5
|
"author": "iceinvein",
|
|
6
6
|
"type": "prompt",
|
|
@@ -121,8 +121,8 @@ DEMETER: OrderProcessor.calculateShipping()
|
|
|
121
121
|
Chain: order.getShippingAddress().getCountry().getTaxRate()
|
|
122
122
|
Depth: 3 hops
|
|
123
123
|
Location: src/orders/processor.ts:142
|
|
124
|
-
Fix: Tell, Don't Ask —
|
|
125
|
-
Trade-off: Order
|
|
124
|
+
Fix: Tell, Don't Ask — move the shipping calculation into Order: order.calculateShipping() reaches its own address internally, so OrderProcessor stops traversing. (Not order.getShippingTaxRate() — a wrapper getter that traverses internally is the Hidden Traversal anti-pattern, see Guard Rails.)
|
|
125
|
+
Trade-off: Order takes on shipping logic and grows; if shipping rules vary by carrier or channel, prefer parameter narrowing (pass shippingCountry) instead
|
|
126
126
|
```
|
|
127
127
|
|
|
128
128
|
```
|
|
@@ -140,7 +140,7 @@ Decision engine. The agent analyzes method calls in code it writes or reviews, i
|
|
|
140
140
|
|
|
141
141
|
## The Law of Demeter Reference
|
|
142
142
|
|
|
143
|
-
|
|
143
|
+
The law is commonly glossed as informal rules like these (Lieberherr's formal statement is the permitted-receiver constraint below, not this list):
|
|
144
144
|
|
|
145
145
|
1. **Each unit should have only limited knowledge of other units:** Only units that are directly related to the current unit.
|
|
146
146
|
2. **Each unit should only talk to its friends:** Don't talk to strangers (objects you don't know directly).
|
|
@@ -148,7 +148,7 @@ Karl Lieberherr's formal statement of the Law of Demeter consists of five rules:
|
|
|
148
148
|
4. **Don't climb the object tree:** Don't chain method calls to navigate through intermediate objects.
|
|
149
149
|
5. **The recipient of a message should not be the result of another message sent to a different object:** Avoid a.b().c(); instead, call a.getC() or ask a to do the work.
|
|
150
150
|
|
|
151
|
-
|
|
151
|
+
Lieberherr's formal statement is this permitted-receiver constraint: from object O, you can only call methods on objects that are:
|
|
152
152
|
- O itself
|
|
153
153
|
- Formal parameters of the method
|
|
154
154
|
- Instance variables of O
|
|
@@ -159,7 +159,7 @@ The Law was formalized as a graph constraint: from object O, you can only call m
|
|
|
159
159
|
|
|
160
160
|
**Don't count dots mechanically.** Some multi-dot expressions are fine. `LocalDate.of(2024, 4, 11).atTime(10, 30)` is a fluent API designed for chaining. The law is about reducing *coupling and fragility*, not eliminating all dots.
|
|
161
161
|
|
|
162
|
-
**Aggregates and entities are exceptions.** If Customer owns Address (they're a single aggregate), then `customer.address.street` is fine—it's internal navigation, not a violation.
|
|
162
|
+
**Aggregates and entities are exceptions.** If Customer owns Address (they're a single aggregate), then `customer.address.street` is fine—it's internal navigation, not a violation. This is a deliberate relaxation of the strict law (which permits no calls on accessor results, even within an aggregate); this skill applies Demeter to module boundaries, not within cohesive entities.
|
|
163
163
|
|
|
164
164
|
**Don't wrap chains in facade methods.** Creating `order.getShippingCountry()` that internally chains `this.shippingAddress.country` doesn't solve the problem; it hides it. The fragility is still there.
|
|
165
165
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "demeter-enforcer",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Lieberherr-inspired Law of Demeter analysis: detect chain violations, parameter drilling, and hidden traversal; fix with tell-don't-ask or parameter narrowing",
|
|
5
5
|
"author": "iceinvein",
|
|
6
6
|
"type": "prompt",
|
|
@@ -18,7 +18,7 @@ A structural analysis framework based on Robert C. Martin's *Clean Architecture*
|
|
|
18
18
|
- "Why do I need a database to test this business rule?"
|
|
19
19
|
- "Why does changing the API response format require modifying domain entities?"
|
|
20
20
|
|
|
21
|
-
**Not for:** Dependencies *within* a single layer (
|
|
21
|
+
**Not for:** Dependencies *within* a single layer, and coupling *strength* between same-layer modules (both → `coupling-auditor`; a single module doing too many unrelated things → `cohesion-analyzer`). Framework-internal wiring (e.g., how Express middleware chains — that's the framework's design). Designing the port/adapter boundary itself (→ `port-adapter-auditor`; this skill checks which way dependencies point across layers).
|
|
22
22
|
|
|
23
23
|
## The Process
|
|
24
24
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dependency-direction-auditor",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Martin-inspired dependency direction analysis: trace imports across layers, classify violations by severity, recommend inversion",
|
|
5
5
|
"author": "iceinvein",
|
|
6
6
|
"type": "prompt",
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: design-review
|
|
3
|
-
description: Use when reviewing
|
|
3
|
+
description: Use when reviewing a design document, technical spec, architecture doc, API design, or database schema, especially one AI helped write. Trigger on "review my design", "does this design make sense", "scope this down", "feels like too much", "check if this holds together", or a design that reads as a feature list without a unifying idea. NOT for UI/visual review (rams-design-audit, gestalt-reviewer, cognitive-load-auditor) or an existing codebase (codebase-architecture).
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Design
|
|
6
|
+
# Design Review
|
|
7
|
+
|
|
8
|
+
A design-integrity review.
|
|
7
9
|
|
|
8
10
|
## Overview
|
|
9
11
|
|
|
@@ -30,6 +32,8 @@ You are a thoughtful, experienced design partner. Not an adversary — but you a
|
|
|
30
32
|
|
|
31
33
|
**IMPORTANT:** This is an interactive interview, not a checklist. Ask ONE question at a time. Listen to the answer. Follow up based on what was actually said, not what you planned to ask next.
|
|
32
34
|
|
|
35
|
+
**Non-interactive fallback:** if the user asks for a straight review without an interview ("just review it, don't quiz me"), or no human is in the loop, run the same phases against the document itself: answer each phase's questions from the text where possible, record the ones the document cannot answer as open risks, and emit the Synthesis. Say explicitly that the interview was skipped.
|
|
36
|
+
|
|
33
37
|
### Phase 1: The One-Sentence Test
|
|
34
38
|
|
|
35
39
|
Start here. Always.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "design-review",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Brooks-inspired design integrity review: tests conceptual integrity, constraint exploitation, removal discipline, and scope control",
|
|
5
5
|
"author": "iceinvein",
|
|
6
6
|
"type": "prompt",
|
|
@@ -33,7 +33,7 @@ Before writing any error handling, classify the error using Duffy's taxonomy:
|
|
|
33
33
|
- In production: Use process supervisors, crash recovery, and monitoring. The process restarts clean. This is safer than continuing with corrupted state.
|
|
34
34
|
|
|
35
35
|
**Recoverable error** (expected operational failure)
|
|
36
|
-
- Examples: network timeout, file not found, authentication rejected, rate limited, validation failure, external service unavailable
|
|
36
|
+
- Examples: network timeout, file not found, authentication rejected, rate limited, runtime validation failure of external data (precondition *design* belongs to `contract-enforcer`), external service unavailable
|
|
37
37
|
- Correct response: **Surface to the caller as a typed result.** The caller decides the recovery strategy — retry, fallback, surface to user, queue for later.
|
|
38
38
|
- Why: These aren't bugs — they're part of normal operation. The system should handle them explicitly, not treat them as exceptional. The caller has context for recovery that the failing function doesn't.
|
|
39
39
|
- Implementation: Use result types (`Result<T, E>`), error unions, or typed exceptions — never string messages or generic error classes.
|
|
@@ -157,7 +157,7 @@ Error *classification* is technical. Error *recovery strategy* is often a produc
|
|
|
157
157
|
|
|
158
158
|
## The Duffy Classification (Reference)
|
|
159
159
|
|
|
160
|
-
|
|
160
|
+
Adapted from Joe Duffy's Midori error model (Midori's split is two-way: bugs and fatal conditions both end in abandonment; the three-way taxonomy this skill uses separates fatal for practical triage):
|
|
161
161
|
|
|
162
162
|
1. **Bugs are not recoverable at runtime.** They indicate programmer mistakes. The correct response is to fail fast, gather diagnostics, and fix the code. Trying to recover from bugs leads to undefined behavior.
|
|
163
163
|
|
|
@@ -167,7 +167,7 @@ From Joe Duffy's Midori error model:
|
|
|
167
167
|
|
|
168
168
|
4. **The boundary between bug and recoverable depends on context.** A "file not found" error is recoverable if the user might have mistyped a path. It's a bug if the file is a configuration file that was validated at startup and should always exist.
|
|
169
169
|
|
|
170
|
-
5. **
|
|
170
|
+
5. **Recoverable errors are visible in the type system; bugs are never catchable.** In Midori, recoverable errors flow through declared, typed channels (results or checked/typed exceptions the caller must acknowledge), while bugs never throw anything catchable; they trigger abandonment (fail-fast process termination). Whatever your language, keep the two channels distinct: recoverable errors in signatures, bugs to fail-fast.
|
|
171
171
|
|
|
172
172
|
## Abrahams' Exception Safety Guarantees (Reference)
|
|
173
173
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "error-strategist",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Duffy & Abrahams-inspired error handling: classify errors (bug/recoverable/fatal), assign safety guarantees, design recovery boundaries",
|
|
5
5
|
"author": "iceinvein",
|
|
6
6
|
"type": "prompt",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: event-design-reviewer
|
|
3
|
-
description: Use when designing domain events, naming events, defining event payloads, or reviewing event-driven communication between bounded contexts
|
|
3
|
+
description: Use when designing domain events, naming events, defining event payloads, or reviewing event-driven communication between bounded contexts. Trigger on "what should this event be called?", "what data should the event carry?", "should this be an event or a command?", or events named after implementation details. NOT for UI event handlers (onClick), framework-level events, or channel topology and delivery guarantees (integration-pattern-auditor).
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Event Design Reviewer
|
|
@@ -155,7 +155,7 @@ Example:
|
|
|
155
155
|
EVENT DESIGN: UserUpdated
|
|
156
156
|
Type: event (correct — it's a fact about something that happened)
|
|
157
157
|
Domain test: FAIL — "updated" is meaningless. Updated how? A domain expert would ask "what changed?"
|
|
158
|
-
Naming: wrong —
|
|
158
|
+
Naming: wrong — past tense (good) but a generic CRUD name that doesn't describe the domain action
|
|
159
159
|
Payload: thin — only carries { userId }, forcing consumers to query user service
|
|
160
160
|
Envelope: missing correlationId and version field
|
|
161
161
|
Smells: CRUD naming, thin payload creates temporal coupling, no schema versioning
|
|
@@ -190,7 +190,7 @@ Event naming is a domain decision. The agent enforces the principles but the hum
|
|
|
190
190
|
|
|
191
191
|
**Vernon (2013):** Domain events are raised within the aggregate that owns the state change. The aggregate guarantees consistency; the event communicates the fact.
|
|
192
192
|
|
|
193
|
-
**Dahan (2009)
|
|
193
|
+
**Dahan:** Udi Dahan's domain-events pattern (2009) underpins the now-standard domain-event vs. integration-event split, later popularized by microservices guidance. Domain events are internal to a bounded context (can carry rich domain types). Integration events cross boundaries (must use a shared, stable schema).
|
|
194
194
|
|
|
195
195
|
| Concept | Domain Event | Integration Event |
|
|
196
196
|
|---------|-------------|-------------------|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "event-design-reviewer",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Evans/Vernon/Dahan-inspired event design: domain-meaningful naming, fat payloads, schema evolution, and the domain expert test",
|
|
5
5
|
"author": "iceinvein",
|
|
6
6
|
"type": "prompt",
|
|
@@ -41,17 +41,17 @@ Evaluate the change against the laws most relevant to the situation:
|
|
|
41
41
|
- Massive rewrites almost always fail because they fight the system's natural evolution rate.
|
|
42
42
|
- Incremental, well-directed changes succeed because they work with the system's grain.
|
|
43
43
|
|
|
44
|
-
**
|
|
44
|
+
**V. Conservation of Familiarity** — The rate of effective change is limited by the team's ability to absorb novelty. (Law IV, Conservation of Organizational Stability, is skipped here: it concerns process, not individual changes — see the Complete Reference below.)
|
|
45
45
|
- How much novelty does this change introduce? New patterns, new abstractions, new conventions?
|
|
46
46
|
- Will the team still recognize this area of the codebase after the change?
|
|
47
47
|
- Changes that exceed the team's absorption rate create unknown unknowns — the team no longer fully understands what they have.
|
|
48
48
|
|
|
49
|
-
**
|
|
49
|
+
**VI. Continuing Growth** — Functional content must continually increase to maintain user satisfaction.
|
|
50
50
|
- Is the system's *structure* keeping pace with its *functionality*?
|
|
51
51
|
- Growth without structural investment creates fragility: the system can do more but is harder to extend.
|
|
52
52
|
- Structural investment without growth is gold-plating: the architecture is beautiful but doesn't serve more users.
|
|
53
53
|
|
|
54
|
-
**
|
|
54
|
+
**VII. Declining Quality** — Unless rigorously adapted to account for environmental changes, system quality will appear to decline.
|
|
55
55
|
- Is the environment (dependencies, platforms, security requirements, user expectations) evolving in ways this code isn't keeping up with?
|
|
56
56
|
- A codebase that was excellent in 2020 may be declining in 2026 — not because it got worse, but because the world moved on.
|
|
57
57
|
|
|
@@ -61,6 +61,7 @@ Look at the area of code being changed:
|
|
|
61
61
|
|
|
62
62
|
**Churn analysis:**
|
|
63
63
|
- How often has this area been modified recently? High churn signals evolution pressure — this area is under active adaptation or struggling with accumulated debt.
|
|
64
|
+
- Measure it: `git log --since="6 months ago" --name-only --pretty=format: -- <path> | sort | uniq -c | sort -rn | head -20` ranks the hotspots; `git log --oneline --since="6 months ago" -- <path> | wc -l` counts commits touching the area. As a rough heuristic, a file in the repo's top decile of commit counts is high-churn.
|
|
64
65
|
- Is each successive change *smaller and easier* (debt being paid down) or *larger and harder* (debt compounding)?
|
|
65
66
|
- Are changes concentrated in a few files (hotspots) or spread evenly?
|
|
66
67
|
|