@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.
Files changed (234) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +18 -37
  3. package/package/corpus/agents/backend-developer.md +125 -0
  4. package/package/corpus/agents/code-reviewer.md +165 -0
  5. package/package/corpus/agents/coordinator.md +163 -0
  6. package/package/corpus/agents/frontend-developer.md +246 -0
  7. package/package/corpus/agents/orchestrator.md +196 -0
  8. package/package/corpus/agents/performance-reviewer.md +109 -0
  9. package/package/corpus/agents/planner.md +145 -0
  10. package/package/corpus/agents/repository-investigation-reviewer.md +45 -0
  11. package/package/corpus/agents/repository-investigator.md +50 -0
  12. package/package/corpus/agents/security-reviewer.md +118 -0
  13. package/package/corpus/agents/slice-implementer.md +59 -0
  14. package/package/corpus/agents/spec-writer.md +149 -0
  15. package/package/corpus/harnesses/pi/extensions/cratis-hooks/index.ts +213 -0
  16. package/package/corpus/harnesses/pi/extensions/cratis-rules/index.ts +27 -0
  17. package/package/corpus/harnesses/pi/extensions/package.json +4 -0
  18. package/package/corpus/harnesses/pi/extensions/subagent/agents.ts +167 -0
  19. package/package/corpus/harnesses/pi/extensions/subagent/index.ts +352 -0
  20. package/package/corpus/hooks/README.md +434 -0
  21. package/package/corpus/hooks/agent-stop.md +49 -0
  22. package/package/corpus/hooks/pre-commit.md +47 -0
  23. package/package/corpus/hooks/scripts/cratis-guard-writes.sh +87 -0
  24. package/package/corpus/hooks/scripts/cratis-nuget-pins.txt +11 -0
  25. package/package/corpus/hooks/scripts/cratis-pattern-scan.sh +197 -0
  26. package/package/corpus/hooks/scripts/cratis-patterns.json +84 -0
  27. package/package/corpus/hooks/scripts/cratis-quality-gate.sh +219 -0
  28. package/package/corpus/hooks/scripts/hook-lib.sh +152 -0
  29. package/package/corpus/hooks/scripts/quality-gates.json +261 -0
  30. package/package/corpus/hooks/scripts/type-references-allowlist.txt +71 -0
  31. package/package/corpus/hooks/scripts/validate-package-imports.sh +166 -0
  32. package/package/corpus/hooks/scripts/validate-package-subpaths.sh +120 -0
  33. package/package/corpus/hooks/scripts/validate-type-references.sh +308 -0
  34. package/package/corpus/hooks/settings.template.json +40 -0
  35. package/package/corpus/prompts/add-business-rule.prompt.md +22 -0
  36. package/package/corpus/prompts/add-concept.prompt.md +17 -0
  37. package/package/corpus/prompts/add-ef-migration.prompt.md +24 -0
  38. package/package/corpus/prompts/add-projection.prompt.md +20 -0
  39. package/package/corpus/prompts/add-reactor.prompt.md +22 -0
  40. package/package/corpus/prompts/add-reducer.prompt.md +20 -0
  41. package/package/corpus/prompts/audit-hooks.prompt.md +15 -0
  42. package/package/corpus/prompts/check-doc-drift.prompt.md +21 -0
  43. package/package/corpus/prompts/code-review.prompt.md +9 -0
  44. package/package/corpus/prompts/new-feature.prompt.md +9 -0
  45. package/package/corpus/prompts/new-vertical-slice.prompt.md +18 -0
  46. package/package/corpus/prompts/review-pr.prompt.md +35 -0
  47. package/package/corpus/prompts/review-skill.prompt.md +16 -0
  48. package/package/corpus/prompts/scaffold-feature.prompt.md +16 -0
  49. package/package/corpus/prompts/ship-changes.prompt.md +20 -0
  50. package/package/corpus/prompts/verify-ai-setup.prompt.md +19 -0
  51. package/package/corpus/prompts/write-documentation.prompt.md +21 -0
  52. package/package/corpus/prompts/write-specs.prompt.md +22 -0
  53. package/package/corpus/rules/capability-is-not-authority.md +31 -0
  54. package/package/corpus/rules/code-quality.csharp.md +91 -0
  55. package/package/corpus/rules/code-quality.md +82 -0
  56. package/package/corpus/rules/code-quality.typescript.md +89 -0
  57. package/package/corpus/rules/components.md +207 -0
  58. package/package/corpus/rules/concepts.md +115 -0
  59. package/package/corpus/rules/csharp.md +269 -0
  60. package/package/corpus/rules/dialogs.md +264 -0
  61. package/package/corpus/rules/documentation-structure-and-formatting.md +148 -0
  62. package/package/corpus/rules/documentation.md +90 -0
  63. package/package/corpus/rules/editing-cratis-docs.md +69 -0
  64. package/package/corpus/rules/efcore.md +235 -0
  65. package/package/corpus/rules/efcore.specs.md +44 -0
  66. package/package/corpus/rules/exit-codes-and-wrappers.md +33 -0
  67. package/package/corpus/rules/framework.md +52 -0
  68. package/package/corpus/rules/frontend-quality.md +59 -0
  69. package/package/corpus/rules/frontend-testing.md +126 -0
  70. package/package/corpus/rules/general.md +305 -0
  71. package/package/corpus/rules/git-commits.md +138 -0
  72. package/package/corpus/rules/github-actions.md +92 -0
  73. package/package/corpus/rules/glossary.md +61 -0
  74. package/package/corpus/rules/guards-and-fuses.md +45 -0
  75. package/package/corpus/rules/local-work-artifacts.md +33 -0
  76. package/package/corpus/rules/managing-ai-rules.md +40 -0
  77. package/package/corpus/rules/orleans.md +50 -0
  78. package/package/corpus/rules/pull-requests.md +78 -0
  79. package/package/corpus/rules/react.md +195 -0
  80. package/package/corpus/rules/reactors.md +238 -0
  81. package/package/corpus/rules/rtk.md +37 -0
  82. package/package/corpus/rules/specs.csharp.md +139 -0
  83. package/package/corpus/rules/specs.md +132 -0
  84. package/package/corpus/rules/specs.scenarios.csharp.md +172 -0
  85. package/package/corpus/rules/specs.typescript.md +139 -0
  86. package/package/corpus/rules/storybook.md +84 -0
  87. package/package/corpus/rules/terminal-commands.md +19 -0
  88. package/package/corpus/rules/typescript.md +149 -0
  89. package/package/corpus/rules/verification-discipline.md +21 -0
  90. package/package/corpus/rules/vertical-slices.md +338 -0
  91. package/package/corpus/rules/web-fetching.md +11 -0
  92. package/package/corpus/rules/writing-correct-examples.md +35 -0
  93. package/package/corpus/rules/writing-cratis-docs.md +70 -0
  94. package/package/corpus/skills/cratis-engineering-csharp-conventions/LICENSE +2 -0
  95. package/package/corpus/skills/cratis-engineering-csharp-conventions/SKILL.md +131 -0
  96. package/package/corpus/skills/cratis-engineering-csharp-conventions/references/code-style.md +187 -0
  97. package/package/corpus/skills/cratis-engineering-csharp-conventions/references/domain-philosophy.md +91 -0
  98. package/package/corpus/skills/cratis-engineering-csharp-conventions/references/exceptions-logging-and-di.md +223 -0
  99. package/package/corpus/skills/cratis-engineering-decision-record/LICENSE +2 -0
  100. package/package/corpus/skills/cratis-engineering-decision-record/SKILL.md +133 -0
  101. package/package/corpus/skills/cratis-engineering-decision-record/references/record-format.md +107 -0
  102. package/package/corpus/skills/cratis-engineering-docs-authoring/LICENSE +2 -0
  103. package/package/corpus/skills/cratis-engineering-docs-authoring/SKILL.md +86 -0
  104. package/package/corpus/skills/cratis-engineering-docs-authoring/references/site-format.md +46 -0
  105. package/package/corpus/skills/cratis-engineering-effect-boundaries/LICENSE +2 -0
  106. package/package/corpus/skills/cratis-engineering-effect-boundaries/SKILL.md +130 -0
  107. package/package/corpus/skills/cratis-engineering-effect-boundaries/references/failure-archetypes.md +133 -0
  108. package/package/corpus/skills/cratis-fundamentals-concept/verification.json +8 -0
  109. package/package/profile-catalog.json +821 -0
  110. package/package.json +35 -13
  111. package/src/index.ts +80 -0
  112. /package/{skills → package/corpus/skills}/cratis-application-react-specifications/LICENSE +0 -0
  113. /package/{skills → package/corpus/skills}/cratis-application-react-specifications/SKILL.md +0 -0
  114. /package/{skills → package/corpus/skills}/cratis-application-slice-specifications/LICENSE +0 -0
  115. /package/{skills → package/corpus/skills}/cratis-application-slice-specifications/SKILL.md +0 -0
  116. /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/LICENSE +0 -0
  117. /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/SKILL.md +0 -0
  118. /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/references/authentication.md +0 -0
  119. /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/references/authorization.md +0 -0
  120. /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/references/frontend.md +0 -0
  121. /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/references/local-development.md +0 -0
  122. /package/{skills → package/corpus/skills}/cratis-arc-authentication-authorization-and-identity/references/tenancy.md +0 -0
  123. /package/{skills → package/corpus/skills}/cratis-arc-command/LICENSE +0 -0
  124. /package/{skills → package/corpus/skills}/cratis-arc-command/SKILL.md +0 -0
  125. /package/{skills → package/corpus/skills}/cratis-arc-command/references/command-result.md +0 -0
  126. /package/{skills → package/corpus/skills}/cratis-arc-command/references/handler-shapes.md +0 -0
  127. /package/{skills → package/corpus/skills}/cratis-arc-command/references/proxy-generation.md +0 -0
  128. /package/{skills → package/corpus/skills}/cratis-arc-command/references/read-model-injection.md +0 -0
  129. /package/{skills → package/corpus/skills}/cratis-arc-command-execution/LICENSE +0 -0
  130. /package/{skills → package/corpus/skills}/cratis-arc-command-execution/SKILL.md +0 -0
  131. /package/{skills → package/corpus/skills}/cratis-arc-command-validation/LICENSE +0 -0
  132. /package/{skills → package/corpus/skills}/cratis-arc-command-validation/SKILL.md +0 -0
  133. /package/{skills → package/corpus/skills}/cratis-arc-ef-core-migration/LICENSE +0 -0
  134. /package/{skills → package/corpus/skills}/cratis-arc-ef-core-migration/SKILL.md +0 -0
  135. /package/{skills → package/corpus/skills}/cratis-arc-observable-query-http/LICENSE +0 -0
  136. /package/{skills → package/corpus/skills}/cratis-arc-observable-query-http/SKILL.md +0 -0
  137. /package/{skills → package/corpus/skills}/cratis-arc-query-paging/LICENSE +0 -0
  138. /package/{skills → package/corpus/skills}/cratis-arc-query-paging/SKILL.md +0 -0
  139. /package/{skills → package/corpus/skills}/cratis-arc-react-page/LICENSE +0 -0
  140. /package/{skills → package/corpus/skills}/cratis-arc-react-page/SKILL.md +0 -0
  141. /package/{skills → package/corpus/skills}/cratis-arc-react-page/references/data-page.md +0 -0
  142. /package/{skills → package/corpus/skills}/cratis-arc-react-page/references/data-tables.md +0 -0
  143. /package/{skills → package/corpus/skills}/cratis-arc-react-page/references/dialogs.md +0 -0
  144. /package/{skills → package/corpus/skills}/cratis-arc-react-page/references/mvvm.md +0 -0
  145. /package/{skills → package/corpus/skills}/cratis-arc-react-page/references/queries-and-commands.md +0 -0
  146. /package/{skills → package/corpus/skills}/cratis-chronicle-cli-operations/LICENSE +0 -0
  147. /package/{skills → package/corpus/skills}/cratis-chronicle-cli-operations/SKILL.md +0 -0
  148. /package/{skills → package/corpus/skills}/cratis-chronicle-client-dotnet/LICENSE +0 -0
  149. /package/{skills → package/corpus/skills}/cratis-chronicle-client-dotnet/SKILL.md +0 -0
  150. /package/{skills → package/corpus/skills}/cratis-chronicle-client-elixir/LICENSE +0 -0
  151. /package/{skills → package/corpus/skills}/cratis-chronicle-client-elixir/SKILL.md +0 -0
  152. /package/{skills → package/corpus/skills}/cratis-chronicle-client-kotlin/LICENSE +0 -0
  153. /package/{skills → package/corpus/skills}/cratis-chronicle-client-kotlin/SKILL.md +0 -0
  154. /package/{skills → package/corpus/skills}/cratis-chronicle-client-typescript/LICENSE +0 -0
  155. /package/{skills → package/corpus/skills}/cratis-chronicle-client-typescript/SKILL.md +0 -0
  156. /package/{skills → package/corpus/skills}/cratis-chronicle-compliance/LICENSE +0 -0
  157. /package/{skills → package/corpus/skills}/cratis-chronicle-compliance/SKILL.md +0 -0
  158. /package/{skills → package/corpus/skills}/cratis-chronicle-event-constraints/LICENSE +0 -0
  159. /package/{skills → package/corpus/skills}/cratis-chronicle-event-constraints/SKILL.md +0 -0
  160. /package/{skills → package/corpus/skills}/cratis-chronicle-event-modeling/LICENSE +0 -0
  161. /package/{skills → package/corpus/skills}/cratis-chronicle-event-modeling/SKILL.md +0 -0
  162. /package/{skills → package/corpus/skills}/cratis-chronicle-event-specifications/LICENSE +0 -0
  163. /package/{skills → package/corpus/skills}/cratis-chronicle-event-specifications/SKILL.md +0 -0
  164. /package/{skills → package/corpus/skills}/cratis-chronicle-event-type-migration/LICENSE +0 -0
  165. /package/{skills → package/corpus/skills}/cratis-chronicle-event-type-migration/SKILL.md +0 -0
  166. /package/{skills → package/corpus/skills}/cratis-chronicle-mcp-inspection/LICENSE +0 -0
  167. /package/{skills → package/corpus/skills}/cratis-chronicle-mcp-inspection/SKILL.md +0 -0
  168. /package/{skills → package/corpus/skills}/cratis-chronicle-mcp-inspection/references/blocked-tools.md +0 -0
  169. /package/{skills → package/corpus/skills}/cratis-chronicle-mcp-inspection/references/observational-tools.md +0 -0
  170. /package/{skills → package/corpus/skills}/cratis-chronicle-multi-tenancy/LICENSE +0 -0
  171. /package/{skills → package/corpus/skills}/cratis-chronicle-multi-tenancy/SKILL.md +0 -0
  172. /package/{skills → package/corpus/skills}/cratis-chronicle-projection/LICENSE +0 -0
  173. /package/{skills → package/corpus/skills}/cratis-chronicle-projection/SKILL.md +0 -0
  174. /package/{skills → package/corpus/skills}/cratis-chronicle-projection/references/fluent-builder.md +0 -0
  175. /package/{skills → package/corpus/skills}/cratis-chronicle-projection/references/model-bound-attributes.md +0 -0
  176. /package/{skills → package/corpus/skills}/cratis-chronicle-reactor/LICENSE +0 -0
  177. /package/{skills → package/corpus/skills}/cratis-chronicle-reactor/SKILL.md +0 -0
  178. /package/{skills → package/corpus/skills}/cratis-chronicle-read-model/LICENSE +0 -0
  179. /package/{skills → package/corpus/skills}/cratis-chronicle-read-model/SKILL.md +0 -0
  180. /package/{skills → package/corpus/skills}/cratis-chronicle-read-model/references/queries.md +0 -0
  181. /package/{skills → package/corpus/skills}/cratis-chronicle-read-model-specifications/LICENSE +0 -0
  182. /package/{skills → package/corpus/skills}/cratis-chronicle-read-model-specifications/SKILL.md +0 -0
  183. /package/{skills → package/corpus/skills}/cratis-chronicle-reducer/LICENSE +0 -0
  184. /package/{skills → package/corpus/skills}/cratis-chronicle-reducer/SKILL.md +0 -0
  185. /package/{skills → package/corpus/skills}/cratis-chronicle-web-workbench/LICENSE +0 -0
  186. /package/{skills → package/corpus/skills}/cratis-chronicle-web-workbench/SKILL.md +0 -0
  187. /package/{skills → package/corpus/skills}/cratis-cli-terminal-workbench/LICENSE +0 -0
  188. /package/{skills → package/corpus/skills}/cratis-cli-terminal-workbench/SKILL.md +0 -0
  189. /package/{skills → package/corpus/skills}/cratis-code-review/LICENSE +0 -0
  190. /package/{skills → package/corpus/skills}/cratis-code-review/SKILL.md +0 -0
  191. /package/{skills → package/corpus/skills}/cratis-components-accessibility/LICENSE +0 -0
  192. /package/{skills → package/corpus/skills}/cratis-components-accessibility/SKILL.md +0 -0
  193. /package/{skills → package/corpus/skills}/cratis-components-schema-editor/LICENSE +0 -0
  194. /package/{skills → package/corpus/skills}/cratis-components-schema-editor/SKILL.md +0 -0
  195. /package/{skills → package/corpus/skills}/cratis-components-stepper-command-dialog/LICENSE +0 -0
  196. /package/{skills → package/corpus/skills}/cratis-components-stepper-command-dialog/SKILL.md +0 -0
  197. /package/{skills → package/corpus/skills}/cratis-components-styling/LICENSE +0 -0
  198. /package/{skills → package/corpus/skills}/cratis-components-styling/SKILL.md +0 -0
  199. /package/{skills → package/corpus/skills}/cratis-components-toolbar/LICENSE +0 -0
  200. /package/{skills → package/corpus/skills}/cratis-components-toolbar/SKILL.md +0 -0
  201. /package/{skills → package/corpus/skills}/cratis-documentation-writing/LICENSE +0 -0
  202. /package/{skills → package/corpus/skills}/cratis-documentation-writing/SKILL.md +0 -0
  203. /package/{skills → package/corpus/skills}/cratis-event-model-diagram/LICENSE +0 -0
  204. /package/{skills → package/corpus/skills}/cratis-event-model-diagram/SKILL.md +0 -0
  205. /package/{skills → package/corpus/skills}/cratis-fundamentals-concept/LICENSE +0 -0
  206. /package/{skills → package/corpus/skills}/cratis-fundamentals-concept/SKILL.md +0 -0
  207. /package/{skills → package/corpus/skills}/cratis-fundamentals-type-discovery/LICENSE +0 -0
  208. /package/{skills → package/corpus/skills}/cratis-fundamentals-type-discovery/SKILL.md +0 -0
  209. /package/{skills → package/corpus/skills}/cratis-governed-release-methodology/LICENSE +0 -0
  210. /package/{skills → package/corpus/skills}/cratis-governed-release-methodology/SKILL.md +0 -0
  211. /package/{skills → package/corpus/skills}/cratis-lens-browser-extension/LICENSE +0 -0
  212. /package/{skills → package/corpus/skills}/cratis-lens-browser-extension/SKILL.md +0 -0
  213. /package/{skills → package/corpus/skills}/cratis-performance-review/LICENSE +0 -0
  214. /package/{skills → package/corpus/skills}/cratis-performance-review/SKILL.md +0 -0
  215. /package/{skills → package/corpus/skills}/cratis-screenplay-model-authoring/LICENSE +0 -0
  216. /package/{skills → package/corpus/skills}/cratis-screenplay-model-authoring/SKILL.md +0 -0
  217. /package/{skills → package/corpus/skills}/cratis-security-review/LICENSE +0 -0
  218. /package/{skills → package/corpus/skills}/cratis-security-review/SKILL.md +0 -0
  219. /package/{skills → package/corpus/skills}/cratis-specification-by-example/LICENSE +0 -0
  220. /package/{skills → package/corpus/skills}/cratis-specification-by-example/SKILL.md +0 -0
  221. /package/{skills → package/corpus/skills}/cratis-specifications-csharp/LICENSE +0 -0
  222. /package/{skills → package/corpus/skills}/cratis-specifications-csharp/SKILL.md +0 -0
  223. /package/{skills → package/corpus/skills}/cratis-specifications-csharp/references/application-scenarios.md +0 -0
  224. /package/{skills → package/corpus/skills}/cratis-specifications-csharp/references/csharp-patterns.md +0 -0
  225. /package/{skills → package/corpus/skills}/cratis-specifications-csharp/references/integration-specs.md +0 -0
  226. /package/{skills → package/corpus/skills}/cratis-specifications-typescript/LICENSE +0 -0
  227. /package/{skills → package/corpus/skills}/cratis-specifications-typescript/SKILL.md +0 -0
  228. /package/{skills → package/corpus/skills}/cratis-specifications-typescript/references/typescript-patterns.md +0 -0
  229. /package/{skills → package/corpus/skills}/cratis-stage-rendering-and-sandbox/LICENSE +0 -0
  230. /package/{skills → package/corpus/skills}/cratis-stage-rendering-and-sandbox/SKILL.md +0 -0
  231. /package/{skills → package/corpus/skills}/cratis-studio-mcp-safety-guidance/LICENSE +0 -0
  232. /package/{skills → package/corpus/skills}/cratis-studio-mcp-safety-guidance/SKILL.md +0 -0
  233. /package/{skills → package/corpus/skills}/cratis-studio-mcp-safety-guidance/references/blocked-tools.md +0 -0
  234. /package/{skills → package/corpus/skills}/cratis-studio-mcp-safety-guidance/references/observational-tools.md +0 -0
@@ -0,0 +1,223 @@
1
+ # Exceptions, logging, and dependency injection
2
+
3
+ ## Exceptions
4
+
5
+ Every exception type communicates *what went wrong in domain terms*. A built-in
6
+ `InvalidOperationException` says nothing; a domain `AuthorAlreadyRegistered`
7
+ says everything.
8
+
9
+ - Throw only for genuinely exceptional situations, never for control flow.
10
+ - Always define a custom type deriving from `Exception`. Never throw a built-in
11
+ exception type.
12
+ - Never suffix the type name with `Exception`.
13
+ - Always supply a meaningful message.
14
+ - Document the type with an XML summary starting "The exception that is thrown
15
+ when …".
16
+ - Never write an empty or silently swallowing `catch`. Handle it, log it, or let
17
+ it propagate. When ignoring is genuinely correct, use an exception filter
18
+ (`catch (<ExceptionType>) when (<condition>)`) whose body states the decision
19
+ through a comment or a fallback — never a bare `catch { }`.
20
+
21
+ ```csharp
22
+ /// <summary>
23
+ /// The exception that is thrown when <condition>.
24
+ /// </summary>
25
+ /// <param name="<parameterName>">The <see cref="<ParameterType>"/> that <description>.</param>
26
+ public class <DomainExceptionName>(<ParameterType> <parameterName>)
27
+ : Exception($"<message> '{<parameterName>}' <detail>");
28
+ ```
29
+
30
+ ```csharp
31
+ var <identifier> = await <source>.<FindMethod>(<argument>)
32
+ ?? throw new <DomainExceptionName>(<argument>);
33
+ ```
34
+
35
+ ## Logging
36
+
37
+ - Use structured logging with named parameters.
38
+ - Inject `ILogger<T>` where `T` is the containing class.
39
+ - Keep message definitions in a separate `<ClassName>Logging.cs` file as a
40
+ `static partial` internal class.
41
+ - Use the `[LoggerMessage]` attribute and do **not** supply an `eventId`.
42
+ - Choose the level deliberately: `Information`, `Warning`, `Error`, `Debug`.
43
+
44
+ ```csharp
45
+ // <ClassName>Logging.cs
46
+ namespace <RootNamespace>.<Feature>;
47
+
48
+ static partial class <ClassName>Logging
49
+ {
50
+ [LoggerMessage(LogLevel.Information, "<message> '{<Parameter>}'")]
51
+ internal static partial void <MessageName>(
52
+ this ILogger<<ClassName>> logger, <ParameterType> <parameter>);
53
+ }
54
+ ```
55
+
56
+ ```csharp
57
+ public class <ClassName>(ILogger<<ClassName>> logger)
58
+ {
59
+ public Task <MethodName>(<ParameterType> <parameter>)
60
+ {
61
+ logger.<MessageName>(<parameter>);
62
+ <statement>;
63
+ }
64
+ }
65
+ ```
66
+
67
+ ## Dependency injection
68
+
69
+ The framework discovers and wires dependencies by convention. Explicit
70
+ registration is the exception, not the rule.
71
+
72
+ - Prefer constructor injection. Never inject `IServiceProvider` to resolve
73
+ collaborators — that is the service-locator anti-pattern.
74
+ - Mark a singleton with the `[Singleton]` attribute rather than registering it
75
+ explicitly.
76
+ - A convention-based `IFoo → Foo` pair needs no registration.
77
+ - Command and query `Handle()` parameters resolve from DI by type.
78
+
79
+ ```csharp
80
+ // Preferred — constructor injection
81
+ public class <ClassName>(<ICollaboratorType> <collaborator>);
82
+
83
+ // Avoid — service locator
84
+ public class <ClassName>(IServiceProvider provider)
85
+ {
86
+ void <MethodName>() =>
87
+ provider.GetService<<ICollaboratorType>>()!.<Method>();
88
+ }
89
+ ```
90
+
91
+ ## Service lifetimes — `[Singleton]` is a narrow choice
92
+
93
+ **Assume every application is multi-tenant**, even when it ships with a single
94
+ tenant and no tenant resolution configured. A single-tenant application is a
95
+ multi-tenant one with one tenant in it, and the code shape that serves both is
96
+ the same. The shape that serves only one has to be found and rewritten later,
97
+ from the far side of a data migration, in production.
98
+
99
+ That gives one rule with two faces:
100
+
101
+ > **A singleton may not depend on anything that belongs to a tenant, a user, or
102
+ > a request.**
103
+
104
+ These resolve **per scope**, and the scope carries the tenant, so none may be
105
+ injected into a `[Singleton]`:
106
+
107
+ | Off limits in a singleton | Why |
108
+ | --- | --- |
109
+ | The scoped event store and everything reached from it — event log, read models, constraints, event types, projections, reducers, PII | Resolved for the scope's namespace |
110
+ | A MongoDB collection, database, or client | The database name resolves per scope from the current tenant |
111
+ | An EF Core `DbContext` | Scoped for the same reason, and not thread-safe |
112
+ | A read model injected directly by key | Same scope, same binding |
113
+ | Any held tenant, principal, claims, correlation id, or HTTP context **value** | Belongs to one request and would outlive it |
114
+
115
+ A `[Singleton]` taking one of these is a **captive dependency**: the container
116
+ hands it the *root* scope's instance and keeps it for process lifetime. The root
117
+ scope has no request, so it resolves no tenant — every read and write goes to
118
+ the default namespace forever, regardless of who is asking.
119
+
120
+ **It does not throw. It returns nothing.** A query against the wrong namespace
121
+ hits a database that exists and is empty, so the caller receives an empty
122
+ collection, a null read model, or a default-valued options object and carries
123
+ on. The application starts, pages render, the build is green, and configuration
124
+ a tenant spent an afternoon entering is simply absent. It is invisible while
125
+ there is one tenant; every symptom appears the day a second arrives.
126
+
127
+ **What to use instead.** Default to the convention (transient), which inherits
128
+ the resolving scope's tenant for free, or a scoped lifetime when a service must
129
+ be shared within one request. Reserve `[Singleton]` for what is genuinely
130
+ process-wide and holds no tenant-, user-, or request-bound state: implementation
131
+ aggregators, HTTP client wrappers, options readers, pure computation, framework
132
+ plumbing.
133
+
134
+ When something must be a singleton and still needs data — a hosted service, a
135
+ dispatcher, a poller — inject `IServiceScopeFactory` and open a scope per unit
136
+ of work:
137
+
138
+ ```csharp
139
+ // Wrong — the scoped collaborator captures the root scope's default namespace forever
140
+ [Singleton]
141
+ public class <ClassName>(<IScopedCollaboratorType> <collaborator>) : <IInterfaceName>
142
+ {
143
+ public Task<<ResultType>?> <MethodName>() => <collaborator>.<Method>(<argument>);
144
+ }
145
+
146
+ // Right — a scope per call, so collaborators bind to the caller's tenant
147
+ [Singleton]
148
+ public class <ClassName>(IServiceScopeFactory scopeFactory) : <IInterfaceName>
149
+ {
150
+ public async Task<<ResultType>?> <MethodName>()
151
+ {
152
+ using var scope = scopeFactory.CreateScope();
153
+ var <collaborator> = scope.ServiceProvider
154
+ .GetRequiredService<<IScopedCollaboratorType>>();
155
+
156
+ return await <collaborator>.<Method>(<argument>);
157
+ }
158
+ }
159
+ ```
160
+
161
+ A client that names its store and namespace explicitly **is** singleton-safe,
162
+ and is the right collaborator when a flow knows which namespace it means and has
163
+ no scope to resolve one from. Naming the namespace is a deliberate, readable
164
+ statement that this code crosses a tenant boundary; capturing a scoped service
165
+ is the same crossing made by accident.
166
+
167
+ **The current user is not process-wide either.** Never keep the signed-in user,
168
+ their principal, claims, roles, or anything derived from them in a singleton.
169
+ The distinction that matters: *the accessor is fine, the value is not.* An HTTP
170
+ context accessor is itself a singleton and safe to inject; reading a value out
171
+ of it once and keeping it is not. A current-user service may be a singleton only
172
+ when every method reads through the accessor on each call and stores nothing.
173
+ Anything that derives something per user and wants to keep it holds a cache
174
+ **keyed by the user**, never a single field.
175
+
176
+ **Off-request work carries its tenant.** Reactors, hosted services, background
177
+ dispatch, and scheduled jobs run with no request, so a tenant resolver has
178
+ nothing to read. Observers may be instantiated per namespace, but the
179
+ collaborators they call are not — a flow that reaches a tenant-blind singleton
180
+ has left its namespace behind without saying so. Such a flow states its tenant
181
+ explicitly rather than inheriting whatever the root scope happens to be.
182
+
183
+ ## Discovering implementations — `IInstancesOf<T>`, never `IEnumerable<T>`
184
+
185
+ When a type needs every implementation of an abstraction — handlers, strategies,
186
+ filters, validators, formatters — inject `IInstancesOf<TInterface>` from
187
+ `Cratis.Types`. The framework discovers and instantiates every implementation by
188
+ convention, so no explicit registration exists anywhere.
189
+
190
+ ```csharp
191
+ // Wrong — hand-maintained registrations. A new implementation added elsewhere
192
+ // silently does nothing until someone remembers this file, and dead
193
+ // registrations linger after types are removed.
194
+ services.AddSingleton<<IHandlerType>, <FirstHandler>>();
195
+ services.AddSingleton<<IHandlerType>, <SecondHandler>>();
196
+
197
+ public class <AggregatorName>(IEnumerable<<IHandlerType>> handlers) : <IAggregatorType>;
198
+
199
+ // Right — implementations discovered automatically
200
+ [Singleton]
201
+ public class <FirstHandler>(<CollaboratorType> <collaborator>) : <IHandlerType>;
202
+
203
+ [Singleton]
204
+ public class <SecondHandler>(<CollaboratorType> <collaborator>) : <IHandlerType>;
205
+
206
+ [Singleton]
207
+ public class <AggregatorName>(IInstancesOf<<IHandlerType>> handlers) : <IAggregatorType>;
208
+ ```
209
+
210
+ Rules:
211
+
212
+ - Never inject `IEnumerable<TInterface>` to enumerate implementations of an
213
+ abstraction. That signature works only when every implementation is
214
+ hand-registered, which defeats convention-based discovery.
215
+ - Never register a type that exists to be discovered. Mark it `[Singleton]`, or
216
+ rely on the `IFoo → Foo` convention for a transient, and delete the
217
+ registration line.
218
+ - `IInstancesOf<T>` resolves at the point of access, so an implementation added
219
+ later in the assembly becomes available without touching the consumer or any
220
+ composition root.
221
+ - `IEnumerable<T>` remains the right type to **return** from a method that
222
+ yields a sequence of values. The rule applies only to enumerating
223
+ *implementations* of an abstraction.
@@ -0,0 +1,2 @@
1
+ Copyright (c) Cratis. All rights reserved.
2
+ Licensed under the MIT license. See LICENSE file in the canonical Cratis/AI repository for the full license text.
@@ -0,0 +1,133 @@
1
+ ---
2
+ name: cratis-engineering-decision-record
3
+ description: Consult, author, accept, and supersede decision records in a Cratis repository's decisions/ folder. Use before an architectural, contract, scope, or cross-cutting change, when a ruling has been made that later work must obey, or when an accepted decision has to be replaced. Defer product documentation, session handovers, and work-item status to their own workflows.
4
+ license: LICENSE
5
+ ---
6
+
7
+ # Cratis decision records
8
+
9
+ A decision is a durable choice with a **decider** and a **date**. It is
10
+ documentation, not a work record: it lives in the repository's `decisions/`
11
+ folder and is reviewed like any other documentation. A handover may summarize a
12
+ decision; it never holds the only copy.
13
+
14
+ This skill owns the *procedure* — how to consult, author, accept, and supersede
15
+ a record. It does not decide what to decide, and it never grants acceptance.
16
+
17
+ ## When you need this
18
+
19
+ - You are about to make an architectural, contract, scope, or cross-cutting
20
+ change. Consult first: a decision you did not read still binds the change.
21
+ - A ruling was made — in review, in chat, in a meeting — that later work has to
22
+ obey. Record it in the same turn, while the reasoning is still available.
23
+ - An accepted decision no longer holds and has to be replaced, narrowed, or
24
+ qualified.
25
+ - Your change would contradict an accepted record. Stop: supersession or a human
26
+ verdict comes first, never a workaround.
27
+
28
+ ## When you do not
29
+
30
+ - **Session notes, plans, handovers, status boards.** Those are work records.
31
+ They belong in the repository's ignored local working directory, never in
32
+ `decisions/`.
33
+ - **Product or API documentation.** A record says what was chosen and why; the
34
+ documentation says how the thing works. Use the documentation workflow.
35
+ - **A work item's status.** "Blocked on X" is a work item field, not a decision.
36
+ - **A reversible choice inside your own scope that nobody will re-litigate.**
37
+ Make it and move on; see the significance test in step 2.
38
+ - **A decision this repository does not own.** Company-level and portfolio
39
+ decisions live in the record set that owns them. Cite that id; do not copy the
40
+ record into a repository that cannot supersede it.
41
+
42
+ ## Steps
43
+
44
+ 1. **List the records in force for the paths you are changing.** Read
45
+ `decisions/`, keep the records whose `applies-to` matches a path you are
46
+ about to touch and whose `status` is `accepted`, and order them newest first.
47
+ Report the count — "0 records matched" and "3 matched, none contradicted" are
48
+ different verdicts and must read differently.
49
+ 2. **Cite what you relied on.** Name the ids on the work item, in the pull
50
+ request body, and as a `Decision: <id>` commit trailer. A change that
51
+ silently contradicts an accepted record is a defect even when the code is
52
+ correct.
53
+ 3. **Apply the significance test before writing anything.** Write a record only
54
+ when at least one of these holds: someone will otherwise re-litigate the
55
+ choice; it binds paths beyond the one you are changing; reversing it would
56
+ cost real migration or rework; or it rejects an option a reasonable reader
57
+ would reach for. If none holds, say so and make the change without a record.
58
+ 4. **Pass the completeness gate, or open with `status: returned`.** A proposed
59
+ record states the options considered *including the one not taken and why*,
60
+ the default that applies if the question is never answered and what that
61
+ default costs, the timeline the decision has to hold to, and what is in scope
62
+ and out. A record missing any of the four is returned to its proposer for
63
+ revision — `returned` is not a rejection.
64
+ 5. **Write the verification criterion before acceptance, not after.** State the
65
+ observable signal that will say the decision was actually carried out, as
66
+ `Done when` and `Verify by`. A decision whose success cannot be observed
67
+ cannot reach `stage: verified`.
68
+ 6. **Open the record as `status: proposed`, `stage: none`, and regenerate the
69
+ index.** A record the index does not list is a record the consult step in
70
+ step 1 will never find.
71
+ 7. **Accept by recording a resolved actor and a date.** Set `status: accepted`,
72
+ `decided` to the date, and `decider` to a named person — never a role, a
73
+ team, or a tool. Acceptance is a human verdict: draft it, do not grant it.
74
+ 8. **Spawn the build work carrying the criterion verbatim.** The `Done when` and
75
+ `Verify by` text written in step 5 travels onto the work item unchanged, so
76
+ the thing that gets built is the thing that was decided.
77
+ 9. **Move `stage` only on the evidence the next stage requires.** `none` →
78
+ `implemented` when the change exists in the tree; `implemented` → `verified`
79
+ only on a signal observed this time. Accepted is not implemented, and
80
+ implemented is not verified.
81
+ 10. **Supersede rather than rewrite.** Never edit an accepted record's decision
82
+ text in place — that text is what people relied on. Correct a typo or add
83
+ context under a dated banner that says what changed and why. Change the
84
+ *choice* only with a new record.
85
+ 11. **Point both ways and sweep the citations.** The new record names the one it
86
+ replaces in `supersedes`; the replaced record's `status` becomes
87
+ `superseded` and it gains a `superseded-by` pointer forward, with its
88
+ original text preserved. Then find every work item, pull request body, and
89
+ commit trailer citing the old id and point it at the new one. A reader
90
+ arriving at either record must be able to reach the other.
91
+
92
+ The exact front-matter fields, the closed value sets, and the index shape are in
93
+ [record-format.md](references/record-format.md).
94
+
95
+ ## What breaks
96
+
97
+ - **A role in the `decider` field.** "The architecture team decided" names
98
+ nobody who can be asked what they meant or who can supersede it. The record
99
+ reads as authority but resolves to no one.
100
+ - **Decision text edited in place.** The next reader sees text nobody ever
101
+ agreed to, and the people who relied on the old wording have no way to tell
102
+ what changed. This is the failure that makes a whole `decisions/` folder
103
+ untrustworthy, because it is invisible.
104
+ - **A one-way supersession.** The new record says it supersedes the old one, but
105
+ the old one still reads as accepted. Whoever arrives from a search, a
106
+ citation, or an old pull request follows a decision that was replaced.
107
+ - **`stage: verified` set on a green build.** Compilation proves it builds, not
108
+ that the decision was carried out. The stage then lies about the only thing it
109
+ exists to say.
110
+ - **A ruling that stayed in chat.** It binds the next change and nobody can find
111
+ it. The symptom is the same argument being had a second time, with a different
112
+ outcome.
113
+ - **One record settling three questions.** It cannot be superseded for one of
114
+ them, so it survives past the point where a third of it is wrong.
115
+ - **An `applies-to` that matches nothing.** Step 1 returns zero records and reads
116
+ as "nothing binds this change" instead of "the glob is wrong". Report the count
117
+ so an empty result is visible rather than reassuring.
118
+
119
+ ## How it is proven
120
+
121
+ - **Consult ran and found something specific.** The count from step 1 appears in
122
+ the report, and the ids it returned appear on the work item, in the pull
123
+ request body, and in a `Decision:` commit trailer.
124
+ - **Acceptance resolves.** The record carries a `decided` date and a `decider`
125
+ that names a person you could actually ask.
126
+ - **Supersession is traversable.** Follow `superseded-by` forward and
127
+ `supersedes` back; both land on the other record. Search the repository for
128
+ the superseded id and confirm no live citation still points only at it.
129
+ - **The stage matches the evidence.** `implemented` is confirmed by the change
130
+ being in the tree; `verified` is confirmed by naming the signal — the command,
131
+ the gate, the observed behavior — that was watched *this time*.
132
+ - **The index resolves.** Every record in `decisions/` appears in the index, and
133
+ every index entry resolves to a file.
@@ -0,0 +1,107 @@
1
+ # Decision record format
2
+
3
+ The shape below is the one Cratis repositories that keep a `decisions/` folder
4
+ converge on. A repository that already defines a stricter local shape stays
5
+ authoritative; add fields there rather than dropping the ones listed here.
6
+
7
+ ## Front matter
8
+
9
+ | Field | Required | Meaning |
10
+ | --- | --- | --- |
11
+ | `id` | Yes | Stable identifier, unique in the repository, never reused after supersession. |
12
+ | `title` | Yes | The single question the record settles, stated as a choice. |
13
+ | `status` | Yes | Where the record stands in its own review lifecycle. Closed set below. |
14
+ | `stage` | Yes | How far an accepted decision has travelled from words into observed behavior. Closed set below. |
15
+ | `class` | Yes | What kind of choice this is, which sets who may settle it. Closed set below. |
16
+ | `reversibility` | Yes | What undoing it would cost. Closed set below. |
17
+ | `decided` | On acceptance | The date the decision was accepted. |
18
+ | `decider` | On acceptance | A named person. Never a role, a team, or a tool. |
19
+ | `applies-to` | Yes | The paths this record binds, as globs. What the consult step matches against. |
20
+ | `supersedes` | When replacing | The id of the record this one replaces. |
21
+ | `superseded-by` | When replaced | The id of the record that replaced this one. |
22
+
23
+ `status` and `superseded-by` move together: a record marked `superseded` without
24
+ a forward pointer strands every reader who arrives at it.
25
+
26
+ ## Closed value sets
27
+
28
+ Do not invent a word for a state one of these sets already names.
29
+
30
+ **`status`**
31
+
32
+ | Value | Meaning |
33
+ | --- | --- |
34
+ | `proposed` | Written and offered for a verdict; not yet in force. |
35
+ | `returned` | Sent back to the proposer for revision; not a rejection. |
36
+ | `accepted` | In force; binding on work that touches the paths it covers. |
37
+ | `rejected` | Refused; the choice it proposed is not taken. |
38
+ | `deferred` | Deliberately not settled yet, with the reason recorded. |
39
+ | `superseded` | Replaced by a later record, which it points at. |
40
+
41
+ **`stage`**
42
+
43
+ | Value | Meaning |
44
+ | --- | --- |
45
+ | `none` | Accepted, but nothing has been built against it yet. |
46
+ | `implemented` | The change the decision calls for exists in the tree. |
47
+ | `verified` | A signal observed this time confirms the implementation. |
48
+
49
+ **`class`**
50
+
51
+ | Value | Meaning |
52
+ | --- | --- |
53
+ | `strategy` | Direction, portfolio, or ownership of a body of work. |
54
+ | `contract` | An interface, schema, protocol, or release boundary others build on. |
55
+ | `product` | What is built, for whom, and what it promises. |
56
+ | `working` | A local, reversible choice inside one team's own scope. |
57
+
58
+ **`reversibility`**
59
+
60
+ | Value | Meaning |
61
+ | --- | --- |
62
+ | `reversible` | Undone at negligible cost; decide fast and revisit. |
63
+ | `costly` | Undone, but only by paying real migration or rework cost. |
64
+ | `irreversible` | Cannot be undone; requires a human verdict before acting. |
65
+
66
+ `class` and `reversibility` together say who may settle the record. A `strategy`
67
+ or `irreversible` record is never accepted by an agent.
68
+
69
+ ## Body sections
70
+
71
+ A record's body carries, in this order:
72
+
73
+ 1. **Context** — the situation that forced a choice, and what changes if nobody
74
+ chooses.
75
+ 2. **Decision** — the choice, in one paragraph, in the present tense. This is the
76
+ text that is never edited in place once the record is accepted.
77
+ 3. **Options considered** — including the one not taken and why. This is the part
78
+ a future reader needs most and the part nobody remembers.
79
+ 4. **Default if unanswered** — what happens if the question is never settled, and
80
+ what that costs. A record without this cannot be weighed against doing nothing.
81
+ 5. **Timeline and scope** — the horizon the decision holds to, what is in scope,
82
+ and what is explicitly out.
83
+ 6. **Verification** — `Done when` and `Verify by`, written before acceptance. The
84
+ observable signal that says the decision was carried out.
85
+ 7. **Consequences** — what this makes easier, what it makes harder, and what it
86
+ forecloses.
87
+
88
+ ## Corrections after acceptance
89
+
90
+ A typo fix or added context goes under a dated banner inside the record:
91
+
92
+ ```markdown
93
+ > **2026-03-04 — clarification.** The decision text below said "client"; every
94
+ > use of that word means the generated client SDK, not a consuming application.
95
+ > The choice itself is unchanged.
96
+ ```
97
+
98
+ Anything that changes the choice is a new record with two-way pointers, not a
99
+ banner.
100
+
101
+ ## Index
102
+
103
+ The folder carries an index listing every record with its id, title, status,
104
+ stage, decided date, and decider. The index is regenerated whenever a record is
105
+ added or its status changes; a record the index omits is a record the consult
106
+ step will never find. Two checks keep it honest: every file in the folder appears
107
+ in the index, and every index entry resolves to a file.
@@ -0,0 +1,2 @@
1
+ Copyright (c) Cratis. All rights reserved.
2
+ Licensed under the MIT license. See LICENSE file in the canonical Cratis/AI repository for the full license text.
@@ -0,0 +1,86 @@
1
+ ---
2
+ name: cratis-engineering-docs-authoring
3
+ description: Draft accurate Cratis documentation content after the owning repository, page placement, document type, and authoritative product sources are known. Use for tutorials, how-to guides, explanations, and references; defer placement, existing-page discovery, and visual QA to their companion workflows.
4
+ license: LICENSE
5
+ ---
6
+
7
+ # Cratis documentation authoring
8
+
9
+ Draft one accurate Cratis documentation page in the voice and structure required
10
+ by its document type. This skill owns **content**. It does not decide which
11
+ repository owns a page, wire site navigation, locate an existing source page, or
12
+ perform visual QA.
13
+
14
+ ## Required inputs
15
+
16
+ Before drafting, establish:
17
+
18
+ - the owning repository and destination page;
19
+ - document type: tutorial, how-to, explanation, or reference;
20
+ - target reader and the outcome they need;
21
+ - authoritative product source for every API, command, version, and capability;
22
+ - explicit scope and important exclusions.
23
+
24
+ Use repository evidence to resolve routine details. Ask only when materially
25
+ different document types, audiences, or product choices remain plausible.
26
+
27
+ ## Route near misses
28
+
29
+ - New-page placement or navigation is unresolved: defer to
30
+ `cratis-engineering-docs-add-page`.
31
+ - The request changes an existing page whose source location is unresolved:
32
+ defer to `cratis-engineering-docs-edit-page`.
33
+ - The request is to render, screenshot, or diagnose visual layout: defer to
34
+ `cratis-engineering-docs-visual-qa`.
35
+ - A product/API claim lacks first-party source evidence: stop and identify the
36
+ missing authority instead of drafting the claim.
37
+ - The subject is not Cratis product or engineering documentation: do not apply
38
+ this skill.
39
+
40
+ ## Write one document type
41
+
42
+ Do not mix Diátaxis types on one page:
43
+
44
+ | Type | Reader need | Shape |
45
+ | --- | --- | --- |
46
+ | Tutorial | Learn by completing a guided outcome | Ordered steps with visible results |
47
+ | How-to | Solve one concrete problem | Prerequisites, direct procedure, completion check |
48
+ | Explanation | Understand why and when | Concepts, boundaries, trade-offs, diagram |
49
+ | Reference | Look up exact information | Exhaustive tables, fields, commands, signatures |
50
+
51
+ For the detailed mechanical format, read
52
+ [site-format.md](references/site-format.md).
53
+
54
+ ## Drafting workflow
55
+
56
+ 1. Open with the reader's concrete friction and the Cratis capability that
57
+ relieves it.
58
+ 2. Organize by the reader's workflow, not by implementation namespaces or an
59
+ alphabetical API dump.
60
+ 3. Use active voice, present tense, second person, and American English.
61
+ 4. Explain the invisible behavior after each example: what the framework does
62
+ and why the boundary matters.
63
+ 5. Verify every API and command against first-party source at the applicable
64
+ revision. Never translate a C# example into another client language by guess.
65
+ 6. State maturity, authorization, side effects, unsupported surfaces, and when a
66
+ simpler approach is better.
67
+ 7. Show a visible result in tutorials and procedures. Use Mermaid for a
68
+ non-trivial explanation.
69
+ 8. End with the natural next page or workflow.
70
+
71
+ ## Correctness boundary
72
+
73
+ Never invent product APIs, customer claims, versions, support commitments,
74
+ marketplace availability, or private implementation details. Do not copy a code
75
+ sample from memory. If the source cannot prove a claim, omit it or mark the gap
76
+ for the owning maintainer.
77
+
78
+ A successful build proves rendering, not technical correctness. The owning
79
+ repository still runs its documentation, snippet, link, and product gates.
80
+
81
+ ## Output
82
+
83
+ Return or write the page content only at the already approved destination. Do
84
+ not modify navigation, generated copies, project context, credentials, package
85
+ manifests, or unrelated documentation. Report the authoritative source checked
86
+ and the verification that still remains.
@@ -0,0 +1,46 @@
1
+ # Cratis documentation site format
2
+
3
+ Use these rules for a page that will render on the Cratis Astro Starlight site.
4
+ The owning repository remains authoritative when it defines a stricter format.
5
+
6
+ ## Frontmatter and headings
7
+
8
+ - Include `title` and `description` frontmatter.
9
+ - Do not add a body H1; the site renders the title as H1.
10
+ - Start body sections at H2.
11
+ - Use sentence case and no trailing punctuation in headings.
12
+ - Keep the page's main workflow visible in H2 sections.
13
+
14
+ ## Code and commands
15
+
16
+ - Tag every code fence with its language.
17
+ - Dedent copied snippets to their natural source indentation.
18
+ - Use complete, runnable examples without ellipses.
19
+ - Verify examples against first-party product source.
20
+ - Use the client-owned multi-language snippet mechanism when shared product docs
21
+ support more than one client; do not hand-translate unsupported clients.
22
+
23
+ ## Links and navigation
24
+
25
+ - Use descriptive link text, never "here" or "read more."
26
+ - Use root-relative links between products.
27
+ - Keep site-level links extensionless.
28
+ - Preserve the owning product repository's source-link convention.
29
+ - Do not edit generated synchronized pages; edit the owning source repository.
30
+
31
+ ## Tables, asides, and diagrams
32
+
33
+ - Use GitHub-Flavored Markdown tables with a spaced separator row.
34
+ - Use Starlight or owning-repository note/caution syntax for boundaries and
35
+ security warnings.
36
+ - Use Mermaid for architecture, sequence, or state explanations.
37
+ - Give images meaningful alternative text.
38
+
39
+ ## File hygiene
40
+
41
+ - Use American English.
42
+ - End the file with one newline.
43
+ - Keep project paths, credentials, local endpoints, and private data out of
44
+ shared documentation.
45
+ - Run the owning repository's build, lint, snippet, and link checks before
46
+ calling the page complete.
@@ -0,0 +1,2 @@
1
+ Copyright (c) Cratis. All rights reserved.
2
+ Licensed under the MIT license. See LICENSE file in the canonical Cratis/AI repository for the full license text.