@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,337 @@
1
+ ---
2
+ paths:
3
+ - "**/handlers/**/*.py"
4
+ - "**/services/**/*.py"
5
+ - "**/consumers/**/*.py"
6
+ - "**/workers/**/*.py"
7
+ - "**/*_async*.py"
8
+ ---
9
+
10
+ # Python Async Patterns
11
+
12
+ ## Async Function Basics
13
+
14
+ ```python
15
+ import asyncio
16
+ from typing import AsyncIterator
17
+
18
+ # Always use async def for I/O operations
19
+ async def fetch_user(user_id: int) -> User:
20
+ return await db.users.get(user_id)
21
+
22
+ # Never mix sync I/O in async functions
23
+ # BAD
24
+ async def bad_fetch():
25
+ return requests.get(url) # Blocks event loop!
26
+
27
+ # GOOD
28
+ async def good_fetch():
29
+ async with httpx.AsyncClient() as client:
30
+ return await client.get(url)
31
+ ```
32
+
33
+ ## Concurrent Execution
34
+
35
+ ```python
36
+ import asyncio
37
+
38
+ # Run tasks concurrently
39
+ async def fetch_all_data():
40
+ # Wrong - sequential execution
41
+ users = await fetch_users()
42
+ orders = await fetch_orders()
43
+ products = await fetch_products()
44
+
45
+ # Right - concurrent execution
46
+ users, orders, products = await asyncio.gather(
47
+ fetch_users(),
48
+ fetch_orders(),
49
+ fetch_products(),
50
+ )
51
+
52
+ return users, orders, products
53
+
54
+ # With error handling
55
+ async def fetch_with_errors():
56
+ results = await asyncio.gather(
57
+ fetch_users(),
58
+ fetch_orders(),
59
+ fetch_products(),
60
+ return_exceptions=True, # Don't fail on first error
61
+ )
62
+
63
+ for result in results:
64
+ if isinstance(result, Exception):
65
+ logger.error(f"Task failed: {result}")
66
+ ```
67
+
68
+ ## TaskGroup (Python 3.11+)
69
+
70
+ ```python
71
+ async def process_items(items: list[Item]) -> list[Result]:
72
+ results = []
73
+
74
+ async with asyncio.TaskGroup() as tg:
75
+ for item in items:
76
+ tg.create_task(process_item(item))
77
+
78
+ # All tasks complete when exiting context
79
+ return results
80
+
81
+ # With exception handling
82
+ async def process_with_handling(items: list[Item]):
83
+ try:
84
+ async with asyncio.TaskGroup() as tg:
85
+ for item in items:
86
+ tg.create_task(process_item(item))
87
+ except* ValueError as eg:
88
+ for exc in eg.exceptions:
89
+ logger.error(f"Validation error: {exc}")
90
+ except* ConnectionError as eg:
91
+ for exc in eg.exceptions:
92
+ logger.error(f"Connection error: {exc}")
93
+ ```
94
+
95
+ ## Async Context Managers
96
+
97
+ ```python
98
+ from contextlib import asynccontextmanager
99
+
100
+ @asynccontextmanager
101
+ async def get_db_connection():
102
+ conn = await create_connection()
103
+ try:
104
+ yield conn
105
+ finally:
106
+ await conn.close()
107
+
108
+ # Usage
109
+ async def query_users():
110
+ async with get_db_connection() as conn:
111
+ return await conn.fetch("SELECT * FROM users")
112
+
113
+ # Class-based context manager
114
+ class AsyncDatabaseSession:
115
+ async def __aenter__(self):
116
+ self.session = await create_session()
117
+ return self.session
118
+
119
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
120
+ if exc_type:
121
+ await self.session.rollback()
122
+ else:
123
+ await self.session.commit()
124
+ await self.session.close()
125
+ ```
126
+
127
+ ## Async Iterators
128
+
129
+ ```python
130
+ from typing import AsyncIterator
131
+
132
+ async def fetch_pages(url: str) -> AsyncIterator[Page]:
133
+ next_url = url
134
+ while next_url:
135
+ response = await fetch(next_url)
136
+ yield response.data
137
+ next_url = response.next_url
138
+
139
+ # Usage
140
+ async def process_all_pages():
141
+ async for page in fetch_pages("/api/items"):
142
+ for item in page.items:
143
+ await process_item(item)
144
+
145
+ # Async comprehension
146
+ async def get_all_items():
147
+ return [
148
+ item
149
+ async for page in fetch_pages("/api/items")
150
+ for item in page.items
151
+ ]
152
+ ```
153
+
154
+ ## Semaphore for Rate Limiting
155
+
156
+ ```python
157
+ import asyncio
158
+
159
+ async def fetch_with_limit(urls: list[str], max_concurrent: int = 10):
160
+ semaphore = asyncio.Semaphore(max_concurrent)
161
+
162
+ async def fetch_one(url: str):
163
+ async with semaphore:
164
+ async with httpx.AsyncClient() as client:
165
+ return await client.get(url)
166
+
167
+ return await asyncio.gather(*[fetch_one(url) for url in urls])
168
+ ```
169
+
170
+ ## Timeouts
171
+
172
+ ```python
173
+ import asyncio
174
+
175
+ async def fetch_with_timeout(url: str, timeout: float = 10.0):
176
+ try:
177
+ async with asyncio.timeout(timeout):
178
+ return await fetch(url)
179
+ except asyncio.TimeoutError:
180
+ logger.error(f"Timeout fetching {url}")
181
+ raise
182
+
183
+ # Or with wait_for (older style)
184
+ async def fetch_with_wait_for(url: str):
185
+ try:
186
+ return await asyncio.wait_for(fetch(url), timeout=10.0)
187
+ except asyncio.TimeoutError:
188
+ raise
189
+ ```
190
+
191
+ ## Background Tasks
192
+
193
+ ```python
194
+ import asyncio
195
+ from collections.abc import Callable
196
+
197
+ class BackgroundTasks:
198
+ def __init__(self):
199
+ self._tasks: set[asyncio.Task] = set()
200
+
201
+ def add_task(self, coro):
202
+ task = asyncio.create_task(coro)
203
+ self._tasks.add(task)
204
+ task.add_done_callback(self._tasks.discard)
205
+
206
+ async def shutdown(self):
207
+ for task in self._tasks:
208
+ task.cancel()
209
+ await asyncio.gather(*self._tasks, return_exceptions=True)
210
+
211
+ # Usage in FastAPI
212
+ background = BackgroundTasks()
213
+
214
+ @app.post("/orders")
215
+ async def create_order(order: Order):
216
+ saved = await save_order(order)
217
+ background.add_task(send_notification(order))
218
+ return saved
219
+
220
+ @app.on_event("shutdown")
221
+ async def shutdown():
222
+ await background.shutdown()
223
+ ```
224
+
225
+ ## Async Queue
226
+
227
+ ```python
228
+ import asyncio
229
+
230
+ async def producer(queue: asyncio.Queue[int]):
231
+ for i in range(10):
232
+ await queue.put(i)
233
+ print(f"Produced: {i}")
234
+ await asyncio.sleep(0.1)
235
+ await queue.put(None) # Sentinel to stop
236
+
237
+ async def consumer(queue: asyncio.Queue[int]):
238
+ while True:
239
+ item = await queue.get()
240
+ if item is None:
241
+ break
242
+ print(f"Consumed: {item}")
243
+ queue.task_done()
244
+
245
+ async def main():
246
+ queue: asyncio.Queue[int] = asyncio.Queue(maxsize=5)
247
+
248
+ await asyncio.gather(
249
+ producer(queue),
250
+ consumer(queue),
251
+ )
252
+ ```
253
+
254
+ ## Async Lock
255
+
256
+ ```python
257
+ import asyncio
258
+
259
+ class Counter:
260
+ def __init__(self):
261
+ self._value = 0
262
+ self._lock = asyncio.Lock()
263
+
264
+ async def increment(self):
265
+ async with self._lock:
266
+ self._value += 1
267
+ return self._value
268
+
269
+ async def get(self) -> int:
270
+ async with self._lock:
271
+ return self._value
272
+ ```
273
+
274
+ ## SQLAlchemy Async
275
+
276
+ ```python
277
+ from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
278
+ from sqlalchemy.orm import sessionmaker
279
+
280
+ # Create async engine
281
+ engine = create_async_engine(
282
+ "postgresql+asyncpg://user:pass@localhost/db",
283
+ echo=True,
284
+ )
285
+
286
+ # Async session factory
287
+ async_session = sessionmaker(
288
+ engine,
289
+ class_=AsyncSession,
290
+ expire_on_commit=False,
291
+ )
292
+
293
+ # Usage
294
+ async def get_user(user_id: int) -> User | None:
295
+ async with async_session() as session:
296
+ result = await session.execute(
297
+ select(User).where(User.id == user_id)
298
+ )
299
+ return result.scalar_one_or_none()
300
+
301
+ # FastAPI dependency
302
+ async def get_db() -> AsyncIterator[AsyncSession]:
303
+ async with async_session() as session:
304
+ try:
305
+ yield session
306
+ await session.commit()
307
+ except Exception:
308
+ await session.rollback()
309
+ raise
310
+ ```
311
+
312
+ ## httpx Async Client
313
+
314
+ ```python
315
+ import httpx
316
+
317
+ # Reuse client for connection pooling
318
+ class ApiClient:
319
+ def __init__(self, base_url: str):
320
+ self._client = httpx.AsyncClient(
321
+ base_url=base_url,
322
+ timeout=30.0,
323
+ headers={"User-Agent": "MyApp/1.0"},
324
+ )
325
+
326
+ async def get(self, path: str) -> dict:
327
+ response = await self._client.get(path)
328
+ response.raise_for_status()
329
+ return response.json()
330
+
331
+ async def close(self):
332
+ await self._client.aclose()
333
+
334
+ # Usage with context manager
335
+ async with httpx.AsyncClient() as client:
336
+ response = await client.get("https://api.example.com/data")
337
+ ```