@kody-ade/kody-engine-lite 0.1.27 → 0.1.29
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 +81 -37
- package/dist/bin/cli.js +74 -16
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,24 +2,93 @@
|
|
|
2
2
|
|
|
3
3
|
**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.
|
|
4
4
|
|
|
5
|
+
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 self-improving memory.
|
|
6
|
+
|
|
7
|
+
## Pipeline
|
|
8
|
+
|
|
5
9
|
```
|
|
6
|
-
|
|
10
|
+
┌─────────────────────────────────────────────────────────┐
|
|
11
|
+
│ @kody on issue │
|
|
12
|
+
└────────────────────────┬────────────────────────────────┘
|
|
13
|
+
│
|
|
14
|
+
┌────────────────────────▼────────────────────────────────┐
|
|
15
|
+
│ ① TASKIFY │
|
|
16
|
+
│ Classify task, detect complexity, ask questions │
|
|
17
|
+
│ Model: haiku │ Output: task.json │
|
|
18
|
+
└────────────────────────┬────────────────────────────────┘
|
|
19
|
+
│
|
|
20
|
+
┌────────────▼────────────┐
|
|
21
|
+
│ LOW? skip to ④ │
|
|
22
|
+
│ MEDIUM? continue │
|
|
23
|
+
│ HIGH? continue │
|
|
24
|
+
└────────────┬────────────┘
|
|
25
|
+
│
|
|
26
|
+
┌────────────────────────▼────────────────────────────────┐
|
|
27
|
+
│ ② PLAN │
|
|
28
|
+
│ TDD implementation plan (deep reasoning) │
|
|
29
|
+
│ Model: opus │ Output: plan.md │
|
|
30
|
+
└────────────────────────┬────────────────────────────────┘
|
|
31
|
+
│
|
|
32
|
+
┌────────────▼────────────┐
|
|
33
|
+
│ HIGH risk? │
|
|
34
|
+
│ 🛑 Pause for approval │──── @kody approve
|
|
35
|
+
└────────────┬────────────┘
|
|
36
|
+
│
|
|
37
|
+
┌────────────────────────▼────────────────────────────────┐
|
|
38
|
+
│ ③ BUILD │
|
|
39
|
+
│ Implement code via Claude Code tools │
|
|
40
|
+
│ Model: sonnet │ Output: code changes + git commit │
|
|
41
|
+
└────────────────────────┬────────────────────────────────┘
|
|
42
|
+
│
|
|
43
|
+
┌────────────────────────▼────────────────────────────────┐
|
|
44
|
+
│ ④ VERIFY │
|
|
45
|
+
│ typecheck + tests + lint │
|
|
46
|
+
│ ┌──────────────────────────────────────────────┐ │
|
|
47
|
+
│ │ Fail? → AI diagnosis → autofix → retry ×2 │ │
|
|
48
|
+
│ └──────────────────────────────────────────────┘ │
|
|
49
|
+
└────────────────────────┬────────────────────────────────┘
|
|
50
|
+
│
|
|
51
|
+
┌────────────────────────▼────────────────────────────────┐
|
|
52
|
+
│ ⑤ REVIEW │
|
|
53
|
+
│ Code review: PASS/FAIL + Critical/Major/Minor │
|
|
54
|
+
│ Model: opus │ Output: review.md │
|
|
55
|
+
└────────────────────────┬────────────────────────────────┘
|
|
56
|
+
│
|
|
57
|
+
┌────────────────────────▼────────────────────────────────┐
|
|
58
|
+
│ ⑥ REVIEW-FIX │
|
|
59
|
+
│ Fix Critical and Major findings │
|
|
60
|
+
│ Model: sonnet │ Output: code changes + git commit │
|
|
61
|
+
└────────────────────────┬────────────────────────────────┘
|
|
62
|
+
│
|
|
63
|
+
┌────────────────────────▼────────────────────────────────┐
|
|
64
|
+
│ ⑦ SHIP │
|
|
65
|
+
│ Push branch + create PR with Closes #N │
|
|
66
|
+
│ Output: ship.md + PR link │
|
|
67
|
+
└────────────────────────┬────────────────────────────────┘
|
|
68
|
+
│
|
|
69
|
+
┌────────────────────────▼────────────────────────────────┐
|
|
70
|
+
│ ✅ PR created & ready for review │
|
|
71
|
+
└─────────────────────────────────────────────────────────┘
|
|
7
72
|
```
|
|
8
73
|
|
|
9
|
-
|
|
74
|
+
Each stage runs in a **fresh context window** with **accumulated context** from previous stages — so complex tasks (auth systems, CRUD features, API clients) don't lose track of earlier decisions.
|
|
75
|
+
|
|
76
|
+
[Pipeline details →](docs/PIPELINE.md)
|
|
10
77
|
|
|
11
78
|
## Why Kody?
|
|
12
79
|
|
|
13
|
-
Most AI coding tools are **autocomplete** (Copilot) or **chat-based** (Cursor, Cline). You still drive. Kody is different: it's an **autonomous pipeline** that takes an issue and delivers a tested, reviewed PR.
|
|
80
|
+
Most AI coding tools are **autocomplete** (Copilot) or **chat-based** (Cursor, Cline). You still drive. Kody is different: it's an **autonomous pipeline** that takes an issue and delivers a tested, reviewed PR — even for complex, multi-file features that single-agent tools choke on.
|
|
14
81
|
|
|
15
82
|
| | Kody | Copilot Workspace | Devin | Cursor Agent |
|
|
16
83
|
|---|---|---|---|---|
|
|
17
84
|
| **Runs in CI** | GitHub Actions | GitHub Cloud | Devin Cloud | Local IDE |
|
|
18
85
|
| **Fire and forget** | Comment `@kody`, walk away | Must interact | Must interact | Must be open |
|
|
19
86
|
| **Quality gates** | typecheck + tests + lint + AI diagnosis + auto-retry | Basic | Runs tests | Runs tests |
|
|
20
|
-
| **Risk gate** | Pauses HIGH-risk
|
|
87
|
+
| **Risk gate** | Pauses HIGH-risk for human approval | No | No | No |
|
|
21
88
|
| **Model flexible** | Any LLM via LiteLLM | GitHub models only | Proprietary | Cursor models |
|
|
22
89
|
| **Open source** | MIT | Proprietary | Proprietary | Proprietary |
|
|
90
|
+
| **Accumulated context** | Curated context flows between stages | Single bloated conversation | Single agent | Single agent |
|
|
91
|
+
| **Complex tasks** | Full auth system: 7 stages + 3 autofix retries | Struggles with large scope | Better | Struggles with large scope |
|
|
23
92
|
| **Cost** | Your API costs only | $10-39/month | $20-500/month | Subscription |
|
|
24
93
|
|
|
25
94
|
[Full comparison →](docs/COMPARISON.md)
|
|
@@ -30,48 +99,22 @@ Most AI coding tools are **autocomplete** (Copilot) or **chat-based** (Cursor, C
|
|
|
30
99
|
# 1. Install
|
|
31
100
|
npm install -g @kody-ade/kody-engine-lite
|
|
32
101
|
|
|
33
|
-
# 2.
|
|
34
|
-
cd your-project
|
|
35
|
-
kody-engine-lite init
|
|
36
|
-
|
|
37
|
-
# 3. Set up GitHub
|
|
102
|
+
# 2. Set up GitHub secret
|
|
38
103
|
gh secret set ANTHROPIC_API_KEY --repo owner/repo
|
|
39
104
|
# Settings → Actions → "Allow GitHub Actions to create and approve pull requests"
|
|
40
105
|
|
|
41
|
-
#
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
git push
|
|
106
|
+
# 3. Initialize (auto-detects, commits, and pushes)
|
|
107
|
+
cd your-project
|
|
108
|
+
kody-engine-lite init
|
|
45
109
|
|
|
46
|
-
#
|
|
110
|
+
# 4. Comment on any issue
|
|
47
111
|
@kody
|
|
48
112
|
```
|
|
49
113
|
|
|
50
|
-
`init` spawns Claude Code to analyze your project and generates: workflow file, config with auto-detected quality commands, project memory (architecture + conventions),
|
|
114
|
+
`init` spawns Claude Code to analyze your project and generates: workflow file, config with auto-detected quality commands, project memory (architecture + conventions), 14 GitHub labels — then commits and pushes everything.
|
|
51
115
|
|
|
52
116
|
**Prerequisites:** Node.js >= 22, [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code), [GitHub CLI](https://cli.github.com/), git
|
|
53
117
|
|
|
54
|
-
## Pipeline
|
|
55
|
-
|
|
56
|
-
```
|
|
57
|
-
@kody on issue
|
|
58
|
-
↓
|
|
59
|
-
1. taskify — classify task, detect complexity, ask questions → task.json
|
|
60
|
-
2. plan — TDD implementation plan (deep reasoning) → plan.md
|
|
61
|
-
↓ HIGH risk? pause for human approval
|
|
62
|
-
3. build — implement code via Claude Code tools → code changes
|
|
63
|
-
4. verify — typecheck + tests + lint (AI diagnosis + autofix) → verify.md
|
|
64
|
-
5. review — code review: PASS/FAIL + Critical/Major/Minor → review.md
|
|
65
|
-
6. review-fix — fix Critical and Major findings → code changes
|
|
66
|
-
7. ship — push branch + create PR with Closes #N → ship.md
|
|
67
|
-
↓
|
|
68
|
-
PR created
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Complexity auto-detected: **low** skips plan/review (4 stages), **medium** skips review-fix (6 stages), **high** runs all 7.
|
|
72
|
-
|
|
73
|
-
[Pipeline details →](docs/PIPELINE.md)
|
|
74
|
-
|
|
75
118
|
## Commands
|
|
76
119
|
|
|
77
120
|
### GitHub Comments
|
|
@@ -99,6 +142,7 @@ kody-engine-lite init [--force]
|
|
|
99
142
|
- **Risk Gate** — HIGH-risk tasks pause for human plan approval before building ([details](docs/FEATURES.md#risk-gate))
|
|
100
143
|
- **AI Failure Diagnosis** — classifies errors as fixable/infrastructure/pre-existing/abort before retry ([details](docs/FEATURES.md#ai-powered-failure-diagnosis))
|
|
101
144
|
- **Question Gates** — asks product/architecture questions when the task is unclear ([details](docs/FEATURES.md#question-gates))
|
|
145
|
+
- **Accumulated Context** — each stage passes curated context to the next — fresh window, shared knowledge ([details](docs/FEATURES.md#accumulated-context))
|
|
102
146
|
- **Retrospective** — analyzes each run, identifies patterns, suggests improvements ([details](docs/FEATURES.md#retrospective-system))
|
|
103
147
|
- **Auto-Learning** — extracts coding conventions from each successful run ([details](docs/FEATURES.md#auto-learning-memory))
|
|
104
148
|
- **Any LLM** — route through LiteLLM to use MiniMax, GPT, Gemini, local models ([setup guide](docs/LITELLM.md))
|
|
@@ -107,7 +151,7 @@ kody-engine-lite init [--force]
|
|
|
107
151
|
|
|
108
152
|
| Doc | What's in it |
|
|
109
153
|
|-----|-------------|
|
|
110
|
-
| [Pipeline](docs/PIPELINE.md) | Stage details, complexity skipping,
|
|
154
|
+
| [Pipeline](docs/PIPELINE.md) | Stage details, complexity skipping, accumulated context, artifacts |
|
|
111
155
|
| [Features](docs/FEATURES.md) | Risk gate, diagnosis, retrospective, auto-learn, labels |
|
|
112
156
|
| [LiteLLM](docs/LITELLM.md) | Non-Anthropic model setup, auto-start, tested providers |
|
|
113
157
|
| [Configuration](docs/CONFIGURATION.md) | Full config reference, env vars, workflow setup |
|
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
|
|
|
@@ -2072,6 +2100,7 @@ async function runPipelineInner(ctx) {
|
|
|
2072
2100
|
state = initState(ctx.taskId);
|
|
2073
2101
|
writeState(state, ctx.taskDir);
|
|
2074
2102
|
}
|
|
2103
|
+
ctx.sessions = state.sessions ?? {};
|
|
2075
2104
|
if (state.state !== "running") {
|
|
2076
2105
|
state.state = "running";
|
|
2077
2106
|
for (const stage of STAGES) {
|
|
@@ -2159,6 +2188,7 @@ async function runPipelineInner(ctx) {
|
|
|
2159
2188
|
error: isTimeout ? "Stage timed out" : result.error ?? "Stage failed"
|
|
2160
2189
|
};
|
|
2161
2190
|
state.state = "failed";
|
|
2191
|
+
state.sessions = ctx.sessions;
|
|
2162
2192
|
writeState(state, ctx.taskDir);
|
|
2163
2193
|
logger.error(`[${def.name}] ${isTimeout ? "\u23F1 timed out" : `\u2717 failed: ${result.error}`}`);
|
|
2164
2194
|
if (ctx.input.issueNumber && !ctx.input.local) {
|
|
@@ -2166,6 +2196,7 @@ async function runPipelineInner(ctx) {
|
|
|
2166
2196
|
}
|
|
2167
2197
|
break;
|
|
2168
2198
|
}
|
|
2199
|
+
state.sessions = ctx.sessions;
|
|
2169
2200
|
writeState(state, ctx.taskDir);
|
|
2170
2201
|
}
|
|
2171
2202
|
const allCompleted = STAGES.every((s) => state.stages[s.name].state === "completed");
|
|
@@ -3307,12 +3338,39 @@ ${archItems.join("\n")}
|
|
|
3307
3338
|
fs19.writeFileSync(conventionsPath, "# Conventions\n\n<!-- Auto-learned conventions will be appended here -->\n");
|
|
3308
3339
|
console.log(" \u2713 .kody/memory/conventions.md (seed)");
|
|
3309
3340
|
}
|
|
3341
|
+
console.log("\n\u2500\u2500 Git \u2500\u2500");
|
|
3342
|
+
const filesToCommit = [
|
|
3343
|
+
".github/workflows/kody.yml",
|
|
3344
|
+
"kody.config.json",
|
|
3345
|
+
".kody/memory/architecture.md",
|
|
3346
|
+
".kody/memory/conventions.md"
|
|
3347
|
+
].filter((f) => fs19.existsSync(path18.join(cwd, f)));
|
|
3348
|
+
if (filesToCommit.length > 0) {
|
|
3349
|
+
try {
|
|
3350
|
+
execFileSync11("git", ["add", ...filesToCommit], { cwd, stdio: "pipe" });
|
|
3351
|
+
const staged = execFileSync11("git", ["diff", "--cached", "--name-only"], { cwd, encoding: "utf-8" }).trim();
|
|
3352
|
+
if (staged) {
|
|
3353
|
+
execFileSync11("git", ["commit", "--no-gpg-sign", "-m", "chore: add kody engine"], { cwd, stdio: "pipe" });
|
|
3354
|
+
console.log(` \u2713 Committed: ${filesToCommit.join(", ")}`);
|
|
3355
|
+
try {
|
|
3356
|
+
execFileSync11("git", ["push"], { cwd, stdio: "pipe", timeout: 3e4 });
|
|
3357
|
+
console.log(" \u2713 Pushed to origin");
|
|
3358
|
+
} catch {
|
|
3359
|
+
console.log(" \u25CB Push failed \u2014 run 'git push' manually");
|
|
3360
|
+
}
|
|
3361
|
+
} else {
|
|
3362
|
+
console.log(" \u25CB No new changes to commit");
|
|
3363
|
+
}
|
|
3364
|
+
} catch (err) {
|
|
3365
|
+
console.log(` \u25CB Git commit skipped: ${err instanceof Error ? err.message : err}`);
|
|
3366
|
+
}
|
|
3367
|
+
}
|
|
3310
3368
|
const allChecks = [...checks, ghAuth, ghRepo];
|
|
3311
3369
|
const failed = allChecks.filter((c) => !c.ok);
|
|
3312
3370
|
console.log("\n\u2500\u2500 Summary \u2500\u2500");
|
|
3313
3371
|
if (failed.length === 0) {
|
|
3314
3372
|
console.log(" \u2713 All checks passed! Ready to use.");
|
|
3315
|
-
console.log("\n Next: Comment '@kody
|
|
3373
|
+
console.log("\n Next: Comment '@kody' on a GitHub issue");
|
|
3316
3374
|
} else {
|
|
3317
3375
|
console.log(` \u26A0 ${failed.length} issue(s) to fix:`);
|
|
3318
3376
|
for (const c of failed) {
|