agentleFS
sourjyasourjya/kiro-rails/.claude/CLAUDE.md

kiro-rails

CLAUDE.md9 starsChanged 4 months agoMITView on GitHub

Project-specific values that override the generic defaults in the managed steering files. This is the ONLY steering file you should edit. All other steering files are managed by kiro-rails and will be overwritten on upgrade.

  • Reads credentials
  • Installs packages
  • Commits and pushes

The file

Show its rules and text

We split this CLAUDE.md into the rules it gives an agent

150 rules. About 0 are common, 104 are distinctive, and 46 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈104

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 46

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Delete sections you don't need

    line 18
  2. Distinctive:

    Use JSONB over JSON for queryable structured data

    line 44
  3. Distinctive:

    When any rule below conflicts with convenience, the rule wins.

    line 147
  4. Very specific:

    Never change code outside the scope of the current task: No drive-by refactors. → change-discipline.md

    line 164
  5. Very specific:

    Never modify an already-applied database migration: Create a new one. → database-conventions.md

    line 168
  6. Distinctive:

    Schema first, code second: - before implementing any API endpoint, define the response type (Pydantic model, TypeScript interface, or Zod …

    line 210
  7. Very specific:

    Never assume response shape: - don't write resp.data.message without verifying the backend actually returns {data: {message: ...}}.

    line 211
  8. Very specific:

    Axios/fetch unwrapping: - document whether your API client unwraps responses.

    line 214
  9. Distinctive:

    When connecting frontend to backend:

    line 218
  10. Very specific:

    Log the actual response: - before writing rendering code, console.log or inspect the actual API response shape.

    line 220
  11. Very specific:

    Handle nested envelopes: - if the API returns {data: {project: {...}}}, don't type the result as Project.

    line 221
  12. Very specific:

    Array vs object: - verify: does the endpoint return [...] or {items: [...]} or {results: [...]}?

    line 222
  13. Distinctive:

    Null vs undefined vs missing: - document which fields can be null, which are optional (may be missing from response), and which are always …

    line 223
  14. Very specific:

    Structured error responses: - all API errors return a consistent shape: {error: string, detail?: string, code?: string}.

    line 227
  15. Distinctive:

    Never expose internals: - no stack traces, file paths, SQL queries, or internal service names in error responses.

    line 228
  16. Distinctive:

    Generous in dev: - start with 100+/min in development.

    line 234
  17. Distinctive:

    Read any file in the repository

    line 253
  18. Distinctive:

    Run linting, type checking, and tests

    line 254
  19. Distinctive:

    Update documentation and changelog

    line 256
  20. Very specific:

    Commit secrets, .env files, or credentials

    line 266
  21. Distinctive:

    Remove or weaken existing tests (unless explicitly asked)

    line 270
  22. Distinctive:

    Follow existing patterns from similar components: - before creating a new service, route, or component, find an existing one that does …

    line 280
  23. Distinctive:

    Don't refactor while implementing: - if you notice code that could be improved but it's outside the current task, note it for later.

    line 281
  24. Distinctive:

    When in doubt, be consistent: - if the codebase uses one pattern and the style guide says another, follow the codebase.

    line 282
  25. Distinctive:

    No extra improvements: - do not refactor, optimize, or "clean up" code that is not part of the current task, even if it looks wrong.

    line 291
  26. Distinctive:

    No unsolicited dependency updates: - don't upgrade packages, change configs, or modify tooling unless the task requires it.

    line 292
  27. Distinctive:

    Scope creep is a bug: - if implementation reveals a needed change outside the current scope, document it as a separate task.

    line 293
  28. Distinctive:

    Review your diff before committing: - every line in the diff should relate to the task.

    line 294
  29. Distinctive:

    Two-fix limit: - if your second fix attempt for the same issue introduces yet another failure, STOP immediately.

    line 302
  30. Distinctive:

    Map all paths: - before attempting fix #3, read the FULL integration context: all related code paths, all consumers, all edge cases.

    line 303
  31. Distinctive:

    Document what you tried: - before the third attempt, write down: what fix #1 did, why it failed, what fix #2 did, why it failed.

    line 305
  32. Distinctive:

    Ask for help: - if you cannot identify the root cause after mapping all paths, say so.

    line 306
  33. Distinctive:

    Review all values: - default values, field names, identifiers, paths, URLs, error messages.

    line 314
  34. Very specific:

    Check return types: - if you copied a function that returns isConnected: true, ask: is that the correct default HERE?

    line 315
  35. Distinctive:

    Check message objects: - if constructing a new object based on a similar one, verify ALL required fields are included.

    line 316
  36. Very specific:

    Check config references: - if the copied code references a config file, manifest, or package.json entry, verify that entry exists for the …

    line 317
  37. Very specific:

    npm files array: - after creating new directories or entry points, verify they're listed in package.json files.

    line 325
  38. Very specific:

    pyproject.toml include: - after creating new Python modules, verify they're included in the package build.

    line 326
  39. Very specific:

    bin entries: - after creating CLI entry points, verify the bin field in package.json points to the correct file.

    line 327
  40. Very specific:

    After adding any import: - verify the dependency is declared in the manifest (package.json or pyproject.toml).

    line 328
  41. Distinctive:

    Every new dependency must have a functional justification tied to a concrete requirement, test need, or architectural concern.

    line 332
  42. Distinctive:

    Do not add libraries speculatively.

    line 333
  43. Very specific:

    Keep dependency manifests (pyproject.toml, package.json) lean and auditable.

    line 334
  44. Distinctive:

    Check for overlap: - before adding a new package, verify no existing dependency already provides the same functionality.

    line 337
  45. Distinctive:

    Pin versions explicitly: - never use floating version ranges in production dependencies.

    line 339
  46. Distinctive:

    Audit before adding: - check the package's maintenance status, download count, last update date, and known vulnerabilities before adding it …

    line 340
  47. Distinctive:

    No god classes, hidden coupling, or ambiguous ownership boundaries.

    line 346
  48. Distinctive:

    Write code as if a different engineer will inherit the project under delivery pressure.

    line 347
  49. Very specific:

    All commit-cadence, checkpoint, message-format, and branch rules live in one place: see git-and-focus-discipline.md (Part 3 - Commit …

    line 351
  50. Very specific:

    When it exceeds 500 lines, roll over: rename to docs/changelogs/CHANGELOG.YYYY-MM-DD.md and start fresh

    line 360
  51. Distinctive:

    Do NOT copy, summarize, or selectively preserve entries - just roll it over clean

    line 361
  52. Distinctive:

    Write consolidated changelog entries grouped by feature

    line 362
  53. Distinctive:

    Do not clutter the repository root with ad hoc notes, temporary design files, scratchpads, or undocumented artifacts.

    line 366
  54. Very specific:

    All project documentation lives in docs/ (except README.md at root).

    line 367
  55. Distinctive:

    No credentials in source control

    line 371
  56. Distinctive:

    Use .env.example for configuration templates

    line 372
  57. Distinctive:

    Run secret-exposure review before commits

    line 373
  58. Distinctive:

    On attempt #2+ of any fix: Do NOT wait until the fix is done.

    line 397
  59. Distinctive:

    Add new categories as they emerge.

    line 426
  60. Distinctive:

    Test gaps: - add regression tests or smoke tests

    line 433
  61. Distinctive:

    Process gaps: - update documentation or checklists

    line 434
  62. Distinctive:

    When a pattern appears 3+ times:

    line 438
  63. Distinctive:

    Write a concrete steering rule in the appropriate steering file

    line 439
  64. Distinctive:

    Add a regression test if applicable

    line 440
  65. Distinctive:

    Consider automation (hooks, linters, CI checks)

    line 442
  66. Distinctive:

    Every piece of code must be commented so that a follow-on developer - or a coding agent picking up the project cold - can understand all …

    line 453
  67. Distinctive:

    During code writing - NON-NEGOTIABLE: - every file you create or modify MUST have comments meeting this standard BEFORE you move to the …

    line 457
  68. Distinctive:

    All comments must be written so that both human developers and AI coding agents can fully reconstruct the intent, constraints, and …

    line 468
  69. Distinctive:

    No shorthand or project-internal jargon without explanation

    line 469
  70. Distinctive:

    When a method exists because of a non-obvious requirement, say so

    line 472
  71. Distinctive:

    Every file must start with a docstring/JSDoc block that includes:

    line 476
  72. Distinctive:

    Every class - public, internal, or private - must have a docstring/JSDoc that includes:

    line 484
  73. Distinctive:

    Every class property, instance variable, and TypeScript class member must be documented:

    line 492
  74. Very specific:

    Python: use inline comments or Pydantic Field(description=...) for model fields

    line 493
  75. Very specific:

    TypeScript: use JSDoc @property or inline comments above the declaration

    line 494
  76. Distinctive:

    Every method and function must have a docstring/JSDoc, regardless of visibility (public, protected, private, internal helper):

    line 500
  77. Distinctive:

    Do NOT use for:

    line 520
  78. Distinctive:

    When code depends on or mirrors code in another module, add a cross-reference:

    line 536
  79. Distinctive:

    Document why each value exists, not just what it is.

    line 543
  80. Distinctive:

    Test your comments compile: - if you write a comment containing special characters, verify the file still parses.

    line 554
  81. Very specific:

    If feature A needs something from feature B, it goes through B's public index.ts export, or it belongs in shared/.

    line 649
  82. Distinctive:

    If a "shared" item accumulates feature-specific parameters or branches, it should be split back into feature-scoped copies

    line 661
  83. Distinctive:

    Backend-only project: remove the frontend section entirely - don't leave dead structure

    line 667
  84. Distinctive:

    Frontend-only project: remove the backend section entirely

    line 668
  85. Very specific:

    Monorepo: use packages/ with each package following the same internal layer/feature structure

    line 670
  86. Distinctive:

    Keep the principles (layer-first backend, feature-first frontend, graduation policy) even when the directory names change

    line 672
  87. Distinctive:

    One database per project: - no sharing databases across projects

    line 694
  88. Very specific:

    All connection strings in .env: - never hardcode host, port, database name, or credentials

    line 696
  89. Very specific:

    Never prompt for passwords: - always read from .env

    line 704
  90. Distinctive:

    Never modify already-applied migrations: - create new ones to alter schema

    line 724
  91. Distinctive:

    No N+1 queries: - use eager loading, joins, or batch queries

    line 730
  92. Distinctive:

    Parameterized queries only: - never string interpolation for SQL

    line 732
  93. Distinctive:

    Don't fight the ORM: - if the ORM handles it, don't drop to raw SQL unless there's a measurable performance reason

    line 735
  94. Distinctive:

    Keep transactions short: - don't hold transactions open across network calls or user interactions

    line 740
  95. Distinctive:

    Handle rollback: - every transaction must have a clear rollback path on failure

    line 741
  96. Distinctive:

    Use connection pooling in production - never open a new connection per request

    line 745
  97. Very specific:

    Timestamps: - use timezone.utc for all database timestamps.

    line 753
  98. Distinctive:

    Large result sets: - always paginate. Never return unbounded query results.

    line 754
  99. Distinctive:

    Use advisory locks for distributed coordination

    line 762
  100. Very specific:

    Use EXPLAIN ANALYZE to verify query plans for new endpoints

    line 764
  101. Distinctive:

    Use for development, testing, and single-user applications

    line 774
  102. Very specific:

    All documentation must be placed in the appropriate docs/ subdirectory based on its purpose:

    line 789
  103. Very specific:

    DO NOT: Create documentation files in docs/ root, mix document types, or create new subdirectories without documenting their purpose.

    line 837
  104. Very specific:

    DO: Place ADRs in docs/decisions/ with proper numbering, update this list if adding a new documentation category.

    line 839
  105. Distinctive:

    Before substantive implementation begins, establish a structured plan:

    line 848
  106. Distinctive:

    If implementation realities require a plan change: update the spec/roadmap, document the reason, record in changelog.

    line 853
  107. Distinctive:

    UX acceptance criteria for any user-facing feature: - not just "show data" but how it's shown: hierarchy, spacing, interaction placement, …

    line 861
  108. Distinctive:

    Every task has a concrete deliverable (file path, test name, endpoint)

    line 872
  109. Distinctive:

    No vague tasks like "implement the feature" - break down to individual functions/components

    line 875
  110. Very specific:

    Every ADR must be linked in docs/roadmap/roadmap.md at the sprint/milestone row where the decision was made.

    line 881
  111. Distinctive:

    Only link ADRs that actually exist on disk

    line 885
  112. Very specific:

    All docs live in docs/ directory (except README.md)

    line 891
  113. Very specific:

    Use mutateAsync + await for dependent operations: - if operation B depends on operation A completing, use await mutateAsync() for A, …

    line 910
  114. Distinctive:

    Auth token timing: - never fire API requests that require auth before confirming the token is available.

    line 912
  115. Distinctive:

    Sequence mutations that share state: - if two mutations modify the same resource, await the first before firing the second.

    line 913
  116. Very specific:

    Never silently ignore errors: - every error must be raised, logged, or explicitly handled.

    line 921
  117. Distinctive:

    Use specific error types: - not catch-all handlers. Each error type should clearly indicate what went wrong and where.

    line 922
  118. Distinctive:

    Fix root causes, not symptoms: - if an error keeps occurring, fix the underlying issue rather than adding retry/fallback logic around it.

    line 925
  119. Distinctive:

    External service calls: retry with backoff: - use exponential backoff for transient failures.

    line 926
  120. Distinctive:

    API endpoints return proper HTTP status codes: - never return 200 for errors.

    line 927
  121. Distinctive:

    Frontend errors: catch at boundaries: - use error boundaries (React) or equivalent.

    line 928
  122. Distinctive:

    Pagination for all list endpoints: - never return unbounded result sets.

    line 937
  123. Distinctive:

    No N+1 queries: - use eager loading, joins, or batch queries.

    line 938
  124. Distinctive:

    Database indexes: - every column used in WHERE, JOIN, or ORDER BY clauses in frequent queries must have an index.

    line 940
  125. Distinctive:

    Timeouts on all external calls: - every HTTP request, database query, and external service call must have an explicit timeout.

    line 942
  126. Very specific:

    Use the application's dialog/modal system: - every dialog must render through the project's themed component (e.g., ConfirmDialog, …

    line 951
  127. Distinctive:

    ZERO BLACKBOXES: Every pipeline, background process, and async workflow must be observable from day one.

    line 957
  128. Distinctive:

    Structured logging: - every operation logs: what started, what inputs it received, what it produced, how long it took, whether it succeeded …

    line 961
  129. Distinctive:

    Correlation IDs: - every pipeline run or background task gets a unique ID that flows through all log entries and database records.

    line 962
  130. Very specific:

    State transitions: - every job/task has explicit states (PENDING → RUNNING → SUCCESS/FAILED/RETRYING) stored in the database.

    line 963
  131. Distinctive:

    Error context: - when something fails, log the full context: what was being processed, what step failed, what the input was.

    line 965
  132. Distinctive:

    Resumability: - if a pipeline crashes mid-run, it must be resumable from where it stopped via database checkpointing.

    line 966
  133. Distinctive:

    Discuss architecture first: - before implementing any pipeline or background process, discuss the architecture: data flow, failure modes, …

    line 967
  134. Distinctive:

    ALL hooks at the top of the component: - before any early returns, conditional logic, or variable declarations that depend on props.

    line 983
  135. Very specific:

    Verify required providers exist: - before using useQuery, useParams, useNavigate, or any context hook, confirm the component is rendered …

    line 985
  136. Very specific:

    Use mutateAsync + await for dependent operations: - never fire-and-forget with mutate() when a subsequent operation depends on the …

    line 986
  137. Distinctive:

    Document event capture/propagation: - when adding event handlers, note what events are captured, what propagation is stopped, and what …

    line 990
  138. Distinctive:

    Escape key layering: - when multiple components listen for Escape (modals, drawers, dropdowns), implement a stack-based system.

    line 993
  139. Very specific:

    Outside-click handlers + portals: - if a component renders via a portal (e.g., dropdown menu on document.body), the outside-click handler …

    line 994
  140. Distinctive:

    Header/body alignment: - use the SAME layout strategy (grid or flex with identical gaps/gutters) for both header and body rows.

    line 999
  141. Very specific:

    Popover/dropdown positioning: - verify the positioning direction matches the trigger's screen location.

    line 1000
  142. Very specific:

    When setting staleTime: - document what invalidation scenarios exist.

    line 1005
  143. Very specific:

    After mutations, always invalidate: - call queryClient.invalidateQueries() for affected keys.

    line 1006
  144. Very specific:

    Error + retry on 401: - if a query gets a 401, don't let staleTime prevent retry.

    line 1007
  145. Very specific:

    Optimistic updates need rollback: - if using optimistic updates, always implement the onError rollback.

    line 1008
  146. Distinctive:

    When extracting a shared component from an existing implementation, or when a new consumer adopts a shared component:

    line 1012
  147. Very specific:

    Prop parity audit: - before declaring a consumer "done", list every prop the original passes and verify the new consumer passes equivalent …

    line 1014
  148. Distinctive:

    Test with real data: - never verify a component extraction with empty/default data only.

    line 1016
  149. Very specific:

    Layout wrapper parity: - verify the new consumer uses the same layout container (full-width, max-width, padding) as the original.

    line 1017
  150. Distinctive:

    Before marking any UI component or feature task as done, verify:

    line 1040

≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
CLAUDE.md

Project Rules (generated from kiro-rails steering by scripts/export-to-claude.sh)

Source of truth: .kiro/steering/*.md - edit there and re-run; do not edit this file.

Capability sync ledger (what maps to what, and fidelity): docs/references/kiro-claude-sync-ledger.md


inclusion: always

Project Overrides

Project-specific values that override the generic defaults in the managed steering files. This is the ONLY steering file you should edit. All other steering files are managed by kiro-rails and will be overwritten on upgrade.

<!-- ────────────────────────────────────────────── INSTRUCTIONS: - Uncomment and fill in sections relevant to your project - Delete sections you don't need - The installer can populate these values interactively ────────────────────────────────────────────── -->

Tech Stack

<!-- Uncomment and set your stack: - **Backend**: Python 3.12+ with FastAPI - **Frontend**: TypeScript with React + Vite - **Backend Dependencies**: uv with pyproject.toml - **Frontend Dependencies**: npm with package.json -->

Dev Server Ports

<!-- Uncomment and set your ports: - Backend: FastAPI + uvicorn on port 8000 - Frontend: Vite dev server on port 5173 -->

Database Engine

<!-- Uncomment your engine and remove the others: ### PostgreSQL - Host: localhost, Port: 5432 - Use JSONB over JSON for queryable structured data - Enable pg_stat_statements for query monitoring ### MySQL - Host: localhost, Port: 3306 - charset=utf8mb4, collation=utf8mb4_unicode_ci - Enable strict mode (STRICT_TRANS_TABLES) ### SQLite - Path: ./data/app.db - Enable WAL mode for concurrent access -->

Migration Tool

<!-- Uncomment your migration tool: - **Alembic** (SQLAlchemy) - migrations run with admin credentials via env.py - **Prisma Migrate** - schema.prisma is the source of truth - **Django Migrations** - manage.py migrate with admin DB URL - **Knex** - knexfile.js reads from .env -->

Project-Specific Rules

  • NEVER mention context exhaustion, context depth, or remaining context percentage. The user can see the figure. Do not warn, suggest stopping, or recommend "fresh sessions." Just keep working until told to stop or until you literally cannot produce output. No exceptions.
<!-- Add any rules specific to your project: - Example: All API responses must include a `request_id` field - Example: Feature flags are managed via LaunchDarkly, not .env - Example: Use Celery for all background tasks -->

Domain Constants

<!-- List your project's domain-specific constant categories: - Example: Order statuses (PENDING, CONFIRMED, SHIPPED, DELIVERED, CANCELLED) - Example: User roles (ADMIN, MANAGER, MEMBER, VIEWER) - Example: Subscription tiers (FREE, PRO, ENTERPRISE) -->

Code Style Overrides

<!-- Add project-specific code style rules: - Example: Use datetime.now(timezone.utc) - never datetime.utcnow() - Example: All service classes must inherit from BaseService - Example: Use structlog for all logging, not stdlib logging -->

Design Tokens (UX Rubric Thresholds)

<!-- These values configure the thresholds in .kiro/steering/ux-console-idiom.md. The rubric checks are fixed; these numbers are team-configurable. Uncomment and set for your design system: ### Typography (D family) - Body text size range: 13–14px - Allowed font weights: 400, 600 (max 2) - Body line-height range: 1.4–1.6 ### Surfaces (S family) - Content primacy: ≥60% of viewport height for primary content ### Consistency (K family) - Max distinct border-radius values: 2 - Spacing scale base: 4px increments - Icon style: outline (not mixed) - Color palette: [list your token names or hex values] ### Save Model (V family) - Save pattern: explicit (one of: explicit-button | auto-save | inline-confirm) ### Tables (T family) - Max unbounded list items before pagination: 50 ### Feedback timing - Save confirmation deadline: 300ms - Long operation progress threshold: 2s ### Date format - Consistent date format: YYYY-MM-DD (or your team's choice) -->

Environment and Tooling

<!-- Uncomment and set your environment: - Virtual environment: .venv in project root - Package manager: uv (Python), npm (frontend) - Linter: ruff (Python), eslint (frontend) - Formatter: ruff format (Python), prettier (frontend) -->

inclusion: always description: The hard stops - what an agent must never do autonomously. The shortest, sharpest file in the steering set. Read it first.

Agent Boundaries

The hardest constraints, stated plainly. Everything here is elaborated elsewhere; this file exists so the rules are impossible to miss and impossible to "load past." When any rule below conflicts with convenience, the rule wins.

Never (without explicit user confirmation)

  1. Never commit directly to main, force-push it, or rebase it. Every change goes on its own branch. → git-and-focus-discipline.md
  2. Never end a session or turn with uncommitted work on a branch. Commit (feature or checkpoint:) or stash before the context boundary. → git-and-focus-discipline.md
  3. Never resolve conflicts with git checkout --ours . / --theirs . or any blanket strategy. Per-file only. → git-and-focus-discipline.md
  4. Never modify a test to make it pass. Fix the implementation. A failing test is information, not an obstacle. → testing-standards.md
  5. Never delete files, config, or .env, change CI/CD, or alter shared infrastructure without explicit confirmation. → change-discipline.md
  6. Never add, remove, or upgrade a dependency outside the task's stated need, and never via pip/requirements.txt (use uv). → change-discipline.md
  7. Never commit secrets, credentials, or .env contents. → change-discipline.md
  8. Never change code outside the scope of the current task. No drive-by refactors. → change-discipline.md
  9. Never reach into another repository or kill a process you did not spawn. → session-isolation.md
  10. Never modify an already-applied database migration. Create a new one. → database-conventions.md

Always

  1. Always branch first, and check for an existing branch in the area before creating one (scripts/branch-check.sh). → git-and-focus-discipline.md
  2. Always checkpoint before a multi-file or multi-session task (git commit -m "checkpoint: before <task>"). → git-and-focus-discipline.md
  3. Always commit at every meaningful checkpoint (compiles + affected tests pass + lint clean). Do not let a passing state sit uncommitted. → git-and-focus-discipline.md
  4. Always merge-and-delete the branch as one motion when work lands on main. → git-and-focus-discipline.md
  5. Always run a variant search after a bug fix. The reported instance is rarely the only one. → git-and-focus-discipline.md
  6. Always stop and ask on a genuine ambiguity or conflict. Two minutes of clarification beats twenty hours of rebuilding; a confident wrong guess is the expensive failure mode. → git-and-focus-discipline.md

When a new request arrives mid-task

File it to docs/backlog/INBOX.md and finish the current task first. Divert only when the user explicitly orders it. → git-and-focus-discipline.md



inclusion: fileMatch fileMatchPattern: ["/api/", "/routes/", "/services//.ts", "/services//.py", "/schemas/", "**/hooks/use*.ts"]

API Contract Discipline

Rules for API boundary code. Loaded when working on routes, services, schemas, or data-fetching hooks.

Contract-First Development - MANDATORY

Define the response shape BEFORE implementing either side.

Rules

  1. Schema first, code second - before implementing any API endpoint, define the response type (Pydantic model, TypeScript interface, or Zod schema). Both frontend and backend implement against this contract.
  2. Never assume response shape - don't write resp.data.message without verifying the backend actually returns {data: {message: ...}}. Check the schema or test the endpoint.
  3. Envelope consistency - decide once per project: do list endpoints return raw arrays or {items: [...], total: N}? Document it. Never mix approaches.
  4. Type the full response - including HTTP status, headers, and error shapes. Don't just type the happy path.
  5. Axios/fetch unwrapping - document whether your API client unwraps responses. If using Axios, resp.data is the body. If your client auto-unwraps, the hook gets the body directly. Never guess.

Response Shape Verification - MANDATORY

When connecting frontend to backend:

  1. Log the actual response - before writing rendering code, console.log or inspect the actual API response shape. Don't assume from the backend code.
  2. Handle nested envelopes - if the API returns {data: {project: {...}}}, don't type the result as Project. Type it as {data: {project: Project}} and extract.
  3. Array vs object - verify: does the endpoint return [...] or {items: [...]} or {results: [...]}? This is the #1 source of frontend crashes.
  4. Null vs undefined vs missing - document which fields can be null, which are optional (may be missing from response), and which are always present.

Error Response Contract - MANDATORY

  1. Structured error responses - all API errors return a consistent shape: {error: string, detail?: string, code?: string}. Never return raw exception messages.
  2. Never expose internals - no stack traces, file paths, SQL queries, or internal service names in error responses. Use generic messages with correlation IDs for debugging.
  3. HTTP status codes are semantic - 400 for validation, 401 for auth, 403 for authorization, 404 for not found, 409 for conflict, 422 for unprocessable, 500 for server errors. Never return 200 with an error body.

Rate Limiting - GUIDANCE

  1. Per-endpoint, not global - rate limits should be scoped to specific endpoints, not applied as global middleware that blocks everything.
  2. Generous in dev - start with 100+/min in development. Tighten for production based on actual usage patterns.
  3. Return 429 with Retry-After - include the Retry-After header so clients know when to retry.


inclusion: always

Change Discipline

Rules governing what you can change, how changes must be scoped, dependency management, and commit hygiene.

Permission Boundaries - MANDATORY

Explicit rules for what may be changed, what requires approval, and what must never be touched.

✅ Always Allowed

  • Read any file in the repository
  • Run linting, type checking, and tests
  • Edit source files within the scope of the current task
  • Update documentation and changelog

⚠️ Ask First

  • Adding or removing dependencies
  • Database schema changes or new migrations
  • Deleting files or directories
  • Changing CI/CD configuration
  • Modifying shared infrastructure code used by multiple services

🚫 Never

  • Commit secrets, .env files, or credentials
  • Force push to main or protected branches
  • Modify generated files (dist/, build/, lock files unless updating deps)
  • Modify already-applied database migrations
  • Remove or weaken existing tests (unless explicitly asked)
  • Change code outside the scope of the current task

Consistency - Match Existing Patterns - MANDATORY

When touching existing code, matching the existing style is more important than "ideal" style.

Rules

  1. New code must look like it was written by the same author - match naming conventions, formatting, patterns, and idioms already present in the file/module.
  2. Follow existing patterns from similar components - before creating a new service, route, or component, find an existing one that does something similar and follow its structure.
  3. Don't refactor while implementing - if you notice code that could be improved but it's outside the current task, note it for later. Don't mix refactoring with feature work.
  4. When in doubt, be consistent - if the codebase uses one pattern and the style guide says another, follow the codebase. Consistency within a project trumps external standards.

Change Scope Discipline - MANDATORY

Change only what was asked for. No drive-by refactors, no unsolicited improvements.

Rules

  1. Minimal changes - modify as few lines as possible while correctly solving the problem. Every changed line must be justified by the task.
  2. No extra improvements - do not refactor, optimize, or "clean up" code that is not part of the current task, even if it looks wrong.
  3. No unsolicited dependency updates - don't upgrade packages, change configs, or modify tooling unless the task requires it.
  4. Scope creep is a bug - if implementation reveals a needed change outside the current scope, document it as a separate task. Don't silently expand the change.
  5. Review your diff before committing - every line in the diff should relate to the task. If something doesn't, revert it.

Fix Depth Rule - MANDATORY

If a fix introduces a new failure, STOP. Do not chain fixes blindly.

Rules

  1. Two-fix limit - if your second fix attempt for the same issue introduces yet another failure, STOP immediately.
  2. Map all paths - before attempting fix #3, read the FULL integration context: all related code paths, all consumers, all edge cases. Draw the complete picture.
  3. Root cause, not symptoms - each failed fix is evidence you're treating a symptom. Step back and identify the actual root cause.
  4. Document what you tried - before the third attempt, write down: what fix #1 did, why it failed, what fix #2 did, why it failed. The pattern reveals the real problem.
  5. Ask for help - if you cannot identify the root cause after mapping all paths, say so. Don't keep guessing.

Copy-Paste Verification - MANDATORY

After copying code from another context, verify EVERY field makes sense in the new context.

Rules

  1. Review all values - default values, field names, identifiers, paths, URLs, error messages. Each must be correct for the NEW context, not the source.
  2. Check return types - if you copied a function that returns isConnected: true, ask: is that the correct default HERE?
  3. Check message objects - if constructing a new object based on a similar one, verify ALL required fields are included. Don't drop fields.
  4. Check config references - if the copied code references a config file, manifest, or package.json entry, verify that entry exists for the new context.

Package Manifest Verification - MANDATORY

After creating any file that should be published or deployed, verify it's included in the manifest.

Rules

  1. npm files array - after creating new directories or entry points, verify they're listed in package.json files. Run npm pack --dry-run to confirm.
  2. pyproject.toml include - after creating new Python modules, verify they're included in the package build.
  3. bin entries - after creating CLI entry points, verify the bin field in package.json points to the correct file.
  4. After adding any import - verify the dependency is declared in the manifest (package.json or pyproject.toml). Don't use undeclared packages.

Dependency Minimalism

  • Every new dependency must have a functional justification tied to a concrete requirement, test need, or architectural concern.
  • Do not add libraries speculatively. If the standard library or an existing dependency can do the job, use it.
  • Keep dependency manifests (pyproject.toml, package.json) lean and auditable.
  • Python dependencies are managed exclusively via uv and pyproject.toml. Never use requirements.txt, pip install, pip freeze, or poetry. Add deps with uv add <package>. The lockfile is uv.lock.
  • Justify every new dependency - the commit message or task notes must explain why this dependency is needed and why existing deps or stdlib can't do the job.
  • Check for overlap - before adding a new package, verify no existing dependency already provides the same functionality.
  • Prefer small, focused packages over large frameworks when only one feature is needed.
  • Pin versions explicitly - never use floating version ranges in production dependencies. Lock files must be committed.
  • Audit before adding - check the package's maintenance status, download count, last update date, and known vulnerabilities before adding it to the project.

Design Principles

  • Favor composition over inheritance. Use inheritance only when it is semantically justified and materially improves the design.
  • Public interfaces, domain models, service boundaries, and infrastructure adapters must be explicit and easy to reason about.
  • No god classes, hidden coupling, or ambiguous ownership boundaries.
  • Write code as if a different engineer will inherit the project under delivery pressure.

Commit Discipline

All commit-cadence, checkpoint, message-format, and branch rules live in one place: see git-and-focus-discipline.md (Part 3 - Commit Discipline). In short: commit every meaningful checkpoint (compiles + affected tests pass + lint clean), one logical change per commit, Conventional-Commit messages, update the changelog for behavior/structure changes, and never end a session with uncommitted work.

Changelog Rolling Policy

  • docs/changelogs/CHANGELOG.md should stay under 500 lines
  • When it exceeds 500 lines, roll over: rename to docs/changelogs/CHANGELOG.YYYY-MM-DD.md and start fresh
  • Do NOT copy, summarize, or selectively preserve entries - just roll it over clean
  • Write consolidated changelog entries grouped by feature

Repository Hygiene

  • Do not clutter the repository root with ad hoc notes, temporary design files, scratchpads, or undocumented artifacts.
  • All project documentation lives in docs/ (except README.md at root).

Security & Credentials

  • No credentials in source control
  • Use .env.example for configuration templates
  • Run secret-exposure review before commits
  • Credentials, API keys, and test accounts must be externalized into secure configuration - never inline


inclusion: always

Chokepoint Logging - MANDATORY

A chokepoint is any error, crash, or near-miss that required multiple attempts to fix or revealed a gap in process. Logging them creates institutional memory that prevents the same class of bug from recurring.

What Is a Chokepoint

Any error that:

  • Required more than one attempt to fix
  • Was caused by a pattern that could recur elsewhere
  • Revealed a gap in tooling, testing, or process
  • Broke production (even briefly)

When to Log

On attempt #2+ of any fix. Do NOT wait until the fix is done.

  1. BEFORE fixing (on attempt #2+): Append to docs/engineering/chokepoint-log.md:
    ### CP-NNN: description | file | attempt #N | gap: what was missing
  2. AFTER green (before next task): Append resolution:
    - **Root cause:** one sentence
    - **Resolution:** one sentence
    - **Pattern:** category tag
    - **Guardrail candidate:** proposed rule or test

Pattern Categories

TagMeaning
ROUTE_ORDERINGSpecific routes must precede parameterized catch-alls
CSS_OVERSIGHTMissing scrollbar/overflow/responsive handling
LAYOUT_OVERFLOWFlex/grid children exceeding viewport
QUERY_INVALIDATIONMutation not invalidating all affected queries
TYPE_MISMATCHAPI returns different shape than frontend expects
IMPORT_ERRORWrong export/import pattern causing runtime crash
DEPLOY_REGRESSIONBuild deployed without smoke test
TOOL_MISUSEUsing wrong tool when a dedicated tool exists
STATE_SYNCMultiple sources of truth drifting apart
RACE_CONDITIONAsync operations executing in wrong order

Add new categories as they emerge.

Periodic Analysis

At the end of each sprint (or every 20 chokepoints), review the log for:

  1. Recurring patterns - promote to steering rules
  2. Tooling gaps - file as feature requests or create scripts
  3. Test gaps - add regression tests or smoke tests
  4. Process gaps - update documentation or checklists

Guardrail Promotion

When a pattern appears 3+ times:

  1. Write a concrete steering rule in the appropriate steering file
  2. Add a regression test if applicable
  3. Mark the chokepoint entries as "promoted" with a link to the rule
  4. Consider automation (hooks, linters, CI checks)


inclusion: always

Code Commenting Standards

Every piece of code must be commented so that a follow-on developer - or a coding agent picking up the project cold - can understand all pieces without needing to ask the original author.

Enforcement

  1. During code writing - NON-NEGOTIABLE - every file you create or modify MUST have comments meeting this standard BEFORE you move to the next task. Do not write code first and "add comments later" - comments are part of the implementation, not an afterthought.
  2. Automated hook - .kiro/hooks/comment-standards-check.kiro.hook intercepts git commits and verifies staged source files meet this standard.
  3. Maintainability review - the maintainability review prompt explicitly checks for commenting compliance and flags undocumented code as HIGH severity.
  4. Linting rules - Enable docstring rules in your linter config.

Guiding Principle

Comments answer "why" and "how it fits", not "what it does". Every comment should assume the reader has zero prior context about the project.

Agent-Readability Requirement

All comments must be written so that both human developers and AI coding agents can fully reconstruct the intent, constraints, and architectural role of the code. This means:

  • No shorthand or project-internal jargon without explanation
  • Spell out acronyms on first use in each file
  • State assumptions explicitly rather than relying on tribal knowledge
  • When a method exists because of a non-obvious requirement, say so

Module-Level Docstrings / File-Level JSDoc

Every file must start with a docstring/JSDoc block that includes:

  1. A one-line summary of the module's purpose
  2. How this module fits into the larger architecture
  3. Key design decisions or tradeoffs (link to ADRs where applicable)
  4. For complex modules: a brief description of the internal flow

Class Docstrings

Every class - public, internal, or private - must have a docstring/JSDoc that includes:

  1. What the class represents and its responsibility boundary
  2. Why this class exists as a separate abstraction (justification)
  3. Key collaborators: what other classes/services it interacts with
  4. Thread-safety or lifecycle notes if applicable

Property and Attribute Documentation

Every class property, instance variable, and TypeScript class member must be documented:

  • Python: use inline comments or Pydantic Field(description=...) for model fields
  • TypeScript: use JSDoc @property or inline comments above the declaration
  • State what the property holds, its valid range or constraints, and why it exists if non-obvious
  • For Pydantic/dataclass fields: document each field's purpose, not just its type

Method and Function Docstrings - All Visibility Levels

Every method and function must have a docstring/JSDoc, regardless of visibility (public, protected, private, internal helper):

  1. Purpose: what it does and when it should be called
  2. Justification: why this method exists - what requirement, design decision, or constraint motivated it. If it could have been done differently, briefly note why this approach was chosen
  3. Args/Params: describe each parameter, its expected values, and edge cases
  4. Returns: what is returned and under what conditions
  5. Raises/Throws: exceptions that can be raised and when
  6. Side effects: any state mutations, I/O, or external calls

For trivial getters/setters, a one-line docstring is sufficient. The justification requirement applies to any method with non-obvious logic.

Inline Comments

Use for:

  • Non-obvious design decisions and the reasoning behind them
  • Cross-module relationships and data flow explanations
  • Security rationale (why a check exists, what attack it prevents)
  • Performance tradeoffs (why this algorithm, why this data structure)
  • Backward compatibility notes
  • Workarounds with references to the issue/bug they address

Do NOT use for:

  • Restating what the code does (the code itself should be readable)
  • Obvious variable assignments
  • Standard library usage

Section Separators

For files with multiple logical sections, use comment block separators:

# ──────────────────────────────────────────────
# Section Name
# ──────────────────────────────────────────────

Cross-Reference Comments

When code depends on or mirrors code in another module, add a cross-reference:

  • "See also: ADR-005 for rationale"
  • "The frontend mirrors these checks in auth.service.ts"
  • "This constant must stay in sync with backend/src/core/config.py"

Enum and Constant Comments

Document why each value exists, not just what it is. If a constant's value was chosen for a specific reason (protocol requirement, performance threshold, external API contract), state that reason.

Comment-Safe Patterns - MANDATORY

Never write comments that break the parser.

Rules

  1. No unescaped */ inside JSDoc/block comments - glob patterns like **/*.ts contain */ which prematurely closes the comment block. Use backticks or rephrase: `**/*.ts` or "all TypeScript files recursively".
  2. No unescaped /* that opens a nested comment - some languages don't support nested block comments. A stray /* inside a comment creates a parsing error.
  3. Regex in comments must be in backticks - patterns like /api\/v[0-9]+/ can confuse parsers. Always wrap in inline code: `/api\/v[0-9]+/`.
  4. Test your comments compile - if you write a comment containing special characters, verify the file still parses. A broken comment is worse than no comment.


inclusion: always

Code Organization

Runtime environment, folder structure, and development server configuration.

Runtime and Environment

Defaults below. Override in user-project-overrides.md for your stack.

  • Backend: Python 3.12+ with FastAPI
  • Frontend: TypeScript with React + Vite
  • Backend Dependencies: uv with pyproject.toml
  • Frontend Dependencies: npm with package.json

Folder Organization Principles - MANDATORY

These rules apply regardless of framework, language, or stack.

Backend: Domain-Grouped Within Layers

Organize backend code by layer first, domain second. Each layer directory (routes, models, schemas, services) contains subdirectories grouped by domain when the project has more than a handful of files per layer.

backend/src/
├── api/                      # Route/controller layer
│   ├── v1/                   # API version namespace
│   │   ├── auth.py
│   │   ├── users.py
│   │   └── products.py
│   └── deps.py               # Shared route dependencies (auth, db session)
├── core/                     # Configuration, security, database setup
├── common/                   # Cross-cutting: middleware, logging, shared utils
├── models/                   # ORM / data models
│   ├── auth/                 # user.py, role.py, session.py
│   ├── products/             # product.py, category.py
│   └── base.py               # Shared base model
├── schemas/                  # Request/response schemas (Pydantic, Zod, etc.)
│   ├── auth/
│   ├── products/
│   └── common.py             # Shared pagination, error response schemas
├── services/                 # Business logic layer
│   ├── auth/
│   ├── products/
│   └── base.py               # Base service class if applicable
├── constants/                # Domain constants - NEVER inline in model files
│   ├── auth.py
│   └── products.py
└── main.py                   # Application entry point

Rules:

  • Group by domain when a layer has 5+ files. Below that, flat is fine.
  • Each domain subdirectory gets an __init__.py (Python) or index.ts (TS) that re-exports its public API.
  • common/ is for truly cross-cutting concerns (logging, middleware, error handling). Not a dumping ground.
  • constants/ holds all domain constants - never define them inline in model or service files.
  • Adapt layer names to your framework's conventions (e.g., views/ for Django, handlers/ for Go, controllers/ for Express).

Frontend: Feature-Sliced Design

Organize frontend code by feature first. Each feature is a self-contained module with its own components, hooks, services, and types.

frontend/src/
├── app/                      # Application root (routing, providers, layout)
├── features/                 # Feature modules - one per domain
│   ├── auth/
│   │   ├── components/       # Feature-specific UI components
│   │   ├── hooks/            # Feature-specific hooks
│   │   ├── services/         # API calls for this feature
│   │   ├── types/            # Feature-specific type definitions
│   │   ├── utils/            # Feature-specific helpers
│   │   └── index.ts          # Public API - ONLY export what other features need
│   ├── dashboard/
│   │   ├── components/
│   │   ├── hooks/
│   │   └── index.ts
├── shared/                   # Cross-feature reusable code
│   ├── components/           # Generic UI (Button, Modal, Layout)
│   ├── hooks/                # Generic hooks (useDebounce, useLocalStorage)
│   ├── utils/                # Generic helpers (formatDate, cn())
│   └── types/                # Shared type definitions
├── services/                 # Global API client setup, interceptors
└── types/                    # App-wide type definitions

Rules:

  • Features never import from each other's internals - only through index.ts.
  • If feature A needs something from feature B, it goes through B's public index.ts export, or it belongs in shared/.
  • Each feature's index.ts is the only entry point. Internal files are private to the feature.
  • This pattern works for React, Vue, Svelte, Angular, or any component-based framework.

Shared vs Feature-Scoped - Graduation Policy

Code starts in the feature where it was first needed and graduates to shared/ only when reuse is proven:

  1. First use: lives inside the feature directory
  2. Second feature needs it: move it to shared/ and update both imports
  3. Never preemptively put code in shared/ - that creates a junk drawer
  4. shared/ items must be genuinely generic: no feature-specific logic, no domain assumptions, no hardcoded business rules
  5. If a "shared" item accumulates feature-specific parameters or branches, it should be split back into feature-scoped copies

Customizing for Your Stack

The directory structures above are defaults. Adapt them to your stack:

  • Backend-only project: remove the frontend section entirely - don't leave dead structure
  • Frontend-only project: remove the backend section entirely
  • Different framework: rename layers to match your framework's conventions (e.g., Django views/, Go handlers/, Rails controllers/)
  • Monorepo: use packages/ with each package following the same internal layer/feature structure
  • No ORM: replace models/ with whatever your data layer uses (entities/, repositories/, etc.)
  • Keep the principles (layer-first backend, feature-first frontend, graduation policy) even when the directory names change

Local Development Servers

Defaults below. Override in user-project-overrides.md for your ports.

  • Backend: default port 8000
  • Frontend: default port 5173


inclusion: always

Database Conventions

Database architecture, credential management, migration rules, and ORM conventions.

Architecture Principles

  1. One database per project - no sharing databases across projects
  2. Separate test database - tests never touch the application database
  3. All connection strings in .env - never hardcode host, port, database name, or credentials
  4. Test database is disposable - tests may truncate/recreate tables freely

Credential Management

  • Admin/root credentials are for migrations and schema changes only - stored in .env
  • App user gets DML privileges only (SELECT, INSERT, UPDATE, DELETE) - no CREATE/DROP in production
  • Test user gets full privileges on the test database only
  • Never prompt for passwords - always read from .env
  • Never use root for application connections - root is for admin operations only

.env Structure

# Admin (migrations, schema changes)
DB_ADMIN_URL=<engine>://<admin_user>:<admin_password>@localhost:<port>/<project>

# Application (runtime)
DATABASE_URL=<engine>://<project>_app:<app_password>@localhost:<port>/<project>

# Test
TEST_DATABASE_URL=<engine>://<project>_test:<test_password>@localhost:<port>/<project>_test

Migration Rules

  • Migrations run with admin credentials - they need DDL privileges
  • Application code connects with the app user - limited to DML
  • Never modify already-applied migrations - create new ones to alter schema
  • No business logic in migrations - migrations are schema changes only
  • Migrations must be reversible where possible - include downgrade/rollback steps

ORM Conventions

  • No N+1 queries - use eager loading, joins, or batch queries
  • Review ORM-generated SQL for new endpoints - check query plans for performance
  • Parameterized queries only - never string interpolation for SQL
  • Explicit timeouts on all database calls - no indefinite waits
  • Index every column used in WHERE, JOIN, or ORDER BY for frequent queries - document index decisions
  • Don't fight the ORM - if the ORM handles it, don't drop to raw SQL unless there's a measurable performance reason

Transaction Boundaries

  • Explicit, not implicit - wrap multi-step operations in explicit transactions
  • Keep transactions short - don't hold transactions open across network calls or user interactions
  • Handle rollback - every transaction must have a clear rollback path on failure

Connection Pooling

  • Use connection pooling in production - never open a new connection per request
  • Set pool size based on expected concurrency and database max connections
  • Configure idle connection timeout to prevent stale connections
  • Monitor pool exhaustion - log when pool is near capacity

Common Pitfalls

  • Soft deletes vs hard deletes - decide once per project, document in an ADR. Don't mix approaches.
  • Timestamps - use timezone.utc for all database timestamps. Store as UTC, convert on display.
  • Large result sets - always paginate. Never return unbounded query results.
  • Schema drift - the migration tool is the single source of truth for schema. Never modify schema manually.

Engine-Specific Notes

PostgreSQL

  • Use JSONB over JSON for queryable structured data
  • Use advisory locks for distributed coordination
  • Enable pg_stat_statements for query performance monitoring
  • Use EXPLAIN ANALYZE to verify query plans for new endpoints

MySQL

  • Set charset=utf8mb4 and collation=utf8mb4_unicode_ci as defaults
  • Enable strict mode (STRICT_TRANS_TABLES)
  • Be aware of implicit type conversions in WHERE clauses

SQLite

  • Enable WAL mode for concurrent read/write access
  • Be aware of single-writer limitation - not suitable for high-concurrency production
  • Use for development, testing, and single-user applications


inclusion: always

Documentation Standards

Documentation organization, spec quality standards, API versioning, and roadmap planning.

Documentation Organization

All documentation must be placed in the appropriate docs/ subdirectory based on its purpose:

docs/decisions/ (Architecture Decision Records)

  • Format: ADR-###-descriptive-name.md (e.g., ADR-001-tech-stack.md)
  • Content: Context, decision, alternatives considered, consequences
  • Immutability: ADRs are historical artifacts; status can change to "superseded" but content stays

docs/architecture/

  • Purpose: Technical documentation of HOW the system works today
  • Content: System structure, data flows, component interactions, implementation patterns

docs/roadmap/

  • Purpose: Project planning and milestone tracking
  • Content: Roadmaps, milestone plans, implementation schedules

docs/changelogs/

  • Purpose: Historical record of changes to the system
  • Content: CHANGELOG.md (current), archived changelogs (CHANGELOG.YYYY-MM-DD.md)

docs/bugs/

  • Purpose: Bug investigation and resolution documentation
  • Format: BUG-###-short-description.md

docs/ideas/

  • Purpose: Feature exploration and research before promotion to specs
  • Content: Freeform markdown exploring a feature concept
  • Archive: Promoted ideas move to docs/ideas/_archive/

docs/technical-debt/

  • Purpose: Known technical debt items and remediation plans

docs/testing/

  • Purpose: Testing strategy, test plans, coverage reports

docs/runbooks/

  • Purpose: Operational guides and setup instructions

docs/references/

  • Purpose: External documentation, research materials, API guides

docs/engineering/

  • Purpose: Engineering process documentation, execution standards

docs/security/

  • Purpose: Security review reports and findings log

Placement Rules

DO NOT: Create documentation files in docs/ root, mix document types, or create new subdirectories without documenting their purpose.

DO: Place ADRs in docs/decisions/ with proper numbering, update this list if adding a new documentation category.

API Versioning

  • APIs must be versioned from the start of the project.
  • Versioning strategy must be explicit, documented, and applied consistently.

Development Roadmap and Planning

  • Before substantive implementation begins, establish a structured plan:
    • Kiro Specs (preferred): requirements.md, design.md, and tasks.md under .kiro/specs/{feature-name}/
    • Manual Roadmap (for broader planning): docs/roadmap/roadmap.md with milestones and TODO items
  • Link specs to the roadmap at the appropriate timeline point.
  • Execute work incrementally, one task at a time.
  • If implementation realities require a plan change: update the spec/roadmap, document the reason, record in changelog.

Spec Quality Standards - NON-NEGOTIABLE

Requirements.md must include:

  • Numbered user stories with acceptance criteria (testable, not vague)
  • Non-functional requirements (performance, cost, reliability, accessibility)
  • Explicit "out of scope" section to prevent scope creep
  • UX acceptance criteria for any user-facing feature - not just "show data" but how it's shown: hierarchy, spacing, interaction placement, density expectations

Design.md must include:

  • Architecture diagram showing service interactions
  • Data model with actual SQL or Pydantic schemas (not hand-wavy descriptions)
  • API contracts with request/response examples
  • Frontend component tree with data flow
  • For pipelines/background processes: observability design (what gets logged, what metrics are emitted, how to trace a request end-to-end)

Tasks.md must include:

  • Phases with clear boundaries and checkpoint gates
  • Every task has a concrete deliverable (file path, test name, endpoint)
  • TDD structure: RED → GREEN → REFACTOR per step
  • Security checkpoint at final phase
  • No vague tasks like "implement the feature" - break down to individual functions/components

If a spec feels thin, it IS thin. Expand it before writing code.

ADR Roadmap Linking - MANDATORY

Every ADR must be linked in docs/roadmap/roadmap.md at the sprint/milestone row where the decision was made.

Rules:

  • Link ADRs in chronological order within each row
  • Only link ADRs that actually exist on disk
  • Format: [ADR-###](../decisions/ADR-###-descriptive-name.md) (relative path from docs/roadmap/)

Code Documentation

  • See code-commenting-standards.md for docstring and comment rules
  • All docs live in docs/ directory (except README.md)


inclusion: always

Error Handling & Performance

Standards for error handling, performance optimization, and themed UI dialogs.

Async Discipline - MANDATORY

Operations that depend on each other must be sequenced. Never fire-and-forget before a dependent operation.

Rules

  1. Use mutateAsync + await for dependent operations - if operation B depends on operation A completing, use await mutateAsync() for A, not mutate(). mutate is fire-and-forget; it does NOT wait for completion.
  2. Never block async event loops with sync I/O - in Python asyncio, never call sync functions that take >100ms (HTTP requests, LLM calls, file I/O on large files) without await asyncio.to_thread() or loop.run_in_executor().
  3. Auth token timing - never fire API requests that require auth before confirming the token is available. Check auth state before making dependent requests, not after a 401.
  4. Sequence mutations that share state - if two mutations modify the same resource, await the first before firing the second. Parallel mutations on shared state cause race conditions.

Error Handling Standards - MANDATORY

Errors must be explicit, contextual, and never silently swallowed.

Rules

  1. Never silently ignore errors - every error must be raised, logged, or explicitly handled. Empty except: / catch {} blocks are forbidden.
  2. Use specific error types - not catch-all handlers. Each error type should clearly indicate what went wrong and where.
  3. Error messages must include context - request parameters, status codes, what operation was being attempted, and what input caused the failure. No generic "something went wrong."
  4. No automatic fallbacks - code should either succeed or fail clearly. Fallbacks are only allowed when explicitly designed and documented. Silent fallbacks hide real problems.
  5. Fix root causes, not symptoms - if an error keeps occurring, fix the underlying issue rather than adding retry/fallback logic around it.
  6. External service calls: retry with backoff - use exponential backoff for transient failures. Raise the last error if all attempts fail. Log each retry attempt.
  7. API endpoints return proper HTTP status codes - never return 200 for errors. Use 4xx for client errors, 5xx for server errors, with structured error response bodies.
  8. Frontend errors: catch at boundaries - use error boundaries (React) or equivalent. Show user-friendly messages, log the full error for debugging.

Performance Guidelines - MANDATORY

Design for efficiency from the start. Performance is not an afterthought.

Rules

  1. Cache expensive operations - database queries, API calls, computed values. Use appropriate cache invalidation strategies.
  2. Pagination for all list endpoints - never return unbounded result sets. Default page size must be a named constant.
  3. No N+1 queries - use eager loading, joins, or batch queries. Review ORM-generated SQL for new endpoints.
  4. Lazy load heavy resources - large images, optional modules, below-the-fold content. Load on demand, not upfront.
  5. Database indexes - every column used in WHERE, JOIN, or ORDER BY clauses in frequent queries must have an index. Document index decisions.
  6. Bundle size awareness (frontend) - monitor bundle size. Use code splitting and tree shaking. Avoid importing entire libraries when only one function is needed.
  7. Timeouts on all external calls - every HTTP request, database query, and external service call must have an explicit timeout. No indefinite waits.

Themed Dialogs - MANDATORY

All confirmation dialogs, alerts, and informational popups must use the application's themed dialog components. No exceptions.

Rules

  1. Never use native browser dialogs - window.alert(), window.confirm(), and window.prompt() are forbidden. They cannot be styled, break the visual experience, and behave inconsistently across browsers.
  2. Use the application's dialog/modal system - every dialog must render through the project's themed component (e.g., ConfirmDialog, AlertDialog, Modal) so it inherits the design system's colors, typography, spacing, and animations.
  3. Consistent UX across all interactions - destructive actions get a themed confirmation dialog with clear action labels (not "OK/Cancel"). Informational messages use themed toast/snackbar notifications. Error messages use themed error dialogs with context.
  4. Accessible by default - themed dialogs must trap focus, support Escape to close, and include proper ARIA roles (role="dialog", aria-modal="true").

Observability-First Design - MANDATORY

ZERO BLACKBOXES. Every pipeline, background process, and async workflow must be observable from day one.

Rules for all background/async/pipeline code:

  1. Structured logging - every operation logs: what started, what inputs it received, what it produced, how long it took, whether it succeeded or failed. JSON structured logging, not print statements.
  2. Correlation IDs - every pipeline run or background task gets a unique ID that flows through all log entries and database records.
  3. State transitions - every job/task has explicit states (PENDING → RUNNING → SUCCESS/FAILED/RETRYING) stored in the database.
  4. Metrics - track: items processed, items failed, processing time, queue depth, retry count.
  5. Error context - when something fails, log the full context: what was being processed, what step failed, what the input was.
  6. Resumability - if a pipeline crashes mid-run, it must be resumable from where it stopped via database checkpointing.
  7. Discuss architecture first - before implementing any pipeline or background process, discuss the architecture: data flow, failure modes, retry strategy, observability hooks.


inclusion: fileMatch fileMatchPattern: ["/*.tsx", "/*.jsx"]

Frontend Patterns

Rules for React/JSX development. Loaded only when working on frontend component files.

React Hooks - NON-NEGOTIABLE

  1. ALL hooks at the top of the component - before any early returns, conditional logic, or variable declarations that depend on props. React requires the same hooks to run in the same order every render.
  2. Never place hooks after early returns - this causes "Rendered more hooks than during the previous render" crashes.
  3. Verify required providers exist - before using useQuery, useParams, useNavigate, or any context hook, confirm the component is rendered inside the required provider (QueryClientProvider, Router, etc.).
  4. Use mutateAsync + await for dependent operations - never fire-and-forget with mutate() when a subsequent operation depends on the result. mutate is fire-and-forget; mutateAsync returns a promise.

Event Propagation - MANDATORY

  1. Document event capture/propagation - when adding event handlers, note what events are captured, what propagation is stopped, and what other handlers exist on parent/child elements.
  2. React synthetic stopPropagation() does NOT stop native DOM events - if you need to stop a native event (e.g., window-level Escape listener), use e.nativeEvent.stopImmediatePropagation() or manage an event stack.
  3. Never spread DnD {...listeners} on containers with click handlers - DnD listeners capture all pointer events. Apply them to a dedicated drag handle element instead.
  4. Escape key layering - when multiple components listen for Escape (modals, drawers, dropdowns), implement a stack-based system. The topmost layer consumes the event; lower layers ignore it.
  5. Outside-click handlers + portals - if a component renders via a portal (e.g., dropdown menu on document.body), the outside-click handler must check if the click target is inside the portal, not just inside the trigger's DOM tree.

CSS Layout - MANDATORY

  1. Flex containers: always set min-h-0 and overflow-hidden on intermediate containers. Without min-h-0, flex children cannot shrink below their content size.
  2. Header/body alignment - use the SAME layout strategy (grid or flex with identical gaps/gutters) for both header and body rows. Never mix CSS grid for headers with flex for rows.
  3. Popover/dropdown positioning - verify the positioning direction matches the trigger's screen location. right: 0 extends leftward (correct for right-side triggers). left: 0 extends rightward (correct for left-side triggers).
  4. Absolute positioning inside overflow containers - elements with position: absolute are clipped by ancestor overflow: hidden. Use a portal or move the positioned element outside the overflow container.

Cache & Data Fetching - MANDATORY

  1. When setting staleTime - document what invalidation scenarios exist. After any mutation that changes server state, verify the cache is invalidated or the query is refetched.
  2. After mutations, always invalidate - call queryClient.invalidateQueries() for affected keys. Don't rely on staleTime expiry for data freshness after writes.
  3. Error + retry on 401 - if a query gets a 401, don't let staleTime prevent retry. Set retry: false for auth-dependent queries or clear the query cache on auth state change.
  4. Optimistic updates need rollback - if using optimistic updates, always implement the onError rollback. Don't leave stale optimistic state on failure.

Component Extraction & Reuse - MANDATORY

When extracting a shared component from an existing implementation, or when a new consumer adopts a shared component:

  1. Prop parity audit - before declaring a consumer "done", list every prop the original passes and verify the new consumer passes equivalent values. Empty props ({}, [], false) are the #1 source of "it compiles but looks wrong."
  2. Compare against the source, not against "compiles" - the acceptance criterion is "behaves like the original", not "TypeScript is happy." Open both the source and the new consumer side-by-side.
  3. Test with real data - never verify a component extraction with empty/default data only. Use the same data the original consumer uses.
  4. Layout wrapper parity - verify the new consumer uses the same layout container (full-width, max-width, padding) as the original. A component inside max-w-4xl looks nothing like the same component at full width.
  5. Interactive behavior parity - hover states, click handlers, optimistic updates, undo/toast patterns. If the original has them, the new consumer needs them too (or explicitly documents why not).

Completion Verification - MANDATORY

tsc --noEmit + vite build passing is NECESSARY but NOT SUFFICIENT for UI work.

Build tools verify types, imports, and syntax. They do NOT verify:

  • Visual output matches expectations
  • Props carry correct values (not empty defaults)
  • Layout fills the expected space
  • Interactive behavior works
  • The page looks like what the user asked for

Rules

  1. Never declare UI work "done" based solely on build output - you must verify the rendered result visually or explicitly state what you could not verify.
  2. When visual verification is unavailable - say so honestly. List specific things the user should check: "I cannot verify visually. Please confirm: (1) status pills show colors, (2) delete button appears on hover, (3) table fills full width." Never say "risk is minimal" without evidence.
  3. The user sees pixels, not types - a shared component architecture is worthless if the consumer passes wrong props. The last 5% (correct props, correct layout, correct behavior) is what makes the feature work.
  4. Speculation is not verification - "it should work" and "the risk is minimal" are not acceptable substitutes for actually checking. If you haven't verified, say "I haven't verified this."

Component Completeness - MANDATORY

Before marking any UI component or feature task as done, verify:

  1. Error state - what does the user see when the API call fails?
  2. Loading state - what does the user see while data is loading?
  3. Empty state - what does the user see when there's no data?
  4. Persistence - does any state need to survive page reload? If yes, where is it persisted?
  5. Destructive actions - do delete/remove actions have confirmation dialogs with undo?
  6. Themed components only - no native <select>, window.alert(), window.confirm(), or title attributes. Use the design system.

UX Non-Negotiables - MANDATORY

These rules apply to ALL frontend layout and interaction decisions. Violations are bugs.

  1. Interaction locality - controls must be near the object they affect. Never place a section menu at the far-right edge when the section title is on the left. Actions go before or beside their target.
  2. Primary content gets primary space - descriptions, comments, and form fields are content, not metadata. They get dominant width and vertical breathing room. Never squeeze content below metadata.
  3. No decorative borders unless they encode state - thick colored borders with no functional meaning are visual noise. Use subtle background, shadow, or tokenized selection treatment.
  4. Minimum readable text size - body text minimum 14px. Content text (descriptions, comments) preferred 15-16px. Comments are content, not admin data.
  5. First-glance test - within 3 seconds, user must know: what am I viewing, what is most important, what can I do next.
  6. Density matches task type - data grids: compact is acceptable. Reading, comments, task detail, forms: spacious is required.
  7. Copy the reason, not just the surface - when borrowing a pattern from another product, preserve WHY it works (interaction model, hierarchy, locality). Don't copy the visual and break the interaction.
  8. No justify-between for section actions - section-level controls use leading or adjacent placement. Never push primary section controls to the far-right trailing slot unless they affect the entire page.


inclusion: always description: Git branching, commit cadence, and agent focus - branch isolation, defensive checkpoints, request triage, and merge-and-delete hygiene in one place

Git & Focus Discipline

This file governs one behavioral domain: how an agent uses git and how it stays focused on one task at a time. The two are inseparable - undisciplined focus (thrashing between tasks) is what entangles unrelated changes on the wrong branch, and undisciplined git (uncommitted work, branch sprawl) is what makes lost focus unrecoverable.

Two failure modes this file exists to prevent. Both are invisible when they happen and expensive much later:

  1. Branch sprawl & divergence - branches that are never merged-and-deleted pile up, silently diverge, and produce duplicate-but-different versions of the same file.
  2. Task thrashing & lost work - dropping the current job to chase a new request, or ending a session with work uncommitted, so the thread (and sometimes the code) evaporates.

The hard "never" rules referenced throughout live in agent-boundaries.md - the shortest file in this set. Read it first; this file is the detailed "how".


Core Principle

Every concrete piece of work gets its own branch. Commit every meaningful checkpoint within that branch. Merge to main when it works, then delete the branch. Never mix unrelated work on the same branch.

main ──→ feat/A ──→ merge+delete ──→ fix/B ──→ merge+delete ──→ feat/C ──→ ...

Part 1 - Branch Hygiene

A branch exists to isolate one task and then disappear. A branch that outlives its task is a liability. These rules come first because branch divergence is the most common and most damaging failure mode.

  1. One task, one branch. Never reuse a branch for a second, unrelated task.
  2. Check before you branch. Before creating a branch in a feature area, confirm no branch already touches it:
    bash scripts/branch-check.sh <area>
    If one exists, build on the latest of it (rebased on main) or merge it first. Do not create a parallel branch that will fork into a duplicate file.
  3. Never start new work with a branch still open. Reach Definition of Done, or explicitly park the current branch, before creating another. Unmerged branch + new work = guaranteed divergence.
  4. Merge-and-delete is a single motion. The moment work merges to main, delete the branch:
    git checkout main && git merge --no-ff feat/x && git branch -d feat/x
    Do not keep it "just in case" - main has the history.
  5. Detect collisions while you work. Run bash scripts/branch-check.sh (no args) to list other unmerged branches editing the same files you are - the early-warning signal for silent divergence.
  6. Prune merged branches regularly:
    git branch --merged main | grep -v '^\*\|main' | xargs -r git branch -d
  7. If two branches have already diverged on the same file, do not re-type or guess. Identify the superset version (the most complete, correct one), restore that single file onto the surviving branch, commit it immediately, then delete the dead branch. Uncommitted reconciliation is itself a root cause - commit it before doing anything else.

The anti-pattern this kills

~200 branches, almost none merged-and-deleted. Two independently touched the same feature area on the same day, producing duplicate-but-divergent files. The workflow said "merge then delete"; in practice they piled up and silently diverged.

Branch sprawl is not cosmetic. Every un-deleted branch is a chance for the next task to fork reality.

Parallel agent sessions

If more than one agent session may touch this repo (or a sibling tree) at once, each session gets its own git worktree on its own branch - never a shared working directory. scripts/branch-check.sh is the detective control (warns after the fact); worktrees are the preventive control. See session-isolation.md for the full cross-session safety rules.


Part 2 - Branch Types & Naming

SituationBranch typeExample
Building a new feature or specfeat/feat/ingredient-analysis
Fixing a reported bugfix/fix/bug-003-score-calc
UI/UX change onlyui/ui/dashboard-layout
Tests onlytest/test/auth-regression
Tooling, config, depschore/chore/update-deps
Documentation onlydocs/docs/adr-001-tech-stack
Refactor (no behaviour change)refactor/refactor/extract-service

Rules:

  • Always kebab-case after the /
  • 3-5 words max
  • Include BUG-### for bug fixes: fix/bug-034-description
  • Include spec name for spec work: feat/spec-name

Part 3 - Commit Discipline

A branch is not a place to hoard uncommitted work. Commit at every meaningful checkpoint so that no context boundary, crash, or bad next step can erase a good state. This is the discipline most agents lack by default.

What counts as a "meaningful checkpoint"

A commit-worthy checkpoint is reached when all three hold:

  1. The code compiles / imports cleanly (no syntax or import errors).
  2. The affected tests pass (the tests touching the code you just changed).
  3. There are no new lint errors introduced by the change.

The moment you reach that state, commit before moving to the next logical unit of work. Do not let a passing state sit uncommitted while you start the next piece - context compression, session end, or a bad subsequent step will erase it.

Defensive Checkpoints - MANDATORY

Before starting any task that will touch more than 3 files or span more than one session, create a labeled checkpoint commit first:

git add -A && git commit -m "checkpoint: before <task-description>"

This creates a safe rollback point. A checkpoint is not a feature commit - it does not need to pass tests or meet the commit-message standard below. Its only job is to make the pre-task state recoverable. (This is the one sanctioned exception to "never commit failing code" - a checkpoint is explicitly flagged as such.)

Never end a session with uncommitted work - MANDATORY

Agent sessions end abruptly - context compaction, a closed terminal, a crash. Work left in the working tree but not in git is gone.

  • At any natural stopping point (task done, turn ending, switching away), run git status. If there are uncommitted changes on a branch, commit them (feature commit if at a checkpoint, checkpoint: commit otherwise) or stash them.
  • The commit-checkpoint-on-stop hook reminds you of this on agent stop, but the rule holds whether or not the hook fires.

One logical change per commit - MANDATORY

  • One logical change per commit. When multiple files change for different reasons, prefer separate commits per reason. Do not bundle unrelated changes - it makes rollback impossible.
  • Test before a feature commit. Never commit code that makes existing tests fail, unless the commit is an explicitly-labeled checkpoint:.
  • Review your diff before committing. Every changed line must relate to the task (see change-discipline.md).

Commit Message Format

Conventional Commits:

<type>(<optional scope>): <short description>
TypeWhen
featNew feature
fixBug fix
choreTooling, deps, config
docsDocumentation only
testTests only
refactorNo behaviour change
uiFrontend-only visual change
perfPerformance improvement

(checkpoint: is the one non-Conventional prefix, reserved for the defensive rollback commits described above.)


Part 4 - The Standard Lifecycle

Standard Git Scripts

All git operations MUST use the scripts in scripts/ which pipe output through tee to logs/. This ensures output is always captured.

ScriptPurposeLog file
./scripts/git-commit-push.sh "message"Commit, merge to main, pushlogs/git-commit-push.txt

1. Start from main

git checkout main && git checkout -b feat/my-work

2. Work and commit incrementally (at every meaningful checkpoint)

git add -A && git commit -m "feat: description of what changed"

3. Merge to main when done

bash scripts/git-commit-push.sh "feat: description"

4. Start the next piece of work from main

git checkout -b feat/next-thing

Part 5 - Focus & The Request Queue Protocol

When a new request arrives while you are mid-task, the default is to FILE it, not DO it.

Triage, don't thrash

When the user sends a request while you have unfinished work in progress, classify it:

  1. Same task - a clarification, correction, or refinement of what you're already doing → fold it in and keep going.
  2. Explicit divert - the user clearly says to switch now ("stop", "drop that", "this is critical, fix it first") → switch, but commit or stash the current work first so it is not lost.
  3. Unrelated new request (the common case) → file it and continue.

How to file it

  1. Append the request to docs/backlog/INBOX.md (create it if missing) with the date and what you were doing when it arrived.
  2. Acknowledge in one line: "Noted [request] in the backlog - I'll finish [current task] first, then pick it up."
  3. Return to the task at hand. Do not start the new work.

Why this is strict

Switching tasks mid-stream is the root cause of:

  • Half-finished features abandoned on branches.
  • Unrelated changes bleeding into the wrong branch - you're on feat/auth fixing auth, an unrelated CSS or logic fix gets committed there too, and now two unrelated changes are entangled so neither can be reverted cleanly.
  • Lost context - the original task's plan evaporates and is never completed.

A filed request is never lost. An abandoned task usually is. Only the user may authorize a divert - you do not divert on your own judgment that the new thing is "quick."


Part 6 - Definition of Done

A task is not done when the code works. It is done when ALL of the following are true, in order:

  1. The change is complete and matches the request.
  2. Tests are written and passing (TDD - see testing-standards.md).
  3. The changelog and any affected docs are updated.
  4. The work is committed on its own branch.
  5. The branch is merged to main.
  6. The merged branch is deleted.
  7. The backlog is checked - drain the next docs/backlog/INBOX.md item or report what remains.

Only after step 7 do you start the next piece of work. "I'll commit it later" is how branches pile up and diverge.


Part 7 - Handling Bugs During Feature Work

Do NOT fix bugs on the current feature branch.

  1. Note it down - add to docs/bugs/
  2. Finish or stash the current feature
  3. Create a dedicated fix branch from main
  4. Fix, test, merge
  5. Return to the feature branch and merge main

Bug Resolution Workflow - MANDATORY

When a bug is identified, follow this workflow in full:

  1. Assign a bug number - check docs/bugs/ for the highest existing BUG-### number and increment by 1
  2. Create the bug document - docs/bugs/BUG-###-short-description.md with: ID, Severity, Status, Description, Reproduction steps, Root cause, Fix description, Files changed, Regression tests added
  3. Fix the bug - minimal and targeted fix on a fix/bug-###-description branch. Do not refactor unrelated code.
  4. Variant search - NON-NEGOTIABLE - after identifying the root cause:
    • Search for the same pattern at all other call sites in the codebase
    • Search for the same vulnerability class elsewhere (e.g., if you found one SQL injection, search for all raw SQL)
    • Document: "Variant search: checked [locations]. Found [N] additional instances."
    • Fix ALL variants in the same branch, not just the reported instance
    • The variant-search-on-fix-branch hook reminds you of this whenever you work on a fix/ branch - the reported instance is rarely the only one.
  5. Add regression tests - NON-NEGOTIABLE - every bug fix requires both negative AND positive regression tests:
    • Negative test: reproduces the bug, must FAIL on unfixed code (RED phase)
    • Positive test: confirms the fix, passes after fix (GREEN phase)
    • Named after the bug: test_bug###_<description> (Python) or it('BUG-###: <description>') (TypeScript)
    • Never mark a bug FIXED without regression tests committed in the same change
  6. Link to the roadmap - add a reference in the roadmap or spec tasks for traceability
  7. Update the changelog - add entry to docs/changelogs/CHANGELOG.md under today's date
  8. Update the bug document status - set Status to FIXED, fill in Fixed date and remaining fields

Part 8 - Spec-Driven Work

  1. Create feat/<spec-name> branch from main
  2. Complete ALL tasks in the spec on that branch
  3. Merge to main when the spec is complete
  4. ONLY THEN create the next spec's branch

Never start Phase 2 before Phase 1 is merged to main.


Part 9 - Forbidden Actions & Per-File Conflict Resolution

ActionWhy it's banned
Fixing a bug on a feature branchEntangles unrelated changes
Creating a branch from another feature branchMisses main's latest work
Committing directly to mainBypasses branch isolation
Leaving a branch unmerged and starting new workCreates divergence
Leaving a session with uncommitted workWork evaporates at the context boundary
Mixing multiple features on one branchMakes rollback impossible
Modifying a test to make it passHides the real failure - fix the implementation
git checkout --ours . or git checkout --theirs .Blanket conflict resolution reverts work
Force-pushing or rebasing mainRewrites shared history

Per-File Conflict Resolution - MANDATORY

FORBIDDEN:

git checkout --ours .    # ← BANNED
git checkout --theirs .  # ← BANNED

Resolve each file individually based on which side has the correct work. On a genuine ambiguity you cannot resolve from the code, stop and ask - two minutes of clarification beats twenty hours of rebuilding. A confident wrong guess is the expensive failure mode.


Cross-references

  • agent-boundaries.md - the hard "never" rules in their shortest form.
  • change-discipline.md - change-scope discipline (keep unrelated edits out of the diff), fix-depth rule, permission boundaries.
  • session-isolation.md - cross-repo and cross-session safety, worktree usage.
  • testing-standards.md - TDD cycle, regression-test requirements.
  • scripts/branch-check.sh - branch collision detector used by the rules above.
  • docs/backlog/INBOX.md - the request queue the focus protocol writes to.


inclusion: always

Import Path Rules

Absolute Rule: No Deep Relative Imports

NEVER use ../../ or deeper relative paths in any import statement. This applies to both Python backend and TypeScript frontend.

Relative imports beyond one level (../) create fragile, unreadable code that breaks on refactors. Use path aliases instead.

Python Backend

Use #src/ subpath imports or absolute package imports. Never ../../.

Allowed

# Absolute package imports (preferred)
from packages.common.models import Ingredient
from packages.evidence.src.scoring import ConsensusScorer

# Same-package relative (one level only, for tightly coupled files)
from .models import Ingredient
from ..core import config

Forbidden

# BANNED - deep relative imports
from ...common.models import Ingredient
from ....evidence.src.scoring import ConsensusScorer

Configuration

Each package's pyproject.toml declares itself as an installable package. Cross-package imports use the package name directly, resolved by uv workspaces.

TypeScript Frontend

Use @/ path alias for all imports. Never ../../.

Allowed

// Path alias (preferred for all cross-directory imports)
import { useAnalysis } from '@/features/analysis/hooks/useAnalysis'
import { Button } from '@/shared/components/Button'
import { api } from '@/services/api'
import type { Ingredient } from '@/types/ingredient'

// Same-directory relative (only for tightly coupled files in the same feature)
import { IngredientCard } from './IngredientCard'

Forbidden

// BANNED - any relative import crossing directory boundaries
import { Button } from '../../shared/components/Button'
import { api } from '../../../services/api'

Configuration

vite.config.ts:

resolve: {
  alias: { '@': path.resolve(__dirname, './src') }
}

tsconfig.json:

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": { "@/*": ["src/*"] }
  }
}

Enforcement

  • Code review catches violations
  • ESLint no-restricted-imports rule bans ../.. patterns in frontend
  • Ruff import sorting keeps Python imports clean
  • When touching existing files with deep relative imports, fix them opportunistically


inclusion: auto description: File naming conventions for test files and source code organization

File Naming Conventions

Test Files Must Mirror Source File Names

Test files must use the exact same name as the source file they test, with the appropriate test suffix.

Backend (Python)

Source fileTest file
src/services/auth.pytests/unit/test_auth.py
src/models/user.pytests/unit/test_user.py

Frontend (TypeScript)

Source fileTest file
src/features/auth/auth.service.tstests/unit/auth.service.test.ts
src/shared/hooks/useAuth.tstests/unit/useAuth.test.ts

Rules

  • Never mix conventions - the test file name is always derived from the source file name
  • E2E tests use kebab-case descriptive names (e.g. ingredient-analysis-flow.test.ts)


inclusion: always

Project-Specific Conventions

Rules specific to this project's codebase, tools, and architecture. For project-specific overrides (tech stack, ports, database, code style), see user-project-overrides.md.

Git and Terminal Workflow

Terminal output capture can be unreliable in this environment. Always use the standard git scripts in scripts/ which pipe output through tee to logs/.

Domain Constants Strategy

Rule: All domain constants live in a dedicated constants directory - never inline in model files.

  • Never define domain constants inline in a model file
  • When adding a new feature with constants, create a dedicated constants file

Testing Execution

  • Always stream test output: use pytest -v --tb=short with NO pipes (| tail, | head, | grep)
  • Both positive AND negative test cases are required

Code Style

  • Use datetime.now(timezone.utc) - never datetime.utcnow() (deprecated)
  • Use parameterized queries for all SQL - never string interpolation
  • Separation of concerns: keep services as separate classes

Architecture Decisions

  • ADRs are required before major implementations - store them in docs/decisions/

Environment and Tooling

  • Use the project's virtual environment for all Python work. Never install packages globally.
  • Never install packages in the global Python registry.

Command Output Logging - MANDATORY

ALL commands that produce output you need to analyze MUST be logged to files using tee.

Logging Pattern:

python -m pytest tests/ -v --tb=short 2>&1 | tee logs/test_results.log

Log File Location:

  • All command logs: logs/

Reusable Utility Scripts - MANDATORY

When the first need arises for any repeated operation, write a parameterized reusable script with logging and error checking. Then use that script going forward. No ad-hoc multi-line shell commands for operations that will be repeated.

Rules

  1. First need = script. The moment you do something manually that could recur (restart a service, run a migration, deploy, seed data, check health), write a script in scripts/.
  2. Parameterized. Scripts accept arguments (service name, environment, etc.) - not hardcoded for one case.
  3. Verbose with logging. Scripts log what they're doing with timestamps. On failure, they print useful diagnostics.
  4. Error checking. Scripts use set -uo pipefail, check exit codes, and fail loudly.
  5. Reuse. Once a script exists, always use it. Never rewrite the same logic inline.
  6. Discoverable. Scripts live in scripts/ with descriptive names. Add a comment header explaining usage.

Anti-Patterns (BANNED)

# WRONG - ad-hoc multi-line restart
fuser -k 8060/tcp 2>/dev/null
sleep 2
cd /path/to/project && nohup .venv/bin/python -m uvicorn ...
echo $! > logs/server.pid
sleep 5
curl -s http://localhost:PORT/health

# CORRECT - one-liner using the script
bash scripts/restart-service.sh service-name

Minimize shell calls. If you find yourself making the same type of shell call 3+ times in a session (restart, health check, token fetch, DB query pattern), that is a candidate for a reusable script. Write it in scripts/, then use it going forward. TracePulse get_audit_trail can help identify repeated patterns.



inclusion: always

Reusable Architecture

Reusable component design, infrastructure abstraction, and centralized configuration.

Reusable Component Architecture - MANDATORY

Before building any new service, module, component, or helper, think reuse-first.

Design-Time Mindset

  1. Search before building - scan the codebase for existing implementations that solve the same or a similar problem. Duplication is a bug.
  2. Identify the generic core - every piece of logic has a domain-specific shell and a generic core. Extract the generic core as a standalone unit with clean inputs/outputs.
  3. Design for reuse, place locally - architect components with clean interfaces, dependency injection, and no hardcoded assumptions. But place them in the feature where they're first needed (per the Graduation Policy in code-organization.md). The clean design makes future graduation to shared/ trivial.
  4. Pure functions by default - helper methods and utilities should be pure functions (no side effects, no hidden state, no implicit dependencies) wherever possible. Pure functions are trivially reusable and testable.
  5. Parameterize, don't specialize - if a component could serve multiple consumers with minor variations, accept those variations as parameters rather than forking the implementation.

When NOT to Make Something Reusable

  • If it requires more than 3 domain-specific parameters to generalize, it's not ready - keep it feature-scoped
  • If the "generic" version would be more complex than two specialized copies, don't abstract
  • If only one consumer exists and no second consumer is foreseeable, don't over-engineer

Review Checkpoint

When designing any new module, answer these before writing code:

  • Does something similar already exist in the codebase?
  • What is the generic core vs. the domain-specific wrapper?
  • Could another feature, service, or project use this with zero modification?
  • Am I hardcoding anything that should be a parameter?

Infrastructure Abstraction - MANDATORY

Every external dependency gets an interface. Storage, email, payments, auth providers, AI models, notification channels - all must be accessed through an abstract interface with swappable backend implementations. No service should be hardwired to a specific vendor or infrastructure.

Adapter Pattern for External Services

Define an abstract interface for each infrastructure concern. Implement one adapter per backend. Application code depends only on the interface, never on a concrete implementation.

This applies to:

  • File storage (local filesystem ↔ S3 ↔ GCS)
  • Configuration persistence (file ↔ localStorage ↔ IndexedDB)
  • Email/SMS (console logger ↔ SES ↔ SendGrid)
  • Notifications (log ↔ SNS ↔ WebSocket)
  • AI/ML providers (local model ↔ OpenAI ↔ Bedrock)
  • Payment processing, auth providers, and any other external service

Factory + Config-Driven Instantiation

Backends are selected via configuration, never hardcoded. A factory function reads the config and returns the correct adapter:

storage = create_storage_backend(settings.STORAGE_BACKEND)  # "local" | "s3"
email = create_email_backend(settings.EMAIL_BACKEND)         # "console" | "ses"
  • The factory is the only place that knows about concrete implementations
  • Application code receives the interface - it never imports a specific backend directly
  • Switching providers is a config change, not a code change

Secure Defaults

All infrastructure adapters must enforce security at the interface level:

  1. Content-type validation - never trust client-provided MIME types on upload. Validate server-side.
  2. Size limits at the interface - enforce max file size in the abstract interface, not just the implementation. Every backend inherits the same limits.
  3. Path traversal prevention - sanitize all keys and paths. Reject ../, absolute paths, and null bytes.
  4. Signed/expiring URLs - never expose raw storage paths (S3 keys, file paths). All download URLs must be signed with expiration.
  5. Least privilege - each adapter uses credentials scoped to its specific function. Storage adapters don't get database credentials.

Idempotency

  • Uploads are idempotent - uploading the same key with the same content is a no-op
  • Deletes are idempotent - deleting a non-existent object succeeds silently
  • Config writes are idempotent - writing the same value is a no-op
  • Design all infrastructure operations so they can be safely retried without side effects

Observability

Every infrastructure adapter must emit structured logs for every operation:

  • What: operation type (upload, download, delete, send)
  • Target: key, recipient, resource identifier
  • Size: bytes transferred (where applicable)
  • Duration: wall-clock time of the operation
  • Outcome: success or failure with error category
  • The abstract interface defines the logging contract - implementations inherit it, not duplicate it

Centralized Configuration & Constants - MANDATORY

ZERO embedded literals. All configuration values, magic numbers, string constants, and environment-dependent settings must live in dedicated, centralized locations - never scattered across modules.

State Persistence - MANDATORY

Every piece of state must have an explicit persistence strategy.

Rules

  1. Ask "what happens on reload?" - for any state introduced by a feature, explicitly decide: does it survive page reload? If yes, where is it stored?
  2. Module-level variables are ephemeral - they are destroyed on page reload, content script reload, or server restart. If state must persist, use: localStorage, sessionStorage, IndexedDB, chrome.storage, database, or URL params.
  3. Single source of truth - never store the same state in multiple locations (e.g., memory + localStorage + database). Pick one authoritative source and derive the rest.
  4. Document intentional ephemerality - if state is deliberately ephemeral (e.g., a hover state, animation frame), add a comment: // Ephemeral: resets on reload (intentional).
  5. Sync state on startup - if persistent state exists (localStorage, database), load it on component mount / app startup. Don't start with empty state and wait for a user action to hydrate.

Configuration Hierarchy

backend/src/
├── core/
│   └── config.py             # App config: reads from env vars, .env, defaults
├── constants/                # Domain constants - organized by domain
│   ├── auth.py               # Roles, token lifetimes, OAuth scopes
│   ├── products.py           # Categories, statuses, limits
│   └── common.py             # Shared constants (pagination defaults, date formats)
frontend/src/
├── shared/
│   └── config/
│       ├── env.ts            # Environment-dependent config (API URLs, feature flags)
│       └── constants.ts      # App-wide constants
├── features/
│   └── auth/
│       └── constants.ts      # Feature-scoped constants (only if used by this feature alone)

Rules

  1. No string literals in business logic - URLs, status values, error messages, field names, limits, thresholds - all go in constants files or config.
  2. No magic numbers - every numeric value with business meaning gets a named constant with a comment explaining why that value was chosen.
  3. Config reads from environment - all environment-dependent values (DB URLs, API keys, feature flags, ports) go through a single config module that reads from .env / environment variables with typed defaults.
  4. Constants are grouped by domain - constants/auth.py for auth-related values, constants/products.py for product-related values. Not one giant constants file.
  5. Feature-scoped constants stay in the feature - if a constant is only used within one feature, it lives in that feature's constants.ts or at the top of the relevant module. It graduates to shared/ or constants/ when a second consumer appears.
  6. Enums over string literals - use enums (Python Enum, TypeScript enum or as const) for any value that has a fixed set of options. Never compare against raw strings.
  7. Single source of truth - if the same value is needed by both frontend and backend, define it in the backend and expose it via API or shared schema. Never duplicate constants across the stack.

What Belongs Where

Value typeLocation
Environment-dependent (DB URL, API keys, ports)core/config.py / shared/config/env.ts
Domain constants (statuses, roles, categories)constants/<domain>.py / features/<domain>/constants.ts
Shared constants (pagination, date formats)constants/common.py / shared/config/constants.ts
Error messagesconstants/<domain>.py or a dedicated constants/errors.py
Feature flagscore/config.py (read from env)

Periodic Review Policy

Purpose

This policy governs when and how automated code reviews are triggered during development. All reviews are powered by hooks in .kiro/hooks/. Results are stored in docs/security/ and docs/reviews/ respectively.

The security review system follows a three-tier model - one prompt, three hooks, three scopes - that matches review depth to development context. See docs/tiered-review-methodology.md for full rationale.


Quick Reference - Which Review, When

Use /review-guide for interactive help. The short version:

You just...Run this
Finished UI work/review-ux-live (browser walk) or /review-ux-audit (from code)
Completed a feature/review-code-security (Tier 2) + /review-code-maintainability
Changed auth/API code/review-code-security + /review-api-contracts
Added dependencies/review-dependency-risk
Wrote a spec/review-spec-readiness
End of sprint/review-code-security (Tier 3) + /review-test-quality
Shipping AI features/review-ai-agent-surface
Worried about perf/review-frontend-performance or /review-observability

Full catalog: 17 prompts in .kiro/prompts/review-*.md


Threat Modeling - Recommended Before First Review

Before running your first Tier 2 or Tier 3 security review, build a threat model for the project using the AWS Labs Threat Modeling MCP Server. This produces a structured threat model (assets, trust boundaries, threat actors, data flows) that the security review prompts can reference to reduce false positives.

Setup: Add to .kiro/settings/mcp.json:

{
  "mcpServers": {
    "threat-modeling": {
      "command": "uvx",
      "args": ["threat-modeling-mcp-server"]
    }
  }
}

Workflow: Run the threat modeling process → export to docs/security/THREAT_MODEL.md or .threatmodel/ → the security review prompt reads it before scanning.

Without a threat model, the reviewer infers trust boundaries from code alone, which is the primary cause of false positives.


Tier 1 - Pre-Commit (Every Commit)

Hook: security-tier1-precommit.json Trigger: Automatically on every git commit Scope: Staged files only

Fires when:

  • Any git commit command is detected
  • Any call to scripts/git-commit-push.sh is detected

Checks: Secrets, unsafe execution, auth bypass, missing input validation, PII in logs

Output: Inline block/warn response only - no SRR file generated

  • CRITICAL and HIGH findings block the commit
  • MEDIUM findings warn but allow

Tier 2 - Feature Complete

Hook: security-tier2-feature.json Trigger: After feature completion or manual invocation Scope: Files changed since the last SRR, plus new integrations, routes, and IAM definitions

Fires when:

  • A new route, Lambda handler, or service is added and marked complete
  • Any external integration (OAuth, third-party API, database, message queue) is wired up
  • A new IAM role, policy, or cloud resource is defined
  • Manually triggered when a feature branch is ready for review

Checks: All Tier 1 categories plus OWASP S1-S13, BOLA/IDOR, cryptographic quality, file upload security

Output: Full SRR report - docs/security/SRR-{###}-{YYYY-MM-DD}-T2.md

  • SECURITY_LOG.md updated
  • CRITICAL/HIGH findings create immediate fix tasks
  • MEDIUM/LOW findings added to roadmap

Tier 3 - Sprint or Phase End

Hook: security-tier3-sprint.json Trigger: Manual invocation at sprint or phase end Scope: Full codebase

Fires when:

  • End of each development sprint or phase
  • Before any major release or deployment
  • Manually triggered when systemic drift is suspected
  • Any dependency manifest (package.json, requirements.txt, etc.) has had significant changes across the sprint

Checks: All Tier 1 and Tier 2 categories plus supply chain (D1-D5), secure headers and CORS (S15), logging security (S16), rate limiting systemic review (S14-EXT), AI-generation artifact review, test coverage delta

Output: Full SRR report - docs/security/SRR-{###}-{YYYY-MM-DD}-T3.md

  • SECURITY_LOG.md updated
  • CRITICAL/HIGH findings create immediate fix tasks
  • MEDIUM/LOW findings added to roadmap
  • Dependency manifest snapshot recorded in docs/security/dep-snapshot-{YYYY-MM-DD}.md

Maintainability Review

Trigger: Manual invocation at feature completion and sprint end Scope: Changed files at feature completion; full codebase at sprint end

Fires when:

  • A feature or module is marked complete
  • Before any major commit or PR
  • At the end of each development sprint or phase
  • Manually triggered when structural drift is suspected

Output: Full MRR report - docs/reviews/MRR-{###}-{YYYY-MM-DD}.md

  • REVIEW_LOG.md updated
  • Phase 1 quick wins added to active sprint backlog
  • Phase 2 and Phase 3 items added to roadmap

UX Review - Live Browser Walk

Prompt: .kiro/prompts/review-ux-live.md Agent: .kiro/agents/ux-reviewer.json (restricted-tool: browser MCP + read + script exec only) Rubric: the "UX Console-Idiom Rubric" rules in CLAUDE.md (loaded on-demand, NOT always-on) Trigger: Manual invocation at UI feature completion or pre-release Scope: All user-facing routes (or subset specified by the invoker)

Fires when:

  • A ui/ or feat/ branch with frontend changes is marked feature-complete
  • Before any release (per the release checklist in versioning.md)
  • Manually triggered when UX regression is suspected
  • After a significant design system or layout change

Does NOT fire:

  • On every commit (too expensive - browser automation)
  • On backend-only changes with no UI impact
  • As always-on context (per research evidence on context-bloat cost)

Checks: Console-idiom rubric (9 families, 44 checks): Density & Type, Surfaces & Layout, Read-First Editing, Save Model, Tables & Lists, Empty States & Feedback, Copy & Correctness, Accessibility & States, Consistency & Tokens

Output: Full UXR report - docs/ux-reviews/UXR-{###}-{YYYY-MM-DD}.md

  • Systemic findings + per-page findings with rubric IDs
  • Prioritized plan (ship-now / fix-soon / defer)
  • Mandatory Corrections/Retractions section
  • Gate: PASS (zero Sev-1, no page below 70) or FAIL

Gate behavior:

  • FAIL blocks release (same weight as a Tier 2 security finding)
  • Sev-1 findings create immediate fix tasks
  • Sev-2 findings added to next sprint backlog

Sequencing Rule

When both a security review and a maintainability review are due at the same checkpoint (e.g., end of sprint or feature complete), run in this order:

  1. Tier 2 or Tier 3 security review first
  2. Maintainability review second

Security findings may surface structural issues that the maintainability review should account for.


Adversarial Verification - Reducing False Positives

Security reviews use a two-pass approach to reduce false positives:

Pass 1: Discovery (built into the security prompt)

The code-security-reviewer agent scans the codebase and produces findings with the severity calibration rubric and self-verification pass built into the prompt.

Pass 2: Independent Verification (separate agent)

For Tier 2 and Tier 3 reviews, after the discovery pass produces findings, spawn the security-verifier agent to adversarially disprove them:

Instruction to include in T2/T3 review workflow:

After producing the SRR findings above, invoke the security-verifier agent
with ONLY the list of HIGH+ findings (no reasoning, no context from this review).
The verifier will independently search the codebase for compensating controls
and report DISPROVED / CONFIRMED / DOWNGRADE for each finding.
Update the SRR with the verification results before finalizing.

When to use each approach

ContextVerification approach
Tier 1 (pre-commit)None - speed matters, findings are high-confidence patterns
Tier 2 (feature complete)Self-verification pass (built into prompt)
Tier 3 (sprint end)Self-verification + spawn security-verifier agent for HIGH+ findings
Pre-release or post-incidentFull independent verification - spawn verifier for ALL findings

Why two agents matter

The same agent that finds an issue is biased toward confirming it (confirmation bias). A separate agent with no access to the discovery reasoning and instructions to disprove each finding roughly halves false positives (per Anthropic's "Using LLMs to Secure Source Code" research, May 2026).


Output Convention

Review TypeOutput PathNaming Pattern
Security Tier 1Inline onlyNo file
Security Tier 2docs/security/SRR-{###}-{YYYY-MM-DD}-T2.md
Security Tier 3docs/security/SRR-{###}-{YYYY-MM-DD}-T3.md
AI Surface Reviewdocs/security/AISR-{###}-{YYYY-MM-DD}.md
Maintainabilitydocs/reviews/MRR-{###}-{YYYY-MM-DD}.md
UX Reviewdocs/ux-reviews/UXR-{###}-{YYYY-MM-DD}.md
Dep snapshotdocs/security/dep-snapshot-{YYYY-MM-DD}.md

Report Numbering

  • SRR numbers are sequential across all tiers: SRR-001, SRR-002, SRR-003, ...
  • MRR numbers are sequential: MRR-001, MRR-002, MRR-003, ...
  • UXR numbers are sequential: UXR-001, UXR-002, UXR-003, ...
  • Always check existing files in docs/security/, docs/reviews/, and docs/ux-reviews/ to determine the next number before creating a new report
  • The tier suffix (T2 or T3) is appended after the date, not the number

Folder Structure

.kiro/
- hooks/
  - security-tier1-precommit.json
  - security-tier2-feature.json
  - security-tier3-sprint.json
- prompts/
  - review-code-security.md
  - review-code-maintainability.md
- steering/
  - review-policy.md

docs/
- security/
  - SECURITY_LOG.md
  - dep-snapshot-{YYYY-MM-DD}.md
  - SRR-{###}-{YYYY-MM-DD}-T2.md
  - SRR-{###}-{YYYY-MM-DD}-T3.md
- reviews/
  - REVIEW_LOG.md
  - MRR-{###}-{YYYY-MM-DD}.md
- ux-reviews/
  - UXR-{###}-{YYYY-MM-DD}.md


inclusion: always description: Operate only inside your own project - never reach into sibling repos, never touch git trees or processes you don't own

Session Isolation

Multiple agent sessions can run on one machine at the same time, sharing the filesystem and sibling git repositories. A session that reaches outside its own project corrupts another session's work. These rules keep each session in its lane.

This is the failure this file prevents:

A session launched for repo tactiq reached into the sibling planiq repo - git -C /home/sourjya/coding/planiq reset --hard, a cherry-pick, a checkout, a PR - and corrupted the git state of a different session that was actively working planiq. Another session nearly ran kill on its own host terminal.

The Boundary - MANDATORY

Your project root is the directory you were launched in. Everything you do stays inside it.

  1. Never operate on another repository. Do not cd into a sibling project, do not run git -C <other-path> ..., and do not read/write/commit through absolute paths that point outside your project root.
  2. Never infer cross-repo intent. If a task seems to need changes in another repository, STOP and tell the user to run that work in that repo's own session. Do not reach across on your own judgment - that is exactly how git -C /other/repo reset --hard happens.
  3. Branches and PRs belong to one repo. Checking out a branch, cherry-picking, rebasing, or opening a PR in a repo that is not your project root is forbidden, even when asked indirectly ("also fix the thing in the other project").

Concurrent Sessions - MANDATORY

Assume another agent may be working in this tree, or a sibling tree, right now.

  1. Verify before destructive git. Before reset --hard, checkout -f, clean -fd, cherry-pick, rebase, or branch deletion, confirm: (a) you are in your own project root, and (b) the current branch and working-tree state are what you expect. If the branch or HEAD moved under you, a foreign actor touched the tree - STOP and report, do not "fix" it blindly.
  2. One worktree per concurrent session - the preventive control. When more than one agent session may touch this repo at once, each session gets its own git worktree on its own branch: git worktree add ../<name> <branch>. Never switch branches in, or share, a single working tree across sessions - that is what collides on HEAD. scripts/branch-check.sh is the detective control (warns after a collision); worktrees prevent it.
  3. Run the guard. bash scripts/session-guard.sh records this session's lock and warns if another live session holds the tree or if HEAD drifted unexpectedly.

Processes - MANDATORY

  1. Never kill a process you did not spawn. Your terminal, your MCP servers, and your parent session share one process tree - killing "the other agent" can be suicide (your own session) or sabotage (the user's other work).
  2. Identify before you signal. Before any kill/pkill, map the process tree and confirm the target is something you started. When unsure, report the PIDs to the user and let them decide. Never pkill by name pattern across the machine.

Cross-references

  • git-and-focus-discipline.md - in-repo branch discipline, commit cadence, and focus (this file is about cross-repo and cross-session safety).
  • scripts/session-guard.sh - session lock + working-tree integrity check.


inclusion: always

Testing Standards

Test folder organization, task-first discipline, and test-driven development rules.

Test Folder Organization - STRICT

Directory Structure

tests/
├── unit/                     # Fast, isolated tests - no I/O, no DB, no network
│   ├── auth/                 # Mirrors backend/src domain structure
│   │   ├── test_auth_service.py
│   │   └── test_token_utils.py
│   ├── products/
│   │   ├── test_product_service.py
│   │   └── test_pricing.py
│   └── common/
│       └── test_pagination.py
├── integration/              # Tests that hit real DB, APIs, or external services
│   ├── test_auth_flow.py
│   └── test_product_api.py
├── e2e/                      # End-to-end tests (Playwright, Cypress, etc.)
│   └── test_checkout_flow.py
├── property/                 # Property-based tests (Hypothesis, fast-check)
│   └── test_pricing_properties.py
├── conftest.py               # Root fixtures: DB sessions, auth helpers, test client
└── unit/conftest.py          # Unit-specific fixtures (mocks, fakes)

Rules

  • NEVER create __tests__/ folders, co-located test files, or any alternative test directory structure
  • Unit test subdirectories mirror source domains - if the source has services/auth/, tests go in tests/unit/auth/
  • One test file per source file - auth_service.py → test_auth_service.py. Never bundle unrelated tests.
  • Test file naming mirrors source - prefix with test_ (Python) or suffix with .test.ts / .spec.ts (TypeScript)
  • Shared fixtures in conftest.py - never duplicate fixture setup across test files. Extract to the nearest conftest.py.
  • Integration tests are separate from unit tests - unit tests must run without any external dependencies (DB, network, filesystem). Integration tests get their own directory.
  • Create subdirectories as domains emerge - don't pre-create empty test directories. Add them when the first test for that domain is written.

Frontend Test Structure

frontend/tests/
├── unit/
│   ├── auth/
│   │   ├── LoginForm.test.tsx
│   │   └── useAuth.test.ts
│   ├── dashboard/
│   │   └── DashboardPage.test.tsx
│   └── shared/
│       └── Button.test.tsx
├── integration/
│   └── auth-flow.test.ts
├── e2e/
│   └── checkout.spec.ts
└── setup.ts                  # Test setup (mocks, providers, global config)

Task-First Discipline - MANDATORY

CRITICAL: No code may be written without a task list. This is non-negotiable.

Where the task list lives:

  • Full spec features: .kiro/specs/{feature-name}/tasks.md
  • Bug fixes: docs/bugs/BUG-###-description.md
  • Minor enhancements: create a minimal task list inline before starting

The task list must be followed in order:

  1. Read the full task list before writing any code
  2. Mark each task [-] (in progress) before starting it
  3. Write tests FIRST (RED phase) per TDD rules
  4. Implement to make tests pass (GREEN phase)
  5. Mark each task [x] (complete) before moving to the next
  6. Never skip tasks or reorder them without documenting why

Test-Driven Development (TDD) - MANDATORY

The TDD Cycle

  1. RED: Write a failing test first
  2. GREEN: Write minimal code to make it pass
  3. REFACTOR: Clean up while keeping tests green

TDD Workflow Rules

  • NEVER write implementation code before writing its test
  • NEVER skip the RED phase - you must see the test fail first
  • Tests define the contract - implementation fulfills it
  • Each test should fail for the right reason (missing functionality, not syntax errors)

Exceptions to TDD

The ONLY exceptions where you may write code before tests:

  • Database migrations (but test the models they create)
  • Configuration files (JSON, YAML, .env templates)
  • Documentation (Markdown, ADRs)
  • Build scripts and tooling configuration

Testing Requirements

  • Every bug fix must include a regression test
  • Minimum 80% code coverage for new code
  • Both positive AND negative test cases required for every feature


inclusion: manual description: Console-idiom UX rubric - 9 check families with severity scoring for data-dense admin/SaaS interfaces. Load with /ux-console-idiom when reviewing or generating UI.

UX Console-Idiom Rubric

A checkable UX quality rubric for console-style applications - admin panels, dashboards, SaaS control planes, and data-dense internal tools. Each check has a unique ID, severity, and a binary pass/fail criterion.

Load this file when reviewing, auditing, or generating UI for console-type applications. It layers on top of WCAG 2.2 AA and Nielsen's 10 heuristics as the house standard - specific where they are general.

Customize: Override threshold values in user-project-overrides.md under the Design Tokens section. The IDs and severity model are fixed; the numeric thresholds are team-configurable.


Scoring Model

  • Starting score: 100 per page/screen
  • Sev-1 (blocking/data-loss/misleading): −15 each
  • Sev-2 (idiom/flow break): −5 each
  • Sev-3 (polish): −1 each
  • Ship gate: zero Sev-1 findings AND no page below 70

Severity Definitions

LevelMeaningExamples
Sev-1Data loss, user blocked, or actively misleadingModal with no Escape/close; save silently fails; destructive action without confirmation
Sev-2Breaks the console idiom or interrupts task flowMultiple save patterns on one page; unreadable density; broken navigation state
Sev-3Polish issue, cosmetic inconsistencyInconsistent border-radius; orphaned label; extra font weight

D - Density & Type

Controls typographic consistency and information density.

IDCheckSevCriterion
D-1Body text size2Body text within the configured range (default: 13–14px). Outliers flagged.
D-2Font weight count2No more than 2 font weights in use (default: 400, 600). Each additional weight is a finding.
D-3Heading hierarchy3Heading sizes decrease monotonically (h1 > h2 > h3). No size inversions.
D-4Line height3Body line-height between 1.4–1.6. Below 1.3 is a Sev-2 density violation.
D-5Micro-label variant3Badges, tags, and status pills use a dedicated smaller type size, not body text.

S - Surfaces & Layout

Controls spatial organization and container usage.

IDCheckSevCriterion
S-1Content primacy2Primary content (forms, descriptions, data) gets ≥60% of viewport height. Metadata is secondary.
S-2Section control placement2Section actions are adjacent to (leading or beside) their section header. Never trailing-far-right unless page-level.
S-3Consistent card/panel usage3Cards/panels of the same type use identical padding, border-radius, and shadow.
S-4Scroll containment2Each scrollable region is independently scrollable. No double-scrollbar or body-scroll-lock-while-panel-scrolls.
S-5Responsive breakpoints3Layout does not break or overflow between configured breakpoints.

R - Read-First Editing

Controls the inline-edit and detail-view patterns.

IDCheckSevCriterion
R-1Read state is default2Detail views render in read mode first. Edit mode requires an explicit user action.
R-2Edit affordance visible2The path from read to edit is discoverable within 1 click/tap from the read view.
R-3Cancel discards cleanly2Cancelling an edit restores the exact prior read state. No partial saves, no stale form data.
R-4Dirty-state indicator3When a form has unsaved changes, a visual indicator (dot, label, or disabled-nav warning) is visible.

V - Save Model

Controls how mutations are committed and confirmed.

IDCheckSevCriterion
V-1One save pattern per app2The entire application uses ONE save pattern (explicit Save button, auto-save, or inline confirm). Never mix.
V-2Save confirmation2Every successful save produces visible feedback (toast, inline check, status change) within 300ms.
V-3Save failure is loud1A failed save MUST surface an error the user can act on. Silent save failure is a Sev-1.
V-4Pending state during save3The save trigger shows a loading/pending state while the operation is in flight. No stale-looking button.

T - Tables & Lists

Controls data-grid and list-view patterns.

IDCheckSevCriterion
T-1Header–body alignment2Table headers and body cells use the same layout strategy (grid or flex with identical columns). No alignment drift.
T-2Row height consistency3All rows in a scan-mode table have identical height. Variable-height rows break scan flow.
T-3Empty state2A table/list with zero items shows a purposeful empty state (message + primary action), never a blank white space.
T-4Pagination or virtual scroll2Lists with >50 items are paginated or virtualized. Never render unbounded DOM lists.
T-5Sort/filter discoverability3Sort and filter controls are visible without interaction (not hidden behind a menu) on data tables.

E - Empty States & Feedback

Controls system status communication.

IDCheckSevCriterion
E-1Loading state2Every async-loaded section shows a skeleton or spinner. No blank flash before content appears.
E-2Error state2Every section that can fail shows a meaningful error (what happened + what to do next). No raw exception messages.
E-3Empty state with action2Empty sections explain what the area is for AND provide a primary creation action.
E-4Optimistic feedback3Actions that will succeed >99% of the time may show instant feedback (optimistic UI), with rollback on failure.
E-5Progress for long operations2Operations taking >2s show progress (determinate if possible, indeterminate otherwise).

C - Copy & Correctness

Controls text quality and data display.

IDCheckSevCriterion
C-1Pluralization2All countable nouns pluralize correctly ("1 item" / "3 items", never "1 items").
C-2Label/value pairing3Every data value has an adjacent label. No orphaned numbers or strings without context.
C-3Truncation with tooltip3Text that truncates (ellipsis) reveals full content on hover/focus via a tooltip or expansion.
C-4Consistent date format3A single date format is used throughout the app (configure in design tokens).
C-5User-generated names displayed as-is2User-provided names (project names, labels) display in their original case. Never slug-case or auto-transform.

A - Accessibility & States

Controls WCAG compliance and interactive state coverage.

IDCheckSevCriterion
A-1Focus management1Modals and dialogs trap focus on open AND return focus to the trigger on close. Violation is Sev-1 if it blocks task completion.
A-2Contrast ratio2Text meets WCAG 2.2 SC 1.4.3 (4.5:1 normal, 3:1 large). UI components meet SC 1.4.11 (3:1).
A-3Keyboard navigation1Every interactive element is reachable and operable via keyboard. Tab order follows visual order.
A-4Escape closes overlays1Pressing Escape closes the topmost overlay (modal, dropdown, drawer). Missing Escape is Sev-1 if it traps the user.
A-5Named form controls2Every <input>, <select>, and <textarea> has a visible or aria-label. No unlabelled controls.
A-6Disabled state clarity3Disabled controls are visually distinct (opacity, cursor) and have a title/tooltip explaining WHY they are disabled.

K - Consistency & Tokens

Controls design-system adherence and visual consistency.

IDCheckSevCriterion
K-1Border-radius set3At most N distinct border-radius values in use (default: 2). Additional values are findings.
K-2Color palette adherence2All colors used are from the configured design token palette. Off-palette colors are findings.
K-3Spacing scale3Padding and margin values align to the configured spacing scale (e.g., 4px increments).
K-4Icon style consistency3All icons use the same style family (outline OR filled, not mixed).
K-5Active/selected state2The current tab, nav item, or selection uses a consistent active-state treatment across the app.

Using This Rubric

In review prompts

Reference this file and require findings to carry a rubric ID + severity:

Finding: D-2 (Sev-2) - 4 font weights in use (400, 500, 600, 700). Expected max 2.
Fix: Remove 500 and 700; consolidate to 400/600.

In generation-time steering

Reference the design tokens in user-project-overrides.md to prevent writing non-compliant UI in the first place (prevention > detection).

In CI/report gates

Use the scoring model: a page with one Sev-1 finding automatically fails. A page at 65/100 fails. The report must carry the rubric ID for traceability.

Evidence

Findings SHOULD include quantitative evidence from scripts/style-survey.js (computed-style census) or accessibility-tree inspection. Screenshot-only findings are provisional until confirmed by live interaction.


Cross-references

  • user-project-overrides.md - team-specific threshold overrides (font size, weight count, radii count, spacing scale)
  • ux-pattern-registry.md - reference layout patterns for common screen types
  • review-ux-audit.md - review prompt that scores against this rubric
  • review-ux-live.md - live browser-walk protocol using this rubric
  • scripts/style-survey.js - quantitative evidence collection script


inclusion: manual

UX Pattern Registry

Reference patterns for common screen types. Load with /ux-pattern-registry when designing or reviewing UI.

Before implementing any major screen, find the matching pattern below. If no pattern matches, propose a new entry before coding.


Task Detail View

Use when: User needs to read, edit, comment, or inspect a single task/item.

Layout:

  • Large title at top, full width
  • Metadata (status, assignee, dates) secondary - compact row or sidebar
  • Description and comments get primary content space (dominant height)
  • Activity/comments must not be visually minimized

Rules:

  • Section controls adjacent to section headers (leading or beside)
  • Content canvas gets 60%+ of viewport height
  • Comments rendered at body text size (15-16px), not small/muted
  • Subtle selection state - no thick decorative borders

Reference: Asana task detail, Linear issue detail, Notion page


Data Table / List View

Use when: User scans, filters, sorts, and selects from many items.

Layout:

  • Compact density acceptable
  • Column headers aligned with cell content (same layout strategy)
  • Bulk actions near selection indicator
  • Filters above or beside the table, not buried

Rules:

  • Row height consistent - no variable-height rows in scan mode
  • Clickable rows have hover state
  • Header and body use identical grid/flex strategy (no alignment drift)
  • Pagination or infinite scroll - never unbounded lists

Reference: GitHub issues list, Linear board, Airtable grid


Form / Settings Page

Use when: User fills in or modifies structured data.

Layout:

  • Spacious - generous vertical gaps between field groups
  • Labels above inputs (not beside, unless very short forms)
  • Primary action (Save/Submit) at bottom, visually prominent
  • Destructive actions (Delete) separated and de-emphasized

Rules:

  • Field groups have clear section headers
  • Validation errors inline, adjacent to the field
  • No horizontal scrolling - form fits viewport width
  • Tab order follows visual order

Reference: GitHub settings, Stripe dashboard settings


Dashboard / Overview

Use when: User needs a high-level summary with drill-down capability.

Layout:

  • Cards or panels for distinct metric groups
  • Most important metrics largest/topmost
  • Secondary details accessible via click, not shown upfront

Rules:

  • No more than 7±2 top-level items visible without scrolling
  • Each card has a clear label and one primary number/status
  • Drill-down affordance visible (arrow, link, hover state)
  • Empty states for cards with no data

Reference: Vercel dashboard, Datadog overview, GitHub repo home


Modal / Dialog

Use when: User must complete a focused sub-task without losing page context.

Layout:

  • Centered, max-width 600px for forms, 800px for content
  • Title + close button at top
  • Primary action bottom-right, cancel bottom-left
  • Content scrolls if needed, buttons stay fixed

Rules:

  • Focus trapped inside modal
  • Escape closes (unless destructive action in progress)
  • Backdrop click closes (unless form has unsaved changes)
  • No nested modals - use a drawer or navigate instead

Reference: GitHub "New issue" dialog, Linear "Create issue"


Empty State

Use when: A screen or section has no data to display.

Layout:

  • Centered in the content area
  • Icon or illustration (optional, subtle)
  • Clear message: what this area is for + what to do next
  • Primary action button to create/add the first item

Rules:

  • Never show a blank white space with no explanation
  • Message uses plain language, not technical jargon
  • Action button matches the primary creation flow
  • Don't show filters/sort controls when there's nothing to filter

Reference: Notion empty page, Linear empty project



inclusion: auto description: Version numbering, git tagging, and release process

Versioning and Release Process

Version Scheme

Semantic Versioning: MAJOR.MINOR.PATCH

  • MAJOR (1.0.0, 2.0.0): Breaking changes to public APIs, data formats, or user-facing contracts. Users must update their setup.
  • MINOR (0.1.0, 0.2.0): New features, new capabilities. Backward compatible.
  • PATCH (0.1.1, 0.1.2): Bug fixes, documentation updates, performance improvements. No new features.

Pre-1.0 Rules (Beta)

While in beta (0.x.y):

  • Minor version bumps for feature additions
  • Patch bumps for bug fixes
  • Breaking changes are allowed without major bump (beta expectation)
  • Each minor version gets a git tag

When to Tag

TriggerVersion bumpExample
Bug fix that affects usersPATCH0.1.0 -> 0.1.1
Security fixPATCH (immediate)0.1.1 -> 0.1.2
New featureMINOR0.1.2 -> 0.2.0
Breaking change (pre-1.0)MINOR0.2.0 -> 0.3.0
Stable releaseMAJOR0.x.y -> 1.0.0

When NOT to Tag

  • Documentation-only changes (no tag, no version bump)
  • Internal refactors with no user-visible change
  • Test additions
  • CI/build changes
<!-- CUSTOMIZE: List all files that must be updated on version bump -->

Files to Update on Version Bump

The git tag is the authoritative version. docs/changelogs/CHANGELOG.md is the authoritative human-readable record. Every other version reference is a copy that must be kept in sync with them.

Every file that hard-codes the version string must be listed here and bumped on every release. kiro-rails has no build manifest, but its two installers each carry a version constant that gates the "already installed / upgrade" decision, so they ARE version files and must stay in sync with the tag:

install.sh    -> CURRENT_VERSION="0.18.0"
install.ps1   -> $CurrentVersion = "0.18.0"

(These drifted to 0.15.0 while tags reached 0.17.3 precisely because this list did not name them - KRL-13. A version reference not on this list is one that silently never gets bumped.) If you fork kiro-rails into a project WITH a build manifest, add pyproject.toml / package.json here too; if you strip the installers, remove this block rather than pointing the checklist at a file that does not exist.

Verify tags and changelog agree before releasing:

git tag -l "v*" | sort -V | tail -1                        # latest tag
grep -m1 -oE '^## [0-9-]+ - v[0-9.]+' docs/changelogs/CHANGELOG.md   # latest documented

Release Checklist

  1. All tests pass
  2. Lint clean
  3. Update version in all version files listed above (skip if the project has none)
  4. Update docs/changelogs/CHANGELOG.md - move Unreleased items under the new version header with date
  5. Regenerate the Claude bonus layer - the committed .claude/ tree is a generated artifact and MUST be refreshed before tagging: bash scripts/export-to-claude.sh && git add .claude. Verify it is in sync with bash scripts/check-claude-fresh.sh (must print OK).
  6. Commit: chore: release vX.X.X
  7. Tag: git tag -a vX.X.X -m "vX.X.X - brief description"
  8. Push: git push origin main --tags

Tag Format

v0.1.0    (not 0.1.0 - always prefix with v)
v0.2.0
v1.0.0

Git Tag Commands

# Create annotated tag (always use annotated, not lightweight)
git tag -a v0.1.0 -m "v0.1.0 - description"

# Push tag
git push origin v0.1.0

# List tags
git tag -l "v*"

# Delete a tag (if you made a mistake)
git tag -d v0.1.0
git push origin --delete v0.1.0

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.