@cratis/pi 0.0.1 → 2.0.2
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,138 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**/*"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# How to Write Git Commits
|
|
6
|
+
|
|
7
|
+
Commits are the permanent record of how the codebase evolved. Each commit should tell a clear story: *what* changed and *why*. A reviewer reading `git log --oneline` should understand the arc of the work without opening any diffs.
|
|
8
|
+
|
|
9
|
+
## Never rewrite history
|
|
10
|
+
|
|
11
|
+
**Committed history is append-only. Never rewrite it — under any circumstances, on any branch, including your own.**
|
|
12
|
+
|
|
13
|
+
These commands are **forbidden** unless the human explicitly asks for that specific command on that specific branch in that specific message:
|
|
14
|
+
|
|
15
|
+
| Forbidden | Why |
|
|
16
|
+
|---|---|
|
|
17
|
+
| `git rebase` (any form, incl. `-i`, `--onto`, `--autosquash`) | rewrites every replayed commit; the originals become unreachable |
|
|
18
|
+
| `git commit --amend` | replaces the tip commit; the original is unreachable immediately |
|
|
19
|
+
| `git reset --hard`, `git reset` onto an earlier commit | discards commits and, with `--hard`, uncommitted work too |
|
|
20
|
+
| `git push --force`, `git push --force-with-lease`, `git push -f` | destroys the remote's copy — the one backup that survives local loss |
|
|
21
|
+
| `git branch -D` / `git branch -d` on a branch holding unmerged commits | strands those commits with no ref; `git gc` then deletes them |
|
|
22
|
+
| `git checkout`/`git switch` away while another agent's commits sit only on this branch | the commits leave with the branch and the working tree silently reverts |
|
|
23
|
+
| `git filter-branch`, `git filter-repo`, history-rewriting scripts | rewrites the entire history graph |
|
|
24
|
+
| `git gc --prune=now`, `git reflog expire` | destroys the recovery path for anything already stranded |
|
|
25
|
+
| `git merge --squash`, `gh pr merge --squash`, `--rebase`, the **Squash and merge** / **Rebase and merge** buttons | collapses or replays the branch's commits into new ones; every original commit becomes unreachable and the branch's real history is destroyed at the moment of merge |
|
|
26
|
+
|
|
27
|
+
**Merging is part of this rule, and it is the easiest place to get it wrong.** A squash merge feels
|
|
28
|
+
like an integration step rather than a rewrite, which is exactly why it slips past: the branch is
|
|
29
|
+
deleted straight afterwards, so the commits it collapsed have no ref left and `gc` eventually takes
|
|
30
|
+
them. **Always merge with a true merge commit** — `git merge --no-ff`, or `gh pr merge --merge`.
|
|
31
|
+
Never `--squash`, never `--rebase`, and never the equivalent buttons in the GitHub UI.
|
|
32
|
+
|
|
33
|
+
If a repository's settings only allow squash or rebase merges, that is a **setting to raise with the
|
|
34
|
+
owner, not a licence to squash.** Stop and ask.
|
|
35
|
+
|
|
36
|
+
**This is not stylistic.** A commit can exist as an object (`git cat-file -t <sha>` succeeds) while being absent from every branch *and* from the working tree — reachable only through `git reflog`, and only until `gc` runs. Work has already been lost in this repository exactly this way: a branch checkout carried another session's commit away, the branch was deleted, and the file changes silently reverted in the tree. It was recovered from the reflog by luck, because someone asked the right question in time.
|
|
37
|
+
|
|
38
|
+
### What to do instead
|
|
39
|
+
|
|
40
|
+
- **Made a mistake in the last commit?** Add a new commit that corrects it. The wrong state stays in history, and that is fine — history is a record of what happened, not a curated story of what you wish had happened.
|
|
41
|
+
- **Need to undo a commit?** `git revert <sha>` — it records the undo as a new commit and loses nothing.
|
|
42
|
+
- **Messy commits before a PR?** Leave them. A reviewer reading a coherent series of small commits is better served than by one squashed blob, and the project does not require a linear history.
|
|
43
|
+
- **Landing a PR?** `gh pr merge --merge` (a real merge commit). **Not `--squash`, not `--rebase`.** The commits on the branch are the record of how the change was actually built; squashing throws that away permanently in exchange for a tidier `main`, which is not a trade this project makes.
|
|
44
|
+
- **Need someone else's changes?** `git merge`, never `git rebase`.
|
|
45
|
+
- **Need to move a commit to another branch?** `git cherry-pick` — it copies, leaving the original reachable.
|
|
46
|
+
- **Working alongside another agent or session?** Use `git worktree add` so each has its own checkout and branch. Never two sessions committing in one working tree.
|
|
47
|
+
|
|
48
|
+
### Before you finish
|
|
49
|
+
|
|
50
|
+
Verify your own commits are still reachable on the branch **and** that their content is still in the working tree — those are two different things. `git log --oneline -5` plus a `grep` for something the commit introduced. If a commit has gone missing, `git reflog` is the recovery tool: find the SHA, `git tag` it immediately so `gc` cannot take it, then `git cherry-pick` it back.
|
|
51
|
+
|
|
52
|
+
## Logical Grouping
|
|
53
|
+
|
|
54
|
+
Every commit must be a **single logical unit of work**. Group related changes together; separate unrelated changes into distinct commits.
|
|
55
|
+
|
|
56
|
+
### What belongs in one commit
|
|
57
|
+
|
|
58
|
+
- A bug fix and the spec that proves it.
|
|
59
|
+
- A new file and the changes to existing files needed to integrate it (imports, registrations, wiring).
|
|
60
|
+
- A refactor that moves or renames code — only the mechanical transformation, nothing else.
|
|
61
|
+
- An interface change together with all implementation updates required to compile.
|
|
62
|
+
|
|
63
|
+
### What does NOT belong in one commit
|
|
64
|
+
|
|
65
|
+
- A bug fix mixed with an unrelated feature.
|
|
66
|
+
- Source code changes mixed with unrelated spec additions for a different area.
|
|
67
|
+
- Formatting or style cleanups bundled with behavioral changes.
|
|
68
|
+
- Multiple independent fixes or features squashed into a single commit.
|
|
69
|
+
|
|
70
|
+
### Deciding where to split
|
|
71
|
+
|
|
72
|
+
Ask: "If I needed to revert this commit, would I lose exactly one coherent change?" If reverting would undo two unrelated things, it should be two commits.
|
|
73
|
+
|
|
74
|
+
Common split points:
|
|
75
|
+
|
|
76
|
+
1. **Infrastructure / plumbing first** — interface additions, new types, or schema changes that later commits build on.
|
|
77
|
+
2. **Core logic second** — the behavioral change that uses the new infrastructure.
|
|
78
|
+
3. **Specs / tests third** — the specs that prove the behavioral change works. Specs may also be combined with the core logic commit when they are tightly coupled (e.g., a TDD red-green cycle or a bug fix with its regression test).
|
|
79
|
+
4. **Integration or wiring last** — connecting the new behavior to the rest of the system (DI registration, routing, UI hookup).
|
|
80
|
+
|
|
81
|
+
When a task produces both source fixes and new integration specs, prefer separate commits for the source changes and the specs — unless the specs are inseparable from the fix (e.g., a single bug fix + its regression test).
|
|
82
|
+
|
|
83
|
+
## Commit Messages
|
|
84
|
+
|
|
85
|
+
### Format
|
|
86
|
+
|
|
87
|
+
```text
|
|
88
|
+
<imperative summary of what this commit does>
|
|
89
|
+
|
|
90
|
+
<optional body — why the change was made, context, trade-offs>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
- **Subject line**: imperative mood, present tense. Start with a verb: `Add`, `Fix`, `Remove`, `Rename`, `Extract`, `Update`, `Support`.
|
|
94
|
+
- **No period** at the end of the subject line.
|
|
95
|
+
- **72-character limit** on the subject line. If you cannot describe the change in 72 characters, the commit is probably too large — split it.
|
|
96
|
+
- **Body**: separated from the subject by a blank line. Explain *why*, not *what* (the diff shows the what). Use bullet points for multi-part changes.
|
|
97
|
+
|
|
98
|
+
### Good examples
|
|
99
|
+
|
|
100
|
+
```text
|
|
101
|
+
Fix duplicate key crash in IdentityStorage.Populate
|
|
102
|
+
|
|
103
|
+
The upsert used InsertOne which threw on existing identities.
|
|
104
|
+
Replace with ReplaceOne using upsert: true.
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
```text
|
|
108
|
+
Add type-safe event migration API with expression-based builders
|
|
109
|
+
|
|
110
|
+
Introduce EventTypeMigration<TUpgrade, TPrevious> base class with
|
|
111
|
+
typed property builders for Split, Join, Rename, and DefaultValue
|
|
112
|
+
operations. Migrators are discovered automatically by convention.
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
```text
|
|
116
|
+
Add integration specs for observer replay on redaction
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Bad examples
|
|
120
|
+
|
|
121
|
+
- `Fix stuff` — meaningless.
|
|
122
|
+
- `WIP` — never commit work-in-progress; stage and commit when the unit is complete.
|
|
123
|
+
- `Add files` — says nothing about what or why.
|
|
124
|
+
- `Fix bug and add new feature and update docs` — three unrelated things.
|
|
125
|
+
- `Changed Observer.Handling.cs` — describes a file, not a behavior.
|
|
126
|
+
|
|
127
|
+
## When to Commit
|
|
128
|
+
|
|
129
|
+
- **After each logical unit passes the build** — `dotnet build` with zero errors and zero warnings, or `yarn compile` with zero errors.
|
|
130
|
+
- **Before starting a different kind of work** — about to switch from fixing a bug to adding a feature? Commit the bug fix first.
|
|
131
|
+
- **After completing specs for a change** — if the specs are a separate commit from the source change.
|
|
132
|
+
- **Never commit code that does not compile.** Every commit must be a buildable, working state of the codebase.
|
|
133
|
+
|
|
134
|
+
## Staging Discipline
|
|
135
|
+
|
|
136
|
+
- Use `git add <specific files>` rather than `git add .` or `git add -A`. Only stage files that belong to the current logical unit.
|
|
137
|
+
- Review `git diff --cached` before committing to verify nothing unrelated was staged.
|
|
138
|
+
- If you realize mid-commit that unrelated changes are mixed in, unstage them and commit only the related subset.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: ".github/workflows/**"
|
|
3
|
+
paths:
|
|
4
|
+
- ".github/workflows/**"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# GitHub Actions workflows: capacity, cost, and release discipline
|
|
8
|
+
|
|
9
|
+
> **Why this rule exists.** On 2026-08-25 the organization's hosted runners starved for
|
|
10
|
+
> most of a working day: every repository ran its scheduled jobs at the same minute,
|
|
11
|
+
> hour-long jobs with no timeout occupied the shared concurrency pool, and a
|
|
12
|
+
> comment-triggered assistant booted a runner for every comment in two repositories.
|
|
13
|
+
> The remediation that followed is encoded here so it stays true.
|
|
14
|
+
|
|
15
|
+
## The budget you are spending
|
|
16
|
+
|
|
17
|
+
- The whole organization shares **one hosted-runner concurrency pool** (20 concurrent
|
|
18
|
+
jobs on the Free plan, 5 for macOS). Every queued job competes with every repository.
|
|
19
|
+
- **Public repositories** run free on hosted runners; **private repositories bill every
|
|
20
|
+
minute** — Linux 1×, Windows 2×, macOS 10× — against a small monthly allowance.
|
|
21
|
+
- The organization runs its own scale set (`cratis-arc`). Jobs there cost nothing and
|
|
22
|
+
do not touch the hosted pool.
|
|
23
|
+
|
|
24
|
+
## Scheduling
|
|
25
|
+
|
|
26
|
+
- **Never schedule on the top of the hour**, and never copy another repository's cron.
|
|
27
|
+
`0 6 * * *` in 36 repositories produced a 270-job stampede into 20 slots. Pick a
|
|
28
|
+
deterministic offset unique to the repository (minute 1–59, spread across 03:00–07:00 UTC).
|
|
29
|
+
- A scheduled workflow that exists to keep coverage (nightly full matrix, health probe)
|
|
30
|
+
should run the *narrowest* thing that preserves the claim it exists to make.
|
|
31
|
+
- **A scheduled workflow whose subject no longer exists is deleted, not left running.**
|
|
32
|
+
It still queues into the shared pool every day, and a scheduled no-op is the worst
|
|
33
|
+
kind: it never fails, so nothing ever draws attention to it. Deleting it is also the
|
|
34
|
+
only way to stop handing it whatever secrets it was passed — `Cratis/AI` ran a daily
|
|
35
|
+
package update against a repository with no package manifest of any kind, checking out
|
|
36
|
+
the full history under an organization-wide write PAT to find nothing to update.
|
|
37
|
+
|
|
38
|
+
## Every job, always
|
|
39
|
+
|
|
40
|
+
- **`timeout-minutes` on every job.** The default is 6 hours; one hung job holds a
|
|
41
|
+
pool slot for all of it. Tiers that work: quick checks 15, builds 30–45,
|
|
42
|
+
publish/release 60, integration/benchmarks 120.
|
|
43
|
+
- **A `concurrency` group on every pull-request verification workflow** with
|
|
44
|
+
`cancel-in-progress: true`, keyed `${{ github.workflow }}-${{ github.ref }}`.
|
|
45
|
+
**Never** cancel-in-progress on publish, release, or deploy workflows — a cancelled
|
|
46
|
+
half-publish is worse than a queued one.
|
|
47
|
+
|
|
48
|
+
## Matrices and operating systems
|
|
49
|
+
|
|
50
|
+
- Run the full OS matrix on `schedule`/`workflow_dispatch`; run **Linux only on pull
|
|
51
|
+
request syncs**. Windows bills double and macOS ten-fold, and per-PR duplication has
|
|
52
|
+
to earn that cost with unique signal. (Measured before adopting this: 75 dual-OS runs
|
|
53
|
+
of one private repository, zero Windows-only failures.)
|
|
54
|
+
- Skip the expensive job entirely for documentation-only changes: a cheap change-detection
|
|
55
|
+
job (`git diff --name-only HEAD^1 HEAD` on the merge commit) gating the build job.
|
|
56
|
+
|
|
57
|
+
## Runners
|
|
58
|
+
|
|
59
|
+
- Private-repository jobs belong on the organization scale set: `runs-on: cratis-arc`,
|
|
60
|
+
or a repository variable such as `${{ vars.<REPO>_RUNNER || 'ubuntu-latest' }}` so
|
|
61
|
+
routing changes without a code change.
|
|
62
|
+
- On self-hosted runners, `actions/setup-dotnet` cannot write `/usr/share/dotnet`.
|
|
63
|
+
Set `DOTNET_INSTALL_DIR: ${{ runner.temp }}/dotnet` on the setup step.
|
|
64
|
+
- **Never** route `pull_request`-triggered jobs of a *public* repository to self-hosted
|
|
65
|
+
runners — that hands code execution on our infrastructure to any fork.
|
|
66
|
+
|
|
67
|
+
## Automation that writes back
|
|
68
|
+
|
|
69
|
+
- A bot that pushes to a branch must **retry with `git pull --rebase`** — the branch
|
|
70
|
+
moves while the job runs, and a plain push loses the whole run to a non-fast-forward.
|
|
71
|
+
- A bot's pre-push verification build must match the strictest configuration any CI in
|
|
72
|
+
the organization applies to the same commit (build `Release` when consumers enforce
|
|
73
|
+
analyzers there). Do not add `[skip ci]` to bot commits as a load optimization: the
|
|
74
|
+
downstream CI run is the only check that sees the merged result.
|
|
75
|
+
- Comment-triggered agent workflows must gate on the trigger phrase in the job's `if:`
|
|
76
|
+
(for example `contains(github.event.comment.body, '@claude')`) so a runner only
|
|
77
|
+
starts when the agent is actually addressed.
|
|
78
|
+
|
|
79
|
+
## Releases
|
|
80
|
+
|
|
81
|
+
- A pull request that changes nothing outward-facing — workflow edits, CI configuration,
|
|
82
|
+
documentation — carries the **`no-release`** label, never `patch`. See
|
|
83
|
+
[`pull-requests.md`](./pull-requests.md). Merging config-only work under `patch` cut
|
|
84
|
+
four unintended releases on 2026-08-25.
|
|
85
|
+
- Every repository's release-intent gate must accept `no-release`; a gate that only
|
|
86
|
+
accepts `major`/`minor`/`patch` forces exactly that mistake.
|
|
87
|
+
|
|
88
|
+
## In this repository specifically
|
|
89
|
+
|
|
90
|
+
- Keep one workflow that runs `Source/Verification`, checks harness adapters, and
|
|
91
|
+
uses `cratis/release-action` for semantic versioning and release decisions.
|
|
92
|
+
- Do not add evidence, provenance, inventory, or generated-catalog gates.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**/*"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Cratis Glossary
|
|
6
|
+
|
|
7
|
+
One precise line per load-bearing term, so the same word means the same thing everywhere. When a rule or skill uses one of these, this is the definition it intends.
|
|
8
|
+
|
|
9
|
+
## Events & streams
|
|
10
|
+
|
|
11
|
+
- **Event** — an immutable, past-tense **fact** that something happened; an `[EventType]` record. Never mutated; lives in the log forever.
|
|
12
|
+
- **Event source** — the entity an event stream belongs to (the stream key); identified by an `EventSourceId<T>`.
|
|
13
|
+
- **Event source id** — the strongly-typed identity of an event source (`EventSourceId<T>`). Implicit in the event context — **never** an event payload property.
|
|
14
|
+
- **Event stream** — the ordered events for one event source within an event sequence.
|
|
15
|
+
- **Event sequence** — a named, append-ordered log; `EventSequenceId` (the event **log**, **outbox**, **inbox**).
|
|
16
|
+
- **Event log** — the default event sequence where domain events are appended.
|
|
17
|
+
- **Outbox / inbox** — cross-service event sequences: a producer appends its public contract event to the outbox; a consumer observes the inbox.
|
|
18
|
+
- **EventContext** — metadata traveling with an event (event source id, sequence number, occurred, causation/correlation, subject).
|
|
19
|
+
|
|
20
|
+
## Read side
|
|
21
|
+
|
|
22
|
+
- **Read model** — a `[ReadModel]` record holding queryable derived state, built by a projection or reducer; exposes `static` query methods.
|
|
23
|
+
- **Projection** — declares how a read model is built by consuming **events** (model-bound attributes, or fluent `IProjectionFor<T>`); pure events→state, no side effects, never reads other read models.
|
|
24
|
+
- **Reducer** — `IReducerFor<T>`; a "current state + event → next state" read-model builder; the last-resort escape hatch when projections can't express the transition.
|
|
25
|
+
- **Reactor** — `IReactor`; observes events and produces **side effects** (notifications, commands, follow-up events). The "if this then that".
|
|
26
|
+
- **Observer** — Chronicle's umbrella for anything consuming an event sequence (projection, reducer, reactor); carries subscription / replay / **quarantine** state.
|
|
27
|
+
- **Sink** — where a read model is persisted (MongoDB, EF Core).
|
|
28
|
+
- **AutoMap** — Chronicle's on-by-default mapping of matching event→read-model property names; **never call `.AutoMap()`**.
|
|
29
|
+
- **Query** — a `static` method on a `[ReadModel]`; returns derived state, **snapshot** (one-shot) or **observable** (live).
|
|
30
|
+
|
|
31
|
+
## Write side
|
|
32
|
+
|
|
33
|
+
- **Command** — a `[Command]` record expressing an imperative **intent**; its public `Handle()` produces event(s) (or a response).
|
|
34
|
+
- **Provide()** — the command method that fetches/computes data after validation/authorization and before `Handle()`; may short-circuit with a `ValidationResult`.
|
|
35
|
+
- **Causation chain** — the ordered links saying how an append came about (root process → command → …), each carrying properties. A command records its **name and its property values** there, so an event says what the command was asked to do; the chain lives in the event log and is as permanent as the events.
|
|
36
|
+
- **Constraint** — `IConstraint`; an **append-time** invariant (uniqueness / concurrency) enforced at the event-store level.
|
|
37
|
+
- **DCB (Dynamic Consistency Boundary)** — enforcing a state-dependent rule **under concurrency** by injecting the read model into `Handle()` and returning `Result<TEvent, ValidationResult>`.
|
|
38
|
+
- **Consistency boundary** — the scope within which an invariant holds atomically (an event source, or the read model a DCB rule inspects).
|
|
39
|
+
- **EventForEventSourceId** — self-describing wrapper to append an event to a **specific** (cross-stream) event source, from a command `Handle()` or from a reactor handler (reactor support has shipped since Chronicle 15.35). It carries the event stream type and id, source type, subject, occurred time, tags and causation, so it is also how a reactor sets those explicitly.
|
|
40
|
+
- **ReactorDelivery** — the identity of one delivery of one event to one reactor partition; declare it as a handler parameter and Chronicle passes it in. Stable across a replay and across recovering a failed partition, so a receipt kept under its `Id` is what makes a side effect survive re-delivery. An identity, not a guarantee — Chronicle does not know whether the effect ran.
|
|
41
|
+
|
|
42
|
+
## Structure & types
|
|
43
|
+
|
|
44
|
+
- **Slice** — the vertical unit of one behavior (command + events + projection + read model + component + specs), created/changed/deleted together.
|
|
45
|
+
- **Slice types** — **State Change** (command → events), **State View** (events → read model), **Automation** (events → side effect), **Translation** (events → follow-up events).
|
|
46
|
+
- **Concept** — a `ConceptAs<T>`, a strongly-typed wrapper over a primitive domain value (never raw `Guid`/`string`/`int`).
|
|
47
|
+
- **EventSourceId<T>** — the strongly-typed event-source identity; derive entity identities from this, not `ConceptAs<Guid>`.
|
|
48
|
+
- **Proxy** — the generated TypeScript command/query client, produced from C# on a **Debug** build; carries a `// @generated by Cratis` header and is never hand-edited.
|
|
49
|
+
|
|
50
|
+
## Compliance & multi-tenancy
|
|
51
|
+
|
|
52
|
+
- **Subject / `[Subject]`** — the natural person a piece of PII belongs to (for GDPR erasure); defaults to the `EventSourceId<T>` identity.
|
|
53
|
+
- **`[PII]`** — marks an inherently personal value so Chronicle can manage/erase it.
|
|
54
|
+
- **`[NotAudited]`** — an **Arc** marking (`Cratis.Arc.Chronicle.Commands`, not a Chronicle type) for a value that is secret but *not* personal data (password, token, API key), so it is never written to the causation chain. Withholds only; it does not encrypt or enroll the value in erasure the way Chronicle's `[PII]` does.
|
|
55
|
+
- **`[OnceOnly]`** — marks a reactor handler (or the whole reactor class) as non-replayable: Chronicle skips it for every event arriving as part of a **replay** — observer rewind, redaction, revision. Replay-exclusion only, not exactly-once and not per-event-source deduplication; recovering a failed partition re-delivers the event as an ordinary observation and the handler runs again. Use a `ReactorDelivery` receipt for that case.
|
|
56
|
+
- **Namespace / tenant** — Chronicle isolates tenants by **namespace**; each namespace has its own events, observers, and read models.
|
|
57
|
+
|
|
58
|
+
## Profiles
|
|
59
|
+
|
|
60
|
+
- **Application profile** — building an app *on* Cratis (event-sourced CQRS, vertical slices, MVVM frontend).
|
|
61
|
+
- **Framework profile** — contributing to a Cratis framework repo *itself* (Arc, Chronicle, Fundamentals, Components — libraries). See `framework.md`.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**/*"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Guards, scans and fuses
|
|
6
|
+
|
|
7
|
+
A guard that cannot fail is worse than no guard: it converts "nobody looked" into a green
|
|
8
|
+
check. Every line is tagged **[contract]** (binding) or **[convention]** (the house
|
|
9
|
+
default) per the Three Levels of Authority in [`general.md`](./general.md).
|
|
10
|
+
|
|
11
|
+
## Non-vacuity
|
|
12
|
+
|
|
13
|
+
- **[contract] A scan over a possibly-empty population carries a non-vacuity check.**
|
|
14
|
+
Assert the subject count is what you expect before believing the result, and fail when
|
|
15
|
+
the population is unexpectedly empty.
|
|
16
|
+
- **[contract] Report the count on success.** "Checked 0 files, found 0 problems" and
|
|
17
|
+
"checked 412 files, found 0 problems" are different verdicts and must read differently.
|
|
18
|
+
- **[contract] A pattern that matches nothing is a defect in the pattern** until proven
|
|
19
|
+
otherwise. Prove a matcher still matches by planting a violation; see
|
|
20
|
+
[`exit-codes-and-wrappers.md`](./exit-codes-and-wrappers.md).
|
|
21
|
+
|
|
22
|
+
## Allowlists
|
|
23
|
+
|
|
24
|
+
- **[contract] Every allowlist entry records its reason** — why this subject is exempt,
|
|
25
|
+
and what would end the exemption.
|
|
26
|
+
- **[contract] Every allowlist entry has a sibling check** that fails when the entry
|
|
27
|
+
becomes unnecessary, so the list shrinks instead of accumulating forever.
|
|
28
|
+
- **[convention] Prefer an expiry to a permanent exemption.** An entry nobody revisits is
|
|
29
|
+
a rule quietly deleted.
|
|
30
|
+
|
|
31
|
+
## Destructive passes
|
|
32
|
+
|
|
33
|
+
- **[contract] Distinguish "subject set empty" from "qualifying set empty".** Finding no
|
|
34
|
+
candidates at all is a different situation from finding candidates that none qualified;
|
|
35
|
+
an unattended pass must refuse to proceed on the first.
|
|
36
|
+
- **[contract] Every unattended destructive pass carries a per-pass fuse** — a maximum
|
|
37
|
+
number of subjects it may act on in one run, which stops the run rather than trimming
|
|
38
|
+
the work silently.
|
|
39
|
+
- **[contract] Prepare the inverse before the forward action**, per the Interactive Agent
|
|
40
|
+
Mutation Protocol in [`general.md`](./general.md). If an exact inverse or a safe
|
|
41
|
+
compensation cannot be prepared, stop.
|
|
42
|
+
- **[contract] Re-read preconditions immediately before each mutation and stop on drift.**
|
|
43
|
+
An authorization is for the state that was shown, not for whatever the state became.
|
|
44
|
+
- **[convention] Dry-run output is the review artifact.** If a human cannot tell from the
|
|
45
|
+
dry run exactly what will change, the dry run is not finished.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**/*"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Local AI work artifacts belong in `.ai-work/` only
|
|
6
|
+
|
|
7
|
+
AI-assisted sessions produce working artifacts: plans, handover documents, session
|
|
8
|
+
notes, continuation prompts, status boards, TODO and scratch analyses, research
|
|
9
|
+
dumps, and similar coordination files. These are **work records, not documentation**.
|
|
10
|
+
|
|
11
|
+
- Create every such artifact inside **`.ai-work/`** at the repository root — never at
|
|
12
|
+
the repository root itself, never under documentation folders, never anywhere else.
|
|
13
|
+
- `.ai-work/` is listed in `.gitignore` and must stay untracked. Never commit anything
|
|
14
|
+
inside it, never `git add -f` anything inside it, and never remove the ignore entry.
|
|
15
|
+
- These artifacts must never enter git history or reach GitHub — not on any branch.
|
|
16
|
+
If you find one tracked in git, move it into `.ai-work/` and remove it from
|
|
17
|
+
tracking in a dedicated commit.
|
|
18
|
+
- A genuine follow-up that must survive the session is **not** a work record — suggest
|
|
19
|
+
opening a GitHub issue for it (or open one when asked) so future work is tracked
|
|
20
|
+
where everyone can see it, instead of leaving a planning file behind.
|
|
21
|
+
- Knowledge that must outlive the session (real documentation, ADRs, operator
|
|
22
|
+
guides) is written deliberately into the repository's documentation structure
|
|
23
|
+
through normal review — not left behind as a work record.
|
|
24
|
+
- **A decision log is not a work record.** A decision — a durable choice with a
|
|
25
|
+
decider and a date — is documentation: it lives in **`decisions/`** (or the
|
|
26
|
+
repository's documented decisions folder) and is reviewed like any other
|
|
27
|
+
documentation. A handover may summarize decisions; it never holds the only
|
|
28
|
+
copy. If a session produced a real decision, land the record in `decisions/`
|
|
29
|
+
before the session's `.ai-work/` files are discarded.
|
|
30
|
+
- The record's shape (front matter, status and stage values, supersession
|
|
31
|
+
pointers) is defined by the decision-record skill and the shared vocabulary
|
|
32
|
+
once this repository carries them; until then use the repository's existing
|
|
33
|
+
decisions folder and keep decider and date explicit.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: ".cratis/ai/**,.claude/**,.github/**,.agents/**,.pi/**,.cursor/**,.opencode/**,Source/**"
|
|
3
|
+
paths:
|
|
4
|
+
- ".cratis/ai/**"
|
|
5
|
+
- ".claude/**"
|
|
6
|
+
- ".github/**"
|
|
7
|
+
- ".agents/**"
|
|
8
|
+
- ".pi/**"
|
|
9
|
+
- ".cursor/**"
|
|
10
|
+
- ".opencode/**"
|
|
11
|
+
- "Source/**"
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Managing Cratis AI
|
|
15
|
+
|
|
16
|
+
`.cratis/ai` is the only canonical corpus. Edit rules, agents, prompts, skills,
|
|
17
|
+
hooks, and harness-specific source assets there.
|
|
18
|
+
|
|
19
|
+
Harness folders are adapters, not copies:
|
|
20
|
+
|
|
21
|
+
- Claude Code: `.claude`
|
|
22
|
+
- Codex: `.agents` and `AGENTS.md`
|
|
23
|
+
- GitHub Copilot: `.github`
|
|
24
|
+
- Cursor: `.cursor`
|
|
25
|
+
- OpenCode: `.opencode` and `AGENTS.md`
|
|
26
|
+
- Pi: `.pi` and `AGENTS.md`
|
|
27
|
+
|
|
28
|
+
Run `npm run setup --prefix Source/Harness.Setup` after adding or removing an
|
|
29
|
+
agent, prompt, or harness asset. Run the same command with `-- --check` to verify
|
|
30
|
+
that every adapter points to the canonical corpus.
|
|
31
|
+
|
|
32
|
+
The managed consumer path is `cratis ai install`. It resolves
|
|
33
|
+
`.cratis/ai.json`, installs selected content, records hashes in
|
|
34
|
+
`.cratis/ai.manifest.json`, and configures every selected harness. Native plugins
|
|
35
|
+
are independent single-harness integrations and do not provide that managed
|
|
36
|
+
lifecycle.
|
|
37
|
+
|
|
38
|
+
Do not add a second corpus, generated catalog tree, provenance ledger, or
|
|
39
|
+
repository inventory. Quality comes from focused verification in
|
|
40
|
+
`Source/Verification` and review of the source diff.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**/*.cs"
|
|
3
|
+
profile: framework
|
|
4
|
+
paths:
|
|
5
|
+
- "**/*.cs"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Orleans Conventions
|
|
9
|
+
|
|
10
|
+
> **⚠️ APPLIES ONLY TO PROJECTS USING MICROSOFT ORLEANS**
|
|
11
|
+
> If your project does not reference `Microsoft.Orleans` or any Orleans packages, **ignore this entire file**. These rules are irrelevant outside of Orleans contexts.
|
|
12
|
+
|
|
13
|
+
These conventions apply to projects that use Microsoft Orleans for distributed grain-based actors.
|
|
14
|
+
|
|
15
|
+
## General
|
|
16
|
+
|
|
17
|
+
- Do **not** split Orleans grain interfaces into a separate project. Keep all grain types in the same project as their implementations.
|
|
18
|
+
- Use localhost clustering for local development (`UseLocalhostClustering()`).
|
|
19
|
+
- Do **not** add `[Alias]` attributes to grain interfaces or methods — rely on the default alias generated by Orleans.
|
|
20
|
+
|
|
21
|
+
## Storage Providers
|
|
22
|
+
|
|
23
|
+
- Centralize all storage provider names in a single `WellKnownStorageProviders` static class at the root of the project.
|
|
24
|
+
- Reference provider names via the constants in `WellKnownStorageProviders` — never use magic strings.
|
|
25
|
+
- Use `WellKnownStorageProviders.Default` as the name for the primary MongoDB-backed storage provider.
|
|
26
|
+
|
|
27
|
+
```csharp
|
|
28
|
+
public static class WellKnownStorageProviders
|
|
29
|
+
{
|
|
30
|
+
public const string Default = "MongoDbGrainStorage";
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
- Annotate grains with `[StorageProvider(ProviderName = WellKnownStorageProviders.Default)]` when they need persistent state.
|
|
35
|
+
|
|
36
|
+
## MongoDB Grain Storage
|
|
37
|
+
|
|
38
|
+
- The `MongoDbGrainStorage<TState>` implementation accepts `IMongoCollection<TState>` as its only dependency — no additional plumbing is required.
|
|
39
|
+
- Register it as a keyed singleton in the Orleans silo builder:
|
|
40
|
+
|
|
41
|
+
```csharp
|
|
42
|
+
builder.Host.UseOrleans(siloBuilder =>
|
|
43
|
+
{
|
|
44
|
+
siloBuilder.UseLocalhostClustering();
|
|
45
|
+
siloBuilder.Services.AddKeyedSingleton<IGrainStorage>(
|
|
46
|
+
WellKnownStorageProviders.Default,
|
|
47
|
+
(sp, _) => new MongoDbGrainStorage<MyState>(
|
|
48
|
+
sp.GetRequiredService<IMongoCollection<MyState>>()));
|
|
49
|
+
});
|
|
50
|
+
```
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
applyTo: "**/*"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# How to Do Pull Requests
|
|
6
|
+
|
|
7
|
+
PR descriptions serve two purposes: they help reviewers understand the change *now*, and they become the release notes that users read *later*. Write them with both audiences in mind.
|
|
8
|
+
|
|
9
|
+
## Description
|
|
10
|
+
|
|
11
|
+
- Follow the repository's pull request template (`.github/pull_request_template.md`).
|
|
12
|
+
- Focus on the **Added**, **Changed**, **Fixed**, **Removed**, **Security**, and **Deprecated** sections. Remove sections that are empty — don't leave blank headings.
|
|
13
|
+
- Each bullet should be short, self-contained, and release-note ready.
|
|
14
|
+
- **Write for users of the framework, not for internal developers.** Only include changes that have an impact on anyone using what we build — new APIs, changed behavior, fixed bugs, removed features. Do not list internal implementation details like storage changes, converter updates, gRPC contract internals, or spec additions. If a change is purely internal plumbing, it does not belong in the PR description.
|
|
15
|
+
- Add the associated issue reference at the end of a bullet when there is a real GitHub issue for the change (e.g. `(#351)`). Keep it a bare reference — **no closing keywords** (`Closes #351`, `Fixes #351`) anywhere in the body, because the published release notes are the PR description verbatim. If there is no associated issue, omit the reference entirely. Never use a placeholder like `(#issue)` or leave the example number `(#123)` literally, and never invent a random issue number. **Always verify the issue number read-only using the accepted repository source — never guess or invent a number.** Issue comments and closure are separate notification/effect operations: prepare a bounded post-merge disposition, but do not perform either unless the repository has a current exact operation profile and authority.
|
|
16
|
+
- Include a summary only if there is a cohesive theme across the changes. If you find yourself restating individual bullets in slightly different words, the summary adds no value — remove it.
|
|
17
|
+
- Never include Copilot prompt content in the PR description. Remove any "Original prompt" / coding agent transcript blocks before publishing.
|
|
18
|
+
|
|
19
|
+
## Commits
|
|
20
|
+
|
|
21
|
+
See the full [Git Commits guide](./git-commits.md) for rules on logical grouping, message format, and staging discipline.
|
|
22
|
+
|
|
23
|
+
Quick reminders:
|
|
24
|
+
|
|
25
|
+
- Imperative mood: "Add author registration" not "Added author registration".
|
|
26
|
+
- Each commit = one logical unit of work. No WIP commits in the final PR.
|
|
27
|
+
- Never mix unrelated changes in a single commit.
|
|
28
|
+
|
|
29
|
+
## Labels
|
|
30
|
+
|
|
31
|
+
Confirm the current repository workflow contract before selecting release intent. Label mutations, merge, and any resulting publication/release require separate explicit authorization for their exact effects; a descriptive label does not grant authority.
|
|
32
|
+
|
|
33
|
+
**Release-intent labels can trigger publication.** Confirm the repository’s current workflows and declared effects; never assume an absent label prevents publication. A proposed semantic label describes impact, not permission to publish.
|
|
34
|
+
|
|
35
|
+
- Label the PR according to semantic versioning impact:
|
|
36
|
+
- **major** — breaking changes to public APIs
|
|
37
|
+
- **minor** — new features, new slices, non-breaking additions
|
|
38
|
+
- **patch** — bug fixes, refactoring with identical behavior
|
|
39
|
+
|
|
40
|
+
### A pull request that changes nothing outward-facing carries `no-release`
|
|
41
|
+
|
|
42
|
+
**If nothing in the PR can change what a consumer compiles against, runs, or observes, propose repository-supported non-release intent, ordinarily `no-release`** — not `patch`. Confirm that the current workflow supports the label, requires exactly one release-intent label, and suppresses publication as intended before applying it with authorization.
|
|
43
|
+
|
|
44
|
+
Where the repository requires release intent, `no-release` is a decision, not an omission. Missing required labels are blockers, not a reason to bypass the check.
|
|
45
|
+
|
|
46
|
+
This covers, whenever the PR touches *only* these:
|
|
47
|
+
|
|
48
|
+
- **Documentation** — anything under `Documentation/**`, READMEs, the `.cratis/ai/` corpus.
|
|
49
|
+
- **CI and repository automation** — `.github/workflows/**`, `.github/scripts/**`, `.github/CODEOWNERS`, issue/PR templates.
|
|
50
|
+
- **Tests and specs** — `*.Specs/**`, `when_*/**`, `for_*/**`, `Integration/**`, and test-only fixtures.
|
|
51
|
+
- **Build and tooling configuration** that produces no shipped artifact difference — lint config, editor config, local scripts.
|
|
52
|
+
|
|
53
|
+
The test is **outward-facing effect, not file location**. A change under `Source/**` that only touches specs is not shippable; a one-line change to a published package's behavior is, however small. If a consumer could not tell the difference by upgrading, there is nothing to version. When genuinely unsure, ask rather than defaulting to `patch` — an unnecessary release is not free: it burns a version number, ships release notes describing nothing, and buries the releases that matter.
|
|
54
|
+
|
|
55
|
+
A non-release pull request must satisfy the relevant required checks like any other. Confirm label acceptance and publication suppression against the current workflow contract; do not assume external CI or API state.
|
|
56
|
+
|
|
57
|
+
### Group small related changes into one pull request
|
|
58
|
+
|
|
59
|
+
Do not open a pull request per task when the tasks belong to the same body of work. Several small merged PRs become several releases, and a stream of near-empty patch releases makes the release history useless for the people it is written for. Collect related work — a set of CI gates, a group of fixes in one area, the steps of one refactor — onto **one branch, as separate commits**, and open **one** pull request. Commits stay one-logical-unit-each; the pull request is the release boundary, and the release boundary should be a coherent, describable change.
|
|
60
|
+
|
|
61
|
+
**Before consolidating open PRs, review each PR’s release intent and workflow effects.** Integration may trigger completion/publication behavior on an absorbed PR. Propose supported non-release intent where appropriate; obtain separate explicit authorization before relabeling or merging exact targets. Never assume consolidation silently updates release intent or authorizes notifications.
|
|
62
|
+
|
|
63
|
+
Split into separate pull requests when the changes are genuinely unrelated, when one is urgent and the others are not, or when one is risky enough to want its own revert.
|
|
64
|
+
|
|
65
|
+
## Quality Gates
|
|
66
|
+
|
|
67
|
+
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.
|
|
68
|
+
|
|
69
|
+
**`no-release` does not otherwise excuse a PR from this section.** A CI, tooling, or spec-only pull request ships nothing, but it is exactly the kind of change that can break the build or the pipeline for everyone else — a broken workflow or a deleted spec does its damage without ever being released. Hold it to every gate below.
|
|
70
|
+
|
|
71
|
+
Before marking code/automation work ready, select the affected-project gates that apply from the following list; run wider checks for cross-cutting changes and repository-required merge/release gates:
|
|
72
|
+
|
|
73
|
+
- `dotnet build` — zero errors, zero warnings
|
|
74
|
+
- `dotnet test` — all specs pass
|
|
75
|
+
- `yarn lint` — zero errors
|
|
76
|
+
- `npx tsc -b` — zero TypeScript errors
|
|
77
|
+
- Code follows all project coding standards and conventions
|
|
78
|
+
- **Required CI checks pass.** After an authorized push, inspect checks and failure logs. Diagnose within a bounded attempt, fix in-scope causes, and re-run relevant gates after each fix. Report unrelated/environmental failures and missing authority as blockers rather than retrying indefinitely or silently waiving required checks.
|