2026-09-13 10:46:28 +00:00
|
|
|
|
# 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.
|
|
|
|
|
|
|
2026-09-13 16:29:03 +00:00
|
|
|
|
It also enforces its own safety net: **independent verification gates** (a stage
|
|
|
|
|
|
is not done until the loop's `--verify` command exits 0), a **destructive-command
|
|
|
|
|
|
guard**, per-iteration **git checkpoints with revert**, **budget/stall limits**,
|
|
|
|
|
|
**secret redaction**, **notifications** and an optional **reviewer pass**.
|
|
|
|
|
|
|
|
|
|
|
|
By default every iteration runs in its **own fresh session** (small context, cheaper,
|
|
|
|
|
|
more targeted): the loop carries only a curated handoff — goal, current stage,
|
|
|
|
|
|
previous summary, operator answers and a handoff packet the agent prepares. Turn on
|
|
|
|
|
|
**Use shared context between iterations** (dashboard checkbox, `--shared-context`, or
|
|
|
|
|
|
`S` in the terminal) to keep one growing session instead.
|
|
|
|
|
|
|
2026-09-13 10:46:28 +00:00
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
|
|
```
|
2026-09-13 16:29:03 +00:00
|
|
|
|
┌─ loop ───────────────────────────────────────────────────────────────────┐
|
|
|
|
|
|
│ for i in 1..N: │
|
2026-09-13 10:46:28 +00:00
|
|
|
|
│ ┌─ section: Iteration i/N — <stage> ───────────────────────────────┐ │
|
2026-09-13 16:29:03 +00:00
|
|
|
|
│ │ ▸ 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 │
|
|
|
|
|
|
└──────────────────────────────────────────────────────────────────────────┘
|
2026-09-13 10:46:28 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 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
|
|
|
|
|
|
|
2026-09-13 10:51:43 +00:00
|
|
|
|
### Installed as a submodule (recommended)
|
|
|
|
|
|
|
2026-09-13 16:29:03 +00:00
|
|
|
|
The launcher resolves the git root of the current directory and installs
|
|
|
|
|
|
`node_modules` on first use. Run it with no `--goal` to open the dashboard
|
|
|
|
|
|
launcher and pick a plan in the UI:
|
2026-09-13 10:51:43 +00:00
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# from anywhere inside the repo (or a submodule — it scopes to that repo)
|
2026-09-13 16:29:03 +00:00
|
|
|
|
tools/kilocode-loop/kilo-loop # open the dashboard launcher (pick a plan in the UI)
|
|
|
|
|
|
tools/kilocode-loop/kilo-loop --list-goals # print discovered plans + state, then exit
|
|
|
|
|
|
tools/kilocode-loop/kilo-loop --goal .kilocode-loop/goal.json -n 5 # run one directly
|
|
|
|
|
|
tools/kilocode-loop/kilo-loop --dry-run --goal examples/goal.example.json # offline rehearsal
|
2026-09-13 10:51:43 +00:00
|
|
|
|
|
|
|
|
|
|
# same command from anywhere, once the launcher is on PATH
|
2026-09-13 16:29:03 +00:00
|
|
|
|
kilo-loop
|
2026-09-13 10:51:43 +00:00
|
|
|
|
kilo-loop --goal plans/another-goal.md -n 5
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Per-repo defaults live in `<repo>/.kilocode-loop/config.json` (agent, iterations,
|
2026-09-13 16:29:03 +00:00
|
|
|
|
session mode, HITL, port, context threshold, default verify). No goal is injected
|
|
|
|
|
|
by default — pass `--goal` to run one directly, or pick it in the dashboard.
|
2026-09-13 10:51:43 +00:00
|
|
|
|
|
|
|
|
|
|
### Standalone
|
|
|
|
|
|
|
2026-09-13 10:46:28 +00:00
|
|
|
|
```bash
|
2026-09-13 10:51:43 +00:00
|
|
|
|
npm install
|
|
|
|
|
|
|
2026-09-13 10:46:28 +00:00
|
|
|
|
# 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>.
|
|
|
|
|
|
|
2026-09-13 16:29:03 +00:00
|
|
|
|
## Pre-flight confirmation
|
|
|
|
|
|
|
|
|
|
|
|
On an interactive terminal a **direct** run (`kilo-loop --goal …`) does not start
|
|
|
|
|
|
immediately: it prints a summary of the resolved scenario and waits for
|
|
|
|
|
|
confirmation. Launcher mode (no `--goal`) skips this — nothing runs until you
|
|
|
|
|
|
press **Start run** in the dashboard.
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
╭─ About to run ───────────────────────────────────────────────────────╮
|
|
|
|
|
|
│ Goal Workflows module — review, simplification & hardening │
|
|
|
|
|
|
│ Source /home/.../.kilocode-loop/goal.json │
|
|
|
|
|
|
│ Project /home/.../wiz4apps │
|
|
|
|
|
|
│ Agent code-design │
|
|
|
|
|
|
│ Iterations 5 │
|
|
|
|
|
|
│ Context fresh session per iteration (handoff) │
|
|
|
|
|
|
│ HITL on-question │
|
|
|
|
|
|
│ Auto-approve yes │
|
|
|
|
|
|
│ Dashboard http://127.0.0.1:7999 │
|
|
|
|
|
|
│ Mode live │
|
|
|
|
|
|
╰──────────────────────────────────────────────────────────────────────╯
|
|
|
|
|
|
|
|
|
|
|
|
1. [ ] Close Phase 1 residuals
|
|
|
|
|
|
2. [ ] Phase 2 — architecture convergence residuals
|
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
|
|
Start this run? [Y/n]
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Enter/`y` starts; anything else cancels without starting anything (no run dir, no
|
|
|
|
|
|
dashboard, no sessions). A missing/broken goal file fails here, before anything is
|
|
|
|
|
|
created.
|
|
|
|
|
|
|
|
|
|
|
|
- `--no-confirm` / `--yes` — skip the prompt and start immediately.
|
|
|
|
|
|
- Non-interactive stdin/stdout (pipes, CI, `--dry-run` harness) always starts
|
|
|
|
|
|
immediately.
|
|
|
|
|
|
- Set `"confirm": false` in `.kilocode-loop/config.json` to make auto-start the
|
|
|
|
|
|
default for a repo.
|
|
|
|
|
|
|
2026-09-13 10:46:28 +00:00
|
|
|
|
## Controls
|
|
|
|
|
|
|
|
|
|
|
|
| Where | Key / button | Effect |
|
|
|
|
|
|
| --- | --- | --- |
|
|
|
|
|
|
| Terminal | `X` | Abort the loop **after** the current session finishes |
|
|
|
|
|
|
| Terminal | `P` | Pause / resume before the next iteration |
|
2026-09-13 16:29:03 +00:00
|
|
|
|
| Terminal | `S` | Toggle shared context (fresh sessions ⇄ one growing session) |
|
2026-09-13 10:46:28 +00:00
|
|
|
|
| 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) |
|
2026-09-13 16:29:03 +00:00
|
|
|
|
| Terminal | `Ctrl+C` (SIGINT) | Stop the run and exit. It works whether or not the dashboard is open; a second `Ctrl+C` force-exits immediately |
|
2026-09-13 10:46:28 +00:00
|
|
|
|
| Dashboard | Pause / Abort after session / Stop now | Same controls from the browser |
|
2026-09-13 16:29:03 +00:00
|
|
|
|
| Dashboard | **Use shared context between iterations** | Off (default) = fresh session + handoff per iteration; on = one growing session |
|
|
|
|
|
|
| Dashboard | **Revert before #N** | Restore the checkpoint taken before iteration N (confirmation required) |
|
|
|
|
|
|
| Dashboard | **Report** | Download `report.md` for the active run |
|
|
|
|
|
|
| Dashboard | question modal | Answer the pending questions (option buttons become editable answers); answers go into the next session |
|
|
|
|
|
|
|
|
|
|
|
|
### Top-bar activity indicator
|
|
|
|
|
|
|
|
|
|
|
|
The header doubles as a status light, driven purely by CSS animations (JS only
|
|
|
|
|
|
toggles a `topbar--<state>` class):
|
|
|
|
|
|
|
|
|
|
|
|
- **running / starting** — a glowing blue→green segment sweeps along the bottom
|
|
|
|
|
|
edge over a faint travelling sheen, so it is obvious work is in progress;
|
|
|
|
|
|
- **waiting-answer** — pulsing purple, to draw attention to a pending question;
|
|
|
|
|
|
- **paused** — a static amber line (deliberately not animating);
|
|
|
|
|
|
- **error / done-with-errors / stale** — the bar is tinted light red with a
|
|
|
|
|
|
pulsing red line;
|
|
|
|
|
|
- **aborted / stopped-budget / stalled / stopped-guard** — a light amber tint
|
|
|
|
|
|
(warning, not failure);
|
|
|
|
|
|
- **done** — a static green line; **idle** — plain header.
|
|
|
|
|
|
|
|
|
|
|
|
All movement is disabled under `prefers-reduced-motion: reduce` (the state colour
|
|
|
|
|
|
stays). See `public/styles.css` (`topbar--*`) and `topbarState()` in
|
|
|
|
|
|
`public/app.js`.
|
|
|
|
|
|
|
|
|
|
|
|
## Fresh sessions vs shared context
|
|
|
|
|
|
|
|
|
|
|
|
Default (`sharedContext: false` / checkbox off) — each iteration is an independent
|
|
|
|
|
|
`kilo run` with **no session history**. To keep the work coherent, the runner
|
|
|
|
|
|
carries forward only:
|
|
|
|
|
|
|
|
|
|
|
|
- the goal, its stages and the current stage;
|
|
|
|
|
|
- the previous iteration's `progress.json` (topic, summary, next stage, percent);
|
|
|
|
|
|
- all operator answers collected so far;
|
|
|
|
|
|
- the list of files changed so far this run;
|
|
|
|
|
|
- the previous iteration's **handoff packet**.
|
|
|
|
|
|
|
|
|
|
|
|
The handoff packet is a bounded markdown file (`.kilocode-loop/handoff.md`, ~120
|
|
|
|
|
|
lines max) that the agent writes at the end of every iteration: current state,
|
|
|
|
|
|
decisions & constraints, next steps, prepared data, open questions. The runner
|
|
|
|
|
|
embeds it into the next prompt and then deletes the file, so a forgotten packet can
|
|
|
|
|
|
never leak into a later iteration. Older packets are archived per iteration in
|
|
|
|
|
|
`runs/<runId>/iterations/<NN>-handoff-in.md`.
|
|
|
|
|
|
|
|
|
|
|
|
Shared context (`sharedContext: true` / checkbox on) — one growing session is
|
|
|
|
|
|
continued across iterations (`--session <id>`), so the whole history is available
|
|
|
|
|
|
but the context (and cost) grows every iteration. The handoff sections are then
|
|
|
|
|
|
skipped because the session already has the history.
|
|
|
|
|
|
|
|
|
|
|
|
The toggle is live: the dashboard checkbox (`POST /api/control { "action":
|
|
|
|
|
|
"set-shared-context", "value": true|false }`) and `S` in the terminal apply from the
|
|
|
|
|
|
next iteration onward.
|
2026-09-13 10:46:28 +00:00
|
|
|
|
|
|
|
|
|
|
## 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
|
2026-09-13 16:29:03 +00:00
|
|
|
|
handoff.md # context packet for the next fresh iteration
|
|
|
|
|
|
review.json # reviewer verdict (when --review is on)
|
2026-09-13 10:46:28 +00:00
|
|
|
|
runs/<runId>/
|
|
|
|
|
|
state.json # full run state (for the dashboard)
|
2026-09-13 16:29:03 +00:00
|
|
|
|
events.jsonl # every log line (secrets redacted)
|
2026-09-13 10:46:28 +00:00
|
|
|
|
report.md # end-of-run summary
|
2026-09-13 16:29:03 +00:00
|
|
|
|
checkpoints/
|
|
|
|
|
|
iter-01.json # HEAD + untracked list for iteration 1
|
|
|
|
|
|
iter-01.patch # `git diff HEAD` at the checkpoint
|
2026-09-13 10:46:28 +00:00
|
|
|
|
iterations/
|
|
|
|
|
|
01-prompt.md # exact prompt sent
|
2026-09-13 16:29:03 +00:00
|
|
|
|
01-review-prompt.md # reviewer prompt (when --review is on)
|
|
|
|
|
|
02-handoff-in.md # handoff packet consumed by iteration 2
|
2026-09-13 10:46:28 +00:00
|
|
|
|
01-report.json
|
|
|
|
|
|
01-report.md
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-09-13 16:29:03 +00:00
|
|
|
|
## Verification gates, guards, budgets and checkpoints
|
|
|
|
|
|
|
|
|
|
|
|
Since v0.2 the loop no longer trusts the agent's own "done". Every safety feature
|
|
|
|
|
|
is opt-out, and all of them apply to the *loop*, not the agent's prompt.
|
|
|
|
|
|
|
|
|
|
|
|
### Independent verification (the loop runs the check itself)
|
|
|
|
|
|
|
|
|
|
|
|
A stage is not marked `done` until a verify command the loop itself runs exits 0.
|
|
|
|
|
|
Set it globally, per stage, or both (the stage wins):
|
|
|
|
|
|
|
|
|
|
|
|
```jsonc
|
|
|
|
|
|
{
|
|
|
|
|
|
"title": "Ship the parser",
|
|
|
|
|
|
"stages": [
|
|
|
|
|
|
{ "id": "s1", "title": "Rebuild the parser", "verify": "pnpm test", "acceptance": "no failures" }
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Markdown goals take directives after `::`:
|
|
|
|
|
|
|
|
|
|
|
|
```markdown
|
|
|
|
|
|
- [ ] Rebuild the parser :: verify: pnpm test :: acceptance: no failures
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
When verify fails, the stage is recorded as `blocked`, the failing output is fed
|
|
|
|
|
|
back into the next iteration's prompt, and `completedStages` is not advanced. Set
|
|
|
|
|
|
`--no-sync-goal` to stop the loop from ticking `[x]` in a markdown goal file.
|
|
|
|
|
|
|
|
|
|
|
|
### Destructive-command guard
|
|
|
|
|
|
|
|
|
|
|
|
Two layers:
|
|
|
|
|
|
|
|
|
|
|
|
1. **Pre-execution** — the loop injects deny rules for destructive bash patterns
|
|
|
|
|
|
(`git commit`, `git push`, `git reset --hard`, `git clean -f`,
|
|
|
|
|
|
`npm|pnpm publish`, history rewrites, raw disk writes, recursive deletes of
|
|
|
|
|
|
system/home paths, …) into the child `kilo run` via `KILO_CONFIG_CONTENT`, so
|
|
|
|
|
|
`--auto` still denies them. Skipped when the project already sets a scalar
|
|
|
|
|
|
`permission.bash`.
|
2026-09-13 19:38:01 +00:00
|
|
|
|
2. **Runtime** — every `tool_use` is scanned; a match **aborts that session
|
|
|
|
|
|
immediately** (damage control) and, by default, the run **continues with the
|
|
|
|
|
|
next iteration**: the still-incomplete stage is retried and the safety note is
|
|
|
|
|
|
fed back into the next prompt (`## Loop safety feedback`), so the agent can
|
|
|
|
|
|
reach the same result a safer way. In shared-context mode the aborted session
|
|
|
|
|
|
is replaced by a fresh one with a synthesized handoff.
|
|
|
|
|
|
|
|
|
|
|
|
Use `--guard-stop` to restore the old behaviour (stop the whole run on the first
|
|
|
|
|
|
hit, status `stopped-guard`) and `--max-guard-blocks <n>` (default 3) to cap how
|
|
|
|
|
|
many *consecutive* guard-blocked iterations are tolerated before the loop stops.
|
|
|
|
|
|
|
|
|
|
|
|
`rm -rf` is **path-aware and `cd`-aware** in both layers: recursive deletes whose
|
|
|
|
|
|
targets are all strictly inside a temp directory (`os.tmpdir()`, `/tmp`,
|
|
|
|
|
|
`/var/tmp`) are allowed, so routine scratch cleanup no longer blocks a run —
|
|
|
|
|
|
including the common agent pattern `cd /tmp && rm -rf <scratch>`, where the
|
|
|
|
|
|
relative target is resolved against the temp cwd. Deleting the temp root itself,
|
|
|
|
|
|
a relative path with no known temp cwd, or any non-temp absolute path is still
|
|
|
|
|
|
blocked; `cd /repo && rm -rf src` stays blocked. Mixed commands (one temp target
|
|
|
|
|
|
plus one unsafe target) are blocked. Pre-execution denies only the catastrophic
|
|
|
|
|
|
recursive targets (`~`, `$HOME`, `/home/*`, `/etc*`, `/usr*`, `/opt*`, `/root*`,
|
|
|
|
|
|
`/boot*`, `/srv*`, `.git/`), while the runtime scanner remains the catch-all for
|
|
|
|
|
|
everything else.
|
2026-09-13 16:29:03 +00:00
|
|
|
|
|
|
|
|
|
|
### Checkpoints and revert
|
|
|
|
|
|
|
|
|
|
|
|
Before each iteration the loop captures a checkpoint under
|
|
|
|
|
|
`runs/<runId>/checkpoints/`: HEAD, `git diff HEAD` and the untracked-file list.
|
|
|
|
|
|
Nothing is committed. **Revert before #N** on the dashboard (or
|
|
|
|
|
|
`POST /api/revert { iteration }`) restores tracked files to HEAD, re-applies the
|
|
|
|
|
|
checkpoint's own diff and deletes untracked files created afterwards. Revert is
|
|
|
|
|
|
destructive and always behind a confirmation; it does not touch submodule
|
|
|
|
|
|
contents or committed history. Disable with `--no-checkpoint`.
|
|
|
|
|
|
|
|
|
|
|
|
### Budgets and stall detection
|
|
|
|
|
|
|
|
|
|
|
|
- `--max-cost <usd>` / `--max-tokens <n>` — stop with status `stopped-budget`.
|
|
|
|
|
|
- `--max-stale-iterations <n>` — stop with status `stalled` after N iterations
|
|
|
|
|
|
that change no files and advance no stage.
|
|
|
|
|
|
- `--max-iteration-minutes <n>` — per-iteration hard timeout (already existed).
|
|
|
|
|
|
|
|
|
|
|
|
### Auto-recovery from model/network errors
|
|
|
|
|
|
|
|
|
|
|
|
If `kilo run` dies because the provider connection is reset, the iteration is
|
|
|
|
|
|
retried instead of failing and losing the turn. Detection covers
|
|
|
|
|
|
`Connection reset by [peer|server]`, `ECONNRESET`/`ETIMEDOUT`/`EPIPE`,
|
|
|
|
|
|
`socket hang up`, `fetch failed`, `premature close`, HTTP `429/5xx`, and
|
|
|
|
|
|
`rate limit`/`overloaded`/`timed out`.
|
|
|
|
|
|
|
|
|
|
|
|
- Each retry **continues the interrupted session** (`--session <id>`), so work
|
|
|
|
|
|
already done in the turn is preserved (in shared mode the run session; in fresh
|
|
|
|
|
|
mode the session the failed attempt created).
|
|
|
|
|
|
- Exponential backoff with jitter: `--retry-delay` (default 2000 ms), doubling
|
|
|
|
|
|
per attempt up to `--retry-max-delay` (default 60000 ms).
|
|
|
|
|
|
- `--max-retries <n>` (default 3); `--no-retry` disables it entirely.
|
|
|
|
|
|
- Timeouts (`--max-iteration-minutes`), a command-guard hit, or a user Stop are
|
2026-09-13 19:38:01 +00:00
|
|
|
|
**not** retried as transient errors. A guard hit instead aborts the session and
|
|
|
|
|
|
the loop continues with the next iteration (see `--guard-stop` /
|
|
|
|
|
|
`--max-guard-blocks`).
|
2026-09-13 16:29:03 +00:00
|
|
|
|
- The dashboard marks the iteration `retrying` (`auto-retry ×N`) and the report
|
|
|
|
|
|
records the attempt count and the last transient reason.
|
|
|
|
|
|
- Optionally notify on retries with `--notify …` (event `model-retry`).
|
|
|
|
|
|
|
2026-09-13 19:38:01 +00:00
|
|
|
|
### Resuming a stopped run
|
|
|
|
|
|
|
|
|
|
|
|
When a run does not reach `done` (guard, error, stall, budget, abort), the CLI
|
|
|
|
|
|
prints the exact command to continue it:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
Resume this run: kilo-loop --goal <goal> --resume <runId>
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
`--resume <runId>` reloads that run's saved state: stages it already reported as
|
|
|
|
|
|
`done` are skipped, `lastPercent` is carried over, and — when the previous run was
|
|
|
|
|
|
interrupted by the guard — the safety note is injected into the first iteration
|
|
|
|
|
|
again. `--resume last` (or `latest`) resolves to the most recent saved run, so the
|
|
|
|
|
|
everyday recovery command is simply:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
kilo-loop --goal .kilo/plans/<plan>.md --resume last
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Saved runs live under `.kilocode-loop/runs/<runId>/`; `kilo-loop report --last`
|
|
|
|
|
|
shows the most recent one without starting anything.
|
|
|
|
|
|
|
2026-09-13 16:29:03 +00:00
|
|
|
|
### Secret redaction
|
|
|
|
|
|
Every log line, `state.json`, per-iteration report and the run report is scrubbed
|
|
|
|
|
|
before it is written: bearer/Basic headers, `sk-`/`ghp_`/`xox`/AWS/JWT tokens,
|
|
|
|
|
|
`token=`/`password:` values and URL userinfo. Disable with `--no-redact`.
|
|
|
|
|
|
|
|
|
|
|
|
### Notifications
|
|
|
|
|
|
|
|
|
|
|
|
`--notify <targets>` (space/comma separated) sends out-of-band alerts for
|
|
|
|
|
|
`question`, `verify-failed`, `guard`, `budget`, `stalled` and `run-done`:
|
|
|
|
|
|
|
|
|
|
|
|
| Target | Behaviour |
|
|
|
|
|
|
| --- | --- |
|
|
|
|
|
|
| `https://hooks.slack.com/...` | Slack incoming webhook (`{ text }`) |
|
|
|
|
|
|
| `https://ntfy.sh/<topic>` or `ntfy://<host>/<topic>` | ntfy POST + `Title` header |
|
|
|
|
|
|
| `telegram://<botToken>/<chatId>` | Telegram `sendMessage` |
|
|
|
|
|
|
| any `https://` URL | generic JSON payload `{ event, title, text, sentAt }` |
|
|
|
|
|
|
|
|
|
|
|
|
### Reviewer pass
|
|
|
|
|
|
|
|
|
|
|
|
`--review` runs one extra reviewer session (agent `--review-agent`, default the
|
|
|
|
|
|
run agent) after a stage passes verify. The reviewer inspects the working tree and
|
|
|
|
|
|
writes `.kilocode-loop/review.json` with `{ verdict: "pass"|"block", … }`; a
|
|
|
|
|
|
`block` un-advances the stage and raises the reviewer's questions. Skipped in
|
|
|
|
|
|
`--dry-run`.
|
|
|
|
|
|
|
|
|
|
|
|
### Hybrid context
|
|
|
|
|
|
|
|
|
|
|
|
In shared-context mode, `--auto-fresh-tokens <n>` switches to a fresh session (with
|
|
|
|
|
|
a synthesized handoff) once the context passes that size, instead of only warning.
|
|
|
|
|
|
|
|
|
|
|
|
## Report subcommand & exit codes
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
kilo-loop report # most recent run's report.md
|
|
|
|
|
|
kilo-loop report <runId> --json # redacted run state
|
|
|
|
|
|
kilo-loop report --last -C /repo
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
`report` is read-only: it starts nothing and makes no API calls.
|
|
|
|
|
|
|
|
|
|
|
|
Exit codes: `0` done, `1` done-with-errors, `2` aborted, `3` budget,
|
|
|
|
|
|
`4` stalled, `5` stopped-guard.
|
|
|
|
|
|
|
|
|
|
|
|
## Kilo vs opencode
|
|
|
|
|
|
|
|
|
|
|
|
The loop drives a CLI, not a library: it spawns `<bin> run --format json` and
|
|
|
|
|
|
parses the line-delimited JSON event stream. opencode is the same lineage as the
|
|
|
|
|
|
Kilo CLI (near-identical `run` surface), so the wire format is compatible:
|
|
|
|
|
|
|
|
|
|
|
|
| Shared with opencode | |
|
|
|
|
|
|
| --- | --- |
|
|
|
|
|
|
| `/run --format json` NDJSON events | `tool_use`, `step_finish`, `text`, `reasoning`, `error`; `part.tool`, `part.state.input`, `part.tokens{cache}`, `part.cost`, `sessionID` |
|
|
|
|
|
|
| Flags | `--agent`, `--model`, `--variant`, `--thinking`, `--session`, `--continue`, `--title`, `--format json` |
|
|
|
|
|
|
|
|
|
|
|
|
Two things differ, and the tool adapts to them automatically:
|
|
|
|
|
|
|
|
|
|
|
|
| | kilo | opencode |
|
|
|
|
|
|
| --- | --- | --- |
|
|
|
|
|
|
| Auto-approve flag | `--auto` | `--dangerously-skip-permissions` |
|
|
|
|
|
|
| Inline config env (guard) | `KILO_CONFIG_CONTENT` | `OPENCODE_CONFIG_CONTENT` |
|
|
|
|
|
|
| Project config for `permission.bash` | `kilo.json`, `.kilo/kilo.json` | `opencode.json`, `.opencode/opencode.json` |
|
|
|
|
|
|
|
|
|
|
|
|
Usage:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# point the loop at opencode (runtime auto-detected from the binary name)
|
|
|
|
|
|
KILO_BIN=opencode kilo-loop --goal goal.md -n 5 \
|
|
|
|
|
|
--agent build --model anthropic/claude-sonnet
|
|
|
|
|
|
|
|
|
|
|
|
# or be explicit
|
|
|
|
|
|
kilo-loop --runtime opencode --agent build ...
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
`--runtime` defaults to `auto`, which detects `opencode` from the binary name.
|
|
|
|
|
|
Agent names and model IDs are CLI-specific: set `--agent`/`--model` to something
|
|
|
|
|
|
defined in your opencode config (the Kilo default `code-design` is not an
|
|
|
|
|
|
opencode agent). Everything the loop itself provides — verification gates,
|
|
|
|
|
|
checkpoints, budgets, redaction, notifications, the dashboard and `report` — is
|
|
|
|
|
|
runtime-independent.
|
|
|
|
|
|
|
2026-09-13 10:46:28 +00:00
|
|
|
|
## Goal files
|
|
|
|
|
|
|
|
|
|
|
|
`--goal-text "..."` — a single implicit stage.
|
|
|
|
|
|
|
|
|
|
|
|
`--goal file.json`:
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"title": "Stabilise the workflows module",
|
|
|
|
|
|
"description": "…",
|
2026-09-13 16:29:03 +00:00
|
|
|
|
"stages": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"id": "stage-1",
|
|
|
|
|
|
"title": "Remove legacy libs",
|
|
|
|
|
|
"details": "…",
|
|
|
|
|
|
"verify": "pnpm test",
|
|
|
|
|
|
"acceptance": "test suite is green",
|
|
|
|
|
|
"model": "provider/fast-model",
|
|
|
|
|
|
"agent": "code",
|
|
|
|
|
|
"variant": "high"
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
2026-09-13 10:46:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-09-13 16:29:03 +00:00
|
|
|
|
Stage fields: `id`, `title`, `details`, `done`, and optional `verify`,
|
|
|
|
|
|
`acceptance`, `model`, `agent`, `variant` (per-stage routing overrides the run
|
|
|
|
|
|
defaults). `--goal file.md` — the first `#` heading is the title, each `- [ ]` /
|
|
|
|
|
|
`- [x]` item is a stage, and `:: verify: … :: acceptance: …` adds directives:
|
2026-09-13 10:46:28 +00:00
|
|
|
|
|
|
|
|
|
|
```markdown
|
|
|
|
|
|
# Stabilise the workflows module
|
|
|
|
|
|
|
2026-09-13 16:29:03 +00:00
|
|
|
|
- [ ] Remove legacy libs :: verify: pnpm test
|
2026-09-13 10:46:28 +00:00
|
|
|
|
- [x] Rewire the builder
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-09-13 16:29:03 +00:00
|
|
|
|
## Dashboard launcher (pick a plan in the UI)
|
|
|
|
|
|
|
|
|
|
|
|
Run `kilo-loop` **without** `--goal` and the dashboard opens in launcher mode: no
|
|
|
|
|
|
run is started until you pick one.
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
kilo-loop # launcher only
|
|
|
|
|
|
kilo-loop --list-goals # print every discovered plan + its state, then exit
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
The launcher lets you:
|
|
|
|
|
|
|
|
|
|
|
|
- **pick a plan** from a dropdown — plans are discovered under
|
|
|
|
|
|
`.kilocode-loop/goals/**`, the legacy `.kilocode-loop/goal.{json,md}`, and any
|
|
|
|
|
|
markdown plan under `plans/` or `.kilo/plans/` that contains `- [ ]` items;
|
|
|
|
|
|
- see each plan's **state** (done/total, %, type, last run status/iterations/cost);
|
|
|
|
|
|
- **set the verify command** per stage (kept in the goal file;
|
|
|
|
|
|
`- [ ] Title :: verify: cmd` for markdown, `stage.verify` for JSON) or once for
|
|
|
|
|
|
all plans (stored in `.kilocode-loop/config.json`);
|
|
|
|
|
|
- **Mark 100%** all stages done (`- [x]` for markdown, `done: true` for JSON) for a
|
|
|
|
|
|
plan that was finished outside the loop, or **Clear done** to reopen it;
|
|
|
|
|
|
- **Delete plan** — moves the plan file to the gitignored
|
|
|
|
|
|
`.kilocode-loop/trash/<timestamp>-<name>` (recoverable; nothing is committed).
|
|
|
|
|
|
The UI asks for confirmation first;
|
|
|
|
|
|
- set iterations / agent / HITL / dry-run and **Start run**;
|
|
|
|
|
|
- write an optional **custom instruction** (textarea). It is added to the top of
|
|
|
|
|
|
every iteration prompt (under `## Operator instructions for this run`, before
|
|
|
|
|
|
the goal) and the run header shows `custom instruction` while it is active.
|
|
|
|
|
|
It maps to the same `promptExtra` as the CLI `--prompt-extra`; leaving the
|
|
|
|
|
|
field empty keeps any instruction coming from the CLI or config.
|
|
|
|
|
|
|
|
|
|
|
|
After a run finishes, **New run** returns to the launcher (the plan list is
|
|
|
|
|
|
refreshed with the new completion state). `POST /api/start` refuses to start a
|
|
|
|
|
|
second run while one is active.
|
|
|
|
|
|
|
2026-09-13 19:38:01 +00:00
|
|
|
|
### Reaching the dashboard from a phone (same Wi-Fi)
|
|
|
|
|
|
|
|
|
|
|
|
By default the dashboard binds loopback (`127.0.0.1`), so only this machine can
|
|
|
|
|
|
open it. `--lan` binds **every interface** (`0.0.0.0`) and the console prints the
|
|
|
|
|
|
machine's real LAN address to open on another device:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
kilo-loop --lan # or set "lan": true in .kilocode-loop/config.json
|
|
|
|
|
|
# Dashboard http://192.168.1.106:7999 (Ctrl+Click to open)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Then open that URL on the phone (same Wi-Fi/router). A wildcard bind is never
|
|
|
|
|
|
shown as a URL; the tool resolves the primary non-virtual interface (docker/vpn
|
|
|
|
|
|
bridges are filtered out). An explicit `--host <ip>` still wins, and `--local`
|
|
|
|
|
|
forces loopback back on.
|
|
|
|
|
|
|
|
|
|
|
|
> **Security:** the dashboard has no authentication and exposes control
|
|
|
|
|
|
> endpoints (start/stop/pause, revert which deletes untracked files). Only use
|
|
|
|
|
|
> `--lan` on a trusted network, and prefer `--local` (or `--host 127.0.0.1`) on
|
|
|
|
|
|
> shared/public Wi-Fi.
|
|
|
|
|
|
|
|
|
|
|
|
## Scaffolding a plan (`new-plan`)
|
|
|
|
|
|
|
|
|
|
|
|
Plans must contain `- [ ]` checkbox stages to be discovered at all. Generate one
|
|
|
|
|
|
from the project's template instead of hand-writing the format:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
kilo-loop new-plan "My plan title" # writes .kilo/plans/<epoch-ms>-<slug>.md
|
|
|
|
|
|
kilo-loop new-plan "My plan title" --print # preview without writing
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
The template is `<project>/.kilo/templates/plan.md` (a sensible default is used if
|
|
|
|
|
|
the project has none). Optional flags: `--slug <s>`, `--epoch <ms>`, `--dir <d>`,
|
|
|
|
|
|
`--project <p>`, `--print`, `--force`. The scaffolder is also available directly
|
|
|
|
|
|
at `tools/kilocode-loop/new-plan.mjs`.
|
|
|
|
|
|
|
2026-09-13 10:46:28 +00:00
|
|
|
|
## 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)
|
2026-09-13 16:29:03 +00:00
|
|
|
|
--shared-context one growing session across iterations (costly)
|
|
|
|
|
|
--no-shared-context fresh session per iteration + handoff (default)
|
|
|
|
|
|
--session-mode <mode> legacy alias: continue = shared, fresh = no shared
|
2026-09-13 10:46:28 +00:00
|
|
|
|
--hitl <mode> always | on-question | off
|
2026-09-13 16:29:03 +00:00
|
|
|
|
--runtime <mode> auto | kilo | opencode (auto-detects from the CLI binary)
|
2026-09-13 10:46:28 +00:00
|
|
|
|
--max-iteration-minutes <n>
|
|
|
|
|
|
--context-warn-tokens <n>
|
|
|
|
|
|
--prompt-extra <file> extra instructions for every iteration
|
|
|
|
|
|
|
2026-09-13 16:29:03 +00:00
|
|
|
|
Verification & safety
|
|
|
|
|
|
--verify "<cmd>" loop-run check; a stage is not done until it exits 0
|
|
|
|
|
|
--verify-timeout-minutes <n>
|
|
|
|
|
|
--checkpoint / --no-checkpoint
|
2026-09-13 19:38:01 +00:00
|
|
|
|
--guard / --no-guard deny destructive bash; a hit aborts the session
|
|
|
|
|
|
--guard-stop stop the run on the first guard hit (default: continue)
|
|
|
|
|
|
--max-guard-blocks <n> consecutive guard hits tolerated (default 3)
|
2026-09-13 16:29:03 +00:00
|
|
|
|
--redact / --no-redact
|
|
|
|
|
|
--max-cost <usd>
|
|
|
|
|
|
--max-tokens <n>
|
|
|
|
|
|
--max-stale-iterations <n>
|
|
|
|
|
|
--retry / --no-retry retry an iteration on a model connection reset (default on)
|
|
|
|
|
|
--max-retries <n> retry attempts per iteration (default 3)
|
|
|
|
|
|
--retry-delay <ms> first backoff delay (default 2000, doubles)
|
|
|
|
|
|
--retry-max-delay <ms> backoff cap (default 60000)
|
|
|
|
|
|
--review / --review-agent <name>
|
|
|
|
|
|
--auto-fresh-tokens <n>
|
|
|
|
|
|
--sync-goal / --no-sync-goal
|
|
|
|
|
|
--force run even when every stage is marked done
|
|
|
|
|
|
--list-goals list discovered plans + state, then exit
|
|
|
|
|
|
--notify <targets>
|
|
|
|
|
|
|
2026-09-13 10:46:28 +00:00
|
|
|
|
Dashboard
|
|
|
|
|
|
-p, --port <n> default 7999
|
|
|
|
|
|
--host <host> default 127.0.0.1
|
2026-09-13 19:38:01 +00:00
|
|
|
|
--lan bind 0.0.0.0 so a phone on the same Wi-Fi can open it
|
|
|
|
|
|
--local force loopback only (overrides a config "lan": true)
|
2026-09-13 10:46:28 +00:00
|
|
|
|
--keep-open keep the dashboard after the loop
|
|
|
|
|
|
|
|
|
|
|
|
Utility
|
2026-09-13 19:38:01 +00:00
|
|
|
|
new-plan "<title>" scaffold .kilo/plans/<epoch-ms>-<slug>.md from .kilo/templates/plan.md
|
2026-09-13 10:46:28 +00:00
|
|
|
|
--dry-run simulate the agent (no API calls)
|
2026-09-13 19:38:01 +00:00
|
|
|
|
--resume <runId|last> reuse a previous run's session + stage progress
|
2026-09-13 10:46:28 +00:00
|
|
|
|
--run-id <id>
|
|
|
|
|
|
--quiet suppress the live console stream
|
|
|
|
|
|
--no-color
|
2026-09-13 16:29:03 +00:00
|
|
|
|
--no-confirm, --yes start immediately (skip the pre-flight confirmation)
|
2026-09-13 10:46:28 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Config can also live in `<project>/.kilocode-loop/config.json` (CLI wins).
|
|
|
|
|
|
|
|
|
|
|
|
## Dashboard API
|
|
|
|
|
|
|
|
|
|
|
|
| Method | Path | Purpose |
|
|
|
|
|
|
| --- | --- | --- |
|
2026-09-13 16:29:03 +00:00
|
|
|
|
| `GET` | `/api/state` | Current run snapshot (`{status:"idle", idle:true}` when no run is active) |
|
2026-09-13 10:46:28 +00:00
|
|
|
|
| `GET` | `/api/events` | SSE stream (`state` + `log` messages) |
|
2026-09-13 16:29:03 +00:00
|
|
|
|
| `GET` | `/api/goals` | Discoverable plans/goals with per-stage completion and last run |
|
|
|
|
|
|
| `POST` | `/api/goals/verify` | `{ "file": "…", "stageIndex": N, "verify": "cmd" }` — set a stage verify (`stageIndex` omitted = global, JSON goals only) |
|
|
|
|
|
|
| `POST` | `/api/goals/verify-global` | `{ "verify": "cmd" }` — default verify for all runs (`.kilocode-loop/config.json`) |
|
|
|
|
|
|
| `POST` | `/api/start` | `{ "file": "…", "iterations": N, "agent": "…", "hitl": "…", "dryRun": bool }` — start a run from the launcher |
|
2026-09-13 10:46:28 +00:00
|
|
|
|
| `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) |
|
2026-09-13 16:29:03 +00:00
|
|
|
|
| `GET` | `/api/runs/:id/export` | Full run report (markdown) |
|
|
|
|
|
|
| `GET` | `/api/runs/:id/diff/:iter` | Checkpoint patch captured before iteration N |
|
|
|
|
|
|
| `GET` | `/api/checkpoints` | Active run's checkpoints (`?run=<id>` for a saved run) |
|
|
|
|
|
|
| `GET` | `/api/runs/:id/checkpoints` | Saved run's checkpoints |
|
|
|
|
|
|
| `POST` | `/api/control` | `{ "action": "pause"\|"resume"\|"abort-after-current"\|"stop" }` and `{ "action": "set-shared-context", "value": true\|false }` |
|
|
|
|
|
|
| `POST` | `/api/revert` | `{ "iteration": N }` — restore the checkpoint before iteration N |
|
2026-09-13 10:46:28 +00:00
|
|
|
|
| `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
|
2026-09-13 16:29:03 +00:00
|
|
|
|
`kilo.json` / `.kilo` permissions before unattended runs. The command guard adds
|
|
|
|
|
|
deny rules for destructive bash patterns on top of them.
|
2026-09-13 10:46:28 +00:00
|
|
|
|
- `--dry-run` performs no API calls and no file changes (beyond its own
|
2026-09-13 16:29:03 +00:00
|
|
|
|
`progress.json`); it also skips verify commands and the reviewer pass.
|
|
|
|
|
|
- Logs, state and reports are redacted before they are persisted; use
|
|
|
|
|
|
`--no-redact` only when you trust the target. `--no-guard` and
|
|
|
|
|
|
`--no-checkpoint` trade safety for speed.
|
|
|
|
|
|
- `report` and `--json` are read-only.
|
2026-09-13 10:46:28 +00:00
|
|
|
|
|
|
|
|
|
|
## 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
|
2026-09-13 16:29:03 +00:00
|
|
|
|
src/verify.mjs independent verify command runner
|
|
|
|
|
|
src/goals.mjs goal/plan registry, summaries, verify editing
|
|
|
|
|
|
src/controller.mjs run lifecycle (start multiple plans from the dashboard)
|
|
|
|
|
|
src/guard.mjs destructive-command guard (pre-execution + runtime)
|
|
|
|
|
|
src/checkpoint.mjs per-iteration git checkpoints + revert
|
|
|
|
|
|
src/redact.mjs secret redaction for persisted logs/state/reports
|
|
|
|
|
|
src/notify.mjs webhook/ntfy/telegram notifications
|
|
|
|
|
|
src/reportcli.mjs `kilo-loop report` subcommand
|
2026-09-13 10:46:28 +00:00
|
|
|
|
src/simulator.mjs --dry-run agent
|
|
|
|
|
|
public/ dashboard UI
|
|
|
|
|
|
examples/ sample goals
|
|
|
|
|
|
test/ node:test unit tests (npm test)
|
|
|
|
|
|
```
|