270 lines
10 KiB
Markdown
270 lines
10 KiB
Markdown
# kilocode-loop
|
|
|
|
Goal-driven autonomous loop runner for the **Kilo CLI** (`kilo run`), with a live
|
|
Express dashboard, per-iteration reports (tokens / cost / context / topic / % /
|
|
next stage), streamed section headings for every action, terminal controls and
|
|
human-in-the-loop between sessions.
|
|
|
|
It is a self-contained mini-app: one Node process spawns `kilo run --format json`
|
|
for every iteration, parses the event stream, and turns the agent's own
|
|
`progress.json` into the operator report.
|
|
|
|
```
|
|
┌─ loop ──────────────────────────────────────────────────────────────────┐
|
|
│ for i in 1..N: │
|
|
│ ┌─ section: Iteration i/N — <stage> ───────────────────────────────┐ │
|
|
│ │ ▸ Read src/foo.vue (tool → section heading) │ │
|
|
│ │ ▸ Edit src/foo.vue │ │
|
|
│ │ ▸ Run pnpm typecheck │ │
|
|
│ └────────────────────────────────────────────────────────────────┘ │
|
|
│ report: tokens · cost · context · topic · % · next stage │
|
|
│ human-in-the-loop: ask the operator if the agent needs a decision │
|
|
└─────────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
## Requirements
|
|
|
|
- Node.js ≥ 20 (developed on Node 24)
|
|
- The Kilo CLI on `PATH` (`kilo` / `kilocode`), authenticated
|
|
- A git repository to work in (the agent never commits)
|
|
|
|
```bash
|
|
npm install
|
|
```
|
|
|
|
## Quick start
|
|
|
|
### Installed as a submodule (recommended)
|
|
|
|
The launcher resolves the git root of the current directory, installs
|
|
`node_modules` on first use, and picks up `<repo>/.kilocode-loop/goal.json` when
|
|
no goal is passed:
|
|
|
|
```bash
|
|
# from anywhere inside the repo (or a submodule — it scopes to that repo)
|
|
tools/kilocode-loop/kilo-loop # uses .kilocode-loop/goal.json, 5 iterations
|
|
tools/kilocode-loop/kilo-loop -n 3 # override the iteration count
|
|
tools/kilocode-loop/kilo-loop --goal plans/another-goal.md
|
|
tools/kilocode-loop/kilo-loop --dry-run # offline rehearsal
|
|
|
|
# same command from anywhere, once the launcher is on PATH
|
|
kilo-loop --goal plans/another-goal.md -n 5
|
|
```
|
|
|
|
Per-repo defaults live in `<repo>/.kilocode-loop/config.json` (agent, iterations,
|
|
session mode, HITL, port, context threshold). The goal lives in
|
|
`<repo>/.kilocode-loop/goal.json` — edit it, or point `--goal` somewhere else.
|
|
|
|
### Standalone
|
|
|
|
```bash
|
|
npm install
|
|
|
|
# Real run: 5 iterations of the code-design agent against ./your-repo
|
|
node bin/kilocode-loop.mjs \
|
|
--goal /path/to/your-repo/.kilocode-loop/goal.json \
|
|
-n 5 \
|
|
--project /path/to/your-repo \
|
|
--agent code-design \
|
|
--port 7999
|
|
|
|
# Offline rehearsal: no API calls, exercises the loop, reports, dashboard and HITL
|
|
node bin/kilocode-loop.mjs --dry-run \
|
|
--goal examples/goal.example.json -n 5 --project /tmp/demo --port 7999
|
|
```
|
|
|
|
Then open the dashboard at <http://127.0.0.1:7999>.
|
|
|
|
## Controls
|
|
|
|
| Where | Key / button | Effect |
|
|
| --- | --- | --- |
|
|
| Terminal | `X` | Abort the loop **after** the current session finishes |
|
|
| Terminal | `P` | Pause / resume before the next iteration |
|
|
| Terminal | `Q` | Stop **now** (kills the current `kilo` session) |
|
|
| Terminal | `?` | Print shortcut help |
|
|
| Terminal | typing + `Enter` | Answer a pending question (number keys pick an option) |
|
|
| Dashboard | Pause / Abort after session / Stop now | Same controls from the browser |
|
|
| Dashboard | question modal | Answer the pending questions; answers go into the next session |
|
|
|
|
## How a report is produced
|
|
|
|
Each iteration the runner writes a prompt that embeds a **contract**: at the end
|
|
of the session the agent must write `<project>/.kilocode-loop/progress.json`:
|
|
|
|
```json
|
|
{
|
|
"iteration": 2,
|
|
"topic": "Rework SettingsByokSection",
|
|
"stageId": "stage-2",
|
|
"stageStatus": "in_progress",
|
|
"percent": 40,
|
|
"nextStage": "Verify layout and dark theme",
|
|
"summary": "Replaced the card grid with a q-select + config panel. Typecheck passes.",
|
|
"filesChanged": ["src/components/settings/SettingsByokSection.vue"],
|
|
"needsInput": false,
|
|
"questions": []
|
|
}
|
|
```
|
|
|
|
From that + the CLI event stream the runner derives:
|
|
|
|
- **iteration number** — loop counter
|
|
- **tokens / cost** — summed from every `step_finish` event
|
|
- **context size** — `tokens.total` of the last step (how full the window is)
|
|
- **topic** — `progress.topic`
|
|
- **% complete** — `progress.percent`, or the ratio of completed goal stages
|
|
- **next stage** — `progress.nextStage`, or the first not-done stage
|
|
- **files changed** — git delta since the iteration started, plus `filesChanged`
|
|
|
|
If the agent forgets the contract, the runner falls back to the goal stages and
|
|
scrapes question-looking lines out of the agent's text.
|
|
|
|
### Reports on disk
|
|
|
|
```
|
|
<project>/.kilocode-loop/
|
|
progress.json # the agent's machine-readable report
|
|
answers.json # operator answers from HITL
|
|
runs/<runId>/
|
|
state.json # full run state (for the dashboard)
|
|
events.jsonl # every log line
|
|
report.md # end-of-run summary
|
|
iterations/
|
|
01-prompt.md # exact prompt sent
|
|
01-report.json
|
|
01-report.md
|
|
```
|
|
|
|
## Goal files
|
|
|
|
`--goal-text "..."` — a single implicit stage.
|
|
|
|
`--goal file.json`:
|
|
|
|
```json
|
|
{
|
|
"title": "Stabilise the workflows module",
|
|
"description": "…",
|
|
"stages": [{ "id": "stage-1", "title": "Remove legacy libs", "details": "…" }]
|
|
}
|
|
```
|
|
|
|
`--goal file.md` — the first `#` heading is the title, each `- [ ]` / `- [x]`
|
|
item is a stage:
|
|
|
|
```markdown
|
|
# Stabilise the workflows module
|
|
|
|
- [ ] Remove legacy libs
|
|
- [x] Rewire the builder
|
|
```
|
|
|
|
## CLI reference
|
|
|
|
```
|
|
Goal
|
|
--goal <file> .json goal or .md checklist
|
|
--goal-text "<text>" inline goal
|
|
-n, --iterations <N> loop count (default 5)
|
|
|
|
Execution
|
|
-C, --project <dir> repository the agent works in (default cwd)
|
|
-a, --agent <name> Kilo agent (default code-design)
|
|
-m, --model <id> model override (provider/model)
|
|
--variant <name> reasoning variant (e.g. high, max)
|
|
--thinking capture reasoning parts
|
|
--auto / --no-auto auto-approve permissions (default: auto)
|
|
--session-mode <mode> continue (one growing session) | fresh
|
|
--hitl <mode> always | on-question | off
|
|
--max-iteration-minutes <n>
|
|
--context-warn-tokens <n>
|
|
--prompt-extra <file> extra instructions for every iteration
|
|
|
|
Dashboard
|
|
-p, --port <n> default 7999
|
|
--host <host> default 127.0.0.1
|
|
--keep-open keep the dashboard after the loop
|
|
|
|
Utility
|
|
--dry-run simulate the agent (no API calls)
|
|
--resume <runId> reuse a previous run's session + stage progress
|
|
--run-id <id>
|
|
--quiet suppress the live console stream
|
|
--no-color
|
|
```
|
|
|
|
Config can also live in `<project>/.kilocode-loop/config.json` (CLI wins).
|
|
|
|
## Dashboard API
|
|
|
|
| Method | Path | Purpose |
|
|
| --- | --- | --- |
|
|
| `GET` | `/api/state` | Current run snapshot |
|
|
| `GET` | `/api/events` | SSE stream (`state` + `log` messages) |
|
|
| `GET` | `/api/runs` | List saved runs |
|
|
| `GET` | `/api/runs/:id` | Load a saved run (with its log) |
|
|
| `GET` | `/api/runs/:id/report/:iter` | Iteration report (markdown) |
|
|
| `POST` | `/api/control` | `{ "action": "pause"\|"resume"\|"abort-after-current"\|"stop" }` |
|
|
| `POST` | `/api/answer` | `{ "answers": [{ "question": "…", "answer": "…" }] }` |
|
|
|
|
## How it drives the Kilo CLI
|
|
|
|
`kilo run --format json` emits one JSON object per line:
|
|
|
|
```jsonc
|
|
{"type":"step_start","timestamp":…,"sessionID":"…","part":{…}}
|
|
{"type":"tool_use","part":{"tool":"edit","state":{"status":"completed","input":{…}}}}
|
|
{"type":"text","part":{"type":"text","text":"…"}}
|
|
{"type":"step_finish","part":{"cost":0.0021,"tokens":{"total":14411,"input":14025,"output":2,"reasoning":0,"cache":{"read":384,"write":0}}}}
|
|
{"type":"error","error":…}
|
|
```
|
|
|
|
- The runner captures `sessionID` from the first event and passes
|
|
`--session <id>` on later iterations, so `--session-mode continue` keeps one
|
|
growing context (and `--session-mode fresh` starts a new one each time).
|
|
- Unattended runs need `--auto`: without it, non-interactive permission requests
|
|
are auto-rejected by the CLI ("pass --auto for autonomous use"). `--auto` is on
|
|
by default; deny destructive permissions in the project `kilo.json` if needed.
|
|
- `--thinking` is required for `reasoning` events to be emitted.
|
|
|
|
## Safety
|
|
|
|
- The runner never commits or pushes; the agent is instructed not to either.
|
|
- `--auto` approves permissions the project does not explicitly deny — review
|
|
`kilo.json` / `.kilo` permissions before unattended runs.
|
|
- `--dry-run` performs no API calls and no file changes (beyond its own
|
|
`progress.json`).
|
|
|
|
## Adding it to the main project as a submodule
|
|
|
|
This repo is standalone and has its own history. To pull it into another repo:
|
|
|
|
```bash
|
|
# 1. create an empty repo on Forgejo (e.g. w4c-agent/kilocode-loop), then:
|
|
cd /path/to/main-repo
|
|
git submodule add ssh://git@localhost:13022/w4c-agent/kilocode-loop.git tools/kilocode-loop
|
|
git commit -m "chore: add kilocode-loop submodule"
|
|
```
|
|
|
|
Because it is a submodule, `node_modules/` stays local and is never committed.
|
|
|
|
## Layout
|
|
|
|
```
|
|
bin/kilocode-loop.mjs entry point (wires config → orchestrator → dashboard)
|
|
src/config.mjs CLI/config parsing
|
|
src/orchestrator.mjs the loop, controls, HITL, report assembly
|
|
src/kilocode.mjs `kilo run` driver + JSONL event parser
|
|
src/goal.mjs goal files, agent contract, progress/percent/questions
|
|
src/state.mjs run state, persistence, log stream
|
|
src/reports.mjs console/markdown reports, formatting
|
|
src/console.mjs live console renderer
|
|
src/terminal.mjs TTY controls
|
|
src/server.mjs Express + SSE dashboard API
|
|
src/simulator.mjs --dry-run agent
|
|
public/ dashboard UI
|
|
examples/ sample goals
|
|
test/ node:test unit tests (npm test)
|
|
```
|