@codyswann/lisa 1.76.5 → 1.77.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/all/deletions.json +5 -1
- package/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +21 -1
- package/plugins/lisa/hooks/inject-rules.sh +22 -0
- package/{all/copy-overwrite/.claude → plugins/lisa}/rules/base-rules.md +4 -3
- package/{all/copy-overwrite/.claude → plugins/lisa}/rules/verification.md +10 -0
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +23 -1
- package/plugins/lisa-rails/hooks/inject-rules.sh +22 -0
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/hooks/lint-on-edit.sh +3 -1
- package/plugins/src/base/.claude-plugin/plugin.json +4 -0
- package/plugins/src/base/hooks/inject-rules.sh +22 -0
- package/plugins/src/base/rules/base-rules.md +89 -0
- package/plugins/src/base/rules/coding-philosophy.md +428 -0
- package/plugins/src/base/rules/intent-routing.md +126 -0
- package/plugins/src/base/rules/security-audit-handling.md +30 -0
- package/plugins/src/base/rules/verification.md +93 -0
- package/plugins/src/rails/.claude-plugin/plugin.json +6 -0
- package/plugins/src/rails/hooks/inject-rules.sh +22 -0
- package/plugins/src/rails/rules/rails-conventions.md +176 -0
- package/plugins/src/typescript/hooks/lint-on-edit.sh +3 -1
- package/rails/deletions.json +2 -1
- package/plugins/lisa/hooks/enforce-plan-rules.sh +0 -15
- package/plugins/lisa/hooks/sync-tasks.sh +0 -107
- package/plugins/src/base/hooks/enforce-plan-rules.sh +0 -15
- package/plugins/src/base/hooks/sync-tasks.sh +0 -107
- /package/{all/copy-overwrite/.claude → plugins/lisa}/rules/coding-philosophy.md +0 -0
- /package/{all/copy-overwrite/.claude → plugins/lisa}/rules/intent-routing.md +0 -0
- /package/{all/copy-overwrite/.claude → plugins/lisa}/rules/security-audit-handling.md +0 -0
- /package/{rails/copy-overwrite/.claude → plugins/lisa-rails}/rules/rails-conventions.md +0 -0
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
# Coding Philosophy
|
|
2
|
+
|
|
3
|
+
This rule enforces the core coding philosophy: **immutability**, **predictable structure**, **functional transformations**, **test-driven development**, **clean deletion**, and **simplicity**.
|
|
4
|
+
|
|
5
|
+
## Guiding Principles: YAGNI + SOLID + DRY + KISS
|
|
6
|
+
|
|
7
|
+
Follow these software engineering principles, **deferring to Occam's Razor/KISS whenever principles conflict**:
|
|
8
|
+
|
|
9
|
+
### KISS (Keep It Simple, Stupid) - The Tiebreaker
|
|
10
|
+
|
|
11
|
+
When principles conflict, **always choose the simpler solution**.
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
// KISS: Simple direct approach
|
|
15
|
+
const isAdmin = user.role === "admin";
|
|
16
|
+
|
|
17
|
+
// Over-engineered: Abstraction without value
|
|
18
|
+
const isAdmin = RoleChecker.getInstance().checkRole(user, RoleTypes.ADMIN);
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### YAGNI (You Ain't Gonna Need It)
|
|
22
|
+
|
|
23
|
+
Don't build features, abstractions, or flexibility you don't need **right now**.
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
// Correct: Solve today's problem
|
|
27
|
+
const formatDate = (date: Date) => date.toISOString().split("T")[0];
|
|
28
|
+
|
|
29
|
+
// Wrong: Building for hypothetical future needs
|
|
30
|
+
const formatDate = (date: Date, format?: string, locale?: string, timezone?: string) => {
|
|
31
|
+
// 50 lines handling cases that may never be used
|
|
32
|
+
};
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### DRY (Don't Repeat Yourself) - With KISS Constraint
|
|
36
|
+
|
|
37
|
+
Extract duplication only when:
|
|
38
|
+
1. The same logic appears **3+ times**
|
|
39
|
+
2. The abstraction is **simpler** than the duplication
|
|
40
|
+
3. The extracted code has a **clear single purpose**
|
|
41
|
+
|
|
42
|
+
### SOLID Principles - Applied Pragmatically
|
|
43
|
+
|
|
44
|
+
| Principle | Apply When | Skip When |
|
|
45
|
+
| ------------------------- | --------------------------------------------- | --------------------------------------- |
|
|
46
|
+
| **S**ingle Responsibility | Function does 2+ unrelated things | Splitting adds complexity |
|
|
47
|
+
| **O**pen/Closed | Extension points have clear use cases | No foreseeable extensions |
|
|
48
|
+
| **L**iskov Substitution | Using inheritance hierarchies | Using composition (preferred) |
|
|
49
|
+
| **I**nterface Segregation | Consumers need different subsets | Interface is already small |
|
|
50
|
+
| **D**ependency Inversion | Testing requires mocking external services | Direct dependency is simpler |
|
|
51
|
+
|
|
52
|
+
### Decision Framework
|
|
53
|
+
|
|
54
|
+
When unsure, ask in order:
|
|
55
|
+
1. **Do I need this now?** (YAGNI) - If no, don't build it
|
|
56
|
+
2. **Is there a simpler way?** (KISS) - Choose the simpler option
|
|
57
|
+
3. **Am I repeating myself 3+ times?** (DRY) - Extract if the abstraction is simpler
|
|
58
|
+
4. **Does this function do one thing?** (SOLID-SRP) - Split only if clearer
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Core Principles
|
|
63
|
+
|
|
64
|
+
### 1. Immutability First
|
|
65
|
+
|
|
66
|
+
Never mutate data. Always create new references.
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
// Correct - spread creates new object
|
|
70
|
+
const updated = { ...user, name: "New Name" };
|
|
71
|
+
|
|
72
|
+
// Incorrect - mutation
|
|
73
|
+
user.name = "New Name";
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 2. Function Structure Ordering
|
|
77
|
+
|
|
78
|
+
All functions, hooks, and components follow a strict ordering:
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
1. Variable definitions and derived state (const, useState, useMemo, useCallback)
|
|
82
|
+
2. Side effects (useEffect, function calls with no return value)
|
|
83
|
+
3. Return statement
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### 3. Functional Transformations
|
|
87
|
+
|
|
88
|
+
Use `map`, `filter`, `reduce` instead of imperative loops and mutations.
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
// Correct - functional transformation
|
|
92
|
+
const names = users.map(u => u.name);
|
|
93
|
+
|
|
94
|
+
// Incorrect - imperative mutation
|
|
95
|
+
const names = [];
|
|
96
|
+
users.forEach(u => names.push(u.name));
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 4. Test-Driven Development (TDD)
|
|
100
|
+
|
|
101
|
+
**Always write failing tests before implementation code.** This is mandatory, not optional.
|
|
102
|
+
|
|
103
|
+
```text
|
|
104
|
+
TDD Cycle:
|
|
105
|
+
1. RED: Write a failing test that defines expected behavior
|
|
106
|
+
2. GREEN: Write the minimum code to make the test pass
|
|
107
|
+
3. REFACTOR: Clean up while keeping tests green
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 5. Clean Deletion
|
|
111
|
+
|
|
112
|
+
**Delete old code completely.** No deprecation warnings, migration shims, or backward-compatibility layers unless explicitly requested.
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
// Correct: Remove the old code entirely
|
|
116
|
+
const calculateScore = (player: Player): number => player.stats.overall;
|
|
117
|
+
|
|
118
|
+
// Wrong: Keeping deprecated versions around
|
|
119
|
+
/** @deprecated Use calculateScore instead */
|
|
120
|
+
const getPlayerScore = (player: Player): number => calculateScore(player);
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**Clean deletion rules:**
|
|
124
|
+
- When replacing code, delete the old version completely
|
|
125
|
+
- Never create `V2`, `New`, or `Old` suffixed functions/variables
|
|
126
|
+
- Never add `@deprecated` comments - just remove the code
|
|
127
|
+
- Never write migration code unless explicitly asked
|
|
128
|
+
- Trust git history for recovery if needed
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Quick Reference
|
|
133
|
+
|
|
134
|
+
### Variable Declaration
|
|
135
|
+
|
|
136
|
+
| Pattern | Status | Example |
|
|
137
|
+
| ------- | --------- | ----------------------------- |
|
|
138
|
+
| `const` | Required | `const value = calculate();` |
|
|
139
|
+
| `let` | Forbidden | Use ternary or reduce instead |
|
|
140
|
+
| `var` | Forbidden | Never use |
|
|
141
|
+
|
|
142
|
+
### Array Operations
|
|
143
|
+
|
|
144
|
+
| Instead of | Use |
|
|
145
|
+
| ----------------------- | -------------------------------------------- |
|
|
146
|
+
| `arr.push(item)` | `[...arr, item]` |
|
|
147
|
+
| `arr.pop()` | `arr.slice(0, -1)` |
|
|
148
|
+
| `arr.splice(i, 1)` | `arr.filter((_, idx) => idx !== i)` |
|
|
149
|
+
| `arr.sort()` | `[...arr].sort()` |
|
|
150
|
+
| `arr[i] = value` | `arr.map((v, idx) => idx === i ? value : v)` |
|
|
151
|
+
| `forEach` with mutation | `reduce` or `map` |
|
|
152
|
+
|
|
153
|
+
### Object Operations
|
|
154
|
+
|
|
155
|
+
| Instead of | Use |
|
|
156
|
+
| ------------------------- | ----------------------------- |
|
|
157
|
+
| `obj.key = value` | `{ ...obj, key: value }` |
|
|
158
|
+
| `delete obj.key` | `({ key: _, ...rest } = obj)` |
|
|
159
|
+
| `Object.assign(obj, ...)` | `{ ...obj, ...other }` |
|
|
160
|
+
|
|
161
|
+
### Building Lookup Objects
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
// Correct - reduce with spread
|
|
165
|
+
const lookup = items.reduce(
|
|
166
|
+
(acc, item) => ({ ...acc, [item.id]: item }),
|
|
167
|
+
{} as Record<string, Item>
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
// Incorrect - forEach with Map.set
|
|
171
|
+
const lookup = new Map();
|
|
172
|
+
items.forEach(item => lookup.set(item.id, item));
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Conditional Values
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
// Correct - ternary expression
|
|
179
|
+
const status = isComplete ? "done" : "pending";
|
|
180
|
+
|
|
181
|
+
// Incorrect - let with reassignment
|
|
182
|
+
let status = "pending";
|
|
183
|
+
if (isComplete) {
|
|
184
|
+
status = "done";
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Hook Structure Example
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
export const usePlayerData = (playerId: string) => {
|
|
194
|
+
// 1. VARIABLES & STATE (first)
|
|
195
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
196
|
+
const { data } = useQuery(GetPlayerDocument, { variables: { playerId } });
|
|
197
|
+
|
|
198
|
+
const playerName = useMemo(() => data?.player?.name ?? "Unknown", [data]);
|
|
199
|
+
|
|
200
|
+
const handleRefresh = useCallback(() => {
|
|
201
|
+
refetch();
|
|
202
|
+
}, [refetch]);
|
|
203
|
+
|
|
204
|
+
// 2. SIDE EFFECTS (second)
|
|
205
|
+
useEffect(() => {
|
|
206
|
+
console.log("Player loaded:", playerName);
|
|
207
|
+
}, [playerName]);
|
|
208
|
+
|
|
209
|
+
// 3. RETURN (last)
|
|
210
|
+
return { playerName, isLoading, handleRefresh };
|
|
211
|
+
};
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Container Component Example
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
const PlayerCardContainer: React.FC<Props> = ({ playerId }) => {
|
|
218
|
+
// 1. VARIABLES & STATE
|
|
219
|
+
const { data, loading } = useQuery(GetPlayerDocument, { variables: { playerId } });
|
|
220
|
+
const { colors } = useTheme();
|
|
221
|
+
|
|
222
|
+
const formattedStats = useMemo(
|
|
223
|
+
() => data?.stats?.map(s => ({ ...s, display: formatStat(s) })) ?? [],
|
|
224
|
+
[data?.stats]
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
const handlePress = useCallback(() => {
|
|
228
|
+
router.push(`/players/${playerId}`);
|
|
229
|
+
}, [playerId]);
|
|
230
|
+
|
|
231
|
+
// 2. SIDE EFFECTS (none in this example)
|
|
232
|
+
|
|
233
|
+
// 3. RETURN
|
|
234
|
+
return (
|
|
235
|
+
<PlayerCardView
|
|
236
|
+
stats={formattedStats}
|
|
237
|
+
colors={colors}
|
|
238
|
+
loading={loading}
|
|
239
|
+
onPress={handlePress}
|
|
240
|
+
/>
|
|
241
|
+
);
|
|
242
|
+
};
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Utility Function Example
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
export const calculateTeamRankings = (
|
|
249
|
+
players: readonly Player[]
|
|
250
|
+
): readonly TeamRanking[] => {
|
|
251
|
+
// 1. VARIABLES & DERIVED VALUES
|
|
252
|
+
const validPlayers = players.filter(p => p.team && p.score != null);
|
|
253
|
+
|
|
254
|
+
const teamScores = validPlayers.reduce(
|
|
255
|
+
(acc, player) => ({
|
|
256
|
+
...acc,
|
|
257
|
+
[player.team.id]: {
|
|
258
|
+
teamId: player.team.id,
|
|
259
|
+
totalScore: (acc[player.team.id]?.totalScore ?? 0) + player.score,
|
|
260
|
+
count: (acc[player.team.id]?.count ?? 0) + 1,
|
|
261
|
+
},
|
|
262
|
+
}),
|
|
263
|
+
{} as Record<string, { teamId: string; totalScore: number; count: number }>
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
const rankings = Object.values(teamScores).map(t => ({
|
|
267
|
+
teamId: t.teamId,
|
|
268
|
+
avgScore: t.totalScore / t.count,
|
|
269
|
+
}));
|
|
270
|
+
|
|
271
|
+
const sorted = [...rankings].sort((a, b) => b.avgScore - a.avgScore);
|
|
272
|
+
|
|
273
|
+
// 2. NO SIDE EFFECTS IN PURE FUNCTIONS
|
|
274
|
+
|
|
275
|
+
// 3. RETURN
|
|
276
|
+
return sorted;
|
|
277
|
+
};
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
## Anti-Patterns to Avoid
|
|
283
|
+
|
|
284
|
+
### Never use `let` for conditional assignment
|
|
285
|
+
|
|
286
|
+
```typescript
|
|
287
|
+
// Wrong
|
|
288
|
+
let result;
|
|
289
|
+
if (condition) {
|
|
290
|
+
result = valueA;
|
|
291
|
+
} else {
|
|
292
|
+
result = valueB;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Correct
|
|
296
|
+
const result = condition ? valueA : valueB;
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Never mutate arrays
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
// Wrong
|
|
303
|
+
const items = [];
|
|
304
|
+
data.forEach(d => items.push(transform(d)));
|
|
305
|
+
|
|
306
|
+
// Correct
|
|
307
|
+
const items = data.map(d => transform(d));
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Never use Map when Record suffices
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
// Wrong
|
|
314
|
+
const lookup = new Map<string, User>();
|
|
315
|
+
users.forEach(u => lookup.set(u.id, u));
|
|
316
|
+
const user = lookup.get(userId);
|
|
317
|
+
|
|
318
|
+
// Correct
|
|
319
|
+
const lookup = users.reduce(
|
|
320
|
+
(acc, u) => ({ ...acc, [u.id]: u }),
|
|
321
|
+
{} as Record<string, User>
|
|
322
|
+
);
|
|
323
|
+
const user = lookup[userId];
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Never sort in place
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
// Wrong - mutates original
|
|
330
|
+
const sorted = items.sort((a, b) => a.value - b.value);
|
|
331
|
+
|
|
332
|
+
// Correct - creates new array
|
|
333
|
+
const sorted = [...items].sort((a, b) => a.value - b.value);
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### Never place useEffect before variable definitions
|
|
337
|
+
|
|
338
|
+
```typescript
|
|
339
|
+
// Wrong
|
|
340
|
+
useEffect(() => {
|
|
341
|
+
/* ... */
|
|
342
|
+
}, [value]);
|
|
343
|
+
const value = useMemo(() => calculate(), [dep]);
|
|
344
|
+
|
|
345
|
+
// Correct
|
|
346
|
+
const value = useMemo(() => calculate(), [dep]);
|
|
347
|
+
useEffect(() => {
|
|
348
|
+
/* ... */
|
|
349
|
+
}, [value]);
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## Immutable Patterns Reference
|
|
355
|
+
|
|
356
|
+
### Building Lookup Objects with Reduce
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
const colorMap =
|
|
360
|
+
edges?.reduce(
|
|
361
|
+
(acc, edge) => (edge.color ? { ...acc, [edge.tagId]: edge.color } : acc),
|
|
362
|
+
{} as Record<string, string>
|
|
363
|
+
) ?? {};
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Accumulating Multiple Properties
|
|
367
|
+
|
|
368
|
+
```typescript
|
|
369
|
+
const teamGprAccumulator = validPlayers.reduce(
|
|
370
|
+
(acc, player) => {
|
|
371
|
+
const teamId = player.team?.id;
|
|
372
|
+
if (!teamId) return acc;
|
|
373
|
+
|
|
374
|
+
const existing = acc[teamId];
|
|
375
|
+
return {
|
|
376
|
+
...acc,
|
|
377
|
+
[teamId]: {
|
|
378
|
+
teamId,
|
|
379
|
+
teamName: player.team.name,
|
|
380
|
+
gprSum: (existing?.gprSum ?? 0) + player.gpr,
|
|
381
|
+
playerCount: (existing?.playerCount ?? 0) + 1,
|
|
382
|
+
},
|
|
383
|
+
};
|
|
384
|
+
},
|
|
385
|
+
{} as Record<string, { teamId: string; teamName: string; gprSum: number; playerCount: number }>
|
|
386
|
+
);
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Nested Object Updates
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
const updated = {
|
|
393
|
+
...state,
|
|
394
|
+
user: {
|
|
395
|
+
...state.user,
|
|
396
|
+
profile: {
|
|
397
|
+
...state.user.profile,
|
|
398
|
+
avatar: newAvatar,
|
|
399
|
+
},
|
|
400
|
+
},
|
|
401
|
+
};
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### Conditional Property Addition
|
|
405
|
+
|
|
406
|
+
```typescript
|
|
407
|
+
const result = {
|
|
408
|
+
...baseObj,
|
|
409
|
+
...(condition && { optionalProp: value }),
|
|
410
|
+
};
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### Ternary Chain for Multiple Conditions
|
|
414
|
+
|
|
415
|
+
```typescript
|
|
416
|
+
const priority = score > 90 ? "high" : score > 70 ? "medium" : "low";
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### Readonly Types for Function Parameters
|
|
420
|
+
|
|
421
|
+
```typescript
|
|
422
|
+
export const calculateTeamGprRank = (
|
|
423
|
+
leaguePlayers: readonly (PlayerWithScores | null | undefined)[],
|
|
424
|
+
myTeamId: string | null | undefined
|
|
425
|
+
): number | null => {
|
|
426
|
+
// ...
|
|
427
|
+
};
|
|
428
|
+
```
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Intent Routing
|
|
2
|
+
|
|
3
|
+
Classify the user's request and execute the matching flow. Each flow is a sequence of agents. Sub-flows can be invoked by any flow.
|
|
4
|
+
|
|
5
|
+
## Flows
|
|
6
|
+
|
|
7
|
+
### Fix
|
|
8
|
+
When: Bug reports, broken behavior, error messages, JIRA bug tickets.
|
|
9
|
+
|
|
10
|
+
Sequence:
|
|
11
|
+
1. `git-history-analyzer` — understand why affected code exists, find related past fixes/reverts
|
|
12
|
+
2. `debug-specialist` — reproduce the bug, prove root cause with evidence
|
|
13
|
+
3. `architecture-specialist` — assess fix risk, identify files to change, check for ripple effects
|
|
14
|
+
4. `test-specialist` — design regression test strategy
|
|
15
|
+
5. `bug-fixer` — implement fix via TDD (reproduction becomes failing test)
|
|
16
|
+
6. **Verify sub-flow**
|
|
17
|
+
7. **Ship sub-flow**
|
|
18
|
+
8. `learner` — capture discoveries for future sessions
|
|
19
|
+
|
|
20
|
+
### Build
|
|
21
|
+
When: New features, stories, tasks, JIRA story/task tickets.
|
|
22
|
+
|
|
23
|
+
Sequence:
|
|
24
|
+
1. `product-specialist` — define acceptance criteria, user flows, error states
|
|
25
|
+
2. `architecture-specialist` — research codebase, design approach, map dependencies
|
|
26
|
+
3. `test-specialist` — design test strategy (coverage, edge cases, TDD sequence)
|
|
27
|
+
4. `builder` — implement via TDD (acceptance criteria become tests)
|
|
28
|
+
5. **Verify sub-flow**
|
|
29
|
+
6. **Review sub-flow**
|
|
30
|
+
7. **Ship sub-flow**
|
|
31
|
+
8. `learner` — capture discoveries
|
|
32
|
+
|
|
33
|
+
### Investigate
|
|
34
|
+
When: "Why is this happening?", triage requests, JIRA spike tickets.
|
|
35
|
+
|
|
36
|
+
Sequence:
|
|
37
|
+
1. `git-history-analyzer` — understand code evolution, find related changes
|
|
38
|
+
2. `debug-specialist` — reproduce, trace execution, prove root cause
|
|
39
|
+
3. `ops-specialist` — check logs, errors, health (if runtime issue)
|
|
40
|
+
4. Report findings with evidence, recommend next action (Fix, Build, or escalate)
|
|
41
|
+
|
|
42
|
+
### Plan
|
|
43
|
+
When: "Break this down", epic planning, large scope work, JIRA epic tickets.
|
|
44
|
+
|
|
45
|
+
Sequence:
|
|
46
|
+
1. `product-specialist` — define acceptance criteria for the whole scope
|
|
47
|
+
2. `architecture-specialist` — understand scope, map dependencies, identify cross-cutting concerns
|
|
48
|
+
3. Break down into ordered tasks, each with: acceptance criteria, verification type, dependencies
|
|
49
|
+
|
|
50
|
+
### Verify
|
|
51
|
+
When: Pre-ship quality gate. Used as a sub-flow by Fix and Build.
|
|
52
|
+
|
|
53
|
+
Sequence:
|
|
54
|
+
1. Run full test suite — all tests must pass before proceeding
|
|
55
|
+
2. Run quality checks — lint, typecheck, and format
|
|
56
|
+
3. `verification-specialist` — verify acceptance criteria are met empirically
|
|
57
|
+
|
|
58
|
+
### Ship
|
|
59
|
+
When: Code is ready to deploy. Used as a sub-flow by Fix, Build, and Improve.
|
|
60
|
+
|
|
61
|
+
Sequence:
|
|
62
|
+
1. Commit — atomic conventional commits via `git-commit` skill
|
|
63
|
+
2. PR — create/update pull request via `git-submit-pr` skill
|
|
64
|
+
3. **Review sub-flow** (if not already done)
|
|
65
|
+
4. PR Watch Loop (repeat until mergeable):
|
|
66
|
+
- If status checks fail → fix and push
|
|
67
|
+
- If merge conflicts → resolve and push
|
|
68
|
+
- If bot review feedback (CodeRabbit, etc.):
|
|
69
|
+
- Valid feedback → implement fix, push, resolve comment
|
|
70
|
+
- Invalid feedback → reply explaining why, resolve comment
|
|
71
|
+
- Repeat until all checks pass and all comments are resolved
|
|
72
|
+
5. Merge the PR
|
|
73
|
+
6. `ops-specialist` — deploy to target environment
|
|
74
|
+
7. `verification-specialist` — post-deploy health check and smoke test
|
|
75
|
+
8. `ops-specialist` — monitor for errors in first minutes
|
|
76
|
+
|
|
77
|
+
### Review
|
|
78
|
+
When: Code review requests, PR review, quality assessment. Used as a sub-flow by Build.
|
|
79
|
+
|
|
80
|
+
Sequence:
|
|
81
|
+
1. Run in parallel: `quality-specialist`, `security-specialist`, `performance-specialist`
|
|
82
|
+
2. `product-specialist` — verify acceptance criteria are met empirically
|
|
83
|
+
3. `test-specialist` — verify test coverage and quality
|
|
84
|
+
4. Consolidate findings, ranked by severity
|
|
85
|
+
|
|
86
|
+
### Improve
|
|
87
|
+
When: Refactoring, optimization, coverage improvement, complexity reduction.
|
|
88
|
+
|
|
89
|
+
Sequence:
|
|
90
|
+
1. `architecture-specialist` — identify target, measure baseline, plan approach
|
|
91
|
+
2. `test-specialist` — ensure existing test coverage before refactoring (safety net)
|
|
92
|
+
3. `builder` — implement improvements via TDD
|
|
93
|
+
4. `verification-specialist` — measure again, prove improvement
|
|
94
|
+
5. **Ship sub-flow**
|
|
95
|
+
6. `learner` — capture discoveries
|
|
96
|
+
|
|
97
|
+
#### Improve: Test Quality
|
|
98
|
+
When: "Improve tests", "strengthen test suite", "fix weak tests", test quality improvement.
|
|
99
|
+
|
|
100
|
+
Sequence:
|
|
101
|
+
1. `test-specialist` — scan tests, identify weak/brittle tests, rank by improvement impact
|
|
102
|
+
2. `builder` — implement test improvements
|
|
103
|
+
3. **Verify sub-flow**
|
|
104
|
+
4. **Ship sub-flow**
|
|
105
|
+
5. `learner` — capture discoveries
|
|
106
|
+
|
|
107
|
+
### Monitor
|
|
108
|
+
When: "Check the logs", "Any errors?", health checks, production monitoring.
|
|
109
|
+
|
|
110
|
+
Sequence:
|
|
111
|
+
1. `ops-specialist` — health checks, log inspection, error monitoring, performance analysis
|
|
112
|
+
2. Report findings, escalate if action needed
|
|
113
|
+
|
|
114
|
+
## JIRA Entry Point
|
|
115
|
+
|
|
116
|
+
When the request references a JIRA ticket (ticket ID like PROJ-123 or a JIRA URL):
|
|
117
|
+
|
|
118
|
+
1. Hand off to `jira-agent`
|
|
119
|
+
2. `jira-agent` reads the ticket, validates structural quality, and runs analytical triage
|
|
120
|
+
3. If triage finds unresolved ambiguities, `jira-agent` posts findings and STOPS — no work begins
|
|
121
|
+
4. `jira-agent` determines intent and delegates to the appropriate flow above
|
|
122
|
+
5. `jira-agent` syncs progress at milestones and posts evidence at completion
|
|
123
|
+
|
|
124
|
+
## Sub-flow Usage
|
|
125
|
+
|
|
126
|
+
Flows reference sub-flows by name. When a flow says "Ship sub-flow", execute the full Ship sequence. When it says "Review sub-flow", execute the full Review sequence. Sub-flows can be nested (e.g., Ship includes Review).
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Security Audit Handling
|
|
2
|
+
|
|
3
|
+
If `git push` fails because the pre-push hook reports security vulnerabilities, follow these steps. Never use `--no-verify` to bypass the security audit.
|
|
4
|
+
|
|
5
|
+
## Node.js Projects (GHSA advisories)
|
|
6
|
+
|
|
7
|
+
1. Note the GHSA ID(s), affected package(s), and advisory URL from the error output
|
|
8
|
+
2. Check the advisory URL to determine if a patched version of the vulnerable package exists
|
|
9
|
+
3. If a patched version exists: add a resolution/override in package.json to force the patched version (add to both `resolutions` and `overrides` sections), then run the package manager install command to regenerate the lockfile, commit the changes, and retry the push
|
|
10
|
+
4. If no patched version exists and the vulnerability is safe for this project (e.g., transitive dependency with no untrusted input, devDeps only, or build tool only): add an exclusion entry to `audit.ignore.local.json` with the format `{"id": "GHSA-xxx", "package": "pkg-name", "reason": "why this is safe for this project"}`, then commit and retry the push
|
|
11
|
+
|
|
12
|
+
### Critical: Override the vulnerable package, not its parent
|
|
13
|
+
|
|
14
|
+
When the audit output shows a dependency chain like `@expo/cli › glob › minimatch`, the vulnerable package is **minimatch**, not glob. Always override the **leaf package** that has the actual vulnerability.
|
|
15
|
+
|
|
16
|
+
**Never override a parent package to force a lower major version** — other packages in the project may depend on a newer major version, and a resolution/override forces ALL installations to the specified version. For example, overriding `glob` to `^8.1.0` will break `@expo/cli` which requires `glob@^13.0.0`, causing `expo prebuild` to fail with `files.map is not a function`.
|
|
17
|
+
|
|
18
|
+
Before adding a resolution/override, verify:
|
|
19
|
+
- You are targeting the **actually vulnerable package**, not a parent in the chain
|
|
20
|
+
- The override version is **compatible with all dependents** (check with `bun why <package>` or `npm ls <package>`)
|
|
21
|
+
- The override does not **downgrade** a package across a major version boundary that other dependencies require
|
|
22
|
+
|
|
23
|
+
## Rails Projects (bundler-audit)
|
|
24
|
+
|
|
25
|
+
1. Note the advisory ID, affected gem, and advisory URL from the error output
|
|
26
|
+
2. Check if a patched version of the gem exists
|
|
27
|
+
3. If a patched version exists:
|
|
28
|
+
- If the gem is a **direct dependency** (listed in Gemfile): update its version constraint in Gemfile, run `bundle update <gem>`, commit the changes, and retry the push
|
|
29
|
+
- If the gem is a **transitive dependency** (not in Gemfile, only in Gemfile.lock): run `bundle update <gem>` to pull the patched version without changing the Gemfile, commit the lockfile change, and retry the push
|
|
30
|
+
4. If no patched version exists and the vulnerability is safe for this project: document the exception and retry the push
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Empirical Verification
|
|
2
|
+
|
|
3
|
+
This repository supports AI agents as first-class contributors.
|
|
4
|
+
|
|
5
|
+
This file is the operational contract that defines how agents plan work, execute changes, verify outcomes, and escalate when blocked.
|
|
6
|
+
|
|
7
|
+
If anything here conflicts with other repo docs, treat this file as authoritative for agent behavior.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Core Principle
|
|
12
|
+
|
|
13
|
+
Agents must close the loop between code changes and observable system behavior.
|
|
14
|
+
|
|
15
|
+
No agent may claim success without evidence from runtime verification.
|
|
16
|
+
|
|
17
|
+
Never assume something works because the code "looks correct." Run a command, observe the output, compare to expected result.
|
|
18
|
+
|
|
19
|
+
**Verification is not linting, typechecking, or testing.** Those are quality checks. Verification is using the resulting software the way a user would — interacting with the UI, calling the API, running the CLI command, observing the behavior. Tests pass in isolation; verification proves the system works as a whole. Passing tests, linting, and typechecking does not constitute verification.
|
|
20
|
+
|
|
21
|
+
Verification is mandatory. Never skip it, defer it, or claim it was unnecessary. Every task must be verified before claiming completion.
|
|
22
|
+
|
|
23
|
+
Before starting implementation, state your verification plan — how you will use the resulting software to prove it works. Do not begin implementation until the plan is confirmed.
|
|
24
|
+
|
|
25
|
+
After verifying a change empirically, encode that verification as automated tests. The manual proof that something works should become a repeatable regression test that catches future regressions. Every verification should answer: "How do I turn this into a test?"
|
|
26
|
+
|
|
27
|
+
Every pull request must include step-by-step instructions for reviewers to independently replicate the verification. These are not test commands — they are the exact steps a human would follow to use the software and confirm the change works. If a reviewer cannot reproduce your verification from the PR description alone, the PR is incomplete.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Roles
|
|
32
|
+
|
|
33
|
+
### Builder Agent
|
|
34
|
+
|
|
35
|
+
Implements the change in code and infrastructure.
|
|
36
|
+
|
|
37
|
+
### Verifier Agent
|
|
38
|
+
|
|
39
|
+
Acts as the end user (human user, API client, operator, attacker, or system) and produces proof artifacts.
|
|
40
|
+
|
|
41
|
+
Verifier Agent must be independent from Builder Agent when possible.
|
|
42
|
+
|
|
43
|
+
### Human Overseer
|
|
44
|
+
|
|
45
|
+
Approves risky operations, security boundary crossings, and any work the agents cannot fully verify.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Verification Levels
|
|
50
|
+
|
|
51
|
+
Agents must label every task outcome with exactly one of these:
|
|
52
|
+
|
|
53
|
+
- **FULLY VERIFIED**: Verified in the target environment with end-user simulation and captured artifacts.
|
|
54
|
+
- **PARTIALLY VERIFIED**: Verified in a lower-fidelity environment or with incomplete surfaces, with explicit gaps documented.
|
|
55
|
+
- **UNVERIFIED**: Verification blocked, human action required, no claim of correctness permitted.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Verification Types
|
|
60
|
+
|
|
61
|
+
Every change requires one or more verification types. Classify the change first, then verify each applicable type.
|
|
62
|
+
|
|
63
|
+
### Always Required
|
|
64
|
+
|
|
65
|
+
| Type | What to prove | Acceptable proof |
|
|
66
|
+
|------|---------------|------------------|
|
|
67
|
+
| **Test** | Unit and integration tests pass for all changed code paths | Test runner output showing all relevant tests green with no skips |
|
|
68
|
+
| **Type Safety** | No type errors introduced by the change | Type checker exits clean on the full project |
|
|
69
|
+
| **Lint/Format** | Code meets project style and quality rules | Linter and formatter exit clean on changed files |
|
|
70
|
+
|
|
71
|
+
### Conditional
|
|
72
|
+
|
|
73
|
+
| Type | When it applies | What to prove | Acceptable proof |
|
|
74
|
+
|------|----------------|---------------|------------------|
|
|
75
|
+
| **UI** | Change affects user-visible interface | Feature renders correctly and interactions work as expected | Automated session recording or screenshots showing correct states; for cross-platform changes, evidence from each platform or explicit gap documentation |
|
|
76
|
+
| **API** | Change affects HTTP/GraphQL/RPC endpoints | Endpoint returns correct status, headers, and body for success and error cases | Request/response capture showing schema and data match expectations |
|
|
77
|
+
| **Database** | Change involves schema, migrations, or queries | Schema is correct after migration; data integrity is maintained | Query output showing expected schema and data state |
|
|
78
|
+
| **Auth** | Change affects authentication or authorization | Correct access for allowed roles; rejection for disallowed roles | Request traces showing enforcement across at least two roles |
|
|
79
|
+
| **Security** | Change involves input handling, secrets, or attack surfaces | Exploit is prevented; safe handling is enforced | Reproduction of attack pre-fix failing post-fix, or evidence of sanitization/rejection |
|
|
80
|
+
| **Performance** | Change claims performance improvement or affects hot paths | Measurable improvement in latency, throughput, or resource usage | Before/after benchmarks with methodology documented |
|
|
81
|
+
| **Infrastructure** | Change affects deployment, scaling, or cloud resources | Resources are created/updated correctly; system is stable | Infrastructure state output showing expected configuration; stability metrics during transition |
|
|
82
|
+
| **Observability** | Change affects logging, metrics, or tracing | Events are emitted with correct structure and correlation | Log or metric output showing expected entries with correlation IDs |
|
|
83
|
+
| **Background Jobs** | Change affects queues, workers, or scheduled tasks | Job enqueues, processes, and reaches terminal state correctly | Evidence of enqueue, processing, and final state; idempotency check when relevant |
|
|
84
|
+
| **Configuration** | Change affects config files, feature flags, or environment variables | Configuration is loaded and applied correctly at runtime | Application output showing the configuration taking effect |
|
|
85
|
+
| **Documentation** | Change affects documentation content or structure | Documentation is accurate and matches implementation | Content inspection confirming accuracy against actual behavior |
|
|
86
|
+
| **Cache** | Change affects caching behavior or invalidation | Cache hits, misses, and invalidation work as expected | Evidence of cache behavior (hit/miss logs, TTL verification, key inspection) |
|
|
87
|
+
| **Email/Notification** | Change affects outbound messages | Message is sent with correct content to correct recipient | Captured message content or delivery log showing expected output |
|
|
88
|
+
| **PR** | Shipping code (always applies when opening a PR) | PR includes goal summary, verification level, proof artifacts, and reproduction steps | PR description containing all required sections |
|
|
89
|
+
| **Deploy** | Shipping code to an environment | Deployment completes and application is healthy in the target environment | Deployment output and health check evidence from the target environment |
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
For the full verification lifecycle (classify, check tooling, plan, execute, loop), surfaces, escalation protocol, and proof artifact requirements, see the `verification-lifecycle` skill loaded by the `verification-specialist` agent.
|
|
@@ -4,6 +4,12 @@
|
|
|
4
4
|
"description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
|
|
5
5
|
"author": { "name": "Cody Swann" },
|
|
6
6
|
"hooks": {
|
|
7
|
+
"SessionStart": [
|
|
8
|
+
{ "matcher": "", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/inject-rules.sh" }] }
|
|
9
|
+
],
|
|
10
|
+
"SubagentStart": [
|
|
11
|
+
{ "matcher": "", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/inject-rules.sh" }] }
|
|
12
|
+
],
|
|
7
13
|
"PostToolUse": [
|
|
8
14
|
{
|
|
9
15
|
"matcher": "Write|Edit",
|