@kody-ade/kody-engine-lite 0.1.28 → 0.1.30
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 +124 -47
- package/dist/bin/cli.js +61 -16
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,86 +1,163 @@
|
|
|
1
1
|
# Kody Engine Lite
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@kody-ade/kody-engine-lite)
|
|
4
|
+
[](LICENSE)
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
@kody → taskify → plan → build → verify → review → fix → ship → PR created
|
|
7
|
-
```
|
|
6
|
+
**Issue → PR in one command.** Comment `@kody` on a GitHub issue and Kody autonomously classifies, plans, builds, tests, reviews, fixes, and ships a pull request.
|
|
8
7
|
|
|
9
|
-
Kody is a 7-stage autonomous SDLC pipeline that runs in GitHub Actions. It uses Claude Code (or any LLM via LiteLLM) to turn issues into production-ready PRs — with quality gates, AI-powered failure diagnosis, risk-based human approval, and
|
|
8
|
+
Kody is a 7-stage autonomous SDLC pipeline that runs in GitHub Actions. It uses Claude Code (or any LLM via LiteLLM) to turn issues into production-ready PRs — with quality gates, AI-powered failure diagnosis, risk-based human approval, and shared context between stages.
|
|
10
9
|
|
|
11
10
|
## Why Kody?
|
|
12
11
|
|
|
13
|
-
Most AI coding tools are **autocomplete** (Copilot) or **chat-based** (Cursor, Cline). You still drive. Kody is
|
|
14
|
-
|
|
15
|
-
Single agents hit context limits on large tasks. Kody splits work into focused stages — each with a fresh context window but access to curated context from previous stages. A 27-minute auth system build (JWT, sessions, middleware, RBAC, 7 stages, 3 autofix retries) completes end-to-end without losing track.
|
|
12
|
+
Most AI coding tools are **autocomplete** (Copilot) or **chat-based** (Cursor, Cline). You still drive. Kody is an **autonomous pipeline** — comment `@kody`, walk away, come back to a PR.
|
|
16
13
|
|
|
17
14
|
| | Kody | Copilot Workspace | Devin | Cursor Agent |
|
|
18
15
|
|---|---|---|---|---|
|
|
19
16
|
| **Runs in CI** | GitHub Actions | GitHub Cloud | Devin Cloud | Local IDE |
|
|
20
|
-
| **Fire and forget** |
|
|
21
|
-
| **
|
|
22
|
-
| **
|
|
17
|
+
| **Fire and forget** | Yes | No — interactive | Partially | No — IDE must be open |
|
|
18
|
+
| **Pipeline stages** | 7 stages with quality gates | Plan → implement | Single agent | Single agent |
|
|
19
|
+
| **Shared sessions** | Stages share Claude Code sessions (no cold starts) | Single conversation | Single conversation | Single conversation |
|
|
20
|
+
| **Risk gate** | Pauses HIGH-risk for human approval | No | No | No |
|
|
21
|
+
| **AI failure diagnosis** | Classifies errors before retry (fixable/infra/abort) | No | No | No |
|
|
23
22
|
| **Model flexible** | Any LLM via LiteLLM | GitHub models only | Proprietary | Cursor models |
|
|
24
23
|
| **Open source** | MIT | Proprietary | Proprietary | Proprietary |
|
|
25
|
-
| **Accumulated context** | Curated context flows between stages | Single conversation | Single agent | Single agent |
|
|
26
|
-
| **Complex tasks** | 27-min auth system with 7 stages + autofix | Struggles with large scope | Better | Struggles with large scope |
|
|
27
24
|
| **Cost** | Your API costs only | $10-39/month | $20-500/month | Subscription |
|
|
28
25
|
|
|
29
26
|
[Full comparison →](docs/COMPARISON.md)
|
|
30
27
|
|
|
28
|
+
## Pipeline
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
32
|
+
│ @kody on issue │
|
|
33
|
+
└──────────────────────────┬──────────────────────────────────┘
|
|
34
|
+
│
|
|
35
|
+
┌──────────────────────────▼──────────────────────────────────┐
|
|
36
|
+
│ ① TASKIFY Tier: cheap │
|
|
37
|
+
│ Classify task, detect complexity, ask questions → task.json │
|
|
38
|
+
└──────────────────────────┬──────────────────────────────────┘
|
|
39
|
+
│
|
|
40
|
+
┌────────────▼────────────┐
|
|
41
|
+
│ LOW? skip to ④ │
|
|
42
|
+
│ MEDIUM? continue │
|
|
43
|
+
│ HIGH? continue │
|
|
44
|
+
└────────────┬────────────┘
|
|
45
|
+
│
|
|
46
|
+
┌──────────────────────────▼──────────────────────────────────┐
|
|
47
|
+
│ ② PLAN Tier: strong │
|
|
48
|
+
│ TDD implementation plan (deep reasoning) → plan.md │
|
|
49
|
+
└──────────────────────────┬──────────────────────────────────┘
|
|
50
|
+
│
|
|
51
|
+
┌────────────▼────────────┐
|
|
52
|
+
│ HIGH risk? │
|
|
53
|
+
│ 🛑 Pause for approval │──── @kody approve
|
|
54
|
+
└────────────┬────────────┘
|
|
55
|
+
│
|
|
56
|
+
┌──────────────────────────▼──────────────────────────────────┐
|
|
57
|
+
│ ③ BUILD Tier: mid │
|
|
58
|
+
│ Implement code via Claude Code tools → code + git commit│
|
|
59
|
+
└──────────────────────────┬──────────────────────────────────┘
|
|
60
|
+
│
|
|
61
|
+
┌──────────────────────────▼──────────────────────────────────┐
|
|
62
|
+
│ ④ VERIFY (deterministic gate) │
|
|
63
|
+
│ typecheck + tests + lint │
|
|
64
|
+
│ ┌───────────────────────────────────────────────────┐ │
|
|
65
|
+
│ │ Fail? → AI diagnosis → autofix → retry (up to 2) │ │
|
|
66
|
+
│ └───────────────────────────────────────────────────┘ │
|
|
67
|
+
└──────────────────────────┬──────────────────────────────────┘
|
|
68
|
+
│
|
|
69
|
+
┌──────────────────────────▼──────────────────────────────────┐
|
|
70
|
+
│ ⑤ REVIEW Tier: strong │
|
|
71
|
+
│ Code review: PASS/FAIL + Critical/Major/Minor → review.md │
|
|
72
|
+
└──────────────────────────┬──────────────────────────────────┘
|
|
73
|
+
│
|
|
74
|
+
┌──────────────────────────▼──────────────────────────────────┐
|
|
75
|
+
│ ⑥ REVIEW-FIX Tier: mid │
|
|
76
|
+
│ Fix Critical and Major findings → code + commit│
|
|
77
|
+
└──────────────────────────┬──────────────────────────────────┘
|
|
78
|
+
│
|
|
79
|
+
┌──────────────────────────▼──────────────────────────────────┐
|
|
80
|
+
│ ⑦ SHIP (deterministic) │
|
|
81
|
+
│ Push branch + create PR with Closes #N → ship.md + PR│
|
|
82
|
+
└──────────────────────────┬──────────────────────────────────┘
|
|
83
|
+
│
|
|
84
|
+
┌──────────────────────────▼──────────────────────────────────┐
|
|
85
|
+
│ ✅ PR created & ready for review │
|
|
86
|
+
└─────────────────────────────────────────────────────────────┘
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Tiers are configurable** — cheap/mid/strong map to any model via `modelMap` in config. Defaults: haiku/sonnet/opus. Route to MiniMax, GPT, Gemini, or local models via [LiteLLM](docs/LITELLM.md).
|
|
90
|
+
|
|
91
|
+
**Shared sessions** — stages in the same group share a Claude Code session: taskify+plan (explore), build+autofix+review-fix (implementation), review (fresh perspective). No cold-start re-exploration between stages.
|
|
92
|
+
|
|
93
|
+
[Pipeline details →](docs/PIPELINE.md)
|
|
94
|
+
|
|
31
95
|
## Quick Start
|
|
32
96
|
|
|
97
|
+
**Prerequisites:** Node.js >= 22, [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code), [GitHub CLI](https://cli.github.com/), git
|
|
98
|
+
|
|
99
|
+
### 1. Install
|
|
100
|
+
|
|
33
101
|
```bash
|
|
34
|
-
# 1. Install
|
|
35
102
|
npm install -g @kody-ade/kody-engine-lite
|
|
103
|
+
```
|
|
36
104
|
|
|
37
|
-
|
|
105
|
+
### 2. Set up GitHub
|
|
106
|
+
|
|
107
|
+
```bash
|
|
38
108
|
gh secret set ANTHROPIC_API_KEY --repo owner/repo
|
|
39
|
-
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Then in GitHub: **Settings → Actions → General → "Allow GitHub Actions to create and approve pull requests"**
|
|
112
|
+
|
|
113
|
+
### 3. Initialize
|
|
40
114
|
|
|
41
|
-
|
|
115
|
+
```bash
|
|
42
116
|
cd your-project
|
|
43
117
|
kody-engine-lite init
|
|
44
|
-
|
|
45
|
-
# 4. Comment on any issue
|
|
46
|
-
@kody
|
|
47
118
|
```
|
|
48
119
|
|
|
49
|
-
|
|
120
|
+
This analyzes your project and generates workflow, config, memory, and labels — then commits and pushes.
|
|
50
121
|
|
|
51
|
-
|
|
122
|
+
### 4. Use
|
|
52
123
|
|
|
53
|
-
|
|
124
|
+
Comment on any GitHub issue:
|
|
54
125
|
|
|
55
126
|
```
|
|
56
|
-
@kody
|
|
57
|
-
↓
|
|
58
|
-
1. taskify — classify task, detect complexity, ask questions → task.json
|
|
59
|
-
2. plan — TDD implementation plan (deep reasoning) → plan.md
|
|
60
|
-
↓ HIGH risk? pause for human approval
|
|
61
|
-
3. build — implement code via Claude Code tools → code changes
|
|
62
|
-
4. verify — typecheck + tests + lint (AI diagnosis + autofix) → verify.md
|
|
63
|
-
5. review — code review: PASS/FAIL + Critical/Major/Minor → review.md
|
|
64
|
-
6. review-fix — fix Critical and Major findings → code changes
|
|
65
|
-
7. ship — push branch + create PR with Closes #N → ship.md
|
|
66
|
-
↓
|
|
67
|
-
PR created
|
|
127
|
+
@kody
|
|
68
128
|
```
|
|
69
129
|
|
|
70
|
-
|
|
130
|
+
### Switch to a different model (optional)
|
|
71
131
|
|
|
72
|
-
|
|
132
|
+
Add `litellm-config.yaml` to route all tiers through MiniMax (or any LLM):
|
|
133
|
+
|
|
134
|
+
```yaml
|
|
135
|
+
# litellm-config.yaml
|
|
136
|
+
model_list:
|
|
137
|
+
- model_name: claude-haiku-4-5-20251001
|
|
138
|
+
litellm_params:
|
|
139
|
+
model: minimax/MiniMax-M2.7-highspeed
|
|
140
|
+
api_key: os.environ/MINIMAX_API_KEY
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
```json
|
|
144
|
+
// kody.config.json — add litellmUrl
|
|
145
|
+
{ "agent": { "litellmUrl": "http://localhost:4000" } }
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Kody auto-starts the proxy and loads API keys from `.env`. [Full LiteLLM guide →](docs/LITELLM.md)
|
|
73
149
|
|
|
74
150
|
## Commands
|
|
75
151
|
|
|
76
152
|
### GitHub Comments
|
|
77
153
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
154
|
+
| Command | What it does |
|
|
155
|
+
|---------|-------------|
|
|
156
|
+
| `@kody` | Run full pipeline |
|
|
157
|
+
| `@kody approve` | Resume after questions or risk gate |
|
|
158
|
+
| `@kody fix` | Re-run from build stage. Write feedback in the comment body — it gets injected into the build prompt |
|
|
159
|
+
| `@kody rerun` | Resume from the failed or paused stage |
|
|
160
|
+
| `@kody rerun --from <stage>` | Resume from a specific stage |
|
|
84
161
|
|
|
85
162
|
### CLI
|
|
86
163
|
|
|
@@ -95,20 +172,20 @@ kody-engine-lite init [--force]
|
|
|
95
172
|
|
|
96
173
|
## Key Features
|
|
97
174
|
|
|
175
|
+
- **Shared Sessions** — stages in the same group share a Claude Code session, eliminating cold-start codebase re-exploration ([details](docs/FEATURES.md#shared-sessions))
|
|
98
176
|
- **Risk Gate** — HIGH-risk tasks pause for human plan approval before building ([details](docs/FEATURES.md#risk-gate))
|
|
99
177
|
- **AI Failure Diagnosis** — classifies errors as fixable/infrastructure/pre-existing/abort before retry ([details](docs/FEATURES.md#ai-powered-failure-diagnosis))
|
|
100
178
|
- **Question Gates** — asks product/architecture questions when the task is unclear ([details](docs/FEATURES.md#question-gates))
|
|
179
|
+
- **Any LLM** — route through LiteLLM to use MiniMax, GPT, Gemini, local models ([setup guide](docs/LITELLM.md))
|
|
101
180
|
- **Retrospective** — analyzes each run, identifies patterns, suggests improvements ([details](docs/FEATURES.md#retrospective-system))
|
|
102
181
|
- **Auto-Learning** — extracts coding conventions from each successful run ([details](docs/FEATURES.md#auto-learning-memory))
|
|
103
|
-
- **Accumulated Context** — each stage passes curated context to the next — fresh window, shared knowledge ([details](docs/FEATURES.md#accumulated-context))
|
|
104
|
-
- **Any LLM** — route through LiteLLM to use MiniMax, GPT, Gemini, local models ([setup guide](docs/LITELLM.md))
|
|
105
182
|
|
|
106
183
|
## Documentation
|
|
107
184
|
|
|
108
185
|
| Doc | What's in it |
|
|
109
186
|
|-----|-------------|
|
|
110
|
-
| [Pipeline](docs/PIPELINE.md) | Stage details, complexity skipping, artifacts
|
|
111
|
-
| [Features](docs/FEATURES.md) | Risk gate, diagnosis, retrospective, auto-learn, labels |
|
|
187
|
+
| [Pipeline](docs/PIPELINE.md) | Stage details, shared sessions, complexity skipping, artifacts |
|
|
188
|
+
| [Features](docs/FEATURES.md) | Risk gate, diagnosis, sessions, retrospective, auto-learn, labels |
|
|
112
189
|
| [LiteLLM](docs/LITELLM.md) | Non-Anthropic model setup, auto-start, tested providers |
|
|
113
190
|
| [Configuration](docs/CONFIGURATION.md) | Full config reference, env vars, workflow setup |
|
|
114
191
|
| [Comparison](docs/COMPARISON.md) | vs Copilot, Devin, Cursor, Cline, SWE-agent, OpenHands |
|
package/dist/bin/cli.js
CHANGED
|
@@ -87,20 +87,22 @@ function checkCommand(command2, args2) {
|
|
|
87
87
|
function createClaudeCodeRunner() {
|
|
88
88
|
return {
|
|
89
89
|
async run(_stageName, prompt, model, timeout, _taskDir, options) {
|
|
90
|
-
|
|
91
|
-
"
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
90
|
+
const args2 = [
|
|
91
|
+
"--print",
|
|
92
|
+
"--model",
|
|
93
|
+
model,
|
|
94
|
+
"--dangerously-skip-permissions",
|
|
95
|
+
"--allowedTools",
|
|
96
|
+
"Bash,Edit,Read,Write,Glob,Grep"
|
|
97
|
+
];
|
|
98
|
+
if (options?.sessionId) {
|
|
99
|
+
if (options.resumeSession) {
|
|
100
|
+
args2.push("--resume", options.sessionId);
|
|
101
|
+
} else {
|
|
102
|
+
args2.push("--session-id", options.sessionId);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return runSubprocess("claude", args2, prompt, timeout, options);
|
|
104
106
|
},
|
|
105
107
|
async healthCheck() {
|
|
106
108
|
return checkCommand("claude", ["--version"]);
|
|
@@ -824,6 +826,17 @@ var init_runner_selection = __esm({
|
|
|
824
826
|
// src/stages/agent.ts
|
|
825
827
|
import * as fs5 from "fs";
|
|
826
828
|
import * as path5 from "path";
|
|
829
|
+
function getSessionInfo(stageName, sessions) {
|
|
830
|
+
const group = SESSION_GROUP[stageName];
|
|
831
|
+
if (!group) return void 0;
|
|
832
|
+
const existing = sessions[group];
|
|
833
|
+
if (existing) {
|
|
834
|
+
return { sessionId: existing, resumeSession: true };
|
|
835
|
+
}
|
|
836
|
+
const newId = crypto.randomUUID();
|
|
837
|
+
sessions[group] = newId;
|
|
838
|
+
return { sessionId: newId, resumeSession: false };
|
|
839
|
+
}
|
|
827
840
|
function validateStageOutput(stageName, content) {
|
|
828
841
|
switch (stageName) {
|
|
829
842
|
case "taskify":
|
|
@@ -850,10 +863,16 @@ async function executeAgentStage(ctx, def) {
|
|
|
850
863
|
if (config.agent.litellmUrl) {
|
|
851
864
|
extraEnv.ANTHROPIC_BASE_URL = config.agent.litellmUrl;
|
|
852
865
|
}
|
|
866
|
+
const sessions = ctx.sessions ?? {};
|
|
867
|
+
const sessionInfo = getSessionInfo(def.name, sessions);
|
|
868
|
+
if (sessionInfo) {
|
|
869
|
+
logger.info(` session: ${SESSION_GROUP[def.name]} (${sessionInfo.resumeSession ? "resume" : "new"})`);
|
|
870
|
+
}
|
|
853
871
|
const runner = getRunnerForStage(ctx, def.name);
|
|
854
872
|
const result = await runner.run(def.name, prompt, model, def.timeout, ctx.taskDir, {
|
|
855
873
|
cwd: ctx.projectDir,
|
|
856
|
-
env: extraEnv
|
|
874
|
+
env: extraEnv,
|
|
875
|
+
...sessionInfo
|
|
857
876
|
});
|
|
858
877
|
if (result.outcome !== "completed") {
|
|
859
878
|
return { outcome: result.outcome, error: result.error, retries: 0 };
|
|
@@ -924,6 +943,7 @@ ${summary}
|
|
|
924
943
|
`;
|
|
925
944
|
fs5.appendFileSync(contextPath, entry);
|
|
926
945
|
}
|
|
946
|
+
var SESSION_GROUP;
|
|
927
947
|
var init_agent = __esm({
|
|
928
948
|
"src/stages/agent.ts"() {
|
|
929
949
|
"use strict";
|
|
@@ -932,6 +952,14 @@ var init_agent = __esm({
|
|
|
932
952
|
init_config();
|
|
933
953
|
init_runner_selection();
|
|
934
954
|
init_logger();
|
|
955
|
+
SESSION_GROUP = {
|
|
956
|
+
taskify: "explore",
|
|
957
|
+
plan: "explore",
|
|
958
|
+
build: "build",
|
|
959
|
+
autofix: "build",
|
|
960
|
+
"review-fix": "build",
|
|
961
|
+
review: "review"
|
|
962
|
+
};
|
|
935
963
|
}
|
|
936
964
|
});
|
|
937
965
|
|
|
@@ -1006,6 +1034,7 @@ function runQualityGates(taskDir, projectRoot) {
|
|
|
1006
1034
|
const cwd = projectRoot ?? process.cwd();
|
|
1007
1035
|
const allErrors = [];
|
|
1008
1036
|
const allSummary = [];
|
|
1037
|
+
const rawOutputs = [];
|
|
1009
1038
|
let allPass = true;
|
|
1010
1039
|
const commands = [
|
|
1011
1040
|
{ name: "typecheck", cmd: config.quality.typecheck },
|
|
@@ -1027,10 +1056,11 @@ function runQualityGates(taskDir, projectRoot) {
|
|
|
1027
1056
|
allPass = false;
|
|
1028
1057
|
const errors = parseErrors(result.output);
|
|
1029
1058
|
allErrors.push(...errors.map((e) => `[${name}] ${e}`));
|
|
1059
|
+
rawOutputs.push({ name, output: result.output.slice(-3e3) });
|
|
1030
1060
|
}
|
|
1031
1061
|
allSummary.push(...extractSummary(result.output, name));
|
|
1032
1062
|
}
|
|
1033
|
-
return { pass: allPass, errors: allErrors, summary: allSummary };
|
|
1063
|
+
return { pass: allPass, errors: allErrors, summary: allSummary, rawOutputs };
|
|
1034
1064
|
}
|
|
1035
1065
|
var init_verify_runner = __esm({
|
|
1036
1066
|
"src/verify-runner.ts"() {
|
|
@@ -1162,6 +1192,18 @@ function executeGateStage(ctx, def) {
|
|
|
1162
1192
|
`);
|
|
1163
1193
|
for (const s of verifyResult.summary) {
|
|
1164
1194
|
lines.push(`- ${s}
|
|
1195
|
+
`);
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
if (verifyResult.rawOutputs.length > 0) {
|
|
1199
|
+
lines.push(`
|
|
1200
|
+
## Raw Output
|
|
1201
|
+
`);
|
|
1202
|
+
for (const { name, output } of verifyResult.rawOutputs) {
|
|
1203
|
+
lines.push(`### ${name}
|
|
1204
|
+
\`\`\`
|
|
1205
|
+
${output}
|
|
1206
|
+
\`\`\`
|
|
1165
1207
|
`);
|
|
1166
1208
|
}
|
|
1167
1209
|
}
|
|
@@ -2072,6 +2114,7 @@ async function runPipelineInner(ctx) {
|
|
|
2072
2114
|
state = initState(ctx.taskId);
|
|
2073
2115
|
writeState(state, ctx.taskDir);
|
|
2074
2116
|
}
|
|
2117
|
+
ctx.sessions = state.sessions ?? {};
|
|
2075
2118
|
if (state.state !== "running") {
|
|
2076
2119
|
state.state = "running";
|
|
2077
2120
|
for (const stage of STAGES) {
|
|
@@ -2159,6 +2202,7 @@ async function runPipelineInner(ctx) {
|
|
|
2159
2202
|
error: isTimeout ? "Stage timed out" : result.error ?? "Stage failed"
|
|
2160
2203
|
};
|
|
2161
2204
|
state.state = "failed";
|
|
2205
|
+
state.sessions = ctx.sessions;
|
|
2162
2206
|
writeState(state, ctx.taskDir);
|
|
2163
2207
|
logger.error(`[${def.name}] ${isTimeout ? "\u23F1 timed out" : `\u2717 failed: ${result.error}`}`);
|
|
2164
2208
|
if (ctx.input.issueNumber && !ctx.input.local) {
|
|
@@ -2166,6 +2210,7 @@ async function runPipelineInner(ctx) {
|
|
|
2166
2210
|
}
|
|
2167
2211
|
break;
|
|
2168
2212
|
}
|
|
2213
|
+
state.sessions = ctx.sessions;
|
|
2169
2214
|
writeState(state, ctx.taskDir);
|
|
2170
2215
|
}
|
|
2171
2216
|
const allCompleted = STAGES.every((s) => state.stages[s.name].state === "completed");
|