@eventmodelers/cli 1.0.162 → 2.0.1
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 +22 -27
- package/RELEASE_NOTES.md +20 -2
- package/cli.js +461 -225
- package/lib/adapters/spec-kitty-adapter.js +3 -7
- package/lib/global-agent-id.js +45 -0
- package/lib/modeling-local-ai.js +4 -2
- 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 +121 -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 +250 -163
- 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 +182 -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/skills/connect/SKILL.md +1 -5
- package/shared/skills/learn-eventmodelers-api/SKILL.md +13 -0
- package/shared/skills/request-feedback/SKILL.md +1 -2
- package/shared/skills/ui-contract/SKILL.md +5 -3
- package/stacks/axon/templates/build-kit/CLAUDE.md +3 -3
- 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 +18 -41
- package/stacks/blank/templates/build-kit/CLAUDE.md +3 -3
- 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 +19 -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 +3 -3
- 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 +19 -42
- package/stacks/kurrent/templates/build-kit/CLAUDE.md +3 -4
- 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 +18 -41
- package/stacks/modeling-kit/templates/.claude/skills/attributes/SKILL.md +1 -17
- 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/examples/SKILL.md +0 -8
- package/stacks/modeling-kit/templates/.claude/skills/stressor-analysis/SKILL.md +0 -2
- package/stacks/modeling-kit/templates/.claude/skills/walkthrough/SKILL.md +1 -1
- package/stacks/modeling-kit/templates/.claude/skills/wdyt/SKILL.md +1 -1
- package/stacks/modeling-kit/templates/kit/AGENTS.md +0 -1
- package/stacks/modeling-kit/templates/kit/CLAUDE-STANDALONE.md +3 -4
- package/stacks/modeling-kit/templates/kit/CLAUDE.md +11 -72
- 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 +3 -3
- 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 +3 -4
- 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 +18 -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 +3 -3
- package/stacks/react/templates/build-kit/lib/AGENT.md +6 -7
- package/stacks/react/templates/build-kit/lib/backend-prompt.md +20 -37
- package/stacks/react/templates/build-kit/lib/prompt.md +19 -42
- package/stacks/supabase/templates/build-kit/CLAUDE.md +3 -3
- 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 +2 -2
- package/stacks/supabase-react/templates/.claude/skills/build-state-view/SKILL.md +2 -2
- package/stacks/supabase-react/templates/build-kit/CLAUDE.md +3 -3
- package/stacks/supabase-react/templates/build-kit/lib/AGENT.md +6 -7
- package/stacks/supabase-react/templates/build-kit/lib/backend-prompt.md +20 -37
- package/stacks/supabase-react/templates/build-kit/lib/prompt.md +19 -42
- package/stacks/umadb/templates/build-kit/CLAUDE.md +3 -3
- 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 +18 -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
|
@@ -17,20 +17,19 @@ You work within **exactly ONE context at a time** — the one named in `.build-k
|
|
|
17
17
|
|
|
18
18
|
0. Do not read the entire code base. Focus on the tasks in this description.
|
|
19
19
|
1. Read `.build-kit/.slices/current_context.json` to find the active context name, then read `.build-kit/.slices/<contextName>/index.json`. Every item in status "planned" is a task.
|
|
20
|
-
2. Read
|
|
20
|
+
2. Read `.build-kit/AGENTS.md` **if it exists** — the project's accumulated learnings, generated from what earlier builds recorded. If the slice's `slice.json` has a `lastAttempt`, an earlier attempt at it failed: read its `reason`, `lastReply`, `branch` and `changed`, and do not repeat what failed.
|
|
21
21
|
3. Make sure you are on the right branch "feature/<slicename>", if unsure, start from main.
|
|
22
|
-
5.
|
|
23
|
-
**IMPORTANT: Only work on
|
|
22
|
+
5. Your slice is the one the task request names (the run loop picked the highest priority slice with status "Planned"); it becomes your PRD. The run loop has already claimed it — its status is "InProgress" in index.json and on the board. Build that slice and do not call `update-slice-status`: the run loop owns the slice's status on the board.
|
|
23
|
+
**IMPORTANT: Only work on the slice named in the task request. Never switch to another slice, whatever its status. If the task request names no slice and no slice has status "Planned" in the current context, reply with:**
|
|
24
24
|
<promise>NO_TASKS</promise> and stop immediately. Do not work on other slices and do not switch to another context.
|
|
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
25
|
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
|
-
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.
|
|
26
|
+
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.
|
|
28
27
|
7. Define the slice type and load the matching skill:
|
|
29
28
|
- Write slice (has commands, no processors) → `build-state-change`
|
|
30
29
|
- Read slice (has readModel / information flow) → `build-state-view`
|
|
31
30
|
- Translation slice (`sliceType === "TRANSLATION"`) → read `description` and `notes` from slice.json for hints; default to `build-automation` if nothing else is specified
|
|
32
31
|
- Automation slice (processors-array is not empty) → `build-automation`
|
|
33
|
-
8.
|
|
32
|
+
8. Record each learning the moment you have it (see **Recording Learnings**), not at the end.
|
|
34
33
|
9. Analyze and Implement that single slice, make use of the skills in the skills directory, but also your previsously collected
|
|
35
34
|
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.
|
|
36
35
|
10. The slice in the json is always true, the code follows what is defined in the json
|
|
@@ -43,48 +42,27 @@ You work within **exactly ONE context at a time** — the one named in `.build-k
|
|
|
43
42
|
If the tests for the slice are not yet named predictably, run `./mvnw test -q` and check for failures.
|
|
44
43
|
15. If checks pass, commit ALL changes with message: `feat: [Slice Name]` and merge back to main as FF merge ( update
|
|
45
44
|
first )
|
|
46
|
-
16.
|
|
47
|
-
17.
|
|
48
|
-
18.
|
|
45
|
+
16. Record the outcome with `npx @eventmodelers/cli slice-status Done` — not by editing index.json, and do not call `update-slice-status`: the run loop pushes the status to the board when your turn ends. For STATE_VIEW/STATE_CHANGE slices when `handover` is enabled the status to record is `Handover`, not `Done` — see the `ui-contract` skill, Step 4. A slice you could not finish needs no status: leave it as it is and the run loop discards the attempt.
|
|
46
|
+
17. Record any reusable learning you have not recorded yet (see **Recording Learnings**).
|
|
47
|
+
18. If an entry in `.build-kit/AGENTS.md` turned out wrong or obsolete, retract it (see **Recording Learnings**).
|
|
49
48
|
19. Finish the iteration.
|
|
50
49
|
|
|
51
50
|
## Escalating Ambiguity
|
|
52
51
|
|
|
53
|
-
**Default: make a reasonable assumption and build the slice.** If a detail is unclear or missing (an example value, a field type, a status mapping, a referenced event that isn't modeled yet, ...), pick the most sensible interpretation from `slice.json`, its specifications and the surrounding model, build it, and record each assumption in one line
|
|
52
|
+
**Default: make a reasonable assumption and build the slice.** If a detail is unclear or missing (an example value, a field type, a status mapping, a referenced event that isn't modeled yet, ...), pick the most sensible interpretation from `slice.json`, its specifications and the surrounding model, build it, and record each assumption in one line as a code comment. Ambiguity alone is never a reason to stop. **Only if the slice literally cannot be built** — nothing runnable can be produced even with sensible assumptions — invoke `/request-feedback` with the specific question; it posts the question as a comment on the slice and marks it `Blocked`. That must be the absolute exception; a `Blocked` slice should mean "impossible without a human", never "the agent preferred to ask".
|
|
54
53
|
|
|
55
|
-
##
|
|
54
|
+
## Recording Learnings
|
|
56
55
|
|
|
57
|
-
|
|
56
|
+
`.build-kit/AGENTS.md` is generated from the learnings recorded so far — read it at the start of every session, never edit it by hand. Record a learning the moment you have it:
|
|
58
57
|
|
|
59
58
|
```
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
- What was implemented
|
|
63
|
-
- Files changed
|
|
64
|
-
- **Learnings for future iterations:**
|
|
65
|
-
- Patterns discovered (e.g., "this codebase uses X for Y")
|
|
66
|
-
- Gotchas encountered (e.g., "don't forget to update Z when changing W")
|
|
67
|
-
- Useful context (e.g., "the evaluation panel is in component X")
|
|
68
|
-
---
|
|
59
|
+
npx @eventmodelers/cli learn "<one terse line>" --topic "<topic>"
|
|
69
60
|
```
|
|
70
61
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
If you discover a **reusable pattern** that future iterations should know, add it to the `## Codebase Patterns` section
|
|
77
|
-
at the TOP of progress.txt (create it if it doesn't exist). This section should consolidate the most important
|
|
78
|
-
learnings:
|
|
79
|
-
|
|
80
|
-
```
|
|
81
|
-
## Codebase Patterns
|
|
82
|
-
- Example: Use event sourcing aggregate patterns for all state changes
|
|
83
|
-
- Example: Always use @CommandHandler on the aggregate for write slices
|
|
84
|
-
- Example: Export query result types from the slice package
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
Only add patterns that are **general and reusable**, not story-specific details.
|
|
62
|
+
- Only what is genuinely reusable: codebase patterns, gotchas, commands that work or don't, conventions — and, after a failed approach, what was tried and why it failed. Not slice-specific details, and nothing the code or git log already says.
|
|
63
|
+
- One learning per call, one line each. A learning that is already in `.build-kit/AGENTS.md` is skipped for you.
|
|
64
|
+
- `--scope system` for what is true of the modeled domain (a business rule, a naming convention of the model); `repo` (the default) for the codebase and its tooling. `--tag <tag>` labels it (repeatable).
|
|
65
|
+
- One in `.build-kit/AGENTS.md` that turned out wrong or obsolete: `npx @eventmodelers/cli learnings --ids` lists each with its id, `npx @eventmodelers/cli learn --retract <id>` removes it.
|
|
88
66
|
|
|
89
67
|
## Update AGENTS.md Files
|
|
90
68
|
|
|
@@ -110,7 +88,7 @@ Before committing, check if any edited files have learnings worth preserving in
|
|
|
110
88
|
- Slice specific implementation details
|
|
111
89
|
- Story-specific implementation details
|
|
112
90
|
- Temporary debugging notes
|
|
113
|
-
- Information already in
|
|
91
|
+
- Information already recorded as a learning in `.build-kit/AGENTS.md`
|
|
114
92
|
- Task specific learnings
|
|
115
93
|
|
|
116
94
|
Only update AGENTS.md if you have **genuinely reusable knowledge** that would help future work
|
|
@@ -154,9 +132,9 @@ If ALL slices in the current context are Done, reply with:
|
|
|
154
132
|
- If no `.eventmodelers/config.json` exists anywhere (project root or an ancestor directory, or `~/.eventmodelers/config.json` — the one inside `.build-kit/` is only an optional override, so its absence means nothing), skip all platform communication (MCP calls, `update-slice-status`, board sync) and continue working locally.
|
|
155
133
|
- Work on ONE slice per iteration
|
|
156
134
|
- Commit frequently
|
|
157
|
-
-
|
|
158
|
-
- Read
|
|
135
|
+
- Record learnings as you go with `learn`
|
|
136
|
+
- Read `.build-kit/AGENTS.md` before starting
|
|
159
137
|
|
|
160
138
|
## When an iteration completes
|
|
161
139
|
|
|
162
|
-
|
|
140
|
+
Make sure every reusable learning is recorded with `learn`; `.build-kit/AGENTS.md` is generated from them — never edit it by hand.
|
|
@@ -4,17 +4,11 @@ You are an autonomous agent reacting to slice status change events on an Eventmo
|
|
|
4
4
|
|
|
5
5
|
## Your Loop
|
|
6
6
|
|
|
7
|
-
1. Read `AGENT.md` to load accumulated
|
|
8
|
-
2.
|
|
9
|
-
3.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
4. Pick the **oldest task** (earliest `createdAt`).
|
|
13
|
-
5. Execute the task — see the Execution section below.
|
|
14
|
-
6. After execution, remove that task from the array and write `.build-kit/tasks.json` back.
|
|
15
|
-
7. Append a progress entry to `progress.txt` (create if missing).
|
|
16
|
-
8. Update `AGENT.md` with any new reusable learnings discovered this iteration.
|
|
17
|
-
9. Reply normally so the next iteration can pick up the next task.
|
|
7
|
+
1. Read `AGENT.md` and, if it exists, `.build-kit/AGENTS.md` to load accumulated knowledge before doing anything else.
|
|
8
|
+
2. The task request at the end of this prompt names your task: its id and the slice change that queued it (`sliceId`, `sliceTitle`, `sliceStatus`, …). It is the oldest one waiting — the run loop picked it for you.
|
|
9
|
+
3. Execute the task — see the Execution section below.
|
|
10
|
+
4. Record any reusable learning with `npx @eventmodelers/cli learn "<one terse line>" --topic <topic>` (see **Recording Learnings**).
|
|
11
|
+
5. Reply normally. The run loop completes the task when your turn ends and hands you the next one in a fresh turn — you never read or write a queue file.
|
|
18
12
|
|
|
19
13
|
## Execution
|
|
20
14
|
|
|
@@ -48,11 +42,11 @@ Inspect the `sliceStatus` in the payload:
|
|
|
48
42
|
|
|
49
43
|
This is the build trigger. Setting `InProgress` and building are one atomic step:
|
|
50
44
|
|
|
51
|
-
**Default: make a reasonable assumption and build the slice.** If a detail is unclear or missing (an example value, a field type, a status mapping, a referenced event that isn't modeled yet, ...), pick the most sensible interpretation from `slice.json`, its specifications and the surrounding model, build it, and record each assumption in one line
|
|
45
|
+
**Default: make a reasonable assumption and build the slice.** If a detail is unclear or missing (an example value, a field type, a status mapping, a referenced event that isn't modeled yet, ...), pick the most sensible interpretation from `slice.json`, its specifications and the surrounding model, build it, and record each assumption in one line as a code comment. Ambiguity alone is never a reason to stop. **Only if the slice literally cannot be built** — nothing runnable can be produced even with sensible assumptions — invoke `/request-feedback` with the specific question; it posts the question as a comment on the slice and marks it `Blocked`. That must be the absolute exception; a `Blocked` slice should mean "impossible without a human", never "the agent preferred to ask".
|
|
52
46
|
|
|
53
47
|
1. Immediately call `/update-slice-status` to set the slice to `InProgress` on the board.
|
|
54
48
|
|
|
55
|
-
**Claim conflict**: if this call reports the slice is already in `InProgress` (or any status other than `Planned`), another agent already claimed it first — this is expected, not an error.
|
|
49
|
+
**Claim conflict**: if this call reports the slice is already in `InProgress` (or any status other than `Planned`), another agent already claimed it first — this is expected, not an error. Say so in your reply, drop this task without building, and continue the loop (the next task will naturally cover the next slice). Do not retry.
|
|
56
50
|
|
|
57
51
|
2. Run `/load-slice sliceId=<payload.sliceId>` to fetch the full slice, then read the slice definition from `.build-kit/.slices/<contextSlug>/<sliceFolder>/slice.json`. The runner keeps a `slice.json` fresh from a summary endpoint, so a file holding only `id`, `title`, `status` and `sliceType` is that stub, not an empty slice — never conclude a slice has no elements from it. Only if the full fetch itself returns no commands/events/read models/fields is the slice actually empty.
|
|
58
52
|
|
|
@@ -78,48 +72,31 @@ This is the build trigger. Setting `InProgress` and building are one atomic step
|
|
|
78
72
|
Another agent is already building this slice. Log it and skip — do not build.
|
|
79
73
|
|
|
80
74
|
#### `Done`
|
|
81
|
-
Summarize what was completed
|
|
75
|
+
Summarize what was completed in your reply.
|
|
82
76
|
|
|
83
77
|
#### `Blocked`
|
|
84
|
-
|
|
78
|
+
State the blocker in your reply.
|
|
85
79
|
|
|
86
80
|
#### `Review`
|
|
87
|
-
Fetch slice details and prepare a review summary in
|
|
81
|
+
Fetch slice details and prepare a review summary in your reply.
|
|
88
82
|
|
|
89
83
|
#### Any other status (`Created`, etc.)
|
|
90
|
-
Load the slice and
|
|
84
|
+
Load the slice and note the state transition in your reply. No build action.
|
|
91
85
|
|
|
92
86
|
Use the skills available in `.claude/skills/` to interact with the board.
|
|
93
87
|
|
|
94
|
-
##
|
|
88
|
+
## Recording Learnings
|
|
95
89
|
|
|
96
|
-
|
|
90
|
+
`.build-kit/AGENTS.md` is generated from the learnings recorded so far — read it at the start of every session, never edit it by hand. Record a learning the moment you have it:
|
|
97
91
|
|
|
98
|
-
## Progress Report Format
|
|
99
|
-
|
|
100
|
-
APPEND to `progress.txt` (never replace):
|
|
101
92
|
```
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
Slice: [sliceTitle] ([sliceId])
|
|
105
|
-
Status change: [sliceStatus]
|
|
106
|
-
|
|
107
|
-
Action taken:
|
|
108
|
-
- [what was done in response to the slice change]
|
|
109
|
-
|
|
110
|
-
Learnings:
|
|
111
|
-
- [any patterns, gotchas, or reusable knowledge discovered]
|
|
112
|
-
---
|
|
93
|
+
npx @eventmodelers/cli learn "<one terse line>" --topic "<topic>"
|
|
113
94
|
```
|
|
114
95
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
<
|
|
119
|
-
|
|
120
|
-
## Updating AGENT.md
|
|
121
|
-
|
|
122
|
-
After completing a task, add any **reusable** learnings to `AGENT.md` — patterns, gotchas, API quirks, or skill behaviour that future iterations should know. Only add things that are general and applicable beyond this single task. Do not duplicate what is already there.
|
|
96
|
+
- Only what is genuinely reusable: codebase patterns, gotchas, commands that work or don't, conventions — and, after a failed approach, what was tried and why it failed. Not slice-specific details, and nothing the code or git log already says.
|
|
97
|
+
- One learning per call, one line each. A learning that is already in `.build-kit/AGENTS.md` is skipped for you.
|
|
98
|
+
- `--scope system` for what is true of the modeled domain (a business rule, a naming convention of the model); `repo` (the default) for the codebase and its tooling. `--tag <tag>` labels it (repeatable).
|
|
99
|
+
- One in `.build-kit/AGENTS.md` that turned out wrong or obsolete: `npx @eventmodelers/cli learnings --ids` lists each with its id, `npx @eventmodelers/cli learn --retract <id>` removes it.
|
|
123
100
|
|
|
124
101
|
## Important
|
|
125
102
|
|
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: bridge-spec-kitty-specify
|
|
3
|
-
description: "Adapter: generate a Spec Kitty mission spec.md (and auto-evaluate its quality checklist) from an Eventmodelers board's exported event model, instead of running the /spec-kitty.specify interview. Use when the user says \"use the event model as the spec\", \"sync the board to spec-kitty\", \"generate the spec from the event model\", or when a .slices/ export exists and a Spec Kitty mission needs to start or refresh from it."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# bridge-spec-kitty-specify
|
|
7
|
-
|
|
8
|
-
Replaces the human interview in `/spec-kitty.specify` with a direct read of an
|
|
9
|
-
Eventmodelers board export. The event model is the source of truth; `spec.md`
|
|
10
|
-
becomes a **generated, read-only artifact** derived from it. Everything
|
|
11
|
-
downstream of specify (`/spec-kitty.plan`, `/spec-kitty.tasks`,
|
|
12
|
-
implement/review/merge) is untouched — this skill only produces the two
|
|
13
|
-
artifacts that phase gate expects: `spec.md` and `checklists/requirements.md`.
|
|
14
|
-
|
|
15
|
-
Do not use this to hand-author or hand-edit `spec.md` — if the event model is
|
|
16
|
-
wrong, fix it on the board and re-run this skill. A `spec.md` produced here
|
|
17
|
-
that gets manually edited afterward will be silently overwritten on the next
|
|
18
|
-
sync; there is no merge/diff in this version (see Limitations).
|
|
19
|
-
|
|
20
|
-
## Inputs
|
|
21
|
-
|
|
22
|
-
The Eventmodelers `listen` server (`npx @eventmodelers/cli listen`) writes the
|
|
23
|
-
board export locally. Read it directly — do not call the board API:
|
|
24
|
-
|
|
25
|
-
- `.slices/current_context.json` → `{ "name": "<context>" }` — which context
|
|
26
|
-
to ingest if the user didn't name one.
|
|
27
|
-
- `.slices/<context>/index.json` → `{ "slices": [{ id, slice, index, context,
|
|
28
|
-
folder, status, group }] }` — the ordered slice list.
|
|
29
|
-
- `.slices/<context>/context.json` → context-level name/package info.
|
|
30
|
-
- `.slices/<context>/<folder>/slice.json` → full slice detail per the
|
|
31
|
-
[event-modeling-spec](https://github.com/dilgerma/event-modeling-spec)
|
|
32
|
-
contract: `commands[]`, `events[]`, `readModels[]` (projections/queries),
|
|
33
|
-
`screens[]`, `automations[]`/`processors[]`, `specifications[]` (given/when/
|
|
34
|
-
then), plus free-text `description`/`notes`.
|
|
35
|
-
|
|
36
|
-
If `.slices/` doesn't exist yet, stop and tell the user to run
|
|
37
|
-
`npx @eventmodelers/cli listen` (or `init-modeling` first if the kit isn't
|
|
38
|
-
installed) and push the board export before retrying.
|
|
39
|
-
|
|
40
|
-
## Flow
|
|
41
|
-
|
|
42
|
-
1. **Resolve the mission.** If an existing `kitty-specs/<slug>/meta.json`
|
|
43
|
-
already points at this context (check `purpose_tldr`/a stored context
|
|
44
|
-
reference), re-sync into it. Otherwise create a new mission dir the same
|
|
45
|
-
way `/spec-kitty.specify` does: kebab-case name + 8-char ULID suffix,
|
|
46
|
-
`mission_type: software-dev` (this adapter does not introduce a new
|
|
47
|
-
mission type — see project memory on why). Write `meta.json` matching the
|
|
48
|
-
shape in an existing mission (`mission_id`, `mission_slug`, `purpose_tldr`,
|
|
49
|
-
`purpose_context`, `target_branch`, etc.).
|
|
50
|
-
2. **Load every slice** referenced in `index.json` by reading each
|
|
51
|
-
`<folder>/slice.json`. Do not skip slices with empty `specifications` —
|
|
52
|
-
surface them as gaps in the checklist instead (step 4).
|
|
53
|
-
3. **Compose `spec.md`** using the standard Spec Kitty template sections,
|
|
54
|
-
sourced only from what the model actually states — never invent detail
|
|
55
|
-
the board doesn't have:
|
|
56
|
-
- **Purpose** ← `context.json` name/description, or ask the user for a
|
|
57
|
-
one-paragraph purpose if the board has none.
|
|
58
|
-
- **Primary User Story** ← walk the slices in `index.json` order (this is
|
|
59
|
-
already the chronological/timeline order from the board) and narrate
|
|
60
|
-
the SCREEN → COMMAND → EVENT → READMODEL flow across them.
|
|
61
|
-
- **Acceptance Scenarios** ← one bullet per `specifications[]` entry,
|
|
62
|
-
copied straight from its given/when/then — do not paraphrase away
|
|
63
|
-
precision the model already captured.
|
|
64
|
-
- **Edge Cases** ← `specifications[]` entries that describe rejection/
|
|
65
|
-
negative/boundary behavior (reject, invalid, already-exists, etc.).
|
|
66
|
-
- **Domain Language** ← distinct nouns from event/command/read-model field
|
|
67
|
-
names and titles, deduped.
|
|
68
|
-
- **Functional Requirements (FR-###)** ← one row per COMMAND (state-change
|
|
69
|
-
slice) and per AUTOMATION slice; wording from the command/automation
|
|
70
|
-
name + `description`.
|
|
71
|
-
- **Non-Functional Requirements / Constraints** ← only from explicit
|
|
72
|
-
`notes`/`description` content tagged as timing/authorization/volume
|
|
73
|
-
constraints. If the model states none, leave the table empty — do not
|
|
74
|
-
fabricate NFRs to fill it.
|
|
75
|
-
- **Key Entities** ← distinct read-model/event payload shapes.
|
|
76
|
-
- **Interfaces to Other Teams** ← any `TRANSLATION`-type slice or external
|
|
77
|
-
system mentioned in a slice's `description`.
|
|
78
|
-
4. **Evaluate `checklists/requirements.md`** against the ingested model
|
|
79
|
-
instead of a human review pass. Check an item only if the model
|
|
80
|
-
demonstrably satisfies it:
|
|
81
|
-
- "No [NEEDS CLARIFICATION] markers remain" → fails if any slice has an
|
|
82
|
-
empty `specifications[]` or a `description` containing `TODO`/`TBD`.
|
|
83
|
-
- "Requirements are testable and unambiguous" → fails if an FR/NFR row has
|
|
84
|
-
no backing `specifications[]` entry.
|
|
85
|
-
- "Non-functional requirements include measurable thresholds" → fails
|
|
86
|
-
(leave unchecked, don't skip the row) if the NFR table is empty but the
|
|
87
|
-
model contains AUTOMATION slices implying a timing constraint the board
|
|
88
|
-
never made explicit.
|
|
89
|
-
- Leave any check unchecked with a `## Notes` explanation when the event
|
|
90
|
-
model genuinely doesn't provide enough to verify it — this checklist
|
|
91
|
-
gates `/spec-kitty.plan`, so a false pass defeats the point of the gate.
|
|
92
|
-
5. **Hand off.** Once `spec.md` + `checklists/requirements.md` are written,
|
|
93
|
-
tell the user the mission is ready for `/spec-kitty.plan` as normal — do
|
|
94
|
-
not run plan/tasks yourself from this skill.
|
|
95
|
-
|
|
96
|
-
## Re-sync behavior
|
|
97
|
-
|
|
98
|
-
Re-running this skill against the same mission regenerates `spec.md` and
|
|
99
|
-
`checklists/requirements.md` wholesale from the current `.slices/` state.
|
|
100
|
-
There is no field-level diff against the previous generation — if the spec
|
|
101
|
-
needs to reflect board changes, re-run this skill rather than hand-patching
|
|
102
|
-
`spec.md`.
|
|
103
|
-
|
|
104
|
-
## Guardrail
|
|
105
|
-
|
|
106
|
-
If a required section can't be populated from the event model (e.g. no
|
|
107
|
-
Purpose anywhere on the board), ask the user rather than inventing one — an
|
|
108
|
-
invented Purpose defeats the reason this adapter exists (the event model,
|
|
109
|
-
not the LLM, is the source of truth for product intent).
|
|
110
|
-
|
|
111
|
-
## Limitations (by design, v1)
|
|
112
|
-
|
|
113
|
-
- Does not itself generate `tasks/WP##-*.md` from slices — see the companion
|
|
114
|
-
`bridge-spec-kitty-tasks` skill, which enforces a 1:1
|
|
115
|
-
slice-to-WP mapping when `wps.yaml` is written during
|
|
116
|
-
`/spec-kitty.tasks-outline`.
|
|
117
|
-
- Does not introduce a new Spec Kitty mission type. Spec Kitty 3.2.5's
|
|
118
|
-
built-in mission types are loaded from a flat directory inside the
|
|
119
|
-
installed package (`doctrine/missions/mission_types/*.yaml`) via
|
|
120
|
-
`MissionTypeRepository.default()`, and org-pack extension for the
|
|
121
|
-
`mission_types` kind is unwired in this version (fragments only add
|
|
122
|
-
governance-graph metadata, not an executable type). A real native mission
|
|
123
|
-
type would require patching the installed `spec-kitty-cli` package itself.
|
|
124
|
-
This adapter avoids that entirely — it stays inside `mission_type:
|
|
125
|
-
software-dev` and only replaces the specify phase's *inputs*.
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: bridge-spec-kitty-tasks
|
|
3
|
-
description: "Adapter: enforce a 1:1 mapping between Eventmodelers board slices and Spec Kitty work packages when writing wps.yaml. Use when the user says \"one slice should become one task/WP\", \"generate tasks from the event model\", or right after bridge-spec-kitty-specify, in place of freeform subtask-grouping judgment in /spec-kitty.tasks-outline."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# bridge-spec-kitty-tasks
|
|
7
|
-
|
|
8
|
-
Companion to `bridge-spec-kitty-specify`. That skill turns the event model into
|
|
9
|
-
`spec.md`; this one enforces that each **slice** on the board becomes exactly
|
|
10
|
-
**one work package** — never split across WPs, never merged with another
|
|
11
|
-
slice — when Spec Kitty's task-planning pipeline builds `wps.yaml`.
|
|
12
|
-
|
|
13
|
-
This replaces only step 3–6 of `/spec-kitty.tasks-outline` (deriving
|
|
14
|
-
subtasks and rolling them into WPs). `/spec-kitty.tasks-packages` and
|
|
15
|
-
`/spec-kitty.tasks-finalize` run completely unmodified afterward — they only
|
|
16
|
-
ever consume `wps.yaml`, and don't care where its groupings came from.
|
|
17
|
-
|
|
18
|
-
## Why a hard 1:1 boundary
|
|
19
|
-
|
|
20
|
-
Spec Kitty's default `tasks-outline` groups subtasks into WPs by
|
|
21
|
-
judgment (target 3–7 subtasks, merge small ones, split large ones). That's
|
|
22
|
-
the right default when subtask boundaries come from an LLM reading prose. It
|
|
23
|
-
is the *wrong* default here: the event model already drew the real
|
|
24
|
-
boundaries (each SLICE_BORDER is a reviewable, independently buildable unit
|
|
25
|
-
the board's `Planned → InProgress → Done` slice lifecycle already governs).
|
|
26
|
-
Re-grouping at the WP layer would create a second, competing notion of "unit
|
|
27
|
-
of work" that drifts from the board over time. So this skill trades away
|
|
28
|
-
`tasks-outline`'s sizing flexibility on purpose: WP boundary = slice
|
|
29
|
-
boundary, full stop.
|
|
30
|
-
|
|
31
|
-
## Inputs
|
|
32
|
-
|
|
33
|
-
Same event-model export as `bridge-spec-kitty-specify`:
|
|
34
|
-
`.slices/<context>/index.json` (slice list, board/timeline order) and each
|
|
35
|
-
`.slices/<context>/<folder>/slice.json` (commands, events, readModels,
|
|
36
|
-
automations, `specifications`). Also read, from `feature_dir`:
|
|
37
|
-
`spec.md` (for FR/NFR ids — already generated by `bridge-spec-kitty-specify`) and
|
|
38
|
-
`plan.md` (for the tech-stack/file-layout context needed to fill
|
|
39
|
-
`owned_files`, since the event model doesn't know the codebase's directory
|
|
40
|
-
structure).
|
|
41
|
-
|
|
42
|
-
## Flow
|
|
43
|
-
|
|
44
|
-
1. **One WP per slice, in board order.** Assign `WP01`, `WP02`, ... following
|
|
45
|
-
`index.json`'s order (already the board's chronological/timeline order).
|
|
46
|
-
Do not reorder for "phase grouping" the way default `tasks-outline` does —
|
|
47
|
-
the board order already encodes the intended build sequence.
|
|
48
|
-
2. **Subtasks come from inside the slice, not across slices.** For each
|
|
49
|
-
slice, break its own commands/read-models/screens/automations into T-ids
|
|
50
|
-
(one per command handler, one per read-model endpoint, one per
|
|
51
|
-
screen/automation, one for its tests) — all nested under that slice's one
|
|
52
|
-
WP. Every subtask must trace to exactly one slice; never let a subtask
|
|
53
|
-
span two slices.
|
|
54
|
-
3. **Dependencies from event flow, not guesswork.** WP *B* depends on WP *A*
|
|
55
|
-
iff slice B's commands/queries/automations consume an event that slice
|
|
56
|
-
A's commands/automations produce. Derive this by diffing each slice's
|
|
57
|
-
emitted event names against every other slice's consumed event names —
|
|
58
|
-
this is mechanical, not judgment-based, so don't also apply
|
|
59
|
-
`tasks-outline`'s "Phase 2 typically depends on Phase 1" heuristic on top
|
|
60
|
-
of it.
|
|
61
|
-
4. **`requirement_refs` from the spec's own FR/NFR table.** Match each
|
|
62
|
-
slice's command/read-model/automation names against `spec.md`'s FR/NFR
|
|
63
|
-
rows (written by `bridge-spec-kitty-specify` from these same slices) and cite
|
|
64
|
-
whichever ids trace to this slice. A slice with no matching row means
|
|
65
|
-
`bridge-spec-kitty-specify` needs a re-run, not a fabricated ref here.
|
|
66
|
-
5. **Write `wps.yaml`** using the exact schema `/spec-kitty.tasks-outline`
|
|
67
|
-
expects (`id`, `title`, `dependencies`, `owned_files`, `requirement_refs`,
|
|
68
|
-
`plan_concern_refs` or `cross_cutting: true`, `subtasks`, `prompt_file:
|
|
69
|
-
null`) — so `tasks-packages`/`finalize-tasks` need no awareness that this
|
|
70
|
-
skill (rather than default `tasks-outline`) produced it.
|
|
71
|
-
6. **Hand off.** Tell the user to continue with `/spec-kitty.tasks-packages`
|
|
72
|
-
then `/spec-kitty.tasks-finalize` (or `spec-kitty next`) exactly as normal.
|
|
73
|
-
|
|
74
|
-
## Guardrail: don't fix boundary problems here
|
|
75
|
-
|
|
76
|
-
If a slice's own scope would blow past Spec Kitty's WP sizing ceiling (>10
|
|
77
|
-
subtasks / >700 lines), **do not silently split it into two WPs** — that
|
|
78
|
-
breaks the 1:1 invariant this skill exists to enforce, and produces the
|
|
79
|
-
exact spec/code drift it's meant to prevent. Instead, flag it to the user:
|
|
80
|
-
the slice is too coarse on the board itself, so split the SLICE_BORDER
|
|
81
|
-
there and re-run both `bridge-spec-kitty-specify` and this skill. The event model
|
|
82
|
-
stays the single place slice boundaries get decided.
|
|
83
|
-
|
|
84
|
-
The same holds in the other direction: never merge two small slices into
|
|
85
|
-
one WP for tidiness, even if `tasks-outline`'s default guidance would.
|
|
86
|
-
|
|
87
|
-
## Limitations (v1)
|
|
88
|
-
|
|
89
|
-
- `owned_files`/file-layout ownership still comes from `plan.md`, which is
|
|
90
|
-
still produced by the normal, LLM-authored `/spec-kitty.plan` — the event
|
|
91
|
-
model has no notion of source-file structure, so this isn't something to
|
|
92
|
-
push onto it.
|
|
93
|
-
- Re-running this skill after the board changes regenerates `wps.yaml`
|
|
94
|
-
wholesale from the current slice set, same as `bridge-spec-kitty-specify`'s
|
|
95
|
-
re-sync behavior — no field-level diff against a prior run.
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Runs the AI agent with the given prompt in the project directory.
|
|
3
|
-
# Called by ralph.sh with cwd already set to the project root.
|
|
4
|
-
# Usage: ./agent.sh "<prompt>"
|
|
5
|
-
|
|
6
|
-
set -euo pipefail
|
|
7
|
-
|
|
8
|
-
PROMPT="${1:-}"
|
|
9
|
-
if [[ -z "$PROMPT" ]]; then
|
|
10
|
-
echo "ERROR: No prompt provided"
|
|
11
|
-
exit 1
|
|
12
|
-
fi
|
|
13
|
-
|
|
14
|
-
claude --dangerously-skip-permissions -p "$PROMPT"
|
|
15
|
-
|
|
16
|
-
# --- To use a local Ollama model instead, comment out the line above
|
|
17
|
-
# and uncomment the block below. Run `ollama serve` first.
|
|
18
|
-
#
|
|
19
|
-
# MODEL="${OLLAMA_MODEL:-qwen3.5:9b}"
|
|
20
|
-
# node "$(dirname "$0")/ollama-agent.js" "$MODEL"
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Ralph agent loop — two independent loops, each triggered by their own condition
|
|
3
|
-
#
|
|
4
|
-
# onTask: tasks.json has entries → load slice from board, update .build-kit/.slices/
|
|
5
|
-
# onPlannedSlice: .build-kit/.slices/ has a "Planned" slice → build it
|
|
6
|
-
#
|
|
7
|
-
# The loops are NOT causally linked — either can trigger on its own.
|
|
8
|
-
#
|
|
9
|
-
# Usage: ./ralph.sh [iterations] [project_dir]
|
|
10
|
-
# iterations — number of loop cycles to run; 0 or omitted means run forever
|
|
11
|
-
# project_dir — path to the project root; defaults to the parent of .build-kit
|
|
12
|
-
|
|
13
|
-
set -euo pipefail
|
|
14
|
-
|
|
15
|
-
KIT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
16
|
-
ITERATIONS="${1:-0}"
|
|
17
|
-
PROJECT_DIR="${2:-"$KIT_DIR/.."}"
|
|
18
|
-
TASKS_FILE="$KIT_DIR/tasks.json"
|
|
19
|
-
PROMPT_FILE="$KIT_DIR/lib/prompt.md"
|
|
20
|
-
BACKEND_PROMPT_FILE="$KIT_DIR/lib/backend-prompt.md"
|
|
21
|
-
AGENT_SCRIPT="$KIT_DIR/lib/agent.sh"
|
|
22
|
-
|
|
23
|
-
HAS_CREDENTIALS=true
|
|
24
|
-
if [[ "${RALPH_LOCAL:-}" == "1" ]]; then
|
|
25
|
-
echo "[ralph] --local — platform sync disabled." >&2
|
|
26
|
-
HAS_CREDENTIALS=false
|
|
27
|
-
elif [[ ! -f "$KIT_DIR/.eventmodelers/config.json" ]]; then
|
|
28
|
-
echo "[ralph] Note: no .eventmodelers/config.json found — platform sync disabled." >&2
|
|
29
|
-
echo " To enable board sync, follow: https://app.eventmodelers.ai/documentation#build" >&2
|
|
30
|
-
echo " Code generation from local slice definitions will still run." >&2
|
|
31
|
-
HAS_CREDENTIALS=false
|
|
32
|
-
fi
|
|
33
|
-
|
|
34
|
-
echo "Ralph — kit: $KIT_DIR project: $PROJECT_DIR"
|
|
35
|
-
|
|
36
|
-
# Returns 0 if tasks.json has at least one task
|
|
37
|
-
has_pending_tasks() {
|
|
38
|
-
[[ -f "$TASKS_FILE" ]] || return 1
|
|
39
|
-
local content
|
|
40
|
-
content=$(cat "$TASKS_FILE")
|
|
41
|
-
[[ "$content" != "[]" && -n "$content" ]]
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
# Status this loop picks work up from — `run --status-trigger <status>` (RALPH_STATUS_TRIGGER), default Planned
|
|
45
|
-
PICKUP_STATUS="${RALPH_STATUS_TRIGGER:-Planned}"
|
|
46
|
-
|
|
47
|
-
# Returns 0 if any JSON under .build-kit/.slices/ contains a slice in the pickup status
|
|
48
|
-
has_planned_slices() {
|
|
49
|
-
grep -rqi "\"status\"[[:space:]]*:[[:space:]]*\"$PICKUP_STATUS\"" "$KIT_DIR/.slices/" --include='index.json' 2>/dev/null
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
# Returns the title of the first "Planned" slice, or empty string
|
|
53
|
-
get_planned_slice_title() {
|
|
54
|
-
for index_file in "$KIT_DIR/.slices/"*/index.json; do
|
|
55
|
-
[[ -f "$index_file" ]] || continue
|
|
56
|
-
local title
|
|
57
|
-
title=$(node -e "
|
|
58
|
-
try {
|
|
59
|
-
const d = JSON.parse(require('fs').readFileSync(process.argv[1], 'utf-8'));
|
|
60
|
-
const s = (d.slices||[]).find(s => (s.status||'').toLowerCase() === process.argv[2].toLowerCase());
|
|
61
|
-
if (s) process.stdout.write(s.slice || s.id || '');
|
|
62
|
-
} catch(e) {}
|
|
63
|
-
" "$index_file" "$PICKUP_STATUS" 2>/dev/null)
|
|
64
|
-
if [[ -n "$title" ]]; then
|
|
65
|
-
echo "$title"
|
|
66
|
-
return
|
|
67
|
-
fi
|
|
68
|
-
done
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
# prompt.md and backend-prompt.md are instruction manuals with no request in them — handed one
|
|
72
|
-
# alone, the agent may read it as background and ask what to do. Every turn ends with the concrete
|
|
73
|
-
# request, the same one lib/ralph.js's taskRequest() appends.
|
|
74
|
-
task_request() {
|
|
75
|
-
printf '\n\n---\n\nYour task now: %s, following the instructions above. Start immediately.\n' "$1"
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
# Runs agent.sh with the given prompt; retries on non-zero exit
|
|
79
|
-
run_agent() {
|
|
80
|
-
local label="$1"
|
|
81
|
-
local prompt="$2"
|
|
82
|
-
while true; do
|
|
83
|
-
echo "[$(date -u +%H:%M:%S)] $label"
|
|
84
|
-
(cd "$PROJECT_DIR" && bash "$AGENT_SCRIPT" "$prompt") 2>&1 && return 0
|
|
85
|
-
echo "[$(date -u +%H:%M:%S)] Agent error — retrying in 60s..."
|
|
86
|
-
sleep 60
|
|
87
|
-
done
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
cycle=0
|
|
91
|
-
while [[ "$ITERATIONS" -eq 0 || "$cycle" -lt "$ITERATIONS" ]]; do
|
|
92
|
-
ran_something=false
|
|
93
|
-
|
|
94
|
-
if [[ "$HAS_CREDENTIALS" == true ]] && has_pending_tasks; then
|
|
95
|
-
run_agent "onTask: loading slice from board..." "$(cat "$PROMPT_FILE"; task_request 'process the pending tasks in tasks.json')"
|
|
96
|
-
ran_something=true
|
|
97
|
-
fi
|
|
98
|
-
|
|
99
|
-
if has_planned_slices; then
|
|
100
|
-
slice_title=$(get_planned_slice_title)
|
|
101
|
-
run_agent "onPlannedSlice: building \"$slice_title\"..." "$(cat "$BACKEND_PROMPT_FILE"; task_request "build the $PICKUP_STATUS slice \"$slice_title\"")"
|
|
102
|
-
echo "[$(date -u +%H:%M:%S)] Slice \"$slice_title\" build complete — waiting for next slice"
|
|
103
|
-
ran_something=true
|
|
104
|
-
fi
|
|
105
|
-
|
|
106
|
-
if [[ "$ran_something" == false ]]; then
|
|
107
|
-
sleep 3
|
|
108
|
-
fi
|
|
109
|
-
|
|
110
|
-
(( cycle++ )) || true
|
|
111
|
-
done
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Standalone realtime agent — subscribes to board events and writes tasks.json.
|
|
3
|
-
// The same logic runs embedded inside ralph-claude.js / ralph-local-ai.js, so you
|
|
4
|
-
// only need this if you want to run the agent independently (e.g. separate terminal).
|
|
5
|
-
// Usage: node realtime-agent.js [kit_dir]
|
|
6
|
-
|
|
7
|
-
import { loadLocalConfig, fetchPlatformConfig, retryTransient, startRealtimeAgent } from './lib/ralph.js';
|
|
8
|
-
import { redactConsole } from './lib/redact.js';
|
|
9
|
-
import { dirname, resolve } from 'path';
|
|
10
|
-
import { fileURLToPath } from 'url';
|
|
11
|
-
|
|
12
|
-
const kitDir = process.argv[2] ? resolve(process.argv[2]) : dirname(fileURLToPath(import.meta.url));
|
|
13
|
-
|
|
14
|
-
const local = loadLocalConfig(kitDir);
|
|
15
|
-
redactConsole([local.token]);
|
|
16
|
-
const cfg = await retryTransient('fetchPlatformConfig', () => fetchPlatformConfig(local));
|
|
17
|
-
|
|
18
|
-
console.log(`[agent] Starting — org=${cfg.organizationId}${cfg.boardId ? `, board=${cfg.boardId}` : ''}, base=${cfg.baseUrl}`);
|
|
19
|
-
|
|
20
|
-
await startRealtimeAgent(cfg, kitDir);
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
# Agent Learnings
|
|
2
|
-
|
|
3
|
-
Patterns and gotchas discovered during task processing. Update this file
|
|
4
|
-
whenever you encounter something reusable.
|
|
5
|
-
|
|
6
|
-
## tasks.json
|
|
7
|
-
|
|
8
|
-
- Tasks are objects with `id`, `createdAt`, and `payload` (a
|
|
9
|
-
`SliceChangedPayload`).
|
|
10
|
-
- Unlike build-kit, every status change is queued (not just non-`Planned`
|
|
11
|
-
ones) — see `queueAllStatuses` in `lib/ralph.js`.
|
|
12
|
-
- After completing a task, remove it from the array entirely — do not add a
|
|
13
|
-
status field.
|
|
14
|
-
- Write `[]` to `tasks.json` if the last task is completed.
|
|
15
|
-
|
|
16
|
-
## SliceChangedPayload fields
|
|
17
|
-
|
|
18
|
-
```
|
|
19
|
-
event always "slice:changed"
|
|
20
|
-
organizationId org UUID or null
|
|
21
|
-
boardId board UUID
|
|
22
|
-
sliceId SLICE_BORDER node UUID
|
|
23
|
-
sliceTitle human-readable slice name (may be null)
|
|
24
|
-
sliceStatus e.g. "Created", "Planned", "InProgress", "Done" (may be null)
|
|
25
|
-
timestamp unix ms when the change was emitted
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Bridge target
|
|
29
|
-
|
|
30
|
-
- The active target framework lives in `.bridge-kit/bridge.json`'s `target`
|
|
31
|
-
field, written at `init --bridge --target <name>` time. This file is
|
|
32
|
-
committed (unlike `.eventmodelers/config.json`, which is gitignored) since
|
|
33
|
-
it's project policy shared by every teammate and CI runner, not a
|
|
34
|
-
per-machine credential.
|
|
35
|
-
- Skill naming convention: `bridge-<target>-specify` (kept in sync every
|
|
36
|
-
task) and `bridge-<target>-tasks` (invoked separately, by that framework's
|
|
37
|
-
own task-planning phase — not from this loop).
|
|
38
|
-
|
|
39
|
-
## Executors
|
|
40
|
-
|
|
41
|
-
- Claude (`ralph-claude.js`, this prompt) is the default. `bridge --local-ai`
|
|
42
|
-
swaps in a local model instead — same prompt, different executor.
|
|
43
|
-
- `bridge --hook "<command>"` (or a `hookCommand` persisted in
|
|
44
|
-
`bridge.json`) bypasses this prompt entirely: `ralph-hook.js` runs an
|
|
45
|
-
arbitrary shell command per batch of changes instead of any AI agent — e.g.
|
|
46
|
-
commit + push `.slices/` and let a CI pipeline do the actual translation.
|
|
47
|
-
If you're reading this file, a hook wasn't configured for this run.
|