@eventmodelers/cli 1.0.163 → 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/README.md +48 -36
- package/RELEASE_NOTES.md +20 -2
- package/cli.js +774 -247
- package/lib/adapters/spec-kitty-adapter.js +3 -7
- package/lib/build-kits.js +23 -0
- package/lib/global-agent-id.js +45 -0
- package/lib/modeling-local-ai.js +4 -2
- package/lib/scaffold-model.js +71 -0
- package/lib/scaffold.js +224 -0
- package/lib/supervise.js +60 -0
- package/lib/ui-baseline.js +123 -0
- package/package.json +1 -1
- package/shared/build-kit/README.md +4 -19
- package/shared/build-kit/lib/agent-lock.js +75 -0
- package/shared/build-kit/lib/agent-name.js +27 -0
- package/shared/build-kit/lib/event-prune.js +58 -0
- package/shared/build-kit/lib/events-view.js +134 -0
- package/shared/build-kit/lib/local-ai-agent.js +14 -26
- package/shared/build-kit/lib/mcp-register.js +17 -1
- package/shared/build-kit/lib/prompt-journal.js +191 -0
- package/shared/build-kit/lib/prompt-replay.js +35 -0
- package/shared/build-kit/lib/ralph.js +218 -169
- package/shared/build-kit/lib/slice-curation.js +40 -0
- package/shared/build-kit/lib/slice-events.js +93 -0
- package/shared/build-kit/lib/slice-git.js +86 -0
- package/shared/build-kit/lib/slice-learnings.js +197 -0
- package/shared/build-kit/lib/slice-projection.js +101 -0
- package/shared/build-kit/lib/slice-run.js +181 -0
- package/shared/build-kit/lib/slice-state.js +184 -0
- package/shared/build-kit/lib/slice-tasks.js +35 -0
- package/shared/build-kit/ralph-claude.js +4 -2
- package/shared/build-kit/ralph-exec.js +4 -2
- package/shared/build-kit/ralph-local-ai.js +5 -3
- package/shared/scaffold/LICENSE-em-scaffold +21 -0
- package/shared/scaffold/supabase/generate.mjs +290 -0
- package/shared/scaffold/supabase/template/scripts/create-user.mjs.tmpl +29 -0
- package/shared/scaffold/supabase/template/scripts/dev.mjs.tmpl +145 -0
- package/shared/scaffold/supabase/template/scripts/write-env.mjs.tmpl +44 -0
- package/shared/scaffold/supabase/template/server.ts.tmpl +168 -0
- package/shared/scaffold/supabase/template/src/common/extraEndpoints.ts.tmpl +5 -0
- package/shared/scaffold/supabase/template/src/common/notImplemented.test.ts.tmpl +58 -0
- package/shared/scaffold/supabase/template/src/common/notImplemented.ts.tmpl +29 -0
- package/shared/scaffold/supabase/template/supabase/migrations/_V0__supabase_stubs.sql.tmpl +34 -0
- package/shared/scaffold/supabase/template/web/src/App.tsx.tmpl +38 -0
- package/shared/scaffold/supabase/template/web/src/app/Layout.tsx.tmpl +48 -0
- package/shared/scaffold/supabase/template/web/src/app/NotFound.tsx.tmpl +12 -0
- package/shared/scaffold/supabase/template/web/src/app/SignIn.tsx.tmpl +42 -0
- package/shared/scaffold/supabase/template/web/src/app/TimelinePage.tsx.tmpl +73 -0
- package/shared/scaffold/supabase/template/web/src/app/pages.ts.tmpl +26 -0
- package/shared/scaffold/supabase/template/web/src/app/skeleton.css.tmpl +25 -0
- package/shared/scaffold/supabase/template/web/src/lib/NotBuilt.tsx.tmpl +12 -0
- package/shared/scaffold/supabase/template/web/src/lib/api.ts.tmpl +226 -0
- package/shared/scaffold/supabase/template/web/src/main.tsx.tmpl +13 -0
- package/shared/skills/learn-eventmodelers-api/SKILL.md +17 -4
- package/shared/skills/request-feedback/SKILL.md +1 -2
- package/shared/skills/ui-contract/SKILL.md +7 -5
- package/shared/skills/update-slice-status/SKILL.md +1 -1
- package/stacks/axon/templates/build-kit/CLAUDE.md +7 -6
- package/stacks/axon/templates/build-kit/lib/AGENT.md +6 -7
- package/stacks/axon/templates/build-kit/lib/backend-prompt.md +20 -42
- package/stacks/axon/templates/build-kit/lib/prompt.md +32 -41
- package/stacks/blank/templates/build-kit/CLAUDE.md +7 -6
- package/stacks/blank/templates/build-kit/lib/AGENT.md +6 -7
- package/stacks/blank/templates/build-kit/lib/backend-prompt.md +20 -37
- package/stacks/blank/templates/build-kit/lib/prompt.md +33 -42
- package/stacks/classic/templates/.claude/skills/build-automation/SKILL.md +1 -1
- package/stacks/classic/templates/.claude/skills/build-state-change/SKILL.md +1 -1
- package/stacks/classic/templates/.claude/skills/build-state-view/SKILL.md +2 -2
- package/stacks/classic/templates/.claude/skills/record-evidence/SKILL.md +2 -2
- package/stacks/classic/templates/build-kit/CLAUDE.md +9 -8
- package/stacks/classic/templates/build-kit/lib/AGENT.md +6 -7
- package/stacks/classic/templates/build-kit/lib/backend-prompt.md +20 -38
- package/stacks/classic/templates/build-kit/lib/prompt.md +33 -42
- package/stacks/kurrent/templates/build-kit/CLAUDE.md +7 -7
- package/stacks/kurrent/templates/build-kit/lib/AGENT.md +6 -7
- package/stacks/kurrent/templates/build-kit/lib/backend-prompt.md +20 -42
- package/stacks/kurrent/templates/build-kit/lib/prompt.md +32 -41
- package/stacks/modeling-kit/templates/.claude/skills/analyze-existing-model/SKILL.md +1 -1
- package/stacks/modeling-kit/templates/.claude/skills/detect-model-drift/SKILL.md +1 -1
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-core-rules/SKILL.md +2 -0
- package/stacks/modeling-kit/templates/.claude/skills/eventmodeling-elaborating-scenarios/SKILL.md +7 -3
- package/stacks/modeling-kit/templates/.claude/skills/wdyt/SKILL.md +1 -1
- package/stacks/modeling-kit/templates/kit/CLAUDE-STANDALONE.md +3 -4
- package/stacks/modeling-kit/templates/kit/CLAUDE.md +18 -28
- package/stacks/modeling-kit/templates/kit/README.md +1 -1
- package/stacks/modeling-kit/templates/kit/lib/config.js +1 -1
- package/stacks/node/templates/build-kit/CLAUDE.md +7 -6
- package/stacks/node/templates/build-kit/lib/AGENT.md +6 -7
- package/stacks/node/templates/build-kit/lib/backend-prompt.md +20 -42
- package/stacks/node/templates/build-kit/lib/prompt.md +18 -41
- package/stacks/opencqrs/templates/build-kit/CLAUDE.md +7 -7
- package/stacks/opencqrs/templates/build-kit/lib/AGENT.md +6 -7
- package/stacks/opencqrs/templates/build-kit/lib/backend-prompt.md +20 -42
- package/stacks/opencqrs/templates/build-kit/lib/prompt.md +32 -41
- package/stacks/react/templates/.claude/skills/build-state-change/SKILL.md +1 -1
- package/stacks/react/templates/.claude/skills/build-state-view/SKILL.md +1 -1
- package/stacks/react/templates/build-kit/CLAUDE.md +7 -6
- package/stacks/react/templates/build-kit/lib/AGENT.md +6 -7
- package/stacks/react/templates/build-kit/lib/backend-prompt.md +25 -42
- package/stacks/react/templates/build-kit/lib/kit.json +1 -1
- package/stacks/react/templates/build-kit/lib/prompt.md +47 -43
- package/stacks/supabase/templates/.claude/skills/build-state-view/SKILL.md +15 -0
- package/stacks/supabase/templates/build-kit/CLAUDE.md +7 -6
- package/stacks/supabase/templates/build-kit/lib/AGENT.md +6 -7
- package/stacks/supabase/templates/build-kit/lib/backend-prompt.md +20 -42
- package/stacks/supabase/templates/build-kit/lib/prompt.md +18 -41
- package/stacks/supabase-react/templates/.claude/skills/build-state-change/SKILL.md +80 -8
- package/stacks/supabase-react/templates/.claude/skills/build-state-view/SKILL.md +66 -13
- package/stacks/supabase-react/templates/build-kit/CLAUDE.md +8 -7
- package/stacks/supabase-react/templates/build-kit/lib/AGENT.md +6 -7
- package/stacks/supabase-react/templates/build-kit/lib/backend-prompt.md +25 -42
- package/stacks/supabase-react/templates/build-kit/lib/kit.json +1 -1
- package/stacks/supabase-react/templates/build-kit/lib/prompt.md +48 -44
- package/stacks/umadb/templates/build-kit/CLAUDE.md +7 -6
- package/stacks/umadb/templates/build-kit/lib/AGENT.md +6 -7
- package/stacks/umadb/templates/build-kit/lib/backend-prompt.md +20 -42
- package/stacks/umadb/templates/build-kit/lib/prompt.md +32 -41
- package/shared/bridge/spec-kitty/bridge-spec-kitty-specify/SKILL.md +0 -125
- package/shared/bridge/spec-kitty/bridge-spec-kitty-tasks/SKILL.md +0 -95
- package/shared/build-kit/lib/agent.sh +0 -20
- package/shared/build-kit/ralph.sh +0 -111
- package/shared/build-kit/realtime-agent.js +0 -20
- package/stacks/bridge/templates/bridge/lib/AGENT.md +0 -47
- package/stacks/bridge/templates/bridge/lib/prompt.md +0 -111
- package/stacks/bridge/templates/bridge/ralph-claude.js +0 -50
- package/stacks/bridge/templates/bridge/ralph-hook.js +0 -103
- package/stacks/bridge/templates/bridge/ralph-local-ai.js +0 -43
- package/stacks/bridge/templates/bridge/ralph-static.js +0 -90
package/README.md
CHANGED
|
@@ -92,7 +92,6 @@ your-project/
|
|
|
92
92
|
│ ├── ralph-claude.js ← realtime agent + task loop
|
|
93
93
|
│ ├── ralph-local-ai.js ← same, via a local/self-hosted model
|
|
94
94
|
│ ├── ralph-exec.js ← same, via an external agent command (Codex CLI, OpenCode, …)
|
|
95
|
-
│ ├── ralph.sh ← bash-only loop (no realtime)
|
|
96
95
|
│ ├── lib/ ← stack-specific agent prompts + helpers
|
|
97
96
|
│ └── .slices/ ← board slices, written by `fetch`/`listen` (or pre-seeded by `init --demo`)
|
|
98
97
|
├── .claude/
|
|
@@ -138,24 +137,40 @@ Use skills in Claude Code with `/skill-name`:
|
|
|
138
137
|
|
|
139
138
|
Which skills install depends on the chosen stack — see `stacks/<name>/templates/.claude/skills/`. `/connect`, `/learn-eventmodelers-api`, `/update-slice-status`, and `/request-feedback` have no stack-specific content and install into every stack from `shared/skills/` instead.
|
|
140
139
|
|
|
140
|
+
## `scaffold`: a runnable app from your board
|
|
141
|
+
|
|
142
|
+
`scaffold <dir>` reads the board and generates an app skeleton around the build kits, so slice building starts from an app that already runs. `--type` picks what gets installed and generated:
|
|
143
|
+
|
|
144
|
+
| Type | Installs | You get |
|
|
145
|
+
|---|---|---|
|
|
146
|
+
| `supabase` (default) | `supabase` at the root, `supabase-react` in `web/` | Supabase email/password sign-in, a layout with one navigation entry per timeline, a page shell per screen at `web/src/pages/<ScreenTitle>.tsx`, `501 Not Implemented` for every modeled endpoint without a slice (a built route always wins), a "not built yet" placeholder in the UI, hot reload for both halves, `npm run up` |
|
|
147
|
+
|
|
148
|
+
Needs on the machine: Node 22, Docker, Supabase CLI, Flyway + Java (the command lists what is missing). The skeleton itself needs nothing beyond Node, on macOS, Linux and Windows: `npm run up` / `down` / `db:stop` / `user -- <email> <password>` / `check` all go through one plain script, `scripts/dev.mjs`. `<dir>` must be empty or new, or an earlier skeleton, which is refreshed from the current model — generated files are rewritten, pages and anything a builder wrote are kept. Titles come from the board verbatim; a screen's route comes only from a `route /orders` line in its description, the post-sign-in page from a "home page" line, and Bulma is used when the screen mockups use it. `--no-install` stops after generating, `--no-check` skips the checks; ports are picked free automatically and a refresh keeps them (`--port api=3200` pins one; repeatable).
|
|
149
|
+
|
|
150
|
+
**Your own templates.** `npx @eventmodelers/cli init-templates [paths...]` copies the built-in templates into `./templates/` for you to edit (`--list` shows the paths; name a file such as `web/src/app/Layout.tsx` or a folder such as `web/src/app` to copy only those, and take only what you mean to change — a copied template stops following the CLI's updates; existing files are kept unless `--force`). `scaffold` uses what it finds there and the built-in template for everything else. Or put `*.tmpl` files in a `templates/` folder in the app's root (or point `--templates <dir>` at one, which also works on the first run). A file there replaces the built-in template at the same path — `templates/web/src/app/Layout.tsx.tmpl` replaces `web/src/app/Layout.tsx` — and a path with no built-in counterpart is simply added. The same tokens apply (`__APP_TITLE__`, `__API_PORT__`, `__WEB_PORT__`, `__DB_PORT__`), and every refresh uses them again, so customisations survive a model change. Only `*.tmpl` files count, so nothing in `templates/` is compiled as project code. Files the scaffold writes once (pages, `extraEndpoints.ts`) are never overwritten whatever you put there; edit those in place.
|
|
151
|
+
|
|
152
|
+
The `supabase` skeleton generator is adapted from the em-scaffold skill by Adrian Mowat (MIT, `shared/scaffold/LICENSE-em-scaffold`).
|
|
153
|
+
|
|
141
154
|
## Everyday commands
|
|
142
155
|
|
|
143
156
|
```bash
|
|
144
157
|
npx @eventmodelers/cli init --stack <name> # scaffold a stack + install + configure (alias: install)
|
|
145
158
|
npx @eventmodelers/cli init --stack <name> --demo # same, plus a ready-made demo model in the kit's .slices/ to build against
|
|
159
|
+
npx @eventmodelers/cli scaffold <dir> --type supabase # app skeleton from the board (sign-in, navigation, a page per screen, 501 for unbuilt slices) + both kits installed, ready for `run`
|
|
146
160
|
npx @eventmodelers/cli re-init # refresh an already-installed kit's scripts/skills only — never touches the root scaffold
|
|
147
161
|
npx @eventmodelers/cli run # start the agent loop (ralph-claude.js) from the installed kit dir
|
|
162
|
+
npx @eventmodelers/cli run --all # every build kit in the project at once (this directory and up to two levels below, e.g. a scaffolded app's root and web/), prefixed output, Ctrl+c stops all; other flags (--agent, --handover, …) go to each
|
|
163
|
+
npx @eventmodelers/cli run --all --modeling # the same, plus a modeling agent running alongside the build kits
|
|
148
164
|
npx @eventmodelers/cli run --local-ai [target] # board work only via a local/self-hosted model (ralph-local-ai.js) — does NOT build slices; build locally with --exec
|
|
149
165
|
npx @eventmodelers/cli run --agent <name> # pick the agent: claude (default), opencode, codex, gemini — bare --agent lists them with their exact commands
|
|
150
166
|
npx @eventmodelers/cli run --agent <name> --model <id> # …on a given model: -m for opencode/codex/gemini, --model for Claude, LOCAL_AI_MODEL for --local-ai
|
|
151
167
|
npx @eventmodelers/cli run --exec "<command>" # manual fallback for any other harness (ralph-exec.js) — agent tracing needs its JSON flag, e.g. "codex exec --json --full-auto"
|
|
152
|
-
npx @eventmodelers/cli run --bash # bash-only loop, no realtime (ralph.sh)
|
|
153
168
|
npx @eventmodelers/cli run --local # skip platform config/credential lookup entirely — local-only, no board sync
|
|
154
169
|
npx @eventmodelers/cli run --modeling # modeling-kit: warm Claude process driven by the board's prompt queue
|
|
155
170
|
npx @eventmodelers/cli run --standalone # same, plus acting on board changes unprompted — and needs no install at all
|
|
156
171
|
npx @eventmodelers/cli run --standalone --board-id <uuid> # …from any directory, against any board (see Power users)
|
|
157
172
|
npx @eventmodelers/cli run --id <id> --name <label> # override this run's agent identity (id + display name); `init --name` persists a name instead
|
|
158
|
-
npx @eventmodelers/cli run --handover # backend kit, this run only: finish slices that have a UI at `
|
|
173
|
+
npx @eventmodelers/cli run --handover # backend kit, this run only: finish slices that have a UI at `Waiting` instead of `Done` (see Backend → UI handover)
|
|
159
174
|
npx @eventmodelers/cli config --handover on|off # persist that choice for the project (`handover` in .eventmodelers/config.json)
|
|
160
175
|
npx @eventmodelers/cli fetch --context <name> # pull full slice detail for one context on the board into <kit-dir>/.slices/
|
|
161
176
|
npx @eventmodelers/cli fetch --context <name> --slice-id <id> # same, then print just that slice
|
|
@@ -200,7 +215,7 @@ npx @eventmodelers/cli run --local
|
|
|
200
215
|
|
|
201
216
|
and the agent starts building — `--local` skips platform config and credential lookup entirely, so it works straight out of `init` with nothing connected. Every TODO you fill in gets exercised on the next iteration against real slice data covering all four slice types (state change, state view, automation, translation), which is exactly the coverage a new stack's `build-*` skills need before it's worth promoting.
|
|
202
217
|
|
|
203
|
-
**Backend → UI handover.** Besides the usual statuses a slice can be `Ready` (modeling done, waiting to be planned) and `
|
|
218
|
+
**Backend → UI handover.** Besides the usual statuses a slice can be `Ready` (modeling done, waiting to be planned) and `Waiting` (backend built, UI contract published, waiting for the UI kit). The flow is `Ready → Planned → InProgress → Waiting → InProgress → Done`. Install with `init --handover` (or `re-init --handover`; switch later with `eventmodelers config --handover on|off`; for a single run `run --handover` overrides the setting without saving anything), which saves `"handover": true` in `.eventmodelers/config.json` — then a backend kit ends STATE_VIEW / STATE_CHANGE slices at `Waiting` instead of `Done` (the `ui-contract` skill, Step 4, owns that rule); without the flag nothing changes: slices end at `Done`, exactly as before. A kit claims work from the status named in its `lib/kit.json` — `{ "pickupStatus": "Waiting" }` for the `react` / `supabase-react` UI kits, absent (= `Planned`) for backend kits. A new UI kit ships that file and sets `Done` when its half is built; a new backend kit just invokes `ui-contract`. Needs a platform with the `Ready` / `Waiting` statuses.
|
|
204
219
|
|
|
205
220
|
**UI contract (handover only).** With handover on, the scaffolded `build-state-view` / `build-state-change` skills end by invoking the shared `ui-contract` skill, which publishes each slice's read (`GET`) or write (`POST`) contract — the endpoint's OpenAPI operation, as a ```` ```yaml ui-contract ```` block — as a `## UI Contract` section in the slice's feedback-lane markdown node (exported in `slice.json` `notes[]`, so a UI build kit can look it up directly). Two things are yours to decide: *where the contract is derived from* (point the `UI Contract` section of those skills at your stack's machine-readable API description, if it has one — the `node`/`supabase` stacks use their `@openapi` blocks via a `ui-contract-from-openapi.md` reference, taking the operation verbatim — otherwise the skill writes the equivalent OpenAPI operation from the route code), and, if you need a different shape or location, a whole-skill override: ship `.claude/skills/ui-contract/SKILL.md` in the stack's templates and it replaces the shared one (stack templates are applied after `shared/skills/`).
|
|
206
221
|
|
|
@@ -210,7 +225,7 @@ Installing both a build stack and `init-modeling` into the same project reuses t
|
|
|
210
225
|
|
|
211
226
|
A modeling-kit install has one runtime: a warm Claude process the CLI keeps alive across
|
|
212
227
|
turns and feeds directly over stdin, so a prompt typed (or spoken) on the board is picked up
|
|
213
|
-
with no cold start and no
|
|
228
|
+
with no cold start and no task-queue round trip.
|
|
214
229
|
|
|
215
230
|
```bash
|
|
216
231
|
npx @eventmodelers/cli run --modeling # react to prompts sent to this board
|
|
@@ -273,7 +288,7 @@ pass `--model <id>` as usual.
|
|
|
273
288
|
|
|
274
289
|
Claude and Gemini need a gateway (e.g. LiteLLM) in front of a non-native server, since they only speak their own protocol.
|
|
275
290
|
|
|
276
|
-
`--agent`, `--exec
|
|
291
|
+
`--agent`, `--exec` and `--local-ai` each pick the runner, so pass at most one of them —
|
|
277
292
|
any two together are rejected. For a local or self-hosted model use `--local-ai`, not `--agent`.
|
|
278
293
|
|
|
279
294
|
To drive either one with a local model instead of Claude, see [Running the modeling agent on a local model](#running-the-modeling-agent-on-a-local-model).
|
|
@@ -524,40 +539,37 @@ npx @eventmodelers/cli init-modeling --global
|
|
|
524
539
|
|
|
525
540
|
Everything else (the kit dir, project scaffold, credentials, MCP registration) still targets the current directory as usual — `--global` only changes where skills land.
|
|
526
541
|
|
|
527
|
-
###
|
|
542
|
+
### Syncing a context to Spec Kitty
|
|
528
543
|
|
|
529
|
-
If you drive development with
|
|
544
|
+
If you drive development with Spec Kitty instead of build-kit's own code generation, `fetch` can restate a context for it in one shot:
|
|
530
545
|
|
|
531
546
|
```bash
|
|
532
|
-
npx @eventmodelers/cli
|
|
533
|
-
npx @eventmodelers/cli bridge
|
|
547
|
+
npx @eventmodelers/cli fetch --context Ticketing --spec-kitty
|
|
534
548
|
```
|
|
535
549
|
|
|
536
|
-
|
|
550
|
+
That sync is deterministic and stops well short of writing Spec Kitty's own artifacts — `lib/adapters/spec-kitty-adapter.js` fetches full slice detail and restates it as a plain markdown mission brief (one section per slice, its scenarios verbatim, nothing invented), then calls `spec-kitty intake --force` to install it at `.kittify/mission-brief.md`. It deliberately doesn't create the mission, write `spec.md`, or author work packages — Spec Kitty's own `/spec-kitty.specify` → `/spec-kitty.plan` → `/spec-kitty.tasks` pipeline does that, because those steps need real judgment (work package boundaries, which files a WP owns, which agent profile fits) that only makes sense with actual codebase context, which this adapter doesn't have. What it replaces is Spec Kitty's *interactive discovery interview*: `/spec-kitty.specify`'s own "Brief Context Detection" step reads `.kittify/mission-brief.md` when present and extracts requirements from it instead of asking the user, so the event model — not a live Q&A — becomes the input. No LLM call happens in this adapter.
|
|
537
551
|
|
|
538
|
-
|
|
552
|
+
`spec-kitty init` (Spec Kitty's own project setup) has to have already been run in the project root — the adapter checks for `.kittify/` first and stops with the exact command to run if it's missing, rather than failing deep inside a cryptic `spec-kitty` CLI error. After the sync, run `/spec-kitty.specify` in your coding agent to turn the brief into an actual mission (the plain `spec-kitty specify` CLI command only scaffolds — brief detection is in the agent-driven prompt).
|
|
539
553
|
|
|
540
|
-
|
|
554
|
+
(The standing bridge loop — `init --bridge` / `bridge` — is retired for now.)
|
|
541
555
|
|
|
542
|
-
|
|
543
|
-
npx @eventmodelers/cli fetch --context Ticketing --spec-kitty
|
|
544
|
-
```
|
|
545
|
-
|
|
546
|
-
Either way, `spec-kitty init` (Spec Kitty's own project setup) has to have already been run in the project root — the adapter checks for `.kittify/` first and stops with the exact command to run if it's missing, rather than failing deep inside a cryptic `spec-kitty` CLI error. After the sync, run `/spec-kitty.specify` in your coding agent to turn the brief into an actual mission (the plain `spec-kitty specify` CLI command only scaffolds — brief detection is in the agent-driven prompt).
|
|
556
|
+
### Reading the event log
|
|
547
557
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
Claude is only the default — some teams don't want an AI agent in this loop at all, e.g. they'd rather just commit + push the board export and let a CI pipeline own the actual translation. `--hook` replaces the AI executor with an arbitrary shell command, run once per batch of slice changes:
|
|
558
|
+
Everything an agent does to a slice, a task, a prompt or a learning is an event in the kit's log (`.build-kit/events/` and `events.log`, or `.agent-modeling-kit/` for a modeling agent). `eventmodelers events` decodes it in the terminal — one line per event, with the slice's title and the first four characters of the agent that wrote it:
|
|
551
559
|
|
|
552
560
|
```bash
|
|
553
|
-
npx @eventmodelers/cli
|
|
554
|
-
npx @eventmodelers/cli
|
|
561
|
+
npx @eventmodelers/cli events # the build kit of this project, else its modeling kit
|
|
562
|
+
npx @eventmodelers/cli events --type claimed,settled # only these event types
|
|
563
|
+
npx @eventmodelers/cli events --slice "Add item" # a slice by id prefix or part of its title
|
|
564
|
+
npx @eventmodelers/cli events --tag ci --last 20 # by tag; only the last 20 that remain
|
|
565
|
+
npx @eventmodelers/cli events --state # what the log folds to: slices, queue, open prompts, learnings
|
|
566
|
+
npx @eventmodelers/cli events --json # the raw events, one per line (pipe to jq)
|
|
567
|
+
npx @eventmodelers/cli events --follow # keep printing as events are appended
|
|
568
|
+
npx @eventmodelers/cli events --kit ../other/.build-kit # another kit's log, from anywhere
|
|
569
|
+
npx @eventmodelers/cli events --global # the global install's log (~/.eventmodelers/kit): what runs without a project install wrote
|
|
570
|
+
npx @eventmodelers/cli events --global --board c2b3b7da # that log mixes every board; --board keeps one (an id prefix)
|
|
555
571
|
```
|
|
556
572
|
|
|
557
|
-
`init --bridge --hook` persists the command to `.bridge-kit/bridge.json` — a plain, **committed** file (unlike `.eventmodelers/config.json`, which is gitignored for credentials) since the hook is project policy meant to be shared by every teammate and CI runner, not per-machine state. `bridge --hook "<command>"` overrides it for a single run without touching that file. Only one executor runs per invocation — `--local-ai`, `--hook`, and `--claude` are mutually exclusive.
|
|
558
|
-
|
|
559
|
-
The hook command runs with `BRIDGE_TASK_COUNT`, `BRIDGE_SLICE_ID`/`_TITLE`/`_STATUS` (the most recent change in the batch), and `BRIDGE_BATCH_FILE` (path to the full batch as JSON) in its environment. It's invoked once per batch, not once per slice — any change that arrives while the hook is still running is left queued for the next batch rather than dropped.
|
|
560
|
-
|
|
561
573
|
### Claude execution & config resolution
|
|
562
574
|
|
|
563
575
|
During install you can optionally point the agent at a local LLM server instead of the default
|
|
@@ -630,7 +642,7 @@ npx @eventmodelers/cli init-config --name ci-builder # name the agent this c
|
|
|
630
642
|
|
|
631
643
|
### Naming an agent
|
|
632
644
|
|
|
633
|
-
Every agent identifies itself to the platform with an `agentId`, and the board's live-agent view shows
|
|
645
|
+
Every agent identifies itself to the platform with an `agentId`, and the board's live-agent view shows it. An agent keeps **one id**: a **project install** mints it on first use (`agentIds` in the project root's `.eventmodelers/config.json`), a **standalone/global run** keeps one per board and repo — the directory it is started in — in `~/.eventmodelers/agent-ids.json`. It is the same agent on every restart, with its chat sessions, its star on the board and the prompts it holds. Two live processes must not share an id (the heartbeat is keyed on `(token, agentId, agentType)`, so the second would replace the first, and its start-up recovery would hand back the first one's prompts), so each run takes a small lock on its id (`.eventmodelers/locks/` in the project, `~/.eventmodelers/locks/` globally); if another live process already holds it, this run gets a fresh id and, unless you named it, an instance-marked name (`cart-service (modeling) · 3f9a`). `--id` is used as given, with no such check — for a second agent on purpose, or a supervisor that knows the id it wants. Without a name an agent shows as `<repo> (<type>)`, the repo being the `origin` remote's name or the folder.
|
|
634
646
|
|
|
635
647
|
`--name` gives an agent a readable label instead of the uuid — accepted by `init`, `re-init`, and `init-config`, saved into `config.json` as `agentName`, and sent with every heartbeat from then on:
|
|
636
648
|
|
|
@@ -657,7 +669,7 @@ Pair it with `--id`: a `--standalone`/`--global` run mints a fresh id per run, s
|
|
|
657
669
|
|
|
658
670
|
### Backend → UI handover (`--handover`)
|
|
659
671
|
|
|
660
|
-
A slice with a UI is only finished once two kits have each built their half: the backend kit builds the endpoint and publishes its contract, the UI kit builds the frontend against it. `--handover` makes the first kit stop at `
|
|
672
|
+
A slice with a UI is only finished once two kits have each built their half: the backend kit builds the endpoint and publishes its contract, the UI kit builds the frontend against it. `--handover` makes the first kit stop at `Waiting` instead of `Done`, so the second one can claim the slice.
|
|
661
673
|
|
|
662
674
|
```bash
|
|
663
675
|
npx @eventmodelers/cli init --stack node --handover # persisted: "handover": true in .eventmodelers/config.json (also re-init)
|
|
@@ -668,18 +680,18 @@ npx @eventmodelers/cli run --handover # this run only — writes
|
|
|
668
680
|
|
|
669
681
|
| | Handover off (default) | Handover on |
|
|
670
682
|
|---|---|---|
|
|
671
|
-
| Backend kit, STATE_VIEW / STATE_CHANGE slice | ends at `Done`, no UI contract published | publishes the UI contract, ends at `
|
|
683
|
+
| Backend kit, STATE_VIEW / STATE_CHANGE slice | ends at `Done`, no UI contract published | publishes the UI contract, ends at `Waiting` |
|
|
672
684
|
| Backend kit, automation / translation | `Done` | `Done` — no UI counterpart |
|
|
673
|
-
| UI kit (`react`, `supabase-react`) | claims `
|
|
685
|
+
| UI kit (`react`, `supabase-react`) | claims `Waiting` only | claims `Waiting` only, sets `Done` when its UI is built |
|
|
674
686
|
|
|
675
|
-
Flow: `Ready → Planned → InProgress →
|
|
687
|
+
Flow: `Ready → Planned → InProgress → Waiting → InProgress → Done`. Precedence for a run is `run --handover` over the project's `handover` setting; the runner states the effective value to the agent as a `Handover: on|off` line in its task, so the agent never has to work it out from `config.json`. `config --handover` writes to the project's config (the installed kit's project, else the nearest `.eventmodelers/config.json` up the tree — never the account-wide one in `~/`).
|
|
676
688
|
|
|
677
689
|
**What to know before relying on it**
|
|
678
690
|
|
|
679
|
-
- **UI kits only ever claim `
|
|
691
|
+
- **UI kits only ever claim `Waiting`.** Against a board whose backend finished slices at `Done`, a `react` / `supabase-react` kit has nothing to do and replies `NO_TASKS` — the backend side must run with handover on.
|
|
680
692
|
- **Both sides need the new kit.** An already-installed backend kit keeps its old `ralph.js` and prompts and silently ignores `--handover` (slices still end at `Done`); `re-init` it to pick the feature up.
|
|
681
|
-
- **The platform must know the `Ready` / `
|
|
682
|
-
- A kit declares what it claims in `lib/kit.json` — `{ "pickupStatus": "
|
|
693
|
+
- **The platform must know the `Ready` / `Waiting` statuses.**
|
|
694
|
+
- A kit declares what it claims in `lib/kit.json` — `{ "pickupStatus": "Waiting" }`; absent means `Planned`.
|
|
683
695
|
- `run --status-trigger <status>` overrides that pickup status for a single run (e.g. `--status-trigger Ready`); nothing is saved.
|
|
684
696
|
|
|
685
697
|
The contract itself is the shared `ui-contract` skill's job (see above); it also owns the rule for which status a slice ends at.
|
|
@@ -763,7 +775,7 @@ npx @eventmodelers/cli re-init --modeling # refresh the modeling kit
|
|
|
763
775
|
npx @eventmodelers/cli re-init --stack supabase # override which stack to refresh from (manifest missing/stale, or switching stacks)
|
|
764
776
|
```
|
|
765
777
|
|
|
766
|
-
`re-init` re-runs `init` against whichever stack `install-manifest.json` says was installed (no need to pass `--stack` again), but skips step 2 of `init` entirely — the root project scaffold (`package.json`, `src/`, `server.ts`, `docker-compose.yml`, etc.) and the root `CLAUDE.md` router are never touched. Use it after upgrading the CLI to pick up fixes to `ralph.js
|
|
778
|
+
`re-init` re-runs `init` against whichever stack `install-manifest.json` says was installed (no need to pass `--stack` again), but skips step 2 of `init` entirely — the root project scaffold (`package.json`, `src/`, `server.ts`, `docker-compose.yml`, etc.) and the root `CLAUDE.md` router are never touched. Use it after upgrading the CLI to pick up fixes to `ralph.js`/skills without re-scaffolding a project you've since built on top of.
|
|
767
779
|
|
|
768
780
|
You don't have to remember to: on startup every command prints a 💡 hint (on stderr) when a newer CLI is on npm, or when a kit in the current directory was installed by an older CLI than the one running — naming the exact `re-init` command to run. The npm lookup happens at most once a day (cached in `~/.eventmodelers/update-check.json`, 1.5 s timeout, silent when offline). Set `EVENTMODELERS_NO_UPDATE_CHECK=1` to turn it off; it is also off when `CI` is set.
|
|
769
781
|
|
package/RELEASE_NOTES.md
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
|
-
##
|
|
1
|
+
## v2.0.0
|
|
2
|
+
|
|
3
|
+
### Architecture: the kit now runs on an event log
|
|
4
|
+
The CLI's local state used to live in mutable files — `tasks.json` as the queue, `progress.txt` as the learnings journal, a `.claim.json` claim record, and status edited in place in `index.json`/`slice.json`. Concurrent writers, a stale board refresh or a crash could each leave those files disagreeing with the board or with each other (the failure modes are written down in `slice-state-learnings.md`). 2.0.0 replaces all of it with **event sourcing**: everything an agent does to a slice, a task, a prompt or a learning is an immutable event appended to a log, and every other file is a projection folded from that log.
|
|
5
|
+
|
|
6
|
+
- **The store.** One JSON file per event under `.build-kit/events/` (`.agent-modeling-kit/` for the modeling agent), written whole before its id is appended to `events.log`; the index line is what commits the event, so concurrent writers cannot tear the log whatever the event size. Events carry tags and `agent_id`/`organization_id`/`board_id` metadata. The store is git-ignored, and the loop's git rules now live in `.git/info/exclude` and `.git/info/attributes`, so starting an agent never dirties the tracked tree.
|
|
7
|
+
- **A pure core.** `fold` derives status, claim, pending outcome, attempts, blocked state, the task queue, open prompts and learnings from the event list; `decideSettle` and `decideRecovery` turn that into push/discard/release actions. Side effects sit around the fold, not inside it.
|
|
8
|
+
- **Slice lifecycle as events.** The loop claims a slice (`claimed`/`claim-confirmed`), settles it after the build by executing `decideSettle` (push the recorded outcome, or discard the attempt, record `attempt-failed` and put the slice back to its pickup status), and settles claims left by dead processes at the top of every iteration. Board refreshes are recorded as `board-observed`, so a stale refresh during a build can no longer revert what the agent recorded. The build agent records its outcome with `eventmodelers slice-status <status>`; the loop owns the status on the board.
|
|
9
|
+
- **Attempts and auto-blocks come from the log**, not from an in-memory map, so a restart no longer hands a stuck slice a fresh budget.
|
|
10
|
+
- **The task queue is the log.** A slice change arrives as `task-queued` (a newer change to the same slice replaces its task); the loop replays the log for the oldest task, hands it to the agent and appends `task-done`. A change landing mid-turn is just another event.
|
|
11
|
+
- **Prompts are journaled.** `prompt-received`/`prompt-finished` bracket every prompt the modeling agent takes; on start, what a crash left open is looked up on the platform and handed back unless it already finished. Recovery asks the platform who holds a prompt (`claimed_by`) rather than tracking process ids.
|
|
12
|
+
- **Learnings are events.** `eventmodelers learn` records one (topic, tags, scope; duplicates skipped) and `learn --retract` withdraws it; `learnings` lists them. `AGENTS.md` is rendered from the events and adopts lines added by hand, so regenerating never loses them. After `RALPH_CURATE_AFTER` (default 10) new learnings, a curator turn that can only merge and retract tidies the list (`learning-merged`, `learnings-curated`).
|
|
13
|
+
- **Look at it.** `eventmodelers events` decodes the log in the terminal — one line per event with the slice title and the writing agent; `--type`, `--slice`, `--tag`, `--last`, `--json`, `--state` (what the log folds to), `--follow`, `--kit`, `--global` and `--board` narrow or redirect it.
|
|
14
|
+
- **One agent id, one live process.** A standalone run keeps a stable agent id per board and repo, and takes an exclusive lock on it, so two processes never share an id, a heartbeat row or each other's prompts. A global install records nothing, so one board's learnings never surface in another's.
|
|
15
|
+
|
|
16
|
+
### Breaking changes
|
|
17
|
+
- `tasks.json` is gone. Nothing reads or writes a queue file any more; the stacks' `prompt.md` files lose their queue steps and the `IDLE` reply, and `AGENT.md` is now a reference.
|
|
18
|
+
- `progress.txt` is gone. Learnings go through `eventmodelers learn`, a failed attempt is read from the slice's `lastAttempt`, and a block reason lives on its event.
|
|
19
|
+
- `run --bash` (the bash-only loop: `ralph.sh`, `lib/agent.sh`, `realtime-agent.js`) is retired. The flag is still recognised, only to say so.
|
|
20
|
+
- The bridge kit is retired: `init --bridge` (with `--target`/`--hook`), the `bridge` command and `uninstall --bridge-kit`. `fetch --spec-kitty` keeps working on its own.
|
|
2
21
|
|
|
3
|
-
### Features
|
|
4
22
|
- `run --modeling`/`run --standalone` accept `--local-ai`, so the modeling agent can be driven by a local or self-hosted model instead of Claude. It was previously rejected as a build-kit-only flag, which conflated two different things: `--bash`/`--exec` select a *queue* the modeling loop has no equivalent of, while `--local-ai` selects a *model*. Both wire dialects are supported — `--local-ai` (bare) or `--local-ai ollama` for Ollama's native `POST /api/chat`, and `--local-ai vllm`/`lmstudio`/`llamacpp` for the OpenAI-compatible `POST /v1/chat/completions` that vLLM, LM Studio, llama.cpp-server, TGI and SGLang serve; anything else OpenAI-compatible works via `LOCAL_AI_URL`. The loop itself is untouched: the prompt queue, the standalone board-change lane and its damping, the idle review and the platform's full MCP tool set all behave as before, because everything Claude-specific already sat behind a single `runTurn(text)` seam. What a local model cannot bring along is the part that is not a wire format — the skills (`/place-element`, `/timeline`, `eventmodeling-*`) and the subagent fan-out are Claude Code features — so a self-directed turn does the most valuable piece of work itself, inline, and the board rules it needs come from the new runner's system prompt (`lib/modeling-local-ai.js`) instead of `.agent-modeling-kit/CLAUDE.md`. `--max-agents` is ignored in this mode. Ollama's `num_ctx` is raised to 49152 by default (the MCP tool schemas alone are ~16k tokens, well past Ollama's 4096 default, which would silently truncate the tool block), with a warning when the schemas still fill >60% of it and a turn cap of 24 tool iterations.
|
|
5
23
|
|
|
6
24
|
- `run --non-interactive` never asks anything: the board and credentials that resolve from flags, `EVENTMODELERS_*` env vars and the config files are final, and an incomplete set fails the run with the reason instead of being interviewed for. A missing TTY already implied this, which covered CI and most supervisors, but not a container started with `-it` or a loop started from a terminal — stdin is a TTY nobody is watching, and the run stopped on the board confirmation or the credentials question forever. `EVENTMODELERS_TOKEN` also now answers the credentials question on its own, the way `EVENTMODELERS_BOARD_ID` always answered the board question: an env var that outranks every config file makes asking where the credentials come from moot. The README gains a container recipe, including the two things a container needs that a laptop already had — a writable HOME for the global kit and per-board credentials, and a `LOCAL_AI_URL` that isn't `localhost`.
|