@cratis/pi 0.0.1 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +18 -37
- package/package/corpus/agents/backend-developer.md +125 -0
- package/package/corpus/agents/code-reviewer.md +165 -0
- package/package/corpus/agents/coordinator.md +163 -0
- package/package/corpus/agents/frontend-developer.md +246 -0
- package/package/corpus/agents/orchestrator.md +196 -0
- package/package/corpus/agents/performance-reviewer.md +109 -0
- package/package/corpus/agents/planner.md +145 -0
- package/package/corpus/agents/repository-investigation-reviewer.md +45 -0
- package/package/corpus/agents/repository-investigator.md +50 -0
- package/package/corpus/agents/security-reviewer.md +118 -0
- package/package/corpus/agents/slice-implementer.md +59 -0
- package/package/corpus/agents/spec-writer.md +149 -0
- package/package/corpus/harnesses/pi/extensions/cratis-hooks/index.ts +213 -0
- package/package/corpus/harnesses/pi/extensions/cratis-rules/index.ts +27 -0
- package/package/corpus/harnesses/pi/extensions/package.json +4 -0
- package/package/corpus/harnesses/pi/extensions/subagent/agents.ts +167 -0
- package/package/corpus/harnesses/pi/extensions/subagent/index.ts +352 -0
- package/package/corpus/hooks/README.md +434 -0
- package/package/corpus/hooks/agent-stop.md +49 -0
- package/package/corpus/hooks/pre-commit.md +47 -0
- package/package/corpus/hooks/scripts/cratis-guard-writes.sh +87 -0
- package/package/corpus/hooks/scripts/cratis-nuget-pins.txt +11 -0
- package/package/corpus/hooks/scripts/cratis-pattern-scan.sh +197 -0
- package/package/corpus/hooks/scripts/cratis-patterns.json +84 -0
- package/package/corpus/hooks/scripts/cratis-quality-gate.sh +219 -0
- package/package/corpus/hooks/scripts/hook-lib.sh +152 -0
- package/package/corpus/hooks/scripts/quality-gates.json +261 -0
- package/package/corpus/hooks/scripts/type-references-allowlist.txt +71 -0
- package/package/corpus/hooks/scripts/validate-package-imports.sh +166 -0
- package/package/corpus/hooks/scripts/validate-package-subpaths.sh +120 -0
- package/package/corpus/hooks/scripts/validate-type-references.sh +308 -0
- package/package/corpus/hooks/settings.template.json +40 -0
- package/package/corpus/prompts/add-business-rule.prompt.md +22 -0
- package/package/corpus/prompts/add-concept.prompt.md +17 -0
- package/package/corpus/prompts/add-ef-migration.prompt.md +24 -0
- package/package/corpus/prompts/add-projection.prompt.md +20 -0
- package/package/corpus/prompts/add-reactor.prompt.md +22 -0
- package/package/corpus/prompts/add-reducer.prompt.md +20 -0
- package/package/corpus/prompts/audit-hooks.prompt.md +15 -0
- package/package/corpus/prompts/check-doc-drift.prompt.md +21 -0
- package/package/corpus/prompts/code-review.prompt.md +9 -0
- package/package/corpus/prompts/new-feature.prompt.md +9 -0
- package/package/corpus/prompts/new-vertical-slice.prompt.md +18 -0
- package/package/corpus/prompts/review-pr.prompt.md +35 -0
- package/package/corpus/prompts/review-skill.prompt.md +16 -0
- package/package/corpus/prompts/scaffold-feature.prompt.md +16 -0
- package/package/corpus/prompts/ship-changes.prompt.md +20 -0
- package/package/corpus/prompts/verify-ai-setup.prompt.md +19 -0
- package/package/corpus/prompts/write-documentation.prompt.md +21 -0
- package/package/corpus/prompts/write-specs.prompt.md +22 -0
- package/package/corpus/rules/capability-is-not-authority.md +31 -0
- package/package/corpus/rules/code-quality.csharp.md +91 -0
- package/package/corpus/rules/code-quality.md +82 -0
- package/package/corpus/rules/code-quality.typescript.md +89 -0
- package/package/corpus/rules/components.md +207 -0
- package/package/corpus/rules/concepts.md +115 -0
- package/package/corpus/rules/csharp.md +269 -0
- package/package/corpus/rules/dialogs.md +264 -0
- package/package/corpus/rules/documentation-structure-and-formatting.md +148 -0
- package/package/corpus/rules/documentation.md +90 -0
- package/package/corpus/rules/editing-cratis-docs.md +69 -0
- package/package/corpus/rules/efcore.md +235 -0
- package/package/corpus/rules/efcore.specs.md +44 -0
- package/package/corpus/rules/exit-codes-and-wrappers.md +33 -0
- package/package/corpus/rules/framework.md +52 -0
- package/package/corpus/rules/frontend-quality.md +59 -0
- package/package/corpus/rules/frontend-testing.md +126 -0
- package/package/corpus/rules/general.md +305 -0
- package/package/corpus/rules/git-commits.md +138 -0
- package/package/corpus/rules/github-actions.md +92 -0
- package/package/corpus/rules/glossary.md +61 -0
- package/package/corpus/rules/guards-and-fuses.md +45 -0
- package/package/corpus/rules/local-work-artifacts.md +33 -0
- package/package/corpus/rules/managing-ai-rules.md +40 -0
- package/package/corpus/rules/orleans.md +50 -0
- package/package/corpus/rules/pull-requests.md +78 -0
- package/package/corpus/rules/react.md +195 -0
- package/package/corpus/rules/reactors.md +238 -0
- package/package/corpus/rules/rtk.md +37 -0
- package/package/corpus/rules/specs.csharp.md +139 -0
- package/package/corpus/rules/specs.md +132 -0
- package/package/corpus/rules/specs.scenarios.csharp.md +172 -0
- package/package/corpus/rules/specs.typescript.md +139 -0
- package/package/corpus/rules/storybook.md +84 -0
- package/package/corpus/rules/terminal-commands.md +19 -0
- package/package/corpus/rules/typescript.md +149 -0
- package/package/corpus/rules/verification-discipline.md +21 -0
- package/package/corpus/rules/vertical-slices.md +338 -0
- package/package/corpus/rules/web-fetching.md +11 -0
- package/package/corpus/rules/writing-correct-examples.md +35 -0
- package/package/corpus/rules/writing-cratis-docs.md +70 -0
- package/package/corpus/skills/cratis-engineering-csharp-conventions/LICENSE +2 -0
- package/package/corpus/skills/cratis-engineering-csharp-conventions/SKILL.md +131 -0
- package/package/corpus/skills/cratis-engineering-csharp-conventions/references/code-style.md +187 -0
- package/package/corpus/skills/cratis-engineering-csharp-conventions/references/domain-philosophy.md +91 -0
- package/package/corpus/skills/cratis-engineering-csharp-conventions/references/exceptions-logging-and-di.md +223 -0
- package/package/corpus/skills/cratis-engineering-decision-record/LICENSE +2 -0
- package/package/corpus/skills/cratis-engineering-decision-record/SKILL.md +133 -0
- package/package/corpus/skills/cratis-engineering-decision-record/references/record-format.md +107 -0
- package/package/corpus/skills/cratis-engineering-docs-authoring/LICENSE +2 -0
- package/package/corpus/skills/cratis-engineering-docs-authoring/SKILL.md +86 -0
- package/package/corpus/skills/cratis-engineering-docs-authoring/references/site-format.md +46 -0
- package/package/corpus/skills/cratis-engineering-effect-boundaries/LICENSE +2 -0
- package/package/corpus/skills/cratis-engineering-effect-boundaries/SKILL.md +130 -0
- package/package/corpus/skills/cratis-engineering-effect-boundaries/references/failure-archetypes.md +133 -0
- package/package/corpus/skills/cratis-fundamentals-concept/verification.json +8 -0
- package/package/profile-catalog.json +821 -0
- package/package.json +35 -13
- package/src/index.ts +80 -0
- /package/{skills → package/corpus/skills}/cratis-application-react-specifications/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-application-react-specifications/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-application-slice-specifications/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-application-slice-specifications/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/references/authentication.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/references/authorization.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/references/frontend.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/references/local-development.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/references/tenancy.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-command/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-command/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-command/references/command-result.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-command/references/handler-shapes.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-command/references/proxy-generation.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-command/references/read-model-injection.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-command-execution/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-command-execution/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-command-validation/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-command-validation/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-ef-core-migration/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-ef-core-migration/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-observable-query-http/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-observable-query-http/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-query-paging/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-query-paging/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-react-page/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-react-page/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-react-page/references/data-page.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-react-page/references/data-tables.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-react-page/references/dialogs.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-react-page/references/mvvm.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-arc-react-page/references/queries-and-commands.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-cli-operations/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-cli-operations/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-client-dotnet/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-client-dotnet/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-client-elixir/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-client-elixir/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-client-kotlin/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-client-kotlin/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-client-typescript/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-client-typescript/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-compliance/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-compliance/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-event-constraints/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-event-constraints/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-event-modeling/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-event-modeling/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-event-specifications/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-event-specifications/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-event-type-migration/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-event-type-migration/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-mcp-inspection/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-mcp-inspection/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-mcp-inspection/references/blocked-tools.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-mcp-inspection/references/observational-tools.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-multi-tenancy/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-multi-tenancy/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-projection/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-projection/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-projection/references/fluent-builder.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-projection/references/model-bound-attributes.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-reactor/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-reactor/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-read-model/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-read-model/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-read-model/references/queries.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-read-model-specifications/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-read-model-specifications/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-reducer/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-reducer/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-web-workbench/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-chronicle-web-workbench/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-cli-terminal-workbench/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-cli-terminal-workbench/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-code-review/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-code-review/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-components-accessibility/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-components-accessibility/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-components-schema-editor/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-components-schema-editor/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-components-stepper-command-dialog/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-components-stepper-command-dialog/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-components-styling/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-components-styling/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-components-toolbar/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-components-toolbar/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-documentation-writing/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-documentation-writing/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-event-model-diagram/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-event-model-diagram/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-fundamentals-concept/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-fundamentals-concept/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-fundamentals-type-discovery/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-fundamentals-type-discovery/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-governed-release-methodology/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-governed-release-methodology/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-lens-browser-extension/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-lens-browser-extension/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-performance-review/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-performance-review/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-screenplay-model-authoring/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-screenplay-model-authoring/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-security-review/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-security-review/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-specification-by-example/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-specification-by-example/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-specifications-csharp/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-specifications-csharp/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-specifications-csharp/references/application-scenarios.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-specifications-csharp/references/csharp-patterns.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-specifications-csharp/references/integration-specs.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-specifications-typescript/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-specifications-typescript/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-specifications-typescript/references/typescript-patterns.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-stage-rendering-and-sandbox/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-stage-rendering-and-sandbox/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-studio-mcp-safety-guidance/LICENSE +0 -0
- /package/{skills → package/corpus/skills}/cratis-studio-mcp-safety-guidance/SKILL.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-studio-mcp-safety-guidance/references/blocked-tools.md +0 -0
- /package/{skills → package/corpus/skills}/cratis-studio-mcp-safety-guidance/references/observational-tools.md +0 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**/*"
|
|
3
|
+
profile: framework
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Framework Profile — Contributing to Cratis Itself
|
|
7
|
+
|
|
8
|
+
> **Framework profile only.** This applies when you are working **inside a Cratis framework repository** (Arc, Chronicle, Fundamentals, Components, Specifications, and the like) — building the framework. If you are building an *application on* Cratis, ignore this file and follow the Application profile (`general.md` + `vertical-slices.md`).
|
|
9
|
+
|
|
10
|
+
The framework repos are **libraries**, not event-sourced applications. The application-profile architecture — vertical slices, model-bound `[Command]`/`[ReadModel]` artifacts, projections/read-models, reactors, MVVM app components — **does not exist here and must not be imposed**. A Cratis framework repo has its own architecture per its purpose.
|
|
11
|
+
|
|
12
|
+
## What still applies (universal rules)
|
|
13
|
+
|
|
14
|
+
Everything tagged `profile: universal` holds in framework repos exactly as in apps: **C# conventions** (`csharp.md`), **TypeScript conventions** (`typescript.md`), **code quality** (`code-quality*.md`), **specs** (`specs.md` / `specs.csharp.md` / `specs.typescript.md` — `Cratis.Specifications` is how the framework tests itself, using the plain `Specification` base + NSubstitute against the classes under test — this is the dominant mode in framework repos. The in-process `*Scenario` family lives in `specs.scenarios.csharp.md` (`profile: application`); it is the *application* default, and a framework repo reaches for it only to test the very engine it provides — Arc → `CommandScenario`, Chronicle → `EventScenario`/`ReadModelScenario`/`ReactorScenario` — not as a general testing mode. The **write-specs** skill is application-oriented), **documentation**, **git-commits**, **pull-requests**, **concepts** (`ConceptAs<T>` / `EventSourceId<T>` are Fundamentals/Chronicle primitives the framework defines and uses), and **American English**.
|
|
15
|
+
|
|
16
|
+
## What does NOT apply
|
|
17
|
+
|
|
18
|
+
Skip these `profile: application` rules entirely when in a framework repo: `vertical-slices.md`, `reactors.md`, `react.md`, `components.md`, `dialogs.md`, `frontend-quality.md`, `frontend-testing.md`, `storybook.md`, `efcore.md`, `efcore.specs.md`. Do not create vertical-slice folders, `[Command]`/`Handle()` records, read models, or MVVM app components in framework source.
|
|
19
|
+
|
|
20
|
+
## The repos and their shape
|
|
21
|
+
|
|
22
|
+
Each framework repo is organized by what it builds, not by feature slices:
|
|
23
|
+
|
|
24
|
+
- **Fundamentals** — the base library. `ConceptAs<T>`, type discovery (`IInstancesOf<T>` / `IImplementationsOf<T>`), serialization, common primitives. `Source/DotNET` (C#) + `Source/JavaScript` (`@cratis/fundamentals`) + the shared ESLint config.
|
|
25
|
+
- **Arc** — the CQRS + model-binding + proxy-generation engine. `Source/DotNET` (the command/query pipeline, validation, authorization, identity, the Roslyn **proxy generator**) + `Source/JavaScript` (`@cratis/arc`, `@cratis/arc.react`, `@cratis/arc.react.mvvm`). Arc.Core does **not** depend on Chronicle.
|
|
26
|
+
- **Chronicle** — the event-sourcing engine. `Source/Kernel` (the engine: **Orleans grains**, event sequences, observers/projections/reducers, storage providers — MongoDB and others), `Source/Clients` (the client SDKs incl. `DotNET` and `Testing`), `Infrastructure`, `Tools`, `Workbench`. The kernel is the deep, performance- and consistency-critical core.
|
|
27
|
+
- **Components** — the React component library on PrimeReact. `Source/<Component>/` folder per component (`CommandDialog`, `DataPage`, `DataTables`, …) with Storybook stories; published as `@cratis/components`. (Application rules *consume* these components; here you *build* them.)
|
|
28
|
+
|
|
29
|
+
Repo conventions follow from this: `Source/DotNET` + `Source/JavaScript` for dual-stack libraries; `Kernel` vs `Clients` for Chronicle; a folder-per-component library layout for Components. Match the structure of the area you are editing — do not introduce app-style layouts.
|
|
30
|
+
|
|
31
|
+
## Framework-contributor principles
|
|
32
|
+
|
|
33
|
+
- **Public API design is the product.** These libraries are consumed by every Cratis app, so the **Lovable APIs** value (`general.md`) is paramount: sane defaults, convention over configuration, extensible/overridable, minimal boilerplate. Design the API the app developer will love before the implementation.
|
|
34
|
+
- **Backward compatibility is a contract.** A change to a public type, attribute, interface, or generated-proxy shape is a breaking change for every downstream app — label PRs by semver impact (`major`/`minor`/`patch`) and treat removals/renames of public surface as `major`.
|
|
35
|
+
- **Convention discovery is built here.** `IInstancesOf<T>` / `IImplementationsOf<T>`, attribute-based discovery, and source generation are the mechanisms the framework *provides*; use them internally too rather than hand-registration where a convention fits.
|
|
36
|
+
- **Source generators / analyzers** (Arc's proxy generator, Fundamentals) follow Roslyn conventions; their output is consumed verbatim by apps, so treat generated shape as public API.
|
|
37
|
+
- **Orleans grains** in the Chronicle kernel follow `orleans.md`.
|
|
38
|
+
- **An alternate implementation of an interface must match the primary one's *semantics*, not just its signature.** Chronicle ships several implementations of the same storage interfaces (MongoDB, SQL, in-memory) and the in-memory ones exist precisely so the real kernel code paths can run without infrastructure. When you touch one, **diff it against the persistent implementations** — the signature tells you nothing about the contract. The specific trap: query criteria carry **sentinels meaning "do not narrow"** (`EventSourceId.Unspecified`, `EventSourceType.Unspecified`/`Default`, `EventStreamType.All`, `EventStreamId.Default`, an empty event-type set). Callers asking for "everything" pass those sentinels, never `null`, so a plain `is not null` check narrows every row away and the read silently returns nothing. A divergence here does not fail — it makes specs pass vacuously, which is worse.
|
|
39
|
+
- **A stub that silently succeeds is a bug, not a placeholder.** An unimplemented method returning `Task.CompletedTask`/an empty result lets a spec assert on work that never happened. Implement it, or make it fail loudly — never leave it quietly lying.
|
|
40
|
+
- **Specs** use `Cratis.Specifications` (the `Establish`/`Because`/`should_` BDD style) with NSubstitute — the same philosophy as apps, without the Arc/Chronicle `*Scenario` app-testing helpers.
|
|
41
|
+
- **Treat "no spec touches this public API" as a defect in itself.** Public surface with zero coverage is where silent breakage lives — an entire read surface, including two shipped assertion helpers, was once dead in `Cratis.Chronicle.Testing` because nothing ever called it. When adding public API, add at least one spec that exercises it end to end.
|
|
42
|
+
|
|
43
|
+
## Quality gates (framework)
|
|
44
|
+
|
|
45
|
+
- Build clean (Debug and Release) with **zero warnings, zero errors**.
|
|
46
|
+
- Specs pass for affected projects (C# via `dotnet test`; TS packages via their test command; Components also `build-storybook`).
|
|
47
|
+
- For public-facing changes (APIs, attributes, generated output, component props): update the product documentation and verify it.
|
|
48
|
+
- Match the repo's existing patterns; when a deep architectural question isn't answered by the universal rules or this file, consult the **repo's own docs/CONTRIBUTING** or ask — do not infer framework internals from a single call site.
|
|
49
|
+
|
|
50
|
+
## Depth lives in the repo
|
|
51
|
+
|
|
52
|
+
This file is the cross-cutting framework-contributor baseline. Repo-specific internals — the Chronicle kernel's grain/observer/storage design, Arc's proxy-generator internals, the Components build pipeline — are owned by each repo's own documentation, not duplicated here. Follow those for area-specific detail.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**/*.{ts,tsx}"
|
|
3
|
+
profile: application
|
|
4
|
+
paths:
|
|
5
|
+
- "**/*.ts"
|
|
6
|
+
- "**/*.tsx"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Frontend Code Quality
|
|
10
|
+
|
|
11
|
+
The frontend is software engineering, held to the same bar as the backend — and it is the part most prone to silent degradation under iterative AI editing: orphaned code, duplicated components, sprawling files, shipped placeholders, untested state machines hidden in JSX. This rule is the maintainability contract that prevents that. It complements [react.md](./react.md) (architecture), [typescript.md](./typescript.md) (style), and [frontend-testing.md](./frontend-testing.md) (specs).
|
|
12
|
+
|
|
13
|
+
Aim for CUPID code: **Composable**, **Unix-like** (small focused pieces), **Predictable**, **Idiomatic**, **Domain-based**.
|
|
14
|
+
|
|
15
|
+
## Non-negotiables
|
|
16
|
+
|
|
17
|
+
1. **Never ship placeholder or dead UI as if it were real.** "Coming soon", lorem-ipsum, fake counts, and stubbed fixtures must not reach a screen backing a feature the code actually implements. An empty state is the *designed* empty state for that surface, not a build-time apology. When you implement the real behavior, delete the placeholder and its strings in the same change.
|
|
18
|
+
2. **Components stay small and single-responsibility.** A `// Section` comment inside a component means that section is its own component. A presentational `.tsx` over ~150 lines, or with more than one clear responsibility, is decomposed. Parent owns state; children receive props.
|
|
19
|
+
3. **State logic lives in a view model, not the component.** Per [react.md](./react.md): extract a `withViewModel` view model (or a tested state module) as soon as a component has 3+ `useState`, any `useCallback`/state-syncing `useEffect`, or derived values. `useCallback`/`useMemo` inside a `withViewModel` component is a smell. Never store React state in a view model; never call hooks inside one — inject the Cratis abstraction. A view model must be constructible in a spec without React.
|
|
20
|
+
4. **Reuse before rewrite.** Check the shared component surface and existing style constants before adding a component or a long class string. Never duplicate a primitive that already exists; prefer a Cratis Components wrapper or an existing shared component over a new one.
|
|
21
|
+
5. **Test behavior, not implementation trivia.** Non-trivial view-model/helper logic gets BDD specs (see [frontend-testing.md](./frontend-testing.md)). Storybook is visual coverage, not a replacement for behavioral specs.
|
|
22
|
+
6. **No `any`, descriptive names, no orphaned code.** `unknown` or a real type, never `any`. After editing a `.tsx`, read past its last closing `};` to confirm no stale `return (...)` block, duplicate body, or unreachable code remains. Comment only a non-obvious *why* — no "what"/provenance comments.
|
|
23
|
+
|
|
24
|
+
## Smell guards
|
|
25
|
+
|
|
26
|
+
Stop-and-fix signals during implementation and review:
|
|
27
|
+
|
|
28
|
+
| Smell | Why it matters | Preferred move |
|
|
29
|
+
|---|---|---|
|
|
30
|
+
| New component added without checking the shared component surface and `@cratis/components` | Duplicates fragment the design system | Reuse an existing primitive/wrapper, or document the missing one |
|
|
31
|
+
| Slice-local helper promoted to the shared component folder after one use | Freezes a one-off as a shared API | Keep it beside the slice until a second real consumer appears |
|
|
32
|
+
| Raw `primereact/*` import where a Cratis wrapper exists | Bypasses Arc behavior, overlay fixes, validation | Use the `@cratis/components` subpath wrapper |
|
|
33
|
+
| Import from the `@cratis/components` root barrel in new code | Pulls optional-peer-heavy exports, hides intent | Import from subpaths (`CommandDialog`, `DataPage`, `DataTables`, `Dialogs`, `Dropdown`, `Toolbar`, `Common`) |
|
|
34
|
+
| Component API has many boolean visual flags (`primary`, `selected`, `muted`, …) | State combinations become undefined | One typed `variant`/`tone` union, or split components |
|
|
35
|
+
| A reusable component reaches into domain strings, generated proxies, identity, query, command, or navigation | It is no longer a primitive | Move it to the slice, or make it explicitly Cratis-aware and test/story it as such |
|
|
36
|
+
| Class/style string copied 3× or grown hard to scan | Styling changes become search-and-replace bugs | Extract to a shared style constant or a focused child component |
|
|
37
|
+
| `style={{ ... }}` with static token names | Bypasses theming and review | Move to `className`; keep `style` only for runtime values |
|
|
38
|
+
|
|
39
|
+
## Definition of done for a frontend change
|
|
40
|
+
|
|
41
|
+
- [ ] No placeholder/stub copy ships for behavior that is actually implemented.
|
|
42
|
+
- [ ] Each component is single-responsibility; oversized components were split.
|
|
43
|
+
- [ ] State/logic crossing the [react.md](./react.md) thresholds lives in a view model.
|
|
44
|
+
- [ ] Reused existing primitives/wrappers instead of duplicating.
|
|
45
|
+
- [ ] No smell guard above is triggered without a short, intentional reason.
|
|
46
|
+
- [ ] File read past its final `};` — no orphaned code.
|
|
47
|
+
- [ ] New/changed reusable or stateful components have Storybook stories.
|
|
48
|
+
- [ ] New/changed view-model/helper behavior has BDD specs (see [frontend-testing.md](./frontend-testing.md)).
|
|
49
|
+
- [ ] Lint, conditional test, and build pass (the project's frontend gates).
|
|
50
|
+
|
|
51
|
+
## Review discipline
|
|
52
|
+
|
|
53
|
+
Treat the frontend gates as seriously as the backend build/test gates — a green lint is the floor, not the goal. For any non-trivial frontend change, run a correctness review (and a reuse/dead-code pass) before completing it. Degradation accrues one "it lints, ship it" at a time.
|
|
54
|
+
|
|
55
|
+
## See also
|
|
56
|
+
|
|
57
|
+
- [react.md](./react.md) — MVVM, Cratis Components, queries/commands.
|
|
58
|
+
- [typescript.md](./typescript.md) — style, type discipline.
|
|
59
|
+
- [frontend-testing.md](./frontend-testing.md) — BDD Vitest specs and layout.
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**/for_*/**/*.{ts,tsx}"
|
|
3
|
+
profile: application
|
|
4
|
+
paths:
|
|
5
|
+
- "**/for_*/**/*.ts"
|
|
6
|
+
- "**/for_*/**/*.tsx"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Frontend Testing
|
|
10
|
+
|
|
11
|
+
Frontend tests are specifications. The `for_/when_/and_` shape is intentionally the same BDD language as the backend Cratis Specifications: one subject, one context, clear setup, small assertions, no framework noise. When in doubt, mirror the structure in the Cratis Components source before inventing a new style.
|
|
12
|
+
|
|
13
|
+
The quality goal is CUPID code: frontend logic that cannot be tested in isolation is usually doing too much or depending on the wrong abstraction.
|
|
14
|
+
|
|
15
|
+
## Frameworks
|
|
16
|
+
|
|
17
|
+
- [Vitest](https://vitest.dev/) for running tests; Mocha-style `describe`/`it`/`beforeEach` structure.
|
|
18
|
+
- [SinonJS](https://sinonjs.org) for mocking/stubbing.
|
|
19
|
+
- [Chai](https://www.chaijs.com) — **always the `.should` fluent interface**, never `expect()`. `result.should.equal(expected)` reads as a sentence and matches the project's prose preference.
|
|
20
|
+
|
|
21
|
+
## Location and naming
|
|
22
|
+
|
|
23
|
+
Tests live next to the unit they specify:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
<Slice>/
|
|
27
|
+
<Subject>.ts
|
|
28
|
+
for_<Subject>/
|
|
29
|
+
when_<context>/
|
|
30
|
+
and_<extra_context>.ts
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
| Shape | Use for |
|
|
34
|
+
|---|---|
|
|
35
|
+
| `for_<Subject>/when_<context>/and_<extra>.ts` | default — view models, helpers with branches, component specs |
|
|
36
|
+
| `for_<Subject>/when_<context>.ts` | tiny pure-helper spec with no useful extra context |
|
|
37
|
+
|
|
38
|
+
snake_case file/folder names so the path reads as a scenario sentence. Use `should` in `it()` descriptions (spaces, not underscores — TS specs read as human sentences). Don't add `.test.ts`/`.spec.ts` files unless the config changes intentionally.
|
|
39
|
+
|
|
40
|
+
## BDD structure
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import { describe, beforeEach, it } from 'vitest';
|
|
44
|
+
import { MyViewModel } from '../../MyViewModel';
|
|
45
|
+
|
|
46
|
+
describe('when filtering active candidates', () => {
|
|
47
|
+
let viewModel: MyViewModel;
|
|
48
|
+
|
|
49
|
+
beforeEach(() => {
|
|
50
|
+
viewModel = new MyViewModel();
|
|
51
|
+
viewModel.setSearch('senior');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should keep candidates matching the search text', () => {
|
|
55
|
+
viewModel.filteredItems.should.have.lengthOf(1);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
- `describe('when ...')` names the scenario, not the class.
|
|
61
|
+
- `beforeEach` does the arrange/act once for the context; each `it('should ...')` asserts one observable outcome.
|
|
62
|
+
|
|
63
|
+
## What to test
|
|
64
|
+
|
|
65
|
+
Behavior that can regress without TypeScript catching it:
|
|
66
|
+
|
|
67
|
+
- View-model state transitions, computed getters, filtering/sorting/selection, wizard steps, validation state, command-value derivation.
|
|
68
|
+
- Pure helpers: parsing, formatting, path lookup, grouping, boundary cases.
|
|
69
|
+
- Command orchestration outside `CommandDialog`: handling of unauthorized / invalid / exception / success outcomes.
|
|
70
|
+
- React component rendering only when markup, wrapper behavior, disabled state, or integration with a wrapped component is the point.
|
|
71
|
+
|
|
72
|
+
**Do not test:** generated Cratis proxies; framework/PrimeReact internals; CSS pixel-perfection; trivial presentational pass-throughs with no branch/derived behavior.
|
|
73
|
+
|
|
74
|
+
## View models
|
|
75
|
+
|
|
76
|
+
Plain TypeScript classes constructible directly in a spec:
|
|
77
|
+
|
|
78
|
+
- No React hooks; no direct `window`/`localStorage`/`location`/timers/network — inject the Cratis/browser abstraction (see [react.md](./react.md)).
|
|
79
|
+
- Derived values are getters, not `useMemo`.
|
|
80
|
+
- Commands are methods with explicit inputs, not inline closures hidden in JSX.
|
|
81
|
+
|
|
82
|
+
Pass small typed fakes or `sinon.stub()` instances for dependencies; avoid broad harnesses until a second spec reuses them.
|
|
83
|
+
|
|
84
|
+
## Component specs
|
|
85
|
+
|
|
86
|
+
The environment is `node`. For behavior that doesn't need browser events, use server-rendered markup:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import React from 'react';
|
|
90
|
+
import { renderToStaticMarkup } from 'react-dom/server';
|
|
91
|
+
import { vi } from 'vitest';
|
|
92
|
+
|
|
93
|
+
vi.mock('primereact/dialog', () => ({
|
|
94
|
+
Dialog: (props: { footer?: React.ReactNode; children?: React.ReactNode }) =>
|
|
95
|
+
React.createElement('div', null, props.footer, props.children),
|
|
96
|
+
}));
|
|
97
|
+
|
|
98
|
+
describe('when rendered while busy', () => {
|
|
99
|
+
let html: string;
|
|
100
|
+
beforeEach(() => { html = renderToStaticMarkup(React.createElement(MyDialog, { isBusy: true })); });
|
|
101
|
+
it('should disable the confirm button', () => { html.should.include('disabled'); });
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
- Mock only the external component boundary needed; prefer typed mock props over `any`.
|
|
106
|
+
- Add jsdom / Testing Library only when behavior truly requires DOM events; don't make it the default.
|
|
107
|
+
- Avoid snapshots — they hide behavior and make refactors noisy.
|
|
108
|
+
|
|
109
|
+
## Stories vs tests
|
|
110
|
+
|
|
111
|
+
Storybook covers visual states, documentation, and manual verification; Vitest covers behavior. A component with non-trivial logic usually needs both — Storybook for variants/interactive state, Vitest for view-model/helper behavior and narrow rendered-component behavior.
|
|
112
|
+
|
|
113
|
+
## Async and time
|
|
114
|
+
|
|
115
|
+
Use `vi.useFakeTimers()` for time-dependent behavior; restore with `vi.useRealTimers()` in `afterEach`. Never depend on the real current date, random values, network, or browser storage. For suspense-query tests, clear the Arc query caches in teardown.
|
|
116
|
+
|
|
117
|
+
## Gate
|
|
118
|
+
|
|
119
|
+
Run the project's frontend test gate (e.g. `yarn test`) for frontend changes; it complements lint and build, it does not replace them.
|
|
120
|
+
|
|
121
|
+
## See also
|
|
122
|
+
|
|
123
|
+
- [react.md](./react.md) — MVVM, view-model testability, Arc hooks.
|
|
124
|
+
- [frontend-quality.md](./frontend-quality.md) — the engineering bar these specs serve.
|
|
125
|
+
- [specs.md](./specs.md) — the backend BDD language this mirrors.
|
|
126
|
+
- skill: **write-specs-frontend** — the step-by-step workflow that applies these conventions.
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
# Cratis — Project Instructions
|
|
2
|
+
|
|
3
|
+
Cratis repositories come in **two profiles**, and the rules are scoped to them. **Identify your profile first** — it decides which rules apply.
|
|
4
|
+
|
|
5
|
+
- **Application profile (default)** — you are *building an application on Cratis*: event-sourced CQRS with **Cratis Chronicle** + **Cratis Arc**, vertical slices, read models persisted to MongoDB/EF Core, and a React + Cratis Components (PrimeReact) frontend in MVVM. Most of this corpus targets this profile.
|
|
6
|
+
- **Framework profile** — you are *contributing to a Cratis framework repository itself* (Arc, Chronicle, Fundamentals, Components, …). These are **libraries** — source generators, the Chronicle kernel (Orleans grains + storage), client SDKs, a React component library — **not** vertical-slice event-sourced apps. The application-architecture rules here **do not apply**; follow **[framework.md](./framework.md)**.
|
|
7
|
+
|
|
8
|
+
**How to tell:** if the repo's own package is `Cratis.*` / `@cratis/*` and it *builds* the framework, you are in the framework profile. If it *consumes* Cratis to build a product, you are in the application profile.
|
|
9
|
+
|
|
10
|
+
Profile-specific rules declare a **`profile:`** in their frontmatter (`application` or `framework`); a rule **without** one is **universal** and applies everywhere — C#/TypeScript style, code quality, specs (`Cratis.Specifications`), documentation, commits/PRs, American English. In this file, everything from **Project Layout** through the **Implementation Workflow** is *application profile* (skip to the Framework profile section if you're contributing to the framework); Philosophy, Authority, Verification, Quality Gates, and the closing sections are universal.
|
|
11
|
+
|
|
12
|
+
> **Arc is a standalone CQRS framework — not bound to event sourcing.** Even within the application profile, Arc provides model-bound commands/queries, validation, authorization, and full-stack proxy generation, and works **without** Chronicle (Arc.Core does not depend on Chronicle). A `[Command]` `Handle()` does not *have* to append events — it can return a response, return `void`, or work through injected services. The event-sourcing behavior (a returned event gets appended; `EventForEventSourceId`; "never inject `IEventLog`") comes from the **Arc + Chronicle** integration. This application is event-sourced, so the slice guidance assumes event-sourced commands — read the event-centric rules as the *house default for this app*, not universal Arc laws.
|
|
13
|
+
|
|
14
|
+
The framework is convention-over-configuration. **Idiomatic Cratis is the goal — not custom abstractions over it.** When something is unclear, prefer the Cratis convention; do not invent. The rules and skills under `.cratis/ai/` are the authoritative answer — if your question is not answered there, ask rather than inferring framework behavior from package internals.
|
|
15
|
+
|
|
16
|
+
## Project Philosophy
|
|
17
|
+
|
|
18
|
+
Every rule here serves **ease of use**, **productivity**, and **maintainability**:
|
|
19
|
+
|
|
20
|
+
- **Lovable APIs** — APIs should be pleasant to use: sane defaults, flexible, extensible, overridable. If an API feels awkward, it is wrong.
|
|
21
|
+
- **Easy to do things right, hard to do things wrong** — convention over configuration; artifact discovery by naming/attributes; minimal boilerplate. The framework guides you into the pit of success.
|
|
22
|
+
- **Events are facts** — immutable records of what happened. Past tense, one purpose, never ambiguous. If you reach for a nullable property on an event, you need a second event.
|
|
23
|
+
- **Strongly-typed primitives are the foundation — get them right first.** The most important, load-bearing decisions in every slice are the domain primitives: `ConceptAs<T>` value types and `EventSourceId<T>` identities (never raw `Guid`/`string`/`int` for a domain value); `ConceptValidator<T>` for invariants that travel with a value everywhere it appears; `CommandValidator<T>` for command-level rules; and past-tense, self-describing `[EventType]` names. These are not boilerplate or an afterthought — they are what makes the model type-safe end to end, the rules enforceable in one place, the events trustworthy forever, and the generated proxies meaningful. Treat naming and typing them precisely as the highest-value craftsmanship in the codebase; a slice built on sloppy primitives is wrong no matter how good the rest is.
|
|
24
|
+
- **High cohesion through vertical slices** — everything for a behavior lives together: backend, frontend, specs. Navigate by feature, not by technical layer.
|
|
25
|
+
- **Full-stack type safety** — shared models flow from C# through proxy generation to TypeScript. End-to-end typing without manual synchronization.
|
|
26
|
+
- **Specialization over reuse** — focused, purpose-built read models over one model reused across conflicting scenarios.
|
|
27
|
+
- **Consistency is king** — when in doubt, follow the established pattern.
|
|
28
|
+
|
|
29
|
+
When these instructions don't cover a situation, apply these values to make the call.
|
|
30
|
+
|
|
31
|
+
## Three Levels of Authority
|
|
32
|
+
|
|
33
|
+
Every rule below is one of three kinds — know which, because they carry different weight:
|
|
34
|
+
|
|
35
|
+
- **Framework contract** — enforced by Arc/Chronicle source, analyzers, or runtime. Violating it breaks the build or behaves wrongly. (e.g. `[Command]` needs a public instance `Handle()`; model-bound queries are static methods on `[ReadModel]`; nullable event properties raise a Chronicle analyzer warning.)
|
|
36
|
+
- **Cratis Application convention** — the house default for maintainability and consistent generated code. The framework does **not** enforce it, but follow it for consistency. (e.g. the slice folder shape, one backend file per small slice, declaration order.)
|
|
37
|
+
- **Product policy** — belongs in a downstream app's own `.cratis/ai/`, not this generic corpus. (e.g. specific roles, locales, design systems.)
|
|
38
|
+
|
|
39
|
+
Where a rule is convention rather than contract, this file says so. Do not claim "the framework requires this" for a convention.
|
|
40
|
+
|
|
41
|
+
## Project-Specific Instructions
|
|
42
|
+
|
|
43
|
+
This corpus is the shared, generic instruction set common to every Cratis
|
|
44
|
+
repository. Individual projects need extra context that does not belong here,
|
|
45
|
+
such as product composition, approved environment names, directions for
|
|
46
|
+
obtaining credentials, and other local conventions ("Product policy" above).
|
|
47
|
+
|
|
48
|
+
- Read repository-owned documentation as the canonical project-specific context when it
|
|
49
|
+
exists.
|
|
50
|
+
- Read repository-owned documentation only as the documented legacy fallback when
|
|
51
|
+
repository-owned documentation does not exist; never merge both contexts.
|
|
52
|
+
- Project context may explain which approved secret mechanism or local setup to
|
|
53
|
+
use, but it must never contain credential values, tokens, keys, passwords, or
|
|
54
|
+
other secrets.
|
|
55
|
+
- Project-specific guidance wins when it deliberately narrows shared behavior,
|
|
56
|
+
but it may not weaken organization security, authorization, or required
|
|
57
|
+
quality gates.
|
|
58
|
+
|
|
59
|
+
## Collaboration Default
|
|
60
|
+
|
|
61
|
+
Default to agentic behavior: inspect local rules, skills, code, tests, and generated patterns; make conservative assumptions supported by that context; implement and verify end to end when feasible. Don't interrupt with questions the repository can answer. Ask when the answer can't be found locally, when reasonable product/domain choices differ meaningfully, when a change is risky, or when the user asked for checkpoints.
|
|
62
|
+
|
|
63
|
+
## Destructive operations
|
|
64
|
+
|
|
65
|
+
Before a destructive or bulk external mutation, show the exact targets and
|
|
66
|
+
actions, explain how to recover, and obtain explicit user authorization. Re-read
|
|
67
|
+
the target state immediately before acting and stop if it changed. Git history
|
|
68
|
+
rewrites remain prohibited unless the user explicitly requests one.
|
|
69
|
+
|
|
70
|
+
## New Repository Strategy Intake
|
|
71
|
+
|
|
72
|
+
When a repository is created in the Cratis organization, prepare one transient,
|
|
73
|
+
no-effect Strategy intake proposal. Do not create, comment on, assign, mention,
|
|
74
|
+
link, or otherwise mutate a GitHub issue unless a current repository profile and
|
|
75
|
+
the exact operation are separately accepted. Tool access and a request to create
|
|
76
|
+
the repository do not supply that issue-effect authority.
|
|
77
|
+
|
|
78
|
+
The proposal should include only the bounded facts needed for Strategy triage:
|
|
79
|
+
|
|
80
|
+
- repository name, URL, visibility, and creation state;
|
|
81
|
+
- purpose, intended users, lifecycle, and whether it is canonical, generated,
|
|
82
|
+
experimental, operational, or scheduled for retirement;
|
|
83
|
+
- accountable owner or explicit vacancy and cross-repository boundaries;
|
|
84
|
+
- upstream/downstream dependencies and current owning records;
|
|
85
|
+
- release, distribution, credential, security, privacy, compliance, and data
|
|
86
|
+
expectations; and
|
|
87
|
+
- requested Strategy identity, portfolio, metadata, ownership, and local AI
|
|
88
|
+
context review.
|
|
89
|
+
|
|
90
|
+
First decide whether no record, an existing Strategy record, a bounded update
|
|
91
|
+
proposal, a new proposal, or a sensitive human route is appropriate. Treat the
|
|
92
|
+
result as Strategy intake, not strategic approval. Do not invent Strategy
|
|
93
|
+
metadata or copy private Strategy content into a public repository. Repository
|
|
94
|
+
creation does not require an issue URL; unresolved Strategy reconciliation is an
|
|
95
|
+
explicit next action for the authorized human/owning process.
|
|
96
|
+
|
|
97
|
+
## Shared AI Distribution
|
|
98
|
+
|
|
99
|
+
Do not copy or synchronize shared `.cratis/ai`, `.agents`, `.claude`, `.github`, or
|
|
100
|
+
`.pi` trees from one Cratis repository to another. A consuming repository must
|
|
101
|
+
never become an accidental source that republishes its local AI corpus.
|
|
102
|
+
|
|
103
|
+
Shared Cratis capabilities are authored and approved in `Cratis/AI`, generated
|
|
104
|
+
into `Cratis/AI.Distribution`, and installed only from an immutable reviewed
|
|
105
|
+
version after its release gates pass. Keep existing repository-local AI files in
|
|
106
|
+
place while the replacement distribution remains under canary; do not restart
|
|
107
|
+
legacy all-to-all propagation and do not delete legacy adapters before reviewed
|
|
108
|
+
retirement evidence exists.
|
|
109
|
+
|
|
110
|
+
Shared public product and `engineering-*` packages contain only public-safe
|
|
111
|
+
Cratis behavior. The `engineering-` prefix identifies the maintainer audience;
|
|
112
|
+
it does not imply confidential package contents or a private registry.
|
|
113
|
+
|
|
114
|
+
The consuming repository owns its project facts, confidential behavior, local
|
|
115
|
+
skills, and minimal host bootstraps. Use repository-owned documentation as canonical
|
|
116
|
+
project context when that migration is active, `.agents/skills/` for private or
|
|
117
|
+
repository-specific local workflows, and repository-owned documentation only as the
|
|
118
|
+
documented legacy context fallback. Never merge, overwrite, or remove these
|
|
119
|
+
local files as a side effect of installing, updating, rolling back, or
|
|
120
|
+
uninstalling shared AI capabilities.
|
|
121
|
+
|
|
122
|
+
Keep confidential and repository-specific behavior local. Generalize and remove
|
|
123
|
+
private facts before proposing a reusable improvement to `Cratis/AI`; never
|
|
124
|
+
reverse-sync a private repository's AI tree or generated adapters.
|
|
125
|
+
|
|
126
|
+
Update shared AI by changing a version pin through the approved organization or
|
|
127
|
+
host mechanism. Canary the new version, observe its behavior and gates, and roll
|
|
128
|
+
back by version when needed. Never patch generated distribution bytes or
|
|
129
|
+
marketplace wrappers by hand.
|
|
130
|
+
|
|
131
|
+
## Verification Discipline
|
|
132
|
+
|
|
133
|
+
A claim is only as good as the signal behind it — a build result, a test run, a lint pass, observed app behavior — not the model's own confidence. Internal reasoning *plans* the work; external signals *confirm* it.
|
|
134
|
+
|
|
135
|
+
- **Confirm "done"/"fixed"/"correct" against a fresh signal — never self-assessment.** Run the relevant gate and observe it pass *this time*.
|
|
136
|
+
- **After a fix, re-run the gate that failed.** Don't argue yourself to green.
|
|
137
|
+
- **A green build is not behavioral correctness.** Compilation proves it builds, not that the slice does the right thing — that's what specs and exercising the UI are for.
|
|
138
|
+
- **Report with inspectable evidence, and name what you didn't verify.**
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
# Application profile
|
|
143
|
+
|
|
144
|
+
> The following — **Project Layout, Slice Types, Slice Naming, the Rules, and the Implementation Workflow** — applies when **building an application on Cratis**. If you are contributing to a Cratis framework repo, skip to **Framework profile** below and follow [framework.md](./framework.md).
|
|
145
|
+
|
|
146
|
+
## Project Layout (Cratis Application convention)
|
|
147
|
+
|
|
148
|
+
The framework discovers commands and read models by attributes and static methods — **the folder shape is a convention, not a requirement.** The house default keeps everything for one behavior together, with **no top-level `Features/` wrapper**: the domain hierarchy lives directly under the app source root.
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
<AppSourceRoot>/ e.g. Source, Source/Core (app-defined)
|
|
152
|
+
├── Common/ shared ConceptAs<T> / EventSourceId<T> types
|
|
153
|
+
├── Identity/ Components/ ... cross-cutting / shared concerns, at the top level
|
|
154
|
+
└── <Module>/ top-level domain area — natural for most apps, NOT required
|
|
155
|
+
└── <Feature>/ grouping within the domain area
|
|
156
|
+
├── <Feature>.tsx pass-through layout (renders <Outlet/>)
|
|
157
|
+
├── <Concept>.cs feature-level concept types
|
|
158
|
+
└── <Slice>/ one folder per behavior — the invariant unit
|
|
159
|
+
├── <Slice>.cs backend artifacts for the slice in one file
|
|
160
|
+
├── *.tsx React component(s) for the slice
|
|
161
|
+
└── when_*/ spec folders
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**The slice is the invariant unit** — one behavior (command + events + projection + component + specs), created/renamed/deleted together. Features group related slices. A `<Module>` is the natural top-level domain grouping for larger areas (e.g. `Accounts`, `Admin`, `Requests`) but is **not required** — a feature may sit directly under the source root when no module grouping is natural; depth follows what fits the application. Cross-cutting concerns (shared concepts in `Common/`, shared components, identity) live at the top level. Namespace mirrors the path under `<AppSourceRoot>` (`<RootNamespace>.<Module>.<Feature>.<Slice>`, dropping any level that isn't present). Splitting the backend file is allowed when a slice grows large or shared concepts move upward; the single-file shape is the default, not a mandate.
|
|
165
|
+
|
|
166
|
+
> **No top-level `Features/` wrapper** — modules/features live directly under the app source root. The framework enforces no layout; this nested domain hierarchy is the chosen Cratis Application convention.
|
|
167
|
+
|
|
168
|
+
## Slice Types
|
|
169
|
+
|
|
170
|
+
Pick exactly one type per slice folder — determined by what the slice *does*.
|
|
171
|
+
|
|
172
|
+
| Type | What it does | Contents |
|
|
173
|
+
| --- | --- | --- |
|
|
174
|
+
| **State Change** | Accepts a command, appends events | Command + validator + event(s); optional `[Passive]` read model for command-side decisions |
|
|
175
|
+
| **State View** | Projects events into a queryable read model | `[ReadModel]` + model-bound projection + static query method(s) |
|
|
176
|
+
| **Automation** | Reacts to events, calls external systems / `ICommandPipeline` | Reactor only |
|
|
177
|
+
| **Translation** | Reacts to events and appends follow-up events to another stream | Reactor only |
|
|
178
|
+
|
|
179
|
+
## Slice Naming (convention)
|
|
180
|
+
|
|
181
|
+
Commands are imperative intents (`Register`, `Create`); the slice folder is the action only, never repeating a noun the Feature already establishes. **`[EventType]` records are past-tense facts** and must be self-describing (`AuthorRegistered`, never `Created`) — this past-tense, one-purpose naming is a Chronicle framework recommendation. Static query methods are descriptive reads (`AllAuthors`, `AuthorById`, `AuthorsByName`).
|
|
182
|
+
|
|
183
|
+
## Rules
|
|
184
|
+
|
|
185
|
+
Tagged **[contract]** (framework-enforced) or **[convention]** (house default). Mechanics and examples live in `vertical-slices.md`.
|
|
186
|
+
|
|
187
|
+
1. **[contract] Model-bound — no controllers.** Commands are `[Command]` records with a public instance `Handle()` (Arc analyzers enforce this); queries are `static` methods on `[ReadModel]` records; projections/constraints/authorization use attributes. Arc generates the HTTP surface. Drop to fluent (`IProjectionFor<T>`, `IConstraint`) only when model-bound can't express the rule.
|
|
188
|
+
2. **[contract] Command validation & data flow.** Put command rejection in `CommandValidator<T>`, global value invariants in `ConceptValidator<T>`, and fetched/computed handler data in **`Provide()`** (runs after validation/authorization; may short-circuit with `ValidationResult.Error` / `Result<TProvided, ValidationResult>`). Keep `Handle()` focused on event construction. For a state-dependent rule that must hold **under concurrency**, inject the read model into `Handle()` and return a typed error via `Result<TEvent, ValidationResult>`. **Throwing from `Provide()`/`Handle()` is an exception (HTTP 500), not a validation rejection** — throw only for genuinely exceptional conditions, never for normal business rejection.
|
|
189
|
+
3. **[contract] Event-source id resolution order:** `ICanProvideEventSourceId` → an `EventSourceId`/`EventSourceId<T>`-derived value → `[Key]` → else Arc/Chronicle generates one. A value actually used as a Chronicle stream identity derives from `EventSourceId<T>` with the underlying `IComparable` primitive — never `ConceptAs<Guid>` for that stream identity. `NotSet`, `New()`, and primitive→derived-id operators are optional domain/API conveniences, not Chronicle requirements; typed empty/zero values are real specified stream IDs, not `EventSourceId.Unspecified`.
|
|
190
|
+
4. **[contract] Events never carry the event-source id** — it is implicit in the event context.
|
|
191
|
+
5. **[contract] `[Key]` / `[Subject]` are distinct.** `[Key]` is for event-source/read-model/projection key resolution; `[Subject]` is compliance identity only. Don't put either on an `EventSourceId<T>` value (it already is both); use them only for non-`EventSourceId<T>` values.
|
|
192
|
+
6. **[contract] Avoid nullable event properties** — Chronicle's analyzer warns on them. Model optional facts as a separate event; resolve nullable command inputs to a non-null sentinel before constructing the event.
|
|
193
|
+
7. **[contract] `[EventType]` takes no arguments for new events** — the type name is the identifier. Use `generation:`/id only when evolving an existing contract; schema changes get a new generation + an `EventTypeMigration<TUpgrade,TPrevious>` (never edit stored-event semantics silently). An enum that only gains a member, or has one renamed, is the exception — Chronicle accepts that in place; a *removed* or *renumbered* member still needs a generation, plus a value map saying what the old values became.
|
|
194
|
+
8. **[convention] Every `[EventType]` has an XML `<summary>`** — a Cratis C# documentation convention (not a Chronicle rule); events live in the log forever, so record why they exist.
|
|
195
|
+
9. **[convention] `[ReadModel]` properties carry no default values** except semantically meaningful enum initial states and `[SetValue<T>]`-driven `bool` flags. False defaults hide missing projection wiring.
|
|
196
|
+
10. **[contract] AutoMap is on by default — never call `.AutoMap()`.** Match property names so AutoMap wires them; diverge with `[SetFrom<T>]` / fluent `.Set().To()` only for genuine name differences. Re-enable `.AutoMap()` only inside a scope where it was disabled with `.NoAutoMap()`.
|
|
197
|
+
11. **[contract] Projections consume events and event context — never other read models.** Default to model-bound attributes; use fluent `IProjectionFor<T>` for joins/nested/context/transforms; use a reducer when the model is "current state + event → next state" (a valid style, not a failure mode).
|
|
198
|
+
12. **[contract] Model-bound query custom paths use `[Path("...")]`** (`PathAttribute`), not ASP.NET `[Route]`. Reserve `[Route]` for controller-based endpoints (which this convention avoids).
|
|
199
|
+
13. **[convention] Cross-slice access is read-only through Chronicle** — inject another slice's read model or reference its events; never instantiate or DI another slice's command/handler/service.
|
|
200
|
+
14. **[contract] Never inject `IEventLog` into `Handle()`** — express appends through return types (`IEnumerable<object>` with `EventForEventSourceId` wrappers for cross-stream). In application reactors, return side-effect events or use `ICommandPipeline`; don't reach for `IEventLog` directly.
|
|
201
|
+
15. **[contract] Never edit a generated file** — proxies carry a `// @generated by Cratis` header. Fix the C# source and rebuild.
|
|
202
|
+
16. **[convention] Use the Cratis dialog wrappers** — never import `Dialog` from `primereact/dialog`; use `CommandDialog` / `Dialog` from `@cratis/components`. The default frontend stack is Cratis Components on PrimeReact theming/tokens/`pt` — **not** Tailwind (Tailwind is one supported unstyled path, not the generic default).
|
|
203
|
+
17. **[convention] One slice is one unit** — creating/renaming/moving/deleting a slice means doing the same to every artifact (the `.cs`, every `when_*/`, every `.tsx`, the composition import/JSX, the route).
|
|
204
|
+
|
|
205
|
+
## Implementation Workflow
|
|
206
|
+
|
|
207
|
+
- **Phase 0 — Model the request.** Confirm Module/Feature, Slice name, slice type, domain rules. For new behavior or unclear event vocabulary, run the **event-modeling** skill before writing code.
|
|
208
|
+
- **Phase 1 — Backend.** Implement a coherent slice change. **Gate:** incrementally build the affected Debug project to regenerate proxies and compile spec code; add Release verification when required for cross-cutting or merge/release gates (see the proxy-generation note below).
|
|
209
|
+
- **Phase 2 — Specs.** Mandatory for every slice type, in-process scenario family first: `CommandScenario<T>` (commands), `EventScenario` (constraints/append), `ReadModelScenario<T>` (projections/reducers), `ReactorScenario<T>` (reactors). Reserve out-of-process integration specs for host/infra/transport boundaries. **Gate:** tests pass.
|
|
210
|
+
- **Phase 3 — Frontend.** Proxies now exist. Build React components from generated proxies, register in the composition page, wire routing. **Gate:** lint, conditional test, and build all clean.
|
|
211
|
+
|
|
212
|
+
**Backend before frontend, always** — the frontend depends on proxies that only exist after a successful Debug build. After a coherent set of changes, incrementally build/compile the affected project and run targeted regression checks before proceeding; do not build after every file.
|
|
213
|
+
|
|
214
|
+
**Proxy generation runs on Debug, not Release.** `dotnet build -c Debug` is the canonical trigger for regenerating TypeScript proxies — it carries the fullest, most reliably-emitted PDB debug information the proxy generator relies on to place generated files. Generate proxies with a Debug build first; when you (or an agent) subsequently build Release purely to verify the app compiles in that configuration, skip proxy regeneration so the second build can't re-run the generator against a different compilation and touch already-correct generated files: `dotnet build -c Release -p:CratisProxiesOutputPath=`. The empty override clears the output path property the generator's MSBuild target is conditioned on, so the target no-ops for that invocation — no generated file is read or written.
|
|
215
|
+
|
|
216
|
+
## Quality Gates
|
|
217
|
+
|
|
218
|
+
| Phase | Command (app-pinned) | Pass criteria |
|
|
219
|
+
| --- | --- | --- |
|
|
220
|
+
| Backend | build (Debug) | zero errors, zero warnings — validates `#if DEBUG` spec code and regenerates proxies |
|
|
221
|
+
| Backend | build (Release) | zero errors, zero warnings — build-only check; pass `-p:CratisProxiesOutputPath=` to skip re-running proxy generation |
|
|
222
|
+
| Specs | test | zero failures |
|
|
223
|
+
| Frontend | lint | zero errors |
|
|
224
|
+
| Frontend | test | zero failures when frontend specs/behavior changed |
|
|
225
|
+
| Frontend | build | zero errors |
|
|
226
|
+
|
|
227
|
+
Run affected-project incremental checks after a coherent change, then targeted regression tests for the changed behavior. Re-run a failed gate after a relevant fix. Reserve wider matrices and clean/Release builds for cross-cutting changes, demonstrated stale outputs, or required merge/release gates. Documentation/rule-only edits need relevant Markdown, frontmatter, link, and corpus checks, not an application build. Diagnose unrelated or environmental failures within a bounded attempt; report the evidence and blocker instead of broadening scope or retrying indefinitely. Required gates remain blocking until satisfied; never silently waive red CI.
|
|
228
|
+
|
|
229
|
+
Documentation-only changes use repository-supported non-release intent, ordinarily `no-release`; confirm the workflow contract rather than assuming a label or API state. Run relevant content, link, frontmatter, and corpus checks instead of unrelated application builds, and satisfy every repository-required check, including release-intent checks where supported. Documentation is never a blanket exemption from red CI. See [pull-requests.md](./pull-requests.md).
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
# Framework profile
|
|
234
|
+
|
|
235
|
+
> You are contributing to a Cratis framework repository (Arc, Chronicle, Fundamentals, Components, …). **The Application-profile sections above do not apply** — there are no vertical slices, model-bound `[Command]`/`[ReadModel]` artifacts, projections/read-models, or MVVM app components here; these are libraries. Follow **[framework.md](./framework.md)** for repo structure, library/API design, source generators, the Chronicle kernel, and the framework quality gates. The universal sections (below, and every `profile: universal` rule) still apply.
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
# Both profiles (universal)
|
|
240
|
+
|
|
241
|
+
## Definition of Done
|
|
242
|
+
|
|
243
|
+
- The affected solution/project builds with zero warnings and zero errors.
|
|
244
|
+
- Relevant specs for every affected project pass.
|
|
245
|
+
- For public-facing changes (clients, SDKs, public APIs, developer-facing behavior), documentation is added or updated and its verification passes.
|
|
246
|
+
|
|
247
|
+
## Where to Look
|
|
248
|
+
|
|
249
|
+
| For | Location |
|
|
250
|
+
| --- | --- |
|
|
251
|
+
| **Contributing to a Cratis framework repo** (framework profile) | `framework.md` |
|
|
252
|
+
| Slice anatomy (commands, `Provide()`, validators, events, projections, read models, reactors, constraints, compliance, cross-slice) | `vertical-slices.md` |
|
|
253
|
+
| C# / TypeScript style | `csharp.md`, `typescript.md` |
|
|
254
|
+
| Service lifetimes — what a singleton may never hold (tenant, user, request state) | `csharp.md` |
|
|
255
|
+
| React + Arc + Cratis Components + MVVM + dialogs | `react.md`, `components.md`, `dialogs.md` |
|
|
256
|
+
| Frontend engineering quality & testing | `frontend-quality.md`, `frontend-testing.md`, `storybook.md` |
|
|
257
|
+
| Spec patterns — universal `Specification` base (both profiles) | `specs.md`, `specs.csharp.md`, `specs.typescript.md` |
|
|
258
|
+
| Spec patterns — the four `*Scenario` helpers (application only) | `specs.scenarios.csharp.md` |
|
|
259
|
+
| Strongly-typed values (`ConceptAs<T>`, `EventSourceId<T>`) | `concepts.md` |
|
|
260
|
+
| Shared term definitions (event, projection, reducer, reactor, observer, DCB, …) | `glossary.md` |
|
|
261
|
+
| Diagnosing a misbehaving slice (read model stale, proxy missing, quarantine, …) | the **diagnose-slice** skill |
|
|
262
|
+
| Inspecting or operating a **running** Chronicle store (failed partitions, replays, browsing events) with the `cratis` CLI | the **inspect-running-chronicle** skill |
|
|
263
|
+
| EF Core read models / migrations | `efcore.md`, `efcore.specs.md` |
|
|
264
|
+
| PRs / commits | `pull-requests.md`, `git-commits.md` |
|
|
265
|
+
| Reading, citing and superseding a decision record | `decision-records.md` |
|
|
266
|
+
| Whether you are allowed to do the thing you are able to do | `capability-is-not-authority.md` |
|
|
267
|
+
| What must stop and ask a human | `human-verdicts.md` |
|
|
268
|
+
| What counts as evidence that something works | `verification-discipline.md` |
|
|
269
|
+
| `next:` / `blocker:` values and when a comment is warranted | `work-records-and-comments.md` |
|
|
270
|
+
| Exit-code meaning and wrappers that lose a verdict | `exit-codes-and-wrappers.md` |
|
|
271
|
+
| Writing a scan, allowlist or destructive pass that cannot pass vacuously | `guards-and-fuses.md` |
|
|
272
|
+
| The section skeleton every engineering recipe follows | `engineering-recipe-skeleton.md` |
|
|
273
|
+
| Event modeling / schema migration / calling commands from code / paging / cross-cutting metadata / multi-tenancy | the matching skills |
|
|
274
|
+
| Step-by-step recipes | `.cratis/ai/skills/` |
|
|
275
|
+
|
|
276
|
+
## Source-of-Truth Discipline
|
|
277
|
+
|
|
278
|
+
- **Rules define invariants; skills define workflows.** A skill may refine how to apply a rule but must not contradict it. On conflict, follow the stricter invariant and fix the stale artifact.
|
|
279
|
+
- **Skills and rules are the authoritative answer.** If not answered there, ask. Don't infer Cratis behavior from package internals.
|
|
280
|
+
- Only make high-confidence suggestions.
|
|
281
|
+
- Don't change dependency manifests / lockfiles / `global.json` / NuGet config unless explicitly asked.
|
|
282
|
+
- When asked to commit, push, create a PR, ship, or land changes, use the **ship-changes** skill.
|
|
283
|
+
|
|
284
|
+
## General
|
|
285
|
+
|
|
286
|
+
- **American English** in all code, comments, and docs (initialize, behavior, color, serialize…).
|
|
287
|
+
- Treat warnings as errors; never suppress warning output.
|
|
288
|
+
- Reuse the active terminal for commands; create a new one only when the current one is busy or fails.
|
|
289
|
+
- All files start with the standard license header:
|
|
290
|
+
|
|
291
|
+
```csharp
|
|
292
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
293
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
## Local AI work artifacts — `.ai-work/` only
|
|
297
|
+
|
|
298
|
+
AI-assisted sessions produce working artifacts: plans, handover documents, session notes, continuation prompts, status boards, scratch analyses, research dumps. These are **work records, not documentation**:
|
|
299
|
+
|
|
300
|
+
- Create every such artifact inside **`.ai-work/`** at the repository root — never at the repository root itself, never under documentation folders, never anywhere else.
|
|
301
|
+
- `.ai-work/` is gitignored and must stay untracked. Never commit anything inside it, never `git add -f` anything inside it, and never remove the ignore entry.
|
|
302
|
+
- These artifacts must never enter git history or reach GitHub — not on any branch. If you find an unrelated tracked work record, report its path and obtain explicit authorization before moving it into `.ai-work/`, removing it from tracking, or making a dedicated cleanup commit. Discovery alone does not authorize unrelated changes or a commit.
|
|
303
|
+
- A genuine follow-up that must survive the session is **not** a work record — suggest opening a GitHub issue for it (or open one when asked) so future work is tracked where everyone can see it, instead of leaving a planning file behind.
|
|
304
|
+
- Knowledge that must outlive the session belongs in the repository's documentation structure through normal review, not in a work record.
|
|
305
|
+
- **A decision log is not a work record.** A decision — a durable choice with a decider and a date — is documentation: it lives in **`decisions/`** (or the repository's documented decisions folder) and is reviewed like any other documentation. A handover may summarize decisions; it never holds the only copy.
|