@eventmodelers/cli 0.0.30 → 0.0.31

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/cli.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { Command } from 'commander';
4
4
  import { fileURLToPath, pathToFileURL } from 'url';
5
- import { dirname, join, relative, resolve, sep } from 'path';
5
+ import { dirname, isAbsolute, join, normalize, relative, resolve, sep } from 'path';
6
6
  import {
7
7
  existsSync,
8
8
  mkdirSync,
@@ -529,6 +529,17 @@ function findAllInstalledKitDirs(cwd) {
529
529
  return KIT_DIR_NAMES.map((name) => join(cwd, name)).filter((p) => existsSync(p));
530
530
  }
531
531
 
532
+ // Appends any line from a previous install's .gitignore that the freshly-copied one
533
+ // doesn't already cover — unlike CLAUDE.md's freeform prose, .gitignore is just a line
534
+ // list, so a simple dedup-append is enough to keep both kits' ignore rules intact.
535
+ function mergeGitignoreLines(oldContent, newContent) {
536
+ const newLines = new Set(newContent.split('\n').map((l) => l.trim()).filter(Boolean));
537
+ const additions = oldContent.split('\n').filter((l) => l.trim() && !newLines.has(l.trim()));
538
+ if (!additions.length) return newContent;
539
+ const sep = newContent.endsWith('\n') ? '' : '\n';
540
+ return `${newContent}${sep}${additions.join('\n')}\n`;
541
+ }
542
+
532
543
  function copyDirContents(srcDir, destDir, { skip = [] } = {}) {
533
544
  if (!existsSync(srcDir)) return;
534
545
  mkdirSync(destDir, { recursive: true });
@@ -567,6 +578,17 @@ function cloneGitStack(url, branch) {
567
578
  return dest;
568
579
  }
569
580
 
581
+ // stack.json's kitSubdir is attacker-controlled (it comes from whatever repo --git
582
+ // cloned) and feeds straight into join(templatesSource, kitSubdir) — installStack
583
+ // then copies everything under that path into the target project. Reject anything
584
+ // that isn't a plain relative subdirectory name so a malicious stack.json can't walk
585
+ // out of the clone (e.g. "../../../../etc") and have arbitrary host files copied in.
586
+ function isSafeRelativeSubpath(p) {
587
+ if (typeof p !== 'string' || !p) return false;
588
+ const normalized = normalize(p);
589
+ return !isAbsolute(normalized) && normalized.split(sep).every((part) => part !== '..');
590
+ }
591
+
570
592
  // A community stack repo must mirror the internal stacks/<key>/templates layout exactly
571
593
  // (templates/.claude, templates/root, templates/<kitSubdir>) so installStack() can treat
572
594
  // it identically to a built-in stack — see STACKS above for the shape. An optional
@@ -580,7 +602,40 @@ function resolveGitStackConfig(clonedDir, name) {
580
602
  console.error(`❌ ${relative(process.cwd(), clonedDir) || clonedDir} has no templates/ directory — a build kit repo needs templates/.claude, templates/root, and templates/<kitSubdir>, the same layout this CLI's own stacks/<name>/templates use.`);
581
603
  process.exit(1);
582
604
  }
583
- const manifest = readJsonSafe(join(clonedDir, 'stack.json'));
605
+ for (const required of ['.claude', 'root']) {
606
+ if (!existsSync(join(templatesSource, required))) {
607
+ console.error(`❌ ${relative(process.cwd(), templatesSource) || templatesSource} is missing "${required}/" — a build kit repo needs templates/.claude, templates/root, and templates/<kitSubdir>, the same layout this CLI's own stacks/<name>/templates use.`);
608
+ process.exit(1);
609
+ }
610
+ }
611
+
612
+ const manifestPath = join(clonedDir, 'stack.json');
613
+ const manifestRaw = existsSync(manifestPath) ? readFileSync(manifestPath, 'utf-8') : null;
614
+ let manifest = {};
615
+ if (manifestRaw !== null) {
616
+ try {
617
+ manifest = JSON.parse(manifestRaw);
618
+ } catch {
619
+ console.error(`❌ ${relative(process.cwd(), manifestPath) || manifestPath} is not valid JSON.`);
620
+ process.exit(1);
621
+ }
622
+ }
623
+
624
+ if (manifest.label !== undefined && (typeof manifest.label !== 'string' || !manifest.label)) {
625
+ console.error('❌ stack.json "label" must be a non-empty string.');
626
+ process.exit(1);
627
+ }
628
+ if (manifest.kitSubdir !== undefined && !isSafeRelativeSubpath(manifest.kitSubdir)) {
629
+ console.error(`❌ stack.json "kitSubdir" must be a plain relative subdirectory name (no "..", no absolute paths) — got ${JSON.stringify(manifest.kitSubdir)}.`);
630
+ process.exit(1);
631
+ }
632
+ for (const boolField of ['useShared', 'needsBoardId']) {
633
+ if (manifest[boolField] !== undefined && typeof manifest[boolField] !== 'boolean') {
634
+ console.error(`❌ stack.json "${boolField}" must be a boolean.`);
635
+ process.exit(1);
636
+ }
637
+ }
638
+
584
639
  const kitSubdir = manifest.kitSubdir || 'build-kit';
585
640
  if (!existsSync(join(templatesSource, kitSubdir))) {
586
641
  console.error(`❌ ${relative(process.cwd(), templatesSource) || templatesSource} is missing its kit subdirectory "${kitSubdir}/" (from stack.json, or the "build-kit" default) — nothing to install.`);
@@ -668,9 +723,72 @@ async function installStack(stackKey, stackCfg, options = {}) {
668
723
 
669
724
  // --- 2. Spread stack scaffold files into the project root ---
670
725
  const rootSrc = join(templatesSource, 'root');
726
+ // root/CLAUDE.md is never copied to the project root directly (see step 3 below) —
727
+ // built-in stacks no longer ship one at all, and an outdated community/--git stack
728
+ // that still does gets it relocated into its own kit dir instead, so this generic
729
+ // copy must never let it slip through to root and clobber the shared router there.
730
+ const stackRootClaudeSrc = join(rootSrc, 'CLAUDE.md');
731
+ const stackShipsOwnRootClaude = existsSync(stackRootClaudeSrc);
671
732
  if (existsSync(rootSrc)) {
672
733
  console.log('📦 Installing project files...');
673
- copyDirContents(rootSrc, targetDir);
734
+ // .gitignore is the one file every stack's root/ ships that can collide with
735
+ // another already-installed kit's own .gitignore (e.g. modeling-kit + a build-kit
736
+ // stack) — capture what's there before the copy below overwrites it wholesale,
737
+ // then merge the two afterwards instead of silently losing whichever rules the
738
+ // first-installed kit added (e.g. node_modules/.idea from a build-kit install).
739
+ const gitignoreDest = join(targetDir, '.gitignore');
740
+ const priorGitignore = existsSync(gitignoreDest) ? readFileSync(gitignoreDest, 'utf-8') : null;
741
+ copyDirContents(rootSrc, targetDir, { skip: ['CLAUDE.md'] });
742
+ if (priorGitignore !== null && existsSync(gitignoreDest)) {
743
+ const incoming = readFileSync(gitignoreDest, 'utf-8');
744
+ const merged = mergeGitignoreLines(priorGitignore, incoming);
745
+ if (merged !== incoming) {
746
+ writeFileSync(gitignoreDest, merged);
747
+ console.log(' ✓ Merged .gitignore with the rules from an already-installed kit');
748
+ }
749
+ }
750
+ }
751
+
752
+ // A modeling-kit + build-kit (or bridge) combo in the same project is supported
753
+ // (they share one config.json — see ensureAgentId) but each kit's own instructions
754
+ // now live in its own kit dir (.build-kit/CLAUDE.md, .agent-modeling-kit/CLAUDE.md)
755
+ // instead of root/CLAUDE.md, precisely so a second kit's install can never clobber
756
+ // the first kit's instructions the way it used to — including an outdated community
757
+ // stack's own root/CLAUDE.md, already relocated above rather than left here to
758
+ // compete for this slot. The root CLAUDE.md is instead a small, stack-agnostic router
759
+ // pointing at whichever kit CLAUDE.md files exist — identical content regardless of
760
+ // which stack installs it, so a fresh project or one that already has the up-to-date
761
+ // router both just get it written/left alone silently. Only a pre-migration
762
+ // single-stack CLAUDE.md (from before this fix shipped) or the user's own hand-edited
763
+ // notes is there an actual decision to make, so that's the one case this asks about
764
+ // instead of silently guessing either way.
765
+ const rootClaudeDest = join(targetDir, 'CLAUDE.md');
766
+ const sharedRootClaude = join(__dirname, 'shared', 'root-claude', 'CLAUDE.md');
767
+ const routerContent = existsSync(sharedRootClaude) ? readFileSync(sharedRootClaude, 'utf-8') : null;
768
+ if (routerContent !== null) {
769
+ if (!existsSync(rootClaudeDest)) {
770
+ writeFileSync(rootClaudeDest, routerContent);
771
+ console.log(' ✓ Installed root CLAUDE.md — a router pointing at .build-kit/CLAUDE.md and .agent-modeling-kit/CLAUDE.md, whichever are present');
772
+ } else if (readFileSync(rootClaudeDest, 'utf-8') === routerContent) {
773
+ console.log(' ✓ Root CLAUDE.md already present and up to date — left as-is');
774
+ } else if (options.print) {
775
+ console.log(' ℹ️ --print — a different root CLAUDE.md already exists, leaving it as-is (rerun without --print to choose)');
776
+ } else {
777
+ const choice = await selectPrompt(
778
+ 'A root CLAUDE.md already exists with different content (your own notes, another stack\'s, or a pre-upgrade file) — overwrite it with the router template pointing at each installed kit\'s own CLAUDE.md?',
779
+ [
780
+ { label: 'Keep the existing CLAUDE.md (recommended)', value: 'keep' },
781
+ { label: 'Overwrite with the router template', value: 'overwrite' },
782
+ ],
783
+ 0,
784
+ );
785
+ if (choice === 'overwrite') {
786
+ writeFileSync(rootClaudeDest, routerContent);
787
+ console.log(' ✓ Overwrote root CLAUDE.md with the router template');
788
+ } else {
789
+ console.log(' ✓ Kept the existing root CLAUDE.md');
790
+ }
791
+ }
674
792
  }
675
793
 
676
794
  // --- 3. Create the kit dir and install the agent runner ---
@@ -683,6 +801,19 @@ async function installStack(stackKey, stackCfg, options = {}) {
683
801
  }
684
802
  copyDirContents(join(templatesSource, stackCfg.kitSubdir), kitDir, { skip: ['.eventmodelers'] });
685
803
 
804
+ // An outdated community/--git stack that still ships root/CLAUDE.md (the pre-fix
805
+ // layout every built-in stack used to follow too) gets it relocated here instead
806
+ // of left in root/ — same destination a built-in stack's own templates/<kitSubdir>
807
+ // now ships it at directly. No prompt needed: this is this stack's own file, moving
808
+ // to where its counterpart already lives, not a conflict with anything else.
809
+ if (stackShipsOwnRootClaude) {
810
+ const kitClaudeDest = join(kitDir, 'CLAUDE.md');
811
+ if (!existsSync(kitClaudeDest)) {
812
+ copyFileSync(stackRootClaudeSrc, kitClaudeDest);
813
+ console.log(` ✓ Relocated this stack's CLAUDE.md into ${stackCfg.kitDirName}/ (root/CLAUDE.md is reserved for the shared router)`);
814
+ }
815
+ }
816
+
686
817
  // Static (no-LLM) bridge adapters live once in this package's own lib/
687
818
  // adapters/ — `fetch --spec-kitty` imports them directly, and a bridge
688
819
  // install gets its own copy here so ralph-static.js can run standalone
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventmodelers/cli",
3
- "version": "0.0.30",
3
+ "version": "0.0.31",
4
4
  "description": "Eventmodelers CLI — real-time Claude agent + skills for Claude Code, for any stack (Node, Supabase, Axon, Cratis, or modeling-only)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,13 @@
1
+ # Project Configuration
2
+
3
+ This project can have more than one eventmodelers agent kit installed at once — typically
4
+ one backend stack plus the modeling kit, working side by side on the same board. Each
5
+ installed kit ships its own CLAUDE.md with that kit's own responsibilities. Check which
6
+ of these exist in this project and read whichever are present, following all of them
7
+ together:
8
+
9
+ - `.build-kit/CLAUDE.md` — building this project's backend from board slices
10
+ - `.agent-modeling-kit/CLAUDE.md` — designing and updating the event model board itself
11
+
12
+ Neither is guaranteed to exist — this file is installed once, up front, before either kit
13
+ is known to be present.
@@ -30,7 +30,7 @@ There are two kinds:
30
30
 
31
31
  > **Comments & description**: Each element in the slice carries a `comments: string[]` array and a `description` field. Use these as implementation hints. When done, resolve each used comment: `POST <BASE_URL>/api/org/<ORG_ID>/boards/<BOARD_ID>/nodes/<nodeId>/comments/<commentId>/resolve` (get IDs first via GET on same path).
32
32
 
33
- Read the target project's `CLAUDE.md` and explore existing slices. Look for:
33
+ Read the target project's `.build-kit/CLAUDE.md` and explore existing slices. Look for:
34
34
 
35
35
  - File splitting conventions (one Java file per class vs inner classes)
36
36
  - Visibility conventions
@@ -27,7 +27,7 @@ New workflow slices live under
27
27
 
28
28
  > **Comments & description**: Each element in the slice carries a `comments: string[]` array and a `description` field. Use these as implementation hints. When done, resolve each used comment: `POST <BASE_URL>/api/org/<ORG_ID>/boards/<BOARD_ID>/nodes/<nodeId>/comments/<commentId>/resolve` (get IDs first via GET on same path).
29
29
 
30
- Read `CLAUDE.md` and check whether the project already uses AF5 Workflows. Look for:
30
+ Read `.build-kit/CLAUDE.md` and check whether the project already uses AF5 Workflows. Look for:
31
31
 
32
32
  - A `WorkflowModule` bean in any `@Configuration` class
33
33
  - Classes annotated with `@Workflow`
@@ -19,7 +19,7 @@ description: >
19
19
 
20
20
  > **Comments & description**: Each element in the slice carries a `comments: string[]` array and a `description` field. Use these as implementation hints. When done, resolve each used comment: `POST <BASE_URL>/api/org/<ORG_ID>/boards/<BOARD_ID>/nodes/<nodeId>/comments/<commentId>/resolve` (get IDs first via GET on same path).
21
21
 
22
- Before writing any code, read the target project's `CLAUDE.md`
22
+ Before writing any code, read the target project's `.build-kit/CLAUDE.md`
23
23
 
24
24
  ## Step 1: Ensure Events Exist
25
25
 
@@ -26,7 +26,7 @@ Ignore case for files and slices in prompts. "CartItems" slice is the same as "c
26
26
 
27
27
  Do not change files with tests unless explicitely instructed: *.test.ts
28
28
 
29
- At the start of every session, read `AGENTS.md` if it exists to load accumulated project learnings.
29
+ At the start of every session, read `.build-kit/AGENTS.md` if it exists to load accumulated project learnings.
30
30
 
31
31
  When starting to work on a slice, invoke the `update-slice-status` skill with `InProgress` status before doing anything else.
32
32
 
@@ -45,7 +45,7 @@ You work within **exactly ONE context at a time** — the one named in `.build-k
45
45
  first )
46
46
  16. Update the PRD to set `status: Done` for the completed story in index.json **and** update the slice status on the eventmodelers board using the `update-slice-status` skill (or MCP if available).
47
47
  17. Append your progress to `progress.txt` after each step in the iteration.
48
- 18. append your new learnings to AGENTS.md in a compressed form, reusable for future iterations. Only add learnings if they are not already there.
48
+ 18. append your new learnings to `.build-kit/AGENTS.md` in a compressed form, reusable for future iterations. Only add learnings if they are not already there.
49
49
  19. Finish the iteration.
50
50
 
51
51
  ## Progress Report Format
@@ -155,4 +155,4 @@ If ALL slices in the current context are Done, reply with:
155
155
 
156
156
  ## When an iteration completes
157
157
 
158
- Use all the key learnings from the progress.txt and update the AGENTS.md file with those learnings.
158
+ Use all the key learnings from the progress.txt and update the `.build-kit/AGENTS.md` file with those learnings.
@@ -23,7 +23,7 @@ event → IReactor method (dispatch by first param type) → side effect / I
23
23
 
24
24
  ## Step 0 — Discover conventions
25
25
 
26
- Read `CLAUDE.md` and one existing reactor. Confirm the namespace root, how reactors are placed within a
26
+ Read `.build-kit/CLAUDE.md` and one existing reactor. Confirm the namespace root, how reactors are placed within a
27
27
  slice, which services are available for side effects, and how existing translations call
28
28
  `ICommandPipeline`. Resolve slice `comments` when done (see the state-change skill's Step 0).
29
29
 
@@ -24,7 +24,7 @@ file**:
24
24
 
25
25
  ## Step 0 — Discover the target project's conventions
26
26
 
27
- Before writing code, read the project's `CLAUDE.md` and **at least one existing slice** (the starter
27
+ Before writing code, read the project's `.build-kit/CLAUDE.md` and **at least one existing slice** (the starter
28
28
  ships one under `SomeModule/SomeFeature/`). Confirm:
29
29
 
30
30
  - The namespace root (read the `.csproj` `<RootNamespace>` and existing `.cs` files — never
@@ -23,7 +23,7 @@ file**:
23
23
 
24
24
  ## Step 0 — Discover conventions
25
25
 
26
- Read `CLAUDE.md` and one existing read slice. Confirm the namespace root, how existing read models
26
+ Read `.build-kit/CLAUDE.md` and one existing read slice. Confirm the namespace root, how existing read models
27
27
  declare queries (snapshot vs observable), whether projections use model-bound attributes or
28
28
  `IProjectionFor<T>`, and the MongoDB collection wiring. Resolve slice `comments` when done (see the
29
29
  state-change skill's Step 0 for the resolve endpoint).
@@ -0,0 +1,12 @@
1
+ # Learnings
2
+
3
+ Reusable learnings accumulated while processing prompts for this board. Append new
4
+ ones in a compressed, reusable form; only add if not already covered here.
5
+
6
+ - `/place-element` requires an existing column — create one via the timeline API if missing.
7
+ - `/wdyt` posts QUESTION comments onto nodes — use for analysis only, not modifications.
8
+ - The `board_id`, `timeline_id`, and `organization_id` from each prompt provide full context — pass them to skills that need them.
9
+ - Node events POST to `/api/boards/:boardId/nodes/events` using `node:created`, `node:changed`, `node:deleted`.
10
+ - `/update-slice-status` rejects moving a slice into a status it's already in — this is a concurrency guard so two agents can't both claim the same slice. Treat this as `ALREADY_IN_STATUS`, not a task failure: drop the prompt, move on to the next task, and do not retry the same update.
11
+ - macOS/BSD `date` silently ignores GNU-only format specifiers like `%N`/`%3N` (sub-second precision) instead of erroring — it prints the literal characters, producing a malformed timestamp that only fails downstream. Don't shell out to `date` for sub-second precision; use `$(( $(date +%s) * 1000 ))` for whole-second-in-ms, or a runtime call (`Date.now()`, `process.hrtime()`) instead.
12
+ - Before retrying a failed shell command a second time, diagnose why it failed (e.g. a GNU/BSD flag mismatch) rather than re-running it unchanged — repeating the same command produces the same failure and just burns retries.
@@ -0,0 +1,45 @@
1
+ # Agent Instructions & Learnings
2
+
3
+ You are an autonomous agent processing prompts for an eventmodelers board.
4
+
5
+ ## Mode
6
+
7
+ This project runs in one mode only — a warm, direct-dispatch session driven by
8
+ `npx @eventmodelers/cli run --modeling`. The first message begins with `MODE=modeling`;
9
+ read and follow the project root's **`claude-modeling.md`** for every prompt in this
10
+ session, and don't re-read it on every turn once you've read it once. There is no
11
+ file-queue loop and no `tasks.json` for a modeling-kit install — that's a build-kit
12
+ concept, for their independent, self-contained slice-implementation tasks.
13
+
14
+ The root `claude-modeling.md` shares the Skill Selection table and Progress Entry Format below.
15
+
16
+ At the start of every session, read `.agent-modeling-kit/AGENTS.md` if it exists to load accumulated learnings.
17
+
18
+ ## Skill Selection
19
+
20
+ | Intent | Skill |
21
+ |--------|-------|
22
+ | Add, rename, or reorder events on a timeline | `/timeline` |
23
+ | Place a COMMAND, READMODEL, or EVENT at a position | `/place-element` |
24
+ | Generate a full storyboard with multiple screens | `/storyboard` |
25
+ | Design or update a single wireframe screen | `/storyboard-screen` |
26
+ | Design or update a single real HTML/CSS screen (explicit request only) | `/html-screen` |
27
+ | Business analysis, gap spotting, posting questions | `/wdyt` |
28
+ | Analyse the existing model structure, slice coverage, element counts | `/analyze-existing-model` |
29
+ | Look up any API endpoint or element type | `/learn-eventmodelers-api` |
30
+ | Add or rename an attribute across a chain of elements | `/attributes` |
31
+ | Add or improve example data on element fields | `/examples` |
32
+ | Update the status of a slice (e.g. done, in-progress) | `/update-slice-status` |
33
+
34
+ Read `.claude/skills/<skill-name>/SKILL.md` before executing — each skill has required inputs and step-by-step instructions.
35
+
36
+ ## Progress Entry Format
37
+
38
+ APPEND to `progress.txt` (never replace):
39
+ ```
40
+ ## [ISO timestamp] — [task/prompt identifier]
41
+ Prompts processed: [prompt text(s)]
42
+ Outcome: [what changed on the board]
43
+ Learnings: [any reusable pattern or gotcha noticed this turn, or "none"]
44
+ ---
45
+ ```
@@ -14,9 +14,9 @@ You are a long-lived process handling many turns in a row. Don't redo one-time s
14
14
 
15
15
  Otherwise skip straight to executing the prompt — re-running `/connect` every turn defeats the point of a modeling session.
16
16
  3. **Resolve `BOARD_ID`** from this turn's `board_id` field; if absent, fall back to `boardId` in `.eventmodelers/config.json`.
17
- 4. Execute the prompt using the skill matched in CLAUDE.md's Skill Selection table.
17
+ 4. Execute the prompt using the skill matched in `.agent-modeling-kit/CLAUDE.md`'s Skill Selection table.
18
18
  **Questioning rule**: you are running autonomously — no human is available to answer questions. If you need clarification, do not pause or ask interactively — post a `QUESTION`-type comment (`/handle-comment` with `action=place`, `type=QUESTION`) on the most relevant node, then continue with your best interpretation.
19
19
  5. If this turn has a `comment_id` field, invoke `/handle-comment` with `action=resolve`, `nodeId` from `node_id`, `commentId` from `comment_id`.
20
- 6. Append a progress entry to `progress.txt` — see CLAUDE.md's Progress Entry Format.
21
- 7. Add any reusable learnings to CLAUDE.md's **Learnings** section at the bottom.
20
+ 6. Append a progress entry to `progress.txt` — see `.agent-modeling-kit/CLAUDE.md`'s Progress Entry Format. Fill in the `Learnings` line with anything reusable noticed this turn (pattern, gotcha, useful context), or "none".
21
+ 7. If this turn's `Learnings` line was not "none", promote it to `.agent-modeling-kit/AGENTS.md` (create it if it doesn't exist) only add it if it's not already there.
22
22
  8. Reply `<promise>DONE</promise>` and wait for the next turn.
@@ -26,7 +26,7 @@ Ignore case for files and slices in prompts. "CartItems" slice is the same as "c
26
26
 
27
27
  Do not change files with tests unless explicitely instructed: *.test.ts
28
28
 
29
- At the start of every session, read `AGENTS.md` if it exists to load accumulated project learnings.
29
+ At the start of every session, read `.build-kit/AGENTS.md` if it exists to load accumulated project learnings.
30
30
 
31
31
  When starting to work on a slice, invoke the `update-slice-status` skill with `InProgress` status before doing anything else.
32
32
 
@@ -25,7 +25,7 @@ You work within **exactly ONE context at a time** — the one named in `.build-k
25
25
  **Claim conflict**: the board rejects the status update if the slice is already in the target status — this is expected: another agent claimed it first, racing you for the same slice. This is NOT an error. Do not stop, do not retry the same slice. Re-read `index.json` (or re-fetch via `load-slice`), pick the next-highest-priority slice still "Planned", and try claiming that one instead. Repeat until a claim succeeds or no "Planned" slice remains, in which case reply `<promise>NO_TASKS</promise>`.
26
26
  6. Pick the slice definition from `.build-kit/.slices/<contextName>/<folder>/slice.json` as defined in the prd. Never work on more than one slice per iteration.
27
27
  7. A slice can define additional prompts as codegen/backendPrompt. any additional prompts defined in backend are hints for the implementation of the slice and have to be taken into account. If you use the additional prompt, add a line in progress.txt
28
- 7. Determine the slice type and invoke the matching skill as defined in the **Building a Slice** section of CLAUDE.md. Do NOT implement manually.
28
+ 7. Determine the slice type and invoke the matching skill as defined in the **Building a Slice** section of `.build-kit/CLAUDE.md`. Do NOT implement manually.
29
29
  8. Write a short progress one liner after each step to progress.txt
30
30
  9. Analyze and Implement that single slice, make use of the skills in the skills directory, but also your previsously collected
31
31
  knowledge. Make a list TODO list for what needs to be done. Also make sure to adjust the implementation according to the json definition. Carefully inspect events, fields and compare against the implemented slice. JSON is the desired state. ATTENTION: A "planned" task can also be just added specifications. So always look at the slice itself, but also the specifications. If specifications were added in json, which are not on code, you need to add them in code.
@@ -39,7 +39,7 @@ You work within **exactly ONE context at a time** — the one named in `.build-k
39
39
  first )
40
40
  16. Update the PRD to set `status: Done` for the completed story in index.json **and** update the slice status on the eventmodelers board using the `update-slice-status` skill (or MCP if available).
41
41
  17. Append your progress to `progress.txt` after each step in the iteration.
42
- 18. append your new learnings to AGENTS.md in a compressed form, reusable for future iterations. Only add learnings if they are not already there.
42
+ 18. append your new learnings to `.build-kit/AGENTS.md` in a compressed form, reusable for future iterations. Only add learnings if they are not already there.
43
43
  19. Finish the iteration.
44
44
 
45
45
  ## Progress Report Format
@@ -149,4 +149,4 @@ If ALL slices in the current context are Done, reply with:
149
149
 
150
150
  ## When an iteration completes
151
151
 
152
- Use all the key learnings from the progress.txt and update the AGENTS.md file with those learnings.
152
+ Use all the key learnings from the progress.txt and update the `.build-kit/AGENTS.md` file with those learnings.
@@ -26,7 +26,7 @@ Ignore case for files and slices in prompts. "CartItems" slice is the same as "c
26
26
 
27
27
  Do not change files with tests unless explicitely instructed: *.test.ts
28
28
 
29
- At the start of every session, read `AGENTS.md` if it exists to load accumulated project learnings.
29
+ At the start of every session, read `.build-kit/AGENTS.md` if it exists to load accumulated project learnings.
30
30
 
31
31
  When starting to work on a slice, invoke the `update-slice-status` skill with `InProgress` status before doing anything else.
32
32
 
@@ -25,7 +25,7 @@ You work within **exactly ONE context at a time** — the one named in `.build-k
25
25
  **Claim conflict**: the board rejects the status update if the slice is already in the target status — this is expected: another agent claimed it first, racing you for the same slice. This is NOT an error. Do not stop, do not retry the same slice. Re-read `index.json` (or re-fetch via `load-slice`), pick the next-highest-priority slice still "Planned", and try claiming that one instead. Repeat until a claim succeeds or no "Planned" slice remains, in which case reply `<promise>NO_TASKS</promise>`.
26
26
  6. Pick the slice definition from `.build-kit/.slices/<contextName>/<folder>/slice.json` as defined in the prd. Never work on more than one slice per iteration.
27
27
  7. A slice can define additional prompts as codegen/backendPrompt. any additional prompts defined in backend are hints for the implementation of the slice and have to be taken into account. If you use the additional prompt, add a line in progress.txt
28
- 7. Determine the slice type and invoke the matching skill as defined in the **Building a Slice** section of CLAUDE.md. Do NOT implement manually.
28
+ 7. Determine the slice type and invoke the matching skill as defined in the **Building a Slice** section of `.build-kit/CLAUDE.md`. Do NOT implement manually.
29
29
  8. Write a short progress one liner after each step to progress.txt
30
30
  9. Analyze and Implement that single slice, make use of the skills in the skills directory, but also your previsously collected
31
31
  knowledge. Make a list TODO list for what needs to be done. Also make sure to adjust the implementation according to the json definition. Carefully inspect events, fields and compare against the implemented slice. JSON is the desired state. ATTENTION: A "planned" task can also be just added specifications. So always look at the slice itself, but also the specifications. If specifications were added in json, which are not on code, you need to add them in code.
@@ -39,7 +39,7 @@ You work within **exactly ONE context at a time** — the one named in `.build-k
39
39
  first )
40
40
  16. Update the PRD to set `status: Done` for the completed story in index.json **and** update the slice status on the eventmodelers board using the `update-slice-status` skill (or MCP if available).
41
41
  17. Append your progress to `progress.txt` after each step in the iteration.
42
- 18. append your new learnings to AGENTS.md in a compressed form, reusable for future iterations. Only add learnings if they are not already there.
42
+ 18. append your new learnings to `.build-kit/AGENTS.md` in a compressed form, reusable for future iterations. Only add learnings if they are not already there.
43
43
  19. Finish the iteration.
44
44
 
45
45
  ## Progress Report Format
@@ -149,4 +149,4 @@ If ALL slices in the current context are Done, reply with:
149
149
 
150
150
  ## When an iteration completes
151
151
 
152
- Use all the key learnings from the progress.txt and update the AGENTS.md file with those learnings.
152
+ Use all the key learnings from the progress.txt and update the `.build-kit/AGENTS.md` file with those learnings.
@@ -1,54 +0,0 @@
1
- # Agent Instructions & Learnings
2
-
3
- You are an autonomous agent processing prompts for an eventmodelers board.
4
-
5
- ## Mode
6
-
7
- This project runs in one mode only — a warm, direct-dispatch session driven by
8
- `npx @eventmodelers/cli run --modeling`. The first message begins with `MODE=modeling`;
9
- read and follow **`claude-modeling.md`** for every prompt in this session, and don't
10
- re-read it on every turn once you've read it once. There is no file-queue loop and no
11
- `tasks.json` for a modeling-kit install — that's a build-kit concept, for their
12
- independent, self-contained slice-implementation tasks.
13
-
14
- `claude-modeling.md` shares the Skill Selection table, Progress Entry Format, and Learnings below.
15
-
16
- ## Skill Selection
17
-
18
- | Intent | Skill |
19
- |--------|-------|
20
- | Add, rename, or reorder events on a timeline | `/timeline` |
21
- | Place a COMMAND, READMODEL, or EVENT at a position | `/place-element` |
22
- | Generate a full storyboard with multiple screens | `/storyboard` |
23
- | Design or update a single wireframe screen | `/storyboard-screen` |
24
- | Design or update a single real HTML/CSS screen (explicit request only) | `/html-screen` |
25
- | Business analysis, gap spotting, posting questions | `/wdyt` |
26
- | Analyse the existing model structure, slice coverage, element counts | `/analyze-existing-model` |
27
- | Look up any API endpoint or element type | `/learn-eventmodelers-api` |
28
- | Add or rename an attribute across a chain of elements | `/attributes` |
29
- | Add or improve example data on element fields | `/examples` |
30
- | Update the status of a slice (e.g. done, in-progress) | `/update-slice-status` |
31
-
32
- Read `.claude/skills/<skill-name>/SKILL.md` before executing — each skill has required inputs and step-by-step instructions.
33
-
34
- ## Progress Entry Format
35
-
36
- APPEND to `progress.txt` (never replace):
37
- ```
38
- ## [ISO timestamp] — [task/prompt identifier]
39
- Prompts processed: [prompt text(s)]
40
- Outcome: [what changed on the board]
41
- ---
42
- ```
43
-
44
- ---
45
-
46
- ## Learnings
47
-
48
- - `/place-element` requires an existing column — create one via the timeline API if missing.
49
- - `/wdyt` posts QUESTION comments onto nodes — use for analysis only, not modifications.
50
- - The `board_id`, `timeline_id`, and `organization_id` from each prompt provide full context — pass them to skills that need them.
51
- - Node events POST to `/api/boards/:boardId/nodes/events` using `node:created`, `node:changed`, `node:deleted`.
52
- - `/update-slice-status` rejects moving a slice into a status it's already in — this is a concurrency guard so two agents can't both claim the same slice. Treat this as `ALREADY_IN_STATUS`, not a task failure: drop the prompt, move on to the next task, and do not retry the same update.
53
- - macOS/BSD `date` silently ignores GNU-only format specifiers like `%N`/`%3N` (sub-second precision) instead of erroring — it prints the literal characters, producing a malformed timestamp that only fails downstream. Don't shell out to `date` for sub-second precision; use `$(( $(date +%s) * 1000 ))` for whole-second-in-ms, or a runtime call (`Date.now()`, `process.hrtime()`) instead.
54
- - Before retrying a failed shell command a second time, diagnose why it failed (e.g. a GNU/BSD flag mismatch) rather than re-running it unchanged — repeating the same command produces the same failure and just burns retries.