ai-ops-compiler 0.1.4 → 0.1.6

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/data/presets.yaml CHANGED
@@ -4,6 +4,7 @@ frontend-web:
4
4
  - role-persona
5
5
  - communication
6
6
  - code-philosophy
7
+ - plan-mode
7
8
  - naming-convention
8
9
  - engineering-standards
9
10
  - typescript
@@ -18,6 +19,7 @@ frontend-app:
18
19
  - role-persona
19
20
  - communication
20
21
  - code-philosophy
22
+ - plan-mode
21
23
  - naming-convention
22
24
  - engineering-standards
23
25
  - flutter
@@ -29,6 +31,7 @@ backend-ts:
29
31
  - role-persona
30
32
  - communication
31
33
  - code-philosophy
34
+ - plan-mode
32
35
  - naming-convention
33
36
  - engineering-standards
34
37
  - typescript
@@ -44,6 +47,7 @@ backend-python:
44
47
  - role-persona
45
48
  - communication
46
49
  - code-philosophy
50
+ - plan-mode
47
51
  - naming-convention
48
52
  - engineering-standards
49
53
  - python
@@ -7,29 +7,29 @@ tags:
7
7
  priority: 28
8
8
  content:
9
9
  constraints:
10
- - 'DO NOT parse LLM text responses with regex or string splitting. Use structured output via Pydantic + response_format / instructor / function calling.'
11
- - 'DO NOT hardcode prompts inline. Externalize to version-controlled templates (files or DB) that are diffable and reviewable.'
12
- - 'DO NOT call synchronous SDK methods inside async applications. Use AsyncOpenAI, AsyncAnthropic, or equivalent async clients.'
13
- - 'DO NOT ignore token limits. Count input tokens and truncate or chunk before sending when context window would be exceeded.'
14
- - 'DO NOT log or persist raw API responses that contain PII. Mask sensitive fields before logging.'
10
+ - 'DO NOT parse model outputs with regex/split when schema output is required. Use structured output (Pydantic + response_format/function calling/instructor).'
11
+ - 'DO NOT hardcode prompts inline. Keep prompts versioned in files or managed storage.'
12
+ - 'DO NOT call sync SDK methods from async app paths.'
13
+ - 'DO NOT ignore token limits. Estimate and chunk/truncate input before requests.'
14
+ - 'DO NOT log raw responses containing PII.'
15
15
  guidelines:
16
- - 'Use instructor or native SDK response_format + Pydantic model to extract structured output from LLM responses.'
17
- - 'Apply exponential backoff retry on LLM API calls via tenacity. Handle 429, 500, and 503 explicitly.'
18
- - 'Abstract provider selection with LiteLLM. Avoid scattering provider-specific SDK calls across the codebase.'
19
- - 'Track per-request token usage (input tokens, output tokens, model name, latency) for cost monitoring.'
20
- - 'Apply semantic versioning to prompt templates. Include the version in LLM call logs for reproducibility.'
21
- - 'Use stream=True for user-facing LLM calls to stream progressive responses (improves TTFB). Reserve non-streaming for internal pipelines that require structured output extraction.'
22
- - 'Define a fallback model chain for primary model failures or rate limits. Use LiteLLM fallbacks config or implement retry-with-downgrade logic.'
16
+ - 'Use Pydantic models with instructor or native response_format JSON schema mode.'
17
+ - 'Apply retry with exponential backoff for 429/5xx transient errors.'
18
+ - 'Centralize provider routing via LiteLLM (or equivalent abstraction).'
19
+ - 'Track model, input/output tokens, and latency per call for cost/perf monitoring.'
20
+ - 'Version prompts and include prompt version in request logs.'
21
+ - 'Stream user-facing responses when possible; keep non-streaming for strict structured extraction flows.'
22
+ - 'Define fallback model chains for rate limits or provider outages.'
23
23
  decision_table:
24
- - when: 'LLM output must conform to a specific schema'
25
- then: 'Use instructor + Pydantic or response_format={"type": "json_schema"}'
26
- avoid: 'Regex parsing of free-text LLM output (brittle, breaks on formatting changes)'
27
- - when: 'Selecting a model for a task'
28
- then: 'Use the smallest model sufficient for the task (Haiku/GPT-4o-mini for classification/extraction; large models for complex reasoning only)'
29
- avoid: 'Defaulting to the largest/most expensive model for every task'
30
- - when: 'Input document exceeds context window'
31
- then: 'Chunk with overlap, process independently, then aggregate results'
32
- avoid: 'Silent truncation at the SDK level (loses data without warning)'
33
- - when: 'Multiple LLM providers must be supported'
34
- then: 'Use LiteLLM unified interface with routing config'
35
- avoid: 'Separate provider SDK call sites scattered across the codebase'
24
+ - when: 'Output must match a strict schema'
25
+ then: 'Use structured output with Pydantic schema validation'
26
+ avoid: 'Regex parsing on free-text responses'
27
+ - when: 'Selecting a model'
28
+ then: 'Use the smallest model that meets quality requirements'
29
+ avoid: 'Defaulting to the largest model for all tasks'
30
+ - when: 'Input exceeds context window'
31
+ then: 'Chunk with overlap and aggregate results'
32
+ avoid: 'Silent SDK truncation'
33
+ - when: 'Multiple providers are required'
34
+ then: 'Use a unified provider abstraction (e.g., LiteLLM)'
35
+ avoid: 'Scattered provider-specific call sites'
@@ -9,22 +9,22 @@ tags:
9
9
  priority: 80
10
10
  content:
11
11
  constraints:
12
- - "DO NOT over-engineer or write 'clever' one-liners. Code must be explicit; magic is forbidden."
13
- - 'DO NOT extract code into shared functions/utils unless it is repeated at least 3 times (Rule of Three).'
14
- - 'DO NOT mutate state. Use const, readonly, and spread operators for immutability.'
15
- - 'DO NOT create side effects in business logic functions. Keep them pure.'
12
+ - 'DO NOT write clever or opaque code. Prefer explicit intent over tricks.'
13
+ - 'DO NOT extract shared abstractions before the Rule of Three.'
14
+ - 'DO NOT mutate state. Use const/final and spread operators for immutability.'
15
+ - 'DO NOT mix side effects into core business functions.'
16
16
  guidelines:
17
- - 'Favor readability over complexity (Simple Made Easy).'
18
- - 'Prefer duplication over the wrong abstraction (WET > DRY).'
19
- - 'For complex business logic, write the failing test case FIRST (TDD).'
20
- - 'Apply Functional Core / Imperative Shell: keep business logic as pure functions, keep services as thin orchestrators.'
21
- - 'Use const/final and spread operators (...) for all data transformations.'
17
+ - 'Optimize for readability and maintainability first.'
18
+ - 'Prefer temporary duplication over premature abstraction.'
19
+ - 'For non-trivial business rules, start with a failing test (TDD).'
20
+ - 'Use a functional-core / imperative-shell structure.'
21
+ - 'Use immutable updates (const/final, copy/spread patterns).'
22
22
  decision_table:
23
- - when: 'Business logic needs to be implemented'
24
- then: 'Write a failing test first, then implement as a pure function'
25
- avoid: 'Writing implementation before tests, or mixing I/O with business logic'
26
- - when: 'Similar code appears in 2 places'
27
- then: 'Keep both copies as-is (WET)'
28
- avoid: 'Premature extraction into a shared utility'
29
- - when: 'Similar code appears in 3+ places'
30
- then: 'Extract into a shared function with a clear, descriptive name'
23
+ - when: 'Implementing complex business logic'
24
+ then: 'Write failing tests first, then implement pure functions'
25
+ avoid: 'Implementation-first with mixed I/O'
26
+ - when: 'Similar code appears in two places'
27
+ then: 'Keep duplication temporarily'
28
+ avoid: 'Early shared abstraction'
29
+ - when: 'Similar code appears in three or more places'
30
+ then: 'Extract a clearly named shared function'
@@ -8,27 +8,27 @@ tags:
8
8
  priority: 33
9
9
  content:
10
10
  constraints:
11
- - 'DO NOT iterate over DataFrame rows with a Python for-loop. Use vectorized operations.'
12
- - 'DO NOT use Pandas .apply(axis=1). It runs at Python speed. Use vectorized column expressions or migrate to Polars.'
13
- - 'DO NOT load an entire dataset that exceeds available RAM into memory. Use streaming or chunked reads (scan_parquet, read_csv_batched, DuckDB out-of-core).'
14
- - 'DO NOT rely on automatic dtype inference (.infer_objects()). Specify explicit dtypes or schema at read time.'
15
- - 'DO NOT mutate DataFrames in-place (inplace=True). Always reassign to a new variable.'
11
+ - 'DO NOT iterate DataFrame rows in Python loops for transformations.'
12
+ - 'DO NOT use Pandas .apply(axis=1). It runs at Python speed; use vectorized expressions or Polars.'
13
+ - 'DO NOT load datasets larger than memory in one shot.'
14
+ - 'DO NOT rely on implicit dtype inference for production pipelines.'
15
+ - 'DO NOT mutate DataFrames in-place.'
16
16
  guidelines:
17
- - 'Prefer Polars for new pipelines: lazy evaluation, multi-threaded execution, no index confusion.'
18
- - 'Use DuckDB for SQL-style analysis on local Parquet/CSV files. Zero-copy interop with Polars and Pandas DataFrames.'
19
- - 'Use generators and itertools for record-level streaming transformations to avoid materializing large datasets.'
20
- - 'Write large outputs as Hive-style partitioned Parquet (year=YYYY/month=MM/) for efficient downstream reads.'
21
- - 'Enforce explicit schemas at all I/O boundaries: Polars Schema, Pandas dtype dict, or Pydantic model.'
17
+ - 'Prefer Polars for new pipelines, especially lazy mode for query pushdown and parallel execution.'
18
+ - 'Use DuckDB for local SQL analytics on Parquet/CSV and out-of-core workloads.'
19
+ - 'Use streaming/chunked reads for large sources (scan_*, batched readers, out-of-core SQL).'
20
+ - 'Write partitioned Parquet outputs for downstream pruning and faster reads.'
21
+ - 'Enforce explicit schemas at I/O boundaries.'
22
22
  decision_table:
23
- - when: 'Table transformation under ~10 GB'
24
- then: 'Polars lazy mode + .collect()'
25
- avoid: 'Pandas (GIL-bound, single-threaded, slow for large frames)'
26
- - when: 'Ad-hoc SQL analysis on local Parquet/CSV files'
27
- then: 'DuckDB SQL directly on files'
28
- avoid: 'Loading into Pandas then filtering in Python (slow, memory-hungry)'
23
+ - when: 'Transforming tables up to medium-large scale'
24
+ then: 'Use Polars lazy pipelines'
25
+ avoid: 'Row-wise pandas patterns'
26
+ - when: 'Ad-hoc SQL analysis on local files is needed'
27
+ then: 'Use DuckDB directly on source files'
28
+ avoid: 'Load-all-then-filter in pandas'
29
29
  - when: 'Data exceeds available memory'
30
- then: 'Polars scan_* (lazy streaming) or DuckDB out-of-core execution'
31
- avoid: 'pandas.read_csv full load (OOM risk)'
32
- - when: 'Complex Python logic needed per row'
33
- then: 'Polars .map_elements() or struct expressions'
34
- avoid: '.iter_rows() for-loop (Python speed, loses vectorization benefits)'
30
+ then: 'Use Polars scan_* or DuckDB out-of-core execution'
31
+ avoid: 'Full-memory pandas reads'
32
+ - when: 'Custom per-row Python logic is unavoidable'
33
+ then: 'Use vectorized expressions or controlled map APIs'
34
+ avoid: 'General-purpose iter_rows for core pipelines'
@@ -8,33 +8,32 @@ tags:
8
8
  priority: 70
9
9
  content:
10
10
  constraints:
11
- - 'DO NOT use floating-point numbers for monetary values. Represent money as an integer in the smallest currency unit (e.g., cents) with an ISO 4217 currency code — { amount: 1099, currency: "USD" } means $10.99. IEEE 754 rounding errors accumulate across arithmetic operations.'
12
- - 'DO NOT expose sequential or auto-increment IDs in external APIs. Use UUIDs. Sequential IDs enable enumeration attacks and leak business volume (e.g., total order count).'
13
- - 'DO NOT store or transmit timestamps without timezone information. Always use ISO 8601 UTC format (e.g., "2024-01-15T09:30:00Z"). Timezone-naive strings ("2024-01-15 09:30:00") are ambiguous and cause silent data corruption across regions.'
14
- - 'DO NOT use magic numbers or magic strings inline. Extract to named constants or env config. Inline literals (e.g., if (retries > 3), setTimeout(fn, 5000)) make intent opaque and changes error-prone.'
15
- - 'DO NOT return inconsistent error response shapes across endpoints. Every error response MUST follow a standard envelope: { code: string, message: string, requestId: string }. Arbitrary shapes (e.g., { success: false, msg }) break client error handling.'
16
- - 'DO NOT accept unbounded input. Enforce Content-Length limits, request body size limits, array length limits, and string length limits at the API boundary. Missing bounds are a DoS vector and amplify downstream processing cost.'
11
+ - 'DO NOT use floating-point for money. Use minor-unit integers with ISO 4217 currency (e.g., { amount: 1099, currency: "USD" }).'
12
+ - 'DO NOT expose sequential IDs in external APIs. Use UUIDs (prefer UUID v7).'
13
+ - 'DO NOT store or transmit timezone-naive timestamps. Use ISO 8601 UTC (e.g., "2024-01-15T09:30:00Z").'
14
+ - 'DO NOT use magic numbers or strings inline. Extract constants or config.'
15
+ - 'DO NOT return inconsistent error shapes. Use { code: string, message: string, details?: unknown[] }.'
16
+ - 'DO NOT accept unbounded input. Enforce body, array, and string size limits at the API boundary.'
17
17
  guidelines:
18
- - 'UTC everywhere: store all timestamps as UTC in the DB (TIMESTAMPTZ), transmit as ISO 8601 UTC in APIs and logs. Convert to local timezone only in the presentation layer.'
19
- - 'Wrap all API responses in a consistent envelope: { data: T | null, error: ErrorEnvelope | null, meta: { requestId: string, timestamp: string } }. This makes client-side response handling uniform regardless of endpoint.'
20
- - 'Propagate a correlation ID (X-Request-Id) through every layer: API gateway service DB query comment → log entry → outbound HTTP headers. This makes distributed tracing and log correlation possible without a full APM setup.'
21
- - 'Validate environment variables at application startup using Zod parse. Print all missing or invalid variables before failing — fail fast with full context rather than a cryptic runtime error on first use.'
22
- - 'Name domain error codes as DOMAIN_ACTION_REASON (e.g., PAYMENT_CHARGE_INSUFFICIENT_FUNDS, AUTH_TOKEN_EXPIRED). Generic codes (INVALID_INPUT, SERVER_ERROR) give clients no actionable information.'
23
- - 'Accept an Idempotency-Key header on non-idempotent mutations (POST, PATCH). Cache the response for the key within a TTL and return the cached response for duplicate requests. This makes retries safe for clients.'
24
- - 'Expose GET /health (liveness — process is alive) and GET /ready (readiness — dependent services reachable) endpoints. Kubernetes liveness and readiness probes require these to be separate.'
25
- - 'Represent monetary amounts as { amount: number, currency: string } where amount is an integer in the minor unit (cents, pence, etc.) and currency is an ISO 4217 code. Divide by the minor unit factor only at the display layer.'
26
- - 'Return empty collections as [] (or {}) instead of null. Returning null forces every client to null-check before calling .map(), .filter(), or Object.keys(). An empty collection is unambiguous and safe to iterate without guards.'
27
- - 'Handle SIGTERM for graceful shutdown: (1) stop accepting new requests, (2) wait for in-flight requests to complete, (3) close DB connection pools and message queue connections before exiting. Align the shutdown timeout with Kubernetes terminationGracePeriodSeconds to avoid forceful pod kills.'
18
+ - 'Use UTC end-to-end: TIMESTAMPTZ in DB, ISO 8601 UTC in API/logs, local conversion only in the presentation layer.'
19
+ - 'Wrap API responses in a consistent envelope: { data: T | null, error: ErrorEnvelope | null, meta: { requestId: string, timestamp: string } }.'
20
+ - 'Propagate X-Request-Id across gateway, service, logs, DB comments, and outbound calls.'
21
+ - 'Validate environment variables at startup (e.g., Zod parse) and fail fast with all missing/invalid keys.'
22
+ - 'Use domain error codes in DOMAIN_ACTION_REASON format (e.g., PAYMENT_CHARGE_INSUFFICIENT_FUNDS).'
23
+ - 'Support Idempotency-Key for POST/PATCH and replay the cached response for duplicate keys within TTL.'
24
+ - 'Expose GET /health (liveness) and GET /ready (readiness) separately.'
25
+ - 'Return empty collections ([] or {}) instead of null.'
26
+ - 'Handle SIGTERM gracefully: stop intake, drain in-flight requests, close resources, then exit.'
28
27
  decision_table:
29
28
  - when: 'A new entity needs a primary key'
30
- then: 'Use UUID v7 (RFC 9562) — time-sortable, B-tree friendly, no enumeration risk'
31
- avoid: 'Auto-increment integers (enumeration attack, leaks volume); UUID v4 (non-sortable, causes B-tree page splits at scale)'
32
- - when: 'An API endpoint needs to return an error'
33
- then: 'Use a structured error envelope: { code: string, message: string, details?: unknown[] } following RFC 9457 (Problem Details for HTTP APIs)'
34
- avoid: 'Arbitrary error shapes ({ success: false, msg: string }) — breaks uniform client error handling and logging'
35
- - when: 'Timestamps are exchanged between systems (API, logs, DB)'
36
- then: 'Use ISO 8601 UTC strings ("2024-01-15T09:30:00Z") for APIs and logs; TIMESTAMPTZ column type for DB'
37
- avoid: 'Unix epoch milliseconds for human-readable interfaces (undebuggable without a converter); timezone-naive strings (ambiguous); ISO 8601 with local offset in storage (inconsistent sort order). Note: Unix epoch is acceptable in compact formats such as JWT exp/iat claims.'
38
- - when: 'An API needs to support multiple versions'
39
- then: 'Use URL path prefix versioning (/v1/, /v2/) — explicit, cacheable, and simple to route'
40
- avoid: 'Header-based versioning (Accept-Version, X-API-Version) — invisible in browser/curl, complicates CDN caching and routing'
29
+ then: 'Use UUID v7'
30
+ avoid: 'Auto-increment IDs or UUID v4 by default'
31
+ - when: 'An endpoint returns an error'
32
+ then: 'Return the standard error envelope'
33
+ avoid: 'Ad-hoc error fields (e.g., { success: false, msg })'
34
+ - when: 'Systems exchange timestamps'
35
+ then: 'Use ISO 8601 UTC in API/logs and TIMESTAMPTZ in DB; Unix epoch is acceptable in compact token formats (e.g., JWT exp/iat)'
36
+ avoid: 'Timezone-naive strings or mixed local-time storage'
37
+ - when: 'An API needs versioning'
38
+ then: 'Use URL versioning (/v1, /v2)'
39
+ avoid: 'Header-only versioning by default'
@@ -7,31 +7,28 @@ tags:
7
7
  priority: 42
8
8
  content:
9
9
  constraints:
10
- - 'DO NOT use plain dict or TypedDict as request/response models. Use Pydantic BaseModel with Field constraints.'
11
- - 'DO NOT perform synchronous blocking I/O inside async def handlers (time.sleep, requests.get, open()). Use httpx.AsyncClient, aiofiles, or run_in_executor.'
12
- - 'DO NOT return manual error dicts from route handlers. Use @app.exception_handler with HTTPException or custom exceptions.'
13
- - 'DO NOT put business logic inside router functions. Inject services via Depends().'
14
- - 'DO NOT hardcode CORS origins. Load them from Pydantic Settings.'
10
+ - 'DO NOT use plain dict/TypedDict as request or response models. Use Pydantic BaseModel with Field constraints.'
11
+ - 'DO NOT run blocking I/O in async handlers. Use async clients or offload to executors.'
12
+ - 'DO NOT return ad-hoc error dicts from handlers. Raise HTTPException/custom exceptions and centralize handlers.'
13
+ - 'DO NOT place business logic in routers. Keep routers thin and inject services via Depends().'
14
+ - 'DO NOT hardcode CORS origins. Load from validated settings.'
15
15
  guidelines:
16
- - 'Use Depends() for DI: DB sessions, auth, services. Write reusable dependency functions.'
17
- - 'Create one APIRouter per domain (prefix="/users", tags=["users"]) and mount on the main app.'
18
- - 'Specify response_model on all endpoints for OpenAPI accuracy and response filtering.'
19
- - 'Use Annotated[T, Depends(...)] pattern (PEP 593) for dependency injection.'
20
- - 'Use Pydantic Settings with SettingsConfigDict(env_file=".env") for environment variable validation at startup.'
21
- - 'Use lifespan async context manager for startup/shutdown. @app.on_event is deprecated and forbidden.'
16
+ - 'Use reusable Depends() providers for DB session, auth context, and services.'
17
+ - 'Use APIRouter per domain with clear prefixes/tags and mount in the main app.'
18
+ - 'Set response_model on endpoints for output filtering and OpenAPI correctness.'
19
+ - 'Use Annotated[T, Depends(...)] for typed dependency injection.'
20
+ - 'Use Pydantic Settings for startup-time environment validation.'
21
+ - 'Use lifespan context manager for startup/shutdown lifecycle management.'
22
22
  decision_table:
23
23
  - when: 'Endpoint is CPU-bound'
24
- then: 'Use def (sync) FastAPI automatically runs it in a threadpool'
25
- avoid: 'async def with blocking code (starves the event loop)'
24
+ then: 'Use sync def and let FastAPI run it in the threadpool'
25
+ avoid: 'async def with blocking code'
26
26
  - when: 'Endpoint is I/O-bound'
27
- then: 'Use async def with async drivers (asyncpg, httpx.AsyncClient, aiofiles)'
28
- avoid: 'def with sync drivers (blocks the threadpool under load)'
29
- - when: 'Shared resource needs setup/teardown (DB pool, HTTP client)'
27
+ then: 'Use async def with async drivers (asyncpg, httpx, aiofiles)'
28
+ avoid: 'Sync driver calls on hot paths'
29
+ - when: 'Shared resources need setup/teardown'
30
30
  then: 'Use lifespan async context manager'
31
- avoid: '@app.on_event("startup"/"shutdown") — deprecated since FastAPI 0.93'
32
- - when: 'Error response must be returned'
33
- then: 'Raise HTTPException or a custom exception handled by @app.exception_handler. Sync with engineering-standards error envelope.'
34
- avoid: 'Returning manual JSONResponse from the route handler'
35
- - when: 'Fire-and-forget work is needed after responding'
36
- then: 'Lightweight tasks: BackgroundTasks (FastAPI built-in). Heavy tasks or retry needed: Celery or TaskIQ (async-native).'
37
- avoid: 'Awaiting the task synchronously inside the route handler (delays response)'
31
+ avoid: '@app.on_event startup/shutdown hooks'
32
+ - when: 'Post-response background work is required'
33
+ then: 'Use BackgroundTasks for light jobs, Celery/TaskIQ for heavy/retriable jobs'
34
+ avoid: 'Awaiting long tasks inside the request handler'
@@ -8,33 +8,33 @@ tags:
8
8
  priority: 30
9
9
  content:
10
10
  constraints:
11
- - 'DO NOT use `dynamic` type. Use `Object` or sealed class + pattern matching instead.'
12
- - 'DO NOT place business logic inside Widget `build()`. Widgets are UI declarations only; move logic to Notifier/Controller or `*.logic.dart` pure functions.'
13
- - "DO NOT use StatefulWidget for shared state that outlives a single widget's lifecycle. Use Riverpod provider instead."
14
- - 'DO NOT use GlobalKey to access widget state. Pass data via provider or callback props to preserve tree encapsulation.'
15
- - 'DO NOT use mutable class fields. All fields must be `final`; use freezed/copyWith for data class updates.'
16
- - 'DO NOT block the UI thread with heavy synchronous operations (e.g., large JSON parsing, image processing). Use `compute` or a dedicated Isolate.'
11
+ - 'DO NOT use dynamic as a default type. Prefer concrete types, Object, or sealed unions.'
12
+ - 'DO NOT put business logic in Widget build(). Keep widgets declarative.'
13
+ - 'DO NOT use StatefulWidget for shared or long-lived state. Use Riverpod providers.'
14
+ - 'DO NOT use GlobalKey to reach into child state for app data flow.'
15
+ - 'DO NOT keep mutable model fields. Prefer immutable classes with copyWith/freezed.'
16
+ - 'DO NOT run heavy synchronous work on the UI thread. Use compute or Isolate.'
17
17
  guidelines:
18
- - 'Use Riverpod with code generation (`@riverpod` annotation). Co-locate providers with the feature directory that consumes them.'
19
- - 'Adopt feature-first directory structure: `lib/features/<feature>/{view,model,provider,logic}`. Shared code goes in `lib/core/`.'
20
- - 'Use sealed class + switch expression for union types (Dart 3 pattern). Apply to AsyncValue and Result patterns.'
21
- - "Prefer `const` constructors on all widgets and data classes to enable Flutter's rebuild optimization."
22
- - 'Use GoRouter for declarative routing and deep-link support. Avoid imperative `Navigator.push()`/`pop()`.'
23
- - 'Use `freezed` (`@freezed` annotation) for immutable data classes to auto-generate copyWith, equality, and JSON serialization. Never implement `==`/`hashCode` manually.'
24
- - 'Write widget tests with `pumpWidget` + `ProviderScope.overrides` for DI mocking. Test pure logic functions with plain unit tests.'
25
- - 'Use `RepaintBoundary` to isolate expensive subtree repaints. Profile with Flutter DevTools before optimizing; avoid premature optimization.'
26
- - 'Handle async states explicitly using Riverpod AsyncValue or a Result pattern (loading / success / failure). Set a global error boundary to prevent unhandled exceptions from reaching the UI.'
27
- - 'Abstract all external data access behind a Repository interface. Providers must never call APIs or databases directly; they receive a Repository implementation via Riverpod DI.'
18
+ - 'Use Riverpod with @riverpod code generation and feature-local providers.'
19
+ - 'Use feature-first directories: lib/features/<feature>/{view,model,provider,logic} and shared code in lib/core.'
20
+ - 'Use sealed classes and pattern matching for Result/Async state handling.'
21
+ - 'Prefer const constructors where possible for rebuild efficiency.'
22
+ - 'Use go_router for declarative routes and deep-link handling.'
23
+ - 'Use freezed for immutable models and generated equality/copy/JSON methods.'
24
+ - 'Write widget tests with ProviderScope.overrides and unit-test pure logic separately.'
25
+ - 'Profile with DevTools before optimization; use RepaintBoundary where repaint isolation is needed.'
26
+ - 'Handle async states explicitly with AsyncValue or a Result type (loading/success/failure). Set a global error boundary to catch unhandled exceptions before they reach the UI.'
27
+ - 'Access external APIs/storage via repositories; providers should depend on repository interfaces.'
28
28
  decision_table:
29
- - when: 'State is ephemeral and scoped to a single widget (e.g., form field focus, animation toggle)'
30
- then: 'Use StatefulWidget or flutter_hooks useState'
31
- avoid: 'Creating a Riverpod provider for trivial local UI state'
32
- - when: "State is shared across widgets or must persist beyond a single widget's lifecycle"
33
- then: 'Use Riverpod Notifier or AsyncNotifier'
34
- avoid: 'StatefulWidget with callback prop drilling or InheritedWidget'
35
- - when: 'A data class requires equality, copyWith, or JSON serialization'
36
- then: 'Annotate with `@freezed` and run build_runner'
37
- avoid: 'Manually implementing `==`, `hashCode`, or `copyWith`'
38
- - when: 'Navigating between screens or handling deep links'
39
- then: 'Declare routes with GoRouter configuration'
40
- avoid: 'Imperative Navigator.push() / Navigator.pop()'
29
+ - when: 'State is local and ephemeral (focus, small toggle)'
30
+ then: 'Use StatefulWidget or flutter_hooks state'
31
+ avoid: 'Creating global/shared providers for trivial local state'
32
+ - when: 'State is shared or must outlive a widget'
33
+ then: 'Use Riverpod Notifier/AsyncNotifier'
34
+ avoid: 'Prop-drilling callback chains'
35
+ - when: 'A model needs equality/copy/JSON generation'
36
+ then: 'Use @freezed + build_runner'
37
+ avoid: 'Manual ==/hashCode/copyWith implementations'
38
+ - when: 'Navigation and deep links are needed'
39
+ then: 'Use GoRouter route configuration'
40
+ avoid: 'Imperative Navigator-only architecture'
@@ -7,28 +7,28 @@ tags:
7
7
  priority: 48
8
8
  content:
9
9
  constraints:
10
- - 'DO NOT rely on implicit nullability defaults. Every field MUST declare nullability explicitly — non-null (!) is the default intent; nullable fields are intentional design decisions (e.g., optional profile picture). Implicit nullability causes mismatches between schema and client expectations.'
11
- - 'DO NOT perform side effects (data mutations) in Query resolvers. Reads belong in Query, writes belong in Mutation — strict separation ensures idempotent caching, safe retry behavior, and predictable client behavior.'
12
- - 'DO NOT use a generic `Error` type as a return value. Define domain-specific union error types per operation (e.g., `union CreateUserResult = User | EmailTakenError | ValidationError`). Generic errors give clients no actionable structure for error handling.'
13
- - 'DO NOT return unbounded lists. Every collection field MUST apply pagination (`first`/`after` for cursor-based or `limit`/`offset` for offset-based). Unbounded lists are a DoS vector and cause memory exhaustion at scale.'
14
- - 'DO NOT expose internal implementation details in enum value names. Use SCREAMING_SNAKE_CASE semantic names (e.g., `PENDING`, `IN_PROGRESS`) — never leak DB column names, internal state machine names, or numeric codes that require server-side knowledge to interpret.'
10
+ - 'DO NOT rely on implicit nullability. Mark every field intentionally (prefer non-null by default).'
11
+ - 'DO NOT perform mutations in Query resolvers. Reads belong to Query, writes belong to Mutation.'
12
+ - 'DO NOT return a generic Error type. Use operation-specific typed errors (union or payload errors).'
13
+ - 'DO NOT return unbounded lists. Every collection must support pagination.'
14
+ - 'DO NOT expose internal implementation details in enum values. Use semantic SCREAMING_SNAKE_CASE names.'
15
15
  guidelines:
16
- - 'Prefer cursor-based pagination (`first`/`after`) using UUID v7 PKs as the cursor — eliminates offset drift on live data and supports infinite scroll reliably. A minimal connection shape `{ nodes: [T!]!, pageInfo: { hasNextPage: Boolean!, endCursor: String } }` is sufficient; full Relay Connection spec (`edges/node`) is optional.'
17
- - 'Design mutation arguments as a single `input` object: `mutation CreateUser($input: CreateUserInput!) { createUser(input: $input) { ... } }`. Never spread individual scalars as top-level arguments — a single input type is versionable and tooling-friendly.'
18
- - 'Return a Payload type from every mutation: `type CreateUserPayload { user: User, userErrors: [UserError!]! }`. Return HTTP 200 with application-level errors in `userErrors` rather than using top-level GraphQL errors, which are harder for clients to branch on.'
19
- - 'Solve N+1 with DataLoader. Resolvers MUST NOT issue DB queries directly delegate to a batch loader keyed by parent IDs. This is mandatory for any `@ResolveField`-equivalent that loads related data.'
20
- - 'Follow schema naming conventions: `PascalCase` for types and enums, `camelCase` for fields and arguments, `SCREAMING_SNAKE_CASE` for enum values. Deviations break code generation tools (`@graphql-codegen`).'
21
- - 'Mark deprecated fields with `@deprecated(reason: "Use newField instead. Removal planned in v3.")` rather than deleting them immediately. Verify client migration before removing in the next major version.'
16
+ - 'Prefer cursor pagination (first/after) for user-facing lists; use offset pagination only for bounded admin tables.'
17
+ - 'Use a single input object for every mutation: mutation X($input: XInput!).'
18
+ - 'Return mutation payload types that can carry both result data and structured errors.'
19
+ - 'Use DataLoader for related entity resolution; field resolvers must not issue per-parent DB queries.'
20
+ - 'Follow naming conventions: PascalCase types/enums, camelCase fields/args, SCREAMING_SNAKE_CASE enum values.'
21
+ - 'Deprecate fields first with @deprecated(reason: "...") and remove only in the next major version.'
22
22
  decision_table:
23
23
  - when: 'A field returns a collection'
24
- then: 'Use cursor-based pagination (`first`/`after`, UUID v7 PK as cursor) — stable under concurrent writes, safe for infinite scroll. Offset pagination (`limit`/`offset`) is acceptable for admin tables with bounded, slow-changing data.'
25
- avoid: 'Unbounded `[Node!]!` return — no limit means memory exhaustion and DoS risk at scale'
26
- - when: 'A mutation needs to communicate failure to the client'
27
- then: 'Return a Payload union type (`User | ValidationError`) and populate `userErrors: [UserError!]!` clients can switch on `__typename` and handle errors as data'
28
- avoid: 'Throwing top-level GraphQL errors for expected business failures clients must catch exceptions instead of branching on typed data'
29
- - when: 'A schema field needs to be removed or renamed'
30
- then: 'Add `@deprecated(reason: "...")` first, confirm all clients have migrated, then remove in the next major schema version'
31
- avoid: 'Removing a field immediately without deprecation — causes runtime errors in deployed clients that have not yet updated their queries'
32
- - when: 'A query needs complex filtering or sorting'
33
- then: 'Define dedicated `FilterInput` / `OrderByInput` input types with typed fields for each filter criterion'
34
- avoid: 'Accepting a JSON string or raw scalar as a filter parameter — loses type safety, IDE auto-complete, and validation at the schema level'
24
+ then: 'Use cursor pagination with a stable cursor'
25
+ avoid: 'Returning unbounded [Node!]! lists'
26
+ - when: 'A mutation must report business failure'
27
+ then: 'Use both a Payload wrapper type AND typed union errors together Payload carries partial success data, union enables __typename switching; they are complementary, not alternatives'
28
+ avoid: 'Throwing top-level GraphQL errors for expected failures, or using only a bare union without a Payload'
29
+ - when: 'A field is removed or renamed'
30
+ then: 'Deprecate first, migrate clients, then remove in next major'
31
+ avoid: 'Immediate schema removal'
32
+ - when: 'Filtering or sorting is complex'
33
+ then: 'Define typed FilterInput/OrderByInput types'
34
+ avoid: 'Accepting raw JSON or string filters'
@@ -6,31 +6,30 @@ tags:
6
6
  priority: 22
7
7
  content:
8
8
  constraints:
9
- - 'DO NOT use requirements.txt. Use uv (preferred) or Poetry with pyproject.toml. Lock file (uv.lock or poetry.lock) must be committed.'
10
- - 'DO NOT use print() for logging. Use structlog with JSON output.'
11
- - 'DO NOT use unittest.TestCase. Use pytest with function-based tests and fixtures.'
12
- - 'DO NOT use bare assert in production code. The -O flag strips assert statements. Use explicit if/raise instead.'
9
+ - 'DO NOT use requirements.txt as the primary dependency spec. Use pyproject.toml with uv (preferred) or Poetry, and commit the lock file.'
10
+ - 'DO NOT use print() for logging. Use structured JSON logging (structlog).'
11
+ - 'DO NOT use unittest.TestCase. Use pytest with fixtures.'
12
+ - 'DO NOT rely on bare assert in production code. Raise explicit exceptions.'
13
13
  guidelines:
14
- - 'uv 0.5+ package management. uv sync, uv run. Commit uv.lock.'
15
- - 'pytest 8+ / pytest-asyncio / pytest-cov testing. Use fixtures, parametrize, and coverage reports.'
16
- - 'httpx 0.28+ sync/async HTTP client. Use ASGITransport for FastAPI integration tests.'
17
- - 'structlog 24+ structured JSON logging. Bind request_id and user_id to the context.'
18
- - 'ruff lint and format (replaces flake8, black, isort). Configure in pyproject.toml [tool.ruff].'
19
- - 'mypy 1.10+ or pyright — static type checking in strict mode. Enforce as a CI gate.'
20
- - 'pydantic-settings 2+ environment variable loading and validation. Single source of truth for config.'
21
- - 'tenacity 9+ retry logic with exponential backoff. Use for external API calls and transient failure recovery.'
22
- - 'Great Expectations 1+ or pandera pipeline input/output data quality validation.'
23
- - 'polars 1+ / duckdb 1+ — core data processing stack. Works in conjunction with data-pipeline-python rule.'
14
+ - 'Use uv for environment and dependency management (uv sync, uv run).'
15
+ - 'Use pytest + pytest-asyncio + pytest-cov for tests.'
16
+ - 'Use httpx for sync/async HTTP and ASGITransport for FastAPI integration tests.'
17
+ - 'Use structlog and bind request_id/user_id in context.'
18
+ - 'Use ruff for lint + format and enforce it in CI.'
19
+ - 'Use mypy or pyright in strict mode.'
20
+ - 'Use pydantic-settings for env loading/validation.'
21
+ - 'Use tenacity for retry/backoff around transient external calls.'
22
+ - 'Use pandera or Great Expectations for data quality validation in pipelines.'
24
23
  decision_table:
25
24
  - when: 'Package management is needed'
26
- then: 'Use uv + pyproject.toml + uv.lock'
27
- avoid: 'pip + requirements.txt (no lock file guarantees), conda (heavy, slow CI)'
28
- - when: 'Lint and format tooling is needed'
29
- then: 'Use ruff as the single tool for lint and format'
30
- avoid: 'flake8 + black + isort (fragmented config, slower CI)'
31
- - when: 'Data quality validation is needed'
32
- then: 'Great Expectations (batch pipeline) or pandera (DataFrame schema)'
33
- avoid: 'Scattered manual assert statements inside pipeline code (untestable, no reporting)'
25
+ then: 'Use uv + pyproject.toml + lock file'
26
+ avoid: 'pip-only requirements.txt workflows'
27
+ - when: 'Lint/format tooling is needed'
28
+ then: 'Use ruff as the default toolchain'
29
+ avoid: 'Split flake8/black/isort stacks'
30
+ - when: 'Data quality checks are needed'
31
+ then: 'Use pandera or Great Expectations with explicit checks'
32
+ avoid: 'Scattered inline asserts with no reporting'
34
33
  - when: 'HTTP client is needed'
35
- then: 'Use httpx (supports both sync and async with a single API)'
36
- avoid: 'requests (no async support), aiohttp (complex low-level API)'
34
+ then: 'Use httpx'
35
+ avoid: 'Mixing requests/aiohttp across services'
@@ -7,37 +7,32 @@ tags:
7
7
  priority: 25
8
8
  content:
9
9
  constraints:
10
- - 'DO NOT use moment.js or dayjs. Use date-fns 4+ (tree-shakeable, immutable, functional API) — import individual functions only.'
11
- - 'DO NOT use jsonwebtoken. Use jose 6+ (Web Crypto API, edge-compatible, no native binary dependencies).'
12
- - 'DO NOT use Express APIs (req/res) directly in NestJS handlers. Route through the NestJS platform adapter layer.'
13
- - 'DO NOT import lodash as a full bundle (import _ from "lodash"). Prefer native JS (structuredClone, Object.groupBy, Array.at) first; only then use individual lodash imports.'
14
- - 'DO NOT use node-fetch or got for HTTP calls inside NestJS. Use @nestjs/axios (HttpModule) or native fetch().'
15
- - 'DO NOT use winston, morgan, or console.log for application logging. Use pino 9+ via nestjs-pino 4+ — it fully replaces the NestJS Logger and provides best-in-class JSON serialization performance.'
10
+ - 'DO NOT use moment/dayjs. Standardize on date-fns with named imports.'
11
+ - 'DO NOT use jsonwebtoken. Use jose 6+.'
12
+ - 'DO NOT handle Express req/res directly in NestJS handlers.'
13
+ - 'DO NOT import lodash as a full bundle. Prefer native APIs or per-function imports.'
14
+ - 'DO NOT use node-fetch/got in NestJS services. Use @nestjs/axios HttpModule or native fetch().'
15
+ - 'DO NOT use winston/morgan/console.log for app logs. Use pino via nestjs-pino.'
16
16
  guidelines:
17
- - 'class-validator 0.14+ / class-transformer 0.5+ — DTO validation and serialization. Always enable whitelist: true in ValidationPipe.'
18
- - '@nestjs/graphql 13+ / @nestjs/apollo 13+ / @apollo/server 5+ — GraphQL API layer. Use code-first approach with TypeScript decorators.'
19
- - '@graphql-codegen/cli 6+ / client-preset 5+ — generate type-safe GraphQL operation types from the SDL at build time.'
20
- - 'date-fns 4+ / date-fns-tz 3+ — date manipulation and timezone handling. Always import individual functions (e.g., import { format } from "date-fns").'
21
- - 'jose 6+ JWT signing, verification, JWK/JWKS handling. Use SignJWT / jwtVerify / createRemoteJWKSet.'
22
- - 'pino 9+ / nestjs-pino 4+ — structured JSON logging. Bootstrap with LoggerModule.forRoot() to replace the NestJS Logger across all modules automatically.'
23
- - 'rxjs 7+ reactive patterns for NestJS interceptors, guards, and event streams. Prefer operators over manual Promise chains.'
24
- - 'vitest 4+ / @nestjs/testing / supertest 7+ unit and e2e testing. ESM-native; no ts-jest or @swc/jest configuration required.'
25
- - 'pg 8+ / @prisma/adapter-pg 7+ — Prisma driver adapter. Configure connection pool size (max, idleTimeoutMillis) explicitly.'
26
- - 'typescript 5+ with strict: true / @swc/core — type checking and fast transpilation in development and CI.'
27
- - 'axios via @nestjs/axios HttpModule — outbound HTTP calls that require interceptors, retry logic, or request/response transformation.'
17
+ - 'Use class-validator + class-transformer DTO validation with ValidationPipe({ whitelist: true }).'
18
+ - 'Use @nestjs/graphql + @nestjs/apollo code-first for GraphQL APIs.'
19
+ - 'Use GraphQL Codegen for operation/result type generation.'
20
+ - 'Use jose for JWT sign/verify and JWKS workflows.'
21
+ - 'Use pino + nestjs-pino as the default structured logger.'
22
+ - 'Use rxjs operators for NestJS interceptors, guards, and event streams.'
23
+ - 'Use Vitest + @nestjs/testing + supertest for unit/e2e tests.'
24
+ - 'Use zod for schema validation outside DTOs (env, external payloads).'
25
+ - 'Keep TypeScript strict mode enabled.'
28
26
  decision_table:
29
- - when: 'JWT authentication is needed'
30
- then: 'Use jose 6+ (SignJWT, jwtVerify, createRemoteJWKSet)'
31
- avoid: 'jsonwebtoken — not Web Crypto compatible, not edge-runtime safe'
32
- - when: 'Date manipulation or formatting is needed'
33
- then: 'Use date-fns 4+ with individual function imports'
34
- avoid: 'moment.js (mutable, large bundle), dayjs (non-standard plugin model)'
35
- - when: 'A utility function is needed (e.g., deep clone, groupBy)'
36
- then: 'Use native JS first (structuredClone, Object.groupBy); only fall back to individual lodash imports'
37
- avoid: "lodash full bundle import (import _ from 'lodash')"
38
- - when: 'Schema validation outside of DTOs is needed (e.g., env vars, external payloads)'
39
- then: 'Use zod with parse/safeParse'
40
- avoid: 'joi (CommonJS-only API), manual type guards (brittle, untestable)'
41
- - when: 'Structured application logging is needed'
42
- then: 'Use pino 9+ via nestjs-pino 4+ (LoggerModule.forRoot)'
43
- avoid: 'winston (slow JSON serialization), morgan (HTTP-only), console.log (unstructured)'
27
+ - when: 'JWT auth is needed'
28
+ then: 'Use jose (SignJWT, jwtVerify, createRemoteJWKSet)'
29
+ avoid: 'jsonwebtoken'
30
+ - when: 'Date handling is needed'
31
+ then: 'Use date-fns named imports'
32
+ avoid: 'moment/dayjs'
33
+ - when: 'Utility helpers are needed (clone/groupBy)'
34
+ then: 'Use native JS first; fallback to scoped lodash imports only'
35
+ avoid: 'import _ from "lodash"'
36
+ - when: 'Structured logging is needed'
37
+ then: 'Use pino via nestjs-pino LoggerModule.forRoot()'
38
+ avoid: 'console.log or mixed logging stacks'