kilo-loop/README.md
Vitali sharp8n 1eb9ec22c2 kilo loop
2026-09-13 19:29:03 +03:00

641 lines
29 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 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.
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 and installs
`node_modules` on first use. Run it with no `--goal` to open the dashboard
launcher and pick a plan in the UI:
```bash
# from anywhere inside the repo (or a submodule — it scopes to that repo)
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
# same command from anywhere, once the launcher is on PATH
kilo-loop
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, default verify). No goal is injected
by default — pass `--goal` to run one directly, or pick it in the dashboard.
### 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>.
## 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.
## Controls
| Where | Key / button | Effect |
| --- | --- | --- |
| Terminal | `X` | Abort the loop **after** the current session finishes |
| Terminal | `P` | Pause / resume before the next iteration |
| Terminal | `S` | Toggle shared context (fresh sessions ⇄ one growing session) |
| 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) |
| 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 |
| Dashboard | Pause / Abort after session / Stop now | Same controls from the browser |
| 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.
## 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
handoff.md # context packet for the next fresh iteration
review.json # reviewer verdict (when --review is on)
runs/<runId>/
state.json # full run state (for the dashboard)
events.jsonl # every log line (secrets redacted)
report.md # end-of-run summary
checkpoints/
iter-01.json # HEAD + untracked list for iteration 1
iter-01.patch # `git diff HEAD` at the checkpoint
iterations/
01-prompt.md # exact prompt sent
01-review-prompt.md # reviewer prompt (when --review is on)
02-handoff-in.md # handoff packet consumed by iteration 2
01-report.json
01-report.md
```
## 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`.
2. **Runtime** — every `tool_use` is scanned; a match aborts the session
immediately and stops the loop with status `stopped-guard`.
`rm -rf` is **path-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 (`rm -rf /tmp/<run>`) no longer blocks a run.
Deleting the temp root itself, a relative/project path, or any non-temp absolute
path is still 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.
### 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
**not** retried.
- 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`).
### 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.
## 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": "…",
"verify": "pnpm test",
"acceptance": "test suite is green",
"model": "provider/fast-model",
"agent": "code",
"variant": "high"
}
]
}
```
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:
```markdown
# Stabilise the workflows module
- [ ] Remove legacy libs :: verify: pnpm test
- [x] Rewire the builder
```
## 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.
## 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)
--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
--hitl <mode> always | on-question | off
--runtime <mode> auto | kilo | opencode (auto-detects from the CLI binary)
--max-iteration-minutes <n>
--context-warn-tokens <n>
--prompt-extra <file> extra instructions for every iteration
Verification & safety
--verify "<cmd>" loop-run check; a stage is not done until it exits 0
--verify-timeout-minutes <n>
--checkpoint / --no-checkpoint
--guard / --no-guard
--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>
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
--no-confirm, --yes start immediately (skip the pre-flight confirmation)
```
Config can also live in `<project>/.kilocode-loop/config.json` (CLI wins).
## Dashboard API
| Method | Path | Purpose |
| --- | --- | --- |
| `GET` | `/api/state` | Current run snapshot (`{status:"idle", idle:true}` when no run is active) |
| `GET` | `/api/events` | SSE stream (`state` + `log` messages) |
| `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 |
| `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) |
| `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 |
| `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. The command guard adds
deny rules for destructive bash patterns on top of them.
- `--dry-run` performs no API calls and no file changes (beyond its own
`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.
## 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/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
src/simulator.mjs --dry-run agent
public/ dashboard UI
examples/ sample goals
test/ node:test unit tests (npm test)
```