@softspark/ai-toolkit 2.11.0 → 3.0.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.
Files changed (108) hide show
  1. package/AGENTS.md +21 -21
  2. package/CHANGELOG.md +62 -0
  3. package/README.md +16 -9
  4. package/app/.claude-plugin/plugin.json +1 -1
  5. package/app/agents/meta-architect.md +44 -0
  6. package/app/skills/agent-creator/SKILL.md +22 -6
  7. package/app/skills/analyze/SKILL.md +21 -1
  8. package/app/skills/api-patterns/SKILL.md +27 -0
  9. package/app/skills/app-builder/SKILL.md +24 -0
  10. package/app/skills/architecture-audit/SKILL.md +24 -0
  11. package/app/skills/architecture-decision/SKILL.md +24 -0
  12. package/app/skills/biz-scan/SKILL.md +24 -0
  13. package/app/skills/brand-voice/SKILL.md +36 -0
  14. package/app/skills/briefing/SKILL.md +41 -1
  15. package/app/skills/build/SKILL.md +24 -1
  16. package/app/skills/chaos/SKILL.md +22 -1
  17. package/app/skills/ci/SKILL.md +22 -1
  18. package/app/skills/ci-cd-patterns/SKILL.md +25 -0
  19. package/app/skills/command-creator/SKILL.md +31 -2
  20. package/app/skills/content-moderation-patterns/SKILL.md +25 -0
  21. package/app/skills/database-patterns/SKILL.md +25 -0
  22. package/app/skills/debug/SKILL.md +23 -1
  23. package/app/skills/design-engineering/SKILL.md +25 -0
  24. package/app/skills/docker-devops/SKILL.md +26 -0
  25. package/app/skills/ecommerce-patterns/SKILL.md +26 -0
  26. package/app/skills/evaluate/SKILL.md +22 -1
  27. package/app/skills/evolve/SKILL.md +25 -0
  28. package/app/skills/explain/SKILL.md +26 -1
  29. package/app/skills/explore/SKILL.md +25 -0
  30. package/app/skills/fix/SKILL.md +26 -1
  31. package/app/skills/git-mastery/SKILL.md +26 -0
  32. package/app/skills/grill-me/SKILL.md +22 -7
  33. package/app/skills/health/SKILL.md +22 -1
  34. package/app/skills/hipaa-validate/SKILL.md +25 -8
  35. package/app/skills/hook-creator/SKILL.md +107 -14
  36. package/app/skills/index/SKILL.md +22 -1
  37. package/app/skills/instinct-review/SKILL.md +25 -1
  38. package/app/skills/introspect/SKILL.md +26 -1
  39. package/app/skills/lint/SKILL.md +27 -1
  40. package/app/skills/mcp-builder/SKILL.md +27 -0
  41. package/app/skills/mem-search/SKILL.md +40 -0
  42. package/app/skills/migrate/SKILL.md +27 -1
  43. package/app/skills/migration-patterns/SKILL.md +26 -0
  44. package/app/skills/night-watch/SKILL.md +22 -1
  45. package/app/skills/observability-patterns/SKILL.md +26 -0
  46. package/app/skills/onboard/SKILL.md +22 -1
  47. package/app/skills/panic/SKILL.md +21 -1
  48. package/app/skills/performance-profiling/SKILL.md +34 -0
  49. package/app/skills/persona/SKILL.md +21 -4
  50. package/app/skills/plan/SKILL.md +26 -0
  51. package/app/skills/plan-writing/SKILL.md +26 -0
  52. package/app/skills/plugin-creator/SKILL.md +23 -6
  53. package/app/skills/pr/SKILL.md +24 -1
  54. package/app/skills/prd-to-issues/SKILL.md +22 -6
  55. package/app/skills/prd-to-plan/SKILL.md +22 -4
  56. package/app/skills/predict/SKILL.md +25 -0
  57. package/app/skills/qa-session/SKILL.md +23 -7
  58. package/app/skills/rag-patterns/SKILL.md +26 -0
  59. package/app/skills/refactor/SKILL.md +26 -0
  60. package/app/skills/refactor-plan/SKILL.md +23 -6
  61. package/app/skills/rollback/SKILL.md +27 -1
  62. package/app/skills/security-patterns/SKILL.md +27 -0
  63. package/app/skills/skill-audit/SKILL.md +22 -5
  64. package/app/skills/skill-creator/SKILL.md +58 -13
  65. package/app/skills/swift-patterns/SKILL.md +27 -107
  66. package/app/skills/swift-patterns/reference/frameworks.md +111 -0
  67. package/app/skills/test/SKILL.md +23 -1
  68. package/app/skills/testing-patterns/SKILL.md +26 -0
  69. package/app/skills/triage-issue/SKILL.md +22 -4
  70. package/app/skills/ubiquitous-language/SKILL.md +23 -8
  71. package/benchmarks/ecosystem-doctor-snapshot.json +395 -0
  72. package/kb/history/completed/deep-coverage-v3-20260423.md +160 -0
  73. package/kb/history/completed/ecosystem-deep-sweep-20260423.md +273 -0
  74. package/kb/procedures/ecosystem-sync-sop.md +255 -0
  75. package/kb/procedures/maintenance-sop.md +13 -2
  76. package/kb/procedures/release-preparation-sop.md +91 -12
  77. package/kb/procedures/release-verification-sop.md +24 -6
  78. package/kb/reference/global-install-model.md +15 -2
  79. package/kb/reference/supported-tools-registry.md +229 -0
  80. package/llms-full.txt +1105 -43
  81. package/llms.txt +4 -0
  82. package/manifest.json +1 -1
  83. package/package.json +4 -1
  84. package/scripts/ecosystem_doctor.py +348 -0
  85. package/scripts/ecosystem_tools.json +500 -0
  86. package/scripts/evaluate_skills.py +84 -0
  87. package/scripts/generate_aider_conf.py +26 -1
  88. package/scripts/generate_antigravity.py +77 -8
  89. package/scripts/generate_augment_agents.py +161 -0
  90. package/scripts/generate_augment_commands.py +160 -0
  91. package/scripts/generate_augment_hooks.py +162 -0
  92. package/scripts/generate_augment_skills.py +98 -0
  93. package/scripts/generate_cline_rules.py +96 -9
  94. package/scripts/generate_codex_hooks.py +13 -2
  95. package/scripts/generate_codex_skills.py +195 -0
  96. package/scripts/generate_copilot.py +296 -18
  97. package/scripts/generate_cursor_agents.py +144 -0
  98. package/scripts/generate_cursor_hooks.py +155 -0
  99. package/scripts/generate_cursor_mdc.py +20 -8
  100. package/scripts/generate_gemini_commands.py +158 -0
  101. package/scripts/generate_gemini_hooks.py +159 -0
  102. package/scripts/generate_gemini_skills.py +98 -0
  103. package/scripts/generate_roo_modes.py +42 -1
  104. package/scripts/generate_windsurf_hooks.py +143 -0
  105. package/scripts/generate_windsurf_rules.py +162 -10
  106. package/scripts/install.py +11 -2
  107. package/scripts/install_steps/ai_tools.py +120 -5
  108. package/scripts/validate.py +20 -3
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: rollback
3
- description: "Roll back a deployment safely with verification"
3
+ description: "Roll back a git commit, database migration, or deployment to a previous known-good state with safety checks and health verification. Use when the user wants to revert recent changes safely — not to undo local edits or halt the whole system."
4
4
  effort: medium
5
5
  disable-model-invocation: true
6
6
  argument-hint: "[target: git/db/deploy]"
@@ -85,3 +85,29 @@ Before any rollback:
85
85
  ```
86
86
 
87
87
  > **CRITICAL: Always confirm with the user before executing destructive rollback operations.**
88
+
89
+ ## Rules
90
+
91
+ - **MUST** confirm the current state AND the target state before rolling back — surface the diff in plain English
92
+ - **MUST** verify a recent backup exists (for DB rollbacks) or explicitly warn the user that none was found
93
+ - **NEVER** roll back without an explicit "yes" from the user — rollbacks are irreversible in the user-experience sense even when technically reversible
94
+ - **NEVER** `git reset --hard` on a branch others have pulled from — it rewrites shared history
95
+ - **CRITICAL**: after any rollback, run a health check (`/health` or the project's equivalent) to confirm the target state is stable — a "successful" rollback to a broken baseline is worse than the original state
96
+ - **MANDATORY**: log the rollback with timestamp, scope, and reason — post-mortems need this trail
97
+
98
+ ## Gotchas
99
+
100
+ - `git revert` creates a **new commit** that undoes the target commit. The reverted commit is still in history — if the target commit was sensitive (secret, PII), revert alone does not remove it. Use history rewriting tools for that.
101
+ - Database migration rollbacks sometimes **lose data**. A forward migration that added a NOT NULL column with a default, then populated it with user data, cannot restore the column contents on rollback — the data is gone.
102
+ - Kubernetes `kubectl rollout undo` rolls back to the previous ReplicaSet, not to a specific version. If you need "rollback to v1.2.3 specifically", track deployments by image tag and use `kubectl set image`, not `rollout undo`.
103
+ - Heroku and similar PaaS platforms `rollback` restores the slug but not environment config that changed after the rollback target was built — new env vars or add-ons may break the rolled-back version.
104
+ - `git reset --soft` preserves staged changes, `--mixed` (default) preserves working tree, `--hard` discards both. Wrong flag = lost work; always state the flag explicitly in the confirmation prompt.
105
+ - Restoring a DB backup on top of an active database can cause data loss between the backup time and the restore time. Take a fresh snapshot before the restore, even when rolling back — the current (broken) state might contain post-backup user writes.
106
+
107
+ ## When NOT to Use
108
+
109
+ - For emergency halt of all agent activity — use `/panic`
110
+ - For undoing local uncommitted edits — use `git checkout` directly, not this skill
111
+ - For an incident with user-facing impact — use `/workflow incident-response` for coordinated response
112
+ - For planned schema changes — use `/migrate` with a forward rollback migration, not this skill after-the-fact
113
+ - For a feature flag off-switch — toggle the flag; rollback is a heavier tool than needed
@@ -100,3 +100,30 @@ For authorization patterns (RBAC, ABAC), see [reference/authorization.md](refere
100
100
  For input validation patterns (SQL injection, XSS, Pydantic), see [reference/input-validation.md](reference/input-validation.md).
101
101
 
102
102
  For OAuth2 flows, CSRF protection, and audit logging, see [reference/oauth-csrf-audit.md](reference/oauth-csrf-audit.md).
103
+
104
+ ## Rules
105
+
106
+ - **MUST** validate all input at the trust boundary, not inside business logic — deep validation allows bad data to spread before rejection
107
+ - **MUST** use parameterized queries (prepared statements) for every SQL interaction — string concatenation is SQL injection
108
+ - **NEVER** store secrets (API keys, tokens, passwords) in code, config files, or git history — use the platform's secret manager
109
+ - **NEVER** log passwords, tokens, PII, or PHI — even at debug level. Logs reach aggregation systems, backups, and disk snapshots.
110
+ - **NEVER** roll your own crypto. Use vetted libraries (bcrypt/argon2 for passwords, libsodium for crypto) and accept their defaults.
111
+ - **CRITICAL**: authentication (who you are) and authorization (what you can do) are distinct concerns. Confusing them produces privilege escalation bugs; AuthN passes → AuthZ still runs.
112
+ - **MANDATORY**: every endpoint is authenticated and authorized by default. Public endpoints are explicit opt-outs, not unmarked defaults.
113
+
114
+ ## Gotchas
115
+
116
+ - JWT tokens signed with `none` algorithm are valid-looking tokens with no signature. Libraries that trust the `alg` header field accept them — always validate `alg` against an allowlist, never use the token's own declaration.
117
+ - `bcrypt` has a 72-byte password length cap; longer passwords are silently truncated, making "UniqueLongPassword..." collide with "UniqueLong...". Pre-hash with SHA-256 before bcrypt for >72 char passwords.
118
+ - `SameSite=Lax` cookies are **sent** on top-level navigations (including POST from a malicious site) in some browsers. CSRF protection requires either `SameSite=Strict` or explicit CSRF tokens; relying on `Lax` alone is insufficient for state-changing endpoints.
119
+ - `Content-Security-Policy` with `unsafe-inline` allows any inline script to run — negating most of CSP's value. Remove `unsafe-inline` and refactor to external scripts, even if it means extra files.
120
+ - Environment variables leak via `printenv` in debug endpoints, `/proc/<pid>/environ` on Linux, and process listings. Prefer mounting secrets as files (Docker secrets, Kubernetes secrets) for defense in depth.
121
+ - Rate limiting by IP address is bypassed by CDN proxies and legitimate shared NAT. Apply rate limits at the **authenticated user** level when possible; IP-level is a coarse last resort.
122
+
123
+ ## When NOT to Load
124
+
125
+ - For dependency vulnerability scanning — use `/cve-scan`
126
+ - For HIPAA-specific healthcare compliance — use `/hipaa-validate`
127
+ - For threat modeling of a new architecture — delegate to the `security-architect` agent
128
+ - For penetration testing and CVE exploitation — delegate to `security-auditor` agent
129
+ - For content moderation (LLM safety filters) — use `/content-moderation-patterns`
@@ -130,8 +130,25 @@ The `/skill-audit` slash command wraps this scanner with Claude's analysis for r
130
130
 
131
131
  ## Rules
132
132
 
133
- - Never modify files without `--fix` flag
134
- - HIGH severity findings should block deployment
135
- - This skill is READ-ONLY by default
136
- - Scan both `app/skills/` and `app/agents/` directories
137
- - Exit with non-zero status if any HIGH findings exist (for CI integration)
133
+ - **MUST** remain read-only by default — file modifications require the explicit `--fix` flag
134
+ - **MUST** exit with non-zero status on any HIGH finding so CI pipelines can gate merges
135
+ - **NEVER** auto-fix HIGH-severity findings — only the human owner decides on dangerous code
136
+ - **NEVER** silence findings by adding exceptions in the audit config; either fix the code or document why the pattern is safe in the skill body
137
+ - **CRITICAL**: scan both `app/skills/` and `app/agents/` agents without tool restrictions are the same risk class as skills with broad `allowed-tools`
138
+ - **MANDATORY**: every finding names a specific fix (replace `eval()` with `ast.literal_eval()`, add missing `allowed-tools`). A finding without a fix is triage noise.
139
+
140
+ ## Gotchas
141
+
142
+ - Regex-based secret detection catches canonical patterns (`sk-...`, `ghp_...`) but misses custom API key formats used by internal services. Augment the regex list with project-specific patterns before trusting "0 HIGH findings".
143
+ - `--fix` on `allowed-tools` infers minimal tool sets from imports, but skills that shell out via Bash may need tools not visible in the static scan. Review auto-added restrictions before merging.
144
+ - Knowledge skills (`user-invocable: false`) with Bash access are HIGH because they auto-load and can act without user triggering. Legitimate exceptions (e.g., `research-mastery` calling `smart_query()`) should be explicitly whitelisted in the audit config with a comment.
145
+ - The scanner flags `eval(` even inside docstrings and commented-out code. Context-aware scanning is hard; the alternative is reviewing each HIGH flag manually — the scan errs on the side of false positives.
146
+ - CI integration with `--ci` exits 1 on any HIGH, which **blocks the commit**. A sudden pattern match (e.g., a legitimate new use of `subprocess.run`) can block unrelated PRs. Keep a fast path for pre-approving new patterns.
147
+
148
+ ## When NOT to Use
149
+
150
+ - For general code-quality metrics (complexity, coverage, duplication) — use `/analyze`
151
+ - For dependency CVE scans — use `/cve-scan`
152
+ - For HIPAA-specific audits — use `/hipaa-validate`
153
+ - For live pentesting of a deployed app — delegate to the `security-auditor` agent
154
+ - When the project has its own security scanner (semgrep, snyk) — prefer it; `/skill-audit` is toolkit-specific
@@ -28,15 +28,19 @@ Create a new skill following the Agent Skills standard.
28
28
  |-------|------|----------|-------------|
29
29
  | `name` | string | yes | Lowercase, hyphens only, max 64 chars |
30
30
  | `description` | string | yes | Third person, max 1024 chars, include key terms |
31
- | `effort` | low/medium/high/max | no | Controls model thinking budget |
31
+ | `effort` | low/medium/high/xhigh/max | no | Controls model thinking budget (xhigh added for Opus 4.7) |
32
32
  | `disable-model-invocation` | bool | no | `true` = only user can trigger (task skills) |
33
33
  | `user-invocable` | bool | no | `false` = knowledge skill, Claude auto-loads |
34
- | `allowed-tools` | csv | no | Restrict tool access for safety |
35
- | `model` | string | no | Override default model |
34
+ | `allowed-tools` | csv or YAML list | no | Restrict tool access for safety; YAML-style lists accepted |
35
+ | `disallowedTools` | csv or YAML list | no | Block specific tools (plugin-shipped agents) |
36
+ | `model` | string | no | Override default model (accepts full IDs like `claude-opus-4-7`) |
36
37
  | `context` | string | no | `fork` to run in isolated subagent |
37
38
  | `agent` | string | no | Agent type to use when `context: fork` |
39
+ | `skills` | csv | no | Auto-load skills for the invoked subagent |
38
40
  | `argument-hint` | string | no | Shown in autocomplete, e.g. `"[target]"` |
39
- | `hooks` | object | no | Lifecycle hooks (PreToolUse, PostToolUse, Stop) |
41
+ | `hooks` | object | no | Lifecycle hooks (`PreToolUse`, `PostToolUse`, `Stop`) scoped to the skill invocation |
42
+ | `maxTurns` | int | no | Cap turns when skill spawns a subagent |
43
+ | `memory` | user/project/local | no | Persistent memory scope (agents only) |
40
44
 
41
45
  ## Classification Guide
42
46
 
@@ -48,7 +52,7 @@ Create a new skill following the Agent Skills standard.
48
52
 
49
53
  ## Writing Guidelines
50
54
 
51
- - **Description**: third person ("Generates...", "Provides..."), include searchable key terms
55
+ - **Description**: third person ("Generates...", "Provides..."), **min 50 chars**, include searchable key terms **and a trigger hint** (e.g., "Use when..."). Short descriptions cause over-triggering — adjacent skills fight for the same query.
52
56
  - **Name**: lowercase, hyphens, max 64 chars -- match the directory name
53
57
  - **Length**: SKILL.md under 500 lines; use `reference/` for overflow
54
58
  - **Be concise**: Claude is smart -- give structure, not lectures
@@ -57,6 +61,26 @@ Create a new skill following the Agent Skills standard.
57
61
  - **Use `$ARGUMENTS`**: place it early so user input is visible
58
62
  - **Tables over prose**: for options, patterns, mappings
59
63
 
64
+ ## Mandatory Sections (meta-architect audit criteria)
65
+
66
+ Every SKILL.md must contain all five, or it will lower the toolkit quality score:
67
+
68
+ 1. **Description ≥50 chars** with trigger hint in frontmatter
69
+ 2. **At least one concrete example** — fenced code block or `## Example` section
70
+ 3. **Hard rules** using uppercase markers: `MUST`, `NEVER`, `CRITICAL`, `MANDATORY`, or `DO NOT`
71
+ 4. **"When NOT to Use" section** — list 2-3 adjacent skills and the boundary between them
72
+ 5. **Under 500 lines** — split into `reference/` if needed
73
+
74
+ These map directly to the mutation strategies in `meta-architect.md`:
75
+ `add_example`, `add_constraint`, `add_edge_case`, `restructure`.
76
+
77
+ ### Rules vs Gotchas — different semantic buckets
78
+
79
+ Split the "hard rules" criterion into two sections when both apply:
80
+
81
+ - **`## Rules`** — prescriptive process constraints (always-true MUST / NEVER): *"MUST form a testable hypothesis before changing code"*, *"NEVER force-push main"*. Required in every skill.
82
+ - **`## Gotchas`** — environment-specific traps the agent would miss without being told, taken from [Anthropic's best practices](https://agentskills.io/skill-creation/best-practices.md#gotchas-sections). Example from their docs: *"The `users` table uses soft deletes. Queries must include `WHERE deleted_at IS NULL` or results will include deactivated accounts."* Add this section only when real domain traps exist — do not pad with a `(none)` placeholder.
83
+
60
84
  ## Directory Structure
61
85
 
62
86
  ```
@@ -74,7 +98,7 @@ Only create subdirectories when the skill needs them. Most skills are a single S
74
98
  ```markdown
75
99
  ---
76
100
  name: {name}
77
- description: "{Third-person description with key terms}"
101
+ description: "{Third-person description, min 50 chars, with trigger hint like 'Use when...'}"
78
102
  argument-hint: "[hint]"
79
103
  allowed-tools: Read, Grep, Glob
80
104
  ---
@@ -97,25 +121,46 @@ $ARGUMENTS
97
121
  2. **Step two**
98
122
  3. **Step three**
99
123
 
100
- ## Output Format
124
+ ## Example
101
125
 
102
- {Expected output structure}
126
+ \`\`\`
127
+ /{name} example-argument
128
+ \`\`\`
129
+
130
+ {Expected observable behavior.}
103
131
 
104
132
  ## Rules
105
133
 
106
- - {Constraint 1}
107
- - {Constraint 2}
134
+ - **MUST** {non-negotiable rule 1}
135
+ - **NEVER** {forbidden action}
136
+ - **CRITICAL**: {safety constraint}
137
+
138
+ ## Gotchas
139
+
140
+ - {environment-specific trap the agent would miss — concrete, not general}
141
+ - {non-obvious behavior of a tool, API, or data layout}
142
+
143
+ ## When NOT to Use
144
+
145
+ - For {adjacent use case} -- use `/{other-skill}` instead
146
+ - For {another case} -- use `/{another-skill}`
147
+ - If {precondition} is not met
108
148
  ```
109
149
 
150
+ Leave out `## Gotchas` entirely when the skill has no domain-specific traps — it is not mandatory, and a stub with nothing concrete is worse than no section.
151
+
110
152
  ## Quality Checklist
111
153
 
112
154
  Before finalizing, verify:
113
155
 
114
- - [ ] Description is specific with searchable key terms
115
- - [ ] SKILL.md is under 500 lines
156
+ - [ ] Description ≥50 chars, third-person, with trigger hint
157
+ - [ ] At least one concrete code-fenced example
158
+ - [ ] `## Rules` section with prescriptive MUST / NEVER / CRITICAL / MANDATORY
159
+ - [ ] `## Gotchas` section when the domain has real environment-specific traps (otherwise omit)
160
+ - [ ] `## When NOT to Use` section naming 2-3 adjacent skills
161
+ - [ ] SKILL.md under 500 lines
116
162
  - [ ] No time-sensitive information (versions, dates)
117
163
  - [ ] Consistent terminology throughout
118
- - [ ] Examples are concrete, not abstract
119
164
  - [ ] File references max 1 level deep
120
165
  - [ ] Workflows have numbered steps
121
166
  - [ ] Frontmatter fields match classification type
@@ -280,113 +280,7 @@ func testLoginFlow() {
280
280
 
281
281
  ## Common Frameworks
282
282
 
283
- ### SwiftUI + @Observable (iOS 17+)
284
-
285
- ```swift
286
- @Observable
287
- final class UserViewModel {
288
- var users: [User] = []
289
- var isLoading = false
290
- private let service: UserService
291
-
292
- init(service: UserService) { self.service = service }
293
-
294
- func load() async {
295
- isLoading = true
296
- defer { isLoading = false }
297
- users = (try? await service.fetchAll()) ?? []
298
- }
299
- }
300
-
301
- struct UserListView: View {
302
- @State private var vm: UserViewModel
303
-
304
- init(service: UserService) {
305
- _vm = State(initialValue: UserViewModel(service: service))
306
- }
307
-
308
- var body: some View {
309
- NavigationStack {
310
- List(vm.users) { user in
311
- NavigationLink(value: user) { Text(user.name) }
312
- }
313
- .navigationTitle("Users")
314
- .navigationDestination(for: User.self) { UserDetailView(user: $0) }
315
- .task { await vm.load() }
316
- }
317
- }
318
- }
319
- ```
320
-
321
- ### Combine
322
-
323
- ```swift
324
- class SearchVM: ObservableObject {
325
- @Published var query = ""
326
- @Published var results: [Item] = []
327
- private var cancellables = Set<AnyCancellable>()
328
-
329
- init(service: SearchService) {
330
- $query
331
- .debounce(for: .milliseconds(300), scheduler: DispatchQueue.main)
332
- .removeDuplicates()
333
- .filter { !$0.isEmpty }
334
- .flatMap { service.search(query: $0) }
335
- .receive(on: DispatchQueue.main)
336
- .sink(receiveCompletion: { _ in },
337
- receiveValue: { [weak self] in self?.results = $0 })
338
- .store(in: &cancellables)
339
- }
340
- }
341
- ```
342
-
343
- ### Structured Concurrency
344
-
345
- ```swift
346
- func fetchAllProfiles(ids: [String]) async throws -> [Profile] {
347
- try await withThrowingTaskGroup(of: Profile.self) { group in
348
- for id in ids { group.addTask { try await fetchProfile(id: id) } }
349
- return try await group.reduce(into: []) { $0.append($1) }
350
- }
351
- }
352
-
353
- // AsyncStream for bridging callbacks
354
- let locations = AsyncStream<Location> { continuation in
355
- manager.onUpdate = { continuation.yield($0) }
356
- continuation.onTermination = { _ in manager.stop() }
357
- }
358
- ```
359
-
360
- ### SwiftData
361
-
362
- ```swift
363
- @Model
364
- final class Item {
365
- var title: String
366
- var timestamp: Date
367
- @Relationship(deleteRule: .cascade) var tags: [Tag]
368
- init(title: String) { self.title = title; self.timestamp = .now; self.tags = [] }
369
- }
370
-
371
- struct ItemListView: View {
372
- @Query(sort: \Item.timestamp, order: .reverse) private var items: [Item]
373
- @Environment(\.modelContext) private var context
374
-
375
- var body: some View {
376
- List(items) { Text($0.title) }
377
- }
378
- }
379
- ```
380
-
381
- ### Vapor (Server-Side)
382
-
383
- ```swift
384
- app.get("users", ":id") { req async throws -> User in
385
- guard let id = req.parameters.get("id", as: UUID.self) else { throw Abort(.badRequest) }
386
- guard let user = try await User.find(id, on: req.db) else { throw Abort(.notFound) }
387
- return user
388
- }
389
- ```
283
+ For SwiftUI + `@Observable`, Combine, Structured Concurrency, SwiftData, and Vapor framework patterns with complete code examples, see [reference/frameworks.md](reference/frameworks.md).
390
284
 
391
285
  ---
392
286
 
@@ -498,3 +392,29 @@ Schemes: separate Debug/Release/Testing. Enable ASan + TSan in test schemes.
498
392
  | Blocking main thread | UI freezes | `async/await`, `Task { }` |
499
393
  | `UserDefaults` for secrets | Insecure | Keychain (`SecItemAdd`) |
500
394
  | `@ObservedObject` for owned state | Object recreated | `@StateObject` or `@State` + `@Observable` |
395
+
396
+ ## Rules
397
+
398
+ - **MUST** use Swift concurrency primitives (`async/await`, actors, `Task`) for new code — GCD is legacy and mixes poorly with the new model
399
+ - **MUST** annotate view models with `@MainActor` when they touch UI state — off-main mutations cause runtime warnings and flaky UI
400
+ - **NEVER** force-unwrap (`!`) without a documented invariant in a comment; runtime crashes from unwrap are the top iOS crash category
401
+ - **NEVER** store secrets in `UserDefaults` or plist — use Keychain APIs (`SecItemAdd`, `SecItemCopyMatching`)
402
+ - **CRITICAL**: SwiftUI state flows downward; mutations flow through `@State`, `@Binding`, or `@Observable`. Never mutate a parent's state from a child via a captured reference — it breaks dependency tracking.
403
+ - **MANDATORY**: every closure that captures `self` inside a reference type uses `[weak self]` or `[unowned self]` — retain cycles are the top memory-leak cause
404
+
405
+ ## Gotchas
406
+
407
+ - `@StateObject` and `@ObservedObject` look similar but behave oppositely on parent re-render: `@StateObject` persists, `@ObservedObject` may re-initialize. Using `@ObservedObject` for view-owned state recreates the object on every render — state loss without error.
408
+ - `Task { @MainActor in ... }` inside a non-`@MainActor` context does **not** synchronously return to main; it schedules. Code between the `await` and `Task` boundary runs on whatever actor you came from, which can race with UI updates.
409
+ - `AsyncStream` continuations without `onTermination` leak: if the consumer cancels, the producer keeps yielding forever. Always install a termination handler.
410
+ - SwiftData `@Query` with `@Environment(\.modelContext)` invalidates on every write; heavy reads in a watched view cause perf drops. Use `@FetchRequest`-style fetch descriptors with explicit refresh, not ambient `@Query`, for large datasets.
411
+ - Combine's `.receive(on: DispatchQueue.main)` schedules asynchronously — if the next operator expects sync execution, order matters. Prefer moving `.receive(on:)` to just before the sink, not mid-pipeline.
412
+ - Swift Concurrency does not compose cleanly with Objective-C completion handlers; `withCheckedContinuation` bridges but a continuation that is never resumed hangs the Task forever. Always pair resumes with all control-flow paths, including errors.
413
+
414
+ ## When NOT to Load
415
+
416
+ - For **Flutter or React Native** cross-platform code — use `/flutter-patterns` or JS patterns; this skill is Swift-only
417
+ - For generic iOS architecture decisions (MVC vs MVVM vs VIPER) — use `/architecture-decision`
418
+ - For Kotlin-based cross-platform mobile (KMP) — use `/kotlin-patterns`
419
+ - For mobile CI/CD specifics (TestFlight, Fastlane) — use `/ci-cd-patterns`
420
+ - For Objective-C interop deep dives — outside scope; this skill focuses on modern Swift
@@ -0,0 +1,111 @@
1
+ # Swift Framework Patterns
2
+
3
+ Detailed patterns for SwiftUI, Combine, Structured Concurrency, SwiftData, and Vapor. Loaded on demand from `swift-patterns/SKILL.md`.
4
+
5
+ ## SwiftUI + @Observable (iOS 17+)
6
+
7
+ ```swift
8
+ @Observable
9
+ final class UserViewModel {
10
+ var users: [User] = []
11
+ var isLoading = false
12
+ private let service: UserService
13
+
14
+ init(service: UserService) { self.service = service }
15
+
16
+ func load() async {
17
+ isLoading = true
18
+ defer { isLoading = false }
19
+ users = (try? await service.fetchAll()) ?? []
20
+ }
21
+ }
22
+
23
+ struct UserListView: View {
24
+ @State private var vm: UserViewModel
25
+
26
+ init(service: UserService) {
27
+ _vm = State(initialValue: UserViewModel(service: service))
28
+ }
29
+
30
+ var body: some View {
31
+ NavigationStack {
32
+ List(vm.users) { user in
33
+ NavigationLink(value: user) { Text(user.name) }
34
+ }
35
+ .navigationTitle("Users")
36
+ .navigationDestination(for: User.self) { UserDetailView(user: $0) }
37
+ .task { await vm.load() }
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ ## Combine
44
+
45
+ ```swift
46
+ class SearchVM: ObservableObject {
47
+ @Published var query = ""
48
+ @Published var results: [Item] = []
49
+ private var cancellables = Set<AnyCancellable>()
50
+
51
+ init(service: SearchService) {
52
+ $query
53
+ .debounce(for: .milliseconds(300), scheduler: DispatchQueue.main)
54
+ .removeDuplicates()
55
+ .filter { !$0.isEmpty }
56
+ .flatMap { service.search(query: $0) }
57
+ .receive(on: DispatchQueue.main)
58
+ .sink(receiveCompletion: { _ in },
59
+ receiveValue: { [weak self] in self?.results = $0 })
60
+ .store(in: &cancellables)
61
+ }
62
+ }
63
+ ```
64
+
65
+ ## Structured Concurrency
66
+
67
+ ```swift
68
+ func fetchAllProfiles(ids: [String]) async throws -> [Profile] {
69
+ try await withThrowingTaskGroup(of: Profile.self) { group in
70
+ for id in ids { group.addTask { try await fetchProfile(id: id) } }
71
+ return try await group.reduce(into: []) { $0.append($1) }
72
+ }
73
+ }
74
+
75
+ // AsyncStream for bridging callbacks
76
+ let locations = AsyncStream<Location> { continuation in
77
+ manager.onUpdate = { continuation.yield($0) }
78
+ continuation.onTermination = { _ in manager.stop() }
79
+ }
80
+ ```
81
+
82
+ ## SwiftData
83
+
84
+ ```swift
85
+ @Model
86
+ final class Item {
87
+ var title: String
88
+ var timestamp: Date
89
+ @Relationship(deleteRule: .cascade) var tags: [Tag]
90
+ init(title: String) { self.title = title; self.timestamp = .now; self.tags = [] }
91
+ }
92
+
93
+ struct ItemListView: View {
94
+ @Query(sort: \Item.timestamp, order: .reverse) private var items: [Item]
95
+ @Environment(\.modelContext) private var context
96
+
97
+ var body: some View {
98
+ List(items) { Text($0.title) }
99
+ }
100
+ }
101
+ ```
102
+
103
+ ## Vapor (Server-Side)
104
+
105
+ ```swift
106
+ app.get("users", ":id") { req async throws -> User in
107
+ guard let id = req.parameters.get("id", as: UUID.self) else { throw Abort(.badRequest) }
108
+ guard let user = try await User.find(id, on: req.db) else { throw Abort(.notFound) }
109
+ return user
110
+ }
111
+ ```
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: test
3
- description: "Run tests with coverage analysis and reporting"
3
+ description: "Run the project's test suite with coverage reporting, auto-detecting the framework (pytest, vitest, jest, flutter test, go test, cargo test, phpunit). Use when the user asks to run existing tests — not to author new ones test-first."
4
4
  effort: medium
5
5
  disable-model-invocation: true
6
6
  argument-hint: "[file or pattern]"
@@ -105,3 +105,25 @@ tests/ # or test/, spec/, __tests__/
105
105
  ├── integration/ # Tests with external dependencies
106
106
  └── e2e/ # End-to-end tests
107
107
  ```
108
+
109
+ ## Rules
110
+
111
+ - **MUST** detect the framework automatically via `detect-runner.py` — do not assume
112
+ - **NEVER** modify tests to make them pass
113
+ - **CRITICAL**: coverage reporting must use the project's configured tool (`--cov=src`, `--coverage`, etc.) — do not invent flags
114
+ - **MANDATORY**: when a test fails, report the failure exactly; do not paraphrase
115
+
116
+ ## Gotchas
117
+
118
+ - `pytest --cov=src` inflates coverage when `tests/` lives under `src/` — test files count toward covered lines. Either move `tests/` out, or use `--cov=src --cov-branch --cov-report=term-missing` with an explicit `[tool.coverage.run] omit = ["tests/*"]` in `pyproject.toml`.
119
+ - `go test ./...` runs packages in parallel by default; a test depending on shared global state may pass alone and fail in the suite. If flakiness appears only under `./...`, suspect shared state, not a bug in the test.
120
+ - `flutter test` without an emulator falls back to the headless "null platform" — widget tests that require a render surface are **silently skipped**. CI without a display must add `flutter test --platform vm` or a virtual framebuffer.
121
+ - `vitest run` and `jest` interpret glob patterns differently: `*.test.ts` in vitest matches filenames, in jest matches paths. Passing the same CLI arg to both produces different test sets — use the framework-native config file when possible.
122
+ - `pytest --lf` (last-failed) silently runs **all** tests if there is no cache from a prior run. First-time runs in CI therefore ignore `--lf` and re-run everything, which can hide "only failed tests" bugs in local runs.
123
+
124
+ ## When NOT to Use
125
+
126
+ - To write new tests test-first — use `/tdd`
127
+ - To author test design patterns — use `/testing-patterns` (knowledge skill)
128
+ - To debug a failing test — use `/debug` after `/test` surfaces the failure
129
+ - For performance/load testing — use dedicated tooling, not `/test`
@@ -82,3 +82,29 @@ For Flutter/Dart testing patterns, see [reference/flutter-testing.md](reference/
82
82
  | "We'll add tests later" | Untested code accumulates — later means never, and coverage gaps compound |
83
83
  | "Mocking everything is fine" | Over-mocking tests the mocks, not the code — mock at boundaries only |
84
84
  | "100% coverage means no bugs" | Coverage measures execution, not correctness — focus on behavior assertions |
85
+
86
+ ## Rules
87
+
88
+ - **MUST** follow Arrange-Act-Assert (AAA) structure in every test — unstructured tests degrade into procedural smoke tests
89
+ - **MUST** test behavior through the public interface, not internal implementation — tests coupled to internals break on every refactor
90
+ - **NEVER** test implementation details (private method return values, internal state flags) — they are not the contract
91
+ - **NEVER** hit real external services in unit tests — use fakes/stubs for boundaries; save real integration for integration tests
92
+ - **CRITICAL**: integration tests must hit real dependencies (database, message queue, external API) when mock-vs-prod divergence is a real risk. Mocked integration tests create false confidence.
93
+ - **MANDATORY**: flaky tests are bugs, not noise. Quarantine or delete them — a tolerated flaky test erodes the suite's credibility.
94
+
95
+ ## Gotchas
96
+
97
+ - Coverage numbers are easy to game: include generated code, test files that import but do not assert, or wide `# pragma: no cover` usage. A 95% reported coverage with 60% real behavior assertion is common.
98
+ - Snapshot tests (Jest `.toMatchSnapshot()`, pytest-regressions) accept any output as "correct" on first run. An incorrect initial snapshot becomes the accepted baseline — review snapshots as carefully as code.
99
+ - Mocks configured with `any` matchers (e.g., `.mock.calls[0][0]` without a schema) pass even when the production call shape changes. Assert on specific arguments, not just "was called".
100
+ - Test isolation fails when globals leak (module-level mutable state, module-scoped fixtures, env vars set in one test). Flakiness that appears only under `pytest -n auto` or `jest --parallel` is usually shared state.
101
+ - Property-based tests (Hypothesis, fast-check) shrink failing examples to minimal reproducers, but shrinking time can dominate the run. For complex generators, cap shrink deadlines or seed the failing example for next-run reproducibility.
102
+ - Test pyramid vs trophy: the "right" ratio depends on stack. Frontend apps with rendering concerns benefit from more integration tests (trophy); pure backend services align better with pyramid. Don't cargo-cult one model.
103
+
104
+ ## When NOT to Load
105
+
106
+ - For **running** the test suite — use `/test`
107
+ - For test-first development workflow — use `/tdd`
108
+ - For debugging a specific test failure — use `/debug` on the failure output
109
+ - For test framework choice in a new project — use `/app-builder`
110
+ - For performance/load testing — this skill covers correctness tests, not load
@@ -114,7 +114,25 @@ Do NOT include file paths, line numbers, or implementation details. Describe mod
114
114
 
115
115
  ## Rules
116
116
 
117
- - Minimal user interactioninvestigate autonomously
118
- - No file paths or line numbers in the issue (durability)
119
- - TDD plan uses vertical slices, not horizontal
120
- - File immediatelydon't ask for review
117
+ - **MUST** explore the codebase for root cause before filing symptoms masquerade as causes often
118
+ - **MUST** propose a TDD fix plan with ordered RED→GREEN cycles, each a vertical slice
119
+ - **NEVER** ask follow-up clarifying questions; one initial question maximum, then investigate autonomously
120
+ - **NEVER** include file paths, function names, or line numbers in the issue body they go stale before the issue is picked up
121
+ - **CRITICAL**: the issue must be reproducible. If reproduction steps cannot be determined from the investigation, say so explicitly in the Problem section — do not fabricate them.
122
+ - **MANDATORY**: file the issue immediately via `gh issue create` and share the URL — do not ask the user to review a draft first
123
+
124
+ ## Gotchas
125
+
126
+ - `gh issue create` without `--body` opens `$EDITOR`. In automated flows the skill hangs — always pass the body file or inline text.
127
+ - "Root cause" often turns out to be two concurrent issues. If the investigation keeps branching, file the most-probable primary cause and note the secondary as a follow-up in the same issue.
128
+ - TDD plans with more than ~5 RED→GREEN cycles usually conceal a deeper design issue. Short plans (2-3 cycles) reflect confident root-cause identification; long plans reflect fishing.
129
+ - The `debugger` agent explored autonomously but returns a narrative. Parse it for: confirmed hypothesis, code paths, and recent changes. Discard speculation.
130
+ - Bugs in framework-adjacent code (middleware, ORM hooks) require test setup that mirrors the framework's call context. A TDD plan that writes the test "like a unit test" may not actually reproduce the framework bug.
131
+
132
+ ## When NOT to Use
133
+
134
+ - For a conversational bug report from a non-engineer — use `/qa-session` first, which returns refined reports this skill can then process
135
+ - For a specific reproducible error with known root cause — use `/fix` directly
136
+ - For architectural-scale problems — use `/architecture-audit`
137
+ - For creating issues from a PRD — use `/prd-to-issues`
138
+ - For debugging without filing an issue — use `/debug`
@@ -64,11 +64,26 @@ Extract and formalize domain terminology into a consistent glossary.
64
64
 
65
65
  ## Rules
66
66
 
67
- - **Be opinionated** — pick the best term, list others as aliases to avoid
68
- - **Flag conflicts explicitly** call out ambiguous usage with clear recommendations
69
- - **Domain terms only** skip generic programming concepts (array, function, endpoint)
70
- - **Tight definitions** one sentence max, define what it IS not what it does
71
- - **Show relationships** — bold term names, express cardinality
72
- - **Group naturally** multiple tables when clusters emerge, one table if cohesive
73
- - **Example dialogue** 3-5 exchanges showing terms used precisely
74
- - **Keep existing** — when re-running, read existing file and update incrementally
67
+ - **MUST** be opinionated — pick the best term and list alternatives as aliases to avoid
68
+ - **MUST** flag every ambiguity (one word two concepts) and every synonym (two words → one concept) with an explicit recommendation
69
+ - **MUST** write tight definitions (one sentence) that define what the term **is**, not what it does
70
+ - **NEVER** include generic programming concepts (array, function, endpoint, class) this glossary is for the **domain**, not the toolchain
71
+ - **NEVER** silently overwrite an existing `UBIQUITOUS_LANGUAGE.md` read the current file first, then update incrementally preserving prior decisions
72
+ - **CRITICAL**: show relationships with cardinality ("an Order belongs to exactly one Customer"). Vocabulary without relationships is a word list, not a language.
73
+ - **MANDATORY**: include 3-5 example dialogue exchanges showing correct usage. Abstract glossaries without dialogue rarely get adopted.
74
+
75
+ ## Gotchas
76
+
77
+ - Domain terms often **overlap** with framework jargon (e.g., "Service" in DDD vs "Service" in Angular). If the framework already claims a term, prefer a domain-specific alternative to avoid collision.
78
+ - Stakeholders resist terminology change even when their current terms are ambiguous. "Account" replacing "User" triggers more discussion than expected — plan for negotiation in the example dialogue section.
79
+ - Glossaries rot when features ship without updating them. A `UBIQUITOUS_LANGUAGE.md` last updated 6 months ago is a snapshot, not a source of truth. Flag staleness in the header and re-run this skill periodically.
80
+ - Relationships between terms are easy to hand-wave with "related to". Pin down the cardinality (`0..1`, `1..*`, `1..1`) — vague relationships produce schema ambiguity later.
81
+ - The opinionated canonical choice may contradict marketing or legal language. Note conflicts explicitly rather than hiding them; the domain model and the marketing site can legitimately diverge.
82
+
83
+ ## When NOT to Use
84
+
85
+ - For writing a **PRD** (full requirements) — use `/write-a-prd`
86
+ - For generating user-facing documentation — use `/docs`
87
+ - For implementation planning — use `/plan` or `/prd-to-plan`
88
+ - For enforcing language in commit messages or code reviews — use `/brand-voice` (distinct concern: writing style, not domain terms)
89
+ - When the project is a single-developer throwaway — glossary overhead is not justified