From b45ae010e9cb6031cc8774b24f5fd9b370180ec0 Mon Sep 17 00:00:00 2001 From: Einar Date: Thu, 10 Sep 2026 12:07:09 +0200 Subject: [PATCH] Adopt the Cratis AI contract MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the synchronized .ai corpus and its generated tool adapters with the Cratis AI subscription contract: - .cratis/PROJECT.md — the canonical project context - .cratis/ai.json — the profile subscription: cratis/documentation plus the applicable cratis/engineering cells - AGENTS.md, CLAUDE.md, and GEMINI.md — minimal bootstraps pointing at the project context, nothing else - removed .ai/, .claude/, the .github Copilot adapters, and the generated .pi adapters; repository-local skills keep living under .agents/ - removed the sync/propagate Copilot-instruction workflows, retired with the synchronization system in Cratis/Workflows Shared skills arrive through the Cratis AI marketplace plugins; general improvements are proposed in Cratis/AI (see .cratis/PROJECT.md). Part of the Cratis/AI#256 corpus retirement. --- .agents/skills | 1 - .ai/README.md | 40 - .ai/agents/backend-developer.md | 131 -- .ai/agents/code-reviewer.md | 174 --- .ai/agents/coordinator.md | 162 -- .ai/agents/frontend-developer.md | 248 --- .ai/agents/orchestrator.md | 195 --- .ai/agents/performance-reviewer.md | 109 -- .ai/agents/planner.md | 140 -- .ai/agents/security-reviewer.md | 118 -- .ai/agents/slice-implementer.md | 59 - .ai/agents/spec-writer.md | 184 --- .ai/hooks/agent-stop.md | 37 - .ai/hooks/pre-commit.md | 47 - .ai/hooks/scripts/validate-ai-setup.sh | 153 -- .ai/prompts/add-business-rule.prompt.md | 83 -- .ai/prompts/add-concept.prompt.md | 92 -- .ai/prompts/add-ef-migration.prompt.md | 67 - .ai/prompts/add-projection.prompt.md | 57 - .ai/prompts/add-reactor.prompt.md | 60 - .ai/prompts/add-reducer.prompt.md | 20 - .ai/prompts/audit-hooks.prompt.md | 15 - .ai/prompts/check-doc-drift.prompt.md | 21 - .ai/prompts/code-review.prompt.md | 8 - .ai/prompts/new-feature.prompt.md | 8 - .ai/prompts/new-vertical-slice.prompt.md | 75 - .ai/prompts/review-pr.prompt.md | 94 -- .ai/prompts/review-skill.prompt.md | 16 - .ai/prompts/scaffold-feature.prompt.md | 91 -- .ai/prompts/ship-changes.prompt.md | 19 - .ai/prompts/verify-ai-setup.prompt.md | 19 - .ai/prompts/write-documentation.prompt.md | 48 - .ai/prompts/write-specs.prompt.md | 71 - .ai/rules/code-quality.csharp.md | 89 -- .ai/rules/code-quality.md | 82 - .ai/rules/code-quality.typescript.md | 86 -- .ai/rules/components.md | 121 -- .ai/rules/concepts.md | 68 - .ai/rules/csharp.md | 212 --- .ai/rules/dialogs.md | 197 --- .../documentation-structure-and-formatting.md | 86 -- .ai/rules/documentation.md | 89 -- .ai/rules/editing-cratis-docs.md | 54 - .ai/rules/efcore.md | 232 --- .ai/rules/efcore.specs.md | 40 - .ai/rules/framework.md | 49 - .ai/rules/frontend-quality.md | 59 - .ai/rules/frontend-testing.md | 126 -- .ai/rules/general.md | 102 -- .ai/rules/git-commits.md | 94 -- .ai/rules/glossary.md | 58 - .ai/rules/kotlin.md | 42 - .ai/rules/local-work-artifacts.md | 23 - .ai/rules/managing-ai-rules.md | 139 -- .ai/rules/orleans.md | 47 - .ai/rules/pull-requests.md | 47 - .ai/rules/react.md | 193 --- .ai/rules/reactors.md | 148 -- .ai/rules/specs.csharp.md | 265 ---- .ai/rules/specs.md | 133 -- .ai/rules/specs.scenarios.csharp.md | 172 --- .ai/rules/specs.typescript.md | 134 -- .ai/rules/storybook.md | 84 -- .ai/rules/terminal-commands.md | 18 - .ai/rules/typescript.md | 208 --- .ai/rules/vertical-slices.md | 177 --- .ai/rules/web-fetching.md | 11 - .ai/rules/writing-correct-examples.md | 35 - .ai/rules/writing-cratis-docs.md | 75 - .ai/skills/add-business-rule/SKILL.md | 138 -- .ai/skills/add-business-rule/evals/evals.json | 27 - .ai/skills/add-concept/SKILL.md | 84 -- .ai/skills/add-cratis-docs-page/SKILL.md | 43 - .ai/skills/add-ef-migration/SKILL.md | 168 --- .ai/skills/add-projection/SKILL.md | 92 -- .ai/skills/add-projection/evals/evals.json | 27 - .../references/CHRONICLE-API.md | 169 --- .ai/skills/add-reactor/SKILL.md | 147 -- .ai/skills/add-reactor/evals/evals.json | 28 - .ai/skills/add-reducer/SKILL.md | 61 - .ai/skills/add-traces/SKILL.md | 199 --- .ai/skills/auth-and-identity/SKILL.md | 174 --- .../references/authentication.md | 129 -- .../references/authorization.md | 159 -- .../references/backend-identity.md | 379 ----- .../auth-and-identity/references/frontend.md | 184 --- .../references/local-development.md | 111 -- .ai/skills/call-command-from-code/SKILL.md | 81 - .ai/skills/cratis-command/SKILL.md | 306 ---- .ai/skills/cratis-command/evals/evals.json | 35 - .../references/command-dialog.md | 138 -- .../references/command-result.md | 81 - .../cratis-command/references/proxy-setup.md | 71 - .../cratis-command/references/validation.md | 104 -- .ai/skills/cratis-csharp-standards/SKILL.md | 79 - .../cratis-csharp-standards/evals/evals.json | 37 - .../references/code-style.md | 187 --- .../references/domain-philosophy.md | 99 -- .../references/exceptions-logging-di.md | 115 -- .ai/skills/cratis-react-page/SKILL.md | 221 --- .ai/skills/cratis-react-page/evals/evals.json | 34 - .../cratis-react-page/references/data-page.md | 103 -- .../references/data-table.md | 62 - .../cratis-react-page/references/dialogs.md | 196 --- .../cratis-react-page/references/mvvm.md | 130 -- .ai/skills/cratis-readmodel/SKILL.md | 249 ---- .ai/skills/cratis-readmodel/evals/evals.json | 33 - .../cratis-readmodel/references/events.md | 91 -- .../references/projections.md | 155 -- .../cratis-readmodel/references/queries.md | 104 -- .../cratis-readmodel/references/reducers.md | 136 -- .ai/skills/cratis-specs-csharp/SKILL.md | 174 --- .../cratis-specs-csharp/evals/evals.json | 37 - .../references/csharp-patterns.md | 166 --- .../references/integration-specs.md | 101 -- .ai/skills/cratis-specs-typescript/SKILL.md | 148 -- .../cratis-specs-typescript/evals/evals.json | 35 - .../references/typescript-patterns.md | 168 --- .ai/skills/cratis-vertical-slice/SKILL.md | 206 --- .../cratis-vertical-slice/evals/evals.json | 34 - .../references/concepts.md | 102 -- .../references/slice-anatomy.md | 255 ---- .../references/slice-types.md | 105 -- .ai/skills/create-event-model/SKILL.md | 80 - .ai/skills/cross-cutting-properties/SKILL.md | 70 - .ai/skills/diagnose-slice/SKILL.md | 42 - .ai/skills/discover-implementations/SKILL.md | 95 -- .ai/skills/edit-cratis-docs/SKILL.md | 50 - .ai/skills/event-modeling/SKILL.md | 63 - .ai/skills/event-type-migrations/SKILL.md | 80 - .ai/skills/multi-tenancy/SKILL.md | 52 - .ai/skills/new-vertical-slice/SKILL.md | 102 -- .../new-vertical-slice/evals/evals.json | 33 - .../new-vertical-slice/references/PATTERNS.md | 351 ----- .ai/skills/observable-query-curl/SKILL.md | 156 -- .ai/skills/qa-cratis-docs/SKILL.md | 51 - .ai/skills/query-paging/SKILL.md | 82 - .ai/skills/review-code/SKILL.md | 69 - .../review-code/references/CHECKLISTS.md | 109 -- .ai/skills/review-performance/SKILL.md | 55 - .ai/skills/review-security/SKILL.md | 57 - .ai/skills/scaffold-feature/SKILL.md | 82 - .ai/skills/ship-changes/SKILL.md | 238 --- .ai/skills/ship-changes/evals/evals.json | 28 - .ai/skills/skill-creator/LICENSE.txt | 202 --- .ai/skills/skill-creator/SKILL.md | 486 ------ .ai/skills/skill-creator/agents/analyzer.md | 274 ---- .ai/skills/skill-creator/agents/comparator.md | 202 --- .ai/skills/skill-creator/agents/grader.md | 223 --- .../skill-creator/assets/eval_review.html | 146 -- .../eval-viewer/generate_review.py | 471 ------ .../skill-creator/eval-viewer/viewer.html | 1325 ----------------- .../skill-creator/references/schemas.md | 430 ------ .ai/skills/skill-creator/scripts/__init__.py | 2 - .../scripts/aggregate_benchmark.py | 401 ----- .../skill-creator/scripts/generate_report.py | 326 ---- .../scripts/improve_description.py | 248 --- .../skill-creator/scripts/package_skill.py | 136 -- .../skill-creator/scripts/quick_validate.py | 103 -- .../scripts/restructure_evals.py | 42 - .ai/skills/skill-creator/scripts/run_eval.py | 310 ---- .ai/skills/skill-creator/scripts/run_loop.py | 332 ----- .ai/skills/skill-creator/scripts/utils.py | 47 - .ai/skills/stepper-command-dialog/SKILL.md | 234 --- .ai/skills/toolbar/SKILL.md | 282 ---- .ai/skills/write-documentation/SKILL.md | 122 -- .ai/skills/write-specs-events/SKILL.md | 207 --- .ai/skills/write-specs-frontend/SKILL.md | 93 -- .ai/skills/write-specs-readmodels/SKILL.md | 216 --- .ai/skills/write-specs/SKILL.md | 85 -- .ai/skills/write-specs/evals/evals.json | 30 - .ai/skills/write-specs/references/EXAMPLES.md | 115 -- .ai/workflows/claude.yml | 31 - .claude/CLAUDE.md | 1 - .claude/agents | 1 - .claude/commands/add-business-rule.md | 1 - .claude/commands/add-concept.md | 1 - .claude/commands/add-ef-migration.md | 1 - .claude/commands/add-projection.md | 1 - .claude/commands/add-reactor.md | 1 - .claude/commands/add-reducer.md | 1 - .claude/commands/audit-hooks.md | 1 - .claude/commands/check-doc-drift.md | 1 - .claude/commands/code-review.md | 1 - .claude/commands/new-feature.md | 1 - .claude/commands/new-vertical-slice.md | 1 - .claude/commands/review-pr.md | 1 - .claude/commands/review-skill.md | 1 - .claude/commands/scaffold-feature.md | 1 - .claude/commands/ship-changes.md | 1 - .claude/commands/verify-ai-setup.md | 1 - .claude/commands/write-documentation.md | 1 - .claude/commands/write-specs.md | 1 - .claude/hooks | 1 - .claude/prompts | 1 - .claude/rules/code-quality.csharp.md | 1 - .claude/rules/code-quality.md | 1 - .claude/rules/code-quality.typescript.md | 1 - .claude/rules/components.md | 1 - .claude/rules/concepts.md | 1 - .claude/rules/csharp.md | 1 - .claude/rules/dialogs.md | 1 - .../documentation-structure-and-formatting.md | 1 - .claude/rules/documentation.md | 1 - .claude/rules/editing-cratis-docs.md | 1 - .claude/rules/efcore.md | 1 - .claude/rules/efcore.specs.md | 1 - .claude/rules/framework.md | 1 - .claude/rules/frontend-quality.md | 1 - .claude/rules/frontend-testing.md | 1 - .claude/rules/git-commits.md | 1 - .claude/rules/glossary.md | 1 - .claude/rules/kotlin.md | 1 - .claude/rules/local-work-artifacts.md | 1 - .claude/rules/managing-ai-rules.md | 1 - .claude/rules/orleans.md | 1 - .claude/rules/pull-requests.md | 1 - .claude/rules/react.md | 1 - .claude/rules/reactors.md | 1 - .claude/rules/specs.csharp.md | 1 - .claude/rules/specs.md | 1 - .claude/rules/specs.scenarios.csharp.md | 1 - .claude/rules/specs.typescript.md | 1 - .claude/rules/storybook.md | 1 - .claude/rules/terminal-commands.md | 1 - .claude/rules/typescript.md | 1 - .claude/rules/vertical-slices.md | 1 - .claude/rules/web-fetching.md | 1 - .claude/rules/writing-correct-examples.md | 1 - .claude/rules/writing-cratis-docs.md | 1 - .claude/skills | 1 - .cratis/PROJECT.md | 31 + .cratis/ai.json | 17 + .github/agents/backend-developer.agent.md | 1 - .github/agents/code-reviewer.agent.md | 1 - .github/agents/coordinator.agent.md | 1 - .github/agents/frontend-developer.agent.md | 1 - .github/agents/orchestrator.agent.md | 1 - .github/agents/performance-reviewer.agent.md | 1 - .github/agents/planner.agent.md | 1 - .github/agents/security-reviewer.agent.md | 1 - .github/agents/slice-implementer.agent.md | 1 - .github/agents/spec-writer.agent.md | 1 - .github/copilot-instructions.md | 1 - .github/hooks | 1 - .../code-quality.csharp.instructions.md | 1 - .../instructions/code-quality.instructions.md | 1 - .../code-quality.typescript.instructions.md | 1 - .../instructions/components.instructions.md | 1 - .github/instructions/concepts.instructions.md | 1 - .github/instructions/csharp.instructions.md | 1 - .github/instructions/dialogs.instructions.md | 1 - ...n-structure-and-formatting.instructions.md | 1 - .../documentation.instructions.md | 1 - .../editing-cratis-docs.instructions.md | 1 - .github/instructions/efcore.instructions.md | 1 - .../instructions/efcore.specs.instructions.md | 1 - .../instructions/framework.instructions.md | 1 - .../frontend-quality.instructions.md | 1 - .../frontend-testing.instructions.md | 1 - .../instructions/git-commits.instructions.md | 1 - .github/instructions/glossary.instructions.md | 1 - .github/instructions/kotlin.instructions.md | 1 - .../local-work-artifacts.instructions.md | 1 - .../managing-ai-rules.instructions.md | 1 - .github/instructions/orleans.instructions.md | 1 - .../pull-requests.instructions.md | 1 - .github/instructions/react.instructions.md | 1 - .github/instructions/reactors.instructions.md | 1 - .../instructions/specs.csharp.instructions.md | 1 - .github/instructions/specs.instructions.md | 1 - .../specs.scenarios.csharp.instructions.md | 1 - .../specs.typescript.instructions.md | 1 - .../instructions/storybook.instructions.md | 1 - .../terminal-commands.instructions.md | 1 - .../instructions/typescript.instructions.md | 1 - .../vertical-slices.instructions.md | 1 - .../instructions/web-fetching.instructions.md | 1 - .../writing-correct-examples.instructions.md | 1 - .../writing-cratis-docs.instructions.md | 1 - .github/prompts | 1 - .github/skills | 1 - .../propagate-copilot-instructions.yml | 26 - .../workflows/sync-copilot-instructions.yml | 16 - AGENTS.md | 7 +- CLAUDE.md | 1 + GEMINI.md | 1 + 287 files changed, 56 insertions(+), 22370 deletions(-) delete mode 120000 .agents/skills delete mode 100644 .ai/README.md delete mode 100644 .ai/agents/backend-developer.md delete mode 100644 .ai/agents/code-reviewer.md delete mode 100644 .ai/agents/coordinator.md delete mode 100644 .ai/agents/frontend-developer.md delete mode 100644 .ai/agents/orchestrator.md delete mode 100644 .ai/agents/performance-reviewer.md delete mode 100644 .ai/agents/planner.md delete mode 100644 .ai/agents/security-reviewer.md delete mode 100644 .ai/agents/slice-implementer.md delete mode 100644 .ai/agents/spec-writer.md delete mode 100644 .ai/hooks/agent-stop.md delete mode 100644 .ai/hooks/pre-commit.md delete mode 100755 .ai/hooks/scripts/validate-ai-setup.sh delete mode 100644 .ai/prompts/add-business-rule.prompt.md delete mode 100644 .ai/prompts/add-concept.prompt.md delete mode 100644 .ai/prompts/add-ef-migration.prompt.md delete mode 100644 .ai/prompts/add-projection.prompt.md delete mode 100644 .ai/prompts/add-reactor.prompt.md delete mode 100644 .ai/prompts/add-reducer.prompt.md delete mode 100644 .ai/prompts/audit-hooks.prompt.md delete mode 100644 .ai/prompts/check-doc-drift.prompt.md delete mode 100644 .ai/prompts/code-review.prompt.md delete mode 100644 .ai/prompts/new-feature.prompt.md delete mode 100644 .ai/prompts/new-vertical-slice.prompt.md delete mode 100644 .ai/prompts/review-pr.prompt.md delete mode 100644 .ai/prompts/review-skill.prompt.md delete mode 100644 .ai/prompts/scaffold-feature.prompt.md delete mode 100644 .ai/prompts/ship-changes.prompt.md delete mode 100644 .ai/prompts/verify-ai-setup.prompt.md delete mode 100644 .ai/prompts/write-documentation.prompt.md delete mode 100644 .ai/prompts/write-specs.prompt.md delete mode 100644 .ai/rules/code-quality.csharp.md delete mode 100644 .ai/rules/code-quality.md delete mode 100644 .ai/rules/code-quality.typescript.md delete mode 100644 .ai/rules/components.md delete mode 100644 .ai/rules/concepts.md delete mode 100644 .ai/rules/csharp.md delete mode 100644 .ai/rules/dialogs.md delete mode 100644 .ai/rules/documentation-structure-and-formatting.md delete mode 100644 .ai/rules/documentation.md delete mode 100644 .ai/rules/editing-cratis-docs.md delete mode 100644 .ai/rules/efcore.md delete mode 100644 .ai/rules/efcore.specs.md delete mode 100644 .ai/rules/framework.md delete mode 100644 .ai/rules/frontend-quality.md delete mode 100644 .ai/rules/frontend-testing.md delete mode 100644 .ai/rules/general.md delete mode 100644 .ai/rules/git-commits.md delete mode 100644 .ai/rules/glossary.md delete mode 100644 .ai/rules/kotlin.md delete mode 100644 .ai/rules/local-work-artifacts.md delete mode 100644 .ai/rules/managing-ai-rules.md delete mode 100644 .ai/rules/orleans.md delete mode 100644 .ai/rules/pull-requests.md delete mode 100644 .ai/rules/react.md delete mode 100644 .ai/rules/reactors.md delete mode 100644 .ai/rules/specs.csharp.md delete mode 100644 .ai/rules/specs.md delete mode 100644 .ai/rules/specs.scenarios.csharp.md delete mode 100644 .ai/rules/specs.typescript.md delete mode 100644 .ai/rules/storybook.md delete mode 100644 .ai/rules/terminal-commands.md delete mode 100644 .ai/rules/typescript.md delete mode 100644 .ai/rules/vertical-slices.md delete mode 100644 .ai/rules/web-fetching.md delete mode 100644 .ai/rules/writing-correct-examples.md delete mode 100644 .ai/rules/writing-cratis-docs.md delete mode 100644 .ai/skills/add-business-rule/SKILL.md delete mode 100644 .ai/skills/add-business-rule/evals/evals.json delete mode 100644 .ai/skills/add-concept/SKILL.md delete mode 100644 .ai/skills/add-cratis-docs-page/SKILL.md delete mode 100644 .ai/skills/add-ef-migration/SKILL.md delete mode 100644 .ai/skills/add-projection/SKILL.md delete mode 100644 .ai/skills/add-projection/evals/evals.json delete mode 100644 .ai/skills/add-projection/references/CHRONICLE-API.md delete mode 100644 .ai/skills/add-reactor/SKILL.md delete mode 100644 .ai/skills/add-reactor/evals/evals.json delete mode 100644 .ai/skills/add-reducer/SKILL.md delete mode 100644 .ai/skills/add-traces/SKILL.md delete mode 100644 .ai/skills/auth-and-identity/SKILL.md delete mode 100644 .ai/skills/auth-and-identity/references/authentication.md delete mode 100644 .ai/skills/auth-and-identity/references/authorization.md delete mode 100644 .ai/skills/auth-and-identity/references/backend-identity.md delete mode 100644 .ai/skills/auth-and-identity/references/frontend.md delete mode 100644 .ai/skills/auth-and-identity/references/local-development.md delete mode 100644 .ai/skills/call-command-from-code/SKILL.md delete mode 100644 .ai/skills/cratis-command/SKILL.md delete mode 100644 .ai/skills/cratis-command/evals/evals.json delete mode 100644 .ai/skills/cratis-command/references/command-dialog.md delete mode 100644 .ai/skills/cratis-command/references/command-result.md delete mode 100644 .ai/skills/cratis-command/references/proxy-setup.md delete mode 100644 .ai/skills/cratis-command/references/validation.md delete mode 100644 .ai/skills/cratis-csharp-standards/SKILL.md delete mode 100644 .ai/skills/cratis-csharp-standards/evals/evals.json delete mode 100644 .ai/skills/cratis-csharp-standards/references/code-style.md delete mode 100644 .ai/skills/cratis-csharp-standards/references/domain-philosophy.md delete mode 100644 .ai/skills/cratis-csharp-standards/references/exceptions-logging-di.md delete mode 100644 .ai/skills/cratis-react-page/SKILL.md delete mode 100644 .ai/skills/cratis-react-page/evals/evals.json delete mode 100644 .ai/skills/cratis-react-page/references/data-page.md delete mode 100644 .ai/skills/cratis-react-page/references/data-table.md delete mode 100644 .ai/skills/cratis-react-page/references/dialogs.md delete mode 100644 .ai/skills/cratis-react-page/references/mvvm.md delete mode 100644 .ai/skills/cratis-readmodel/SKILL.md delete mode 100644 .ai/skills/cratis-readmodel/evals/evals.json delete mode 100644 .ai/skills/cratis-readmodel/references/events.md delete mode 100644 .ai/skills/cratis-readmodel/references/projections.md delete mode 100644 .ai/skills/cratis-readmodel/references/queries.md delete mode 100644 .ai/skills/cratis-readmodel/references/reducers.md delete mode 100644 .ai/skills/cratis-specs-csharp/SKILL.md delete mode 100644 .ai/skills/cratis-specs-csharp/evals/evals.json delete mode 100644 .ai/skills/cratis-specs-csharp/references/csharp-patterns.md delete mode 100644 .ai/skills/cratis-specs-csharp/references/integration-specs.md delete mode 100644 .ai/skills/cratis-specs-typescript/SKILL.md delete mode 100644 .ai/skills/cratis-specs-typescript/evals/evals.json delete mode 100644 .ai/skills/cratis-specs-typescript/references/typescript-patterns.md delete mode 100644 .ai/skills/cratis-vertical-slice/SKILL.md delete mode 100644 .ai/skills/cratis-vertical-slice/evals/evals.json delete mode 100644 .ai/skills/cratis-vertical-slice/references/concepts.md delete mode 100644 .ai/skills/cratis-vertical-slice/references/slice-anatomy.md delete mode 100644 .ai/skills/cratis-vertical-slice/references/slice-types.md delete mode 100644 .ai/skills/create-event-model/SKILL.md delete mode 100644 .ai/skills/cross-cutting-properties/SKILL.md delete mode 100644 .ai/skills/diagnose-slice/SKILL.md delete mode 100644 .ai/skills/discover-implementations/SKILL.md delete mode 100644 .ai/skills/edit-cratis-docs/SKILL.md delete mode 100644 .ai/skills/event-modeling/SKILL.md delete mode 100644 .ai/skills/event-type-migrations/SKILL.md delete mode 100644 .ai/skills/multi-tenancy/SKILL.md delete mode 100644 .ai/skills/new-vertical-slice/SKILL.md delete mode 100644 .ai/skills/new-vertical-slice/evals/evals.json delete mode 100644 .ai/skills/new-vertical-slice/references/PATTERNS.md delete mode 100644 .ai/skills/observable-query-curl/SKILL.md delete mode 100644 .ai/skills/qa-cratis-docs/SKILL.md delete mode 100644 .ai/skills/query-paging/SKILL.md delete mode 100644 .ai/skills/review-code/SKILL.md delete mode 100644 .ai/skills/review-code/references/CHECKLISTS.md delete mode 100644 .ai/skills/review-performance/SKILL.md delete mode 100644 .ai/skills/review-security/SKILL.md delete mode 100644 .ai/skills/scaffold-feature/SKILL.md delete mode 100644 .ai/skills/ship-changes/SKILL.md delete mode 100644 .ai/skills/ship-changes/evals/evals.json delete mode 100644 .ai/skills/skill-creator/LICENSE.txt delete mode 100644 .ai/skills/skill-creator/SKILL.md delete mode 100644 .ai/skills/skill-creator/agents/analyzer.md delete mode 100644 .ai/skills/skill-creator/agents/comparator.md delete mode 100644 .ai/skills/skill-creator/agents/grader.md delete mode 100644 .ai/skills/skill-creator/assets/eval_review.html delete mode 100644 .ai/skills/skill-creator/eval-viewer/generate_review.py delete mode 100644 .ai/skills/skill-creator/eval-viewer/viewer.html delete mode 100644 .ai/skills/skill-creator/references/schemas.md delete mode 100644 .ai/skills/skill-creator/scripts/__init__.py delete mode 100644 .ai/skills/skill-creator/scripts/aggregate_benchmark.py delete mode 100644 .ai/skills/skill-creator/scripts/generate_report.py delete mode 100644 .ai/skills/skill-creator/scripts/improve_description.py delete mode 100644 .ai/skills/skill-creator/scripts/package_skill.py delete mode 100644 .ai/skills/skill-creator/scripts/quick_validate.py delete mode 100644 .ai/skills/skill-creator/scripts/restructure_evals.py delete mode 100644 .ai/skills/skill-creator/scripts/run_eval.py delete mode 100644 .ai/skills/skill-creator/scripts/run_loop.py delete mode 100644 .ai/skills/skill-creator/scripts/utils.py delete mode 100644 .ai/skills/stepper-command-dialog/SKILL.md delete mode 100644 .ai/skills/toolbar/SKILL.md delete mode 100644 .ai/skills/write-documentation/SKILL.md delete mode 100644 .ai/skills/write-specs-events/SKILL.md delete mode 100644 .ai/skills/write-specs-frontend/SKILL.md delete mode 100644 .ai/skills/write-specs-readmodels/SKILL.md delete mode 100644 .ai/skills/write-specs/SKILL.md delete mode 100644 .ai/skills/write-specs/evals/evals.json delete mode 100644 .ai/skills/write-specs/references/EXAMPLES.md delete mode 100644 .ai/workflows/claude.yml delete mode 120000 .claude/CLAUDE.md delete mode 120000 .claude/agents delete mode 120000 .claude/commands/add-business-rule.md delete mode 120000 .claude/commands/add-concept.md delete mode 120000 .claude/commands/add-ef-migration.md delete mode 120000 .claude/commands/add-projection.md delete mode 120000 .claude/commands/add-reactor.md delete mode 120000 .claude/commands/add-reducer.md delete mode 120000 .claude/commands/audit-hooks.md delete mode 120000 .claude/commands/check-doc-drift.md delete mode 120000 .claude/commands/code-review.md delete mode 120000 .claude/commands/new-feature.md delete mode 120000 .claude/commands/new-vertical-slice.md delete mode 120000 .claude/commands/review-pr.md delete mode 120000 .claude/commands/review-skill.md delete mode 120000 .claude/commands/scaffold-feature.md delete mode 120000 .claude/commands/ship-changes.md delete mode 120000 .claude/commands/verify-ai-setup.md delete mode 120000 .claude/commands/write-documentation.md delete mode 120000 .claude/commands/write-specs.md delete mode 120000 .claude/hooks delete mode 120000 .claude/prompts delete mode 120000 .claude/rules/code-quality.csharp.md delete mode 120000 .claude/rules/code-quality.md delete mode 120000 .claude/rules/code-quality.typescript.md delete mode 120000 .claude/rules/components.md delete mode 120000 .claude/rules/concepts.md delete mode 120000 .claude/rules/csharp.md delete mode 120000 .claude/rules/dialogs.md delete mode 120000 .claude/rules/documentation-structure-and-formatting.md delete mode 120000 .claude/rules/documentation.md delete mode 120000 .claude/rules/editing-cratis-docs.md delete mode 120000 .claude/rules/efcore.md delete mode 120000 .claude/rules/efcore.specs.md delete mode 120000 .claude/rules/framework.md delete mode 120000 .claude/rules/frontend-quality.md delete mode 120000 .claude/rules/frontend-testing.md delete mode 120000 .claude/rules/git-commits.md delete mode 120000 .claude/rules/glossary.md delete mode 120000 .claude/rules/kotlin.md delete mode 120000 .claude/rules/local-work-artifacts.md delete mode 120000 .claude/rules/managing-ai-rules.md delete mode 120000 .claude/rules/orleans.md delete mode 120000 .claude/rules/pull-requests.md delete mode 120000 .claude/rules/react.md delete mode 120000 .claude/rules/reactors.md delete mode 120000 .claude/rules/specs.csharp.md delete mode 120000 .claude/rules/specs.md delete mode 120000 .claude/rules/specs.scenarios.csharp.md delete mode 120000 .claude/rules/specs.typescript.md delete mode 120000 .claude/rules/storybook.md delete mode 120000 .claude/rules/terminal-commands.md delete mode 120000 .claude/rules/typescript.md delete mode 120000 .claude/rules/vertical-slices.md delete mode 120000 .claude/rules/web-fetching.md delete mode 120000 .claude/rules/writing-correct-examples.md delete mode 120000 .claude/rules/writing-cratis-docs.md delete mode 120000 .claude/skills create mode 100644 .cratis/PROJECT.md create mode 100644 .cratis/ai.json delete mode 120000 .github/agents/backend-developer.agent.md delete mode 120000 .github/agents/code-reviewer.agent.md delete mode 120000 .github/agents/coordinator.agent.md delete mode 120000 .github/agents/frontend-developer.agent.md delete mode 120000 .github/agents/orchestrator.agent.md delete mode 120000 .github/agents/performance-reviewer.agent.md delete mode 120000 .github/agents/planner.agent.md delete mode 120000 .github/agents/security-reviewer.agent.md delete mode 120000 .github/agents/slice-implementer.agent.md delete mode 120000 .github/agents/spec-writer.agent.md delete mode 100644 .github/copilot-instructions.md delete mode 120000 .github/hooks delete mode 100644 .github/instructions/code-quality.csharp.instructions.md delete mode 100644 .github/instructions/code-quality.instructions.md delete mode 100644 .github/instructions/code-quality.typescript.instructions.md delete mode 100644 .github/instructions/components.instructions.md delete mode 100644 .github/instructions/concepts.instructions.md delete mode 100644 .github/instructions/csharp.instructions.md delete mode 100644 .github/instructions/dialogs.instructions.md delete mode 100644 .github/instructions/documentation-structure-and-formatting.instructions.md delete mode 100644 .github/instructions/documentation.instructions.md delete mode 100644 .github/instructions/editing-cratis-docs.instructions.md delete mode 100644 .github/instructions/efcore.instructions.md delete mode 100644 .github/instructions/efcore.specs.instructions.md delete mode 100644 .github/instructions/framework.instructions.md delete mode 100644 .github/instructions/frontend-quality.instructions.md delete mode 100644 .github/instructions/frontend-testing.instructions.md delete mode 100644 .github/instructions/git-commits.instructions.md delete mode 100644 .github/instructions/glossary.instructions.md delete mode 100644 .github/instructions/kotlin.instructions.md delete mode 120000 .github/instructions/local-work-artifacts.instructions.md delete mode 100644 .github/instructions/managing-ai-rules.instructions.md delete mode 100644 .github/instructions/orleans.instructions.md delete mode 100644 .github/instructions/pull-requests.instructions.md delete mode 100644 .github/instructions/react.instructions.md delete mode 100644 .github/instructions/reactors.instructions.md delete mode 100644 .github/instructions/specs.csharp.instructions.md delete mode 100644 .github/instructions/specs.instructions.md delete mode 100644 .github/instructions/specs.scenarios.csharp.instructions.md delete mode 100644 .github/instructions/specs.typescript.instructions.md delete mode 100644 .github/instructions/storybook.instructions.md delete mode 100644 .github/instructions/terminal-commands.instructions.md delete mode 100644 .github/instructions/typescript.instructions.md delete mode 100644 .github/instructions/vertical-slices.instructions.md delete mode 100644 .github/instructions/web-fetching.instructions.md delete mode 100644 .github/instructions/writing-correct-examples.instructions.md delete mode 100644 .github/instructions/writing-cratis-docs.instructions.md delete mode 120000 .github/prompts delete mode 120000 .github/skills delete mode 100644 .github/workflows/propagate-copilot-instructions.yml delete mode 100644 .github/workflows/sync-copilot-instructions.yml mode change 120000 => 100644 AGENTS.md create mode 100644 CLAUDE.md create mode 100644 GEMINI.md diff --git a/.agents/skills b/.agents/skills deleted file mode 120000 index 6838a11..0000000 --- a/.agents/skills +++ /dev/null @@ -1 +0,0 @@ -../.ai/skills \ No newline at end of file diff --git a/.ai/README.md b/.ai/README.md deleted file mode 100644 index 8887738..0000000 --- a/.ai/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# Shared AI Assistant Configuration - -This folder maintains legacy repository-local AI assistant artifacts; it is not a shared distribution package or propagation hub. - -## Distribution and local adapters - -Cross-repository broadcast, all-to-all propagation, and reverse synchronization -are retired. Do not run legacy propagation or turn a consuming repository into a -hub. Shared public-safe behavior is authored and reviewed in `Cratis/AI`, generated -into `Cratis/AI.Distribution`, and consumed only at an immutable reviewed version -after release gates pass. Propose sanitized reusable improvements upstream for -review; never reverse-sync private trees or local facts. - -These legacy repository-local rules remain locally maintained during canary; -this is not permission to patch generated immutable distribution bytes or copy -whole AI trees. Preserve private/project overlays, local skills, and minimal -host bootstraps. Keep legacy adapters and actual workflows in place until an -approved replacement passes canary and reviewed retirement gates. Update shared -packages via approved exact-version pins; roll back by version. - - -## Structure - -- `rules/` contains shared instruction files. -- `prompts/` contains reusable prompt templates. -- `agents/` contains reusable agent definitions. - -## Tool integration - -- GitHub Copilot files under `.github/` are symlinks to files in `.ai/`. -- Claude Code files under `.claude/` are symlinks to files in `.ai/`. - -## Scoped rule frontmatter - -Scoped rules include both: - -- `applyTo` for GitHub Copilot instruction matching. -- `paths` for Claude Code rule matching. - -When adding or changing a shared rule, update the file in `.ai/rules/` only. See `rules/managing-ai-rules.md` for the full guide on adding, updating, and renaming rules. diff --git a/.ai/agents/backend-developer.md b/.ai/agents/backend-developer.md deleted file mode 100644 index 7645b4a..0000000 --- a/.ai/agents/backend-developer.md +++ /dev/null @@ -1,131 +0,0 @@ ---- -name: Backend Developer -description: > - Specialist for C# backend code within a vertical slice. - Creates the single slice file containing all backend artifacts: - commands, events, validators, constraints, read models, projections, - and reactors — all in strict compliance with the vertical slice architecture. -model: claude-sonnet-4-5 -tools: - - githubRepo - - codeSearch - - usages - - rename - - terminalLastCommand ---- - -# Backend Developer - -## Scope before checklists - -Identify the repository profile and changed lane before selecting rules or running a checklist. Read the repository's `AGENTS.md` and applicable universal rules in `.ai/rules/`. For framework contributions, load `.ai/rules/framework.md` and relevant universal rules only; skip application architecture, vertical-slice, scenario-helper, and consuming-frontend checklists. Application examples below apply only to applications with the corresponding capabilities, not to every Cratis library. - -Scope verification to affected projects/packages and behavior. Documentation-only work uses documentation checks; reviews inspect evidence without building the whole repository. Do not run a full backend/frontend matrix merely because commands appear below. Specs are required for all applicable behavior, including State View, Automation, and Translation, not only state changes. Report skipped or unavailable checks honestly. - -You are the **Backend Developer** for Cratis-based projects. -Your responsibility is to implement the **C# backend code** for a vertical slice. - -After selecting the profile and lane, read the applicable entries only: -- `.ai/rules/vertical-slices.md` -- `.ai/rules/csharp.md` -- `.ai/rules/concepts.md` -- `.ai/rules/efcore.md` -- `.ai/rules/general.md` - ---- - -## Inputs you expect - -- Feature name and slice name -- Slice type (`State Change`, `State View`, `Automation`, `Translation`) -- Domain requirements (what the slice should do) -- Any existing events from other slices this slice depends on -- The namespace root (read from `global.json` or existing source files, e.g. `Studio`, `Library`) - ---- - -## Process - -1. **Determine the namespace root** by reading an existing source file in the project to identify the namespace convention (e.g. `Studio`, `Library`, `MyApp`). -2. **Read existing slices** in the same feature folder to understand naming conventions, existing concepts, and events you may need to reference. -3. **Create a single `.cs` file** at `////.cs`. -4. **Validate** with the affected project's build command, scoped to the changed lane. -5. Fix all compiler errors and warnings before handing back. - ---- - -## File structure rules (mandatory) - -- **One file per slice** — all artifacts in `.cs`. -- File header: - ```csharp - // Copyright (c) Cratis. All rights reserved. - // Licensed under the MIT license. See LICENSE file in the project root for full license information. - ``` -- Namespace: `..` (no `.Features.` in the namespace). -- Order of declarations in the file: - 1. Concepts (if slice-specific) - 2. Commands (with `Handle()` inline) - 3. Validators - 4. Business rules - 5. Constraints - 6. Events - 7. Read models + query methods - 8. Projections - 9. Reactors - ---- - -## Commands — critical rules - -- Record decorated with `[Command]` from `Cratis.Arc.Commands.ModelBound`. -- **`Handle()` defined directly on the record** — no separate handler class. -- Return from `Handle()`: single event, `IEnumerable`, tuple `(event, result)`, or `Result<,>`. -- Event source resolution: `[Key]` parameter → `EventSourceId` typed parameter → `ICanProvideEventSourceId`. - -```csharp -[Command] -public record RegisterProject(ProjectName Name) -{ - public (ProjectRegistered, ProjectId) Handle() - { - var projectId = ProjectId.New(); - return (new ProjectRegistered(Name), projectId); - } -} -``` - ---- - -## Events — critical rules - -- Record decorated with `[EventType]` from `Cratis.Events`. -- **`[EventType]` has NO arguments** — the type name is the identifier. - -```csharp -[EventType] -public record ProjectRegistered(ProjectName Name); -``` - ---- - -## Read models & projections — critical rules - -- Record decorated with `[ReadModel]` from `Cratis.Arc.Queries.ModelBound`. -- Query methods are **static** methods on the record. -- Always call `.AutoMap()` before any `.From<>()`. -- Projections join **events**, never read models. - ---- - -## Completion checklist - -Before handing back to the planner: - -- [ ] `dotnet build` succeeds with zero errors and warnings -- [ ] All artifacts are in a single `.cs` file -- [ ] Namespace follows `..` (no `.Features.`) -- [ ] File header is present -- [ ] No separate handler classes were created -- [ ] `[EventType]` has no arguments -- [ ] `.AutoMap()` is used before `.From<>()` in all projections diff --git a/.ai/agents/code-reviewer.md b/.ai/agents/code-reviewer.md deleted file mode 100644 index 0375a7b..0000000 --- a/.ai/agents/code-reviewer.md +++ /dev/null @@ -1,174 +0,0 @@ ---- -name: Code Reviewer -description: > - Quality gate agent for Cratis-based projects. Reviews code against all - project instruction files, checking architecture conformance, C# and - TypeScript conventions, and vertical slice correctness before merge. -model: claude-sonnet-4-5 -tools: - - githubRepo - - codeSearch - - usages - - rename - - terminalLastCommand ---- - -# Code Reviewer - -## Scope before checklists - -Identify the repository profile and changed lane before selecting rules or running a checklist. Read the repository's `AGENTS.md` and applicable universal rules in `.ai/rules/`. For framework contributions, load `.ai/rules/framework.md` and relevant universal rules only; skip application architecture, vertical-slice, scenario-helper, and consuming-frontend checklists. Application examples below apply only to applications with the corresponding capabilities, not to every Cratis library. - -Scope verification to affected projects/packages and behavior. Documentation-only work uses documentation checks; reviews inspect evidence without building the whole repository. Do not run a full backend/frontend matrix merely because commands appear below. Specs are required for all applicable behavior, including State View, Automation, and Translation, not only state changes. Report skipped or unavailable checks honestly. - -This is a read-only review role: propose corrections and refactors in the report, never perform edits or renames. Use shell access only for non-mutating inspection; ask the parent for checks that would change files or runtime state. - -You are the **Code Reviewer** for Cratis-based projects. -Your responsibility is to review all changed files and ensure they meet project standards before merge. - -Select only diff-relevant, profile-applicable entries: -- `.ai/rules/general.md` -- `.ai/rules/vertical-slices.md` -- `.ai/rules/csharp.md` -- `.ai/rules/specs.csharp.md` -- `.ai/rules/specs.typescript.md` -- `.ai/rules/typescript.md` -- `.ai/rules/components.md` -- `.ai/rules/dialogs.md` -- `.ai/rules/concepts.md` -- `.ai/rules/efcore.specs.md` - ---- - -## Review approach - -Review every changed file. For each issue found: -- State the **file and line number** -- Quote the **problematic code** -- Explain **why it violates the standard** -- Provide the **corrected code** - -When checking unused code, references, or naming, use semantic navigation if the host actually provides it. Otherwise search the changed files and bounded caller/dependency paths, citing evidence and search limits. Report proposed refactors; never run `rename` or modify source during review. - ---- - -## C# Architecture checklist - -- [ ] Each slice lives in its own file under `////.cs` -- [ ] Each artifact type has a single responsibility (commands return events, reactors react, projections project) -- [ ] No shared state between commands -- [ ] No service locator (`IServiceProvider` not injected) -- [ ] No explicit singleton registration when `[Singleton]` attribute suffices -- [ ] Logging is in a separate `*Logging.cs` partial file with `[LoggerMessage]` - -## C# Commands checklist - -- [ ] `record` type, not `class` -- [ ] No properties with setters (immutable) -- [ ] `Handle()` method is the single entry point -- [ ] `Handle()` **returns** the event(s) — never calls `IEventLog` directly -- [ ] Namespace matches folder path: `..` - -## C# Read Models & Projections checklist - -- [ ] Read model is a `record` type with all required props -- [ ] Preferred: projection uses model-bound attributes (`[FromEvent]`, `[Key]`, etc.) directly on the read model — no separate projection class needed -- [ ] If using fluent `IProjectionFor`: `.AutoMap()` MUST appear before any `.From<>()` call -- [ ] Projection does NOT join on the read model — joins are on Chronicle events only -- [ ] No `ToList()`, `ToArray()`, or mutation of public-API collection returns - -## C# Concepts checklist - -- [ ] Strongly typed IDs use `ConceptAs` pattern (see `concepts.instructions.md`) -- [ ] No raw `Guid`, `string`, etc. used where a concept should wrap it -- [ ] `new SomeId(someValue)` implicit-conversion syntax used — not explicit cast - -## C# Code Style checklist - -- [ ] File-scoped namespaces -- [ ] No unused `using` directives -- [ ] `is null` / `is not null` (never `== null` / `!= null`) -- [ ] `var` preferred over explicit type declarations -- [ ] No postfixes: `Async`, `Impl`, `Service` on class names -- [ ] No regions -- [ ] Copyright header present on every file -- [ ] All public types, methods, and properties have multiline XML doc comments -- [ ] `` tags are always multiline — never `/// Text` on one line -- [ ] Methods with parameters have `` for each parameter -- [ ] Non-void methods have `` documentation -- [ ] Custom exception types only (no `InvalidOperationException`, `ArgumentException`, etc.) -- [ ] All custom exception XML docs start with "The exception that is thrown when …" - ---- - -## TypeScript Architecture checklist - -- [ ] Components are in the correct slice folder (not in a global `components/` folder) -- [ ] No `index.ts` barrel files created just to re-export a single component -- [ ] No technical folder structure (`hooks/`, `utils/`, `types/`) — feature/concept folders used - -## TypeScript Type Safety checklist - -- [ ] No `any` type — `unknown` used with type guards where needed -- [ ] No `(x as any)` casts — `value as unknown as TargetType` used instead -- [ ] React synthetic events and DOM events not confused -- [ ] Generic defaults use `unknown` not `any` (e.g. ``) - -## TypeScript Styling checklist - -- [ ] No hard-coded hex/rgb values — PrimeReact CSS variables used -- [ ] CSS co-located with component (`.css` file in same folder) -- [ ] No `!important` unless absolutely required and justified with a comment - -## TypeScript Code Style checklist - -- [ ] `const` over `let`, `let` over `var` -- [ ] No abbreviations: `event` not `e`, `index` not `idx`, `previous` not `prev` -- [ ] No `async` functions that don't `await` anything -- [ ] No unused imports -- [ ] String enums for all enumerations (not numeric) -- [ ] Copyright header on every file - -## Component checklist - -- [ ] README.md exists for complex component folders -- [ ] `CommandDialog` from `@cratis/components/CommandDialog` used for command-based dialogs -- [ ] `Dialog` from `@cratis/components/Dialogs` used for data-only dialogs -- [ ] Never imports `Dialog` directly from `primereact/dialog` -- [ ] No monolithic components — decomposed into smaller, focused sub-components - ---- - -## Specs checklist - -- [ ] Every applicable behavior has specs, including queries, projections, reactors, and state-change commands -- [ ] Happy path covered -- [ ] All validation rules covered -- [ ] All constraint violations covered -- [ ] Bug fixes cover the fix's perimeter — failure, async, boundary, and recovery paths — not just the reported scenario -- [ ] Each regression spec is proven to fail against the pre-fix code (not assumed) -- [ ] No specs for simple property getters or constructor pass-throughs -- [ ] Chai fluent interface used in TypeScript specs (not `expect()`) - ---- - -## Output format - -Start with a **summary**: -> **Review result: ✅ Approved / ⚠️ Approved with comments / ❌ Changes requested** - -Then list issues grouped by file: - -``` -### - -**[BLOCKING]** … or **[SUGGESTION]** … -> Line N: `problematic code` -> Because: explanation -> Fix: -> ``` -> corrected code -> ``` -``` - -End with a checklist of passed / failed items so the developer knows what was verified. diff --git a/.ai/agents/coordinator.md b/.ai/agents/coordinator.md deleted file mode 100644 index c61a6b1..0000000 --- a/.ai/agents/coordinator.md +++ /dev/null @@ -1,162 +0,0 @@ ---- -name: Coordinator -description: > - General-purpose coordinator agent for Cratis-based projects. - Receives a high-level goal, breaks it into parallelisable tasks, - assigns each task to the right specialist agent, tracks progress, - and enforces quality gates before declaring the work done. - Use this agent when a request spans multiple concerns (backend + frontend, - multiple slices, mixed C#/TypeScript work, or requires both implementation - and review). -model: claude-sonnet-4-5 -tools: - - githubRepo - - codeSearch - - usages - - terminalLastCommand ---- - -# Coordinator - -## Scope before checklists - -Identify the repository profile and changed lane before selecting rules or running a checklist. Read the repository's `AGENTS.md` and applicable universal rules in `.ai/rules/`. For framework contributions, load `.ai/rules/framework.md` and relevant universal rules only; skip application architecture, vertical-slice, scenario-helper, and consuming-frontend checklists. Application examples below apply only to applications with the corresponding capabilities, not to every Cratis library. - -Scope verification to affected projects/packages and behavior. Documentation-only work uses documentation checks; reviews inspect evidence without building the whole repository. Do not run a full backend/frontend matrix merely because commands appear below. Specs are required for all applicable behavior, including State View, Automation, and Translation, not only state changes. Report skipped or unavailable checks honestly. - -## Proportional execution - -For ordinary work, return a short plan for one implementer (the parent can implement directly); do not introduce orchestrator → coordinator → planner hierarchies. Use management hierarchies only when the user explicitly requests a large scope with independently owned workstreams. A backend/frontend split or a documentation/review step alone is not justification. - -The team tables and multi-phase templates below are optional planning references for that explicitly requested scope, not automatic delegation requirements. When the host provides no approved delegation capability, return assignments, dependencies, and scoped verification commands to the parent for execution; never simulate delegation or claim planned gates passed. Keep local work records only in `.ai-work/`. - -You are the **Coordinator** for Cratis-based projects. -You do NOT write code yourself — return a scoped plan to the parent; delegation is conditional on the proportional execution policy above. - -After selecting the profile and lane, read the applicable entries only: -- `.ai/rules/general.md` -- `.ai/rules/vertical-slices.md` - ---- - -## Available specialist agents - -| Agent | Handles | -|---|---| -| `backend-developer` | C# slice files — commands, events, validators, constraints, projections, reactors | -| `frontend-developer` | React/TypeScript components, composition pages, routing | -| `spec-writer` | Integration specs (C#) and unit specs (TypeScript) | -| `code-reviewer` | Architecture conformance, C# and TypeScript standards, review checklist | -| `security-reviewer` | Security vulnerabilities, injection, auth/authz, data exposure | -| `performance-reviewer` | Chronicle projections, MongoDB query patterns, .NET allocations, React render overhead | - -For ordinary vertical-slice work, recommend one `slice-implementer` when available, or the parent directly. Add a separate planner only for explicitly requested independent large-scope planning. - ---- - -## Decomposition process - -When you receive a goal: - -1. **Classify the work** — is this a vertical slice implementation, a review, a refactor, a documentation task, or a mix? -2. **Identify components** — list all backend, frontend, spec, and review tasks required. -3. **Identify dependencies** — which tasks block which? (e.g. backend must finish before frontend). -4. **Group into phases** — tasks with no mutual dependencies go in the same phase and can run in parallel. -5. **Assign agents** — pick the right specialist for each task. -6. **Output a plan** — always as a markdown checklist with agent assignments. - ---- - -## Parallelisation rules - -- Tasks in the **same phase** have no mutual dependencies and can be delegated in parallel. -- **Backend before frontend** — TypeScript proxies are generated by `dotnet build`; frontend cannot start until backend is compiled. -- **Specs after backend** — integration specs depend on the slice file existing and compiling. -- **Build is a synchronisation point** — `dotnet build` must succeed before any frontend or spec work begins. -- **Quality gates are last** — code review and security review run after all implementation is complete. -- **Independent features** (no shared events) can have their backends worked on in parallel. - ---- - -## Plan template - -```markdown -## Coordinator Plan: - -### Phase 1 — [can run in parallel] -- [ ] [] -- [ ] [] - -### Phase 2 — (depends on Phase 1) -- [ ] [] - -### Phase 3 — Build -- [ ] Run `dotnet build` — must succeed before any Phase 4 work - -### Phase 4 — [can run in parallel] -- [ ] [] - -### Phase 5 — Quality Gates -- [ ] [code-reviewer] Review all changed files -- [ ] [security-reviewer] Security review of all changed files -``` - ---- - -## Delegation instructions - -When handing off to a specialist agent: - -1. State **exactly which files** need to be created or modified. -2. Provide **all context** the agent needs — feature name, slice name, slice type, existing events, namespace root. -3. State **acceptance criteria** — what "done" looks like for this task. -4. Tell the specialist **which agent to hand back to** when finished. -5. Quote the **relevant instruction file** section that governs the work. - ---- - -## Quality gate criteria - -For implementation, the applicable changed-lane gates must pass. Mark unrelated entries not applicable; this list is not a full-repository command mandate: - -- [ ] `dotnet build` — zero errors, zero warnings -- [ ] `dotnet test` — all specs pass -- [ ] `yarn lint` — zero errors (if frontend present) -- [ ] `npx tsc -b` — zero TypeScript errors (if frontend present) -- [ ] Public-facing changes (clients, SDKs, public APIs) include associated documentation updates -- [ ] `Documentation/verify-markdown.sh` passes when documentation is added or changed -- [ ] `code-reviewer` finds no blocking issues -- [ ] `security-reviewer` finds no vulnerabilities -- [ ] PR description follows the pull request template - ---- - -## When to delegate to the planner instead - -A full backend-to-frontend slice normally needs one implementer, not another manager. Use a separate planner only for explicitly requested large independent scope; otherwise return the short slice sequence to the parent. - ---- - -## Output format - -Always output a plan before starting any delegation: - -```markdown -## Coordinator Plan: - -### Phase 1 — Backend [parallel] -- [ ] [backend-developer] - -### Phase 2 — Build -- [ ] `dotnet build` - -### Phase 3 — Frontend + Specs [parallel] -- [ ] [frontend-developer] -- [ ] [spec-writer] - -### Phase 4 — Quality Gates -- [ ] [code-reviewer] Review all changed files -- [ ] [security-reviewer] Security review -``` - -If the explicit large-scope delegation contract applies, hand off in dependency order; otherwise return the plan to the parent. diff --git a/.ai/agents/frontend-developer.md b/.ai/agents/frontend-developer.md deleted file mode 100644 index 9f86a42..0000000 --- a/.ai/agents/frontend-developer.md +++ /dev/null @@ -1,248 +0,0 @@ ---- -name: Frontend Developer -description: > - Specialist for TypeScript/React frontend code within a vertical slice. - Implements React components that consume auto-generated command and query - proxies, following the project's component and styling conventions. -model: claude-sonnet-4-5 -tools: - - githubRepo - - codeSearch - - usages - - rename - - terminalLastCommand ---- - -# Frontend Developer - -## Scope before checklists - -Identify the repository profile and changed lane before selecting rules or running a checklist. Read the repository's `AGENTS.md` and applicable universal rules in `.ai/rules/`. For framework contributions, load `.ai/rules/framework.md` and relevant universal rules only; skip application architecture, vertical-slice, scenario-helper, and consuming-frontend checklists. Application examples below apply only to applications with the corresponding capabilities, not to every Cratis library. - -Scope verification to affected projects/packages and behavior. Documentation-only work uses documentation checks; reviews inspect evidence without building the whole repository. Do not run a full backend/frontend matrix merely because commands appear below. Specs are required for all applicable behavior, including State View, Automation, and Translation, not only state changes. Report skipped or unavailable checks honestly. - -You are the **Frontend Developer** for Cratis-based projects. -Your responsibility is to implement the **React/TypeScript frontend** for a vertical slice. - -After selecting the profile and lane, read the applicable entries only: -- `.ai/rules/vertical-slices.md` -- `.ai/rules/components.md` -- `.ai/rules/dialogs.md` -- `.ai/rules/typescript.md` -- `.ai/rules/general.md` (TypeScript type safety section) - ---- - -## Inputs you expect - -- Feature name and slice name -- Slice type (`State Change`, `State View`, `Automation`, `Translation`) -- The auto-generated proxy file(s) produced by `dotnet build` (TypeScript commands/queries) -- Whether this slice introduces a new page (requires routing update) - ---- - -## Pre-conditions - -The `dotnet build` step MUST have completed before you start. -Confirm that the TypeScript proxies exist in the slice folder before writing any frontend code. - ---- - -## Process - -1. **Read the existing feature composition page** (`///.tsx`) to understand the current layout and imports. -2. **Create component file(s)** in the slice folder (`////`). -3. **Update the composition page** to import and use the new component. -4. **Update routing** if the slice introduces a new page. -5. **Validate** with `yarn lint` and `npx tsc -b`. - ---- - -## Component rules (mandatory) - -- Place `.tsx` files in the **same folder** as the corresponding `.cs` file. -- Do NOT prefix the file name with the feature or slice name (folder provides context). -- Each component has its own `.css` file for static styles. -- Use PrimeReact CSS variables for all colours, backgrounds, and borders — never hard-code hex values. -- Use `const` over `let`. -- Use full descriptive names (never abbreviations like `e`, `idx`, `prev`). - ---- - -## Command usage pattern - -```tsx -const [registerProject] = RegisterProject.use(); - -const handleSubmit = async () => { - registerProject.name = name; - const result = await registerProject.execute(); - if (result.isSuccess) { - closeDialog(DialogResult.Ok); - } -}; -``` - ---- - -## Query usage pattern (with paging) - -```tsx -const pageSize = 10; - -export const Listing = () => { - const [allProjectsResult, , setPage] = AllProjects.useWithPaging(pageSize); - - return ( - setPage(event.page ?? 0)} - scrollable scrollHeight="flex" - emptyMessage="No items found."> - - - ); -}; -``` - ---- - -## Dialog patterns - -Use this whenever the dialog executes a Cratis Arc command on confirm. The component handles command instantiation, execution, and the confirm/cancel buttons automatically. - -### Command-based dialog — use `CommandDialog` from `@cratis/components/CommandDialog` - -```tsx -import { DialogProps, DialogResult } from '@cratis/arc.react/dialogs'; -import { CommandDialog } from '@cratis/components/CommandDialog'; -import { InputTextField } from '@cratis/components/CommandForm'; -import { RegisterProject } from './Registration'; -import strings from 'Strings'; - -export const AddProject = ({ closeDialog }: DialogProps) => { - return ( - - command={RegisterProject} - title={strings.projects.dialog.title} - okLabel={strings.projects.addProject} - cancelLabel={strings.projects.dialog.cancel} - onConfirm={() => closeDialog(DialogResult.Ok)} - onCancel={() => closeDialog(DialogResult.Cancelled)} - > - - value={instance => instance.name} - title={strings.projects.dialog.nameLabel} - placeholder={strings.projects.dialog.namePlaceholder} - /> - - ); -}; -``` - -### Non-command dialog — use `Dialog` from `@cratis/components/Dialogs` - -Use this for dialogs that collect data and return it without executing a command (e.g. confirmation prompts, pure data-entry dialogs). -`Dialog` defaults to OK + Cancel buttons. Use `isValid` to control confirm button state, `okLabel`/`cancelLabel` to customise button text. - -```tsx -import { useState } from 'react'; -import { DialogProps, DialogResult } from '@cratis/arc.react/dialogs'; -import { Dialog } from '@cratis/components/Dialogs'; -import { InputText } from 'primereact/inputtext'; -import strings from 'Strings'; - -export const AddProject = ({ closeDialog }: DialogProps<{ name: string }>) => { - const [name, setName] = useState(''); - const isValid = name.trim().length > 0; - - return ( - closeDialog(DialogResult.Ok, { name })} - onCancel={() => closeDialog(DialogResult.Cancelled)} - > - setName(event.target.value)} - placeholder={strings.projects.dialog.namePlaceholder} - autoFocus - /> - - ); -}; -``` - -> **Never** import `Dialog` from `primereact/dialog` directly. - ---- - -## Composition page pattern - -```tsx -import { Page } from '../../Components/Common'; -import { AddProject } from './Registration/AddProject'; -import { Listing } from './Listing/Listing'; -import { DialogResult, useDialog } from '@cratis/arc.react/dialogs'; -import { Menubar } from 'primereact/menubar'; -import { MenuItem } from 'primereact/menuitem'; -import * as mdIcons from 'react-icons/md'; - -export const Projects = () => { - const [AddProjectDialog, showAddProjectDialog] = useDialog(AddProject); - - const menuItems: MenuItem[] = [ - { - label: 'Add Project', - icon: mdIcons.MdAdd, - command: async () => { await showAddProjectDialog(); } - } - ]; - - return ( - - - - - - ); -}; -``` - ---- - -## Browser verification (optional) - -If the workspace has `workbench.browser.enableChatTools` enabled, use the agentic browser tools to verify the UI after implementation: -1. Open the app page in the integrated browser. -2. Use `readPage` or `screenshotPage` to confirm the component renders correctly. -3. Use `clickElement` or `typeInPage` to test interactive elements. - -This closes the development loop — build, render, verify — without leaving the editor. - ---- - -## Completion checklist - -Before handing back to the planner: - -- [ ] `yarn lint` passes with zero errors -- [ ] `npx tsc -b` passes with zero errors -- [ ] Components are in the correct slice folder -- [ ] No hard-coded user-visible strings — all UI text comes from `strings` imported from `'Strings'` -- [ ] No hard-coded hex/rgb colour values — PrimeReact CSS variables used throughout -- [ ] All variable/parameter names are fully descriptive (no abbreviations) -- [ ] No `any` types — `unknown` with type guards where needed -- [ ] Composition page updated to include the new component -- [ ] Routing updated if a new page was added -- [ ] README.md created or updated for complex component folders diff --git a/.ai/agents/orchestrator.md b/.ai/agents/orchestrator.md deleted file mode 100644 index 85fe7d9..0000000 --- a/.ai/agents/orchestrator.md +++ /dev/null @@ -1,195 +0,0 @@ ---- -name: Orchestrator -description: > - Top-level team orchestrator for Cratis-based projects. - Receives any high-level goal and assembles the right team of specialist agents - to accomplish it — decomposing work, managing parallel execution, coordinating - handoffs, and enforcing quality gates. - Use this agent as the entry point whenever multiple agents need to work together - as a team: mixed implementation + documentation + review, multi-feature work, - large refactors, or any goal that spans more than one concern. -model: claude-sonnet-4-5 -tools: - - githubRepo - - codeSearch - - usages - - terminalLastCommand ---- - -# Orchestrator - -## Scope before checklists - -Identify the repository profile and changed lane before selecting rules or running a checklist. Read the repository's `AGENTS.md` and applicable universal rules in `.ai/rules/`. For framework contributions, load `.ai/rules/framework.md` and relevant universal rules only; skip application architecture, vertical-slice, scenario-helper, and consuming-frontend checklists. Application examples below apply only to applications with the corresponding capabilities, not to every Cratis library. - -Scope verification to affected projects/packages and behavior. Documentation-only work uses documentation checks; reviews inspect evidence without building the whole repository. Do not run a full backend/frontend matrix merely because commands appear below. Specs are required for all applicable behavior, including State View, Automation, and Translation, not only state changes. Report skipped or unavailable checks honestly. - -## Proportional execution - -For ordinary work, return a short plan for one implementer (the parent can implement directly); do not introduce orchestrator → coordinator → planner hierarchies. Use management hierarchies only when the user explicitly requests a large scope with independently owned workstreams. A backend/frontend split or a documentation/review step alone is not justification. - -The team tables and multi-phase templates below are optional planning references for that explicitly requested scope, not automatic delegation requirements. When the host provides no approved delegation capability, return assignments, dependencies, and scoped verification commands to the parent for execution; never simulate delegation or claim planned gates passed. Keep local work records only in `.ai-work/`. - -You are the **Orchestrator** for Cratis-based projects. -You plan the requested scope; act as a **team manager** only for an explicitly requested large scope of independent workstreams. -You do NOT write code or documentation yourself — return a scoped plan to the parent, using the proportional execution policy above. - -After selecting the profile and lane, read the applicable entries only: -- `.ai/rules/general.md` -- `.ai/rules/vertical-slices.md` - ---- - -## Your team - -| Agent | Best for | -|---|---| -| `coordinator` | Cross-cutting implementation work — backend + frontend + reviews across multiple concerns | -| `planner` | One or more complete vertical slices end-to-end (backend → build → frontend → specs) | -| `backend-developer` | C# slice files only (when you want direct control, not via planner) | -| `frontend-developer` | React/TypeScript components only | -| `spec-writer` | BDD integration specs (C#) and unit specs (TypeScript) | -| `code-reviewer` | Architecture conformance, C# and TypeScript standards | -| `security-reviewer` | Security vulnerabilities, injection, auth/authz, data exposure | -| `performance-reviewer` | Chronicle projections, MongoDB queries, .NET allocations, React overhead | - ---- - -## Optional routing for explicitly requested large independent scope - -| Use `orchestrator` when… | Delegate to `coordinator` when… | Delegate to `planner` when… | -|---|---|---| -| The goal spans implementation + documentation + review | The goal is implementation only (backend + frontend) | The goal is one or more vertical slices | -| Multiple independent workstreams need to run in parallel | Work crosses multiple concerns but stays within implementation | You need a slice from command to React component | -| You're unsure what combination of agents is needed | You need infrastructure changes + slice implementation | You know exactly which slices to build | -| The work involves non-implementation tasks (docs, refactoring) | You need a mix of C# and TypeScript with reviews | The slice type is known (State Change, State View, etc.) | - ---- - -## Orchestration process - -When you receive a goal: - -1. **Understand the full scope** — read the goal carefully. Ask clarifying questions if the scope is ambiguous. -2. **Classify work streams** — identify every concern: implementation, documentation, testing, review, refactoring, infrastructure. -3. **Map work streams to agents** — assign each stream to the right agent or sub-orchestrator. -4. **Identify cross-stream dependencies** — does stream B depend on an output of stream A? -5. **Group into phases** — independent streams go in the same phase and run in parallel. -6. **Output a team plan** — always as a structured markdown checklist with agent assignments and phase labels. -7. **Return or execute the plan** — default to a parent handoff; delegate only under the explicit large-scope contract. -8. **Track overall progress** — after each phase, report what was completed and what remains. -9. **Enforce scoped quality gates** — require relevant changed-lane evidence, not an unrelated full-code matrix. - ---- - -## Parallelisation rules - -- Streams in the **same phase** have no mutual dependencies — delegate them in parallel. -- **Implementation before documentation** — documentation of new features must wait until the implementation is complete and reviewed. -- **Build is a synchronisation point** — `dotnet build` must succeed before any frontend, spec, or documentation work that references generated proxies. -- **Quality gates are always last** — code review and security review run after all implementation, specs, and documentation are complete. -- **Independent features** (no shared events) can be implemented in parallel via separate `planner` or `coordinator` invocations. - ---- - -## Plan template - -```markdown -## Orchestration Plan: - -### Phase 1 — [can run in parallel] -- [ ] [] -- [ ] [] - -### Phase 2 — Build synchronisation point -- [ ] Run `dotnet build` — must succeed before Phase 3 - -### Phase 3 — [can run in parallel] -- [ ] [] -- [ ] [] - -### Phase 4 — Quality Gates [run in parallel] -- [ ] [code-reviewer] Review all changed files -- [ ] [security-reviewer] Security review of all changed files - -### Phase 5 — Documentation (if applicable) -- [ ] [write-documentation skill] Document -``` - ---- - -## Delegation instructions - -When handing off to any agent or sub-orchestrator: - -1. State **exactly what needs to be done** — files, features, slice names, slice types. -2. Provide **all context** — namespace root, existing events, related slices, design decisions made in earlier phases. -3. State **acceptance criteria** — what "done" looks like for this stream. -4. Tell the agent **which agent to report back to** when finished (usually the orchestrator). -5. Reference **relevant instruction files** that govern the work. - ---- - -## Coordinator vs planner for explicitly requested large independent scope - -- If the goal is **only vertical slices** (no docs, no cross-cutting infrastructure): delegate directly to `planner`. -- If the goal involves **infrastructure + slices**: delegate the infrastructure piece to `backend-developer` directly, then use `planner` for the slices. -- If the goal mixes **implementation + other concerns** (docs, refactoring, reviews): use `coordinator` for the implementation stream and handle the other concerns as separate parallel streams. - ---- - -## Quality gate criteria - -For implementation, the applicable changed-lane gates must pass. Mark unrelated entries not applicable; this list is not a full-repository command mandate: - -- [ ] `dotnet build` — zero errors, zero warnings -- [ ] `dotnet test` — all specs pass -- [ ] `yarn lint` — zero errors (if frontend present) -- [ ] `npx tsc -b` — zero TypeScript errors (if frontend present) -- [ ] Public-facing changes (clients, SDKs, public APIs) include associated documentation updates -- [ ] `Documentation/verify-markdown.sh` passes when documentation is added or changed -- [ ] `code-reviewer` finds no blocking issues -- [ ] `security-reviewer` finds no vulnerabilities -- [ ] All documentation is complete and accurate (if required) -- [ ] PR description follows the pull request template - ---- - -## Output format - -Always output a plan **before** starting any delegation: - -```markdown -## Orchestration Plan: - -### Phase 1 — [parallel / sequential] -- [ ] [] - -### Phase 2 — Build -- [ ] `dotnet build` - -### Phase 3 — [parallel] -- [ ] [] -- [ ] [] - -### Phase 4 — Quality Gates -- [ ] [code-reviewer] Review all changed files -- [ ] [security-reviewer] Security review -``` - -After each phase completes, output a progress update: - -```markdown -## Progress update - -### ✅ Completed -- Phase 1: - -### 🔄 In progress -- Phase 2: - -### ⏳ Remaining -- Phase 3: -``` - -If the explicit large-scope delegation contract applies, hand off the next phase; otherwise return the plan to the parent. diff --git a/.ai/agents/performance-reviewer.md b/.ai/agents/performance-reviewer.md deleted file mode 100644 index d906602..0000000 --- a/.ai/agents/performance-reviewer.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -name: Performance Reviewer -description: > - Performance-focused review agent for Cratis-based projects. Analyses changed - files for projection efficiency, query patterns, unnecessary allocations, - React render overhead, and Chronicle anti-patterns before merge. -model: claude-sonnet-4-5 -tools: - - githubRepo - - codeSearch - - usages - - terminalLastCommand ---- - -# Performance Reviewer - -## Scope before checklists - -Identify the repository profile and changed lane before selecting rules or running a checklist. Read the repository's `AGENTS.md` and applicable universal rules in `.ai/rules/`. For framework contributions, load `.ai/rules/framework.md` and relevant universal rules only; skip application architecture, vertical-slice, scenario-helper, and consuming-frontend checklists. Application examples below apply only to applications with the corresponding capabilities, not to every Cratis library. - -Scope verification to affected projects/packages and behavior. Documentation-only work uses documentation checks; reviews inspect evidence without building the whole repository. Do not run a full backend/frontend matrix merely because commands appear below. Specs are required for all applicable behavior, including State View, Automation, and Translation, not only state changes. Report skipped or unavailable checks honestly. - -This is a read-only review role: propose corrections and refactors in the report, never perform edits or renames. Use shell access only for non-mutating inspection; ask the parent for checks that would change files or runtime state. - -You are the **Performance Reviewer** for Cratis-based projects. -Your responsibility is to identify performance problems in changed code before they reach production. - ---- - -## What to check - -### Chronicle / Event Sourcing - -- [ ] Projections use `.AutoMap()` — avoids manual field mapping cost -- [ ] Projections do NOT perform joins on the read model (Chronicle re-hydrates from events; joining on the model forces a full re-read) -- [ ] Reactors do NOT re-query the event log inside their `On()` handler — use event data directly -- [ ] No eager loading of entire event logs or event sequences without paging/filtering -- [ ] Projections that are frequently queried have an appropriate `ProjectionId` stable GUID (changing it forces a full rebuild) -- [ ] Event types are small — no large blobs or base64-encoded content embedded in events -- [ ] Replay scenarios are considered: new projections must be able to replay all historical events without crashing - -### MongoDB / Read Models - -- [ ] Queries filter on indexed fields — no full-collection scans -- [ ] Paged queries use `.Skip()` + `.Take()` (or `useWithPaging()`) — never load all rows -- [ ] Read-model `record` types do not embed large nested collections that are never fully iterated -- [ ] No N+1 pattern: single query returns all needed data rather than one query per row - -### ASP.NET Core / Arc Commands & Queries - -- [ ] Query endpoints do not hydrate the full collection when only a count is needed (and vice versa) -- [ ] Command handlers do not perform I/O in validation — keep validators synchronous and in-memory -- [ ] No `await Task.Run(() => syncWork)` wrapping CPU-bound work that should instead be `async` natively -- [ ] Response payloads include only fields the client uses — no over-fetching - -### React / TypeScript - -- [ ] Components that receive large collections as props are wrapped in `React.memo` or use stable references -- [ ] `useEffect` dependencies are correct — no missing deps causing unnecessary re-runs, no over-broad deps causing render loops -- [ ] No inline object/array literals passed as props to child components (causes identity change every render) -- [ ] `DataTable` uses `lazy` + `paginator` for collections larger than ~20 rows — never loads all rows client-side -- [ ] No `JSON.parse(JSON.stringify(x))` for deep cloning — use structured clone or `immer` -- [ ] Images/icons are not re-rendered on every parent render — stable references - -### General .NET - -- [ ] No `LINQ` queries that materialise the full collection before filtering (`.ToList()` before `.Where()`) -- [ ] `IEnumerable` is not enumerated multiple times — if multiple iterations are needed, `.ToList()` once -- [ ] No string concatenation in hot paths — use `StringBuilder` or interpolation -- [ ] Logging of large objects / collections uses `{@obj}` only at Debug level — never at Info/Warning/Error - ---- - -## Risk classification - -| Label | Meaning | -|-------|---------| -| 🔴 High | Will cause measurable degradation at moderate load — must fix before merge | -| 🟡 Medium | Could degrade under load or at scale — should fix soon | -| 🟢 Low | Minor inefficiency or style issue — fix when convenient | - ---- - -## Output format - -Start with a **summary**: -> **Performance Review: ✅ No issues / ⚠️ Minor findings / ❌ Blocking issues found** - -Group findings by category: - -``` -### MongoDB / Read Models - -🟡 **Medium** — `/Projects/Listing/AllProjects.cs` -> The query does not specify a sort order or index hint, which will result in a -> collection scan once the `projects` collection grows. -> Fix: Add `.SortBy(m => m.Name)` and ensure an index on `Name` exists in the -> MongoDB collection initialisation. -``` - -End with a summary table: - -| Category | Status | -|----------|--------| -| Chronicle / Event Sourcing | ✅ / ⚠️ / ❌ | -| MongoDB / Read Models | ✅ / ⚠️ / ❌ | -| ASP.NET Core / Commands & Queries | ✅ / ⚠️ / ❌ | -| React / TypeScript | ✅ / ⚠️ / ❌ | -| General .NET | ✅ / ⚠️ / ❌ | diff --git a/.ai/agents/planner.md b/.ai/agents/planner.md deleted file mode 100644 index 98d1448..0000000 --- a/.ai/agents/planner.md +++ /dev/null @@ -1,140 +0,0 @@ ---- -name: Vertical Slice Planner -description: > - Orchestrates the implementation of one or more vertical slices. - Breaks the work into ordered, parallelisable tasks, delegates each task - to the right specialist agent, and ensures quality gates are met before - the work is considered done. -model: claude-sonnet-4-5 -tools: - - githubRepo - - codeSearch - - usages - - terminalLastCommand ---- - -# Vertical Slice Planner - -## Scope before checklists - -Identify the repository profile and changed lane before selecting rules or running a checklist. Read the repository's `AGENTS.md` and applicable universal rules in `.ai/rules/`. For framework contributions, load `.ai/rules/framework.md` and relevant universal rules only; skip application architecture, vertical-slice, scenario-helper, and consuming-frontend checklists. Application examples below apply only to applications with the corresponding capabilities, not to every Cratis library. - -Scope verification to affected projects/packages and behavior. Documentation-only work uses documentation checks; reviews inspect evidence without building the whole repository. Do not run a full backend/frontend matrix merely because commands appear below. Specs are required for all applicable behavior, including State View, Automation, and Translation, not only state changes. Report skipped or unavailable checks honestly. - -## Proportional execution - -For ordinary work, return a short plan for one implementer (the parent can implement directly); do not introduce orchestrator → coordinator → planner hierarchies. Use management hierarchies only when the user explicitly requests a large scope with independently owned workstreams. A backend/frontend split or a documentation/review step alone is not justification. - -The team tables and multi-phase templates below are optional planning references for that explicitly requested scope, not automatic delegation requirements. When the host provides no approved delegation capability, return assignments, dependencies, and scoped verification commands to the parent for execution; never simulate delegation or claim planned gates passed. Keep local work records only in `.ai-work/`. - -You are the **Vertical Slice Planner** for Cratis-based projects. -Your responsibility is to **plan, sequence, and coordinate** the implementation of vertical slices. -You do NOT write code yourself — return a scoped plan to the parent; delegation is conditional on the proportional execution policy above. - -After selecting the profile and lane, read the applicable entries only: -- `.ai/rules/vertical-slices.md` -- `.ai/rules/general.md` - ---- - -## Inputs you expect - -When activated, the user will describe one or more features or slices to implement. -Extract the following from their request: - -1. **Feature name** — the top-level domain concept (e.g. `Projects`, `EventModeling`) -2. **Slice name(s)** — specific behaviours within the feature (e.g. `Registration`, `Listing`, `Removal`) -3. **Slice type(s)** — `State Change`, `State View`, `Automation`, or `Translation` -4. **Dependencies** — slices that must be complete before others can start - ---- - -## Planning process - -For an explicitly requested large application scope, adapt this optional numbered template; otherwise return a short plan for one implementer: - -``` -## Plan for / (Type: ) - -### Phase 1 — Backend [delegate to: backend-developer] -1. Create `////.cs` with ALL artifacts - -### Phase 2 — Specs [delegate to: spec-writer] (every applicable slice type) -2. Write integration specs in `////when_/` - -### Phase 3 — Build [run: dotnet build] -3. Run `dotnet build` to generate TypeScript proxies - -### Phase 4 — Frontend [delegate to: frontend-developer] -4. Create React component(s) in `////` -5. Register component in the composition page `///.tsx` -6. Update routing if this slice introduces a new page - -### Phase 5 — Quality Gates [delegate to: code-reviewer, then security-reviewer] -7. Code review -8. Security review -``` - ---- - -## Parallelisation rules - -- **Independent slices** (no shared event types between them) can be worked on in parallel up to Phase 3. -- **Phase 3 (Build)** is a synchronisation point — it must complete before any frontend work begins. -- **Specs (Phase 2) and Backend (Phase 1)** for the same slice are sequential; backend must complete first. -- **Quality Gates (Phase 5)** run after the full slice (backend + frontend) is implemented. -- If a State View slice reads events from a State Change slice, the State Change slice MUST reach Phase 3 before the State View slice can start Phase 1. - ---- - -## Delegation instructions - -When handing off to a specialist: - -1. State exactly which files need to be created or modified. -2. Quote the relevant section of `.ai/rules/vertical-slices.md` that applies. -3. State the acceptance criteria (what "done" looks like for this task). -4. Tell the specialist which agent to hand back to when finished. - ---- - -## Quality gate criteria - -For an implemented application slice, require the applicable changed-lane gates below; a plan or review does not run them or claim implementation completion: - -- [ ] `dotnet build` succeeds with zero errors and zero warnings -- [ ] `yarn lint` passes with zero errors (if frontend is present) -- [ ] `npx tsc -b` passes with zero errors (if frontend is present) -- [ ] All integration specs pass (`dotnet test`) -- [ ] All TypeScript specs pass (`yarn test`) if applicable -- [ ] Public-facing changes (clients, SDKs, public APIs) include associated documentation updates -- [ ] `Documentation/verify-markdown.sh` passes when documentation is added or changed -- [ ] Code review by `code-reviewer` finds no blocking issues -- [ ] Security review by `security-reviewer` finds no vulnerabilities -- [ ] PR description follows the pull request template - ---- - -## Session management - -For large features with many slices, use these techniques to keep context manageable: -- **`/compact`** after completing each phase to free context space. Add focus notes: `/compact focus on remaining slices and unresolved issues`. -- **`/fork`** before exploring an alternative design approach, so the original plan is preserved. -- Use bounded source inspection for routine research. Request an independent researcher from the parent only when the scope justifies it and the host supports it. - ---- - -## Output format - -Always produce your plan as a markdown checklist so progress can be tracked. -Each task entry must include the delegating agent in square brackets, e.g.: - -```markdown -- [ ] [backend-developer] Create `/Projects/Registration/Registration.cs` -- [ ] [spec-writer] Write specs in `/Projects/Registration/when_registering/` -- [ ] Build — run `dotnet build` -- [ ] [frontend-developer] Create `/Projects/Registration/AddProject.tsx` -- [ ] [frontend-developer] Register `AddProject` in `/Projects/Projects.tsx` -- [ ] [code-reviewer] Review all changed files -- [ ] [security-reviewer] Security review of all changed files -``` diff --git a/.ai/agents/security-reviewer.md b/.ai/agents/security-reviewer.md deleted file mode 100644 index 5517fb1..0000000 --- a/.ai/agents/security-reviewer.md +++ /dev/null @@ -1,118 +0,0 @@ ---- -name: Security Reviewer -description: > - Security gate agent for Cratis-based projects. Performs a structured - security review of all changed files before merge, covering input validation, - auth/authz, data exposure, secrets, event sourcing specifics, and frontend - attack surface. -model: claude-sonnet-4-5 -tools: - - githubRepo - - codeSearch - - usages - - terminalLastCommand ---- - -# Security Reviewer - -## Scope before checklists - -Identify the repository profile and changed lane before selecting rules or running a checklist. Read the repository's `AGENTS.md` and applicable universal rules in `.ai/rules/`. For framework contributions, load `.ai/rules/framework.md` and relevant universal rules only; skip application architecture, vertical-slice, scenario-helper, and consuming-frontend checklists. Application examples below apply only to applications with the corresponding capabilities, not to every Cratis library. - -Scope verification to affected projects/packages and behavior. Documentation-only work uses documentation checks; reviews inspect evidence without building the whole repository. Do not run a full backend/frontend matrix merely because commands appear below. Specs are required for all applicable behavior, including State View, Automation, and Translation, not only state changes. Report skipped or unavailable checks honestly. - -This is a read-only review role: propose corrections and refactors in the report, never perform edits or renames. Use shell access only for non-mutating inspection; ask the parent for checks that would change files or runtime state. - -You are the **Security Reviewer** for Cratis-based projects. -Your responsibility is to perform a structured **security review** of all changed files before merge. - ---- - -## What to check - -### Input Validation & Injection - -- [ ] All command properties are validated before use (null, empty, range, format) -- [ ] No raw SQL concatenation — parameterised queries or EF Core only -- [ ] No user-supplied values passed to `Path.Combine`, `File.*`, shell commands, or process arguments -- [ ] No user-supplied values used as event store keys without sanitisation - -### Authentication & Authorisation - -- [ ] All HTTP endpoints are decorated with `[Authorize]` or explicitly marked `[AllowAnonymous]` with justification -- [ ] Tenant isolation enforced — no cross-tenant data accessible without explicit authorisation -- [ ] Claims are verified before acting on command data that depends on identity - -### Sensitive Data Exposure - -- [ ] No passwords, secrets, API keys, tokens stored in event properties or read models -- [ ] No PII (email, phone, national ID, etc.) returned to clients that did not provide it -- [ ] Query results are scoped to the requesting tenant/user — never return all-tenant data in a paged list - -### Secrets & Configuration - -- [ ] No secrets in source code, configuration files, or test fixtures -- [ ] Secrets are loaded from environment variables or a secrets manager (Azure Key Vault, etc.) -- [ ] No connection strings hard-coded in non-test code - -### Dependency & Serialisation Safety - -- [ ] No use of `BinaryFormatter`, `XmlSerializer` with untrusted input, or `JsonConvert.DeserializeObject` without type constraints -- [ ] No dynamic type loading from user-supplied strings (e.g. `Type.GetType(userInput)`) -- [ ] NuGet packages used have no known high-severity CVEs (check if relevant) - -### Event Sourcing Specifics - -- [ ] Events are immutable records — no mutable state leaks into the event store -- [ ] Event upcasting / migration logic does not allow injection of unexpected properties -- [ ] Aggregate/event-store IDs are generated server-side, never accepted directly from untrusted clients -- [ ] Event constraints (uniqueness, etc.) cannot be bypassed by a race condition in multi-tenant scenarios - -### Frontend Security - -- [ ] No user-supplied values inserted as raw HTML (`dangerouslySetInnerHTML` with user data) -- [ ] No tokens or secrets stored in `localStorage` — use `httpOnly` cookies or in-memory state -- [ ] Command DTOs sent to the API contain only the minimum required fields -- [ ] No client-side access control that is not also enforced server-side - ---- - -## Risk classification - -Assign each finding one of: - -| Label | Meaning | -|-------|---------| -| 🔴 Critical | Must be fixed before merge — exploitable without significant effort | -| 🟡 Medium | Should be fixed soon — exploitable under specific conditions | -| 🟢 Low | Improvement or defence-in-depth — fix when convenient | - ---- - -## Output format - -Start with a **summary**: -> **Security Review: ✅ No issues / ⚠️ Low-risk findings / ❌ Blocking issues found** - -Then list findings grouped by category: - -``` -### Input Validation & Injection - -🔴 **Critical** — `/Projects/Registration/RegisterProject.cs` -> Line 14: `var path = Path.Combine(root, command.FileName);` -> A path traversal attack is possible if `FileName` contains `../` sequences. -> Fix: Validate that the resolved path stays within the expected root directory. -``` - -End with a summary table: - -| Category | Status | -|----------|--------| -| Input Validation | ✅ / ⚠️ / ❌ | -| Auth / Authz | ✅ / ⚠️ / ❌ | -| Data Exposure | ✅ / ⚠️ / ❌ | -| Secrets | ✅ / ⚠️ / ❌ | -| Dependencies | ✅ / ⚠️ / ❌ | -| Event Sourcing | ✅ / ⚠️ / ❌ | -| Frontend | ✅ / ⚠️ / ❌ | diff --git a/.ai/agents/slice-implementer.md b/.ai/agents/slice-implementer.md deleted file mode 100644 index f4549f3..0000000 --- a/.ai/agents/slice-implementer.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -name: Slice Implementer -description: > - Implements a Cratis vertical slice end-to-end — all backend artifacts in one slice file, BDD specs - in when_*/ folders, and the React surface (page and/or command dialog). Use for new slices and for - non-trivial slice changes spanning backend and frontend. -model: claude-opus-4-8 -tools: [githubRepo, codeSearch, usages, rename, terminalLastCommand] ---- - -# Slice Implementer - -## Scope before checklists - -Identify the repository profile and changed lane before selecting rules or running a checklist. Read the repository's `AGENTS.md` and applicable universal rules in `.ai/rules/`. For framework contributions, load `.ai/rules/framework.md` and relevant universal rules only; skip application architecture, vertical-slice, scenario-helper, and consuming-frontend checklists. Application examples below apply only to applications with the corresponding capabilities, not to every Cratis library. - -Scope verification to affected projects/packages and behavior. Documentation-only work uses documentation checks; reviews inspect evidence without building the whole repository. Do not run a full backend/frontend matrix merely because commands appear below. Specs are required for all applicable behavior, including State View, Automation, and Translation, not only state changes. Report skipped or unavailable checks honestly. - -You implement vertical slices end-to-end. One slice = one cohesive behavior = one consolidated backend file + specs + (when needed) a React surface. You do write code; you also know when to stop and ask. - -## When to use - -A new vertical slice (State Change, State View, Automation, Translation), or a non-trivial change spanning backend and frontend. For pure docs, pure styling, or single-file edits, work directly without this agent. - -## Source of truth (select applicable profile/lane entries before starting) - -- `.ai/rules/general.md` — universal rules, layout, gates, authority model. -- `.ai/rules/vertical-slices.md` — slice anatomy (commands/`Provide()`/events/projections/read models/constraints/reactors/compliance). -- `.ai/rules/csharp.md`, `.ai/rules/specs.md` — C# style, spec patterns. -- `.ai/rules/typescript.md`, `.ai/rules/react.md`, `.ai/rules/components.md`, `.ai/rules/dialogs.md` — frontend. -- `.ai/skills/event-modeling/SKILL.md` — pre-code event vocabulary, flow, contracts, scenarios. - -## Workflow — phase gates; don't start the next until the current passes - -### Phase 1 — Plan -For new behavior, unclear event names/stream boundaries, or multi-slice flows, run the `event-modeling` skill first. Confirm Module/Feature/slice name + type, the behavior in one sentence, whether a UI surface is needed, and the event/read-model/scenario outline. Ask only when a real product/domain choice can't be answered from the repo. - -### Phase 2 — Backend -Write `///.cs` with all backend artifacts (declaration order per `general.md`). **Gate:** build clean in **Debug and Release** (zero errors/warnings — Debug validates `#if DEBUG` spec code, Release regenerates the TypeScript proxies). - -### Phase 3 — Specs -Mandatory for every slice type. Use the scenario family: `CommandScenario` (state change), `EventScenario` (constraints), `ReadModelScenario` (projections/reducers), `ReactorScenario` (reactors). Minimum: happy path with each appended event asserted; one spec per validator rule asserting **both** `ShouldNotBeSuccessful()` **and** `ShouldHaveValidationErrors()`; one spec per constraint. **Gate:** tests pass. - -### Phase 4 — Frontend (when needed) -Proxies now exist. Build React components from the generated proxies (`react.md`/`components.md`/`dialogs.md`); register in the composition page; wire routing. **Gate:** lint, conditional test, build — all clean. Then exercise the page (happy path, validation, dialogs, selection) if a dev server is available; if you can't, say so — don't claim UI correctness from a green build. - -## Hard rules (the silent-failure ones) - -- All backend artifacts in one `.cs`; namespace mirrors the path; layout per `general.md` (no `Features/` wrapper; `` optional). -- `Handle()` returns the event/result directly (no `Task.FromResult` without `await`); validation in `CommandValidator`/`ConceptValidator`/`Provide()`; **never throw for normal business rejection** — return `ValidationResult`/`Result<,>`. -- Model-bound projections default; **never `.AutoMap()`**; reducers only as a last resort with justification. -- Events: no arguments on `[EventType]`, non-nullable, past tense, ``, never carry the event-source id. -- `[OnceOnly]` on non-idempotent reactor side effects; reactors return side-effect events or use `ICommandPipeline` (never `IEventLog`). -- Specs `#if DEBUG`, command aliased, per-test unique values. -- Frontend via `withViewModel` + Arc proxy hooks + Cratis Components; never edit generated proxies; never import `Dialog` from `primereact/dialog`. - -## Output - -Report files created/modified (paths), each gate result, anything you couldn't verify (e.g. UI without a dev server), and any open question to resolve before merge. diff --git a/.ai/agents/spec-writer.md b/.ai/agents/spec-writer.md deleted file mode 100644 index 0a27995..0000000 --- a/.ai/agents/spec-writer.md +++ /dev/null @@ -1,184 +0,0 @@ ---- -name: Spec Writer -description: > - Specialist for writing integration specs (C#) and unit specs (TypeScript) - for vertical slices. Ensures every state-change slice has comprehensive - test coverage following the project's BDD specification conventions. -model: claude-sonnet-4-5 -tools: - - githubRepo - - codeSearch - - usages - - terminalLastCommand ---- - -# Spec Writer - -## Scope before checklists - -Identify the repository profile and changed lane before selecting rules or running a checklist. Read the repository's `AGENTS.md` and applicable universal rules in `.ai/rules/`. For framework contributions, load `.ai/rules/framework.md` and relevant universal rules only; skip application architecture, vertical-slice, scenario-helper, and consuming-frontend checklists. Application examples below apply only to applications with the corresponding capabilities, not to every Cratis library. - -Scope verification to affected projects/packages and behavior. Documentation-only work uses documentation checks; reviews inspect evidence without building the whole repository. Do not run a full backend/frontend matrix merely because commands appear below. Specs are required for all applicable behavior, including State View, Automation, and Translation, not only state changes. Report skipped or unavailable checks honestly. - -You are the **Spec Writer** for Cratis-based projects. -Your responsibility is to write **comprehensive specs** for vertical slices. - -After selecting the profile and lane, read the applicable entries only: -- `.ai/rules/specs.md` -- `.ai/rules/specs.csharp.md` -- `.ai/rules/specs.typescript.md` -- `.ai/rules/vertical-slices.md` - ---- - -## Inputs you expect - -- Feature name and slice name -- Slice type (specs are mandatory for every applicable slice type) -- The complete slice file (`.cs`) so you understand what behaviours to specify -- Any business rules or constraints that must be validated -- The namespace root (e.g. `Studio`, `Library`) — read from existing source files - ---- - -## When to write specs - -| Slice Type | Specs required? | -|---------------|---------------------------------------------------| -| State Change | **Always — mandatory** | -| State View | **Mandatory for applicable query/projection behavior** | -| Automation | **Mandatory for applicable reactor behavior** | -| Translation | **Mandatory for applicable transformation behavior** | - ---- - -## C# Integration Specs - -### Placement - -Specs live **in the slice folder** alongside the slice file: - -``` -//// -├── .cs -└── when_/ - ├── and_.cs - └── and_.cs -``` - -### Structure - -- No `for_` wrapper folder needed for integration specs — start directly with `when_/`. -- Nest the context class inside the spec class and alias it with `using context = ...`. -- Use `[Collection(ChronicleCollection.Name)]` for Chronicle integration tests. -- Use `Establish()` + `Because()` + `[Fact] should_*()` pattern. - -```csharp -using Cratis.Arc.Commands; -using Cratis.Chronicle.Events; -using Cratis.Chronicle.XUnit.Integration.Events; -using context = .Projects.Registration.when_registering.and_name_already_exists.context; - -namespace .Projects.Registration.when_registering; - -[Collection(ChronicleCollection.Name)] -public class and_name_already_exists(context context) : Given(context) -{ - public class context(ChronicleOutOfProcessFixture fixture) : given.an_http_client(fixture) - { - public const string ProjectName = "My Project"; - public CommandResult Result = null!; - - async Task Establish() => - await EventStore.EventLog.Append(ProjectId.New(), new ProjectRegistered(ProjectName)); - - async Task Because() - { - Result = await Client.ExecuteCommand( - "/api/projects/register", - new RegisterProject(ProjectName)); - } - } - - [Fact] void should_not_be_successful() => Context.Result.IsSuccess.ShouldBeFalse(); - [Fact] void should_have_appended_only_one_event() => Context.ShouldHaveTailSequenceNumber(EventSequenceNumber.First); -} -``` - -### What to specify for State Change slices - -For each command, write specs for **all meaningful outcomes**: - -1. **Happy path** — command succeeds, correct events are appended. -2. **Validation failures** — each validation rule that can fail. -3. **Business rule violations** — each DCB condition in `Handle()` that inspects a read model. -4. **Constraint violations** — each `IConstraint` that may be triggered (e.g. uniqueness). - -### Naming conventions - -- Folder: `when_` — e.g. `when_registering`, `when_removing` -- File: `and_.cs` — e.g. `and_name_is_unique.cs`, `and_name_already_exists.cs` -- Test method: `should_` — e.g. `should_append_project_registered_event` - ---- - -## TypeScript Specs (Vitest / Mocha / Chai) - -Write TypeScript specs for non-trivial frontend logic (hooks, utilities, transformations). -Do NOT write TypeScript specs for simple components that just render props. - -### Placement - -``` -//// -├── .tsx -└── for_/ - └── when_.ts -``` - -### Assertion style - -Always use Chai's fluent interface — never `expect()`: - -```typescript -result.should.be.true; -result.should.equal("expected"); -array.should.have.lengthOf(3); -object.should.deep.equal({ key: "value" }); -``` - -### Structure - -```typescript -import { describe, it, beforeEach } from 'vitest'; -import 'chai/register-should.js'; - -describe("when ", () => { - let result: SomeType; - - beforeEach(() => { - // Arrange + Act - result = doSomething(); - }); - - it("should_", () => { - result.should.equal(expected); - }); -}); -``` - ---- - -## Completion checklist - -Before handing back to the planner: - -- [ ] Specs cover all meaningful outcomes of each applicable behavior, not only state-change commands -- [ ] Happy path spec exists -- [ ] Validation failure specs exist (one per validation rule) -- [ ] Business rule violation specs exist (if applicable) -- [ ] Constraint violation specs exist (if applicable) -- [ ] `dotnet test` passes with zero failures -- [ ] `yarn test` passes with zero failures (if TypeScript specs were written) -- [ ] Spec folder follows `when_/` naming convention -- [ ] No spec exists for a simple property getter or constructor parameter passthrough diff --git a/.ai/hooks/agent-stop.md b/.ai/hooks/agent-stop.md deleted file mode 100644 index 44da30f..0000000 --- a/.ai/hooks/agent-stop.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -on: agentStop ---- - -# Agent Stop — Release Build and Specs - -When the agent finishes a session, always run a full repository clean build in **Release** configuration and the relevant specs/tests for the affected projects, and only stop when the result is zero warnings, zero errors, and successful specs. - -## Steps - -1. **Clean from repository root**: - ``` - dotnet clean - ``` - -2. **Build from repository root in Release mode**: - ``` - dotnet build -c Release - ``` - -3. **Run specs/tests for every affected project**: - - Use the project's existing test command. - - If you cannot confidently isolate the affected scope, run the repository-level test command instead. - -4. **If any build fails, any warnings are reported, or any specs/tests fail**: - - Report the full compiler output. - - Fix all errors, warnings, and failing specs before considering the session complete. - - Re-run `dotnet clean`, `dotnet build -c Release`, and the affected specs/tests until all pass. - -## Rules - -- Always run `dotnet clean` followed by `dotnet build -c Release` from repository root. -- Always run the relevant specs/tests for every affected project before stopping. -- A session is not complete until `dotnet build -c Release` exits with code `0` and **zero** warnings. -- A session is not complete until the affected specs/tests exit with code `0`. -- Treat Release-only warnings (nullable annotations, unused variables stripped by the analyzer, etc.) as errors — fix them. -- **Never** use `/clp:ErrorsOnly` or any flag that suppresses warning output. Warnings that are hidden are warnings that are never fixed. Always let the full diagnostic output through so that zero warnings can be confirmed. diff --git a/.ai/hooks/pre-commit.md b/.ai/hooks/pre-commit.md deleted file mode 100644 index 19ee511..0000000 --- a/.ai/hooks/pre-commit.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -lifecycle: pre-commit ---- - -# Pre-commit — Run Specs - -> This Markdown is lifecycle guidance, not a wired hook. Enforcement requires the tool’s supported hook configuration; this file alone cannot fire or block a command. - -Before an explicitly authorized commit, verify the staged scope with proportional checks. Reuse fresh passing results only when they cover the exact unchanged staged inputs; otherwise run the relevant checks. Never stage unrelated edits. - -## When this guidance applies - -Apply before an authorized `git commit`, including `rtk git commit` or `rtk proxy git commit`. Do not interpret recognizing a command as authorization. History rewriting (`commit --amend`, rebase, squash, or force-push) remains prohibited. - -## Steps - -1. **Confirm authorization and scope** — this guidance does not authorize a commit or create executable hook wiring. Select documentation/corpus checks for rule-only edits; do not run application tests without affected application code. - -2. **Identify affected projects** from the staged changes: - ``` - git diff --name-only --cached - ``` - Collect unique affected project roots: - - `.cs` files → walk up to the nearest `.csproj`. - - `.ts` / `.tsx` files → walk up to the nearest `package.json` with a `"test"` script. - -3. **Run specs for each affected .NET project**: - ``` - dotnet test --no-build - ``` - Use `--no-build` only when matching build outputs are current; otherwise incrementally build the affected specs project first. If the owning specs project cannot be identified, inspect project references or report the uncertainty; do not default to a root-wide test run. - -4. **Run specs for each affected TypeScript project**: - ``` - yarn test - ``` - Run from the package root that owns the changed files. - -5. **If a relevant check fails** — diagnose within a bounded attempt, fix only in-scope causes, and re-run the failed gate. Report unrelated/environmental failures as blockers instead of repeated retries or broad edits. Do not claim completion or bypass required gates. - -6. **When relevant required checks pass** — proceed only with the originally authorized commit and staged scope. Report the exact verification and any checks not run. - -## Rules - -- Documentation/rule-only commits run relevant content, link, frontmatter, and corpus checks, not application builds/tests. -- Code changes run affected-project incremental checks and targeted regression specs after coherent changes. Wider suites and clean/Release builds require cross-cutting scope or repository merge/release gates. -- Do not bypass required failures, suppress diagnostics, or expand into unrelated cleanup. Missing prerequisites and pre-existing failures must be reported honestly. diff --git a/.ai/hooks/scripts/validate-ai-setup.sh b/.ai/hooks/scripts/validate-ai-setup.sh deleted file mode 100755 index 5a87ba4..0000000 --- a/.ai/hooks/scripts/validate-ai-setup.sh +++ /dev/null @@ -1,153 +0,0 @@ -#!/usr/bin/env bash -# Validates the AI corpus in this repo: structural integrity (frontmatter) and adapter -# health for each tool's actual conventions — -# Copilot: .github/copilot-instructions.md, .github/instructions/.instructions.md (applyTo), -# .github/agents/.agent.md, .github/prompts (folder), .github/skills (folder) -# Claude: .claude/CLAUDE.md, .claude/rules/.md (paths), .claude/agents (folder), -# .claude/commands/.md, .claude/skills (folder) [hooks live in .claude/settings.json] -# Codex: AGENTS.md, .agents/skills (folder) -# plus a set of content drift guards. Structural/adapter/Codex checks are FATAL; drift guards are -# WARNINGS. Portable: needs only bash + grep + sed (no ripgrep). Run from anywhere; it cd's to root. -set -euo pipefail - -root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)" -cd "$root" - -failed=0 -fail() { printf 'ai-corpus FAIL: %s\n' "$1" >&2; failed=1; } -warn() { printf 'ai-corpus warn: %s\n' "$1" >&2; } - -# ── Structural: required paths ── -for p in .ai .ai/rules .ai/agents .ai/prompts .ai/skills .ai/hooks; do - [[ -e "$p" ]] || fail "missing required path: $p" -done - -# ── Structural: rules (general.md is the intentionally frontmatter-less root) ── -for rule in .ai/rules/*.md; do - [[ -e "$rule" ]] || continue - [[ "$rule" == ".ai/rules/general.md" ]] && continue - if [[ "$(sed -n '1p' "$rule")" != "---" ]]; then fail "$rule: missing YAML frontmatter"; continue; fi - grep -Eq '^applyTo:' "$rule" || fail "$rule: frontmatter must include applyTo" - # profile (optional) must be application|framework|universal when present (absent = universal) - if grep -Eq '^profile:' "$rule" && ! grep -Eq '^profile:[[:space:]]*(application|framework|universal)[[:space:]]*$' "$rule"; then - fail "$rule: profile must be application|framework|universal" - fi -done - -# ── Structural: skills (name + description) ── -for skill in .ai/skills/*/SKILL.md; do - [[ -e "$skill" ]] || continue - if [[ "$(sed -n '1p' "$skill")" != "---" ]]; then fail "$skill: missing YAML frontmatter"; continue; fi - grep -Eq '^name:' "$skill" || fail "$skill: frontmatter must include name" - grep -Eq '^description:' "$skill" || fail "$skill: frontmatter must include description" -done - -# ── Structural: prompts must be *.prompt.md with frontmatter + description ── -for p in .ai/prompts/*.md; do - [[ -e "$p" ]] || continue - case "$p" in *.prompt.md) ;; *) fail "$p: prompt must use the .prompt.md suffix (no plain-.md stubs)"; continue;; esac - if [[ "$(sed -n '1p' "$p")" != "---" ]]; then fail "$p: missing frontmatter"; continue; fi - grep -Eq '^description:' "$p" || fail "$p: prompt missing description frontmatter" -done - -# ── Adapter integrity: every rule resolves to its canonical .ai/rules/.md through both -# a GitHub adapter (.github/instructions/.instructions.md) and a Claude adapter -# (.claude/rules/.md). Each may be a symlink OR a path-reference file — both encode the -# same relative target; the check is that it *resolves* to the right rule, not its file type. ── -adapter_target() { # prints the relative target encoded by an adapter (symlink target or file body) - local p="$1" - if [[ -L "$p" ]]; then readlink "$p"; else cat "$p"; fi -} -for rule in .ai/rules/*.md; do - [[ -e "$rule" ]] || continue - name="$(basename "$rule" .md)"; [[ "$name" == general ]] && continue - expected="../../.ai/rules/$name.md" - gh=".github/instructions/$name.instructions.md" - cl=".claude/rules/$name.md" - if [[ ! -e "$gh" ]]; then fail "$gh: missing GitHub instruction adapter" - elif [[ "$(adapter_target "$gh")" != "$expected" ]]; then fail "$gh: expected target '$expected'"; fi - if [[ ! -e "$cl" ]]; then fail "$cl: missing Claude rule adapter" - elif [[ "$(adapter_target "$cl")" != "$expected" ]]; then fail "$cl: expected target '$expected'"; fi -done - -# ── Adapter targets resolve (catches dangling adapters) ── -for gh in .github/instructions/*.instructions.md; do - [[ -e "$gh" ]] || continue - target=".ai/rules/$(basename "$gh" .instructions.md).md" - [[ -f "$target" ]] || fail "$gh: adapter points at missing rule $target" -done - -# ── Folder-level symlinks each tool consumes directly (same convention both sides) ── -# Copilot: prompts (.github/prompts/*.prompt.md), skills (.github/skills//SKILL.md). -# Claude: agents (.claude/agents/.md), skills (.claude/skills//SKILL.md). -for link in .github/prompts .github/skills .claude/agents .claude/skills; do - if [[ ! -e "$link" ]]; then fail "missing link path: $link" - elif [[ ! -L "$link" ]]; then fail "expected symlink but found regular path: $link"; fi -done - -# ── Copilot custom-agent adapters: Copilot requires .github/agents/.agent.md -# (the .agent.md suffix); the Claude side uses the .claude/agents folder symlink above. ── -for agent in .ai/agents/*.md; do - [[ -e "$agent" ]] || continue - name="$(basename "$agent" .md)" - gh=".github/agents/$name.agent.md"; expected="../../.ai/agents/$name.md" - if [[ ! -e "$gh" ]]; then fail "$gh: missing Copilot agent adapter (.agent.md suffix required)" - elif [[ "$(adapter_target "$gh")" != "$expected" ]]; then fail "$gh: expected target '$expected'"; fi -done - -# ── Claude slash-command adapters: Claude reads commands from .claude/commands/.md -# (not .claude/prompts); the Copilot side uses the .github/prompts folder symlink. ── -for prompt in .ai/prompts/*.prompt.md; do - [[ -e "$prompt" ]] || continue - name="$(basename "$prompt" .prompt.md)" - cl=".claude/commands/$name.md"; expected="../../.ai/prompts/$name.prompt.md" - if [[ ! -e "$cl" ]]; then fail "$cl: missing Claude command adapter" - elif [[ "$(adapter_target "$cl")" != "$expected" ]]; then fail "$cl: expected target '$expected'"; fi -done - -# ── General-rule root adapters ── -for f in .github/copilot-instructions.md .claude/CLAUDE.md; do - [[ -e "$f" ]] || fail "missing general-rule adapter: $f" -done - -# ── Codex adapters (we claim Codex support) ── -[[ -L AGENTS.md || -f AGENTS.md ]] || fail "AGENTS.md: missing Codex root adapter (-> .ai/rules/general.md)" -[[ -L .agents/skills ]] || fail ".agents/skills: missing Codex skills adapter (-> ../.ai/skills)" - -# ── Hook files ── -for hook in .ai/hooks/pre-commit.md .ai/hooks/agent-stop.md; do - [[ -e "$hook" ]] || fail "missing hook file: $hook" -done - -# ── Content drift guards (WARN only — heuristic, never block on a false positive) ── -if grep -rnE '\.AutoMap\(\)' .ai/rules .ai/skills .ai/agents 2>/dev/null \ - | grep -vE ':[0-9]+:[[:space:]]*#' \ - | grep -vE '(NoAutoMap|never|not |n.t |default|only|disabl)' | grep -q .; then - warn "possible stale .AutoMap() guidance — AutoMap is on by default; call .From<>() directly" -fi -if grep -rnE '\.instructions\.md' .ai/rules .ai/skills .ai/agents .ai/prompts .ai/hooks 2>/dev/null \ - | grep -vE 'managing-ai-rules|validate-ai-setup' | grep -q .; then - warn "'.instructions.md' cross-link leaked into canonical docs — use ./.md" -fi -if grep -rnE '\[EventType\("|\[EventType\(name:|\[EventType\(id:' .ai/rules .ai/skills .ai/agents 2>/dev/null \ - | grep -viE 'never|no arg|not allowed' | grep -q .; then - warn "stale [EventType] argument guidance — new events take no arguments (generation: only for migrations)" -fi -if grep -rnE 'Features//|Features//|Source/Core/Features' .ai/rules .ai/skills .ai/agents .ai/prompts 2>/dev/null | grep -q .; then - warn "possible retired top-level Features/ layout — use /// (Module optional)" -fi -if grep -rnE 'RouteAttribute|\[Route\(' .ai/rules .ai/skills .ai/agents 2>/dev/null | grep -q .; then - warn "stale [Route] for model-bound queries — use [Path]" -fi -if grep -rniE 'custom exception to signal|framework converts it to (an? )?(error|failed)' .ai/rules .ai/skills .ai/prompts 2>/dev/null | grep -q .; then - warn "stale business-rule guidance — return ValidationResult/Result<,>, not a thrown exception" -fi -if grep -rniE '\brtk\b' .ai/rules .ai/skills .ai/agents .ai/prompts 2>/dev/null | grep -q .; then - warn "rtk reference found — rtk was dropped from this corpus" -fi - -if [[ "$failed" -ne 0 ]]; then - printf 'AI corpus validation FAILED.\n' >&2 - exit 1 -fi -printf 'AI corpus validation passed.\n' diff --git a/.ai/prompts/add-business-rule.prompt.md b/.ai/prompts/add-business-rule.prompt.md deleted file mode 100644 index ffd0a20..0000000 --- a/.ai/prompts/add-business-rule.prompt.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -agent: agent -description: Add a business rule (DCB ReadModel argument) or event-store constraint (IConstraint) to an existing command. ---- - -# Add a Business Rule or Constraint - -I need to enforce a new rule on an existing command in a Cratis-based project. - -## Inputs - -- **Command** — name of the existing command, e.g. `RegisterProject` -- **Rule type** — one of: - - **Business rule (DCB)** — add a read model parameter to `Handle()`; the framework fetches and injects the current state before the method runs - - **Event-store constraint** (`IConstraint`) — enforced by Chronicle at the event-log level; typically uniqueness -- **Rule description** — what must be true for the command to succeed, e.g. "project name must be unique across tenant" - -## Business Rules via DCB (ReadModel as argument) - -Business rules that depend on Chronicle event-sourced state are expressed by adding a **read model parameter** to the `Handle()` method. -The framework resolves the read model instance (using the same event-source key as the command) and injects it before `Handle()` runs. - -```csharp -[Command] -public record AddItemToCart(CartId CartId, ItemId ItemId) -{ - /// - /// Adds the item; throws if the cart already holds 3 items. - /// - /// The current cart summary. - /// The event. - /// Thrown when the cart already contains the maximum number of items. - public ItemAddedToCart Handle(CartSummary cart) - { - if (cart.ItemCount >= 3) - throw new CartIsFullException(CartId); - - return new ItemAddedToCart(ItemId); - } -} -``` - -**Rules:** -- The read model parameter type must be a `[ReadModel]`-decorated type in the same feature. -- Throw a **custom exception** (never a built-in one) to signal a violation — the framework converts it to a failed `CommandResult`. -- Multiple read model parameters are allowed if the decision requires more than one projection. - -## Event-Store Constraints (`IConstraint`) - -Constraints are enforced by Chronicle when the event is appended. -Use when the uniqueness or validity guarantee must survive concurrent writes across multiple instances. - -```csharp -public class UniqueProjectName : IConstraint -{ - public void Define(IConstraintBuilder builder) => - builder.Unique(unique => - unique - .On(e => e.Name) - .RemovedWith()); -} -``` - -Constraints are discovered and enforced automatically — no registration required. - -### When to use constraints vs business rules - -| Scenario | Use | -|----------|-----| -| Uniqueness that must survive concurrent writes | `IConstraint` | -| Rule requiring Chronicle event-sourced state | ReadModel parameter in `Handle()` (DCB) | -| Simple synchronous invariant (format, range) | `CommandValidator` | - -## Checklist - -- [ ] Rule is placed in the same slice file as the command -- [ ] ReadModel parameter type is a `[ReadModel]`-decorated type in the same feature -- [ ] Custom exception type (never built-in) is thrown to signal a violation -- [ ] Error messages are user-readable and include relevant context -- [ ] Constraints are auto-discovered — no registration needed -- [ ] Spec added for the failure case — see `write-specs.prompt.md` -- [ ] `dotnet build` passes with zero errors -- [ ] `dotnet test` passes with zero failures diff --git a/.ai/prompts/add-concept.prompt.md b/.ai/prompts/add-concept.prompt.md deleted file mode 100644 index d0bc487..0000000 --- a/.ai/prompts/add-concept.prompt.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -agent: agent -description: Create a strongly-typed Concept (ConceptAs) for a primitive domain value. ---- - -# Add a Concept - -I need to create a **strongly-typed Concept** to wrap a primitive domain value. - -## Inputs - -- **Concept name** — e.g. `ProjectId`, `AuthorName`, `InvoiceNumber` -- **Underlying primitive type** — `Guid`, `string`, `int`, `long`, `decimal`, etc. -- **Is this an event-source ID?** — If yes, an `EventSourceId` implicit conversion is needed -- **Does it need a `New()` factory?** — Typically yes for ID types backed by `Guid` -- **Folder** — where in `Features/` or `Engine/` to place it (matches domain context, NOT a dedicated `Concepts/` folder) - -## Instructions - -Follow `.github/instructions/concepts.instructions.md` exactly. - -### Template - -```csharp -// Copyright (c) Cratis. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using Cratis.Concepts; - -namespace .; - -/// -/// Represents the identity of a . -/// -/// The underlying value. -public record ( Value) : ConceptAs<>(Value) -{ - /// - /// Represents an unset or empty . - /// - public static readonly NotSet = new(); - - /// - /// Implicitly converts a to a . - /// - public static implicit operator ( value) => new(value); -} -``` - -### When the concept is an event-source ID (add after the implicit from primitive) - -```csharp - /// - /// Implicitly converts a to an . - /// - public static implicit operator EventSourceId( id) => new(id.Value.ToString()); -``` - -### When a `New()` factory is needed (Guid-backed IDs) - -```csharp - /// - /// Creates a new with a unique value. - /// - public static New() => new(Guid.NewGuid()); -``` - -### Empty values by type - -| Underlying type | Recommended empty value | -|-----------------|------------------------| -| `Guid` | `Guid.Empty` | -| `string` | `string.Empty` | -| `int` | `0` | -| `long` | `0L` | - -## Placement rules - -- Do NOT create a `Concepts/` folder. -- Place the file in the folder that owns the concept semantically. - - `ProjectId` lives in `Features/Projects/` or the highest-level folder that uses it. - - Shared cross-feature concepts live in the project root source folder. - -## Checklist - -- [ ] Inherits `ConceptAs` (not a plain `record` with a value) -- [ ] Has a `static readonly NotSet` (or `Empty`) sentinel -- [ ] Has an implicit conversion **from** the primitive type -- [ ] Has an implicit conversion **to** `EventSourceId` if used as event-source key -- [ ] Has a `New()` factory if `Guid`-backed -- [ ] Copyright header present -- [ ] `dotnet build` passes with zero errors or warnings diff --git a/.ai/prompts/add-ef-migration.prompt.md b/.ai/prompts/add-ef-migration.prompt.md deleted file mode 100644 index 7547c36..0000000 --- a/.ai/prompts/add-ef-migration.prompt.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -agent: agent -description: Add or update an Entity Framework Core DbContext, table column, or hand-written migration in the project. ---- - -# Add an EF Core Migration - -I need to make a **database schema change** via Entity Framework Core. - -> **Before starting:** Read `.github/instructions/efcore.instructions.md` and `.github/instructions/efcore.specs.instructions.md`. - -## Inputs - -- **Change type** — one of: - - New table / entity - - New column on existing table - - Remove column - - Rename column / table - - New relationship (FK, navigation property) - - Other (describe) -- **Entity name** — the C# record being changed -- **Feature DbContext** — which `ReadOnlyDbContext` or `BaseDbContext` owns this entity - -## Step-by-step process - -### 1 — Update the entity and feature DbContext - -- Add/remove/rename properties on the entity `record` in the **Core** project, co-located with its feature folder. -- Update or create the feature DbContext: - - Inherit from `ReadOnlyDbContext` (read models) or `BaseDbContext` (writable state) — never raw `DbContext` - - Expose `DbSet` as expression-bodied properties: `public DbSet Entities => Set();` - - One focused context per feature — never a "god context" - -### 2 — Add the table name to WellKnownTables - -If this is a new table, add a `const string` to `Database/WellKnownTables.cs` before writing the migration. - -### 3 — Write the migration by hand - -Migrations are **hand-written** in the **Database** project — never use `dotnet ef migrations add`. - -- Place the file in a subfolder matching the entity category: `Database/Missions/v1_1_0.cs` -- Use `v{major}_{minor}_{patch}.cs` naming — never PascalCase names like `AddColumn` -- Namespace must match the folder: `namespace Database.Missions;` -- Always use Cratis Arc cross-database column helpers (`table.StringColumn()`, `table.GuidColumn()`, `table.NumberColumn()`, `table.DateTimeOffsetColumn()`) — never raw `table.Column()` -- Always reference table names from `WellKnownTables` constants — never magic strings - -### 4 — Register the DbContext (if new) - -- Read-only contexts are auto-discovered via `AddReadModelDbContextsWithConnectionStringFromAssemblies` -- Writable contexts need explicit `AddDbContextWithConnectionString` in Infrastructure - -### 5 — Update specs - -- Integration specs using in-memory SQLite pick up schema changes via `context.Database.EnsureCreated()`. -- Follow `.github/instructions/efcore.specs.instructions.md` for testing patterns. - -### 6 — Validate - -Run `dotnet build` and `dotnet test`. Fix all failures before completing. - -## Key rules - -- **Never** use `dotnet ef migrations add` or `dotnet ef database update` -- **Never** hardcode a provider (`UseSqlite`, `UseNpgsql`) — use `UseDatabaseFromConnectionString` -- **Never** mutate state directly through a DbContext — writes flow through Chronicle events -- **Always** use `WellKnownTables` constants and cross-database column helpers diff --git a/.ai/prompts/add-projection.prompt.md b/.ai/prompts/add-projection.prompt.md deleted file mode 100644 index 69d712a..0000000 --- a/.ai/prompts/add-projection.prompt.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -agent: agent -description: Add a Chronicle projection to an existing read model slice. ---- - -# Add a Projection - -I need to add a **Chronicle projection** that populates a read model from events. - -> For **reactors** (automation / translation), use the `add-reactor` prompt instead. - -## Inputs - -- **Events to project from** — list the event types (e.g. `ProjectRegistered`, `ProjectRemoved`) -- **Read model** — paste the `record` type or describe the shape you want - -## Projection rules (mandatory) - -Follow `.github/instructions/vertical-slices.instructions.md` — projection section. - -**Preferred — model-bound:** Place attributes directly on the read model record, no separate class needed. - -```csharp -[ReadModel] -[FromEvent] -public record Project( - [Key] ProjectId Id, - ProjectName Name) -{ - public static ISubject> AllProjects(IMongoCollection collection) => - collection.Observe(); -} -``` - -**Alternative — fluent `IProjectionFor:`** Use for complex joins, children, or conditionals. - -```csharp -public class ProjectProjection : IProjectionFor -{ - public void Define(IProjectionBuilderFor builder) => - builder - .From(b => - b.UsingKey(e => e.ProjectId) - .Set(m => m.Name).To(e => e.Name)) - .RemovedWith(); -} -``` - -**Critical rules:** -- AutoMap is on by default — just call `.From<>()` directly -- Joins are on Chronicle **events**, never on the read model -- Use `.RemovedWith()` for soft-delete events -- **There is NO `ProjectionId Identifier` property — do not add one** - -## After creating the file - -Run `dotnet build` and fix all errors before completing. diff --git a/.ai/prompts/add-reactor.prompt.md b/.ai/prompts/add-reactor.prompt.md deleted file mode 100644 index 5b4beb7..0000000 --- a/.ai/prompts/add-reactor.prompt.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -agent: agent -description: Add a Chronicle reactor (automation or translation) that reacts to events and triggers side effects. ---- - -# Add a Reactor - -I need to add a **Chronicle reactor** that observes events and produces side effects (automation, notifications, translations between slices). - -> **Before starting:** Read `.github/instructions/reactors.instructions.md`. - -## Inputs - -- **Events to react to** — list the event types (e.g. `ProjectRegistered`, `BookReserved`) -- **Purpose** — describe the side-effect or automation to perform -- **Pattern** — `Automation` (reacts to events, triggers side effects) or `Translation` (adapts events across slices by triggering commands) - -## Reactor rules (mandatory) - -```csharp -public class AutomationName(IDependency dependency) : IReactor -{ - /// - /// Handles events. - /// - /// The event. - /// The event context. - public Task HandleSomeEvent(SomeEvent @event, EventContext context) => - dependency.DoSomethingWith(@event); -} -``` - -**Critical rules:** -- `IReactor` is a **marker interface** — no methods to implement -- Event dispatch is by first-parameter type; method name can be anything descriptive -- `EventContext` is optional — omit if event metadata is not needed -- Reactors MUST be idempotent — they may be called more than once for the same event -- Do not query the read model inside the reactor — use the event data directly -- To produce new events, inject `ICommandPipeline` and execute a command — never use `IEventLog` directly - -## Translation pattern - -If the reactor adapts events by triggering commands in another slice: - -```csharp -public class StockKeeping(IStockKeeper stockKeeper, ICommandPipeline commandPipeline) : IReactor -{ - /// - /// Decreases stock when a book is reserved. - /// - /// The event. - /// The event context. - public async Task BookReserved(BookReserved @event, EventContext context) => - await commandPipeline.Execute(new DecreaseStock(@event.Isbn, await stockKeeper.GetStock(@event.Isbn))); -} -``` - -## After creating the file - -Run `dotnet build` and fix all errors before completing. diff --git a/.ai/prompts/add-reducer.prompt.md b/.ai/prompts/add-reducer.prompt.md deleted file mode 100644 index 02dccec..0000000 --- a/.ai/prompts/add-reducer.prompt.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -agent: agent -description: Add a Chronicle reducer to a read model when model-bound and fluent projections cannot express the state transition. ---- - -# Add a Reducer - -Add an `IReducerFor` reducer — the last-resort escape hatch for a "current state + event → next state" transition that model-bound projection attributes and fluent `IProjectionFor` cannot express. Invoke the **add-reducer** skill and follow `.ai/rules/vertical-slices.md`. For ordinary projections, use the **add-projection** prompt instead. - -## Confirm first - -- **Why a reducer** (which model-bound / fluent approach was ruled out) and the **events** + **read model** shape. - -## Key rules - -- Reducers are the **last resort** — exhaust model-bound attributes and fluent `IProjectionFor` first. -- Handle the **nullable current** state (the first event has no prior state). -- Keep reducers passive and deterministic — no side effects, no reading other read models. - -Run a clean build afterward. The skill carries the detail; don't duplicate it here. diff --git a/.ai/prompts/audit-hooks.prompt.md b/.ai/prompts/audit-hooks.prompt.md deleted file mode 100644 index af4940f..0000000 --- a/.ai/prompts/audit-hooks.prompt.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -agent: agent -description: Audit hook files for correctness, portability, and enforcement coverage. ---- - -# Audit Hooks - -Review `.ai/hooks/` and report whether hooks are: - -- enforcing the intended policy -- portable across environments -- aligned with canonical source rules -- using bash-first commands for script execution - -Focus on gaps, risks, and missing checks. If improvements are obvious and low-risk, propose exact edits. diff --git a/.ai/prompts/check-doc-drift.prompt.md b/.ai/prompts/check-doc-drift.prompt.md deleted file mode 100644 index 6e464e3..0000000 --- a/.ai/prompts/check-doc-drift.prompt.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -agent: agent -description: Check for drift between AI assets and documentation inventory. ---- - -# Check Documentation Drift - -Check whether AI assets and docs are in sync: - -- `.ai/rules/` vs documented instruction inventory -- `.ai/skills/` vs documented skill inventory -- `.ai/agents/` vs documented agent roster -- `.ai/hooks/` vs architecture docs - -Report: - -1. Missing documentation entries. -2. Stale documentation entries. -3. Suggested updates by file. - -Apply updates only if asked. diff --git a/.ai/prompts/code-review.prompt.md b/.ai/prompts/code-review.prompt.md deleted file mode 100644 index afd98bd..0000000 --- a/.ai/prompts/code-review.prompt.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -description: 'Review a proposed change for correctness, maintainability, and security.' ---- - -# Code Review Prompt - -Review the proposed change for correctness, maintainability, and security. -Focus on actionable findings and minimize false positives. diff --git a/.ai/prompts/new-feature.prompt.md b/.ai/prompts/new-feature.prompt.md deleted file mode 100644 index 46b6892..0000000 --- a/.ai/prompts/new-feature.prompt.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -description: 'Implement a requested feature as a vertical slice with focused changes and behavior tests.' ---- - -# New Feature Prompt - -Implement the requested feature as a vertical slice with minimal, focused changes. -Add or update tests for behavior changes and validate build/test before completion. diff --git a/.ai/prompts/new-vertical-slice.prompt.md b/.ai/prompts/new-vertical-slice.prompt.md deleted file mode 100644 index fc1b21c..0000000 --- a/.ai/prompts/new-vertical-slice.prompt.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -agent: agent -description: Scaffold a complete vertical slice (backend + specs + frontend) for a Cratis-based project. ---- - -# New Vertical Slice - -I need you to implement a complete **vertical slice** for a Cratis-based project. - -## Inputs - -Please provide (or I'll ask): -- **Feature name** — e.g. `Projects` -- **Slice name** — e.g. `Registration`, `Listing`, `Removal` -- **Slice type** — one of: - - `State Change` — command that appends events and changes read models - - `State View` — query that reads from a read model - - `Automation` — background reactor triggered by events - - `Translation` — transforms/enriches events into other events -- **Domain description** — what the slice does in plain language -- **Properties** — fields on the command/query and their types - -## What I want produced - -Follow `.github/instructions/vertical-slices.instructions.md` exactly. - -### Phase 1 — Backend (delegate to `backend-developer` agent) - -For a **State Change** slice, produce (in this order): -1. Concept types (if new strongly-typed IDs are needed) -2. Command `record` with `Handle()` method, validation, and business rules -3. Event `record` with `[EventType]` attribute (no arguments) -4. Read model `record` with `[ReadModel]` and model-bound projection attributes (`[FromEvent]`, `[Key]`, etc.) - - Use fluent `IProjectionFor` only when model-bound attributes don't fit - -For a **State View** slice, produce: -1. Read model `record` with `[ReadModel]`, model-bound projection attributes (`[FromEvent]`, `[Key]`, etc.), and a static query method - - Use fluent `IProjectionFor` only when model-bound attributes don't fit - -Run `dotnet build` after creating the `.cs` file. Fix all errors before proceeding. - -### Phase 2 — Specs (delegate to `spec-writer` agent, State Change slices only) - -For each command, write specs covering: -- Happy path (command succeeds, correct event appended) -- Each validation failure -- Each business rule violation -- Each constraint violation - -Run `dotnet test` and fix all failures before proceeding. - -### Phase 3 — Frontend (delegate to `frontend-developer` agent) - -1. Create React component(s) in `Features///` -2. Use auto-generated proxy types from `dotnet build` -3. Use `CommandDialog` for command-based dialogs -4. Update the feature composition page -5. Update routing if a new page is introduced - -Run `yarn lint` and `npx tsc -b`. Fix all errors before proceeding. - -### Phase 4 — Quality Gates - -- `dotnet build` — zero errors/warnings -- `dotnet test` — zero failures -- `yarn lint` — zero errors -- `npx tsc -b` — zero errors - -## Constraints - -- Namespace: `..` — detect `` from existing source files -- No abbreviations in TypeScript -- No hard-coded colours — PrimeReact CSS variables only -- Copyright header on every file -- README.md for complex component folders diff --git a/.ai/prompts/review-pr.prompt.md b/.ai/prompts/review-pr.prompt.md deleted file mode 100644 index 36d7c58..0000000 --- a/.ai/prompts/review-pr.prompt.md +++ /dev/null @@ -1,94 +0,0 @@ ---- -agent: agent -description: Review a pull request against all Cratis project standards and produce a structured review report. ---- - -# Review Pull Request - -I need a structured **code review** of a pull request against all Cratis project standards. - -## Inputs - -- **PR number or branch name** — so I can examine the changed files -- **Scope** — which repos / projects are affected - -## Review process - -### Step 1 — Gather context - -- List all changed files in the PR -- Read each changed file in full -- Identify the slice type(s) affected (State Change / State View / Automation / Translation) - -### Step 2 — Architecture review - -Delegate to the `code-reviewer` agent with all changed files. - -Check against: -- `.github/instructions/vertical-slices.instructions.md` -- `.github/instructions/csharp.instructions.md` -- `.github/instructions/typescript.instructions.md` -- `.github/instructions/components.instructions.md` -- `.github/instructions/concepts.instructions.md` -- `.github/copilot-instructions.md` - -### Step 3 — Security review - -Delegate to the `security-reviewer` agent with all changed files. - -Check all security categories: -- Input validation & injection -- Auth / authz -- Sensitive data exposure -- Secrets & configuration -- Dependency & serialisation safety -- Event sourcing specifics -- Frontend attack surface - -### Step 4 — Spec coverage - -- Confirm every State Change command has specs covering happy path + failure cases -- Confirm `dotnet test` output shows no regressions (if available) - -### Step 5 — Documentation - -- If a new public API, feature, or component was added, confirm documentation was updated -- If a breaking change was introduced, confirm it is called out in the PR description - ---- - -## Output format - -``` -## Pull Request Review — # - -### Summary -<2–3 sentence overview of what the PR does> - -### Architecture — ✅ / ⚠️ / ❌ - - -### Security — ✅ / ⚠️ / ❌ - - -### Spec Coverage — ✅ / ⚠️ / ❌ - - -### Documentation — ✅ / ⚠️ / ❌ - - -### Overall verdict -**✅ Approved** / **⚠️ Approved with comments** / **❌ Changes requested** - -**Blocking issues** (must fix before merge): -1. … - -**Suggestions** (non-blocking): -1. … -``` - -## Conventions reminder - -- Blocking issues = anything that violates a `MUST` rule in the instructions -- Suggestions = style improvements, optional enhancements, or `SHOULD` rules -- Be specific: always include file, line number, and corrected code for blocking issues diff --git a/.ai/prompts/review-skill.prompt.md b/.ai/prompts/review-skill.prompt.md deleted file mode 100644 index 82cb681..0000000 --- a/.ai/prompts/review-skill.prompt.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -agent: agent -description: Review one skill for clarity, trigger quality, and maintainability. ---- - -# Review Skill - -Review a specific skill folder under `.ai/skills/` for: - -- trigger quality in the description -- correctness of workflow steps -- overlap with existing skills -- missing references or checklists -- opportunities to split large files - -Return findings first, then proposed edits. diff --git a/.ai/prompts/scaffold-feature.prompt.md b/.ai/prompts/scaffold-feature.prompt.md deleted file mode 100644 index fcd83bc..0000000 --- a/.ai/prompts/scaffold-feature.prompt.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -agent: agent -description: Scaffold a new feature — folder structure, composition page, routing, and first slice skeleton. ---- - -# Scaffold a Feature - -I need to scaffold a **complete new feature** in a Cratis-based project. -This creates the folder structure, composition page, and routing — ready for slices to be added. - -## Inputs - -- **Feature name** — PascalCase, e.g. `Projects`, `Invoices`, `UserManagement` -- **Route path** — URL path for the feature page, e.g. `/projects` -- **Navigation label** — Text shown in the sidebar/navigation, e.g. `Projects` -- **Navigation icon** — Name from `react-icons/md`, e.g. `MdFolderOpen` -- **First slice** — Optional: describe one initial slice to implement after scaffolding (can also be done later with `new-vertical-slice.prompt.md`) - -## What to produce - -### 1 — Feature folder - -``` -Features// -├── .tsx ← composition page -├── .css ← feature-level styles (may be empty) -└── index.ts ← re-exports the composition page -``` - -### 2 — Composition page (`.tsx`) - -```tsx -// Copyright (c) Cratis. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -import { Page } from '../../Core/Page'; - -export const = () => { - return ( - - {/* Slices rendered here */} - - ); -}; -``` - -### 3 — Update routing - -Add the feature to the application router. Locate the router configuration (typically `App.tsx` or a `routes.ts` file) and add: - -```tsx -import { } from './Features/'; - -// Inside the route definitions: -{ path: '', element: < /> } -``` - -### 4 — Update navigation - -Locate the navigation/sidebar configuration and add: - -```tsx -import * as mdIcons from 'react-icons/md'; - -{ - label: '', - icon: mdIcons., - url: '' -} -``` - -### 5 — `index.ts` - -```typescript -// Copyright (c) Cratis. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -export { } from './'; -``` - -## Validation - -After scaffolding, run: -- `yarn lint` — zero errors -- `npx tsc -b` — zero errors -- Confirm the new route renders an empty page without runtime errors - -## Next step - -Once scaffolding is complete, use `new-vertical-slice.prompt.md` to add slices to the feature. -Each slice's component will be imported and composed into `.tsx`. diff --git a/.ai/prompts/ship-changes.prompt.md b/.ai/prompts/ship-changes.prompt.md deleted file mode 100644 index fb4b8eb..0000000 --- a/.ai/prompts/ship-changes.prompt.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -agent: agent -description: > - Ship local changes: create a branch, make logical commits, push, open and - label a PR with a proper description, merge it, and delete the branch. ---- - -# Ship Changes - -Ship the current local modifications to `main` through the standard -branch → commits → PR → merge → cleanup workflow. - -## Inputs - -- **What changed** — brief description of the work (used for branch name and PR title) -- **Label** — `patch`, `minor`, or `major`, or omit entirely if no label should be applied -- **Related issue** — optional GitHub issue number; if unknown, search first - -Load and follow the full instructions from the `ship-changes` skill. diff --git a/.ai/prompts/verify-ai-setup.prompt.md b/.ai/prompts/verify-ai-setup.prompt.md deleted file mode 100644 index f854402..0000000 --- a/.ai/prompts/verify-ai-setup.prompt.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -agent: agent -description: Validate AI framework setup integrity, canonical source conventions, and symlink health. ---- - -# Verify AI Setup - -Validate the repository AI setup by running: - -```bash -bash .ai/hooks/scripts/validate-ai-setup.sh -``` - -If anything fails: - -1. List every failure with the exact file path. -2. Explain whether the issue is canonical-source drift, missing metadata, or broken links. -3. Propose the smallest safe fix. -4. Apply fixes if requested. diff --git a/.ai/prompts/write-documentation.prompt.md b/.ai/prompts/write-documentation.prompt.md deleted file mode 100644 index 675f0a9..0000000 --- a/.ai/prompts/write-documentation.prompt.md +++ /dev/null @@ -1,48 +0,0 @@ ---- -agent: agent -description: "Write DocFX documentation following the Diataxis framework." ---- - -# Write Documentation - -I need you to write **DocFX documentation** for a feature, component, or concept using the **Diataxis framework**. - -## Inputs - -- **Subject** — what to document (e.g. "the Projects feature", "the CommandDialog component", "the ConceptAs type") -- **Document type** — one of: - - **Tutorial** — step-by-step lesson for newcomers - - **How-to Guide** — recipe for accomplishing a specific task - - **Reference** — exhaustive technical description (APIs, attributes, configuration) - - **Explanation** — discussion of concepts, trade-offs, and architecture -- **Target audience** — e.g. new developer, experienced contributor, framework consumer -- **Existing source files** — paste or reference the code to document - -## Instructions - -Follow `.github/instructions/documentation.instructions.md` and the `write-documentation` skill exactly. - -### Workflow - -1. **Clarify** — Confirm the document type, audience, goal, and scope. Ask if anything is ambiguous. -2. **Propose structure** — Present an outline (headings + one-line descriptions). Wait for approval. -3. **Write** — Produce full DocFX-compatible Markdown with correct `toc.yml` entries. - -### File structure - -For a new topic under an existing section, create a folder with an `index.md` and `toc.yml`. Update the parent `toc.yml` to include the new topic. - -### Writing style - -- Active voice, present tense, second person -- Lead with the most important information -- Every code example must be complete and correct -- Link to related topics using relative paths -- Use Mermaid diagrams for architecture, sequence flows, and state transitions -- Do not document internal implementation details in user-facing docs - -### Validation - -- Verify `toc.yml` is valid YAML -- Verify all `href` values point to files that exist -- Verify all Mermaid blocks are valid diff --git a/.ai/prompts/write-specs.prompt.md b/.ai/prompts/write-specs.prompt.md deleted file mode 100644 index 188e045..0000000 --- a/.ai/prompts/write-specs.prompt.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -agent: agent -description: Write comprehensive BDD specs for an existing vertical slice command or query. ---- - -# Write Specs - -I need you to write **comprehensive specs** for an existing vertical slice. - -## What to provide - -Paste or reference the slice file (`.cs`) you want covered. - -## Instructions - -Follow `.github/instructions/specs.csharp.instructions.md` and `.github/instructions/specs.instructions.md`. - -### For a State Change slice (command) - -Write a spec class for **each meaningful outcome**: - -1. **Happy path** — command succeeds, expected event is appended, sequence number advanced. -2. **Each validation failure** — one spec per validation rule. -3. **Each business rule violation** — one spec per condition in `Handle()` that inspects a ReadModel argument (DCB pattern). -4. **Each constraint violation** — one spec per `IConstraint` (e.g. uniqueness). - -### Structure - -``` -Features/// -└── when_/ - ├── and_.cs - ├── and_.cs - └── and_.cs -``` - -### C# spec shape - -```csharp -using context = ...when_.and_.context; - -namespace ...when_; - -[Collection(ChronicleCollection.Name)] -public class and_(context context) : Given(context) -{ - public class context(ChronicleOutOfProcessFixture fixture) : given.an_http_client(fixture) - { - public CommandResult? Result; - - async Task Establish() { /* optional: seed events */ } - - async Task Because() - { - Result = await Client.ExecuteCommand<>( - "/api//", - new (...)); - } - } - - [Fact] void should_() => ...; -} -``` - -### Assertions - -Use `ShouldBeFalse()`, `ShouldBeTrue()`, `ShouldEqual()`, `ShouldHaveTailSequenceNumber()` — never raw `Assert.*`. - -## Validation - -Run `dotnet test` after writing specs. Fix any failures before completing. diff --git a/.ai/rules/code-quality.csharp.md b/.ai/rules/code-quality.csharp.md deleted file mode 100644 index a24b621..0000000 --- a/.ai/rules/code-quality.csharp.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -applyTo: "**/*.cs" ---- - -# Code Quality — C# - -C#-specific applications of the general [Code Quality](./code-quality.instructions.md) principles. - -## Composition over Inheritance - -Use constructor injection to compose behavior. Primary constructors make this natural in modern C# — the type's dependencies are visible at a glance and can be substituted in tests. - -```csharp -// ❌ Inheritance — child is tightly coupled to parent internals -public class ReportExporter : BaseExporter -{ - public override void Export(Report report) { ... } -} - -// ✅ Composition — behavior is injected and interchangeable -public class ReportExporter(IExportStrategy strategy) -{ - public void Export(Report report) => strategy.Execute(report); -} -``` - -**Rules:** -- Never extend a concrete class to add or change behavior — inject a collaborator instead. -- Use interfaces and `ConceptAs` record wrappers rather than inheritance chains. -- Inheritance is acceptable only for framework integration points with a well-defined extension mechanism (e.g. `Specification`, `Migration`, `AggregateRoot`). - -## Open/Closed Principle - -The framework's `IInstancesOf` mechanism makes the open/closed pattern effortless — adding a new implementation is all it takes to extend behavior. Use it instead of growing `switch` statements. - -```csharp -// ❌ Modified every time a new format is added -public class ReportFormatter -{ - public string Format(Report report, string formatType) - { - if (formatType == "csv") return FormatAsCsv(report); - if (formatType == "json") return FormatAsJson(report); - throw new UnknownFormat(formatType); - } -} - -// ✅ New formats added by implementing the interface — no existing code changes -public interface IReportFormatter -{ - string Format(Report report); -} - -public class CsvReportFormatter : IReportFormatter { ... } -public class JsonReportFormatter : IReportFormatter { ... } -``` - -**Rules:** -- Prefer strategy interfaces over `switch`/`if-else` chains that grow over time. -- Use `IInstancesOf` to discover all implementations by convention — no manual registration needed. -- Design public APIs as contracts (interfaces/records) rather than concrete implementations. - -## Separation of Concerns - -The Chronicle + Arc stack has clear layer boundaries. Violating them creates coupling that is hard to undo. - -**Rules:** -- Domain types must not reference EF Core, MongoDB, or HTTP concepts directly. -- Command handlers express intent in domain terms — they delegate persistence and I/O to injected collaborators. -- Projections build read models; they must not trigger commands or produce side effects. -- Reactors handle side effects; they must not directly read or write the event log. - -## Low Coupling - -**Rules:** -- Depend on abstractions (interfaces, records), not on concrete implementations. -- Use constructor injection — it makes dependencies explicit and testable. -- Avoid reaching through an object to call methods on its dependencies (`a.B.C.Do()` is a sign of tight coupling). -- Limit constructor dependencies to four or five — more is a signal the type is doing too much. -- Never reference types from unrelated features directly; go through a shared contract or event instead. - -## Cross-Cutting Concerns - -**Rules:** -- Never write logging statements directly inside command handlers, projections, or domain types. Use the `[LoggerMessage]` pattern in a co-located `*Logging.cs` partial class. -- Never perform authorization checks inside domain logic — express them as attributes or middleware applied at the boundary. -- Never duplicate error-handling or retry logic across handlers — centralize it in a pipeline or middleware. -- Use `ICommandPipeline`, middleware, and decorators to apply cross-cutting concerns at the infrastructure layer so that domain code remains unaware of them. -- When you notice the same infrastructural pattern appearing in two or more places (logging a specific event, catching a specific exception, checking a specific condition), extract it into a shared cross-cutting mechanism rather than duplicating it. diff --git a/.ai/rules/code-quality.md b/.ai/rules/code-quality.md deleted file mode 100644 index c429fe3..0000000 --- a/.ai/rules/code-quality.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -applyTo: "**/*" ---- - -# Code Quality - -Good code is not just code that works — it is code that can be understood, changed, and extended safely. The principles below are the foundation for writing code that remains maintainable as the system grows. They are not abstract ideals; each one has a concrete, practical consequence for how you write and structure code in this project. - -When these principles don't explicitly cover a situation, apply these values to make a judgment call. See the language-specific guides for concrete rules and examples: -- [Code Quality — C#](./code-quality.csharp.instructions.md) -- [Code Quality — TypeScript](./code-quality.typescript.instructions.md) - -## Composition over Inheritance - -Prefer composing behavior from smaller, focused collaborators over building class hierarchies. Inheritance couples the child tightly to the parent's internal structure — a change to the parent can break every subclass. Composition keeps collaborators independent and replaceable. - -**Rules:** -- Never extend a concrete class to add or change behavior — inject a collaborator instead. -- Inheritance is acceptable only for framework integration points where a base class is part of a well-defined extension mechanism. - -## Single Responsibility Principle - -Every type and every method should have **one reason to change** — it should do one thing and do it well. A class that fetches data, transforms it, validates it, and sends an email has four reasons to change. When any of those concerns shifts, you have to touch — and risk breaking — all the others. - -**Rules:** -- A class or method that requires a comment explaining what each section does is a sign it should be split. -- Methods longer than ~20 lines are a signal they are doing too much — extract collaborators or helper methods. -- If a type needs collaborators from two unrelated domains, question whether it has two responsibilities. -- Follow the [File Size Guideline](#file-size--200-line-guideline) below. - -## Open/Closed Principle - -Types should be **open for extension, closed for modification**. Once a type is in use, changing its internals to support new behavior risks breaking existing callers. Instead, design extension points — interfaces, strategies, event hooks — that allow new behavior to be added without touching existing code. - -**Rules:** -- Prefer strategy interfaces over `switch`/`if-else` chains that grow over time. -- Design public APIs as contracts (interfaces/records) rather than concrete implementations. - -## Separation of Concerns - -Each layer and each module should own exactly one concern. Mixing concerns — for example, querying the database and formatting the HTTP response in the same method — creates entanglement that makes both concerns harder to change or test independently. - -**Rules:** -- Keep domain logic out of infrastructure — domain types must not reference infrastructure or transport concepts directly. -- Keep infrastructure out of domain logic — handlers and domain types express intent; they delegate to collaborators for persistence, messaging, and I/O. - -## Low Coupling - -Coupling is the degree to which one module depends on the internals of another. High coupling means a change in one place forces changes everywhere else. Low coupling means modules can evolve independently. - -**Rules:** -- Depend on abstractions, not on concrete implementations. -- Avoid reaching through an object to call methods on its dependencies — this is a sign of tight coupling. -- Limit the number of dependencies a single type takes — more than four or five is a signal it is doing too much. -- Never reference types from unrelated features directly; go through a shared contract or event instead. - -## High Cohesion - -Cohesion measures how closely related the responsibilities within a module are. A highly cohesive class has all its methods and properties working together toward a single goal. A low-cohesion class is a collection of unrelated utilities that happen to live in the same file. - -**Rules:** -- Group code by feature, not by technical role — everything for a behavior belongs together. -- If you find yourself writing methods in a type that use completely different sets of fields or dependencies, the type likely needs to be split. -- Utilities and helpers are acceptable only when the operations they provide are genuinely shared across features; otherwise, keep logic in the feature that owns it. - -## File Size — 200-Line Guideline - -A file exceeding **200 lines** is a strong signal that it contains too many responsibilities. This is not a hard limit — some files are legitimately longer — but whenever you find yourself adding to a file that already approaches this size, stop and ask: can this be split? - -**Rules:** -- When a file crosses 200 lines, look for natural split points: a sub-concept that could become its own type, a behavior that could move to a collaborator, or a section that belongs in a different layer. -- Aim for files that can be understood in a single reading without scrolling. -- Instruction and documentation files follow the same principle — a guide over 200 lines usually contains multiple distinct topics that deserve their own files. - -## Cross-Cutting Concerns - -Cross-cutting concerns — logging, validation, authorization, error handling, metrics, caching — affect many parts of the system but belong to none of them. Scattering them through business logic creates noise and duplication. Centralizing them in infrastructure keeps domain code clean. - -**Rules:** -- Never write logging or authorization checks inside domain logic — apply them at the infrastructure boundary. -- Never duplicate error-handling or retry logic — centralize it in a pipeline, middleware, or decorator. -- When you notice the same infrastructural pattern appearing in two or more places, extract it into a shared cross-cutting mechanism rather than duplicating it. diff --git a/.ai/rules/code-quality.typescript.md b/.ai/rules/code-quality.typescript.md deleted file mode 100644 index 715cb99..0000000 --- a/.ai/rules/code-quality.typescript.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -applyTo: "**/*.ts,**/*.tsx" ---- - -# Code Quality — TypeScript - -TypeScript/React-specific applications of the general [Code Quality](./code-quality.instructions.md) principles. - -## Composition over Inheritance - -React is built on composition — components accept children, hooks compose other hooks, and higher-order utilities wrap behavior. Avoid class hierarchies entirely; the language and framework have moved on. - -```tsx -// ❌ Inheritance — fragile, couples component to base class internals -class SpecialButton extends BaseButton { - override render() { ... } -} - -// ✅ Composition — wrap or delegate, keep each piece independent -export const SpecialButton = ({ onClick, label }: SpecialButtonProps) => ( - -); -``` - -**Rules:** -- Never use class inheritance for React components — compose with props, children, and hooks instead. -- Extract repeated UI patterns into small, focused components rather than adding conditions to a shared parent. -- Extract repeated logic into custom hooks — a hook that does two unrelated things should be two hooks. - -## Open/Closed Principle - -TypeScript discriminated unions and generic constraints let you add new variants without touching existing code. Prefer them over ever-growing `if-else` / `switch` chains. - -```ts -// ❌ Grows every time a new shape is needed -function area(shape: string, a: number, b?: number): number { - if (shape === 'circle') return Math.PI * a * a; - if (shape === 'rectangle') return a * (b ?? 0); - throw new Error('Unknown shape'); -} - -// ✅ New shapes extend the union — existing handler functions are untouched -type Circle = { kind: 'circle'; radius: number }; -type Rectangle = { kind: 'rectangle'; width: number; height: number }; -type Shape = Circle | Rectangle; - -function area(shape: Shape): number { - switch (shape.kind) { - case 'circle': return Math.PI * shape.radius ** 2; - case 'rectangle': return shape.width * shape.height; - } -} -``` - -**Rules:** -- Model variation with discriminated unions rather than optional fields or string literals. -- Design utility functions to accept an interface or generic constraint so new types can be handled by adding a new implementation, not by editing existing code. - -## Separation of Concerns - -React components have one job: render UI and delegate events. Keep data-fetching, business logic, and side effects in dedicated hooks or services — not inline in the component body. - -**Rules:** -- Never write data-fetching or business logic directly in a component — extract it into a hook. -- Component files (`.tsx`) must not import from infrastructure layers such as HTTP clients or storage utilities directly — go through an abstraction or a generated proxy. -- Keep style concerns in co-located `.css` files; keep data concerns in hooks; keep rendering in the component. - -## Low Coupling - -Coupling in TypeScript is often hidden in deep import paths. Barrel files and path aliases make coupling explicit and keep refactoring safe. - -**Rules:** -- Import from barrel `index.ts` files, not from deep internal paths — this limits the blast radius of refactoring. -- Use the configured path aliases (e.g. `Strings`, `Components`) rather than relative `../../../` chains. -- Never import from an unrelated feature's internal files — go through that feature's public barrel export. -- Keep the number of imports in a single file reasonable — many imports from many different areas is a coupling smell. - -## Cross-Cutting Concerns - -**Rules:** -- Use React Error Boundaries to centralize error display — never scatter `try/catch` blocks inside component render paths. -- Use a single top-level provider or hook for global state (e.g. authentication, theming) — never drill context down through many component layers. -- Centralize API error handling in a shared hook or service layer — do not duplicate toast/notification logic per component. -- Apply logging, analytics, and monitoring at the infrastructure edge (e.g. router callbacks, global error handlers) so that feature components remain unaware of them. diff --git a/.ai/rules/components.md b/.ai/rules/components.md deleted file mode 100644 index d1ad855..0000000 --- a/.ai/rules/components.md +++ /dev/null @@ -1,121 +0,0 @@ ---- -applyTo: "**/*.tsx" ---- - -# Building React Components - -## Composition over Monoliths - -A well-built component tree is like a well-organized kitchen — every tool has a place, and you can find what you need without opening every drawer. Large components that do everything are hard to understand, hard to test, and hard to change without breaking something unrelated. - -- Split components into small, focused pieces and compose them together. Each component should have a single, clear responsibility. -- Parent components own state and event handlers; children receive props. This makes data flow predictable and debuggable. -- If you find yourself writing a block comment like `// Author list section` inside a component, that section should be its own component. The comment is a code smell — the component name should provide that context instead. - -## Folder Structure - -- Single-file component → place directly in the parent feature folder. -- Multi-file component (sub-components, hooks, CSS) → create a folder named after the component: - -``` -PrototypeWindow/ - PrototypeWindow.tsx ← composition root - PrototypeWindow.css ← styles for the composition - TitleBar.tsx ← sub-component - CanvasArea.tsx ← sub-component - ResizeHandle.tsx ← sub-component - index.ts ← re-exports public API -``` - -Add an `index.ts` that re-exports the public surface so import paths stay stable. - -## Styling - -Consistent styling comes from discipline: static styles in CSS files, dynamic values inline, and colors always from PrimeReact's design tokens. This ensures theming works automatically and no component breaks the visual language. - -- Use **CSS classes in co-located `.css` files** for static styles. -- Each component must have its own CSS file — never add sub-component styles to the parent's CSS. This keeps styles co-located with the component they belong to. -- The composition root's CSS only contains layout/grid rules for positioning children — it should not style the children themselves. -- Use inline `style` props **only** for runtime-dynamic values (pixel positions, computed sizes). -- Use **PrimeReact CSS variables** for all colors, backgrounds, borders. This ensures the application respects theming and dark/light mode switches: - - `var(--surface-0)` through `var(--surface-900)`, `var(--surface-card)`, `var(--surface-border)`, `var(--surface-ground)` - - `var(--text-color)`, `var(--text-color-secondary)`, `var(--primary-color)`, `var(--primary-color-text)`, `var(--highlight-bg)` - - Never hard-code hex or `rgb()` for UI chrome — it will break when themes change. Only hard-code colors that are intentionally theme-independent (e.g. brand-specific accent dots, traffic-light indicators). -- Name CSS classes with a BEM-like prefix matching the component name. - -## Props - -Props are a component's public API. They should be clear, minimal, and well-documented. - -- Each sub-component declares its own `*Props` interface with JSDoc on every prop. -- Pass only needed props — avoid threading large prop bags through component trees. -- Event handlers follow `on*` naming: `onPointerDown`, `onSelect`. - -## Dialogs - -See [dialogs.instructions.md](./dialogs.instructions.md) for the full dialog guide. - -**Summary:** Never import `Dialog` from `primereact/dialog`. Use `CommandDialog` from `@cratis/components/CommandDialog` for command-executing dialogs and `Dialog` from `@cratis/components/Dialogs` for data-collection dialogs. Do not render manual `