opencode-agile-agent 1.0.1 → 1.0.2
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 +61 -71
- package/bin/cli.js +344 -434
- package/bin/sync-templates.js +45 -0
- package/bin/validate-templates.js +44 -6
- package/package.json +2 -1
- package/templates/.opencode/ARCHITECTURE.md +82 -368
- package/templates/.opencode/README.md +110 -391
- package/templates/.opencode/agents/api-designer.md +45 -312
- package/templates/.opencode/agents/backend-specialist.md +46 -214
- package/templates/.opencode/agents/code-archaeologist.md +45 -260
- package/templates/.opencode/agents/context-gatherer.md +51 -0
- package/templates/.opencode/agents/database-architect.md +45 -212
- package/templates/.opencode/agents/debugger.md +45 -302
- package/templates/.opencode/agents/developer.md +45 -523
- package/templates/.opencode/agents/devops-engineer.md +45 -253
- package/templates/.opencode/agents/documentation-writer.md +45 -247
- package/templates/.opencode/agents/explorer-agent.md +49 -233
- package/templates/.opencode/agents/feature-lead.md +62 -302
- package/templates/.opencode/agents/frontend-specialist.md +46 -186
- package/templates/.opencode/agents/game-developer.md +45 -391
- package/templates/.opencode/agents/mobile-developer.md +45 -264
- package/templates/.opencode/agents/orchestrator.md +48 -463
- package/templates/.opencode/agents/penetration-tester.md +44 -254
- package/templates/.opencode/agents/performance-optimizer.md +45 -292
- package/templates/.opencode/agents/pr-reviewer.md +45 -468
- package/templates/.opencode/agents/product-manager.md +46 -225
- package/templates/.opencode/agents/project-planner.md +45 -248
- package/templates/.opencode/agents/qa-automation-engineer.md +45 -275
- package/templates/.opencode/agents/security-auditor.md +44 -258
- package/templates/.opencode/agents/seo-specialist.md +45 -266
- package/templates/.opencode/agents/system-analyst.md +48 -428
- package/templates/.opencode/agents/test-engineer.md +45 -229
- package/templates/.opencode/archive/README.md +24 -0
- package/templates/.opencode/commands/brainstorm.md +10 -0
- package/templates/.opencode/commands/create.md +11 -0
- package/templates/.opencode/commands/debug.md +10 -0
- package/templates/.opencode/commands/plan.md +9 -0
- package/templates/.opencode/commands/review.md +11 -0
- package/templates/.opencode/commands/status.md +9 -0
- package/templates/.opencode/commands/test.md +10 -0
- package/templates/.opencode/skills/api-patterns/SKILL.md +25 -149
- package/templates/.opencode/skills/brainstorming/SKILL.md +26 -242
- package/templates/.opencode/skills/clean-code/SKILL.md +27 -339
- package/templates/.opencode/skills/code-philosophy/SKILL.md +27 -499
- package/templates/.opencode/skills/context-archive/SKILL.md +47 -0
- package/templates/.opencode/skills/context-gathering/SKILL.md +51 -0
- package/templates/.opencode/skills/frontend-design/SKILL.md +26 -224
- package/templates/.opencode/skills/intelligent-routing/SKILL.md +25 -182
- package/templates/.opencode/skills/parallel-agents/SKILL.md +25 -261
- package/templates/.opencode/skills/plan-writing/SKILL.md +28 -238
- package/templates/.opencode/skills/redteam-validation/SKILL.md +33 -0
- package/templates/.opencode/skills/security-gate/SKILL.md +33 -0
- package/templates/.opencode/skills/systematic-debugging/SKILL.md +25 -197
- package/templates/.opencode/skills/testing-patterns/SKILL.md +25 -238
- package/templates/AGENTS.template.md +300 -426
- package/templates/.opencode/agents/product-owner.md +0 -264
- package/templates/.opencode/workflows/brainstorm.md +0 -110
- package/templates/.opencode/workflows/create.md +0 -108
- package/templates/.opencode/workflows/debug.md +0 -128
- package/templates/.opencode/workflows/deploy.md +0 -160
- package/templates/.opencode/workflows/enhance.md +0 -253
- package/templates/.opencode/workflows/orchestrate.md +0 -130
- package/templates/.opencode/workflows/plan.md +0 -163
- package/templates/.opencode/workflows/review.md +0 -135
- package/templates/.opencode/workflows/status.md +0 -102
- package/templates/.opencode/workflows/test.md +0 -146
|
@@ -1,512 +1,40 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: code-philosophy
|
|
3
|
-
description:
|
|
3
|
+
description: Reason about data flow, invariants, failure posture, and ownership before changing code.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Code Philosophy
|
|
6
|
+
# Code Philosophy
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
## Philosophy
|
|
9
|
+
Good code guides data through deliberate boundaries and makes illegal states hard to reach.
|
|
9
10
|
|
|
10
|
-
##
|
|
11
|
+
## Use When
|
|
12
|
+
- You are reviewing or refactoring logic and state flow.
|
|
13
|
+
- The design has unclear ownership, failure modes, or boundary handling.
|
|
14
|
+
- The question is about how the system should think, not just how it should look.
|
|
11
15
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
## Core Moves
|
|
17
|
+
- Gate untrusted data at the edge.
|
|
18
|
+
- Trust parsed state inside a module or layer.
|
|
19
|
+
- Make side effects explicit and owned.
|
|
20
|
+
- Prefer simple invariants over repeated defensive checks.
|
|
21
|
+
- Expose impossible states quickly and clearly.
|
|
15
22
|
|
|
16
|
-
|
|
23
|
+
## Default Moves
|
|
24
|
+
- Validate input once and reuse the trusted result.
|
|
25
|
+
- Use explicit state transitions instead of hidden mutation.
|
|
26
|
+
- Separate control flow from data transformation where possible.
|
|
17
27
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
## Law 1: Guard Clauses — Handle Unhappy Path First
|
|
21
|
-
|
|
22
|
-
### The Problem
|
|
23
|
-
|
|
24
|
-
Traditional nested conditionals bury the happy path deep inside multiple levels of indentation, making code hard to read and maintain.
|
|
25
|
-
|
|
26
|
-
### The Solution
|
|
27
|
-
|
|
28
|
-
Reject invalid states at the **top** of every function with early returns. The happy path should be the last thing you see, not buried in an `else` branch.
|
|
29
|
-
|
|
30
|
-
### Examples
|
|
31
|
-
|
|
32
|
-
```typescript
|
|
33
|
-
// ❌ BAD — deeply nested, hard to follow
|
|
34
|
-
function process(data: Data | null) {
|
|
35
|
-
if (data) {
|
|
36
|
-
if (data.items.length > 0) {
|
|
37
|
-
if (data.isValid) {
|
|
38
|
-
// ... actual logic deep inside
|
|
39
|
-
return transform(data);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return null;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// ✅ GOOD — guard at the top, logic flows clearly
|
|
47
|
-
function process(data: Data | null) {
|
|
48
|
-
if (!data) return null;
|
|
49
|
-
if (data.items.length === 0) return null;
|
|
50
|
-
if (!data.isValid) return null;
|
|
51
|
-
|
|
52
|
-
// ... actual logic at the top level
|
|
53
|
-
return transform(data);
|
|
54
|
-
}
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
### Benefits
|
|
58
|
-
|
|
59
|
-
- **Readability**: Main logic at top level, not nested
|
|
60
|
-
- **Early Exit**: Fail fast, no deep nesting
|
|
61
|
-
- **Clear Intent**: Each guard shows what we're checking
|
|
62
|
-
|
|
63
|
-
### Checklist
|
|
64
|
-
|
|
65
|
-
- [ ] Are all edge cases (null, empty, unauthorized) handled at the top?
|
|
66
|
-
- [ ] Is the happy path visible without scrolling?
|
|
67
|
-
- [ ] Can I understand the function's purpose from the guards?
|
|
68
|
-
|
|
69
|
-
---
|
|
70
|
-
|
|
71
|
-
## Law 2: Parsed State — Trust Your Types at the Boundary
|
|
72
|
-
|
|
73
|
-
### The Problem
|
|
74
|
-
|
|
75
|
-
Untrusted data (API responses, route params, user input) used directly throughout the codebase leads to scattered defensive checks and type uncertainty.
|
|
76
|
-
|
|
77
|
-
### The Solution
|
|
78
|
-
|
|
79
|
-
Validate and parse untrusted data **at the entry point**. Once inside the system, types should be trusted — no defensive `typeof` checks scattered throughout.
|
|
80
|
-
|
|
81
|
-
### Examples
|
|
82
|
-
|
|
83
|
-
```typescript
|
|
84
|
-
// ❌ BAD — raw API data used directly everywhere
|
|
85
|
-
const id = route.params.id; // string | string[]
|
|
86
|
-
const user = await api.get(`/users/${id}`); // any
|
|
87
|
-
// ... later in the code
|
|
88
|
-
if (typeof user.name === 'string') { // defensive check
|
|
89
|
-
displayName.value = user.name;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// ✅ GOOD — parse at the boundary, use confidently
|
|
93
|
-
const id = String(route.params.id); // parsed to string
|
|
94
|
-
|
|
95
|
-
interface User {
|
|
96
|
-
id: string;
|
|
97
|
-
name: string;
|
|
98
|
-
email: string;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const user = await api.get<User>(`/users/${id}`); // typed
|
|
102
|
-
// ... later in the code
|
|
103
|
-
displayName.value = user.name; // confident, no check needed
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
### With Validation Libraries
|
|
107
|
-
|
|
108
|
-
```typescript
|
|
109
|
-
import { z } from 'zod';
|
|
110
|
-
|
|
111
|
-
// Define schema at the boundary
|
|
112
|
-
const UserSchema = z.object({
|
|
113
|
-
id: z.string(),
|
|
114
|
-
name: z.string(),
|
|
115
|
-
email: z.string().email(),
|
|
116
|
-
age: z.number().min(0).max(150).optional(),
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
// Parse and validate at entry point
|
|
120
|
-
function handleApiResponse(data: unknown): User {
|
|
121
|
-
return UserSchema.parse(data); // throws on invalid
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Now use confidently everywhere
|
|
125
|
-
const user = handleApiResponse(rawData);
|
|
126
|
-
console.log(user.name); // type-safe, no checks needed
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
### Benefits
|
|
130
|
-
|
|
131
|
-
- **Trust**: Once parsed, types are reliable
|
|
132
|
-
- **Clarity**: No scattered `typeof` checks
|
|
133
|
-
- **Safety**: Validation happens once, at the boundary
|
|
134
|
-
|
|
135
|
-
### Checklist
|
|
136
|
-
|
|
137
|
-
- [ ] Is all external data (API, router, events) parsed before use?
|
|
138
|
-
- [ ] Are there defensive type checks that could be removed?
|
|
139
|
-
- [ ] Do types accurately represent what the code expects?
|
|
140
|
-
|
|
141
|
-
---
|
|
142
|
-
|
|
143
|
-
## Law 3: Purity — Functions Should Be Predictable
|
|
144
|
-
|
|
145
|
-
### The Problem
|
|
146
|
-
|
|
147
|
-
Functions that mutate external state or have hidden side effects are hard to test, debug, and reuse. You can't predict the output from the input alone.
|
|
148
|
-
|
|
149
|
-
### The Solution
|
|
150
|
-
|
|
151
|
-
A function that **only computes from its inputs and returns a result** — with no hidden mutations — is easy to test, debug, and reuse.
|
|
152
|
-
|
|
153
|
-
### Examples
|
|
154
|
-
|
|
155
|
-
```typescript
|
|
156
|
-
// ❌ BAD — mutates external state as a side effect
|
|
157
|
-
function applyDiscount(cart: Cart) {
|
|
158
|
-
cart.total = cart.total * 0.9; // hidden mutation
|
|
159
|
-
cart.items.forEach(item => {
|
|
160
|
-
item.discounted = true; // another mutation
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// Usage
|
|
165
|
-
applyDiscount(myCart);
|
|
166
|
-
// What happened? We don't know from the call.
|
|
167
|
-
// Cart is mutated somewhere else.
|
|
168
|
-
|
|
169
|
-
// ✅ GOOD — returns a new value, no side effects
|
|
170
|
-
function applyDiscount(total: number): number {
|
|
171
|
-
return total * 0.9;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function applyDiscountToCart(cart: Cart): Cart {
|
|
175
|
-
return {
|
|
176
|
-
...cart,
|
|
177
|
-
total: applyDiscount(cart.total),
|
|
178
|
-
items: cart.items.map(item => ({ ...item, discounted: true })),
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// Usage
|
|
183
|
-
const discountedCart = applyDiscountToCart(myCart);
|
|
184
|
-
// Clear: we get a new cart, original unchanged
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
### When Mutations Are OK
|
|
188
|
-
|
|
189
|
-
Mutations are acceptable in **controlled, explicit** contexts:
|
|
190
|
-
|
|
191
|
-
```typescript
|
|
192
|
-
// ✅ OK — mutation inside Pinia action (controlled)
|
|
193
|
-
export const useCartStore = defineStore('cart', () => {
|
|
194
|
-
const items = ref<CartItem[]>([]);
|
|
195
|
-
|
|
196
|
-
function addItem(item: CartItem) {
|
|
197
|
-
items.value.push(item); // mutation in action
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
return { items, addItem };
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
// ✅ OK — mutation in local state (contained)
|
|
204
|
-
function setup() {
|
|
205
|
-
const count = ref(0);
|
|
206
|
-
|
|
207
|
-
function increment() {
|
|
208
|
-
count.value++; // local mutation
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
return { count, increment };
|
|
212
|
-
}
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
### Benefits
|
|
216
|
-
|
|
217
|
-
- **Testability**: Pure functions are trivial to test
|
|
218
|
-
- **Predictability**: Same input → same output, always
|
|
219
|
-
- **Reusability**: No hidden dependencies
|
|
220
|
-
|
|
221
|
-
### Checklist
|
|
222
|
-
|
|
223
|
-
- [ ] Do functions avoid mutating props, external refs, or store state?
|
|
224
|
-
- [ ] Can I predict the output from the input alone?
|
|
225
|
-
- [ ] Are side effects explicit and controlled?
|
|
226
|
-
|
|
227
|
-
---
|
|
228
|
-
|
|
229
|
-
## Law 4: Fail Loud — Invalid States Must Scream
|
|
230
|
-
|
|
231
|
-
### The Problem
|
|
232
|
-
|
|
233
|
-
Silent failures cause mysterious bugs. When an invalid state is reached, the code continues with undefined or null values, leading to crashes later with useless stack traces.
|
|
234
|
-
|
|
235
|
-
### The Solution
|
|
236
|
-
|
|
237
|
-
When an invalid state is reached, **throw a clear descriptive error immediately**. Don't let bad data silently propagate.
|
|
28
|
+
## Anti-Patterns
|
|
29
|
+
- Scattered checks, stale state, hidden side effects, catch-all fallbacks, and fuzzy ownership.
|
|
238
30
|
|
|
239
|
-
|
|
31
|
+
## Variation
|
|
32
|
+
- Use more functional style in transformation layers.
|
|
33
|
+
- Allow controlled mutation in stores or actions when the owner is clear.
|
|
34
|
+
- Increase strictness as you move closer to external input.
|
|
240
35
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
const user = store.users.find(u => u.id === id);
|
|
244
|
-
doSomethingWith(user); // might crash later with useless stack trace
|
|
245
|
-
|
|
246
|
-
// ✅ GOOD — fails immediately with context
|
|
247
|
-
const user = store.users.find(u => u.id === id);
|
|
248
|
-
if (!user) {
|
|
249
|
-
throw new Error(`User with id "${id}" not found in store`);
|
|
250
|
-
}
|
|
251
|
-
doSomethingWith(user); // safe, user exists
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
### With Error Boundaries
|
|
255
|
-
|
|
256
|
-
```typescript
|
|
257
|
-
// Component level
|
|
258
|
-
<template>
|
|
259
|
-
<ErrorBoundary>
|
|
260
|
-
<UserProfile :userId="userId" />
|
|
261
|
-
</ErrorBoundary>
|
|
262
|
-
</template>
|
|
263
|
-
|
|
264
|
-
// Store level
|
|
265
|
-
async function fetchUser(id: string): Promise<User> {
|
|
266
|
-
const response = await api.get<User>(`/users/${id}`);
|
|
267
|
-
|
|
268
|
-
if (!response.data) {
|
|
269
|
-
throw new Error(`User ${id} not found (API returned empty)`);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
return response.data;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
// API level
|
|
276
|
-
api.interceptors.response.use(
|
|
277
|
-
response => response,
|
|
278
|
-
error => {
|
|
279
|
-
// Transform API errors to descriptive messages
|
|
280
|
-
const message = error.response?.data?.message
|
|
281
|
-
|| error.message
|
|
282
|
-
|| 'Unknown API error';
|
|
283
|
-
|
|
284
|
-
throw new Error(`API Error: ${message}`);
|
|
285
|
-
}
|
|
286
|
-
);
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
### Benefits
|
|
290
|
-
|
|
291
|
-
- **Fast Feedback**: Know immediately when something is wrong
|
|
292
|
-
- **Clear Context**: Error message explains what failed and why
|
|
293
|
-
- **Easy Debugging**: Stack trace points to the real problem
|
|
294
|
-
|
|
295
|
-
### Checklist
|
|
296
|
-
|
|
297
|
-
- [ ] Do impossible/unexpected states throw descriptive errors?
|
|
298
|
-
- [ ] Are errors silent or do they provide context?
|
|
299
|
-
- [ ] Will debugging be easy if this fails in production?
|
|
300
|
-
|
|
301
|
-
---
|
|
302
|
-
|
|
303
|
-
## Law 5: Readability — Code Reads Like a Sentence
|
|
304
|
-
|
|
305
|
-
### The Problem
|
|
306
|
-
|
|
307
|
-
Cryptic variable names, magic numbers, and complex logic make code hard to understand without extensive comments.
|
|
308
|
-
|
|
309
|
-
### The Solution
|
|
310
|
-
|
|
311
|
-
Variable names explain intent. Functions do one thing with one responsibility. A reader should understand what the code does **without comments**.
|
|
312
|
-
|
|
313
|
-
### Examples
|
|
314
|
-
|
|
315
|
-
```typescript
|
|
316
|
-
// ❌ BAD — what is 'x'? what is 86400000?
|
|
317
|
-
const x = Date.now() - ts > 86400000;
|
|
318
|
-
if (x) {
|
|
319
|
-
// deactivate user
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
// ✅ GOOD — reads like a sentence
|
|
323
|
-
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
|
|
324
|
-
const lastActivityAt = user.lastActivityAt;
|
|
325
|
-
const isExpired = Date.now() - lastActivityAt > ONE_DAY_MS;
|
|
326
|
-
|
|
327
|
-
if (isExpired) {
|
|
328
|
-
deactivateUser(user);
|
|
329
|
-
}
|
|
330
|
-
```
|
|
331
|
-
|
|
332
|
-
### Naming Patterns
|
|
333
|
-
|
|
334
|
-
```typescript
|
|
335
|
-
// ❌ BAD — unclear names
|
|
336
|
-
const d = getData();
|
|
337
|
-
const p = process(d);
|
|
338
|
-
const r = save(p);
|
|
339
|
-
|
|
340
|
-
// ✅ GOOD — descriptive names
|
|
341
|
-
const userData = fetchUserData();
|
|
342
|
-
const processedUser = processUserData(userData);
|
|
343
|
-
const savedUser = saveUserToDatabase(processedUser);
|
|
344
|
-
|
|
345
|
-
// ❌ BAD — abbreviated
|
|
346
|
-
const usr = getUser();
|
|
347
|
-
const addr = usr.addr;
|
|
348
|
-
|
|
349
|
-
// ✅ GOOD — full words
|
|
350
|
-
const user = getUser();
|
|
351
|
-
const address = user.address;
|
|
352
|
-
```
|
|
353
|
-
|
|
354
|
-
### Function Naming
|
|
355
|
-
|
|
356
|
-
```typescript
|
|
357
|
-
// ❌ BAD — vague
|
|
358
|
-
function process(data) { ... }
|
|
359
|
-
function handle(event) { ... }
|
|
360
|
-
function doIt() { ... }
|
|
361
|
-
|
|
362
|
-
// ✅ GOOD — specific
|
|
363
|
-
function validateUserCredentials(credentials) { ... }
|
|
364
|
-
function handleUserRegistration(event) { ... }
|
|
365
|
-
function sendWelcomeEmail() { ... }
|
|
366
|
-
```
|
|
367
|
-
|
|
368
|
-
### Benefits
|
|
369
|
-
|
|
370
|
-
- **Self-Documenting**: Code explains itself
|
|
371
|
-
- **Easy Review**: Reviewers understand quickly
|
|
372
|
-
- **Maintainable**: Future developers can modify safely
|
|
373
|
-
|
|
374
|
-
### Checklist
|
|
375
|
-
|
|
376
|
-
- [ ] Can a teammate understand each function's purpose from its name?
|
|
377
|
-
- [ ] Are variable names self-documenting?
|
|
378
|
-
- [ ] Does the code flow logically without needing comments?
|
|
379
|
-
|
|
380
|
-
---
|
|
381
|
-
|
|
382
|
-
## Putting It All Together
|
|
383
|
-
|
|
384
|
-
### Example: User Authentication
|
|
385
|
-
|
|
386
|
-
```typescript
|
|
387
|
-
// ❌ BAD — violates all 5 laws
|
|
388
|
-
function login(data) {
|
|
389
|
-
if (data) {
|
|
390
|
-
if (data.email && data.password) {
|
|
391
|
-
const user = users.find(u => u.email === data.email);
|
|
392
|
-
if (user) {
|
|
393
|
-
if (user.password === data.password) {
|
|
394
|
-
currentUser = user;
|
|
395
|
-
return true;
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
return false;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
// ✅ GOOD — follows all 5 laws
|
|
404
|
-
interface LoginCredentials {
|
|
405
|
-
email: string;
|
|
406
|
-
password: string;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
interface User {
|
|
410
|
-
id: string;
|
|
411
|
-
email: string;
|
|
412
|
-
passwordHash: string;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
function login(credentials: LoginCredentials): User {
|
|
416
|
-
// Law 1: Guard clauses
|
|
417
|
-
if (!credentials.email || !credentials.password) {
|
|
418
|
-
throw new Error('Email and password are required');
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
// Law 2: Parsed state (credentials already typed)
|
|
422
|
-
const user = findUserByEmail(credentials.email);
|
|
423
|
-
|
|
424
|
-
// Law 4: Fail loud
|
|
425
|
-
if (!user) {
|
|
426
|
-
throw new Error(`User not found: ${credentials.email}`);
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
const isValidPassword = verifyPassword(
|
|
430
|
-
credentials.password,
|
|
431
|
-
user.passwordHash
|
|
432
|
-
);
|
|
433
|
-
|
|
434
|
-
if (!isValidPassword) {
|
|
435
|
-
throw new Error('Invalid password');
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
// Law 3: Purity (returns user, doesn't mutate global)
|
|
439
|
-
return user;
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
// Law 5: Readability (clear names, reads like sentence)
|
|
443
|
-
function findUserByEmail(email: string): User | undefined {
|
|
444
|
-
return users.find(user => user.email === email);
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
function verifyPassword(password: string, hash: string): boolean {
|
|
448
|
-
return bcrypt.compareSync(password, hash);
|
|
449
|
-
}
|
|
450
|
-
```
|
|
451
|
-
|
|
452
|
-
---
|
|
453
|
-
|
|
454
|
-
## Anti-Patterns Summary
|
|
455
|
-
|
|
456
|
-
| Anti-Pattern | Violates | Solution |
|
|
457
|
-
|-------------|----------|----------|
|
|
458
|
-
| Deeply nested conditionals | Law 1 | Guard clauses at top |
|
|
459
|
-
| Scattered type checks | Law 2 | Parse at boundary |
|
|
460
|
-
| Mutating props/state | Law 3 | Return new values |
|
|
461
|
-
| Silent failures | Law 4 | Throw descriptive errors |
|
|
462
|
-
| Cryptic names/numbers | Law 5 | Self-documenting code |
|
|
463
|
-
|
|
464
|
-
---
|
|
465
|
-
|
|
466
|
-
## Review Checklist
|
|
467
|
-
|
|
468
|
-
When reviewing code, check each law:
|
|
469
|
-
|
|
470
|
-
```markdown
|
|
471
|
-
## Code Philosophy Review
|
|
472
|
-
|
|
473
|
-
### Law 1: Guard Clauses
|
|
474
|
-
- [ ] Edge cases handled at top?
|
|
475
|
-
- [ ] Happy path visible?
|
|
476
|
-
- [ ] No deep nesting?
|
|
477
|
-
|
|
478
|
-
### Law 2: Parsed State
|
|
479
|
-
- [ ] External data parsed at entry?
|
|
480
|
-
- [ ] Types trusted inside?
|
|
481
|
-
- [ ] No scattered checks?
|
|
482
|
-
|
|
483
|
-
### Law 3: Purity
|
|
484
|
-
- [ ] No prop mutations?
|
|
485
|
-
- [ ] No hidden side effects?
|
|
486
|
-
- [ ] Functions predictable?
|
|
487
|
-
|
|
488
|
-
### Law 4: Fail Loud
|
|
489
|
-
- [ ] Invalid states throw?
|
|
490
|
-
- [ ] Errors descriptive?
|
|
491
|
-
- [ ] Debugging easy?
|
|
492
|
-
|
|
493
|
-
### Law 5: Readability
|
|
494
|
-
- [ ] Names self-documenting?
|
|
495
|
-
- [ ] Logic flows clearly?
|
|
496
|
-
- [ ] No magic numbers?
|
|
497
|
-
```
|
|
498
|
-
|
|
499
|
-
---
|
|
36
|
+
## Output
|
|
37
|
+
- Return a boundary map, the key invariants, the failure modes, and the recommended flow.
|
|
500
38
|
|
|
501
39
|
## Remember
|
|
502
|
-
|
|
503
|
-
**These laws are not rules — they are principles.**
|
|
504
|
-
|
|
505
|
-
Use them to guide your thinking:
|
|
506
|
-
- **When writing**: Follow them to write better code
|
|
507
|
-
- **When reviewing**: Use them to identify issues
|
|
508
|
-
- **When refactoring**: Apply them to improve existing code
|
|
509
|
-
|
|
510
|
-
**The goal is code that is clear, correct, and performant.**
|
|
511
|
-
|
|
512
|
-
These laws help you achieve that goal consistently.
|
|
40
|
+
Make the correct path easier than the incorrect one.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: context-archive
|
|
3
|
+
description: Store completed feature context bundles in a compact archive for future reference.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Context Archive
|
|
7
|
+
|
|
8
|
+
## Philosophy
|
|
9
|
+
Archive is memory with discipline. Preserve what mattered, remove what did not, and keep active work out of the record.
|
|
10
|
+
|
|
11
|
+
## Use When
|
|
12
|
+
- A feature or bug fix is complete and approved.
|
|
13
|
+
- You need to store proposal, goal, spec, task, and important notes for later.
|
|
14
|
+
- You need a searchable record of why a decision was made.
|
|
15
|
+
- You are closing a feature loop and handing the project back to discovery.
|
|
16
|
+
|
|
17
|
+
## Core Moves
|
|
18
|
+
- Copy the final compact bundle into `.opencode/archive/<feature-slug>/`.
|
|
19
|
+
- Preserve the approved version, not the draft history.
|
|
20
|
+
- Add a short closure note only if it changes future understanding.
|
|
21
|
+
- Keep archive entries small, readable, and immutable.
|
|
22
|
+
|
|
23
|
+
## Default Moves
|
|
24
|
+
- Use the same bundle shape as active work.
|
|
25
|
+
- Name folders by feature slug, optionally with a date when repetition matters.
|
|
26
|
+
- Mark archive entries read-only in practice.
|
|
27
|
+
- Link back to the source feature or review result.
|
|
28
|
+
|
|
29
|
+
## Anti-Patterns
|
|
30
|
+
- Archiving before approval.
|
|
31
|
+
- Stuffing active notes into the archive.
|
|
32
|
+
- Saving huge raw logs instead of the compact bundle.
|
|
33
|
+
- Losing the relationship between archive and shipped work.
|
|
34
|
+
|
|
35
|
+
## Variation
|
|
36
|
+
- Use one folder per feature for long-lived features.
|
|
37
|
+
- Use date suffixes when the same feature is reopened.
|
|
38
|
+
- Include only the minimal final state when the archive is meant as a handoff record.
|
|
39
|
+
|
|
40
|
+
## Output
|
|
41
|
+
- Archive path
|
|
42
|
+
- Archived bundle summary
|
|
43
|
+
- Closure note if needed
|
|
44
|
+
- Source link or review reference
|
|
45
|
+
|
|
46
|
+
## Remember
|
|
47
|
+
Archive should help the next human or agent, not become another trash heap.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: context-gathering
|
|
3
|
+
description: Map project state, active work, ownership, and archive-ready context before planning or proof.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Context Gathering
|
|
7
|
+
|
|
8
|
+
## Philosophy
|
|
9
|
+
Compress the living system into a decision-ready snapshot. This skill should tell the lead what is active, who owns it, and what matters next. It should not become the code discovery layer.
|
|
10
|
+
|
|
11
|
+
## Use When
|
|
12
|
+
- A new request lands and the current project state is unclear.
|
|
13
|
+
- You need to know what the project is doing now, who owns it, and whether there is archive-ready context.
|
|
14
|
+
- You need a compact map before planning, debugging, or proving anything.
|
|
15
|
+
- You need to distinguish active work from archived work.
|
|
16
|
+
- You need to hand exact file discovery to `explorer-agent`.
|
|
17
|
+
|
|
18
|
+
## Core Moves
|
|
19
|
+
- Find the source of truth first: README, AGENTS, architecture, commands, recent commits, and active feature folders.
|
|
20
|
+
- Identify the active path, owner, and current stage.
|
|
21
|
+
- Separate active work from archive-ready work.
|
|
22
|
+
- Capture only what changes the next decision.
|
|
23
|
+
- If exact file paths or implementation patterns are needed, hand off to `explorer-agent`.
|
|
24
|
+
|
|
25
|
+
## Default Moves
|
|
26
|
+
- Start with top-level docs and recent changes.
|
|
27
|
+
- Check for unfinished work or an active feature bundle.
|
|
28
|
+
- Map ownership and dependencies at a high level.
|
|
29
|
+
- Include archive status or target path when relevant.
|
|
30
|
+
- Return a concise snapshot with the recommended next agent.
|
|
31
|
+
|
|
32
|
+
## Anti-Patterns
|
|
33
|
+
- Digging through implementation details when the question is only about project state.
|
|
34
|
+
- Confusing archived history with active work.
|
|
35
|
+
- Dumping raw file lists instead of a decision-ready summary.
|
|
36
|
+
- Treating guesses as facts.
|
|
37
|
+
|
|
38
|
+
## Variation
|
|
39
|
+
- Use a quick scan for simple projects.
|
|
40
|
+
- Use a deeper map when architecture or ownership is unclear.
|
|
41
|
+
- Include archive pointers when a feature is complete or nearly complete.
|
|
42
|
+
|
|
43
|
+
## Output
|
|
44
|
+
- Project snapshot
|
|
45
|
+
- Active work snapshot
|
|
46
|
+
- Ownership and dependencies
|
|
47
|
+
- Recommended next step
|
|
48
|
+
- Archive status or target path
|
|
49
|
+
|
|
50
|
+
## Remember
|
|
51
|
+
If the next agent still has to rediscover the project, the context was not gathered well enough.
|