Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# devloop

`devloop` runs a Codex implementation loop with Claude as the reviewer.
`devloop` runs a configurable implementation and review loop. By default, Codex codes and Claude Code reviews.

Codex makes the change. Claude reviews it. If Claude rejects it, Codex gets the review and tries again. The loop stops when the work is accepted, stalls, becomes unclear, reaches the max turn count, or an agent fails.
The coder makes the change. The reviewer reviews it. If the reviewer rejects it, the coder gets the review and tries again. The loop stops when the work is accepted, stalls, becomes unclear, reaches the max turn count, or an agent fails.

## Install

Expand Down Expand Up @@ -31,7 +31,7 @@ devloop .specs/change.md
Full form:

```sh
devloop [--plain|--tui] [--in-place] [--no-strict] [--report-format html|markdown] spec.md [max=5]
devloop [--plain|--tui] [--in-place] [--no-strict] [--coder codex|claude] [--reviewer codex|claude] [--report-format html|markdown] spec.md [max=5]
```

Common examples:
Expand All @@ -41,6 +41,7 @@ devloop .specs/change.md
devloop --plain .specs/change.md
devloop --tui .specs/change.md
devloop --report-format markdown .specs/change.md 3
devloop --coder claude --reviewer codex .specs/change.md
```

## Write A Spec
Expand All @@ -66,14 +67,15 @@ Strict mode is on by default. In strict mode, the spec must include:
By default, `devloop`:

- runs up to 5 passes, clamped between 1 and 10
- uses Codex as the coder and Claude Code as the reviewer
- uses the TUI in a terminal and plain output elsewhere
- writes an HTML report
- requires Claude to pass every acceptance criterion
- requires the reviewer to pass every acceptance criterion
- creates an isolated sibling git worktree and runs agents there
- creates a local branch and commit when the run is accepted
- never pushes or opens a PR

Use `--plain` for CI. Use `--tui` to force the TUI. Use `--in-place` to opt out of the isolated worktree and run in the current checkout. Use `--no-strict` only when you want weaker acceptance gates.
Use `--plain` for CI. Use `--tui` to force the TUI. Use `--coder` and `--reviewer` to choose `codex` or `claude` for either role. Use `--in-place` to opt out of the isolated worktree and run in the current checkout. Use `--no-strict` only when you want weaker acceptance gates.

## Output

Expand All @@ -85,13 +87,14 @@ Each run writes files under `.codex/`:
.codex/reports/<slug>.html
.codex/reports/<slug>.md
.codex/logs/
.codex/sessions/
.codex/sessions/<slug>-coder-<agent>.id
.codex/sessions/<slug>-reviewer-<agent>.id
.codex/specs/<slug>.md
```

With the default isolated worktree, these files are written inside the generated sibling worktree named `<repo>-<slug>`. The original checkout is left on its current branch, and uncommitted files in that checkout are not included in the run. The spec is snapshotted into `.codex/specs/<slug>.md` inside the worktree. The final CLI/TUI output prints the worktree path and absolute report/track paths.

Before creating the worktree, `devloop` asks Codex to read the spec and repository and return the semantic work item identity. That identity supplies `<slug>`, branch type, and breaking-change status. Explicit spec frontmatter wins when set:
Before creating the worktree, `devloop` asks the configured coder to read the spec and repository and return the semantic work item identity. That identity supplies `<slug>`, branch type, and breaking-change status. Explicit spec frontmatter wins when set:

```yaml
type: fix
Expand Down Expand Up @@ -130,7 +133,7 @@ If `worktree remove` reports local modifications, inspect the worktree first or

## Development

Prereqs: `bun`, `codex`, `claude`, and `git`.
Prereqs: `bun`, `git`, and the agents you configure. The defaults require `codex` and `claude`.

```sh
bun scripts/install.ts
Expand Down
25 changes: 18 additions & 7 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,25 @@ function printResult(result: {
max: number;
report: string;
track: string;
branch?: string;
commit?: string;
worktree?: string;
sourceRepo?: string;
coder?: string;
reviewer?: string;
}) {
console.log("");
console.log(`result: ${result.status}`);
console.log(`passes: ${result.passes} / ${result.max}`);
if ("branch" in result) console.log(`branch: ${result.branch}`);
if ("commit" in result) console.log(`commit: ${result.commit || "none"}`);
console.log(resultLine("result", result.status));
console.log(resultLine("passes", `${result.passes} / ${result.max}`));
if (result.coder) console.log(resultLine("coder", result.coder));
if (result.reviewer) console.log(resultLine("reviewer", result.reviewer));
if (result.branch) console.log(resultLine("branch", result.branch));
if (result.commit !== undefined)
console.log(resultLine("commit", result.commit || "none"));
if (hasWorktreeInfo(result) && isIsolatedWorktree(result))
console.log(`worktree: ${result.worktree}`);
console.log(`report: ${displayPath(result, result.report)}`);
console.log(`track: ${displayPath(result, result.track)}`);
console.log(resultLine("worktree", result.worktree));
console.log(resultLine("report", displayPath(result, result.report)));
console.log(resultLine("track", displayPath(result, result.track)));
}

function hasWorktreeInfo(result: {
Expand All @@ -81,3 +88,7 @@ function displayPath(
) {
return hasWorktreeInfo(result) ? resultPath(result, file) : file;
}

function resultLine(label: string, value: string) {
return `${`${label}:`.padEnd(10)}${value}`;
}
Loading