@malamute/ai-rules 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +270 -121
- package/bin/cli.js +5 -2
- package/configs/_shared/.claude/rules/conventions/documentation.md +324 -0
- package/configs/_shared/.claude/rules/conventions/git.md +265 -0
- package/configs/_shared/.claude/rules/{performance.md → conventions/performance.md} +1 -1
- package/configs/_shared/.claude/rules/conventions/principles.md +334 -0
- package/configs/_shared/.claude/rules/devops/ci-cd.md +262 -0
- package/configs/_shared/.claude/rules/devops/docker.md +275 -0
- package/configs/_shared/.claude/rules/devops/nx.md +194 -0
- package/configs/_shared/.claude/rules/domain/backend/api-design.md +203 -0
- package/configs/_shared/.claude/rules/lang/csharp/async.md +220 -0
- package/configs/_shared/.claude/rules/lang/csharp/csharp.md +314 -0
- package/configs/_shared/.claude/rules/lang/csharp/linq.md +210 -0
- package/configs/_shared/.claude/rules/lang/python/async.md +337 -0
- package/configs/_shared/.claude/rules/lang/python/celery.md +476 -0
- package/configs/_shared/.claude/rules/lang/python/config.md +339 -0
- package/configs/{python/.claude/rules → _shared/.claude/rules/lang/python}/database/sqlalchemy.md +6 -1
- package/configs/_shared/.claude/rules/lang/python/deployment.md +523 -0
- package/configs/_shared/.claude/rules/lang/python/error-handling.md +330 -0
- package/configs/_shared/.claude/rules/lang/python/migrations.md +421 -0
- package/configs/_shared/.claude/rules/lang/python/python.md +172 -0
- package/configs/_shared/.claude/rules/lang/python/repository.md +383 -0
- package/configs/{python/.claude/rules → _shared/.claude/rules/lang/python}/testing.md +2 -69
- package/configs/_shared/.claude/rules/lang/typescript/async.md +447 -0
- package/configs/_shared/.claude/rules/lang/typescript/generics.md +356 -0
- package/configs/_shared/.claude/rules/lang/typescript/typescript.md +212 -0
- package/configs/_shared/.claude/rules/quality/error-handling.md +48 -0
- package/configs/_shared/.claude/rules/quality/logging.md +45 -0
- package/configs/_shared/.claude/rules/quality/observability.md +240 -0
- package/configs/_shared/.claude/rules/quality/testing-patterns.md +65 -0
- package/configs/_shared/.claude/rules/security/secrets-management.md +222 -0
- package/configs/_shared/.claude/skills/analysis/explore/SKILL.md +257 -0
- package/configs/_shared/.claude/skills/analysis/security-audit/SKILL.md +184 -0
- package/configs/_shared/.claude/skills/dev/api-endpoint/SKILL.md +126 -0
- package/configs/_shared/.claude/{commands/generate-tests.md → skills/dev/generate-tests/SKILL.md} +6 -0
- package/configs/_shared/.claude/{commands/fix-issue.md → skills/git/fix-issue/SKILL.md} +6 -0
- package/configs/_shared/.claude/{commands/review-pr.md → skills/git/review-pr/SKILL.md} +6 -0
- package/configs/_shared/.claude/skills/infra/deploy/SKILL.md +139 -0
- package/configs/_shared/.claude/skills/infra/docker/SKILL.md +95 -0
- package/configs/_shared/.claude/skills/infra/migration/SKILL.md +158 -0
- package/configs/_shared/.claude/skills/nx/nx-affected/SKILL.md +72 -0
- package/configs/_shared/.claude/skills/nx/nx-lib/SKILL.md +375 -0
- package/configs/_shared/CLAUDE.md +52 -149
- package/configs/angular/.claude/rules/{components.md → core/components.md} +69 -15
- package/configs/angular/.claude/rules/core/resource.md +285 -0
- package/configs/angular/.claude/rules/core/signals.md +323 -0
- package/configs/angular/.claude/rules/http.md +338 -0
- package/configs/angular/.claude/rules/routing.md +291 -0
- package/configs/angular/.claude/rules/ssr.md +312 -0
- package/configs/angular/.claude/rules/state/signal-store.md +408 -0
- package/configs/angular/.claude/rules/{state.md → state/state.md} +2 -2
- package/configs/angular/.claude/rules/testing.md +7 -7
- package/configs/angular/.claude/rules/ui/aria.md +422 -0
- package/configs/angular/.claude/rules/ui/forms.md +424 -0
- package/configs/angular/.claude/rules/ui/pipes-directives.md +335 -0
- package/configs/angular/.claude/settings.json +1 -0
- package/configs/angular/.claude/skills/ngrx-slice/SKILL.md +362 -0
- package/configs/angular/.claude/skills/signal-store/SKILL.md +445 -0
- package/configs/angular/CLAUDE.md +24 -216
- package/configs/dotnet/.claude/rules/background-services.md +552 -0
- package/configs/dotnet/.claude/rules/configuration.md +426 -0
- package/configs/dotnet/.claude/rules/ddd.md +447 -0
- package/configs/dotnet/.claude/rules/dependency-injection.md +343 -0
- package/configs/dotnet/.claude/rules/mediatr.md +320 -0
- package/configs/dotnet/.claude/rules/middleware.md +489 -0
- package/configs/dotnet/.claude/rules/result-pattern.md +363 -0
- package/configs/dotnet/.claude/rules/validation.md +388 -0
- package/configs/dotnet/.claude/settings.json +21 -3
- package/configs/dotnet/CLAUDE.md +53 -286
- package/configs/fastapi/.claude/rules/background-tasks.md +254 -0
- package/configs/fastapi/.claude/rules/dependencies.md +170 -0
- package/configs/{python → fastapi}/.claude/rules/fastapi.md +61 -1
- package/configs/fastapi/.claude/rules/lifespan.md +274 -0
- package/configs/fastapi/.claude/rules/middleware.md +229 -0
- package/configs/fastapi/.claude/rules/pydantic.md +433 -0
- package/configs/fastapi/.claude/rules/responses.md +251 -0
- package/configs/fastapi/.claude/rules/routers.md +202 -0
- package/configs/fastapi/.claude/rules/security.md +222 -0
- package/configs/fastapi/.claude/rules/testing.md +251 -0
- package/configs/fastapi/.claude/rules/websockets.md +298 -0
- package/configs/fastapi/.claude/settings.json +33 -0
- package/configs/fastapi/CLAUDE.md +144 -0
- package/configs/flask/.claude/rules/blueprints.md +208 -0
- package/configs/flask/.claude/rules/cli.md +285 -0
- package/configs/flask/.claude/rules/configuration.md +281 -0
- package/configs/flask/.claude/rules/context.md +238 -0
- package/configs/flask/.claude/rules/error-handlers.md +278 -0
- package/configs/flask/.claude/rules/extensions.md +278 -0
- package/configs/flask/.claude/rules/flask.md +171 -0
- package/configs/flask/.claude/rules/marshmallow.md +206 -0
- package/configs/flask/.claude/rules/security.md +267 -0
- package/configs/flask/.claude/rules/testing.md +284 -0
- package/configs/flask/.claude/settings.json +33 -0
- package/configs/flask/CLAUDE.md +166 -0
- package/configs/nestjs/.claude/rules/common-patterns.md +300 -0
- package/configs/nestjs/.claude/rules/filters.md +376 -0
- package/configs/nestjs/.claude/rules/interceptors.md +317 -0
- package/configs/nestjs/.claude/rules/middleware.md +321 -0
- package/configs/nestjs/.claude/rules/modules.md +26 -0
- package/configs/nestjs/.claude/rules/pipes.md +351 -0
- package/configs/nestjs/.claude/rules/websockets.md +451 -0
- package/configs/nestjs/.claude/settings.json +16 -2
- package/configs/nestjs/CLAUDE.md +57 -215
- package/configs/nextjs/.claude/rules/api-routes.md +358 -0
- package/configs/nextjs/.claude/rules/authentication.md +355 -0
- package/configs/nextjs/.claude/rules/components.md +52 -0
- package/configs/nextjs/.claude/rules/data-fetching.md +249 -0
- package/configs/nextjs/.claude/rules/database.md +400 -0
- package/configs/nextjs/.claude/rules/middleware.md +303 -0
- package/configs/nextjs/.claude/rules/routing.md +324 -0
- package/configs/nextjs/.claude/rules/seo.md +350 -0
- package/configs/nextjs/.claude/rules/server-actions.md +353 -0
- package/configs/nextjs/.claude/rules/state/zustand.md +6 -6
- package/configs/nextjs/.claude/settings.json +5 -0
- package/configs/nextjs/CLAUDE.md +69 -331
- package/package.json +23 -9
- package/src/cli.js +220 -0
- package/src/config.js +29 -0
- package/src/index.js +13 -0
- package/src/installer.js +361 -0
- package/src/merge.js +116 -0
- package/src/tech-config.json +29 -0
- package/src/utils.js +96 -0
- package/configs/python/.claude/rules/flask.md +0 -332
- package/configs/python/.claude/settings.json +0 -18
- package/configs/python/CLAUDE.md +0 -273
- package/src/install.js +0 -315
- /package/configs/_shared/.claude/rules/{accessibility.md → domain/frontend/accessibility.md} +0 -0
- /package/configs/_shared/.claude/rules/{security.md → security/security.md} +0 -0
- /package/configs/_shared/.claude/skills/{debug → dev/debug}/SKILL.md +0 -0
- /package/configs/_shared/.claude/skills/{learning → dev/learning}/SKILL.md +0 -0
- /package/configs/_shared/.claude/skills/{spec → dev/spec}/SKILL.md +0 -0
- /package/configs/_shared/.claude/skills/{review → git/review}/SKILL.md +0 -0
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/config.py"
|
|
4
|
+
- "**/settings.py"
|
|
5
|
+
- "**/config/**/*.py"
|
|
6
|
+
- "**/settings/**/*.py"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Python Configuration (pydantic-settings)
|
|
10
|
+
|
|
11
|
+
## Basic Settings
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
# config.py
|
|
15
|
+
from pydantic import Field, PostgresDsn, RedisDsn
|
|
16
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Settings(BaseSettings):
|
|
20
|
+
"""Application settings loaded from environment variables."""
|
|
21
|
+
|
|
22
|
+
model_config = SettingsConfigDict(
|
|
23
|
+
env_file=".env",
|
|
24
|
+
env_file_encoding="utf-8",
|
|
25
|
+
case_sensitive=False,
|
|
26
|
+
extra="ignore",
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
# Application
|
|
30
|
+
app_name: str = "MyApp"
|
|
31
|
+
debug: bool = False
|
|
32
|
+
environment: str = Field(default="development", pattern="^(development|staging|production)$")
|
|
33
|
+
|
|
34
|
+
# Server
|
|
35
|
+
host: str = "0.0.0.0"
|
|
36
|
+
port: int = 8000
|
|
37
|
+
workers: int = 4
|
|
38
|
+
|
|
39
|
+
# Database
|
|
40
|
+
database_url: PostgresDsn
|
|
41
|
+
database_pool_size: int = 5
|
|
42
|
+
database_max_overflow: int = 10
|
|
43
|
+
|
|
44
|
+
# Redis
|
|
45
|
+
redis_url: RedisDsn | None = None
|
|
46
|
+
|
|
47
|
+
# Security
|
|
48
|
+
secret_key: str
|
|
49
|
+
jwt_algorithm: str = "HS256"
|
|
50
|
+
access_token_expire_minutes: int = 30
|
|
51
|
+
refresh_token_expire_days: int = 7
|
|
52
|
+
|
|
53
|
+
# CORS
|
|
54
|
+
cors_origins: list[str] = ["http://localhost:3000"]
|
|
55
|
+
|
|
56
|
+
# External APIs
|
|
57
|
+
stripe_api_key: str | None = None
|
|
58
|
+
sendgrid_api_key: str | None = None
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# Singleton instance
|
|
62
|
+
settings = Settings()
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Nested Settings
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
# config/settings.py
|
|
69
|
+
from pydantic import BaseModel
|
|
70
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class DatabaseSettings(BaseModel):
|
|
74
|
+
"""Database configuration."""
|
|
75
|
+
|
|
76
|
+
url: str
|
|
77
|
+
pool_size: int = 5
|
|
78
|
+
max_overflow: int = 10
|
|
79
|
+
echo: bool = False
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class RedisSettings(BaseModel):
|
|
83
|
+
"""Redis configuration."""
|
|
84
|
+
|
|
85
|
+
url: str
|
|
86
|
+
password: str | None = None
|
|
87
|
+
db: int = 0
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class AuthSettings(BaseModel):
|
|
91
|
+
"""Authentication configuration."""
|
|
92
|
+
|
|
93
|
+
secret_key: str
|
|
94
|
+
algorithm: str = "HS256"
|
|
95
|
+
access_token_expire_minutes: int = 30
|
|
96
|
+
refresh_token_expire_days: int = 7
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
class Settings(BaseSettings):
|
|
100
|
+
"""Root settings with nested configuration."""
|
|
101
|
+
|
|
102
|
+
model_config = SettingsConfigDict(
|
|
103
|
+
env_file=".env",
|
|
104
|
+
env_nested_delimiter="__", # DATABASE__URL -> database.url
|
|
105
|
+
case_sensitive=False,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
app_name: str = "MyApp"
|
|
109
|
+
debug: bool = False
|
|
110
|
+
environment: str = "development"
|
|
111
|
+
|
|
112
|
+
database: DatabaseSettings
|
|
113
|
+
redis: RedisSettings | None = None
|
|
114
|
+
auth: AuthSettings
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
settings = Settings()
|
|
118
|
+
|
|
119
|
+
# Access: settings.database.url, settings.auth.secret_key
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Environment-Specific Settings
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
# config/base.py
|
|
126
|
+
from pydantic_settings import BaseSettings
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class BaseAppSettings(BaseSettings):
|
|
130
|
+
"""Base settings shared across all environments."""
|
|
131
|
+
|
|
132
|
+
app_name: str = "MyApp"
|
|
133
|
+
api_prefix: str = "/api/v1"
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
# config/development.py
|
|
137
|
+
class DevelopmentSettings(BaseAppSettings):
|
|
138
|
+
debug: bool = True
|
|
139
|
+
database_url: str = "postgresql://localhost/myapp_dev"
|
|
140
|
+
log_level: str = "DEBUG"
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
# config/production.py
|
|
144
|
+
class ProductionSettings(BaseAppSettings):
|
|
145
|
+
debug: bool = False
|
|
146
|
+
database_url: str # Required in production
|
|
147
|
+
log_level: str = "INFO"
|
|
148
|
+
|
|
149
|
+
model_config = SettingsConfigDict(
|
|
150
|
+
env_file=None, # No .env in production
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
# config/__init__.py
|
|
155
|
+
import os
|
|
156
|
+
from functools import lru_cache
|
|
157
|
+
|
|
158
|
+
from .development import DevelopmentSettings
|
|
159
|
+
from .production import ProductionSettings
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
@lru_cache
|
|
163
|
+
def get_settings():
|
|
164
|
+
environment = os.getenv("ENVIRONMENT", "development")
|
|
165
|
+
|
|
166
|
+
settings_map = {
|
|
167
|
+
"development": DevelopmentSettings,
|
|
168
|
+
"production": ProductionSettings,
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
settings_class = settings_map.get(environment, DevelopmentSettings)
|
|
172
|
+
return settings_class()
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
settings = get_settings()
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Validation
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
from pydantic import field_validator, model_validator
|
|
182
|
+
from pydantic_settings import BaseSettings
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class Settings(BaseSettings):
|
|
186
|
+
environment: str
|
|
187
|
+
debug: bool = False
|
|
188
|
+
|
|
189
|
+
database_url: str
|
|
190
|
+
database_pool_size: int = 5
|
|
191
|
+
|
|
192
|
+
@field_validator("environment")
|
|
193
|
+
@classmethod
|
|
194
|
+
def validate_environment(cls, v: str) -> str:
|
|
195
|
+
allowed = {"development", "staging", "production"}
|
|
196
|
+
if v not in allowed:
|
|
197
|
+
raise ValueError(f"environment must be one of {allowed}")
|
|
198
|
+
return v
|
|
199
|
+
|
|
200
|
+
@field_validator("database_pool_size")
|
|
201
|
+
@classmethod
|
|
202
|
+
def validate_pool_size(cls, v: int) -> int:
|
|
203
|
+
if v < 1 or v > 100:
|
|
204
|
+
raise ValueError("database_pool_size must be between 1 and 100")
|
|
205
|
+
return v
|
|
206
|
+
|
|
207
|
+
@model_validator(mode="after")
|
|
208
|
+
def validate_production(self) -> "Settings":
|
|
209
|
+
if self.environment == "production" and self.debug:
|
|
210
|
+
raise ValueError("debug must be False in production")
|
|
211
|
+
return self
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## FastAPI Integration
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
# main.py
|
|
218
|
+
from functools import lru_cache
|
|
219
|
+
from typing import Annotated
|
|
220
|
+
|
|
221
|
+
from fastapi import Depends, FastAPI
|
|
222
|
+
|
|
223
|
+
from config import Settings
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
@lru_cache
|
|
227
|
+
def get_settings() -> Settings:
|
|
228
|
+
return Settings()
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
SettingsDep = Annotated[Settings, Depends(get_settings)]
|
|
232
|
+
|
|
233
|
+
app = FastAPI()
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
@app.get("/info")
|
|
237
|
+
async def info(settings: SettingsDep):
|
|
238
|
+
return {
|
|
239
|
+
"app_name": settings.app_name,
|
|
240
|
+
"environment": settings.environment,
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
# Override in tests
|
|
245
|
+
def get_test_settings() -> Settings:
|
|
246
|
+
return Settings(
|
|
247
|
+
database_url="postgresql://localhost/test",
|
|
248
|
+
secret_key="test-secret",
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
app.dependency_overrides[get_settings] = get_test_settings
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Secrets Management
|
|
256
|
+
|
|
257
|
+
```python
|
|
258
|
+
from pydantic import SecretStr
|
|
259
|
+
from pydantic_settings import BaseSettings
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
class Settings(BaseSettings):
|
|
263
|
+
# SecretStr hides value in logs and repr
|
|
264
|
+
database_password: SecretStr
|
|
265
|
+
api_key: SecretStr
|
|
266
|
+
|
|
267
|
+
def get_database_url(self) -> str:
|
|
268
|
+
# Access secret value with .get_secret_value()
|
|
269
|
+
password = self.database_password.get_secret_value()
|
|
270
|
+
return f"postgresql://user:{password}@localhost/db"
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
# In code
|
|
274
|
+
settings = Settings()
|
|
275
|
+
print(settings.database_password) # SecretStr('**********')
|
|
276
|
+
print(settings.database_password.get_secret_value()) # actual password
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## .env File
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
# .env
|
|
283
|
+
APP_NAME=MyApp
|
|
284
|
+
ENVIRONMENT=development
|
|
285
|
+
DEBUG=true
|
|
286
|
+
|
|
287
|
+
# Database
|
|
288
|
+
DATABASE__URL=postgresql://user:pass@localhost/myapp
|
|
289
|
+
DATABASE__POOL_SIZE=10
|
|
290
|
+
|
|
291
|
+
# Redis
|
|
292
|
+
REDIS__URL=redis://localhost:6379
|
|
293
|
+
REDIS__DB=0
|
|
294
|
+
|
|
295
|
+
# Auth
|
|
296
|
+
AUTH__SECRET_KEY=your-super-secret-key-here
|
|
297
|
+
AUTH__ACCESS_TOKEN_EXPIRE_MINUTES=60
|
|
298
|
+
|
|
299
|
+
# External APIs
|
|
300
|
+
STRIPE_API_KEY=sk_test_xxx
|
|
301
|
+
SENDGRID_API_KEY=SG.xxx
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## Anti-Patterns
|
|
305
|
+
|
|
306
|
+
```python
|
|
307
|
+
# BAD: Hardcoded secrets
|
|
308
|
+
SECRET_KEY = "my-secret-key"
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
# GOOD: Load from environment
|
|
312
|
+
from pydantic_settings import BaseSettings
|
|
313
|
+
|
|
314
|
+
class Settings(BaseSettings):
|
|
315
|
+
secret_key: str # Required from env
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
# BAD: Global mutable config
|
|
319
|
+
config = {}
|
|
320
|
+
|
|
321
|
+
def load_config():
|
|
322
|
+
global config
|
|
323
|
+
config["db_url"] = os.getenv("DATABASE_URL")
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
# GOOD: Immutable settings with caching
|
|
327
|
+
@lru_cache
|
|
328
|
+
def get_settings() -> Settings:
|
|
329
|
+
return Settings()
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
# BAD: No validation
|
|
333
|
+
database_url = os.getenv("DATABASE_URL") # Could be None!
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
# GOOD: Required fields with validation
|
|
337
|
+
class Settings(BaseSettings):
|
|
338
|
+
database_url: PostgresDsn # Validated URL format, required
|
|
339
|
+
```
|