@rune-kit/rune 2.10.0 → 2.11.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 (205) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +8 -6
  3. package/commands/rune.md +168 -168
  4. package/contexts/dev.md +34 -34
  5. package/contexts/research.md +43 -43
  6. package/contexts/review.md +55 -55
  7. package/extensions/ai-ml/PACK.md +88 -88
  8. package/extensions/ai-ml/skills/ai-agents.md +172 -172
  9. package/extensions/ai-ml/skills/code-sandbox.md +187 -187
  10. package/extensions/ai-ml/skills/deep-research.md +146 -146
  11. package/extensions/ai-ml/skills/embedding-search.md +66 -66
  12. package/extensions/ai-ml/skills/fine-tuning-guide.md +74 -74
  13. package/extensions/ai-ml/skills/llm-architect.md +125 -125
  14. package/extensions/ai-ml/skills/llm-integration.md +64 -64
  15. package/extensions/ai-ml/skills/prompt-patterns.md +72 -72
  16. package/extensions/ai-ml/skills/rag-patterns.md +66 -66
  17. package/extensions/ai-ml/skills/web-extraction.md +114 -114
  18. package/extensions/analytics/PACK.md +92 -92
  19. package/extensions/analytics/skills/ab-testing.md +72 -72
  20. package/extensions/analytics/skills/dashboard-patterns.md +83 -83
  21. package/extensions/analytics/skills/data-validation.md +68 -68
  22. package/extensions/analytics/skills/funnel-analysis.md +81 -81
  23. package/extensions/analytics/skills/sql-patterns.md +57 -57
  24. package/extensions/analytics/skills/statistical-analysis.md +79 -79
  25. package/extensions/analytics/skills/tracking-setup.md +71 -71
  26. package/extensions/backend/PACK.md +104 -104
  27. package/extensions/backend/skills/api-patterns.md +84 -84
  28. package/extensions/backend/skills/async-pipeline.md +193 -193
  29. package/extensions/backend/skills/auth-patterns.md +97 -97
  30. package/extensions/backend/skills/background-jobs.md +133 -133
  31. package/extensions/backend/skills/caching-patterns.md +108 -108
  32. package/extensions/backend/skills/cli-generation.md +133 -133
  33. package/extensions/backend/skills/database-patterns.md +87 -87
  34. package/extensions/backend/skills/middleware-patterns.md +104 -104
  35. package/extensions/chrome-ext/PACK.md +93 -93
  36. package/extensions/chrome-ext/skills/cws-preflight.md +143 -143
  37. package/extensions/chrome-ext/skills/cws-publish.md +104 -104
  38. package/extensions/chrome-ext/skills/ext-ai-integration.md +251 -251
  39. package/extensions/chrome-ext/skills/ext-messaging.md +139 -139
  40. package/extensions/chrome-ext/skills/ext-storage.md +133 -133
  41. package/extensions/chrome-ext/skills/mv3-scaffold.md +164 -164
  42. package/extensions/content/PACK.md +96 -96
  43. package/extensions/content/skills/blog-patterns.md +88 -88
  44. package/extensions/content/skills/cms-integration.md +131 -131
  45. package/extensions/content/skills/content-scoring.md +107 -107
  46. package/extensions/content/skills/i18n.md +83 -83
  47. package/extensions/content/skills/mdx-authoring.md +137 -137
  48. package/extensions/content/skills/reference.md +1014 -1014
  49. package/extensions/content/skills/seo-patterns.md +67 -67
  50. package/extensions/content/skills/video-repurpose.md +153 -153
  51. package/extensions/devops/PACK.md +101 -101
  52. package/extensions/devops/skills/chaos-testing.md +67 -67
  53. package/extensions/devops/skills/ci-cd.md +75 -75
  54. package/extensions/devops/skills/docker.md +58 -58
  55. package/extensions/devops/skills/edge-serverless.md +163 -163
  56. package/extensions/devops/skills/infra-as-code.md +158 -158
  57. package/extensions/devops/skills/kubernetes.md +110 -110
  58. package/extensions/devops/skills/monitoring.md +57 -57
  59. package/extensions/devops/skills/server-setup.md +64 -64
  60. package/extensions/devops/skills/ssl-domain.md +42 -42
  61. package/extensions/ecommerce/PACK.md +116 -116
  62. package/extensions/ecommerce/skills/cart-system.md +79 -79
  63. package/extensions/ecommerce/skills/inventory-mgmt.md +102 -102
  64. package/extensions/ecommerce/skills/order-management.md +126 -126
  65. package/extensions/ecommerce/skills/payment-integration.md +472 -472
  66. package/extensions/ecommerce/skills/shopify-dev.md +69 -69
  67. package/extensions/ecommerce/skills/subscription-billing.md +93 -93
  68. package/extensions/ecommerce/skills/tax-compliance.md +117 -117
  69. package/extensions/gamedev/PACK.md +142 -142
  70. package/extensions/gamedev/skills/asset-pipeline.md +74 -74
  71. package/extensions/gamedev/skills/audio-system.md +129 -129
  72. package/extensions/gamedev/skills/camera-system.md +87 -87
  73. package/extensions/gamedev/skills/ecs.md +98 -98
  74. package/extensions/gamedev/skills/game-loops.md +72 -72
  75. package/extensions/gamedev/skills/input-system.md +199 -199
  76. package/extensions/gamedev/skills/multiplayer.md +180 -180
  77. package/extensions/gamedev/skills/particles.md +105 -105
  78. package/extensions/gamedev/skills/physics-engine.md +89 -89
  79. package/extensions/gamedev/skills/scene-management.md +146 -146
  80. package/extensions/gamedev/skills/threejs-patterns.md +90 -90
  81. package/extensions/gamedev/skills/webgl.md +71 -71
  82. package/extensions/mobile/PACK.md +106 -106
  83. package/extensions/mobile/skills/app-store-connect.md +152 -152
  84. package/extensions/mobile/skills/app-store-prep.md +66 -66
  85. package/extensions/mobile/skills/deep-linking.md +109 -109
  86. package/extensions/mobile/skills/flutter.md +60 -60
  87. package/extensions/mobile/skills/ios-build-pipeline.md +142 -142
  88. package/extensions/mobile/skills/native-bridge.md +66 -66
  89. package/extensions/mobile/skills/ota-updates.md +97 -97
  90. package/extensions/mobile/skills/push-notifications.md +111 -111
  91. package/extensions/mobile/skills/react-native.md +82 -82
  92. package/extensions/saas/PACK.md +116 -116
  93. package/extensions/saas/skills/billing-integration.md +200 -200
  94. package/extensions/saas/skills/feature-flags.md +130 -130
  95. package/extensions/saas/skills/multi-tenant.md +103 -103
  96. package/extensions/saas/skills/onboarding-flow.md +139 -139
  97. package/extensions/saas/skills/subscription-flow.md +95 -95
  98. package/extensions/saas/skills/team-management.md +144 -144
  99. package/extensions/security/PACK.md +99 -99
  100. package/extensions/security/skills/api-security.md +140 -140
  101. package/extensions/security/skills/compliance.md +68 -68
  102. package/extensions/security/skills/owasp-audit.md +64 -64
  103. package/extensions/security/skills/pentest-patterns.md +77 -77
  104. package/extensions/security/skills/secret-mgmt.md +65 -65
  105. package/extensions/security/skills/supply-chain.md +65 -65
  106. package/extensions/trading/PACK.md +80 -80
  107. package/extensions/trading/skills/chart-components.md +55 -55
  108. package/extensions/trading/skills/experiment-loop.md +125 -125
  109. package/extensions/trading/skills/fintech-patterns.md +47 -47
  110. package/extensions/trading/skills/indicator-library.md +58 -58
  111. package/extensions/trading/skills/quant-analysis.md +111 -111
  112. package/extensions/trading/skills/realtime-data.md +58 -58
  113. package/extensions/trading/skills/trade-logic.md +104 -104
  114. package/extensions/ui/PACK.md +130 -130
  115. package/extensions/ui/skills/a11y-audit.md +91 -91
  116. package/extensions/ui/skills/animation-patterns.md +127 -127
  117. package/extensions/ui/skills/component-patterns.md +100 -100
  118. package/extensions/ui/skills/design-decision.md +108 -108
  119. package/extensions/ui/skills/design-system.md +68 -68
  120. package/extensions/ui/skills/landing-patterns.md +155 -155
  121. package/extensions/ui/skills/palette-picker.md +173 -173
  122. package/extensions/ui/skills/react-health.md +90 -90
  123. package/extensions/ui/skills/type-system.md +125 -125
  124. package/extensions/ui/skills/web-vitals.md +153 -153
  125. package/extensions/zalo/PACK.md +145 -145
  126. package/extensions/zalo/skills/zalo-oa-mcp.md +317 -317
  127. package/extensions/zalo/skills/zalo-oa-messaging.md +429 -429
  128. package/extensions/zalo/skills/zalo-oa-setup.md +236 -236
  129. package/extensions/zalo/skills/zalo-oa-webhook.md +189 -189
  130. package/extensions/zalo/skills/zalo-personal-messaging.md +194 -194
  131. package/extensions/zalo/skills/zalo-personal-setup.md +153 -153
  132. package/extensions/zalo/skills/zalo-rate-guard.md +219 -219
  133. package/hooks/auto-format/index.cjs +48 -48
  134. package/hooks/hooks.json +111 -111
  135. package/hooks/post-session-reflect/index.cjs +189 -189
  136. package/hooks/pre-compact/index.cjs +95 -95
  137. package/hooks/run-hook.cmd +1 -1
  138. package/hooks/secrets-scan/index.cjs +100 -100
  139. package/hooks/session-start/index.cjs +71 -71
  140. package/hooks/typecheck/index.cjs +65 -65
  141. package/package.json +63 -63
  142. package/references/ui-pro-max-data/LICENSE-UI-PRO-MAX +21 -21
  143. package/references/ui-pro-max-data/charts.csv +26 -26
  144. package/references/ui-pro-max-data/colors.csv +161 -161
  145. package/references/ui-pro-max-data/styles.csv +68 -68
  146. package/references/ui-pro-max-data/typography.csv +74 -74
  147. package/references/ui-pro-max-data/ui-reasoning.csv +162 -162
  148. package/references/ui-pro-max-data/ux-guidelines.csv +99 -99
  149. package/skills/adversary/SKILL.md +283 -283
  150. package/skills/asset-creator/SKILL.md +157 -157
  151. package/skills/audit/SKILL.md +147 -2
  152. package/skills/autopsy/SKILL.md +335 -335
  153. package/skills/brainstorm/SKILL.md +342 -342
  154. package/skills/browser-pilot/SKILL.md +168 -168
  155. package/skills/constraint-check/SKILL.md +165 -165
  156. package/skills/context-engine/SKILL.md +404 -404
  157. package/skills/cook/SKILL.md +917 -863
  158. package/skills/db/SKILL.md +273 -273
  159. package/skills/debug/SKILL.md +465 -465
  160. package/skills/dependency-doctor/SKILL.md +265 -235
  161. package/skills/deploy/SKILL.md +274 -231
  162. package/skills/design/DESIGN-REFERENCE.md +365 -365
  163. package/skills/design/SKILL.md +589 -589
  164. package/skills/doc-processor/SKILL.md +254 -254
  165. package/skills/docs/SKILL.md +374 -374
  166. package/skills/docs-seeker/SKILL.md +177 -177
  167. package/skills/fix/SKILL.md +330 -330
  168. package/skills/git/SKILL.md +339 -339
  169. package/skills/hallucination-guard/SKILL.md +219 -219
  170. package/skills/incident/SKILL.md +254 -253
  171. package/skills/integrity-check/SKILL.md +169 -169
  172. package/skills/journal/SKILL.md +240 -240
  173. package/skills/launch/SKILL.md +344 -344
  174. package/skills/logic-guardian/SKILL.md +251 -251
  175. package/skills/marketing/SKILL.md +290 -289
  176. package/skills/mcp-builder/SKILL.md +425 -425
  177. package/skills/neural-memory/SKILL.md +362 -362
  178. package/skills/onboard/SKILL.md +404 -403
  179. package/skills/perf/SKILL.md +346 -346
  180. package/skills/plan/SKILL.md +433 -428
  181. package/skills/preflight/SKILL.md +415 -415
  182. package/skills/problem-solver/SKILL.md +380 -284
  183. package/skills/rescue/SKILL.md +474 -474
  184. package/skills/retro/SKILL.md +3 -1
  185. package/skills/review/SKILL.md +612 -588
  186. package/skills/review-intake/SKILL.md +249 -249
  187. package/skills/safeguard/SKILL.md +200 -200
  188. package/skills/sast/SKILL.md +190 -190
  189. package/skills/scaffold/SKILL.md +328 -287
  190. package/skills/scope-guard/SKILL.md +180 -180
  191. package/skills/scout/SKILL.md +263 -263
  192. package/skills/sentinel/SKILL.md +382 -381
  193. package/skills/sentinel-env/SKILL.md +254 -254
  194. package/skills/sequential-thinking/SKILL.md +234 -234
  195. package/skills/session-bridge/SKILL.md +543 -543
  196. package/skills/skill-forge/SKILL.md +581 -581
  197. package/skills/skill-router/SKILL.md +3 -0
  198. package/skills/surgeon/SKILL.md +215 -215
  199. package/skills/team/SKILL.md +556 -537
  200. package/skills/test/SKILL.md +614 -614
  201. package/skills/trend-scout/SKILL.md +145 -145
  202. package/skills/verification/SKILL.md +326 -326
  203. package/skills/video-creator/SKILL.md +201 -201
  204. package/skills/watchdog/SKILL.md +168 -168
  205. package/skills/worktree/SKILL.md +140 -140
@@ -1,133 +1,133 @@
1
- ---
2
- name: "cli-generation"
3
- pack: "@rune/backend"
4
- description: "Generate production-grade CLI wrappers for backend services — command groups, dual output mode (human + JSON), stateful REPL, session management with undo/redo, and pip/npm-installable packaging."
5
- model: sonnet
6
- tools: [Read, Edit, Write, Grep, Glob, Bash]
7
- ---
8
-
9
- # cli-generation
10
-
11
- Generate production-grade CLI wrappers for backend services — command groups, dual output mode (human + JSON), stateful REPL, session management with undo/redo, and pip/npm-installable packaging.
12
-
13
- #### Workflow
14
-
15
- **Step 1 — Analyze backend service surface**
16
- Map existing API endpoints, service methods, or data models to CLI command groups:
17
- ```typescript
18
- interface CLICommandGroup {
19
- name: string; // e.g., 'users', 'orders', 'config'
20
- source: string; // API route file or service class
21
- commands: CLICommand[];
22
- }
23
-
24
- interface CLICommand {
25
- name: string; // e.g., 'list', 'create', 'delete'
26
- sourceMethod: string; // e.g., 'UserService.findAll'
27
- params: CLIParam[];
28
- mutating: boolean; // true = needs confirmation/undo support
29
- }
30
- ```
31
-
32
- **Step 2 — Design dual output mode**
33
- Every command MUST support both human-readable and machine-readable output:
34
- ```typescript
35
- // Human mode (default): tables, colors, formatted text
36
- function formatHuman(data: any, format: 'table' | 'list' | 'detail'): string {
37
- if (format === 'table') return formatTable(data, { borders: true, colors: true });
38
- if (format === 'list') return data.map((d: any) => ` • ${d.name}`).join('\n');
39
- return JSON.stringify(data, null, 2);
40
- }
41
-
42
- // JSON mode (--json flag): structured output for piping/scripting
43
- function formatJSON(data: any): string {
44
- return JSON.stringify(data, null, 2);
45
- }
46
-
47
- // Error output follows same dual pattern
48
- function formatError(error: Error, jsonMode: boolean): string {
49
- if (jsonMode) return JSON.stringify({ error: error.message, type: error.constructor.name });
50
- return chalk.red(`Error: ${error.message}`);
51
- }
52
- ```
53
-
54
- **Step 3 — Implement session with undo/redo**
55
- For mutating operations, maintain session state:
56
- ```typescript
57
- interface CLISession {
58
- id: string;
59
- history: SessionSnapshot[];
60
- undoStack: SessionSnapshot[]; // max 50
61
- redoStack: SessionSnapshot[];
62
- modified: boolean;
63
- }
64
-
65
- function snapshot(session: CLISession, action: string): CLISession {
66
- return {
67
- ...session,
68
- undoStack: [...session.undoStack.slice(-49), { action, state: deepCopy(session) }],
69
- redoStack: [], // new action clears redo
70
- modified: true,
71
- };
72
- }
73
- ```
74
-
75
- **Step 4 — Build REPL mode**
76
- CLI enters REPL when invoked without subcommand:
77
- ```typescript
78
- // Click (Python) — invoke_without_command=True enters REPL
79
- @click.group(invoke_without_command=True)
80
- @click.pass_context
81
- def cli(ctx):
82
- if ctx.invoked_subcommand is None:
83
- start_repl(ctx)
84
-
85
- // Commander (Node.js) — detect no args
86
- if (process.argv.length <= 2) {
87
- startREPL({ history: '~/.myapp_history', prompt: 'myapp> ' });
88
- }
89
- ```
90
-
91
- REPL features: command history (file-persisted), auto-suggest from history, tab completion, colored prompt, help command, status bar showing connection state.
92
-
93
- **Step 5 — Package for distribution**
94
- ```bash
95
- # Python: PEP 420 namespace packages for independent installability
96
- # pyproject.toml or setup.py
97
- entry_points = {
98
- 'console_scripts': ['myapp = myapp.cli:main'],
99
- }
100
-
101
- # Node.js: bin field in package.json
102
- {
103
- "bin": { "myapp": "./bin/cli.js" },
104
- "files": ["bin/", "lib/"]
105
- }
106
- ```
107
-
108
- **Step 6 — Verify installation**
109
- After packaging: install locally (`pip install -e .` or `npm link`), verify binary on PATH (`which myapp`), run `myapp --version`, test `myapp --json` mode, and verify REPL launch.
110
-
111
- #### Example
112
-
113
- ```python
114
- # Generated CLI structure for a backend service
115
- # myapp/
116
- # ├── cli.py ← Click entry point + REPL
117
- # ├── commands/
118
- # │ ├── users.py ← User CRUD commands
119
- # │ ├── orders.py ← Order management
120
- # │ └── config.py ← Config operations
121
- # ├── core/
122
- # │ ├── session.py ← Session + undo/redo
123
- # │ └── client.py ← API client wrapper
124
- # └── utils/
125
- # ├── output.py ← Dual output (human + JSON)
126
- # └── repl.py ← REPL with prompt-toolkit
127
-
128
- # Usage:
129
- # myapp users list → human-readable table
130
- # myapp users list --json → JSON output for piping
131
- # myapp users create --name "Alice" → creates user, snapshots for undo
132
- # myapp → enters REPL mode
133
- ```
1
+ ---
2
+ name: "cli-generation"
3
+ pack: "@rune/backend"
4
+ description: "Generate production-grade CLI wrappers for backend services — command groups, dual output mode (human + JSON), stateful REPL, session management with undo/redo, and pip/npm-installable packaging."
5
+ model: sonnet
6
+ tools: [Read, Edit, Write, Grep, Glob, Bash]
7
+ ---
8
+
9
+ # cli-generation
10
+
11
+ Generate production-grade CLI wrappers for backend services — command groups, dual output mode (human + JSON), stateful REPL, session management with undo/redo, and pip/npm-installable packaging.
12
+
13
+ #### Workflow
14
+
15
+ **Step 1 — Analyze backend service surface**
16
+ Map existing API endpoints, service methods, or data models to CLI command groups:
17
+ ```typescript
18
+ interface CLICommandGroup {
19
+ name: string; // e.g., 'users', 'orders', 'config'
20
+ source: string; // API route file or service class
21
+ commands: CLICommand[];
22
+ }
23
+
24
+ interface CLICommand {
25
+ name: string; // e.g., 'list', 'create', 'delete'
26
+ sourceMethod: string; // e.g., 'UserService.findAll'
27
+ params: CLIParam[];
28
+ mutating: boolean; // true = needs confirmation/undo support
29
+ }
30
+ ```
31
+
32
+ **Step 2 — Design dual output mode**
33
+ Every command MUST support both human-readable and machine-readable output:
34
+ ```typescript
35
+ // Human mode (default): tables, colors, formatted text
36
+ function formatHuman(data: any, format: 'table' | 'list' | 'detail'): string {
37
+ if (format === 'table') return formatTable(data, { borders: true, colors: true });
38
+ if (format === 'list') return data.map((d: any) => ` • ${d.name}`).join('\n');
39
+ return JSON.stringify(data, null, 2);
40
+ }
41
+
42
+ // JSON mode (--json flag): structured output for piping/scripting
43
+ function formatJSON(data: any): string {
44
+ return JSON.stringify(data, null, 2);
45
+ }
46
+
47
+ // Error output follows same dual pattern
48
+ function formatError(error: Error, jsonMode: boolean): string {
49
+ if (jsonMode) return JSON.stringify({ error: error.message, type: error.constructor.name });
50
+ return chalk.red(`Error: ${error.message}`);
51
+ }
52
+ ```
53
+
54
+ **Step 3 — Implement session with undo/redo**
55
+ For mutating operations, maintain session state:
56
+ ```typescript
57
+ interface CLISession {
58
+ id: string;
59
+ history: SessionSnapshot[];
60
+ undoStack: SessionSnapshot[]; // max 50
61
+ redoStack: SessionSnapshot[];
62
+ modified: boolean;
63
+ }
64
+
65
+ function snapshot(session: CLISession, action: string): CLISession {
66
+ return {
67
+ ...session,
68
+ undoStack: [...session.undoStack.slice(-49), { action, state: deepCopy(session) }],
69
+ redoStack: [], // new action clears redo
70
+ modified: true,
71
+ };
72
+ }
73
+ ```
74
+
75
+ **Step 4 — Build REPL mode**
76
+ CLI enters REPL when invoked without subcommand:
77
+ ```typescript
78
+ // Click (Python) — invoke_without_command=True enters REPL
79
+ @click.group(invoke_without_command=True)
80
+ @click.pass_context
81
+ def cli(ctx):
82
+ if ctx.invoked_subcommand is None:
83
+ start_repl(ctx)
84
+
85
+ // Commander (Node.js) — detect no args
86
+ if (process.argv.length <= 2) {
87
+ startREPL({ history: '~/.myapp_history', prompt: 'myapp> ' });
88
+ }
89
+ ```
90
+
91
+ REPL features: command history (file-persisted), auto-suggest from history, tab completion, colored prompt, help command, status bar showing connection state.
92
+
93
+ **Step 5 — Package for distribution**
94
+ ```bash
95
+ # Python: PEP 420 namespace packages for independent installability
96
+ # pyproject.toml or setup.py
97
+ entry_points = {
98
+ 'console_scripts': ['myapp = myapp.cli:main'],
99
+ }
100
+
101
+ # Node.js: bin field in package.json
102
+ {
103
+ "bin": { "myapp": "./bin/cli.js" },
104
+ "files": ["bin/", "lib/"]
105
+ }
106
+ ```
107
+
108
+ **Step 6 — Verify installation**
109
+ After packaging: install locally (`pip install -e .` or `npm link`), verify binary on PATH (`which myapp`), run `myapp --version`, test `myapp --json` mode, and verify REPL launch.
110
+
111
+ #### Example
112
+
113
+ ```python
114
+ # Generated CLI structure for a backend service
115
+ # myapp/
116
+ # ├── cli.py ← Click entry point + REPL
117
+ # ├── commands/
118
+ # │ ├── users.py ← User CRUD commands
119
+ # │ ├── orders.py ← Order management
120
+ # │ └── config.py ← Config operations
121
+ # ├── core/
122
+ # │ ├── session.py ← Session + undo/redo
123
+ # │ └── client.py ← API client wrapper
124
+ # └── utils/
125
+ # ├── output.py ← Dual output (human + JSON)
126
+ # └── repl.py ← REPL with prompt-toolkit
127
+
128
+ # Usage:
129
+ # myapp users list → human-readable table
130
+ # myapp users list --json → JSON output for piping
131
+ # myapp users create --name "Alice" → creates user, snapshots for undo
132
+ # myapp → enters REPL mode
133
+ ```
@@ -1,87 +1,87 @@
1
- ---
2
- name: "database-patterns"
3
- pack: "@rune/backend"
4
- description: "Database design and query patterns — schema design, migrations, indexing strategies, N+1 prevention, soft deletes, read replicas, connection pooling, seeding."
5
- model: sonnet
6
- tools: [Read, Edit, Write, Grep, Glob, Bash]
7
- ---
8
-
9
- # database-patterns
10
-
11
- Database design and query patterns — schema design, migrations, indexing strategies, N+1 prevention, soft deletes, read replicas, connection pooling, seeding.
12
-
13
- #### Workflow
14
-
15
- **Step 1 — Detect ORM and query patterns**
16
- Use Grep to find ORM usage (`prisma.`, `knex(`, `sequelize.`, `typeorm`, `drizzle`, `mongoose.`, `db.query`) and raw SQL strings. Read schema files (`schema.prisma`, `migrations/`, `models/`) to understand the data model.
17
-
18
- **Step 2 — Detect N+1 and missing indexes**
19
- Scan for loops containing database calls (a query inside `for`, `map`, `forEach` → N+1). Check foreign key columns for missing indexes. Identify queries with `WHERE` clauses on unindexed columns. Flag each with the specific query and fix.
20
-
21
- **Step 3 — Emit optimized queries**
22
- For N+1: emit eager loading (`include`, `populate`, `JOIN`). For missing indexes: emit migration files. For unsafe raw SQL: emit parameterized version. For connection pooling: check pool config and recommend sizing based on max connections.
23
-
24
- **Step 4 — Soft delete and query scoping**
25
- Emit soft delete pattern: add `deleted_at TIMESTAMPTZ` column, update all `findMany`/`findUnique` calls to include `WHERE deleted_at IS NULL`. Cascade consideration: soft-delete parent should soft-delete children (emit trigger or application-level cascade). For Prisma: emit a custom extension that injects the filter automatically. Warn about index bloat from soft-deleted rows — add partial index `WHERE deleted_at IS NULL` to keep index lean.
26
-
27
- **Step 5 — Read replicas, connection pooling, and seeding**
28
- Read replicas: emit query routing — writes to primary, reads to replica. Handle replication lag: do not read from replica immediately after write in the same request (use primary for the read-after-write). For Prisma: emit `$extends` with read/write client split. Connection pooling deep dive: PgBouncer in transaction mode for serverless (each query gets a connection); Prisma's built-in pool for long-running servers. Pool sizing formula: `connections = (core_count * 2) + effective_spindle_count`. Seeding: emit factory functions using `@faker-js/faker` — deterministic seeds via `faker.seed(42)` for reproducible test data.
29
-
30
- #### Example
31
-
32
- ```typescript
33
- // BEFORE: N+1 — one query per post to get author
34
- const posts = await prisma.post.findMany();
35
- for (const post of posts) {
36
- post.author = await prisma.user.findUnique({ where: { id: post.authorId } });
37
- }
38
-
39
- // AFTER: eager loading, single query with JOIN
40
- const posts = await prisma.post.findMany({
41
- include: { author: { select: { id: true, name: true, avatar: true } } },
42
- });
43
-
44
- // Migration: missing indexes + soft delete column
45
- -- Migration: add_indexes_and_soft_delete_to_posts
46
- ALTER TABLE posts ADD COLUMN deleted_at TIMESTAMPTZ;
47
- CREATE INDEX idx_posts_author_id ON posts(author_id);
48
- CREATE INDEX idx_posts_created_at ON posts(created_at DESC);
49
- CREATE INDEX idx_posts_active ON posts(author_id, created_at DESC) WHERE deleted_at IS NULL;
50
-
51
- // Prisma soft delete extension (auto-scopes all queries)
52
- const softDelete = Prisma.defineExtension({
53
- name: 'softDelete',
54
- query: {
55
- $allModels: {
56
- async findMany({ model, operation, args, query }) {
57
- args.where = { ...args.where, deletedAt: null };
58
- return query(args);
59
- },
60
- async delete({ model, args, query }) {
61
- return (query as any)({ ...args, data: { deletedAt: new Date() } } as any);
62
- },
63
- },
64
- },
65
- });
66
- const prisma = new PrismaClient().$extends(softDelete);
67
-
68
- // Read replica routing with Prisma
69
- const primaryClient = new PrismaClient({ datasources: { db: { url: PRIMARY_URL } } });
70
- const replicaClient = new PrismaClient({ datasources: { db: { url: REPLICA_URL } } });
71
- const db = { write: primaryClient, read: replicaClient };
72
- // Usage: db.write.user.create(...) vs db.read.user.findMany(...)
73
-
74
- // Factory seeding
75
- import { faker } from '@faker-js/faker';
76
- faker.seed(42); // reproducible
77
-
78
- const createUserFactory = (overrides = {}) => ({
79
- id: faker.string.uuid(),
80
- email: faker.internet.email(),
81
- name: faker.person.fullName(),
82
- createdAt: faker.date.past(),
83
- ...overrides,
84
- });
85
-
86
- await prisma.user.createMany({ data: Array.from({ length: 50 }, () => createUserFactory()) });
87
- ```
1
+ ---
2
+ name: "database-patterns"
3
+ pack: "@rune/backend"
4
+ description: "Database design and query patterns — schema design, migrations, indexing strategies, N+1 prevention, soft deletes, read replicas, connection pooling, seeding."
5
+ model: sonnet
6
+ tools: [Read, Edit, Write, Grep, Glob, Bash]
7
+ ---
8
+
9
+ # database-patterns
10
+
11
+ Database design and query patterns — schema design, migrations, indexing strategies, N+1 prevention, soft deletes, read replicas, connection pooling, seeding.
12
+
13
+ #### Workflow
14
+
15
+ **Step 1 — Detect ORM and query patterns**
16
+ Use Grep to find ORM usage (`prisma.`, `knex(`, `sequelize.`, `typeorm`, `drizzle`, `mongoose.`, `db.query`) and raw SQL strings. Read schema files (`schema.prisma`, `migrations/`, `models/`) to understand the data model.
17
+
18
+ **Step 2 — Detect N+1 and missing indexes**
19
+ Scan for loops containing database calls (a query inside `for`, `map`, `forEach` → N+1). Check foreign key columns for missing indexes. Identify queries with `WHERE` clauses on unindexed columns. Flag each with the specific query and fix.
20
+
21
+ **Step 3 — Emit optimized queries**
22
+ For N+1: emit eager loading (`include`, `populate`, `JOIN`). For missing indexes: emit migration files. For unsafe raw SQL: emit parameterized version. For connection pooling: check pool config and recommend sizing based on max connections.
23
+
24
+ **Step 4 — Soft delete and query scoping**
25
+ Emit soft delete pattern: add `deleted_at TIMESTAMPTZ` column, update all `findMany`/`findUnique` calls to include `WHERE deleted_at IS NULL`. Cascade consideration: soft-delete parent should soft-delete children (emit trigger or application-level cascade). For Prisma: emit a custom extension that injects the filter automatically. Warn about index bloat from soft-deleted rows — add partial index `WHERE deleted_at IS NULL` to keep index lean.
26
+
27
+ **Step 5 — Read replicas, connection pooling, and seeding**
28
+ Read replicas: emit query routing — writes to primary, reads to replica. Handle replication lag: do not read from replica immediately after write in the same request (use primary for the read-after-write). For Prisma: emit `$extends` with read/write client split. Connection pooling deep dive: PgBouncer in transaction mode for serverless (each query gets a connection); Prisma's built-in pool for long-running servers. Pool sizing formula: `connections = (core_count * 2) + effective_spindle_count`. Seeding: emit factory functions using `@faker-js/faker` — deterministic seeds via `faker.seed(42)` for reproducible test data.
29
+
30
+ #### Example
31
+
32
+ ```typescript
33
+ // BEFORE: N+1 — one query per post to get author
34
+ const posts = await prisma.post.findMany();
35
+ for (const post of posts) {
36
+ post.author = await prisma.user.findUnique({ where: { id: post.authorId } });
37
+ }
38
+
39
+ // AFTER: eager loading, single query with JOIN
40
+ const posts = await prisma.post.findMany({
41
+ include: { author: { select: { id: true, name: true, avatar: true } } },
42
+ });
43
+
44
+ // Migration: missing indexes + soft delete column
45
+ -- Migration: add_indexes_and_soft_delete_to_posts
46
+ ALTER TABLE posts ADD COLUMN deleted_at TIMESTAMPTZ;
47
+ CREATE INDEX idx_posts_author_id ON posts(author_id);
48
+ CREATE INDEX idx_posts_created_at ON posts(created_at DESC);
49
+ CREATE INDEX idx_posts_active ON posts(author_id, created_at DESC) WHERE deleted_at IS NULL;
50
+
51
+ // Prisma soft delete extension (auto-scopes all queries)
52
+ const softDelete = Prisma.defineExtension({
53
+ name: 'softDelete',
54
+ query: {
55
+ $allModels: {
56
+ async findMany({ model, operation, args, query }) {
57
+ args.where = { ...args.where, deletedAt: null };
58
+ return query(args);
59
+ },
60
+ async delete({ model, args, query }) {
61
+ return (query as any)({ ...args, data: { deletedAt: new Date() } } as any);
62
+ },
63
+ },
64
+ },
65
+ });
66
+ const prisma = new PrismaClient().$extends(softDelete);
67
+
68
+ // Read replica routing with Prisma
69
+ const primaryClient = new PrismaClient({ datasources: { db: { url: PRIMARY_URL } } });
70
+ const replicaClient = new PrismaClient({ datasources: { db: { url: REPLICA_URL } } });
71
+ const db = { write: primaryClient, read: replicaClient };
72
+ // Usage: db.write.user.create(...) vs db.read.user.findMany(...)
73
+
74
+ // Factory seeding
75
+ import { faker } from '@faker-js/faker';
76
+ faker.seed(42); // reproducible
77
+
78
+ const createUserFactory = (overrides = {}) => ({
79
+ id: faker.string.uuid(),
80
+ email: faker.internet.email(),
81
+ name: faker.person.fullName(),
82
+ createdAt: faker.date.past(),
83
+ ...overrides,
84
+ });
85
+
86
+ await prisma.user.createMany({ data: Array.from({ length: 50 }, () => createUserFactory()) });
87
+ ```
@@ -1,104 +1,104 @@
1
- ---
2
- name: "middleware-patterns"
3
- pack: "@rune/backend"
4
- description: "Middleware architecture — request validation, error handling, logging, CORS, compression, graceful shutdown, health checks, request ID tracking."
5
- model: sonnet
6
- tools: [Read, Edit, Write, Grep, Glob, Bash]
7
- ---
8
-
9
- # middleware-patterns
10
-
11
- Middleware architecture — request validation, error handling, logging, CORS, compression, graceful shutdown, health checks, request ID tracking.
12
-
13
- #### Workflow
14
-
15
- **Step 1 — Audit middleware stack**
16
- Read the main server file (app.ts, server.ts, index.ts) to inventory all middleware in registration order. Check for: missing request ID generation, missing structured logging, inconsistent error responses, missing input validation, CORS misconfiguration (`*` in production).
17
-
18
- **Step 2 — Detect error handling gaps**
19
- Use Grep to find `catch` blocks, error middleware signatures (`err, req, res, next`), and unhandled promise rejections. Check if errors return consistent format (same envelope for 400, 401, 403, 404, 500). Flag any that leak stack traces or internal details in production.
20
-
21
- **Step 3 — Emit middleware improvements**
22
- For each gap, emit the middleware function: request ID (`X-Request-Id` header, UUID per request), structured JSON logger (request method, path, status, duration, request ID), global error handler with consistent envelope, Zod-based request validation middleware.
23
-
24
- **Step 4 — Compression strategy**
25
- Emit response compression middleware. Use `brotli` for static assets and pre-compressible responses (better ratio than gzip, supported by all modern clients). Use `gzip` as fallback for older clients. Conditional compression: skip for already-compressed content types (`image/*`, `video/*`, `application/zip`) — compressing these wastes CPU. In Express: use `compression` package with a `filter` function. In Fastify: `@fastify/compress` with `encodings: ['br', 'gzip']`. Minimum size threshold: do not compress responses < 1KB (overhead exceeds benefit).
26
-
27
- **Step 5 — Graceful shutdown and health checks**
28
- Graceful shutdown: on `SIGTERM`/`SIGINT`, stop accepting new connections, wait for in-flight requests to complete (timeout 30s), then close DB pools and exit. Emit the shutdown handler for Express (`server.close()`), Fastify (`fastify.close()`), and worker processes. Health check endpoints: `/health/live` (liveness — is the process alive? return 200 always unless process is broken), `/health/ready` (readiness — can it serve traffic? check DB connection, Redis connection, return 503 if dependencies are down). In Kubernetes: map liveness to `livenessProbe`, readiness to `readinessProbe`. Do NOT check external third-party APIs in readiness — only your own dependencies.
29
-
30
- #### Example
31
-
32
- ```typescript
33
- // Request ID middleware
34
- const requestId = (req, res, next) => {
35
- req.id = req.headers['x-request-id'] || crypto.randomUUID();
36
- res.setHeader('X-Request-Id', req.id);
37
- next();
38
- };
39
-
40
- // Structured error handler — consistent envelope, no stack leak
41
- const errorHandler = (err, req, res, _next) => {
42
- const status = err.status || 500;
43
- const message = status < 500 ? err.message : 'Internal server error';
44
- logger.error({ err, requestId: req.id, path: req.path });
45
- res.status(status).json({
46
- error: { code: err.code || 'INTERNAL_ERROR', message },
47
- request_id: req.id,
48
- });
49
- };
50
-
51
- // Zod validation middleware
52
- const validate = (schema: z.ZodSchema) => (req, res, next) => {
53
- const result = schema.safeParse({ body: req.body, query: req.query, params: req.params });
54
- if (!result.success) {
55
- return res.status(400).json({ error: { code: 'VALIDATION_ERROR', message: 'Invalid request', details: result.error.flatten() } });
56
- }
57
- Object.assign(req, result.data);
58
- next();
59
- };
60
-
61
- // Compression with conditional skip (Express)
62
- import compression from 'compression';
63
- app.use(compression({
64
- filter: (req, res) => {
65
- const contentType = res.getHeader('Content-Type') as string || '';
66
- if (/image|video|audio|zip|gz|br/.test(contentType)) return false;
67
- return compression.filter(req, res);
68
- },
69
- threshold: 1024, // skip responses < 1KB
70
- }));
71
-
72
- // Graceful shutdown
73
- const gracefulShutdown = async (signal: string) => {
74
- console.log(`Received ${signal}, shutting down gracefully...`);
75
- server.close(async () => {
76
- try {
77
- await prisma.$disconnect();
78
- await redis.quit();
79
- console.log('All connections closed. Exiting.');
80
- process.exit(0);
81
- } catch (err) {
82
- console.error('Error during shutdown:', err);
83
- process.exit(1);
84
- }
85
- });
86
- // Force exit after 30s if still not done
87
- setTimeout(() => { console.error('Forced shutdown after timeout'); process.exit(1); }, 30_000);
88
- };
89
- process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
90
- process.on('SIGINT', () => gracefulShutdown('SIGINT'));
91
-
92
- // Health check endpoints
93
- app.get('/health/live', (req, res) => res.json({ status: 'ok' }));
94
-
95
- app.get('/health/ready', async (req, res) => {
96
- const checks = await Promise.allSettled([
97
- prisma.$queryRaw`SELECT 1`, // DB check
98
- redis.ping(), // Redis check
99
- ]);
100
- const results = { db: checks[0].status, redis: checks[1].status };
101
- const allHealthy = checks.every(c => c.status === 'fulfilled');
102
- res.status(allHealthy ? 200 : 503).json({ status: allHealthy ? 'ready' : 'degraded', checks: results });
103
- });
104
- ```
1
+ ---
2
+ name: "middleware-patterns"
3
+ pack: "@rune/backend"
4
+ description: "Middleware architecture — request validation, error handling, logging, CORS, compression, graceful shutdown, health checks, request ID tracking."
5
+ model: sonnet
6
+ tools: [Read, Edit, Write, Grep, Glob, Bash]
7
+ ---
8
+
9
+ # middleware-patterns
10
+
11
+ Middleware architecture — request validation, error handling, logging, CORS, compression, graceful shutdown, health checks, request ID tracking.
12
+
13
+ #### Workflow
14
+
15
+ **Step 1 — Audit middleware stack**
16
+ Read the main server file (app.ts, server.ts, index.ts) to inventory all middleware in registration order. Check for: missing request ID generation, missing structured logging, inconsistent error responses, missing input validation, CORS misconfiguration (`*` in production).
17
+
18
+ **Step 2 — Detect error handling gaps**
19
+ Use Grep to find `catch` blocks, error middleware signatures (`err, req, res, next`), and unhandled promise rejections. Check if errors return consistent format (same envelope for 400, 401, 403, 404, 500). Flag any that leak stack traces or internal details in production.
20
+
21
+ **Step 3 — Emit middleware improvements**
22
+ For each gap, emit the middleware function: request ID (`X-Request-Id` header, UUID per request), structured JSON logger (request method, path, status, duration, request ID), global error handler with consistent envelope, Zod-based request validation middleware.
23
+
24
+ **Step 4 — Compression strategy**
25
+ Emit response compression middleware. Use `brotli` for static assets and pre-compressible responses (better ratio than gzip, supported by all modern clients). Use `gzip` as fallback for older clients. Conditional compression: skip for already-compressed content types (`image/*`, `video/*`, `application/zip`) — compressing these wastes CPU. In Express: use `compression` package with a `filter` function. In Fastify: `@fastify/compress` with `encodings: ['br', 'gzip']`. Minimum size threshold: do not compress responses < 1KB (overhead exceeds benefit).
26
+
27
+ **Step 5 — Graceful shutdown and health checks**
28
+ Graceful shutdown: on `SIGTERM`/`SIGINT`, stop accepting new connections, wait for in-flight requests to complete (timeout 30s), then close DB pools and exit. Emit the shutdown handler for Express (`server.close()`), Fastify (`fastify.close()`), and worker processes. Health check endpoints: `/health/live` (liveness — is the process alive? return 200 always unless process is broken), `/health/ready` (readiness — can it serve traffic? check DB connection, Redis connection, return 503 if dependencies are down). In Kubernetes: map liveness to `livenessProbe`, readiness to `readinessProbe`. Do NOT check external third-party APIs in readiness — only your own dependencies.
29
+
30
+ #### Example
31
+
32
+ ```typescript
33
+ // Request ID middleware
34
+ const requestId = (req, res, next) => {
35
+ req.id = req.headers['x-request-id'] || crypto.randomUUID();
36
+ res.setHeader('X-Request-Id', req.id);
37
+ next();
38
+ };
39
+
40
+ // Structured error handler — consistent envelope, no stack leak
41
+ const errorHandler = (err, req, res, _next) => {
42
+ const status = err.status || 500;
43
+ const message = status < 500 ? err.message : 'Internal server error';
44
+ logger.error({ err, requestId: req.id, path: req.path });
45
+ res.status(status).json({
46
+ error: { code: err.code || 'INTERNAL_ERROR', message },
47
+ request_id: req.id,
48
+ });
49
+ };
50
+
51
+ // Zod validation middleware
52
+ const validate = (schema: z.ZodSchema) => (req, res, next) => {
53
+ const result = schema.safeParse({ body: req.body, query: req.query, params: req.params });
54
+ if (!result.success) {
55
+ return res.status(400).json({ error: { code: 'VALIDATION_ERROR', message: 'Invalid request', details: result.error.flatten() } });
56
+ }
57
+ Object.assign(req, result.data);
58
+ next();
59
+ };
60
+
61
+ // Compression with conditional skip (Express)
62
+ import compression from 'compression';
63
+ app.use(compression({
64
+ filter: (req, res) => {
65
+ const contentType = res.getHeader('Content-Type') as string || '';
66
+ if (/image|video|audio|zip|gz|br/.test(contentType)) return false;
67
+ return compression.filter(req, res);
68
+ },
69
+ threshold: 1024, // skip responses < 1KB
70
+ }));
71
+
72
+ // Graceful shutdown
73
+ const gracefulShutdown = async (signal: string) => {
74
+ console.log(`Received ${signal}, shutting down gracefully...`);
75
+ server.close(async () => {
76
+ try {
77
+ await prisma.$disconnect();
78
+ await redis.quit();
79
+ console.log('All connections closed. Exiting.');
80
+ process.exit(0);
81
+ } catch (err) {
82
+ console.error('Error during shutdown:', err);
83
+ process.exit(1);
84
+ }
85
+ });
86
+ // Force exit after 30s if still not done
87
+ setTimeout(() => { console.error('Forced shutdown after timeout'); process.exit(1); }, 30_000);
88
+ };
89
+ process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
90
+ process.on('SIGINT', () => gracefulShutdown('SIGINT'));
91
+
92
+ // Health check endpoints
93
+ app.get('/health/live', (req, res) => res.json({ status: 'ok' }));
94
+
95
+ app.get('/health/ready', async (req, res) => {
96
+ const checks = await Promise.allSettled([
97
+ prisma.$queryRaw`SELECT 1`, // DB check
98
+ redis.ping(), // Redis check
99
+ ]);
100
+ const results = { db: checks[0].status, redis: checks[1].status };
101
+ const allHealthy = checks.every(c => c.status === 'fulfilled');
102
+ res.status(allHealthy ? 200 : 503).json({ status: allHealthy ? 'ready' : 'degraded', checks: results });
103
+ });
104
+ ```