@kody-ade/kody-engine 0.4.398 → 0.4.400
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 +7 -7
- package/dist/bin/kody.js +1799 -3187
- package/dist/implementations/run/prompt.md +1 -1
- package/dist/implementations/types.ts +3 -3
- package/kody.config.schema.json +0 -27
- package/package.json +24 -25
- package/templates/workers/goal-manager.md +0 -175
|
@@ -74,7 +74,7 @@ If a prior-art block is present above, READ THE DIFFS — those are failed or su
|
|
|
74
74
|
- **No speculative refactors.** Stay inside the issue's scope. Do not rename variables, retype function signatures, restructure modules, reorder imports, reformat unchanged lines, or "clean up" code adjacent to the change unless that cleanup is *required* by the change. Scope drift in your diff is a hard failure even if the change works — reviewers can't tell what was intentional. If you find a real adjacent bug while working, mention it in `PR_SUMMARY` (without fixing it) so a follow-up issue can be opened.
|
|
75
75
|
- Do NOT run **any** `git` or `gh` commands. The wrapper handles all git/gh operations. If a quality gate fails, that's the failure — do not investigate it via git.
|
|
76
76
|
- Stay on the current branch (`{{branch}}`). It is already checked out for you.
|
|
77
|
-
- Do NOT modify files under: `.kody
|
|
77
|
+
- Do NOT modify files under: `.kody-engine/`, `.kody-lean/`, `node_modules/`, `dist/`, `build/`, `.env`, or any `*.log`.
|
|
78
78
|
- Do NOT post issue comments — the wrapper handles that.
|
|
79
79
|
- Pre-existing quality-gate failures: assume they are NOT yours unless your edits touched related code.
|
|
80
80
|
- Keep the plan and reasoning concise. Long monologues waste turns.
|
|
@@ -49,7 +49,7 @@ export interface Profile {
|
|
|
49
49
|
action?: string
|
|
50
50
|
/**
|
|
51
51
|
* Optional agent this implementation runs *as*. When set, the executor
|
|
52
|
-
* loads hydrated `.kody/agents/<agent>.md` and injects that agent (authoritative
|
|
52
|
+
* loads hydrated `.kody-engine/definitions/agents/<agent>.md` and injects that agent (authoritative
|
|
53
53
|
* identity) ahead of the implementation's own system-prompt append. This is the
|
|
54
54
|
* unification hook: a capability can select an implementation + an agent. Absent →
|
|
55
55
|
* runs with no agent (unchanged legacy behaviour). A declared-but-missing
|
|
@@ -202,7 +202,7 @@ export interface Profile {
|
|
|
202
202
|
* preflight runs. composePrompt prefers these over a fresh disk read so the
|
|
203
203
|
* template survives working-tree churn from runFlow's branch setup — on the CI
|
|
204
204
|
* runner a branch checkout can drop the tracked-but-ignore-negated
|
|
205
|
-
* `.kody/capabilities/<name>/` dir, and reading prompt.md afterwards fails with
|
|
205
|
+
* `.kody-engine/definitions/capabilities/<name>/` dir, and reading prompt.md afterwards fails with
|
|
206
206
|
* ENOENT even though profile.json (read here, earlier) loaded fine.
|
|
207
207
|
*/
|
|
208
208
|
promptTemplates?: Record<string, string>
|
|
@@ -210,7 +210,7 @@ export interface Profile {
|
|
|
210
210
|
* Subagent markdown captured (by declared name) at load time, BEFORE any
|
|
211
211
|
* task branch switch — same rationale as promptTemplates. loadSubagents
|
|
212
212
|
* prefers this snapshot so a capability's `agents/` surviving only on the default
|
|
213
|
-
* checkout (e.g. `.kody/capabilities/<slug>/agents/` absent on a PR branch) doesn't
|
|
213
|
+
* checkout (e.g. `.kody-engine/definitions/capabilities/<slug>/agents/` absent on a PR branch) doesn't
|
|
214
214
|
* crash a PR-targeted capability. Populated by captureSubagentTemplates.
|
|
215
215
|
*/
|
|
216
216
|
subagentTemplates?: Record<string, string>
|
package/kody.config.schema.json
CHANGED
|
@@ -53,22 +53,6 @@
|
|
|
53
53
|
"repo": { "type": "string" }
|
|
54
54
|
}
|
|
55
55
|
},
|
|
56
|
-
"state": {
|
|
57
|
-
"type": "object",
|
|
58
|
-
"description": "External repository and path used for Kody runtime state.",
|
|
59
|
-
"additionalProperties": false,
|
|
60
|
-
"properties": {
|
|
61
|
-
"repo": {
|
|
62
|
-
"type": "string",
|
|
63
|
-
"description": "Full GitHub repository URL for Kody runtime state.",
|
|
64
|
-
"pattern": "^https://github\\.com/[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+(?:\\.git)?$"
|
|
65
|
-
},
|
|
66
|
-
"path": {
|
|
67
|
-
"type": "string",
|
|
68
|
-
"description": "Folder inside state.repo that belongs to this consumer repo."
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
56
|
"agent": {
|
|
73
57
|
"type": "object",
|
|
74
58
|
"required": ["model"],
|
|
@@ -171,17 +155,6 @@
|
|
|
171
155
|
}
|
|
172
156
|
}
|
|
173
157
|
},
|
|
174
|
-
"jobs": {
|
|
175
|
-
"type": "object",
|
|
176
|
-
"additionalProperties": false,
|
|
177
|
-
"properties": {
|
|
178
|
-
"stateBackend": {
|
|
179
|
-
"type": "string",
|
|
180
|
-
"enum": ["contents-api"],
|
|
181
|
-
"default": "contents-api"
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
},
|
|
185
158
|
"access": {
|
|
186
159
|
"type": "object",
|
|
187
160
|
"additionalProperties": false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kody-ade/kody-engine",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.400",
|
|
4
4
|
"description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative implementation profiles.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -12,28 +12,6 @@
|
|
|
12
12
|
"templates",
|
|
13
13
|
"kody.config.schema.json"
|
|
14
14
|
],
|
|
15
|
-
"scripts": {
|
|
16
|
-
"kody:run": "tsx bin/kody.ts",
|
|
17
|
-
"serve": "tsx bin/kody.ts serve",
|
|
18
|
-
"serve:vscode": "tsx bin/kody.ts serve vscode",
|
|
19
|
-
"serve:claude": "tsx bin/kody.ts serve claude",
|
|
20
|
-
"clean:dist": "node scripts/clean-dist.cjs",
|
|
21
|
-
"build": "pnpm clean:dist && tsup && node scripts/copy-assets.cjs",
|
|
22
|
-
"check:modularity": "tsx scripts/check-script-modularity.ts",
|
|
23
|
-
"pretest": "pnpm check:modularity",
|
|
24
|
-
"test": "vitest run tests/unit tests/int --coverage",
|
|
25
|
-
"posttest": "tsx scripts/check-coverage-floor.ts",
|
|
26
|
-
"test:smoke": "vitest run tests/smoke --no-coverage",
|
|
27
|
-
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
28
|
-
"test:all": "vitest run tests --no-coverage",
|
|
29
|
-
"typecheck": "tsc --noEmit",
|
|
30
|
-
"lint": "biome check",
|
|
31
|
-
"lint:fix": "biome check --write",
|
|
32
|
-
"format": "biome format --write",
|
|
33
|
-
"verify:package": "node scripts/verify-package-tarball.cjs",
|
|
34
|
-
"brain:publish": "docker buildx build --platform linux/amd64 -f runner/Dockerfile.brain -t ghcr.io/${KODY_BRAIN_GHCR_OWNER:-aharonyaircohen}/kody-brain:latest --push runner",
|
|
35
|
-
"prepublishOnly": "pnpm typecheck && vitest run tests/unit tests/int --no-coverage && pnpm build && pnpm verify:package"
|
|
36
|
-
},
|
|
37
15
|
"dependencies": {
|
|
38
16
|
"@actions/cache": "^6.0.0",
|
|
39
17
|
"@anthropic-ai/claude-agent-sdk": "0.2.119",
|
|
@@ -58,5 +36,26 @@
|
|
|
58
36
|
"url": "git+https://github.com/aharonyaircohen/kody-engine.git"
|
|
59
37
|
},
|
|
60
38
|
"homepage": "https://github.com/aharonyaircohen/kody-engine",
|
|
61
|
-
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
|
|
62
|
-
|
|
39
|
+
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues",
|
|
40
|
+
"scripts": {
|
|
41
|
+
"kody:run": "tsx bin/kody.ts",
|
|
42
|
+
"serve": "tsx bin/kody.ts serve",
|
|
43
|
+
"serve:vscode": "tsx bin/kody.ts serve vscode",
|
|
44
|
+
"serve:claude": "tsx bin/kody.ts serve claude",
|
|
45
|
+
"clean:dist": "node scripts/clean-dist.cjs",
|
|
46
|
+
"build": "pnpm clean:dist && tsup && node scripts/copy-assets.cjs",
|
|
47
|
+
"check:modularity": "tsx scripts/check-script-modularity.ts",
|
|
48
|
+
"pretest": "pnpm check:modularity",
|
|
49
|
+
"test": "vitest run tests/unit tests/int --coverage",
|
|
50
|
+
"posttest": "tsx scripts/check-coverage-floor.ts",
|
|
51
|
+
"test:smoke": "vitest run tests/smoke --no-coverage",
|
|
52
|
+
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
53
|
+
"test:all": "vitest run tests --no-coverage",
|
|
54
|
+
"typecheck": "tsc --noEmit",
|
|
55
|
+
"lint": "biome check",
|
|
56
|
+
"lint:fix": "biome check --write",
|
|
57
|
+
"format": "biome format --write",
|
|
58
|
+
"verify:package": "node scripts/verify-package-tarball.cjs",
|
|
59
|
+
"brain:publish": "docker buildx build --platform linux/amd64 -f runner/Dockerfile.brain -t ghcr.io/${KODY_BRAIN_GHCR_OWNER:-aharonyaircohen}/kody-brain:latest --push runner"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
# Goal Manager .
|
|
2
|
-
|
|
3
|
-
Autonomous manager for **manager-driven goals**. One worker, every goal:
|
|
4
|
-
each tick it picks up every goal flagged `managed`, breaks it into tasks,
|
|
5
|
-
lets the deterministic `goal-tick` execute them, verifies the
|
|
6
|
-
end-to-end user journey with `qa-engineer`, recovers stalled tasks, and
|
|
7
|
-
stops a goal only when its single deliverable PR is open and the journey
|
|
8
|
-
passes. It never edits code and never merges anything.
|
|
9
|
-
|
|
10
|
-
> Drop this file at `.kody/workers/goal-manager.md` in a consumer repo.
|
|
11
|
-
> The `worker-scheduler` cron invokes `worker-tick` on it automatically.
|
|
12
|
-
|
|
13
|
-
## Worker
|
|
14
|
-
|
|
15
|
-
You coordinate goals **only** through `gh`. You do not write code, open
|
|
16
|
-
PRs, or merge. Everything below is per-goal; you handle all goals in one
|
|
17
|
-
tick.
|
|
18
|
-
|
|
19
|
-
### 1. Discover managed goals
|
|
20
|
-
|
|
21
|
-
```
|
|
22
|
-
ls .kody/goals/*/state.json 2>/dev/null
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
For each, read it (`cat`). A goal is **in scope** when BOTH:
|
|
26
|
-
|
|
27
|
-
- `.state == "active"`, and
|
|
28
|
-
- `.managed == true` (the dashboard's "Let Kody manage this goal" toggle
|
|
29
|
-
writes this; absent/false → ignore the goal entirely).
|
|
30
|
-
|
|
31
|
-
For an in-scope goal, the goal **id** is the directory name
|
|
32
|
-
(`.kody/goals/<id>/state.json`). Its definition (intent + the ordered
|
|
33
|
-
end-to-end user journey that defines "done") is, in priority order:
|
|
34
|
-
|
|
35
|
-
1. `.journey` / `.description` / `.intent` / `.title` fields in
|
|
36
|
-
`state.json` if present, else
|
|
37
|
-
2. the goal's GitHub Discussion body — if `state.json` has a
|
|
38
|
-
`discussionNumber`, fetch it:
|
|
39
|
-
`gh api graphql -f query='{repository(owner:"OWNER",name:"REPO"){discussion(number:N){body title}}}'`
|
|
40
|
-
(resolve OWNER/REPO from `gh repo view --json owner,name`).
|
|
41
|
-
|
|
42
|
-
The **journey** is the acceptance test. If you cannot find any journey
|
|
43
|
-
text, do NOT guess — escalate the goal (see §5) with reason
|
|
44
|
-
`no-journey-defined` and skip it.
|
|
45
|
-
|
|
46
|
-
### 2. Per-goal cursor
|
|
47
|
-
|
|
48
|
-
Keep all per-goal progress under `data.goals[<id>]`. Each entry:
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
{ "cursor": "...", "tasks": [<issue numbers you created>],
|
|
52
|
-
"gate": <qa-gate issue number|null>, "qaRound": <int>,
|
|
53
|
-
"stall": { "<issueNumber>": { "ticks": <int>, "attempts": <int> } },
|
|
54
|
-
"lastQaTick": "<ISO>" }
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
`cursor` ∈ `new | building | qa | finalizing | done | escalated`.
|
|
58
|
-
Missing entry ⇒ treat as `new`.
|
|
59
|
-
|
|
60
|
-
### 3. Decompose (`cursor: new`)
|
|
61
|
-
|
|
62
|
-
One-time setup for the goal:
|
|
63
|
-
|
|
64
|
-
1. Ensure labels exist (idempotent — ignore "already exists"):
|
|
65
|
-
`gh label create "goal:<id>" --color 5319e7 2>/dev/null || true`
|
|
66
|
-
`gh label create "kody:qa-gate" --color b60205 2>/dev/null || true`
|
|
67
|
-
`gh label create "kody:needs-human" --color d93f0b 2>/dev/null || true`
|
|
68
|
-
2. Break the goal into the **smallest correct set of sequential tasks**.
|
|
69
|
-
For each, create an issue:
|
|
70
|
-
`gh issue create --title "<task>" --label "goal:<id>" --body "<precise spec, acceptance criteria>"`
|
|
71
|
-
Record the returned issue numbers in `tasks`. Order matters — the
|
|
72
|
-
stacked-PR model builds them lowest-number first.
|
|
73
|
-
3. Create the **QA gate** issue (exactly one per goal):
|
|
74
|
-
`gh issue create --title "QA gate: <id> — end-to-end journey" --label "goal:<id>" --label "kody:qa-gate" --body "<the full ordered journey, step 1 → success state>"`
|
|
75
|
-
Record its number in `gate`.
|
|
76
|
-
4. Set `cursor: building`. **Do not** dispatch anything yourself —
|
|
77
|
-
`goal-tick` (its own cron) sees the new `goal:<id>` issues and drives
|
|
78
|
-
them. The open `kody:qa-gate` issue keeps the goal short of
|
|
79
|
-
`all-done`, so nothing finalizes until you close it in §4.
|
|
80
|
-
|
|
81
|
-
### 4. Drive + recover (`cursor: building`)
|
|
82
|
-
|
|
83
|
-
Each tick, for the goal:
|
|
84
|
-
|
|
85
|
-
- Enumerate tasks:
|
|
86
|
-
`gh issue list --label "goal:<id>" --state all --json number,state,title`
|
|
87
|
-
and the PRs:
|
|
88
|
-
`gh pr list --state open --json number,headRefName,body,isDraft`.
|
|
89
|
-
A task is **done** when its issue is CLOSED or it has a ready
|
|
90
|
-
(non-draft) open PR (`Closes #<n>` in body, or head ref `^<n>-`).
|
|
91
|
-
- **Stall detection** (per non-gate, non-done task):
|
|
92
|
-
- Increment `stall[n].ticks`.
|
|
93
|
-
- If the task has **no open PR** and `stall[n].ticks >= 3`: it was
|
|
94
|
-
never picked up — re-nudge: `gh issue comment <n> --body "@kody"`,
|
|
95
|
-
`stall[n].attempts += 1`, reset `stall[n].ticks = 0`.
|
|
96
|
-
- If the task has a **draft PR with no new commits** for
|
|
97
|
-
`stall[n].ticks >= 4`: comment `@kody continue` on the PR, bump
|
|
98
|
-
attempts, reset ticks.
|
|
99
|
-
- When `stall[n].attempts >= 3` for any task → escalate (§5) and set
|
|
100
|
-
`cursor: escalated`.
|
|
101
|
-
- Clear `stall[n]` once the task is done.
|
|
102
|
-
- When **every non-gate task is done** → `cursor: qa`.
|
|
103
|
-
|
|
104
|
-
### 4b. Verify the journey (`cursor: qa`)
|
|
105
|
-
|
|
106
|
-
- Throttle: skip if `lastQaTick` is < 20 min ago (avoid stacking QA
|
|
107
|
-
runs); otherwise:
|
|
108
|
-
- Trigger QA against the journey by commenting on the **gate issue**:
|
|
109
|
-
`gh issue comment <gate> --body "@kody qa-engineer --goal <id> --scope \"<the full journey text>\""`
|
|
110
|
-
Set `lastQaTick` = now, `qaRound += 1`.
|
|
111
|
-
- `qa-engineer` browses the running app and files **each failure as a
|
|
112
|
-
new `goal:<id>` task issue** automatically. So on the **next** tick:
|
|
113
|
-
- If new `goal:<id>` task issues appeared after this `qaRound` (issues
|
|
114
|
-
you didn't create / not in `tasks`) → add them to `tasks`, set
|
|
115
|
-
`cursor: building` (the loop fixes them, then QA re-runs).
|
|
116
|
-
- If no new task issues and the latest `qa-engineer` report comment on
|
|
117
|
-
the gate issue is a **PASS** (read it:
|
|
118
|
-
`gh issue view <gate> --json comments`) → the journey works:
|
|
119
|
-
close the gate `gh issue close <gate> --comment "QA passed — journey verified."`,
|
|
120
|
-
set `cursor: finalizing`.
|
|
121
|
-
- If the report is ambiguous/unreachable and `qaRound >= 4` →
|
|
122
|
-
escalate (§5).
|
|
123
|
-
|
|
124
|
-
### 4c. Finish (`cursor: finalizing`)
|
|
125
|
-
|
|
126
|
-
With the gate closed, `goal-tick` observes `all-done`, prepares the
|
|
127
|
-
**single open deliverable PR** (cumulative diff vs the default branch,
|
|
128
|
-
review-ready), closes the task issues, and sets `state: "done"` in
|
|
129
|
-
`state.json`. You do **not** merge — a human merges that PR.
|
|
130
|
-
|
|
131
|
-
- When `state.json.state == "done"` (or the deliverable PR is open and
|
|
132
|
-
task issues are closed): post one summary comment on the gate issue or
|
|
133
|
-
the discussion linking the deliverable PR, set `cursor: done`.
|
|
134
|
-
|
|
135
|
-
### 5. Escalation
|
|
136
|
-
|
|
137
|
-
Escalate by: commenting the reason on the goal's most relevant artifact
|
|
138
|
-
(gate issue if it exists, else the highest-numbered task issue), adding
|
|
139
|
-
the `kody:needs-human` label to that issue, and setting
|
|
140
|
-
`cursor: escalated`. On later ticks, re-check an escalated goal: if a
|
|
141
|
-
human removed `kody:needs-human` or the blocking condition cleared,
|
|
142
|
-
resume at the appropriate cursor.
|
|
143
|
-
|
|
144
|
-
### 6. `cursor: done | escalated`
|
|
145
|
-
|
|
146
|
-
No action. Keep the entry so you don't reprocess it. (These are per-goal;
|
|
147
|
-
the **worker** is evergreen — never emit worker-level `done: true`.)
|
|
148
|
-
|
|
149
|
-
## Allowed Commands
|
|
150
|
-
|
|
151
|
-
`gh` only: `gh issue ...`, `gh pr ...`, `gh label ...`, `gh api ...`,
|
|
152
|
-
`gh repo view`. Read-only shell (`ls`, `cat`) on the checked-out tree to
|
|
153
|
-
read `.kody/goals/*/state.json`.
|
|
154
|
-
|
|
155
|
-
## Restrictions
|
|
156
|
-
|
|
157
|
-
- Never edit, create, or delete files in the working tree (no code, no
|
|
158
|
-
`state.json` writes — the gate is GitHub-side via the qa-gate issue).
|
|
159
|
-
- Never run `git`. Never merge or close a PR. Never mark a PR ready.
|
|
160
|
-
- Never `@kody` a `kody:qa-gate` issue except the one `qa-engineer`
|
|
161
|
-
trigger in §4b.
|
|
162
|
-
- One QA trigger per `qaRound`; honour the 20-min throttle.
|
|
163
|
-
- Do not dispatch implementation tasks yourself — only create the issues;
|
|
164
|
-
`goal-tick` dispatches. Your only `@kody` comments are stall re-nudges
|
|
165
|
-
(§4) and the `qa-engineer` trigger (§4b).
|
|
166
|
-
|
|
167
|
-
## State
|
|
168
|
-
|
|
169
|
-
`cursor` (worker-level): always `"managing"` (evergreen). All real
|
|
170
|
-
progress lives in `data.goals[<id>]` as described in §2. `done`: always
|
|
171
|
-
`false`.
|
|
172
|
-
|
|
173
|
-
**Cadence guard.** If `forceRun` is false and your last tick was < 4 min
|
|
174
|
-
ago (compare a `data.lastTick` ISO you maintain), emit the prior state
|
|
175
|
-
unchanged and exit. Always update `data.lastTick` when you do run.
|