devlyn-cli 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/bin/devlyn.js +3 -0
- package/optional-skills/better-auth-setup/SKILL.md +450 -0
- package/optional-skills/better-auth-setup/references/api-keys.md +236 -0
- package/optional-skills/better-auth-setup/references/config-and-entry.md +239 -0
- package/optional-skills/better-auth-setup/references/middleware.md +409 -0
- package/optional-skills/better-auth-setup/references/schema.md +224 -0
- package/optional-skills/better-auth-setup/references/testing.md +241 -0
- package/optional-skills/generate-skill/CHECKLIST.md +60 -0
- package/optional-skills/generate-skill/PROMPT-PATTERNS.md +370 -0
- package/optional-skills/generate-skill/REFERENCE.md +195 -0
- package/optional-skills/generate-skill/SKILL.md +178 -0
- package/package.json +1 -1
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# Test Infrastructure Reference
|
|
2
|
+
|
|
3
|
+
Test setup, seed factories, and integration test patterns for Better Auth with Bun.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
1. [Test Preload](#test-preload)
|
|
7
|
+
2. [Seed Data Factory](#seed-data-factory)
|
|
8
|
+
3. [Integration Test App](#integration-test-app)
|
|
9
|
+
4. [Database Cleanup](#database-cleanup)
|
|
10
|
+
5. [Key Testing Patterns](#key-testing-patterns)
|
|
11
|
+
|
|
12
|
+
## Test Preload
|
|
13
|
+
|
|
14
|
+
Prevents the most common testing pitfall: real emails sent during test runs.
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
// src/test-utils/setup.ts — preloaded via bunfig.toml
|
|
18
|
+
// Without this, test signups send real emails through Resend
|
|
19
|
+
// when RESEND_API_KEY is in your .env file.
|
|
20
|
+
process.env.NODE_ENV = "test";
|
|
21
|
+
process.env.RESEND_API_KEY = ""; // Force email to console-log fallback
|
|
22
|
+
|
|
23
|
+
// Bridge test database — use a separate DB for tests
|
|
24
|
+
if (process.env.TEST_DATABASE_URL) {
|
|
25
|
+
process.env.DATABASE_URL = process.env.TEST_DATABASE_URL;
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```toml
|
|
30
|
+
# bunfig.toml
|
|
31
|
+
[test]
|
|
32
|
+
preload = ["./src/test-utils/setup.ts"]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Why preload?** Bun's preload runs before any test file imports. This guarantees that config validation (which runs at import time) sees the correct environment variables. Setting `RESEND_API_KEY = ""` before any module loads ensures the email module's lazy client never initializes.
|
|
36
|
+
|
|
37
|
+
## Seed Data Factory
|
|
38
|
+
|
|
39
|
+
Creates a complete tenant hierarchy for integration tests. Every call produces unique identifiers to prevent collisions in parallel test runs.
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
// src/test-utils/db.ts
|
|
43
|
+
import { db } from "../db";
|
|
44
|
+
import {
|
|
45
|
+
organizations, users, orgMemberships,
|
|
46
|
+
projects, apiKeys, sessions, accounts,
|
|
47
|
+
verifications, invitations,
|
|
48
|
+
} from "../db/schema";
|
|
49
|
+
|
|
50
|
+
export async function seedTestData() {
|
|
51
|
+
const uniqueSuffix = `${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
|
|
52
|
+
|
|
53
|
+
// Create org → user → membership → project → API key
|
|
54
|
+
const [org] = await db.insert(organizations).values({
|
|
55
|
+
name: `Test Org ${uniqueSuffix}`,
|
|
56
|
+
slug: `test-org-${uniqueSuffix}`,
|
|
57
|
+
plan: "free",
|
|
58
|
+
}).returning();
|
|
59
|
+
|
|
60
|
+
const [user] = await db.insert(users).values({
|
|
61
|
+
email: `test-${uniqueSuffix}@example.com`,
|
|
62
|
+
name: "Test User",
|
|
63
|
+
emailVerified: true,
|
|
64
|
+
}).returning();
|
|
65
|
+
|
|
66
|
+
await db.insert(orgMemberships).values({
|
|
67
|
+
organizationId: org.id,
|
|
68
|
+
userId: user.id,
|
|
69
|
+
role: "owner",
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const [project] = await db.insert(projects).values({
|
|
73
|
+
organizationId: org.id,
|
|
74
|
+
name: `Test Project ${uniqueSuffix}`,
|
|
75
|
+
slug: `test-project-${uniqueSuffix}`,
|
|
76
|
+
}).returning();
|
|
77
|
+
|
|
78
|
+
// Generate API key
|
|
79
|
+
const { key, hash, prefix } = await generateTestApiKey();
|
|
80
|
+
const [apiKey] = await db.insert(apiKeys).values({
|
|
81
|
+
projectId: project.id,
|
|
82
|
+
name: "Test Key",
|
|
83
|
+
keyHash: hash,
|
|
84
|
+
keyPrefix: prefix,
|
|
85
|
+
}).returning();
|
|
86
|
+
|
|
87
|
+
return { org, user, project, apiKey, plaintextKey: key };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Helper: generate a test API key
|
|
91
|
+
async function generateTestApiKey() {
|
|
92
|
+
const { API_KEY_PREFIX, base62Encode, hashKey } = await import("../lib/api-keys");
|
|
93
|
+
const randomBytes = crypto.getRandomValues(new Uint8Array(32));
|
|
94
|
+
const key = API_KEY_PREFIX + base62Encode(randomBytes);
|
|
95
|
+
const hash = await hashKey(key);
|
|
96
|
+
const prefix = key.slice(0, 12);
|
|
97
|
+
return { key, hash, prefix };
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**Key design decisions:**
|
|
102
|
+
- `uniqueSuffix` uses `Date.now()` + random chars for collision-free parallel tests
|
|
103
|
+
- `emailVerified: true` so tests don't need to go through email verification flow
|
|
104
|
+
- Returns `plaintextKey` so tests can immediately make authenticated requests
|
|
105
|
+
|
|
106
|
+
## Integration Test App
|
|
107
|
+
|
|
108
|
+
Builds the full middleware chain matching production. This catches middleware ordering bugs before they reach production.
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
// src/test-utils/app.ts
|
|
112
|
+
import { Hono } from "hono";
|
|
113
|
+
|
|
114
|
+
// Lazy imports to avoid circular dependency issues during test setup
|
|
115
|
+
export function createIntegrationApp() {
|
|
116
|
+
const { authMiddleware } = require("../middleware/auth");
|
|
117
|
+
const { tenantContextMiddleware } = require("../middleware/tenant-context");
|
|
118
|
+
const { rateLimitMiddleware } = require("../middleware/rate-limit");
|
|
119
|
+
|
|
120
|
+
const app = new Hono();
|
|
121
|
+
|
|
122
|
+
// Request ID
|
|
123
|
+
app.use("*", async (c, next) => {
|
|
124
|
+
c.set("requestId", crypto.randomUUID());
|
|
125
|
+
await next();
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// Auth → Tenant Context → Rate Limit (same order as production)
|
|
129
|
+
app.use("*", authMiddleware);
|
|
130
|
+
app.use("*", tenantContextMiddleware);
|
|
131
|
+
app.use("*", rateLimitMiddleware);
|
|
132
|
+
|
|
133
|
+
// Mount route handlers here...
|
|
134
|
+
return app;
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Why lazy imports?** The auth module imports the database module, which reads `DATABASE_URL` from the environment. If imported eagerly at the top level, the test preload script might not have run yet, causing config validation to fail.
|
|
139
|
+
|
|
140
|
+
## Database Cleanup
|
|
141
|
+
|
|
142
|
+
Delete tables in FK dependency order to avoid constraint violations.
|
|
143
|
+
|
|
144
|
+
```typescript
|
|
145
|
+
// Clean tables in FK dependency order
|
|
146
|
+
export async function cleanupDatabase() {
|
|
147
|
+
// Children first, parents last
|
|
148
|
+
await db.delete(apiKeys);
|
|
149
|
+
await db.delete(projects);
|
|
150
|
+
await db.delete(orgMemberships);
|
|
151
|
+
await db.delete(sessions);
|
|
152
|
+
await db.delete(accounts);
|
|
153
|
+
await db.delete(verifications);
|
|
154
|
+
await db.delete(invitations);
|
|
155
|
+
await db.delete(organizations);
|
|
156
|
+
await db.delete(users);
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Order matters.** If you try to delete `organizations` before `projects`, the FK constraint on `projects.organization_id` will reject the delete. Start from leaf tables and work toward root tables.
|
|
161
|
+
|
|
162
|
+
## Key Testing Patterns
|
|
163
|
+
|
|
164
|
+
### Test Auth via API Key
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
import { describe, test, expect, beforeAll, afterAll } from "bun:test";
|
|
168
|
+
|
|
169
|
+
describe("Protected endpoint", () => {
|
|
170
|
+
let testData: Awaited<ReturnType<typeof seedTestData>>;
|
|
171
|
+
|
|
172
|
+
beforeAll(async () => {
|
|
173
|
+
testData = await seedTestData();
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
afterAll(async () => {
|
|
177
|
+
await cleanupDatabase();
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test("returns 200 with valid API key", async () => {
|
|
181
|
+
const app = createIntegrationApp();
|
|
182
|
+
const res = await app.request("/v1/endpoint", {
|
|
183
|
+
headers: {
|
|
184
|
+
Authorization: `Bearer ${testData.plaintextKey}`,
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
expect(res.status).toBe(200);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
test("returns 401 without auth", async () => {
|
|
191
|
+
const app = createIntegrationApp();
|
|
192
|
+
const res = await app.request("/v1/endpoint");
|
|
193
|
+
expect(res.status).toBe(401);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Test Signup Flow
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
test("signup creates user and personal org", async () => {
|
|
202
|
+
const res = await app.request("/auth/sign-up/email", {
|
|
203
|
+
method: "POST",
|
|
204
|
+
headers: { "Content-Type": "application/json" },
|
|
205
|
+
body: JSON.stringify({
|
|
206
|
+
email: `signup-test-${Date.now()}@example.com`,
|
|
207
|
+
password: "secure-password-123",
|
|
208
|
+
name: "Test User",
|
|
209
|
+
}),
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
expect(res.status).toBe(200);
|
|
213
|
+
|
|
214
|
+
// Verify auto-org creation via databaseHooks
|
|
215
|
+
const user = await db.select().from(users)
|
|
216
|
+
.where(eq(users.email, email)).limit(1);
|
|
217
|
+
|
|
218
|
+
const membership = await db.select().from(orgMemberships)
|
|
219
|
+
.where(eq(orgMemberships.userId, user[0].id)).limit(1);
|
|
220
|
+
|
|
221
|
+
expect(membership).toHaveLength(1);
|
|
222
|
+
expect(membership[0].role).toBe("owner");
|
|
223
|
+
});
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### Test Tenant Isolation
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
test("cannot access resources from another org", async () => {
|
|
230
|
+
const org1 = await seedTestData();
|
|
231
|
+
const org2 = await seedTestData();
|
|
232
|
+
|
|
233
|
+
// Use org1's API key to try accessing org2's project
|
|
234
|
+
const res = await app.request(`/v1/projects/${org2.project.id}`, {
|
|
235
|
+
headers: { Authorization: `Bearer ${org1.plaintextKey}` },
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// Should be 404 (not 403, to prevent ID enumeration)
|
|
239
|
+
expect(res.status).toBe(404);
|
|
240
|
+
});
|
|
241
|
+
```
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Skill Quality Checklist
|
|
2
|
+
|
|
3
|
+
Verify the generated skill against every item below before finalizing.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Frontmatter
|
|
8
|
+
|
|
9
|
+
- [ ] `name` is lowercase, hyphens and digits only, max 64 chars
|
|
10
|
+
- [ ] `name` does not contain "anthropic", "claude", or "official"
|
|
11
|
+
- [ ] `description` is third-person, max 1024 chars
|
|
12
|
+
- [ ] `description` includes specific trigger phrases ("Use when user says...")
|
|
13
|
+
- [ ] `description` first sentence states what the skill does
|
|
14
|
+
- [ ] `allowed-tools` uses the minimal set needed (not all tools)
|
|
15
|
+
- [ ] `argument-hint` shows expected input format if skill takes arguments
|
|
16
|
+
- [ ] No XML tags in any frontmatter field values
|
|
17
|
+
|
|
18
|
+
## Body Structure
|
|
19
|
+
|
|
20
|
+
- [ ] Starts with a title (`#`) and one-line purpose statement
|
|
21
|
+
- [ ] Lists reference files with descriptions (if multi-file)
|
|
22
|
+
- [ ] Workflow uses numbered steps with `###` headings
|
|
23
|
+
- [ ] Each step starts with an action verb (Parse, Read, Generate, Validate)
|
|
24
|
+
- [ ] Each step has clear entry and exit criteria
|
|
25
|
+
- [ ] Output format is explicitly defined
|
|
26
|
+
|
|
27
|
+
## Content Quality
|
|
28
|
+
|
|
29
|
+
- [ ] Instructions are explicit, not vague ("Review for X, Y, Z" not "Review the code")
|
|
30
|
+
- [ ] Includes WHY context for non-obvious rules
|
|
31
|
+
- [ ] Uses XML tags for complex structure (`<example>`, `<rules>`, `<output-format>`)
|
|
32
|
+
- [ ] Uses "consider"/"evaluate" instead of "think"
|
|
33
|
+
- [ ] Contains at least one concrete `<example>` block
|
|
34
|
+
- [ ] Scope is bounded (file limits, directory limits, or explicit boundaries)
|
|
35
|
+
- [ ] No conflicting instructions
|
|
36
|
+
|
|
37
|
+
## Error Handling
|
|
38
|
+
|
|
39
|
+
- [ ] Handles empty `$ARGUMENTS` (asks user or uses sensible detection)
|
|
40
|
+
- [ ] Handles missing files (clear error message, not silent fallback)
|
|
41
|
+
- [ ] Handles unexpected input (validation with actionable error)
|
|
42
|
+
- [ ] No silent fallbacks to defaults (project convention)
|
|
43
|
+
|
|
44
|
+
## Prompt Engineering
|
|
45
|
+
|
|
46
|
+
- [ ] No over-triggering (description is specific, not generic)
|
|
47
|
+
- [ ] No aggressive language ("MUST", "NEVER EVER", "ABSOLUTELY")
|
|
48
|
+
- [ ] No wall of text without headings or structure
|
|
49
|
+
- [ ] No unbounded scope ("analyze everything")
|
|
50
|
+
- [ ] Anti-hallucination patterns applied (grounded in file content)
|
|
51
|
+
- [ ] Degree of freedom matches skill type (guardrails for high, specs for low)
|
|
52
|
+
|
|
53
|
+
## Completeness
|
|
54
|
+
|
|
55
|
+
- [ ] All reference files mentioned in SKILL.md exist
|
|
56
|
+
- [ ] Reference files have table of contents if over 100 lines
|
|
57
|
+
- [ ] Reference files are one level deep (no nested references)
|
|
58
|
+
- [ ] Total SKILL.md is under 500 lines (split if over)
|
|
59
|
+
- [ ] Skill is self-contained (works without external dependencies)
|
|
60
|
+
- [ ] Installation path is correct (`.claude/skills/<skill-name>/`)
|
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
# Prompt Patterns for Claude 4.6 Skills
|
|
2
|
+
|
|
3
|
+
Patterns and anti-patterns for writing effective skill body content that works well with Claude 4.6 models.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Core Principles](#core-principles)
|
|
8
|
+
- [Structural Patterns](#structural-patterns)
|
|
9
|
+
- [Anti-Patterns](#anti-patterns)
|
|
10
|
+
- [Anti-Hallucination Patterns](#anti-hallucination-patterns)
|
|
11
|
+
- [Degree of Freedom Guide](#degree-of-freedom-guide)
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Core Principles
|
|
16
|
+
|
|
17
|
+
### 1. Be Explicit
|
|
18
|
+
|
|
19
|
+
Claude 4.6 follows instructions precisely. Vague prompts get literal interpretations.
|
|
20
|
+
|
|
21
|
+
```markdown
|
|
22
|
+
# Bad — vague
|
|
23
|
+
Review the code and fix issues.
|
|
24
|
+
|
|
25
|
+
# Good — explicit
|
|
26
|
+
Review the code for:
|
|
27
|
+
1. Security vulnerabilities (SQL injection, XSS, command injection)
|
|
28
|
+
2. Performance anti-patterns (N+1 queries, unnecessary re-renders)
|
|
29
|
+
3. Missing error handling
|
|
30
|
+
|
|
31
|
+
For each issue found, output:
|
|
32
|
+
- File and line number
|
|
33
|
+
- Severity (critical/warning/info)
|
|
34
|
+
- Description of the issue
|
|
35
|
+
- Suggested fix with code snippet
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 2. Provide WHY Context
|
|
39
|
+
|
|
40
|
+
Claude generalizes better when it understands the reasoning behind instructions.
|
|
41
|
+
|
|
42
|
+
```markdown
|
|
43
|
+
# Bad — no context
|
|
44
|
+
Always use `const` instead of `let`.
|
|
45
|
+
|
|
46
|
+
# Good — with WHY
|
|
47
|
+
Use `const` by default because it signals immutability to other developers
|
|
48
|
+
and prevents accidental reassignment. Only use `let` when the variable
|
|
49
|
+
must be reassigned within its scope.
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 3. Use XML Tags for Structure
|
|
53
|
+
|
|
54
|
+
XML tags create clear semantic boundaries. Use them for complex sections.
|
|
55
|
+
|
|
56
|
+
```markdown
|
|
57
|
+
<rules>
|
|
58
|
+
- Never modify files outside the project directory
|
|
59
|
+
- Always create a backup before destructive operations
|
|
60
|
+
- Ask for confirmation before deleting more than 3 files
|
|
61
|
+
</rules>
|
|
62
|
+
|
|
63
|
+
<output-format>
|
|
64
|
+
## Review Report
|
|
65
|
+
- **File**: {path}
|
|
66
|
+
- **Issues**: {count}
|
|
67
|
+
- **Severity**: {critical|warning|info}
|
|
68
|
+
</output-format>
|
|
69
|
+
|
|
70
|
+
<example>
|
|
71
|
+
Input: `/review src/auth.ts`
|
|
72
|
+
Output: Review report with 3 issues found...
|
|
73
|
+
</example>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 4. Avoid "Think"
|
|
77
|
+
|
|
78
|
+
When extended thinking is disabled, "think" can cause confusion. Use alternatives:
|
|
79
|
+
|
|
80
|
+
| Instead of | Use |
|
|
81
|
+
|---|---|
|
|
82
|
+
| "Think about..." | "Consider..." |
|
|
83
|
+
| "Think through..." | "Evaluate..." |
|
|
84
|
+
| "Think step by step" | "Work through each step" |
|
|
85
|
+
| "Let me think" | "Let me analyze" |
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Structural Patterns
|
|
90
|
+
|
|
91
|
+
### Pattern 1: Workflow (Most Common)
|
|
92
|
+
|
|
93
|
+
Sequential steps with clear entry/exit criteria. Best for medium-freedom skills.
|
|
94
|
+
|
|
95
|
+
```markdown
|
|
96
|
+
## Workflow
|
|
97
|
+
|
|
98
|
+
### Step 1: Parse Input
|
|
99
|
+
Extract the target from `$ARGUMENTS`.
|
|
100
|
+
If empty, ask the user for the target.
|
|
101
|
+
|
|
102
|
+
### Step 2: Analyze
|
|
103
|
+
Read the target file(s) and identify {specific things}.
|
|
104
|
+
|
|
105
|
+
### Step 3: Generate Output
|
|
106
|
+
Produce {specific output format}.
|
|
107
|
+
|
|
108
|
+
### Step 4: Validate
|
|
109
|
+
Verify the output meets {specific criteria}.
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**When to use**: Most skills. Provides clear structure while allowing flexibility within steps.
|
|
113
|
+
|
|
114
|
+
### Pattern 2: Template (Fill-in-the-Blanks)
|
|
115
|
+
|
|
116
|
+
Fixed output structure with variable content. Best for low-freedom skills.
|
|
117
|
+
|
|
118
|
+
```markdown
|
|
119
|
+
## Output Template
|
|
120
|
+
|
|
121
|
+
Generate the following file:
|
|
122
|
+
|
|
123
|
+
\```yaml
|
|
124
|
+
name: {extracted-name}
|
|
125
|
+
version: {detected-version}
|
|
126
|
+
dependencies:
|
|
127
|
+
{for each dependency}
|
|
128
|
+
- name: {dep-name}
|
|
129
|
+
version: {dep-version}
|
|
130
|
+
{end for}
|
|
131
|
+
\```
|
|
132
|
+
|
|
133
|
+
Rules:
|
|
134
|
+
- `name` must be lowercase with hyphens
|
|
135
|
+
- `version` must follow semver (x.y.z)
|
|
136
|
+
- Dependencies sorted alphabetically
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**When to use**: Config generation, scaffolding, report generation.
|
|
140
|
+
|
|
141
|
+
### Pattern 3: Decision Tree
|
|
142
|
+
|
|
143
|
+
Branching logic based on input analysis. Best for skills that adapt behavior.
|
|
144
|
+
|
|
145
|
+
```markdown
|
|
146
|
+
## Decision Logic
|
|
147
|
+
|
|
148
|
+
Analyze the input and follow the appropriate path:
|
|
149
|
+
|
|
150
|
+
### Path A: Single File
|
|
151
|
+
If `$ARGUMENTS` points to a single file:
|
|
152
|
+
1. Read the file
|
|
153
|
+
2. Analyze for {criteria}
|
|
154
|
+
3. Output inline suggestions
|
|
155
|
+
|
|
156
|
+
### Path B: Directory
|
|
157
|
+
If `$ARGUMENTS` points to a directory:
|
|
158
|
+
1. Glob for relevant files (`**/*.{ts,tsx}`)
|
|
159
|
+
2. Analyze each file
|
|
160
|
+
3. Output a summary report
|
|
161
|
+
|
|
162
|
+
### Path C: No Input
|
|
163
|
+
If `$ARGUMENTS` is empty:
|
|
164
|
+
1. Detect the project type from package.json / pyproject.toml
|
|
165
|
+
2. Find the most relevant files
|
|
166
|
+
3. Follow Path A or Path B based on results
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**When to use**: Skills that handle multiple input types or contexts.
|
|
170
|
+
|
|
171
|
+
### Pattern 4: Conditional Workflow
|
|
172
|
+
|
|
173
|
+
Workflow with conditional steps based on context. Combines workflow + decision tree.
|
|
174
|
+
|
|
175
|
+
```markdown
|
|
176
|
+
## Workflow
|
|
177
|
+
|
|
178
|
+
### Step 1: Detect Context
|
|
179
|
+
Read the project structure and determine:
|
|
180
|
+
- Language (TypeScript, Python, Go, etc.)
|
|
181
|
+
- Framework (Next.js, FastAPI, etc.)
|
|
182
|
+
- Test runner (Jest, Pytest, etc.)
|
|
183
|
+
|
|
184
|
+
### Step 2: Analyze (language-specific)
|
|
185
|
+
|
|
186
|
+
**If TypeScript/JavaScript:**
|
|
187
|
+
- Check for type errors with LSP
|
|
188
|
+
- Scan for common JS anti-patterns
|
|
189
|
+
|
|
190
|
+
**If Python:**
|
|
191
|
+
- Check for type hints
|
|
192
|
+
- Scan for common Python anti-patterns
|
|
193
|
+
|
|
194
|
+
### Step 3: Report
|
|
195
|
+
Output findings in a unified format regardless of language.
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
**When to use**: Skills that work across different project types.
|
|
199
|
+
|
|
200
|
+
### Pattern 5: Examples-Driven
|
|
201
|
+
|
|
202
|
+
Heavy use of examples to specify behavior. Best for high-freedom skills.
|
|
203
|
+
|
|
204
|
+
```markdown
|
|
205
|
+
## Behavior
|
|
206
|
+
|
|
207
|
+
Generate code following these examples exactly:
|
|
208
|
+
|
|
209
|
+
<example>
|
|
210
|
+
Input: "a function that fetches user data"
|
|
211
|
+
Output:
|
|
212
|
+
\```typescript
|
|
213
|
+
async function fetchUserData(userId: string): Promise<User> {
|
|
214
|
+
const response = await fetch(`/api/users/${userId}`);
|
|
215
|
+
if (!response.ok) {
|
|
216
|
+
throw new Error(`Failed to fetch user ${userId}: ${response.statusText}`);
|
|
217
|
+
}
|
|
218
|
+
return response.json();
|
|
219
|
+
}
|
|
220
|
+
\```
|
|
221
|
+
</example>
|
|
222
|
+
|
|
223
|
+
<example>
|
|
224
|
+
Input: "a React hook for local storage"
|
|
225
|
+
Output:
|
|
226
|
+
\```typescript
|
|
227
|
+
function useLocalStorage<T>(key: string, initialValue: T) {
|
|
228
|
+
const [value, setValue] = useState<T>(() => {
|
|
229
|
+
const stored = localStorage.getItem(key);
|
|
230
|
+
return stored ? JSON.parse(stored) : initialValue;
|
|
231
|
+
});
|
|
232
|
+
// ...
|
|
233
|
+
}
|
|
234
|
+
\```
|
|
235
|
+
</example>
|
|
236
|
+
|
|
237
|
+
Key patterns shown in examples:
|
|
238
|
+
- Always include error handling
|
|
239
|
+
- Use TypeScript generics where appropriate
|
|
240
|
+
- Async functions return typed Promises
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**When to use**: Code generation, formatting, transformation skills.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Anti-Patterns
|
|
248
|
+
|
|
249
|
+
Common mistakes when writing Claude 4.6 skills:
|
|
250
|
+
|
|
251
|
+
| Anti-Pattern | Problem | Fix |
|
|
252
|
+
|---|---|---|
|
|
253
|
+
| Over-triggering | Description matches too many scenarios | Add specific trigger phrases: `"Use when user says X, Y, Z"` |
|
|
254
|
+
| Aggressive language | "You MUST", "NEVER EVER", "ABSOLUTELY" | Use calm, clear directives: "Always X", "Do not Y" |
|
|
255
|
+
| Vague triggers | "Use when helpful" | Specific: "Use when reviewing TypeScript code for security" |
|
|
256
|
+
| Wall of text | No structure, no headings | Break into steps with `###` headings |
|
|
257
|
+
| Conflicting rules | "Be concise" + "Include all details" | Prioritize: "Be concise. Include details only for critical issues." |
|
|
258
|
+
| No examples | Claude guesses at desired output | Add 1-2 concrete `<example>` blocks |
|
|
259
|
+
| Unbounded scope | "Analyze everything" | Limit: "Analyze files in `src/` matching `*.ts`" |
|
|
260
|
+
| Silent failures | No error handling instructions | Add: "When X fails, display the error and suggest next steps" |
|
|
261
|
+
|
|
262
|
+
### Over-Triggering Fix
|
|
263
|
+
|
|
264
|
+
```markdown
|
|
265
|
+
# Bad — triggers on any code question
|
|
266
|
+
description: Helps with code. Use for any coding task.
|
|
267
|
+
|
|
268
|
+
# Good — specific triggers
|
|
269
|
+
description: >
|
|
270
|
+
Generate unit tests for TypeScript functions using Jest.
|
|
271
|
+
Use when user says "generate tests", "add tests", "write tests for",
|
|
272
|
+
or when reviewing untested code.
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Scope Bounding
|
|
276
|
+
|
|
277
|
+
```markdown
|
|
278
|
+
# Bad — unbounded
|
|
279
|
+
Analyze the entire codebase for issues.
|
|
280
|
+
|
|
281
|
+
# Good — bounded
|
|
282
|
+
Analyze files matching `$ARGUMENTS` (default: `src/**/*.ts`).
|
|
283
|
+
Limit to 50 files maximum. If more files match, ask the user to narrow the scope.
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Anti-Hallucination Patterns
|
|
289
|
+
|
|
290
|
+
Prevent Claude from inventing information in skills:
|
|
291
|
+
|
|
292
|
+
### 1. Ground in File Content
|
|
293
|
+
|
|
294
|
+
```markdown
|
|
295
|
+
# Bad
|
|
296
|
+
Describe the project architecture.
|
|
297
|
+
|
|
298
|
+
# Good
|
|
299
|
+
Read `README.md`, `package.json`, and the `src/` directory structure.
|
|
300
|
+
Describe the architecture based ONLY on what these files contain.
|
|
301
|
+
Do not infer or assume features not present in the code.
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### 2. Explicit Unknowns
|
|
305
|
+
|
|
306
|
+
```markdown
|
|
307
|
+
If you cannot determine {X} from the available files:
|
|
308
|
+
- State "Unable to determine {X} from the codebase"
|
|
309
|
+
- List what files you checked
|
|
310
|
+
- Suggest what the user could provide to resolve this
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### 3. Verify Before Acting
|
|
314
|
+
|
|
315
|
+
```markdown
|
|
316
|
+
Before generating code:
|
|
317
|
+
1. Read the existing implementation in `$1`
|
|
318
|
+
2. Identify the patterns already used (naming, error handling, imports)
|
|
319
|
+
3. Generate code that matches these existing patterns
|
|
320
|
+
Do not introduce new patterns or dependencies without explicit instruction.
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## Degree of Freedom Guide
|
|
326
|
+
|
|
327
|
+
How much latitude to give Claude based on skill type:
|
|
328
|
+
|
|
329
|
+
### High Freedom
|
|
330
|
+
The skill makes autonomous decisions. Requires strong guardrails.
|
|
331
|
+
|
|
332
|
+
```markdown
|
|
333
|
+
## Guardrails
|
|
334
|
+
- Do NOT modify files outside `$ARGUMENTS` path
|
|
335
|
+
- Do NOT add new dependencies without asking
|
|
336
|
+
- Do NOT delete existing code without replacement
|
|
337
|
+
- Maximum 200 lines of generated code per invocation
|
|
338
|
+
- Always show a diff preview before applying changes
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**Examples**: code generation, refactoring, migration skills
|
|
342
|
+
|
|
343
|
+
### Medium Freedom
|
|
344
|
+
The skill follows a workflow but adapts to context. Requires clear decision criteria.
|
|
345
|
+
|
|
346
|
+
```markdown
|
|
347
|
+
## Decision Criteria
|
|
348
|
+
- If the file has fewer than 50 lines: inline review
|
|
349
|
+
- If the file has 50-500 lines: section-by-section review
|
|
350
|
+
- If the file has more than 500 lines: focus on public API and entry points only
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
**Examples**: review, analysis, documentation skills
|
|
354
|
+
|
|
355
|
+
### Low Freedom
|
|
356
|
+
The skill executes a fixed procedure. Requires exact input/output specs.
|
|
357
|
+
|
|
358
|
+
```markdown
|
|
359
|
+
## Input
|
|
360
|
+
- `$1`: PR number (required, integer)
|
|
361
|
+
- `$2`: Template name (optional, default: "standard")
|
|
362
|
+
|
|
363
|
+
## Output
|
|
364
|
+
A markdown report with exactly these sections:
|
|
365
|
+
1. Summary (1-2 sentences)
|
|
366
|
+
2. Checklist (pass/fail for each template requirement)
|
|
367
|
+
3. Missing Items (list of unfulfilled requirements)
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
**Examples**: validation, scanning, formatting skills
|