@c0x12c/ai-toolkit 1.15.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/.claude-plugin/marketplace.json +16 -0
- package/.claude-plugin/plugin.json +12 -0
- package/README.md +439 -0
- package/VERSION +1 -0
- package/agents/design-critic.md +127 -0
- package/agents/idea-killer.md +72 -0
- package/agents/infrastructure-expert.md +49 -0
- package/agents/micronaut-backend-expert.md +45 -0
- package/agents/phase-reviewer.md +150 -0
- package/agents/research-planner.md +70 -0
- package/agents/solution-architect-cto.md +49 -0
- package/agents/sre-architect.md +49 -0
- package/agents/team-coordinator.md +111 -0
- package/bin/cli.js +780 -0
- package/claude-md/00-header.md +39 -0
- package/claude-md/01-core.md +105 -0
- package/claude-md/05-database.md +20 -0
- package/claude-md/11-backend-micronaut.md +19 -0
- package/claude-md/20-frontend-react.md +44 -0
- package/claude-md/25-ux-design.md +56 -0
- package/claude-md/30-infrastructure.md +24 -0
- package/claude-md/30-project-mgmt.md +119 -0
- package/claude-md/40-product.md +39 -0
- package/claude-md/50-ops.md +34 -0
- package/claude-md/60-research.md +27 -0
- package/claude-md/90-footer.md +21 -0
- package/commands/spartan/brainstorm.md +134 -0
- package/commands/spartan/brownfield.md +157 -0
- package/commands/spartan/build.md +435 -0
- package/commands/spartan/careful.md +94 -0
- package/commands/spartan/commit-message.md +112 -0
- package/commands/spartan/content.md +17 -0
- package/commands/spartan/context-save.md +161 -0
- package/commands/spartan/contribute.md +140 -0
- package/commands/spartan/daily.md +42 -0
- package/commands/spartan/debug.md +308 -0
- package/commands/spartan/deep-dive.md +55 -0
- package/commands/spartan/deploy.md +207 -0
- package/commands/spartan/e2e.md +264 -0
- package/commands/spartan/env-setup.md +166 -0
- package/commands/spartan/epic.md +199 -0
- package/commands/spartan/fe-review.md +181 -0
- package/commands/spartan/figma-to-code.md +260 -0
- package/commands/spartan/forensics.md +46 -0
- package/commands/spartan/freeze.md +84 -0
- package/commands/spartan/fundraise.md +53 -0
- package/commands/spartan/gate-review.md +229 -0
- package/commands/spartan/gsd-upgrade.md +376 -0
- package/commands/spartan/guard.md +42 -0
- package/commands/spartan/init-project.md +178 -0
- package/commands/spartan/init-rules.md +298 -0
- package/commands/spartan/interview.md +154 -0
- package/commands/spartan/kickoff.md +73 -0
- package/commands/spartan/kotlin-service.md +109 -0
- package/commands/spartan/lean-canvas.md +222 -0
- package/commands/spartan/lint-rules.md +122 -0
- package/commands/spartan/map-codebase.md +124 -0
- package/commands/spartan/migration.md +82 -0
- package/commands/spartan/next-app.md +317 -0
- package/commands/spartan/next-feature.md +212 -0
- package/commands/spartan/onboard.md +326 -0
- package/commands/spartan/outreach.md +16 -0
- package/commands/spartan/phase.md +142 -0
- package/commands/spartan/pitch.md +18 -0
- package/commands/spartan/plan.md +210 -0
- package/commands/spartan/pr-ready.md +202 -0
- package/commands/spartan/project.md +106 -0
- package/commands/spartan/qa.md +222 -0
- package/commands/spartan/research.md +254 -0
- package/commands/spartan/review.md +132 -0
- package/commands/spartan/scan-rules.md +173 -0
- package/commands/spartan/sessions.md +143 -0
- package/commands/spartan/spec.md +131 -0
- package/commands/spartan/startup.md +257 -0
- package/commands/spartan/team.md +570 -0
- package/commands/spartan/teardown.md +161 -0
- package/commands/spartan/testcontainer.md +97 -0
- package/commands/spartan/tf-cost.md +123 -0
- package/commands/spartan/tf-deploy.md +116 -0
- package/commands/spartan/tf-drift.md +100 -0
- package/commands/spartan/tf-import.md +107 -0
- package/commands/spartan/tf-module.md +121 -0
- package/commands/spartan/tf-plan.md +100 -0
- package/commands/spartan/tf-review.md +106 -0
- package/commands/spartan/tf-scaffold.md +109 -0
- package/commands/spartan/tf-security.md +147 -0
- package/commands/spartan/think.md +221 -0
- package/commands/spartan/unfreeze.md +13 -0
- package/commands/spartan/update.md +134 -0
- package/commands/spartan/ux.md +1233 -0
- package/commands/spartan/validate.md +193 -0
- package/commands/spartan/web-to-prd.md +706 -0
- package/commands/spartan/workstreams.md +109 -0
- package/commands/spartan/write.md +16 -0
- package/commands/spartan.md +386 -0
- package/frameworks/00-framework-comparison-guide.md +317 -0
- package/frameworks/01-lean-canvas.md +196 -0
- package/frameworks/02-design-sprint.md +304 -0
- package/frameworks/03-foundation-sprint.md +337 -0
- package/frameworks/04-business-model-canvas.md +391 -0
- package/frameworks/05-customer-development.md +426 -0
- package/frameworks/06-jobs-to-be-done.md +358 -0
- package/frameworks/07-mom-test.md +392 -0
- package/frameworks/08-value-proposition-canvas.md +488 -0
- package/frameworks/09-javelin-board.md +428 -0
- package/frameworks/10-build-measure-learn.md +467 -0
- package/frameworks/11-mvp-approaches.md +533 -0
- package/frameworks/think-before-build.md +593 -0
- package/lib/assembler.js +197 -0
- package/lib/assembler.test.js +159 -0
- package/lib/detector.js +166 -0
- package/lib/detector.test.js +221 -0
- package/lib/packs.js +16 -0
- package/lib/resolver.js +272 -0
- package/lib/resolver.test.js +298 -0
- package/lib/worktree.sh +104 -0
- package/package.json +50 -0
- package/packs/backend-micronaut.yaml +35 -0
- package/packs/backend-nodejs.yaml +15 -0
- package/packs/backend-python.yaml +15 -0
- package/packs/core.yaml +37 -0
- package/packs/database.yaml +21 -0
- package/packs/frontend-react.yaml +24 -0
- package/packs/infrastructure.yaml +40 -0
- package/packs/ops.yaml +16 -0
- package/packs/packs.compiled.json +371 -0
- package/packs/product.yaml +22 -0
- package/packs/project-mgmt.yaml +24 -0
- package/packs/research.yaml +39 -0
- package/packs/shared-backend.yaml +14 -0
- package/packs/ux-design.yaml +21 -0
- package/rules/backend-micronaut/API_DESIGN.md +313 -0
- package/rules/backend-micronaut/BATCH_PROCESSING.md +92 -0
- package/rules/backend-micronaut/CONTROLLERS.md +388 -0
- package/rules/backend-micronaut/KOTLIN.md +414 -0
- package/rules/backend-micronaut/RETROFIT_PLACEMENT.md +290 -0
- package/rules/backend-micronaut/SERVICES_AND_BEANS.md +325 -0
- package/rules/core/NAMING_CONVENTIONS.md +208 -0
- package/rules/core/SKILL_AUTHORING.md +174 -0
- package/rules/core/TIMEZONE.md +316 -0
- package/rules/database/ORM_AND_REPO.md +289 -0
- package/rules/database/SCHEMA.md +146 -0
- package/rules/database/TRANSACTIONS.md +311 -0
- package/rules/frontend-react/FRONTEND.md +344 -0
- package/rules/infrastructure/MODULES.md +260 -0
- package/rules/infrastructure/NAMING.md +196 -0
- package/rules/infrastructure/PROVIDERS.md +309 -0
- package/rules/infrastructure/SECURITY.md +310 -0
- package/rules/infrastructure/STATE_AND_BACKEND.md +237 -0
- package/rules/infrastructure/STRUCTURE.md +234 -0
- package/rules/infrastructure/VARIABLES.md +285 -0
- package/rules/shared-backend/ARCHITECTURE.md +46 -0
- package/rules/ux-design/DESIGN_PROCESS.md +176 -0
- package/skills/api-endpoint-creator/SKILL.md +455 -0
- package/skills/api-endpoint-creator/error-handling-guide.md +244 -0
- package/skills/api-endpoint-creator/examples.md +522 -0
- package/skills/api-endpoint-creator/testing-patterns.md +302 -0
- package/skills/article-writing/SKILL.md +109 -0
- package/skills/article-writing/examples.md +59 -0
- package/skills/backend-api-design/SKILL.md +84 -0
- package/skills/backend-api-design/code-patterns.md +138 -0
- package/skills/brainstorm/SKILL.md +95 -0
- package/skills/browser-qa/SKILL.md +87 -0
- package/skills/browser-qa/playwright-snippets.md +110 -0
- package/skills/ci-cd-patterns/SKILL.md +108 -0
- package/skills/ci-cd-patterns/workflows.md +149 -0
- package/skills/competitive-teardown/SKILL.md +93 -0
- package/skills/competitive-teardown/example-analysis.md +50 -0
- package/skills/content-engine/SKILL.md +131 -0
- package/skills/content-engine/examples.md +72 -0
- package/skills/database-patterns/SKILL.md +72 -0
- package/skills/database-patterns/code-templates.md +114 -0
- package/skills/database-table-creator/SKILL.md +141 -0
- package/skills/database-table-creator/examples.md +552 -0
- package/skills/database-table-creator/kotlin-templates.md +400 -0
- package/skills/database-table-creator/migration-template.sql +68 -0
- package/skills/database-table-creator/validation-checklist.md +337 -0
- package/skills/deep-research/SKILL.md +80 -0
- package/skills/design-intelligence/SKILL.md +268 -0
- package/skills/design-workflow/SKILL.md +127 -0
- package/skills/design-workflow/checklists.md +45 -0
- package/skills/idea-validation/SKILL.md +129 -0
- package/skills/idea-validation/example-report.md +50 -0
- package/skills/investor-materials/SKILL.md +122 -0
- package/skills/investor-materials/example-outline.md +70 -0
- package/skills/investor-outreach/SKILL.md +112 -0
- package/skills/investor-outreach/examples.md +76 -0
- package/skills/kotlin-best-practices/SKILL.md +58 -0
- package/skills/kotlin-best-practices/code-patterns.md +132 -0
- package/skills/market-research/SKILL.md +99 -0
- package/skills/security-checklist/SKILL.md +65 -0
- package/skills/security-checklist/audit-reference.md +95 -0
- package/skills/service-debugging/SKILL.md +116 -0
- package/skills/service-debugging/common-issues.md +65 -0
- package/skills/startup-pipeline/SKILL.md +152 -0
- package/skills/terraform-best-practices/SKILL.md +244 -0
- package/skills/terraform-module-creator/SKILL.md +284 -0
- package/skills/terraform-review/SKILL.md +222 -0
- package/skills/terraform-security-audit/SKILL.md +280 -0
- package/skills/terraform-service-scaffold/SKILL.md +574 -0
- package/skills/testing-strategies/SKILL.md +116 -0
- package/skills/testing-strategies/examples.md +103 -0
- package/skills/testing-strategies/integration-test-setup.md +71 -0
- package/skills/ui-ux-pro-max/SKILL.md +238 -0
- package/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/skills/ui-ux-pro-max/data/colors.csv +97 -0
- package/skills/ui-ux-pro-max/data/icons.csv +101 -0
- package/skills/ui-ux-pro-max/data/landing.csv +31 -0
- package/skills/ui-ux-pro-max/data/products.csv +97 -0
- package/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/skills/ui-ux-pro-max/data/styles.csv +68 -0
- package/skills/ui-ux-pro-max/data/typography.csv +58 -0
- package/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/skills/ui-ux-pro-max/python-setup.md +146 -0
- package/skills/ui-ux-pro-max/scripts/core.py +253 -0
- package/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/skills/ui-ux-pro-max/scripts/search.py +114 -0
- package/skills/web-to-prd/SKILL.md +478 -0
- package/templates/build-config.yaml +44 -0
- package/templates/commands-config.yaml +55 -0
- package/templates/competitor-analysis.md +60 -0
- package/templates/content/AGENT_TEMPLATE.md +47 -0
- package/templates/content/COMMAND_TEMPLATE.md +27 -0
- package/templates/content/RULE_TEMPLATE.md +40 -0
- package/templates/content/SKILL_TEMPLATE.md +41 -0
- package/templates/design-config.md +105 -0
- package/templates/design-doc.md +207 -0
- package/templates/epic.md +100 -0
- package/templates/feature-spec.md +181 -0
- package/templates/idea-canvas.md +47 -0
- package/templates/implementation-plan.md +159 -0
- package/templates/prd-template.md +86 -0
- package/templates/preamble.md +89 -0
- package/templates/project-readme.md +35 -0
- package/templates/quality-gates.md +230 -0
- package/templates/spartan-config.yaml +164 -0
- package/templates/user-interview.md +69 -0
- package/templates/validation-checklist.md +108 -0
- package/templates/workflow-backend-micronaut.md +409 -0
- package/templates/workflow-frontend-react.md +233 -0
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
# Service Layer and Bean Management
|
|
2
|
+
|
|
3
|
+
## Service Layer Rules
|
|
4
|
+
|
|
5
|
+
### Core Principle
|
|
6
|
+
|
|
7
|
+
**Services fetch data. Managers persist data.**
|
|
8
|
+
|
|
9
|
+
### Services MUST NOT Call Repositories
|
|
10
|
+
|
|
11
|
+
```kotlin
|
|
12
|
+
// ❌ WRONG - Service calling repository
|
|
13
|
+
class DefaultGitHubSyncService(
|
|
14
|
+
private val commitRepository: GitHubCommitRepository, // NO!
|
|
15
|
+
private val prRepository: GitHubPullRequestRepository // NO!
|
|
16
|
+
) : GitHubSyncService {
|
|
17
|
+
|
|
18
|
+
override suspend fun syncCommits(org: String) {
|
|
19
|
+
val commits = gitHubClient.fetchCommits(org)
|
|
20
|
+
commitRepository.insert(...) // Services should NOT do this!
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ✓ CORRECT - Service returns data, Manager persists
|
|
25
|
+
class DefaultGitHubDataFetcher(
|
|
26
|
+
private val gitHubClient: GitHubGraphQLClient,
|
|
27
|
+
private val identityResolver: IdentityResolver
|
|
28
|
+
) : GitHubDataFetcher {
|
|
29
|
+
|
|
30
|
+
override suspend fun fetchCommits(org: String): Either<ClientException, List<GitHubCommitData>> {
|
|
31
|
+
val commits = gitHubClient.fetchCommits(org)
|
|
32
|
+
return commits.map { it.toData(identityResolver) }.right() // Return DTOs!
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Services Return DTOs, Not Entities
|
|
38
|
+
|
|
39
|
+
Services should return data transfer objects that represent fetched data:
|
|
40
|
+
|
|
41
|
+
```kotlin
|
|
42
|
+
// DTO returned by service
|
|
43
|
+
data class GitHubCommitData(
|
|
44
|
+
val sha: String,
|
|
45
|
+
val authorUsername: String?,
|
|
46
|
+
val employeeId: UUID?, // Resolved by service
|
|
47
|
+
val committedAt: Instant,
|
|
48
|
+
val additions: Int,
|
|
49
|
+
val deletions: Int
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
// Manager converts DTO to Entity for persistence
|
|
53
|
+
class DefaultGitHubSyncManager(...) : GitHubSyncManager {
|
|
54
|
+
|
|
55
|
+
override suspend fun syncCommits(org: String) {
|
|
56
|
+
val commitData = dataFetcher.fetchCommits(org)
|
|
57
|
+
.fold({ return it.left() }, { it })
|
|
58
|
+
|
|
59
|
+
for (data in commitData) {
|
|
60
|
+
val entity = GitHubCommitEntity(
|
|
61
|
+
sha = data.sha,
|
|
62
|
+
employeeId = data.employeeId,
|
|
63
|
+
// ...
|
|
64
|
+
)
|
|
65
|
+
commitRepository.insert(entity) // Manager does persistence
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Service Allowed Dependencies
|
|
72
|
+
|
|
73
|
+
| Allowed | Not Allowed |
|
|
74
|
+
|---------|-------------|
|
|
75
|
+
| External API clients (GitHubGraphQLClient, SlackClient) | Repositories |
|
|
76
|
+
| Identity resolvers (for mapping external IDs) | Database context |
|
|
77
|
+
| Configuration classes | Transaction management |
|
|
78
|
+
| Logging | Other managers |
|
|
79
|
+
| Token providers | |
|
|
80
|
+
|
|
81
|
+
### Manager Allowed Dependencies
|
|
82
|
+
|
|
83
|
+
| Allowed | Not Allowed |
|
|
84
|
+
|---------|-------------|
|
|
85
|
+
| Repositories | External API clients (use Services instead) |
|
|
86
|
+
| Services | Direct HTTP calls |
|
|
87
|
+
| Other managers | |
|
|
88
|
+
| Database context | |
|
|
89
|
+
| Distributed locks | |
|
|
90
|
+
|
|
91
|
+
### Data Flow Examples
|
|
92
|
+
|
|
93
|
+
#### Correct: Manager Orchestrates, Service Fetches
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
1. Controller receives sync request
|
|
97
|
+
↓
|
|
98
|
+
2. Manager.syncCommits() called
|
|
99
|
+
↓
|
|
100
|
+
3. Manager calls Service.fetchCommits()
|
|
101
|
+
↓
|
|
102
|
+
4. Service calls GitHubGraphQLClient
|
|
103
|
+
↓
|
|
104
|
+
5. Service resolves identities
|
|
105
|
+
↓
|
|
106
|
+
6. Service returns List<GitHubCommitData>
|
|
107
|
+
↓
|
|
108
|
+
7. Manager iterates data, calls Repository.insert()
|
|
109
|
+
↓
|
|
110
|
+
8. Manager updates sync cursor
|
|
111
|
+
↓
|
|
112
|
+
9. Manager returns SyncResult to Controller
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### Wrong: Service Does Everything
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
1. Controller receives sync request
|
|
119
|
+
↓
|
|
120
|
+
2. Service.syncCommits() called
|
|
121
|
+
↓
|
|
122
|
+
3. Service calls GitHubGraphQLClient
|
|
123
|
+
↓
|
|
124
|
+
4. Service calls Repository.insert() ← VIOLATION!
|
|
125
|
+
↓
|
|
126
|
+
5. Service returns SyncResult
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Naming Conventions
|
|
130
|
+
|
|
131
|
+
| Layer | Interface Suffix | Implementation Prefix | Example |
|
|
132
|
+
|-------|------------------|----------------------|---------|
|
|
133
|
+
| Service | `*Fetcher` or `*Service` (readonly) | `Default*` | `GitHubDataFetcher` / `DefaultGitHubDataFetcher` |
|
|
134
|
+
| Manager | `*Manager` | `Default*` | `GitHubSyncManager` / `DefaultGitHubSyncManager` |
|
|
135
|
+
| Repository | `*Repository` | `Default*` | `GitHubCommitRepository` / `DefaultGitHubCommitRepository` |
|
|
136
|
+
|
|
137
|
+
### When to Use Service vs Manager
|
|
138
|
+
|
|
139
|
+
#### Use Service (Fetcher) When:
|
|
140
|
+
- Calling external APIs (GitHub, Slack, Notion, Atlas)
|
|
141
|
+
- Transforming external data formats
|
|
142
|
+
- Resolving identities (external ID → employee_id)
|
|
143
|
+
- No database writes needed
|
|
144
|
+
|
|
145
|
+
#### Use Manager When:
|
|
146
|
+
- Orchestrating multiple operations
|
|
147
|
+
- Persisting data to database
|
|
148
|
+
- Managing transactions
|
|
149
|
+
- Business logic that needs DB state
|
|
150
|
+
- Distributed locking
|
|
151
|
+
|
|
152
|
+
### Refactoring Guide: Service Calling Repositories
|
|
153
|
+
|
|
154
|
+
When you find a Service calling repositories:
|
|
155
|
+
|
|
156
|
+
1. **Create a new Manager interface** that defines the operation
|
|
157
|
+
2. **Create a new Fetcher interface** for the external data fetch
|
|
158
|
+
3. **Move DB operations to Manager**
|
|
159
|
+
4. **Move API calls to Fetcher**
|
|
160
|
+
5. **Manager calls Fetcher, then Repository**
|
|
161
|
+
|
|
162
|
+
#### Before (Wrong)
|
|
163
|
+
```kotlin
|
|
164
|
+
class DefaultSyncService(
|
|
165
|
+
private val apiClient: ExternalApiClient,
|
|
166
|
+
private val repository: DataRepository // ← Problem
|
|
167
|
+
) : SyncService {
|
|
168
|
+
|
|
169
|
+
override suspend fun sync() {
|
|
170
|
+
val data = apiClient.fetch()
|
|
171
|
+
repository.insert(data) // ← Service doing persistence
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
#### After (Correct)
|
|
177
|
+
```kotlin
|
|
178
|
+
// Service: Fetch only
|
|
179
|
+
class DefaultDataFetcher(
|
|
180
|
+
private val apiClient: ExternalApiClient
|
|
181
|
+
) : DataFetcher {
|
|
182
|
+
|
|
183
|
+
override suspend fun fetch(): List<DataDTO> {
|
|
184
|
+
return apiClient.fetch().map { it.toDTO() }
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Manager: Orchestrate and persist
|
|
189
|
+
class DefaultSyncManager(
|
|
190
|
+
private val fetcher: DataFetcher,
|
|
191
|
+
private val repository: DataRepository
|
|
192
|
+
) : SyncManager {
|
|
193
|
+
|
|
194
|
+
override suspend fun sync() {
|
|
195
|
+
val data = fetcher.fetch()
|
|
196
|
+
repository.insertAll(data.map { it.toEntity() })
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Bean Management (3-Tier Hierarchy)
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
Application Beans (top) — business logic, depends on module + shared
|
|
207
|
+
↓
|
|
208
|
+
Module Beans (middle) — reusable module components, depends on shared only
|
|
209
|
+
↓
|
|
210
|
+
Shared Beans (bottom) — infrastructure (DB, Redis, AWS), no dependencies
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Bean Creation Rules
|
|
214
|
+
|
|
215
|
+
1. **Always use `@Factory` classes** — never `@Singleton` on implementations directly
|
|
216
|
+
2. **Depend on interfaces**, not concrete classes
|
|
217
|
+
3. **`@Named`** for multiple implementations of same interface
|
|
218
|
+
4. **`@Primary`** for default implementation
|
|
219
|
+
5. **`@Requires`** for conditional bean creation
|
|
220
|
+
6. **No circular dependencies** — fix with interface extraction (see below)
|
|
221
|
+
|
|
222
|
+
```kotlin
|
|
223
|
+
// CORRECT — Factory pattern
|
|
224
|
+
@Factory
|
|
225
|
+
class UserFactory {
|
|
226
|
+
@Singleton
|
|
227
|
+
fun provideUserRepository(db: DatabaseContext): UserRepository {
|
|
228
|
+
return DefaultUserRepository(db)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// WRONG — @Singleton on implementation
|
|
233
|
+
@Singleton
|
|
234
|
+
class DefaultUserRepository(private val db: DatabaseContext) : UserRepository
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Bean Testing
|
|
238
|
+
|
|
239
|
+
Use `@Replaces` to swap beans at any tier in tests:
|
|
240
|
+
```kotlin
|
|
241
|
+
@Singleton
|
|
242
|
+
@Replaces(DatabaseContext::class)
|
|
243
|
+
fun testDatabaseContext(): DatabaseContext = InMemoryDatabaseContext()
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Bean Scope
|
|
247
|
+
|
|
248
|
+
- `@Singleton` — default, use this for most beans
|
|
249
|
+
- `@Prototype` — rare, new instance per injection
|
|
250
|
+
- `@RequestScope` — per HTTP request, controllers only
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Enforcement Checklists
|
|
255
|
+
|
|
256
|
+
### Service Layer Checklist
|
|
257
|
+
|
|
258
|
+
- [ ] Services have NO repository imports
|
|
259
|
+
- [ ] Services have NO `insert`, `update`, `delete` calls
|
|
260
|
+
- [ ] Services return DTOs, not entities
|
|
261
|
+
- [ ] Managers handle all DB operations
|
|
262
|
+
- [ ] Managers wrap DB operations in transactions
|
|
263
|
+
- [ ] External API calls go through Services, not Managers
|
|
264
|
+
|
|
265
|
+
### Bean Checklist
|
|
266
|
+
|
|
267
|
+
- [ ] Determine tier: Shared / Module / Application
|
|
268
|
+
- [ ] Create `@Factory` class with right naming
|
|
269
|
+
- [ ] Define bean method with `@Singleton` (or right scope)
|
|
270
|
+
- [ ] Inject dependencies via method parameters
|
|
271
|
+
- [ ] Verify dependency direction (no upward dependencies)
|
|
272
|
+
- [ ] Return interface type, not concrete implementation
|
|
273
|
+
- [ ] Use `@Named` for multiple implementations
|
|
274
|
+
- [ ] Use `@Primary` for default implementation
|
|
275
|
+
- [ ] Use `@Requires` for conditional creation
|
|
276
|
+
- [ ] No circular dependencies (see "Breaking Circular Dependencies" below)
|
|
277
|
+
- [ ] Bean is testable (can be replaced with `@Replaces`)
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## Breaking Circular Dependencies
|
|
282
|
+
|
|
283
|
+
`Provider<T>` for lazy initialization is a code smell for a circular dependency. Fix the root cause.
|
|
284
|
+
|
|
285
|
+
### The Problem
|
|
286
|
+
|
|
287
|
+
```
|
|
288
|
+
ProjectManager → WorkspaceManager → SomeService → ProjectManager (cycle!)
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
**Bad workaround:**
|
|
292
|
+
```kotlin
|
|
293
|
+
// Provider<T> hides the cycle — DON'T DO THIS
|
|
294
|
+
class DefaultProjectManager(
|
|
295
|
+
private val workspaceManagerProvider: Provider<WorkspaceManager>, // Lazy
|
|
296
|
+
) : ProjectManager
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### The Fix: Interface Extraction + Layer Split
|
|
300
|
+
|
|
301
|
+
**Step 1** — Find the shared functionality causing the cycle.
|
|
302
|
+
|
|
303
|
+
**Step 2** — Extract it into a focused interface:
|
|
304
|
+
```kotlin
|
|
305
|
+
interface ProjectThumbnailResolver {
|
|
306
|
+
suspend fun resolveProjectThumbnailUrl(entity: ProjectEntity): String?
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
**Step 3** — Move the logic to a new component with lower-level dependencies:
|
|
311
|
+
```kotlin
|
|
312
|
+
class DefaultProjectThumbnailResolver(
|
|
313
|
+
private val storageService: StorageService // No cycle
|
|
314
|
+
) : ProjectThumbnailResolver { ... }
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
**Step 4** — Inject directly, no Provider needed:
|
|
318
|
+
```kotlin
|
|
319
|
+
class DefaultProjectManager(
|
|
320
|
+
private val workspaceManager: WorkspaceManager, // Direct injection
|
|
321
|
+
private val projectThumbnailResolver: ProjectThumbnailResolver // New!
|
|
322
|
+
) : ProjectManager
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
**Rule:** If you reach for `Provider<T>`, stop. Extract the shared functionality into its own interface at a lower layer.
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# Naming Conventions
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This document defines the naming conventions used across different layers of the stack. Consistent naming reduces bugs, makes the codebase easier to understand, and helps everyone move faster.
|
|
6
|
+
|
|
7
|
+
## Convention Summary
|
|
8
|
+
|
|
9
|
+
| Layer | Convention | Example |
|
|
10
|
+
|-------|-----------|---------|
|
|
11
|
+
| **Database (SQL)** | `snake_case` | `points_balance`, `user_id`, `created_at` |
|
|
12
|
+
| **Kotlin Code** | `camelCase` | `pointsBalance`, `userId`, `createdAt` |
|
|
13
|
+
| **API JSON (over wire)** | `snake_case` | `"points_balance"`, `"user_id"` |
|
|
14
|
+
| **TypeScript Code** | `camelCase` | `pointsBalance`, `userId`, `createdAt` |
|
|
15
|
+
|
|
16
|
+
## How It Works
|
|
17
|
+
|
|
18
|
+
### Backend (Kotlin + Micronaut)
|
|
19
|
+
|
|
20
|
+
**Jackson ObjectMapper** is configured globally with `SNAKE_CASE` naming strategy:
|
|
21
|
+
|
|
22
|
+
```kotlin
|
|
23
|
+
// In your Jackson configuration module
|
|
24
|
+
fun ObjectMapper.configured(): ObjectMapper {
|
|
25
|
+
propertyNamingStrategy = PropertyNamingStrategies.SNAKE_CASE
|
|
26
|
+
// ... other configuration
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
This means:
|
|
31
|
+
- **Write Kotlin code in `camelCase`** (idiomatic Kotlin)
|
|
32
|
+
- **Jackson automatically converts to `snake_case`** when serializing to JSON
|
|
33
|
+
- **Jackson automatically converts from `snake_case`** when deserializing JSON
|
|
34
|
+
|
|
35
|
+
**Example:**
|
|
36
|
+
```kotlin
|
|
37
|
+
// Kotlin DTO (use camelCase)
|
|
38
|
+
@Serdeable
|
|
39
|
+
data class CreateRecognitionRequest(
|
|
40
|
+
val receiverIds: List<UUID>, // camelCase in code
|
|
41
|
+
val coreValueIds: List<UUID>, // camelCase in code
|
|
42
|
+
val points: Int,
|
|
43
|
+
val message: String
|
|
44
|
+
)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**JSON sent/received (automatic snake_case):**
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"receiver_ids": ["uuid-1", "uuid-2"],
|
|
51
|
+
"core_value_ids": ["uuid-3"],
|
|
52
|
+
"points": 10,
|
|
53
|
+
"message": "Great work!"
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Frontend (TypeScript + React)
|
|
58
|
+
|
|
59
|
+
**Axios interceptors** automatically convert between conventions:
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
// src/lib/case-converter.ts
|
|
63
|
+
export function toSnakeCase<T>(obj: T): T // camelCase -> snake_case
|
|
64
|
+
export function toCamelCase<T>(obj: T): T // snake_case -> camelCase
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
// src/lib/api.ts
|
|
69
|
+
// Request interceptor: Convert camelCase to snake_case before sending
|
|
70
|
+
api.interceptors.request.use((config) => {
|
|
71
|
+
if (config.data && typeof config.data === 'object') {
|
|
72
|
+
config.data = toSnakeCase(config.data)
|
|
73
|
+
}
|
|
74
|
+
return config
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
// Response interceptor: Convert snake_case to camelCase after receiving
|
|
78
|
+
api.interceptors.response.use((response) => {
|
|
79
|
+
if (response.data && typeof response.data === 'object') {
|
|
80
|
+
response.data = toCamelCase(response.data)
|
|
81
|
+
}
|
|
82
|
+
return response
|
|
83
|
+
})
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
This means:
|
|
87
|
+
- **Write TypeScript code in `camelCase`** (idiomatic JavaScript/TypeScript)
|
|
88
|
+
- **Interceptors automatically convert to `snake_case`** when sending requests
|
|
89
|
+
- **Interceptors automatically convert to `camelCase`** when receiving responses
|
|
90
|
+
|
|
91
|
+
**Example:**
|
|
92
|
+
```typescript
|
|
93
|
+
// TypeScript interface (use camelCase)
|
|
94
|
+
export interface CreateRecognitionRequest {
|
|
95
|
+
receiverIds: string[] // camelCase in code
|
|
96
|
+
coreValueIds: string[] // camelCase in code
|
|
97
|
+
points: number
|
|
98
|
+
message: string
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Usage - just use camelCase everywhere
|
|
102
|
+
const data: CreateRecognitionRequest = {
|
|
103
|
+
receiverIds: ['uuid-1', 'uuid-2'],
|
|
104
|
+
coreValueIds: ['uuid-3'],
|
|
105
|
+
points: 10,
|
|
106
|
+
message: 'Great work!'
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Interceptor automatically sends as snake_case
|
|
110
|
+
await api.post('/recognitions', data)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Database (PostgreSQL)
|
|
114
|
+
|
|
115
|
+
All database objects use `snake_case`:
|
|
116
|
+
|
|
117
|
+
```sql
|
|
118
|
+
-- Tables (plural, snake_case)
|
|
119
|
+
CREATE TABLE users (...)
|
|
120
|
+
CREATE TABLE core_values (...)
|
|
121
|
+
CREATE TABLE recognition_receivers (...)
|
|
122
|
+
|
|
123
|
+
-- Columns (snake_case)
|
|
124
|
+
id UUID PRIMARY KEY
|
|
125
|
+
points_balance INTEGER
|
|
126
|
+
allowance_balance INTEGER
|
|
127
|
+
created_at TIMESTAMP
|
|
128
|
+
updated_at TIMESTAMP
|
|
129
|
+
deleted_at TIMESTAMP
|
|
130
|
+
|
|
131
|
+
-- Indexes (idx_tablename_column)
|
|
132
|
+
CREATE INDEX idx_users_email ON users(email)
|
|
133
|
+
CREATE INDEX idx_recognitions_giver_id ON recognitions(giver_id)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## CRITICAL: @QueryValue Must Use Explicit snake_case Names
|
|
137
|
+
|
|
138
|
+
**The frontend axios interceptor converts ALL query params to `snake_case` (e.g., `projectId` → `project_id`). But Micronaut's `@QueryValue` does NOT auto-convert — it matches the EXACT param name from the URL.**
|
|
139
|
+
|
|
140
|
+
**Jackson's SNAKE_CASE config only affects JSON body serialization/deserialization, NOT query parameter binding.**
|
|
141
|
+
|
|
142
|
+
This means ALL multi-word `@QueryValue` params MUST have explicit snake_case names:
|
|
143
|
+
|
|
144
|
+
```kotlin
|
|
145
|
+
// ✅ CORRECT — explicit snake_case name matches what frontend sends
|
|
146
|
+
@QueryValue("project_id") projectId: UUID,
|
|
147
|
+
@QueryValue("alert_id") alertId: UUID,
|
|
148
|
+
@QueryValue("repo_full_name") repoFullName: String,
|
|
149
|
+
|
|
150
|
+
// ❌ WRONG — Micronaut expects ?projectId=xxx but frontend sends ?project_id=xxx
|
|
151
|
+
@QueryValue projectId: UUID,
|
|
152
|
+
@QueryValue alertId: UUID,
|
|
153
|
+
@QueryValue repoFullName: String,
|
|
154
|
+
|
|
155
|
+
// ✅ OK — single-word params don't need explicit name (no case conversion needed)
|
|
156
|
+
@QueryValue status: String,
|
|
157
|
+
@QueryValue limit: Int,
|
|
158
|
+
@QueryValue id: UUID,
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Rule: If a `@QueryValue` param name has more than one word (contains uppercase letters), ALWAYS add explicit `@QueryValue("snake_case_name")`.**
|
|
162
|
+
|
|
163
|
+
## Rules
|
|
164
|
+
|
|
165
|
+
### DO
|
|
166
|
+
|
|
167
|
+
1. **Use `camelCase` in all Kotlin code** (properties, variables, function parameters)
|
|
168
|
+
2. **Use `camelCase` in all TypeScript code** (interfaces, variables, function parameters)
|
|
169
|
+
3. **Use `snake_case` in all SQL** (tables, columns, indexes)
|
|
170
|
+
4. **Let the framework handle conversion** (Jackson for backend, Axios interceptors for frontend)
|
|
171
|
+
5. **ALWAYS add explicit snake_case name to multi-word `@QueryValue` params**
|
|
172
|
+
|
|
173
|
+
### DON'T
|
|
174
|
+
|
|
175
|
+
1. **DON'T manually convert case in API calls** - interceptors handle this
|
|
176
|
+
2. **DON'T use `@JsonProperty` unless mapping external APIs** (like Google OAuth)
|
|
177
|
+
3. **DON'T mix conventions within the same layer**
|
|
178
|
+
4. **DON'T use `snake_case` in Kotlin or TypeScript code**
|
|
179
|
+
5. **DON'T use `camelCase` in SQL or JSON API contracts**
|
|
180
|
+
6. **DON'T use bare `@QueryValue` for multi-word param names** — always add explicit snake_case
|
|
181
|
+
|
|
182
|
+
### When to Use `@JsonProperty`
|
|
183
|
+
|
|
184
|
+
Only use `@JsonProperty` annotation when:
|
|
185
|
+
- Mapping responses from **external APIs** that don't follow your conventions
|
|
186
|
+
- Field names must differ from the automatic conversion for **backwards compatibility**
|
|
187
|
+
|
|
188
|
+
```kotlin
|
|
189
|
+
// ONLY for external APIs (like Google OAuth)
|
|
190
|
+
@Serdeable
|
|
191
|
+
data class GoogleTokenResponse(
|
|
192
|
+
@JsonProperty("access_token")
|
|
193
|
+
val accessToken: String,
|
|
194
|
+
@JsonProperty("expires_in")
|
|
195
|
+
val expiresIn: Int,
|
|
196
|
+
@JsonProperty("id_token")
|
|
197
|
+
val idToken: String?
|
|
198
|
+
)
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Code Review Checklist
|
|
202
|
+
|
|
203
|
+
- [ ] No manual `snake_case` in Kotlin DTO properties
|
|
204
|
+
- [ ] No manual `snake_case` in TypeScript interfaces
|
|
205
|
+
- [ ] No manual case conversion in API calls (let interceptors handle it)
|
|
206
|
+
- [ ] `@JsonProperty` only used for external API mappings
|
|
207
|
+
- [ ] Database columns and tables use `snake_case`
|
|
208
|
+
- [ ] Exposed Table definitions match database column names
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# Skill Authoring Rules
|
|
2
|
+
|
|
3
|
+
Rules for creating and modifying skills in the Spartan AI Toolkit. Follow these when writing new skills or improving existing ones.
|
|
4
|
+
|
|
5
|
+
## Frontmatter (REQUIRED)
|
|
6
|
+
|
|
7
|
+
Every SKILL.md must have these fields:
|
|
8
|
+
|
|
9
|
+
```yaml
|
|
10
|
+
---
|
|
11
|
+
name: skill-name
|
|
12
|
+
description: "What it does. Use when [trigger conditions]."
|
|
13
|
+
allowed_tools:
|
|
14
|
+
- Read
|
|
15
|
+
- Write
|
|
16
|
+
# ... tools the skill needs
|
|
17
|
+
---
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### Description Must Be a Trigger
|
|
21
|
+
|
|
22
|
+
The description tells the model WHEN to activate the skill, not WHAT the skill is.
|
|
23
|
+
|
|
24
|
+
| Bad (summary) | Good (trigger) |
|
|
25
|
+
|----------------|----------------|
|
|
26
|
+
| "Database design patterns including schemas and migrations" | "Database design patterns. Use when creating tables, writing migrations, or implementing repositories." |
|
|
27
|
+
| "The full startup pipeline from brainstorm to outreach" | "Coordinates the full startup pipeline. Use when the user starts a new idea project or references stages/gates." |
|
|
28
|
+
|
|
29
|
+
**Rule:** Every description must contain "Use when" followed by specific trigger conditions.
|
|
30
|
+
|
|
31
|
+
### allowed_tools Must Match the Skill's Needs
|
|
32
|
+
|
|
33
|
+
| Skill type | Typical tools |
|
|
34
|
+
|------------|--------------|
|
|
35
|
+
| Code/backend (writes files) | Read, Write, Edit, Glob, Grep, Bash |
|
|
36
|
+
| Research/analysis (web searches) | WebSearch, WebFetch, Read |
|
|
37
|
+
| Content/writing (creates + researches) | Read, Write, WebSearch |
|
|
38
|
+
| Review/audit (reads only) | Read, Glob, Grep |
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Folder Structure (Skills Are Folders, Not Files)
|
|
43
|
+
|
|
44
|
+
A skill is a directory, not just a markdown file. Use the file system for progressive disclosure.
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
toolkit/skills/my-skill/
|
|
48
|
+
SKILL.md # Main definition — short, high-level (required)
|
|
49
|
+
code-patterns.md # Code examples (if code-heavy skill)
|
|
50
|
+
examples.md # Good/bad examples (if teaching a style)
|
|
51
|
+
checklists.md # Review checklists (if audit/review skill)
|
|
52
|
+
workflows.md # Ready-to-use templates (if scaffolding skill)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### When to Split Into Multiple Files
|
|
56
|
+
|
|
57
|
+
| SKILL.md is... | Action |
|
|
58
|
+
|-----------------|--------|
|
|
59
|
+
| Under 100 lines | One file is fine |
|
|
60
|
+
| 100-150 lines with code blocks | Split code into a reference file |
|
|
61
|
+
| 150+ lines | Must split — too much for one read |
|
|
62
|
+
|
|
63
|
+
### SKILL.md Should Be the Summary
|
|
64
|
+
|
|
65
|
+
Keep SKILL.md short (60-120 lines). It should have:
|
|
66
|
+
- Frontmatter
|
|
67
|
+
- "When to Use" section
|
|
68
|
+
- Key rules and principles (without detailed code)
|
|
69
|
+
- Gotchas section
|
|
70
|
+
- References to supporting files
|
|
71
|
+
|
|
72
|
+
Move into supporting files:
|
|
73
|
+
- Detailed code templates and examples
|
|
74
|
+
- Long checklists
|
|
75
|
+
- Good/bad comparisons
|
|
76
|
+
- Ready-to-use templates
|
|
77
|
+
|
|
78
|
+
Reference with: `> See code-patterns.md for complete implementation templates.`
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Gotchas Section (REQUIRED)
|
|
83
|
+
|
|
84
|
+
Every skill must have a `## Gotchas` section. This is the highest-value content in any skill.
|
|
85
|
+
|
|
86
|
+
### Format
|
|
87
|
+
|
|
88
|
+
```markdown
|
|
89
|
+
## Gotchas
|
|
90
|
+
|
|
91
|
+
- **Bold lead-in sentence.** Explanation of why this matters and what to do instead.
|
|
92
|
+
- **Another gotcha.** Details.
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### What Makes a Good Gotcha
|
|
96
|
+
|
|
97
|
+
- Specific failure patterns Claude hits when using this skill
|
|
98
|
+
- Things that look right but are wrong
|
|
99
|
+
- Common mistakes users make in this domain
|
|
100
|
+
- Counter-intuitive rules that violate defaults
|
|
101
|
+
|
|
102
|
+
### What is NOT a Gotcha
|
|
103
|
+
|
|
104
|
+
- General best practices (put those in Rules)
|
|
105
|
+
- Obvious things Claude already knows
|
|
106
|
+
- Restating the instructions in negative form
|
|
107
|
+
|
|
108
|
+
**Minimum 3 gotchas per skill. Build this section over time as you find new failure patterns.**
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Content Rules
|
|
113
|
+
|
|
114
|
+
### Don't State the Obvious
|
|
115
|
+
|
|
116
|
+
Claude already knows how to code, research, and write. Focus on information that pushes Claude OUT of its normal patterns.
|
|
117
|
+
|
|
118
|
+
| Bad (obvious) | Good (non-obvious) |
|
|
119
|
+
|----------------|---------------------|
|
|
120
|
+
| "Use proper error handling" | "`!!` is banned — use `?.`, `?:`, or null check" |
|
|
121
|
+
| "Write clean code" | "Don't add docstrings to code you didn't change" |
|
|
122
|
+
| "Research thoroughly" | "Press releases aren't research — cross-check with third-party sources" |
|
|
123
|
+
|
|
124
|
+
### Give Claude Flexibility
|
|
125
|
+
|
|
126
|
+
Tell Claude WHAT to check and WHY, not exact steps for every situation. Skills are reused across many contexts — being too specific makes them brittle.
|
|
127
|
+
|
|
128
|
+
| Bad (railroading) | Good (flexible) |
|
|
129
|
+
|---------------------|------------------|
|
|
130
|
+
| "Step 1: Open file X. Step 2: Find line Y. Step 3: Change to Z." | "Check the controller for @ExecuteOn annotation. If missing, add it." |
|
|
131
|
+
|
|
132
|
+
### Use Examples Over Instructions
|
|
133
|
+
|
|
134
|
+
A good/bad example teaches more than a paragraph of rules. When possible, show rather than tell.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Config Pattern (for Stateful Skills)
|
|
139
|
+
|
|
140
|
+
Skills that run repeatedly for the same user should store preferences:
|
|
141
|
+
|
|
142
|
+
```json
|
|
143
|
+
// content-config.json in the project root
|
|
144
|
+
{
|
|
145
|
+
"defaultPlatforms": ["x", "linkedin"],
|
|
146
|
+
"brandVoice": "direct and technical",
|
|
147
|
+
"audience": "developers"
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Read config at skill start. Skip setup questions for configured fields.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Naming
|
|
156
|
+
|
|
157
|
+
| Type | Convention | Example |
|
|
158
|
+
|------|-----------|---------|
|
|
159
|
+
| Skill directory | `kebab-case` | `ci-cd-patterns/` |
|
|
160
|
+
| Main file | `SKILL.md` (always) | `SKILL.md` |
|
|
161
|
+
| Supporting files | `kebab-case.md` | `code-patterns.md` |
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Checklist: Before Shipping a Skill
|
|
166
|
+
|
|
167
|
+
- [ ] Frontmatter has `name`, `description` (with trigger), and `allowed_tools`
|
|
168
|
+
- [ ] Description says "Use when..." with specific conditions
|
|
169
|
+
- [ ] SKILL.md is under 120 lines (split if longer)
|
|
170
|
+
- [ ] Has a `## Gotchas` section with 3+ items
|
|
171
|
+
- [ ] Code-heavy content is in supporting files, not inline
|
|
172
|
+
- [ ] Examples show good AND bad patterns where applicable
|
|
173
|
+
- [ ] Doesn't restate things Claude already knows
|
|
174
|
+
- [ ] Gives Claude flexibility — principles over exact steps
|