@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 +134 -3
- package/package.json +1 -1
- package/shared/root-claude/CLAUDE.md +13 -0
- package/stacks/axon/templates/.claude/skills/build-automation/SKILL.md +1 -1
- package/stacks/axon/templates/.claude/skills/build-automation-workflow/SKILL.md +1 -1
- package/stacks/axon/templates/.claude/skills/build-state-view/SKILL.md +1 -1
- package/stacks/axon/templates/{root → build-kit}/CLAUDE.md +1 -1
- package/stacks/axon/templates/build-kit/lib/backend-prompt.md +2 -2
- package/stacks/cratis-csharp/templates/.claude/skills/build-automation/SKILL.md +1 -1
- package/stacks/cratis-csharp/templates/.claude/skills/build-state-change/SKILL.md +1 -1
- package/stacks/cratis-csharp/templates/.claude/skills/build-state-view/SKILL.md +1 -1
- package/stacks/modeling-kit/templates/kit/AGENTS.md +12 -0
- package/stacks/modeling-kit/templates/kit/CLAUDE.md +45 -0
- package/stacks/modeling-kit/templates/root/claude-modeling.md +3 -3
- package/stacks/node/templates/{root → build-kit}/CLAUDE.md +1 -1
- package/stacks/node/templates/build-kit/lib/backend-prompt.md +3 -3
- package/stacks/supabase/templates/{root → build-kit}/CLAUDE.md +1 -1
- package/stacks/supabase/templates/build-kit/lib/backend-prompt.md +3 -3
- package/stacks/modeling-kit/templates/root/CLAUDE.md +0 -54
- /package/stacks/cratis-csharp/templates/{root → build-kit}/CLAUDE.md +0 -0
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
|
|
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
|
-
|
|
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
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
File without changes
|