@malamute/ai-rules 1.0.0 → 1.3.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 (145) hide show
  1. package/README.md +272 -121
  2. package/bin/cli.js +5 -2
  3. package/configs/_shared/CLAUDE.md +52 -149
  4. package/configs/_shared/rules/conventions/documentation.md +324 -0
  5. package/configs/_shared/rules/conventions/git.md +265 -0
  6. package/configs/_shared/rules/conventions/npm.md +80 -0
  7. package/configs/_shared/{.claude/rules → rules/conventions}/performance.md +1 -1
  8. package/configs/_shared/rules/conventions/principles.md +334 -0
  9. package/configs/_shared/rules/devops/ci-cd.md +262 -0
  10. package/configs/_shared/rules/devops/docker.md +275 -0
  11. package/configs/_shared/rules/devops/nx.md +194 -0
  12. package/configs/_shared/rules/domain/backend/api-design.md +203 -0
  13. package/configs/_shared/rules/lang/csharp/async.md +220 -0
  14. package/configs/_shared/rules/lang/csharp/csharp.md +314 -0
  15. package/configs/_shared/rules/lang/csharp/linq.md +210 -0
  16. package/configs/_shared/rules/lang/python/async.md +337 -0
  17. package/configs/_shared/rules/lang/python/celery.md +476 -0
  18. package/configs/_shared/rules/lang/python/config.md +339 -0
  19. package/configs/{python/.claude/rules → _shared/rules/lang/python}/database/sqlalchemy.md +6 -1
  20. package/configs/_shared/rules/lang/python/deployment.md +523 -0
  21. package/configs/_shared/rules/lang/python/error-handling.md +330 -0
  22. package/configs/_shared/rules/lang/python/migrations.md +421 -0
  23. package/configs/_shared/rules/lang/python/python.md +172 -0
  24. package/configs/_shared/rules/lang/python/repository.md +383 -0
  25. package/configs/{python/.claude/rules → _shared/rules/lang/python}/testing.md +2 -69
  26. package/configs/_shared/rules/lang/typescript/async.md +447 -0
  27. package/configs/_shared/rules/lang/typescript/generics.md +356 -0
  28. package/configs/_shared/rules/lang/typescript/typescript.md +212 -0
  29. package/configs/_shared/rules/quality/error-handling.md +48 -0
  30. package/configs/_shared/rules/quality/logging.md +45 -0
  31. package/configs/_shared/rules/quality/observability.md +240 -0
  32. package/configs/_shared/rules/quality/testing-patterns.md +65 -0
  33. package/configs/_shared/rules/security/secrets-management.md +222 -0
  34. package/configs/_shared/skills/analysis/explore/SKILL.md +257 -0
  35. package/configs/_shared/skills/analysis/security-audit/SKILL.md +184 -0
  36. package/configs/_shared/skills/dev/api-endpoint/SKILL.md +126 -0
  37. package/configs/_shared/{.claude/commands/generate-tests.md → skills/dev/generate-tests/SKILL.md} +6 -0
  38. package/configs/_shared/{.claude/commands/fix-issue.md → skills/git/fix-issue/SKILL.md} +6 -0
  39. package/configs/_shared/{.claude/commands/review-pr.md → skills/git/review-pr/SKILL.md} +6 -0
  40. package/configs/_shared/skills/infra/deploy/SKILL.md +139 -0
  41. package/configs/_shared/skills/infra/docker/SKILL.md +95 -0
  42. package/configs/_shared/skills/infra/migration/SKILL.md +158 -0
  43. package/configs/_shared/skills/nx/nx-affected/SKILL.md +72 -0
  44. package/configs/_shared/skills/nx/nx-lib/SKILL.md +375 -0
  45. package/configs/angular/CLAUDE.md +24 -216
  46. package/configs/angular/{.claude/rules → rules/core}/components.md +69 -15
  47. package/configs/angular/rules/core/resource.md +285 -0
  48. package/configs/angular/rules/core/signals.md +323 -0
  49. package/configs/angular/rules/http.md +338 -0
  50. package/configs/angular/rules/routing.md +291 -0
  51. package/configs/angular/rules/ssr.md +312 -0
  52. package/configs/angular/rules/state/signal-store.md +408 -0
  53. package/configs/angular/{.claude/rules → rules/state}/state.md +2 -2
  54. package/configs/angular/{.claude/rules → rules}/testing.md +7 -7
  55. package/configs/angular/rules/ui/aria.md +422 -0
  56. package/configs/angular/rules/ui/forms.md +424 -0
  57. package/configs/angular/rules/ui/pipes-directives.md +335 -0
  58. package/configs/angular/{.claude/settings.json → settings.json} +3 -0
  59. package/configs/dotnet/CLAUDE.md +53 -286
  60. package/configs/dotnet/rules/background-services.md +552 -0
  61. package/configs/dotnet/rules/configuration.md +426 -0
  62. package/configs/dotnet/rules/ddd.md +447 -0
  63. package/configs/dotnet/rules/dependency-injection.md +343 -0
  64. package/configs/dotnet/rules/mediatr.md +320 -0
  65. package/configs/dotnet/rules/middleware.md +489 -0
  66. package/configs/dotnet/rules/result-pattern.md +363 -0
  67. package/configs/dotnet/rules/validation.md +388 -0
  68. package/configs/dotnet/settings.json +29 -0
  69. package/configs/fastapi/CLAUDE.md +144 -0
  70. package/configs/fastapi/rules/background-tasks.md +254 -0
  71. package/configs/fastapi/rules/dependencies.md +170 -0
  72. package/configs/{python/.claude → fastapi}/rules/fastapi.md +61 -1
  73. package/configs/fastapi/rules/lifespan.md +274 -0
  74. package/configs/fastapi/rules/middleware.md +229 -0
  75. package/configs/fastapi/rules/pydantic.md +433 -0
  76. package/configs/fastapi/rules/responses.md +251 -0
  77. package/configs/fastapi/rules/routers.md +202 -0
  78. package/configs/fastapi/rules/security.md +222 -0
  79. package/configs/fastapi/rules/testing.md +251 -0
  80. package/configs/fastapi/rules/websockets.md +298 -0
  81. package/configs/fastapi/settings.json +35 -0
  82. package/configs/flask/CLAUDE.md +166 -0
  83. package/configs/flask/rules/blueprints.md +208 -0
  84. package/configs/flask/rules/cli.md +285 -0
  85. package/configs/flask/rules/configuration.md +281 -0
  86. package/configs/flask/rules/context.md +238 -0
  87. package/configs/flask/rules/error-handlers.md +278 -0
  88. package/configs/flask/rules/extensions.md +278 -0
  89. package/configs/flask/rules/flask.md +171 -0
  90. package/configs/flask/rules/marshmallow.md +206 -0
  91. package/configs/flask/rules/security.md +267 -0
  92. package/configs/flask/rules/testing.md +284 -0
  93. package/configs/flask/settings.json +35 -0
  94. package/configs/nestjs/CLAUDE.md +57 -215
  95. package/configs/nestjs/rules/common-patterns.md +300 -0
  96. package/configs/nestjs/rules/filters.md +376 -0
  97. package/configs/nestjs/rules/interceptors.md +317 -0
  98. package/configs/nestjs/rules/middleware.md +321 -0
  99. package/configs/nestjs/{.claude/rules → rules}/modules.md +26 -0
  100. package/configs/nestjs/rules/pipes.md +351 -0
  101. package/configs/nestjs/rules/websockets.md +451 -0
  102. package/configs/nestjs/settings.json +31 -0
  103. package/configs/nextjs/CLAUDE.md +69 -331
  104. package/configs/nextjs/rules/api-routes.md +358 -0
  105. package/configs/nextjs/rules/authentication.md +355 -0
  106. package/configs/nextjs/{.claude/rules → rules}/components.md +52 -0
  107. package/configs/nextjs/rules/data-fetching.md +249 -0
  108. package/configs/nextjs/rules/database.md +400 -0
  109. package/configs/nextjs/rules/middleware.md +303 -0
  110. package/configs/nextjs/rules/routing.md +324 -0
  111. package/configs/nextjs/rules/seo.md +350 -0
  112. package/configs/nextjs/rules/server-actions.md +353 -0
  113. package/configs/nextjs/{.claude/rules → rules}/state/zustand.md +6 -6
  114. package/configs/nextjs/{.claude/settings.json → settings.json} +7 -0
  115. package/package.json +24 -9
  116. package/src/cli.js +218 -0
  117. package/src/config.js +63 -0
  118. package/src/index.js +4 -0
  119. package/src/installer.js +414 -0
  120. package/src/merge.js +109 -0
  121. package/src/tech-config.json +45 -0
  122. package/src/utils.js +88 -0
  123. package/configs/dotnet/.claude/settings.json +0 -9
  124. package/configs/nestjs/.claude/settings.json +0 -15
  125. package/configs/python/.claude/rules/flask.md +0 -332
  126. package/configs/python/.claude/settings.json +0 -18
  127. package/configs/python/CLAUDE.md +0 -273
  128. package/src/install.js +0 -315
  129. /package/configs/_shared/{.claude/rules → rules/domain/frontend}/accessibility.md +0 -0
  130. /package/configs/_shared/{.claude/rules → rules/security}/security.md +0 -0
  131. /package/configs/_shared/{.claude/skills → skills/dev}/debug/SKILL.md +0 -0
  132. /package/configs/_shared/{.claude/skills → skills/dev}/learning/SKILL.md +0 -0
  133. /package/configs/_shared/{.claude/skills → skills/dev}/spec/SKILL.md +0 -0
  134. /package/configs/_shared/{.claude/skills → skills/git}/review/SKILL.md +0 -0
  135. /package/configs/dotnet/{.claude/rules → rules}/api.md +0 -0
  136. /package/configs/dotnet/{.claude/rules → rules}/architecture.md +0 -0
  137. /package/configs/dotnet/{.claude/rules → rules}/database/efcore.md +0 -0
  138. /package/configs/dotnet/{.claude/rules → rules}/testing.md +0 -0
  139. /package/configs/nestjs/{.claude/rules → rules}/auth.md +0 -0
  140. /package/configs/nestjs/{.claude/rules → rules}/database/prisma.md +0 -0
  141. /package/configs/nestjs/{.claude/rules → rules}/database/typeorm.md +0 -0
  142. /package/configs/nestjs/{.claude/rules → rules}/testing.md +0 -0
  143. /package/configs/nestjs/{.claude/rules → rules}/validation.md +0 -0
  144. /package/configs/nextjs/{.claude/rules → rules}/state/redux-toolkit.md +0 -0
  145. /package/configs/nextjs/{.claude/rules → rules}/testing.md +0 -0
@@ -0,0 +1,203 @@
1
+ ---
2
+ paths:
3
+ - "**/controllers/**"
4
+ - "**/routes/**"
5
+ - "**/routers/**"
6
+ - "**/endpoints/**"
7
+ - "**/*.controller.ts"
8
+ - "**/*_router.py"
9
+ ---
10
+
11
+ # API Design Principles
12
+
13
+ ## REST Conventions
14
+
15
+ ### HTTP Methods
16
+
17
+ | Method | Usage | Idempotent | Response |
18
+ |--------|-------|------------|----------|
19
+ | `GET` | Read resource(s) | Yes | 200 + data |
20
+ | `POST` | Create resource | No | 201 + created resource |
21
+ | `PUT` | Full update | Yes | 200 + updated resource |
22
+ | `PATCH` | Partial update | Yes | 200 + updated resource |
23
+ | `DELETE` | Remove resource | Yes | 204 No Content |
24
+
25
+ ### URL Structure
26
+
27
+ ```
28
+ GET /api/v1/users # List users
29
+ GET /api/v1/users/:id # Get single user
30
+ POST /api/v1/users # Create user
31
+ PUT /api/v1/users/:id # Replace user
32
+ PATCH /api/v1/users/:id # Update user fields
33
+ DELETE /api/v1/users/:id # Delete user
34
+
35
+ # Nested resources (max 2 levels)
36
+ GET /api/v1/users/:id/orders
37
+ POST /api/v1/users/:id/orders
38
+
39
+ # Actions (when CRUD doesn't fit)
40
+ POST /api/v1/users/:id/activate
41
+ POST /api/v1/orders/:id/cancel
42
+ ```
43
+
44
+ ### Naming Rules
45
+
46
+ - Use **plural nouns**: `/users`, `/orders`, `/products`
47
+ - Use **kebab-case**: `/user-profiles`, `/order-items`
48
+ - Avoid verbs in URLs (use HTTP methods instead)
49
+ - Use query params for filtering: `/users?status=active&role=admin`
50
+
51
+ ## Response Format
52
+
53
+ ### Success Response
54
+
55
+ ```json
56
+ {
57
+ "data": { ... },
58
+ "meta": {
59
+ "timestamp": "2024-01-15T10:30:00Z",
60
+ "requestId": "abc-123"
61
+ }
62
+ }
63
+ ```
64
+
65
+ ### List Response with Pagination
66
+
67
+ ```json
68
+ {
69
+ "data": [ ... ],
70
+ "meta": {
71
+ "total": 100,
72
+ "page": 1,
73
+ "pageSize": 20,
74
+ "totalPages": 5,
75
+ "hasNext": true,
76
+ "hasPrevious": false
77
+ }
78
+ }
79
+ ```
80
+
81
+ ### Error Response (RFC 7807 Problem Details)
82
+
83
+ ```json
84
+ {
85
+ "type": "https://api.example.com/errors/validation",
86
+ "title": "Validation Error",
87
+ "status": 400,
88
+ "detail": "One or more fields failed validation",
89
+ "instance": "/api/v1/users",
90
+ "errors": [
91
+ { "field": "email", "message": "Invalid email format" },
92
+ { "field": "age", "message": "Must be at least 18" }
93
+ ],
94
+ "traceId": "abc-123"
95
+ }
96
+ ```
97
+
98
+ ## Status Codes
99
+
100
+ | Code | When to Use |
101
+ |------|-------------|
102
+ | `200` | Successful GET, PUT, PATCH |
103
+ | `201` | Successful POST (resource created) |
104
+ | `204` | Successful DELETE (no content) |
105
+ | `400` | Bad request (validation error) |
106
+ | `401` | Unauthorized (not authenticated) |
107
+ | `403` | Forbidden (authenticated but not allowed) |
108
+ | `404` | Resource not found |
109
+ | `409` | Conflict (duplicate resource) |
110
+ | `422` | Unprocessable entity (business rule violation) |
111
+ | `429` | Too many requests (rate limited) |
112
+ | `500` | Internal server error |
113
+
114
+ ## Pagination
115
+
116
+ ### Offset-based (simple, for small datasets)
117
+
118
+ ```
119
+ GET /api/v1/users?page=2&pageSize=20
120
+ ```
121
+
122
+ ### Cursor-based (performant, for large datasets)
123
+
124
+ ```
125
+ GET /api/v1/users?cursor=eyJpZCI6MTAwfQ&limit=20
126
+ ```
127
+
128
+ Response includes next cursor:
129
+ ```json
130
+ {
131
+ "data": [...],
132
+ "meta": {
133
+ "nextCursor": "eyJpZCI6MTIwfQ",
134
+ "hasMore": true
135
+ }
136
+ }
137
+ ```
138
+
139
+ ## Filtering & Sorting
140
+
141
+ ```
142
+ # Filtering
143
+ GET /api/v1/users?status=active&role=admin
144
+ GET /api/v1/orders?createdAt[gte]=2024-01-01&createdAt[lte]=2024-12-31
145
+
146
+ # Sorting
147
+ GET /api/v1/users?sort=createdAt:desc
148
+ GET /api/v1/users?sort=lastName:asc,firstName:asc
149
+
150
+ # Field selection (sparse fieldsets)
151
+ GET /api/v1/users?fields=id,name,email
152
+ ```
153
+
154
+ ## Versioning
155
+
156
+ ### URL Path (recommended)
157
+
158
+ ```
159
+ /api/v1/users
160
+ /api/v2/users
161
+ ```
162
+
163
+ ### Header-based (alternative)
164
+
165
+ ```
166
+ Accept: application/vnd.api+json; version=1
167
+ ```
168
+
169
+ ## Rate Limiting
170
+
171
+ Include headers in response:
172
+
173
+ ```
174
+ X-RateLimit-Limit: 100
175
+ X-RateLimit-Remaining: 95
176
+ X-RateLimit-Reset: 1640000000
177
+ Retry-After: 60 (when 429)
178
+ ```
179
+
180
+ ## HATEOAS (optional, for discoverability)
181
+
182
+ ```json
183
+ {
184
+ "data": {
185
+ "id": "123",
186
+ "name": "John"
187
+ },
188
+ "links": {
189
+ "self": "/api/v1/users/123",
190
+ "orders": "/api/v1/users/123/orders",
191
+ "profile": "/api/v1/users/123/profile"
192
+ }
193
+ }
194
+ ```
195
+
196
+ ## Anti-patterns
197
+
198
+ - Verbs in URLs: `/api/getUsers` → `/api/users`
199
+ - Singular nouns: `/api/user/123` → `/api/users/123`
200
+ - Deeply nested: `/api/users/1/orders/2/items/3` → `/api/order-items/3`
201
+ - Inconsistent casing: `/api/userProfiles` → `/api/user-profiles`
202
+ - Returning 200 for errors
203
+ - Exposing internal IDs or sensitive data
@@ -0,0 +1,220 @@
1
+ ---
2
+ paths:
3
+ - "**/*.cs"
4
+ ---
5
+
6
+ # C# Async Patterns
7
+
8
+ ## Task vs ValueTask
9
+
10
+ ```csharp
11
+ // Use Task for most async operations
12
+ public async Task<User> GetUserAsync(int id)
13
+
14
+ // Use ValueTask when:
15
+ // 1. Method often completes synchronously
16
+ // 2. Hot path with many allocations
17
+ public async ValueTask<User?> GetCachedUserAsync(int id)
18
+ {
19
+ if (_cache.TryGetValue(id, out var user))
20
+ return user; // Synchronous path - no allocation
21
+
22
+ return await _repository.GetByIdAsync(id);
23
+ }
24
+
25
+ // BAD - ValueTask misuse (awaiting multiple times)
26
+ var task = GetValueTaskAsync();
27
+ await task;
28
+ await task; // Undefined behavior!
29
+ ```
30
+
31
+ ## Parallel Execution
32
+
33
+ ```csharp
34
+ // GOOD - parallel independent operations
35
+ var userTask = _userService.GetUserAsync(userId);
36
+ var ordersTask = _orderService.GetOrdersAsync(userId);
37
+ var prefsTask = _prefService.GetPreferencesAsync(userId);
38
+
39
+ await Task.WhenAll(userTask, ordersTask, prefsTask);
40
+
41
+ var user = await userTask;
42
+ var orders = await ordersTask;
43
+ var prefs = await prefsTask;
44
+
45
+ // BAD - sequential when parallel is possible
46
+ var user = await _userService.GetUserAsync(userId);
47
+ var orders = await _orderService.GetOrdersAsync(userId);
48
+ var prefs = await _prefService.GetPreferencesAsync(userId);
49
+ ```
50
+
51
+ ## Task.WhenAll Error Handling
52
+
53
+ ```csharp
54
+ // Handle all exceptions from parallel tasks
55
+ try
56
+ {
57
+ await Task.WhenAll(task1, task2, task3);
58
+ }
59
+ catch (Exception)
60
+ {
61
+ // Only first exception is thrown
62
+ // Check individual tasks for all errors
63
+ var exceptions = new[] { task1, task2, task3 }
64
+ .Where(t => t.IsFaulted)
65
+ .SelectMany(t => t.Exception!.InnerExceptions);
66
+
67
+ foreach (var ex in exceptions)
68
+ {
69
+ _logger.LogError(ex, "Task failed");
70
+ }
71
+ throw;
72
+ }
73
+ ```
74
+
75
+ ## Cancellation
76
+
77
+ ```csharp
78
+ // GOOD - check cancellation in loops
79
+ public async Task ProcessBatchAsync(
80
+ IEnumerable<Item> items,
81
+ CancellationToken cancellationToken)
82
+ {
83
+ foreach (var item in items)
84
+ {
85
+ cancellationToken.ThrowIfCancellationRequested();
86
+ await ProcessItemAsync(item, cancellationToken);
87
+ }
88
+ }
89
+
90
+ // GOOD - cancellation with timeout
91
+ using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
92
+ try
93
+ {
94
+ await LongOperationAsync(cts.Token);
95
+ }
96
+ catch (OperationCanceledException)
97
+ {
98
+ _logger.LogWarning("Operation timed out");
99
+ }
100
+
101
+ // Link multiple cancellation tokens
102
+ using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(
103
+ requestToken,
104
+ applicationStoppingToken);
105
+ ```
106
+
107
+ ## Async Streams
108
+
109
+ ```csharp
110
+ // GOOD - IAsyncEnumerable for streaming data
111
+ public async IAsyncEnumerable<User> GetUsersStreamAsync(
112
+ [EnumeratorCancellation] CancellationToken cancellationToken = default)
113
+ {
114
+ await foreach (var user in _context.Users.AsAsyncEnumerable()
115
+ .WithCancellation(cancellationToken))
116
+ {
117
+ yield return user;
118
+ }
119
+ }
120
+
121
+ // Consuming async stream
122
+ await foreach (var user in GetUsersStreamAsync(cancellationToken))
123
+ {
124
+ await ProcessUserAsync(user);
125
+ }
126
+ ```
127
+
128
+ ## Avoid Async Pitfalls
129
+
130
+ ```csharp
131
+ // BAD - async void (except event handlers)
132
+ public async void ProcessAsync() // Exceptions lost, can't await
133
+ {
134
+ await Task.Delay(1000);
135
+ }
136
+
137
+ // GOOD - return Task
138
+ public async Task ProcessAsync()
139
+ {
140
+ await Task.Delay(1000);
141
+ }
142
+
143
+ // BAD - blocking on async (.Result, .Wait())
144
+ public void Process()
145
+ {
146
+ var result = GetDataAsync().Result; // Deadlock risk!
147
+ }
148
+
149
+ // BAD - unnecessary async/await
150
+ public async Task<int> GetCountAsync()
151
+ {
152
+ return await _repository.CountAsync(); // Just return the task
153
+ }
154
+
155
+ // GOOD - return task directly when no additional await needed
156
+ public Task<int> GetCountAsync()
157
+ {
158
+ return _repository.CountAsync();
159
+ }
160
+ ```
161
+
162
+ ## Thread Safety
163
+
164
+ ```csharp
165
+ // GOOD - use concurrent collections
166
+ private readonly ConcurrentDictionary<int, User> _cache = new();
167
+
168
+ // GOOD - SemaphoreSlim for async locking
169
+ private readonly SemaphoreSlim _semaphore = new(1, 1);
170
+
171
+ public async Task<User> GetOrCreateUserAsync(int id)
172
+ {
173
+ await _semaphore.WaitAsync();
174
+ try
175
+ {
176
+ if (!_cache.TryGetValue(id, out var user))
177
+ {
178
+ user = await _repository.GetByIdAsync(id);
179
+ _cache[id] = user;
180
+ }
181
+ return user;
182
+ }
183
+ finally
184
+ {
185
+ _semaphore.Release();
186
+ }
187
+ }
188
+
189
+ // BAD - lock with async (will not compile correctly)
190
+ lock (_syncObject)
191
+ {
192
+ await SomeAsyncOperation(); // Can't await inside lock
193
+ }
194
+ ```
195
+
196
+ ## Channel for Producer/Consumer
197
+
198
+ ```csharp
199
+ public class BackgroundProcessor
200
+ {
201
+ private readonly Channel<WorkItem> _channel =
202
+ Channel.CreateBounded<WorkItem>(new BoundedChannelOptions(100)
203
+ {
204
+ FullMode = BoundedChannelFullMode.Wait
205
+ });
206
+
207
+ public async ValueTask QueueWorkAsync(WorkItem item)
208
+ {
209
+ await _channel.Writer.WriteAsync(item);
210
+ }
211
+
212
+ public async Task ProcessAsync(CancellationToken stoppingToken)
213
+ {
214
+ await foreach (var item in _channel.Reader.ReadAllAsync(stoppingToken))
215
+ {
216
+ await ProcessItemAsync(item);
217
+ }
218
+ }
219
+ }
220
+ ```