@eventmodelers/cli 1.0.73 → 1.0.74

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 (52) hide show
  1. package/README.md +10 -3
  2. package/cli.js +0 -7
  3. package/package.json +2 -2
  4. package/stacks/blank/templates/.claude/skills/build-automation/SKILL.md +1 -1
  5. package/stacks/blank/templates/.claude/skills/build-state-change/SKILL.md +1 -1
  6. package/stacks/blank/templates/.claude/skills/build-state-view/SKILL.md +1 -1
  7. package/stacks/blank/templates/root/README.md +1 -1
  8. package/stacks/modeling-kit/templates/kit/README.md +1 -1
  9. package/stacks/react/templates/.claude/skills/build-automation/SKILL.md +1 -1
  10. package/stacks/react/templates/.claude/skills/build-state-change/SKILL.md +1 -1
  11. package/stacks/react/templates/.claude/skills/build-state-view/SKILL.md +1 -1
  12. package/stacks/cratis-csharp/templates/.claude/skills/_shared/cratis-conventions.md +0 -251
  13. package/stacks/cratis-csharp/templates/.claude/skills/build-automation/SKILL.md +0 -122
  14. package/stacks/cratis-csharp/templates/.claude/skills/build-automation/references/patterns.md +0 -115
  15. package/stacks/cratis-csharp/templates/.claude/skills/build-state-change/SKILL.md +0 -191
  16. package/stacks/cratis-csharp/templates/.claude/skills/build-state-change/references/patterns.md +0 -234
  17. package/stacks/cratis-csharp/templates/.claude/skills/build-state-view/SKILL.md +0 -149
  18. package/stacks/cratis-csharp/templates/.claude/skills/build-state-view/references/patterns.md +0 -166
  19. package/stacks/cratis-csharp/templates/build-kit/CLAUDE.md +0 -78
  20. package/stacks/cratis-csharp/templates/build-kit/lib/AGENT.md +0 -59
  21. package/stacks/cratis-csharp/templates/build-kit/lib/backend-prompt.md +0 -140
  22. package/stacks/cratis-csharp/templates/build-kit/lib/prompt.md +0 -126
  23. package/stacks/cratis-csharp/templates/root/.frontend/index.css +0 -29
  24. package/stacks/cratis-csharp/templates/root/.frontend/index.html +0 -17
  25. package/stacks/cratis-csharp/templates/root/.frontend/main.tsx +0 -18
  26. package/stacks/cratis-csharp/templates/root/.frontend/tsconfig.json +0 -42
  27. package/stacks/cratis-csharp/templates/root/.frontend/tsconfig.node.json +0 -11
  28. package/stacks/cratis-csharp/templates/root/.frontend/vite.config.ts +0 -56
  29. package/stacks/cratis-csharp/templates/root/App.tsx +0 -23
  30. package/stacks/cratis-csharp/templates/root/CratisApp.csproj +0 -25
  31. package/stacks/cratis-csharp/templates/root/CratisApp.sln +0 -18
  32. package/stacks/cratis-csharp/templates/root/GlobalUsings.cs +0 -3
  33. package/stacks/cratis-csharp/templates/root/Home.tsx +0 -102
  34. package/stacks/cratis-csharp/templates/root/Program.cs +0 -26
  35. package/stacks/cratis-csharp/templates/root/README.md +0 -192
  36. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/AllListings.ts +0 -47
  37. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/Listing.cs +0 -11
  38. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/Listing.ts +0 -12
  39. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/ListingDataTable.tsx +0 -17
  40. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Listing/index.ts +0 -1
  41. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Registration/Register.ts +0 -51
  42. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Registration/RegisterDialog.tsx +0 -18
  43. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Registration/Registration.cs +0 -27
  44. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/Registration/index.ts +0 -1
  45. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/SomeFeature.tsx +0 -22
  46. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/SomeName.cs +0 -3
  47. package/stacks/cratis-csharp/templates/root/SomeModule/SomeFeature/index.ts +0 -1
  48. package/stacks/cratis-csharp/templates/root/appsettings.Development.json +0 -9
  49. package/stacks/cratis-csharp/templates/root/appsettings.json +0 -26
  50. package/stacks/cratis-csharp/templates/root/docker-compose.yml +0 -23
  51. package/stacks/cratis-csharp/templates/root/package.json +0 -33
  52. package/stacks/cratis-csharp/templates/root/tsconfig.json +0 -3
@@ -1,166 +0,0 @@
1
- # Read Slice Patterns — Cratis Arc + Chronicle
2
-
3
- Complete code for state-view (read) slices. All artifacts go in a single
4
- `<Module>/<Feature>/<Slice>/<Slice>.cs` (the shipped starter uses `SomeModule/SomeFeature/...` — match
5
- whatever the existing slices use). The example slices use no file header (match the project); namespace
6
- mirrors the folders and drops any `.Features.`. Examples below use short illustrative names
7
- (`MyApp.Authors.Listing`); mirror your project's actual module/feature layout instead.
8
-
9
- ---
10
-
11
- ## 1. Read model + queries (snapshot + observable)
12
-
13
- ```csharp
14
- // Features/Authors/Listing/Listing.cs
15
- namespace MyApp.Authors.Listing;
16
-
17
- using System.Reactive.Subjects;
18
- using Cratis.Arc.Queries.ModelBound;
19
- using MongoDB.Driver;
20
-
21
- [ReadModel]
22
- public record AuthorListItem(AuthorId Id, AuthorName Name, int BookCount)
23
- {
24
- public static async Task<IEnumerable<AuthorListItem>> AllAuthors(
25
- IMongoCollection<AuthorListItem> collection)
26
- => await collection.Find(Builders<AuthorListItem>.Filter.Empty).ToListAsync();
27
-
28
- public static async Task<AuthorListItem?> GetAuthor(
29
- AuthorId id, IMongoCollection<AuthorListItem> collection)
30
- => await collection.Find(a => a.Id == id).FirstOrDefaultAsync();
31
-
32
- public static ISubject<IEnumerable<AuthorListItem>> ObserveAllAuthors(
33
- IMongoCollection<AuthorListItem> collection)
34
- => collection.Observe();
35
-
36
- public static ISubject<AuthorListItem> ObserveAuthor(
37
- AuthorId id, IMongoCollection<AuthorListItem> collection)
38
- => collection.Observe(a => a.Id == id);
39
- }
40
- ```
41
-
42
- Rules: `[ReadModel]` required; methods `public static`; observable methods return `ISubject<T>`
43
- directly (never `Task<ISubject<T>>`); `ConceptAs<T>` for identity fields; one read model per use case.
44
-
45
- ---
46
-
47
- ## 2A. Projection (declarative mapping)
48
-
49
- ```csharp
50
- public class AuthorListItemProjection : IProjectionFor<AuthorListItem>
51
- {
52
- public void Define(IProjectionBuilderFor<AuthorListItem> builder) => builder
53
- .From<AuthorRegistered>(from => from
54
- .Set(m => m.Name).To(e => e.Name)
55
- .Set(m => m.BookCount).WithValue(0))
56
- .From<BookAdded>(from => from
57
- .Add(m => m.BookCount).With(_ => 1))
58
- .From<BookRemoved>(from => from
59
- .Subtract(m => m.BookCount).With(_ => 1));
60
- }
61
- ```
62
-
63
- - Keyed by **event source id** by default (the id passed to `IEventLog.Append`).
64
- - AutoMap is on — `.From<E>()` directly; matching property names map automatically.
65
- - Builder verbs: `Set(...).To(...)` / `.WithValue(...)`, `Add(...).With(...)`, `Subtract(...).With(...)`,
66
- `.Join<T>()`, `.Children(...)`. Projections **join events, never read models**.
67
-
68
- ### Model-bound shorthand (simple cases)
69
- ```csharp
70
- [ReadModel]
71
- public record AuthorInfo(
72
- [Key] Guid Id,
73
- [FromEvent<AuthorRegistered>] string Name,
74
- [SetFrom<AuthorRegistered>(nameof(AuthorRegistered.Country))] string Country);
75
- ```
76
-
77
- ---
78
-
79
- ## 2B. Reducer (running aggregate)
80
-
81
- ```csharp
82
- public class AccountBalanceReducer : IReducerFor<AccountBalance>
83
- {
84
- public AccountBalance Opened(DebitAccountOpened @event, AccountBalance? current, EventContext context)
85
- => new(0m, context.Occurred);
86
-
87
- public AccountBalance Deposited(FundsDeposited @event, AccountBalance? current, EventContext context)
88
- => (current ?? new(0m, context.Occurred)) with { Balance = (current?.Balance ?? 0m) + @event.Amount };
89
-
90
- public AccountBalance Withdrawn(FundsWithdrawn @event, AccountBalance? current, EventContext context)
91
- => (current ?? new(0m, context.Occurred)) with { Balance = (current?.Balance ?? 0m) - @event.Amount };
92
- }
93
-
94
- public record AccountBalance(decimal Balance, DateTimeOffset LastUpdated);
95
- ```
96
-
97
- Return the complete new state; never mutate `current` (`null` on the first event). Add
98
- `[FilterEventsByTag]` / `[EventSourceType]` / `[EventStreamType]` when filtering by metadata.
99
-
100
- ---
101
-
102
- ## 3. Spec — projection result from a sequence of events
103
-
104
- ```csharp
105
- namespace MyApp.Authors.Listing.for_AuthorListItem.when_an_author_registered_and_added_two_books;
106
-
107
- // Use the project's projection-spec harness (e.g. a ProjectionSpecificationContext / Given<context>).
108
- // The shape: append events, observe the resulting read model, assert fields.
109
-
110
- public class and_projecting : Specification
111
- {
112
- AuthorListItem _result;
113
-
114
- void Establish() { /* append AuthorRegistered, BookAdded, BookAdded to the test event store */ }
115
- void Because() { /* run the projection / read the resulting model */ }
116
-
117
- [Fact] void should_have_the_name() => _result.Name.Value.ShouldEqual("John");
118
- [Fact] void should_count_two_books() => _result.BookCount.ShouldEqual(2);
119
- }
120
- ```
121
-
122
- Match the project's existing projection-spec harness — discover it from an existing read slice's specs.
123
-
124
- ---
125
-
126
- ## 4. React — render the query proxy
127
-
128
- The query proxy (`AllAuthors.ts`) is generated **next to** `Listing.cs` — import it from the same
129
- folder. The simplest list UI uses the Cratis `DataTableForObservableQuery` component (see the shipped
130
- example slice's `ListingDataTable.tsx`):
131
-
132
- ```tsx
133
- // Authors/Listing/ListingDataTable.tsx
134
- import { DataTableForObservableQuery } from '@cratis/components/DataTables';
135
- import { Column } from 'primereact/column';
136
- import { AllAuthors } from './AllAuthors'; // co-located generated proxy
137
-
138
- export const ListingDataTable = () => (
139
- <DataTableForObservableQuery query={AllAuthors} dataKey='id' emptyMessage='No authors yet.'>
140
- <Column field='name' header='Name' />
141
- <Column field='bookCount' header='Books' />
142
- </DataTableForObservableQuery>
143
- );
144
- ```
145
-
146
- Hook form (manual rendering):
147
-
148
- ```tsx
149
- const [authors] = AllAuthors.use(); // snapshot or observable, depending on the proxy
150
- const [result, , setPage] = AllAuthors.useWithPaging(10); // paging
151
- // result.data, result.paging.totalItems, result.paging.page
152
- ```
153
-
154
- Observable queries generate an `ObservableQueryFor` proxy (from `collection.Observe()`); snapshot
155
- queries generate `QueryFor`. PrimeReact CSS variables / Tailwind for styling; no `any`; full
156
- descriptive names. Add a barrel `index.ts` for the slice.
157
-
158
- ---
159
-
160
- ## Checklist
161
-
162
- - One `.cs` file, namespace without `.Features.` (no file header unless the project uses one).
163
- - `[ReadModel]` record; `public static` query methods; observable returns `ISubject<T>` directly.
164
- - Projection (mapping) or reducer (aggregate) — discovered automatically, no registration.
165
- - Projections map from events only; one read model per use case.
166
- - `ConceptAs<T>` for identity fields; one spec per scenario; `dotnet build` clean; specs pass.
@@ -1,78 +0,0 @@
1
- # CratisApp — agent conventions
2
-
3
- This is a **Cratis** application: Cratis Arc (CQRS) + Cratis Chronicle (event sourcing) + MongoDB read
4
- models on the backend, React + TypeScript (Vite + PrimeReact) on the frontend, with **full-stack type
5
- safety** via TypeScript proxy generation on `dotnet build`.
6
-
7
- Build slices with the kit's skills — `/build-state-change`, `/build-state-view`, `/build-automation` —
8
- and follow the conventions distilled in
9
- `.build-kit/.claude/skills/_shared/cratis-conventions.md`. **The shipped example slice
10
- under `SomeModule/SomeFeature/` is the concrete pattern to copy** — match its structure exactly.
11
-
12
- **If a slice's requirements are genuinely ambiguous, contradictory, or missing a decision you need in
13
- order to proceed — do not guess, and do not build anyway.** Invoke the `request-feedback` skill with
14
- the specific question; it posts the question as a comment on the slice and marks it `Blocked`, and you
15
- then stop work on this slice for this run. This is an escalation path, not a routine step — read
16
- `slice.json` and the matching build skill's own instructions fully first; most slices are fully
17
- specified and need none of this.
18
-
19
- ## No such thing as harmless drift
20
-
21
- `slice.json` is always the desired state — the code follows what it defines, never the other way
22
- around. If code for a slice already exists — most often because it was previously `Done` and got moved
23
- back to `Planned` — never conclude "already implemented" and move on. A slice does not return to
24
- `Planned` without a reason: diff the current `slice.json` against the existing implementation field by
25
- field (events, commands, params, specifications, routes) and update the code to match every difference
26
- you find. Only mark it `Done` once there is no gap left.
27
-
28
- ## Structure (learn from `SomeModule/SomeFeature/`)
29
-
30
- ```
31
- <Module>/<Feature>/
32
- ├── <Feature>.tsx ← composition page (buttons, dialogs, tables)
33
- ├── index.ts ← barrel: export * from './<Feature>'
34
- ├── <Concept>.cs ← shared concepts (ConceptAs<T>)
35
- └── <Slice>/ ← one slice = one behavior
36
- ├── <Slice>.cs ← ALL backend artifacts for the slice in ONE file
37
- ├── <Proxy>.ts ← GENERATED by dotnet build — never hand-edit
38
- ├── <Component>.tsx ← React component using the generated proxy
39
- └── index.ts ← barrel export
40
- ```
41
-
42
- - Top folder is a **module**, then a **feature**, then **slices**. Namespace is
43
- `CratisApp.<Module>.<Feature>.<Slice>` (the `RootNamespace` is `CratisApp` — see `CratisApp.csproj`).
44
- - **Proxies are generated next to the source** (`CratisProxiesUseSourceFileAsOutputFile=true` in the
45
- `.csproj`): `Register.ts` sits beside `Registration.cs`. Frontend imports the proxy from the **same
46
- folder** (`import { Register } from './Register'`). Files marked `// @generated` are never edited.
47
-
48
- ## Non-negotiables (full detail in the shared conventions doc)
49
-
50
- - ALL backend artifacts for a slice live in ONE `.cs` file.
51
- - `[Command]` records define `Handle()` directly — never separate handler classes.
52
- - `[EventType]` takes NO arguments; events are past-tense and never nullable.
53
- - `ConceptAs<T>` for identity/value types — no raw `Guid` / `string` in the domain.
54
- - `[ReadModel]` records expose queries as `public static` methods; observable queries return
55
- `ISubject<T>` directly (`collection.Observe()`).
56
- - Reactors implement the marker `IReactor`; dispatch is by the first parameter type. Write new events
57
- only via `ICommandPipeline.Execute(...)`, never `IEventLog`. Keep reactors idempotent + stateless.
58
- - Frontend: `CommandDialog` / `InputTextField` from `@cratis/components/*`; never import `Dialog` from
59
- `primereact/dialog`. PrimeReact CSS variables / Tailwind classes for styling; no `any`.
60
-
61
- ## Build, run, test
62
-
63
- ```bash
64
- docker-compose up -d # Chronicle (+ MongoDB) + Aspire dashboard
65
- dotnet build # compiles backend AND regenerates TypeScript proxies
66
- dotnet test # run specs (filter while iterating: --filter "FullyQualifiedName~<Slice>")
67
- npm install && npm run dev # frontend dev server (Vite)
68
- dotnet run # backend (http://localhost:5000, Swagger at /swagger)
69
- ```
70
-
71
- **Sequencing is strict:** a slice's frontend cannot reference its proxy until the backend compiles, so
72
- always go Backend → `dotnet build` → Specs → Frontend → Composition page → Routes (`App.tsx`). Backend
73
- and frontend of the same slice never run in parallel. Build must be zero-warning, zero-error.
74
-
75
- ## Learn more
76
-
77
- - Cratis docs: https://www.cratis.io/docs/
78
- - Conventions: `.build-kit/.claude/skills/_shared/cratis-conventions.md`
@@ -1,59 +0,0 @@
1
- # Agent Learnings
2
-
3
- Patterns and gotchas discovered during task processing. Update this file whenever you encounter something reusable.
4
-
5
- ## Cratis non-negotiables (seed — full detail in `.claude/skills/_shared/cratis-conventions.md`)
6
-
7
- - ALL backend artifacts for a slice go in ONE `.cs` file under the project's slice folder (the shipped starter uses `<Module>/<Feature>/<Slice>/<Slice>.cs` — discover the real top-level folder from an existing slice). Never split into `Commands/`, `Handlers/`, `Events/`.
8
- - `[Command]` records define `Handle()` directly on the record — never a separate handler class.
9
- - `[EventType]` takes NO attribute arguments (the type name is the id); events are past-tense and never nullable.
10
- - Use `ConceptAs<T>` for every identity/value — no raw `Guid`/`string` in the domain.
11
- - Read models: `[ReadModel]` record with `public static` query methods on it; observable queries return `ISubject<T>` directly (never `Task<ISubject<T>>`). Projections join events, never read models.
12
- - Reactors implement the marker `IReactor`; dispatch is by the first parameter type. Write new events only via `ICommandPipeline.Execute(...)`, never `IEventLog`. Reactors must be idempotent and stateless.
13
- - Namespace mirrors the folders and drops any `.Features.` segment: `<Root>.<Module>.<Feature>.<Slice>` (the starter's `<Root>` is `CratisApp`). Find `<Root>` from the `.csproj` `<RootNamespace>` / existing slices; never hard-code.
14
- - `dotnet build` generates the TypeScript proxies — backend must compile before a slice's frontend can reference them. Order: Backend → build → Specs → Frontend → Composition.
15
- - Quality gate: `dotnet build` with zero warnings/errors (warnings = errors); `dotnet test --filter "FullyQualifiedName~<SliceName>"`. File header only if the project's existing `.cs` files already carry one (the shipped example uses none).
16
-
17
- ## tasks.json
18
-
19
- - Tasks are objects with `id`, `createdAt`, and `payload` (a `SliceChangedPayload`).
20
- - After completing a task, remove it from the array entirely — do not add a status field.
21
- - Write `[]` to `tasks.json` if the last task is completed.
22
-
23
- ## SliceChangedPayload fields
24
-
25
- ```
26
- event always "slice:changed"
27
- organizationId org UUID or null
28
- boardId board UUID
29
- sliceId SLICE_BORDER node UUID — use this with /load-slice
30
- sliceTitle human-readable slice name (may be null)
31
- sliceStatus e.g. "Created", "InProgress", "Done", "Blocked" (may be null)
32
- timestamp unix ms when the change was emitted
33
- ```
34
-
35
- ## Slice files
36
-
37
- The realtime agent writes one file per slice on startup and after each `slice:changed` event:
38
-
39
- ```
40
- .slices/<context>/<sliceName>/slice.json
41
- ```
42
-
43
- - `<context>` is the slice's context value, or `default` if none.
44
- - `<sliceName>` is the slice title lowercased with spaces removed (e.g. `"Enable User"` → `enableuser`).
45
-
46
- These files are always up to date — read them directly before invoking any skill.
47
-
48
- ## Skill Usage
49
-
50
- - Always run `/connect` first to load credentials from `.eventmodelers/config.json` before calling any other skill.
51
- - `/load-slice sliceId=<uuid>` re-fetches all slices from the API, refreshes the slice files, and returns the requested slice. Use it when you need a guaranteed-fresh view of a specific slice.
52
- - Read `.slices/<context>/<sliceName>/slice.json` directly when you already know the context and name and the file is recent enough.
53
-
54
- ## Board API
55
-
56
- - The `boardId` and `organizationId` from each payload provide full context — pass them to skills.
57
- - Node events use `node:created`, `node:changed`, `node:deleted` — always POST to `/api/org/:orgId/boards/:boardId/nodes/events`.
58
- - Slice metadata (title, status) lives on the SLICE_BORDER node under `meta.sliceStatus` and `meta.title`.
59
- - `/update-slice-status` rejects moving a slice into a status it's already in — this is a concurrency guard, not a bug. It means another agent already claimed the slice. Treat it as `ALREADY_IN_STATUS`, skip that slice, and move on to the next `Planned` one instead of erroring out.
@@ -1,140 +0,0 @@
1
- # Ralph Agent Instructions — Cratis (Arc + Chronicle)
2
-
3
- You are an autonomous coding agent building software slices in a **Cratis** .NET / C# project. You
4
- apply your skills to implement one slice at a time, the Cratis way.
5
-
6
- The conventions in `.claude/skills/_shared/cratis-conventions.md` are authoritative — read them before
7
- implementing.
8
-
9
- ## Your Task
10
-
11
- 0. Do not read the entire codebase. Focus on the task in this description.
12
- 1. Read `.build-kit/.slices/current_context.json` to find the active context name, then
13
- read `.build-kit/.slices/<contextName>/index.json`. Every item with status "Planned"
14
- is a task.
15
- 2. Read the progress log at `progress.txt` (check the **Codebase Patterns** section first) and the
16
- accumulated learnings in `AGENT.md`.
17
- 3. Make sure you are on the right branch `feature/<slicename>`; if unsure, start from `main`.
18
- 4. Pick the **highest priority** slice where status is **exactly** "Planned" (case insensitive). This
19
- becomes your PRD. Set its status to "InProgress" in `index.json` **and** on the board via the
20
- `update-slice-status` skill (or MCP if available).
21
- **Only work on slices with status "Planned". Never pick up "InProgress", "Done", "Blocked",
22
- "Created", or any other status — even if it looks incomplete. If no slice is "Planned", reply with**
23
- `<promise>NO_TASKS</promise>` **and stop immediately.**
24
- 5. Read the slice definition from
25
- `.build-kit/.slices/<contextName>/<folder>/slice.json` — it is the source of truth.
26
- Never work on more than one slice per iteration.
27
- 6. A slice may define additional `codegen` / `backendPrompt` hints — take them into account and note in
28
- `progress.txt` when used.
29
- 7. Determine the slice type and load the matching skill:
30
- - **State Change** (has `commands` / `events`, no `processors`) → `/build-state-change`
31
- - **State View** (has `readModel` / `projections` / `queries`) → `/build-state-view`
32
- - **Automation** (`processors` array non-empty) → `/build-automation`
33
- - **Translation** (`sliceType === "TRANSLATION"`) → read `description` / `notes` for hints; default
34
- to `/build-automation` (a reactor that triggers a command in its own slice)
35
- 8. Write a short one-line progress note to `progress.txt` after each step.
36
- 9. Implement that single slice using the matching skill as guidance. Make a TODO list of what's needed.
37
- The JSON is the desired state — carefully compare events, fields, commands, and specifications
38
- against the code. A "Planned" task may be **added specifications** on an existing slice: always look
39
- at the slice AND its specifications, and add any missing specs in code.
40
- 10. The JSON is always true — the code follows what the JSON defines.
41
- 11. A slice is only "Done" when the business logic is implemented as defined, the read/write/automation
42
- artifacts exist, every specification in the JSON has an executable equivalent in code, and it
43
- fulfills `slice.json`. There must be no specification in the JSON without a code equivalent.
44
- 12. **Follow the Cratis non-negotiables** (full detail in `cratis-conventions.md`):
45
- - ALL backend artifacts for the slice in ONE `.cs` file under the project's slice folder
46
- (the shipped starter uses `<Module>/<Feature>/<Slice>/<Slice>.cs` — discover the real
47
- top-level folder from an existing slice and match it).
48
- - `[Command]` records with `Handle()` on the record — never separate handler classes.
49
- - `[EventType]` with NO attribute arguments; past-tense names; no nullable properties.
50
- - `ConceptAs<T>` for every identity / value — no raw `Guid` / `string` in the domain.
51
- - Namespace mirrors the folders and drops any `.Features.` segment
52
- (`<Root>.<Module>.<Feature>.<Slice>`; the starter's `<Root>` is `CratisApp`). Read the
53
- `<RootNamespace>` in the `.csproj` and existing slices to find the root; never hard-code it.
54
- - File header: only if the project's existing `.cs` files already carry one — the shipped
55
- example slices use none, so default to no header.
56
- 13. Run quality checks — it is enough to run the tests for the slice only, not all tests. Run from the
57
- **project root** (where the `.csproj`/solution lives), not the kit folder:
58
- - Build: `dotnet build` (zero warnings, zero errors — warnings are treated as errors; this also
59
- regenerates the TypeScript proxies)
60
- - Test (slice only): `dotnet test --filter "FullyQualifiedName~<SliceName>"`
61
- If the slice is UI-triggered, also implement the React component(s) AFTER the build generated the
62
- proxies, then register them in the feature's composition page.
63
- 14. If checks pass, commit ALL changes with message `feat: <Slice Name>` and merge back to `main` as a
64
- fast-forward merge (update first).
65
- 15. Set `status: Done` for the slice in `index.json` **and** on the board via `update-slice-status`.
66
- 16. Append progress to `progress.txt` after each step.
67
- 17. Append new reusable learnings to `AGENT.md` in compressed form (only if not already there).
68
- 18. Finish the iteration.
69
-
70
- ## Sequencing (Cratis-specific)
71
-
72
- `dotnet build` generates the TypeScript proxies — **the frontend of a slice cannot reference its proxy
73
- until the backend compiles**. Always: Backend → `dotnet build` → Specs → Frontend → Composition.
74
- Never implement a slice's frontend before its backend builds.
75
-
76
- ## Escalating Ambiguity
77
-
78
- **If the slice's requirements are genuinely ambiguous, contradictory, or missing a decision you need
79
- in order to proceed — do not guess, and do not build anyway.** Invoke `/request-feedback` with the
80
- specific question; it posts the question as a comment on the slice and marks it `Blocked` on the
81
- board (overriding the `InProgress` set earlier), then stop this iteration without finishing the
82
- build — reply `<promise>DONE</promise>` as if the iteration's work was to raise the question, not to
83
- implement the slice. This is an escalation path, not a routine step — read the slice.json and the
84
- matching build skill's own instructions fully first; most slices are fully specified and need none of
85
- this.
86
-
87
- ## Progress Report Format
88
-
89
- APPEND to `progress.txt` (never replace):
90
-
91
- ```
92
- ## [Date/Time] - [Slice]
93
-
94
- - What was implemented
95
- - Files changed
96
- - **Learnings for future iterations:**
97
- - Patterns discovered (e.g., "this project's namespace root is `Library`")
98
- - Gotchas (e.g., "observable queries must return ISubject<T>, never Task<ISubject<T>>")
99
- - Useful context
100
- ---
101
- ```
102
-
103
- ## Consolidate Patterns
104
-
105
- If you discover a **reusable** pattern, add it to a `## Codebase Patterns` section at the TOP of
106
- `progress.txt` (create it if missing). Only general, reusable patterns — not slice-specific details.
107
-
108
- ```
109
- ## Codebase Patterns
110
- - Namespace root is `<Root>`; slices live under <Module>/<Feature>/<Slice>/
111
- - Read models expose queries as public static methods on the [ReadModel] record
112
- - DCB rules: inject the read model as a Handle() parameter
113
- ```
114
-
115
- ## Quality Requirements
116
-
117
- - ALL commits must pass `dotnet build` (zero warnings/errors) and the slice's `dotnet test`.
118
- - Do NOT commit broken code. Keep changes focused and minimal. Follow existing patterns.
119
-
120
- ## Specifications
121
-
122
- For every specification on the slice, implement one executable spec in code (Cratis.Specifications BDD:
123
- `Establish` / `Because` / `[Fact] should_*`). A slice is not complete if specifications are missing or
124
- cannot execute.
125
-
126
- ## Stop Condition
127
-
128
- **After completing ONE slice, always stop** — the ralph loop will invoke you again for the next slice.
129
- Never chain multiple slices in one iteration.
130
-
131
- - Slice completed and committed → reply `<promise>DONE</promise>`
132
- - No slice has status "Planned" → reply `<promise>NO_TASKS</promise>`
133
- - ALL slices across the index are Done → reply `<promise>COMPLETE</promise>`
134
-
135
- ## Important
136
-
137
- - If `.build-kit/.eventmodelers/config.json` is absent, skip all platform communication
138
- (MCP calls, `update-slice-status`, board sync) and continue working locally.
139
- - Work on ONE slice per iteration. Commit frequently. Update `progress.txt` frequently.
140
- - Read the Codebase Patterns section in `progress.txt` and `AGENT.md` before starting.
@@ -1,126 +0,0 @@
1
- # Agent Task Instructions
2
-
3
- You are an autonomous agent reacting to slice status change events on an Eventmodelers board.
4
-
5
- ## Your Loop
6
-
7
- 1. Read `AGENT.md` to load accumulated learnings before doing anything else.
8
- 2. Read `.build-kit/tasks.json`.
9
- 3. If `tasks.json` is empty or missing, reply with:
10
- <promise>IDLE</promise>
11
- and stop.
12
- 4. Pick the **oldest task** (earliest `createdAt`).
13
- 5. Execute the task — see the Execution section below.
14
- 6. After execution, remove that task from the array and write `.build-kit/tasks.json` back.
15
- 7. Append a progress entry to `progress.txt` (create if missing).
16
- 8. Update `AGENT.md` with any new reusable learnings discovered this iteration.
17
- 9. Reply normally so the next iteration can pick up the next task.
18
-
19
- ## Execution
20
-
21
- Each task has a single `payload` of type `SliceChangedPayload`:
22
-
23
- ```
24
- {
25
- event: "slice:changed"
26
- organizationId: string | null
27
- boardId: string
28
- sliceId: string ← SLICE_BORDER node UUID
29
- sliceTitle: string | null
30
- sliceStatus: string | null ← e.g. "InProgress", "Done", "Blocked"
31
- timestamp: number
32
- }
33
- ```
34
-
35
- ### Step 1 — Load credentials
36
-
37
- Run `/connect` to resolve `TOKEN`, `BOARD_ID`, `ORG_ID`, and `BASE_URL` from `.eventmodelers/config.json`.
38
-
39
- ### Step 2 — Load the slice
40
-
41
- Run `/load-slice sliceId=<payload.sliceId>` to fetch full slice details (title, status, raw node record).
42
-
43
- ### Step 3 — Act on the change
44
-
45
- Inspect the `sliceStatus` in the payload:
46
-
47
- #### `Planned` — build the slice
48
-
49
- This is the build trigger. Setting `InProgress` and building are one atomic step:
50
-
51
- **If the slice's requirements are genuinely ambiguous, contradictory, or missing a decision you need in order to proceed — do not guess, and do not build anyway.** Invoke `/request-feedback` with the specific question; it posts the question as a comment on the slice and marks it `Blocked` (superseding the `InProgress` set in step 1), then drop this task without finishing the build. This is an escalation path, not a routine step — most slices are fully specified.
52
-
53
- 1. Immediately call `/update-slice-status` to set the slice to `InProgress` on the board.
54
-
55
- 2. Read the slice definition from `.build-kit/.slices/<contextSlug>/<sliceFolder>/slice.json` (written by `/load-slice`).
56
-
57
- 3. Determine the **slice type** from the slice.json:
58
- - **Translation** — `sliceType === "TRANSLATION"` → read `description` and `notes` from slice.json for hints; default to `/build-automation` if nothing else is specified
59
- - **Automation** — `processors` array is non-empty → invoke `/build-automation`
60
- - **State-view** — `projections` or `queries` array is non-empty → invoke `/build-state-view`
61
- - **State-change** — default (has `commands` / `events`) → invoke `/build-state-change`
62
-
63
- 4. Invoke the matching skill and follow its instructions **completely**. Do NOT implement the slice manually.
64
-
65
- 5. **Verify against slice.json**: Cross-check the implementation — every command field, event field, and specification in slice.json must appear in the code. No invented fields — if it is not in slice.json, it must not be in the code.
66
-
67
- 6. Run quality checks (from the project root — `dotnet build` also regenerates the TypeScript proxies the frontend depends on):
68
- - Build: `dotnet build` (zero warnings, zero errors)
69
- - Test (slice only): `dotnet test --filter "FullyQualifiedName~<SliceName>"`
70
-
71
- 7. If checks pass, commit all changes with message: `feat: [Slice Name]`.
72
-
73
- 8. Call `/update-slice-status` to set the slice to `Done` on the board.
74
-
75
- #### `InProgress`
76
- Another agent is already building this slice. Log it and skip — do not build.
77
-
78
- #### `Done`
79
- Summarize what was completed and update `progress.txt`.
80
-
81
- #### `Blocked`
82
- Log the blocker in `progress.txt`.
83
-
84
- #### `Review`
85
- Fetch slice details and prepare a review summary in `progress.txt`.
86
-
87
- #### Any other status (`Created`, etc.)
88
- Load the slice and log the state transition in `progress.txt`. No build action.
89
-
90
- Use the skills available in `.claude/skills/` to interact with the board.
91
-
92
- ## Updating tasks.json
93
-
94
- After completing a task, remove it from the array and write the updated array back to `.build-kit/tasks.json`. If the array is now empty, write `[]`.
95
-
96
- ## Progress Report Format
97
-
98
- APPEND to `progress.txt` (never replace):
99
- ```
100
- ## [ISO timestamp] — Task [task.id]
101
-
102
- Slice: [sliceTitle] ([sliceId])
103
- Status change: [sliceStatus]
104
-
105
- Action taken:
106
- - [what was done in response to the slice change]
107
-
108
- Learnings:
109
- - [any patterns, gotchas, or reusable knowledge discovered]
110
- ---
111
- ```
112
-
113
- ## Stop Condition
114
-
115
- If `.build-kit/tasks.json` is empty (`[]`) or does not exist, reply with:
116
- <promise>IDLE</promise>
117
-
118
- ## Updating AGENT.md
119
-
120
- After completing a task, add any **reusable** learnings to `AGENT.md` — patterns, gotchas, API quirks, or skill behaviour that future iterations should know. Only add things that are general and applicable beyond this single task. Do not duplicate what is already there.
121
-
122
- ## Important
123
-
124
- - Process **one task per iteration**.
125
- - Read `AGENT.md` first — it contains patterns from previous iterations.
126
- - Always start with `/connect` if credentials are not yet loaded.
@@ -1,29 +0,0 @@
1
- @import "tailwindcss";
2
- @import 'primereact/resources/themes/lara-dark-blue/theme.css';
3
- @source '../';
4
-
5
- :root {
6
- font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
7
- font-size: 14px;
8
- line-height: 1.5;
9
- font-weight: 400;
10
-
11
- color-scheme: dark;
12
-
13
- font-synthesis: none;
14
- text-rendering: optimizeLegibility;
15
- -webkit-font-smoothing: antialiased;
16
- -moz-osx-font-smoothing: grayscale;
17
- }
18
-
19
- body {
20
- margin: 0;
21
- min-width: 320px;
22
- min-height: 100vh;
23
- background-color: var(--surface-ground);
24
- color: var(--text-color);
25
- }
26
-
27
- #root {
28
- height: 100vh;
29
- }
@@ -1,17 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
-
4
- <head>
5
- <meta charset="UTF-8" />
6
- <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
7
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
- <meta name="base-path" content="" />
9
- <title>CratisApp</title>
10
- </head>
11
-
12
- <body>
13
- <div id="root"></div>
14
- <script type="module" src="/main.tsx"></script>
15
- </body>
16
-
17
- </html>
@@ -1,18 +0,0 @@
1
- import 'reflect-metadata';
2
- import { PrimeReactProvider } from 'primereact/api';
3
- import ReactDOM from 'react-dom/client';
4
- import 'primeicons/primeicons.css';
5
- import './index.css';
6
- import React from 'react';
7
- import { Arc } from '@cratis/arc.react';
8
- import App from '../App.tsx';
9
-
10
- ReactDOM.createRoot(document.getElementById('root')!).render(
11
- <React.StrictMode>
12
- <PrimeReactProvider value={{ ripple: true }}>
13
- <Arc>
14
- <App />
15
- </Arc>
16
- </PrimeReactProvider>
17
- </React.StrictMode>
18
- );