diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml
new file mode 100644
index 0000000..4cf67e8
--- /dev/null
+++ b/.github/workflows/pages.yml
@@ -0,0 +1,33 @@
+name: Deploy website
+
+on:
+ push:
+ branches: [main]
+ paths:
+ - 'site/**'
+ - '.github/workflows/pages.yml'
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+concurrency:
+ group: pages
+ cancel-in-progress: true
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/configure-pages@v5
+ - uses: actions/upload-pages-artifact@v3
+ with:
+ path: site
+ - id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/.gitignore b/.gitignore
index efd656b..3ed379a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,11 @@ node_modules/
dist/
coverage/
+# Demo renderer cache
+.venv-demo/
+__pycache__/
+*.pyc
+
# Loop Engineer runtime data (runs, worktrees, caches) — never version these
.loop-engineer/
diff --git a/.prettierignore b/.prettierignore
index 39336ca..3933a31 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -4,3 +4,4 @@ node_modules/
package-lock.json
CHANGELOG.md
.loop-engineer/
+.venv-demo/
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 01f0031..568342a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,9 +1,13 @@
# Changelog
-All notable changes will appear in this file. The project follows Keep a Changelog and plans to use Semantic Versioning after the first public release.
+All notable changes will appear in this file. The project follows Keep a Changelog and Semantic Versioning.
## [Unreleased]
+## [0.1.0] - 2026-07-15
+
+First public release.
+
### Added
- Local-first Claude Code, Codex CLI and predefined-command providers.
diff --git a/README.md b/README.md
index 61f01e9..38212f8 100644
--- a/README.md
+++ b/README.md
@@ -1,19 +1,76 @@
+
+
# Loop Engineer
-Assign Claude, Codex and local tools to different software-engineering roles and run a controlled development loop in an isolated Git worktree.
+**Loop Engineer is an open-source, local-first multi-agent software-engineering orchestrator for Claude Code, Codex CLI, and isolated Git worktrees.**
+
+Run Claude Code, OpenAI Codex and local checks as one controlled software-development loop.
+
+[](https://github.com/BotondCsereklye/LoopEngineer/actions/workflows/ci.yml)
+[](https://nodejs.org/)
+[](https://www.typescriptlang.org/)
+[](LICENSE)
+[](docs/security.md)
+
+[Website](https://botondcsereklye.github.io/LoopEngineer/) · [Demo](#demo) · [Screenshots](#screenshots) · [Quick start](#quick-start) · [How it works](#how-it-works) · [Security](#security-boundaries) · [Documentation](#documentation)
+
+
-Use your existing authenticated coding-agent CLIs. No API keys, cloud account or automatic push required.
+Loop Engineer gives each agent one role, validates every handoff and keeps writing agents inside an isolated Git worktree. Tests and review gates decide when the loop stops. You inspect the result before anything reaches your branch.
> [!WARNING]
-> Loop Engineer is an unofficial open-source project. It has no affiliation with OpenAI or Anthropic. Review agent output and the generated diff before you copy changes into your branch.
+> Loop Engineer is an unofficial open-source project. OpenAI and Anthropic do not sponsor or endorse it. Review generated code and provider output before using either.
+
+## Demo
+
+Check both provider CLIs without exposing credentials:
+
+
+
+Preview the workflow, then run the controlled loop:
+
+
+
+[Watch the full 23-second MP4](demo/loop-engineer-demo.mp4) or browse the [demo notes and reproducible renderer](demo/README.md).
+
+The recordings use scripted fixture output. They never read a real `~/.claude`, `~/.codex`, repository file, environment secret or provider session.
+
+## Screenshots
+
+### Dashboard and provider connections
+
+See the local project, provider connection states and current-run panel before starting a task.
+
+
+
+### Model and intelligence controls
-## Problem
+Choose Claude Code or OpenAI Codex, then select the model and intelligence level for each role.
-Coding agents can edit quickly, but a long unstructured chat mixes planning, implementation and approval. It can also expose a repository to prompt injection or let a test command exceed the authority you intended to grant.
+
-Loop Engineer assigns one role per step. Each role receives a bounded prompt, a permission profile and a Zod-validated JSON handoff. Writing roles work in a detached Git worktree. The tester runs commands from an exact allowlist.
+### Quality gates and launch controls
-## Workflow
+Set blocking severities, require passing tests and start with a safe dry run.
+
+
+
+These screenshots come from the running local dashboard against a disposable Git fixture. They contain no repository source or credentials.
+
+## Why Loop Engineer
+
+A long agent chat mixes discovery, implementation, testing and approval in one context. Loop Engineer splits those responsibilities and gives each phase a narrow contract.
+
+| Concern | Loop Engineer behavior |
+| ------------ | ----------------------------------------------------------------------------------------------- |
+| Agent access | Read-only roles inspect the repository. Writing roles edit only an isolated worktree. |
+| Handoffs | Zod validates structured JSON between roles. Raw chat transcripts do not become workflow state. |
+| Commands | The local tester runs only configured allowlisted commands without a shell. |
+| Quality | Tests and review findings must satisfy explicit gates. |
+| Delivery | Every run ends with a Markdown report, JSON report and reviewable worktree. |
+| Git | Loop Engineer creates no commit and sends no push. |
+
+## How it works
```text
ANALYZE -> PLAN -> IMPLEMENT -> TEST -> REVIEW -> DECIDE
@@ -22,23 +79,33 @@ ANALYZE -> PLAN -> IMPLEMENT -> TEST -> REVIEW -> DECIDE
+------ FIX
```
-The orchestrator stops when tests and review gates pass, the cycle limit expires, runtime expires, progress stops, a provider fails, or the user cancels.
+| Role | Default provider | Access |
+| ----------- | -------------------- | ------------------- |
+| Analyst | Claude Code or Codex | Read-only |
+| Planner | Claude Code or Codex | Read-only |
+| Implementer | Claude Code or Codex | Worktree write |
+| Tester | Local command runner | Predefined commands |
+| Reviewer | Claude Code or Codex | Read-only |
+| Fixer | Claude Code or Codex | Worktree write |
+| Final judge | Claude Code or Codex | Read-only |
+
+The orchestrator stops when the quality gates pass, a configured cycle or runtime limit expires, progress stalls, a provider fails, or you cancel the run.
+
+## Quick start
-## Installation
+### Install
-Requirements: Node.js 20+, Git, and at least one supported official agent CLI.
+Requirements: Node.js 20+, Git and at least one supported official provider CLI.
```bash
-git clone
-cd loop-engineer
-npm install
+git clone https://github.com/BotondCsereklye/LoopEngineer.git
+cd LoopEngineer
+npm ci
npm run build
npm link
```
-Loop Engineer uses the sessions managed by `claude` and `codex`. Sign in through those CLIs. Do not paste provider passwords or browser tokens into Loop Engineer.
-
-## 30-second quickstart
+### Configure a project
Run these commands inside a Git repository with at least one commit:
@@ -48,33 +115,29 @@ loopeng doctor
loopeng gui
```
-The dashboard opens at `http://127.0.0.1:4317`. Configure the task, role providers, models, quality gates and test commands, then start with a dry run. Loop Engineer does not commit or push.
+The dashboard opens at `http://127.0.0.1:4317`. Connect the installed provider CLIs, then choose a provider, model and intelligence level for every role. Codex model choices include Sol, Terra and Luna; Claude uses its supported CLI aliases. During a real run, **Current run** shows the active role, provider, model, intelligence level and elapsed thinking time. Session-limit errors include the affected provider, role and reset time when the CLI supplies one.
-Prefer the terminal? Run `loopeng run --task "Add input validation to the settings parser"` instead.
-
-## Commands
+Prefer the terminal:
-```text
-loopeng init
-loopeng doctor
-loopeng gui
-loopeng gui --no-open --port 4318
-loopeng run --task "Add password reset"
-loopeng run --task-file task.md
-loopeng run --config loop-engineer.yml --task "Fix the parser"
-loopeng run --dry-run --task "Preview this workflow"
-loopeng status
-loopeng report
-loopeng clean [--force]
+```bash
+loopeng run --dry-run --task "Add input validation to the settings parser"
+loopeng run --task "Add input validation to the settings parser"
```
-`gui` starts a local-only dashboard bound to `127.0.0.1`. It reads the same `loop-engineer.yml` as the CLI and keeps the role permission boundaries fixed. Stop it with `Ctrl+C`.
+## Provider connections
+
+The dashboard can start `claude auth login --claudeai` or `codex login`. Each official CLI owns its browser flow, callback and credential store. Loop Engineer receives only installed and authenticated status.
-`doctor` checks Node, Git, repository state, worktree support, provider installation, command detection, instruction files and write access. It reports an unknown authentication state when an official CLI offers no dependable probe.
+The dashboard contains no password, API-key, OAuth-code or access-token field. Configure API-key, SSO, device-code and enterprise automation flows through the provider's official CLI.
+
+Read [provider setup and smoke tests](docs/providers.md).
## Configuration
-`loopeng init` writes `loop-engineer.yml` and detects common build commands. Zod rejects unknown keys, invalid role permissions and unsafe tester assignments.
+`loopeng init` writes `loop-engineer.yml` and detects common project commands. The schema rejects unknown keys, invalid permissions and unsafe tester assignments.
+
+
+Example configuration
```yaml
version: 1
@@ -113,44 +176,78 @@ security:
redact_secrets: true
```
-See [configuration](docs/configuration.md) for validation rules.
+
-## Roles and providers
+See the [configuration reference](docs/configuration.md) for every field and validation rule.
-The MVP includes `analyst`, `planner`, `implementer`, `reviewer`, `tester`, `fixer` and `final_judge`. Claude Code and Codex CLI handle agent roles. The local provider runs test commands without a shell.
+## Commands
-Provider flags can change between CLI releases. Run `loopeng doctor` after you upgrade a provider. See [providers](docs/providers.md).
+```text
+loopeng init
+loopeng doctor
+loopeng gui [--no-open] [--port ]
+loopeng run --task "Add password reset"
+loopeng run --task-file task.md
+loopeng run --config loop-engineer.yml --task "Fix the parser"
+loopeng run --dry-run --task "Preview this workflow"
+loopeng status
+loopeng report
+loopeng clean [--force]
+```
-## Security model
+`doctor` checks Node.js, Git, worktree support, repository state, provider installation and authentication, command detection, instruction files and write access.
-- Repository text enters prompts inside untrusted-data fences.
-- Read-only roles receive read-only provider permissions.
-- Implementer and fixer receive workspace write access inside the isolated worktree.
-- The tester rejects shell chaining, pipes, redirection, command substitution and denied binaries.
-- Logs and reports redact common token, key and password patterns before storage.
-- Loop Engineer issues no commit, push, force reset or destructive clean command.
+## Security boundaries
-Redaction catches common patterns, not every secret format. Run reports can contain sensitive source context. Keep `.loop-engineer/` local and review [the security model](docs/security.md).
+- Repository content enters prompts inside untrusted-data fences.
+- Analyst, planner, reviewer and final judge receive read-only provider permissions.
+- Implementer and fixer write only inside the managed worktree.
+- The tester rejects chaining, pipes, redirects, command substitution, denied binaries and destructive Git commands.
+- Provider login stays inside the official CLI. The dashboard API never handles credentials.
+- Logs and reports redact common key, token and password formats before storage.
+- Loop Engineer never commits, pushes, force-resets or runs a destructive clean command.
+
+Redaction cannot recognize every custom secret format. Keep `.loop-engineer/` private and treat run reports like build logs. Read the full [security model](docs/security.md) before using the tool on sensitive code.
## Worktrees and reports
-Loop Engineer creates `.loop-engineer/worktrees/` from the current commit. Existing modifications in your main checkout stay untouched. `clean` removes worktrees with Loop Engineer marker files and refuses dirty worktrees unless you pass `--force`.
+Each real run starts from the current commit and creates:
+
+```text
+.loop-engineer/
+├── runs//
+│ ├── report.md
+│ ├── report.json
+│ ├── task.md
+│ ├── config.snapshot.yml
+│ └── validated handoffs and provider events
+└── worktrees//
+ └── generated changes for human review
+```
-Each completed run writes Markdown and JSON under `.loop-engineer/runs//`, together with configuration, task, handoffs, provider events, tests and review results.
+`loopeng clean` removes only marked managed worktrees. It preserves dirty worktrees unless you pass `--force`.
-## Limitations
+## Documentation
-- The MVP supports Claude Code, Codex CLI and a local command runner.
-- Provider CLI output formats may change.
-- The context firewall and redactor reduce risk but cannot prove that a provider will behave safely.
-- Loop Engineer leaves the worktree for human inspection and does not apply its diff to your branch.
-- Windows support depends on Git worktree behavior and provider CLI support on the host.
+| Guide | Covers |
+| -------------------------------------- | -------------------------------------------- |
+| [Architecture](docs/architecture.md) | Components, trust boundaries and data flow |
+| [Workflow](docs/workflow.md) | State machine, loops and stop conditions |
+| [GUI](docs/gui.md) | Local dashboard and provider connections |
+| [Providers](docs/providers.md) | Claude Code, Codex and the local runner |
+| [Configuration](docs/configuration.md) | Schema, commands and quality gates |
+| [Security](docs/security.md) | Process, prompt, credential and Git controls |
+| [Development](docs/development.md) | Build, test and contribution workflow |
+| [Roadmap](docs/roadmap.md) | Planned scope and exclusions |
-## Roadmap
+## Limitations
-Planned work includes Gemini support, optional MCP integration, richer progress evidence and opt-in packaging as a single executable. Cloud accounts, browser automation, automatic pull requests and automatic pushes remain outside the MVP. See [roadmap](docs/roadmap.md).
+- Provider command flags and machine-readable output can change between CLI releases.
+- The context firewall and redactor reduce risk; they cannot prove provider behavior.
+- Loop Engineer leaves generated changes in the worktree for manual inspection.
+- Windows support depends on Git worktree behavior and provider CLI support on the host.
-## Development and contributing
+## Development
```bash
npm ci
@@ -161,11 +258,7 @@ npm run test:coverage
npm run build
```
-Read [CONTRIBUTING.md](CONTRIBUTING.md) and [development notes](docs/development.md). Suggested GitHub topics: `ai-agents`, `claude-code`, `codex-cli`, `developer-tools`, `git-worktree`, `local-first`, `typescript`.
-
-## Disclaimer
-
-You control the provider sessions and repository. Check provider terms, usage limits, generated code, licenses and security impact before adopting a change. Loop Engineer does not bypass provider authentication or usage limits.
+Read [CONTRIBUTING.md](CONTRIBUTING.md), [SECURITY.md](SECURITY.md) and the [Code of Conduct](CODE_OF_CONDUCT.md) before contributing.
## License
diff --git a/demo/README.md b/demo/README.md
new file mode 100644
index 0000000..862533a
--- /dev/null
+++ b/demo/README.md
@@ -0,0 +1,36 @@
+# Demo
+
+These clips show the provider check, dry run and controlled development loop without touching a real Claude Code or Codex session.
+
+## Provider connections
+
+Loop Engineer checks the installed official CLIs and reports only installed and authenticated state. Credentials remain inside each provider's own credential store.
+
+
+
+## Controlled loop
+
+A dry run validates the workflow before any provider runs. A real run performs analysis, planning, implementation, tests and review in an isolated Git worktree.
+
+
+
+## Full video
+
+[Watch the full MP4 demo](loop-engineer-demo.mp4).
+
+## Rebuild the media
+
+The renderer uses deterministic fixture text. It does not read `~/.claude`, `~/.codex`, repository source files, environment secrets or provider output.
+
+Requirements:
+
+- Python 3 with Pillow
+- FFmpeg with H.264 and GIF encoders
+
+```bash
+python3 -m venv .venv-demo
+.venv-demo/bin/pip install -r demo/requirements.txt
+.venv-demo/bin/python demo/render_demo.py
+```
+
+The script writes the MP4, poster and GIF clips under `demo/`.
diff --git a/demo/clips/01-provider-connections.gif b/demo/clips/01-provider-connections.gif
new file mode 100644
index 0000000..ba3990d
Binary files /dev/null and b/demo/clips/01-provider-connections.gif differ
diff --git a/demo/clips/02-controlled-loop.gif b/demo/clips/02-controlled-loop.gif
new file mode 100644
index 0000000..72f86dc
Binary files /dev/null and b/demo/clips/02-controlled-loop.gif differ
diff --git a/demo/loop-engineer-demo-poster.png b/demo/loop-engineer-demo-poster.png
new file mode 100644
index 0000000..836aec4
Binary files /dev/null and b/demo/loop-engineer-demo-poster.png differ
diff --git a/demo/loop-engineer-demo.mp4 b/demo/loop-engineer-demo.mp4
new file mode 100644
index 0000000..16aa1a4
Binary files /dev/null and b/demo/loop-engineer-demo.mp4 differ
diff --git a/demo/render_demo.py b/demo/render_demo.py
new file mode 100644
index 0000000..3806f7d
--- /dev/null
+++ b/demo/render_demo.py
@@ -0,0 +1,283 @@
+#!/usr/bin/env python3
+"""Render Loop Engineer demo media without touching provider sessions.
+
+The renderer draws deterministic fixture output with Pillow, streams raw frames
+to FFmpeg, then derives compact GIF clips for the README.
+"""
+
+from __future__ import annotations
+
+import shutil
+import subprocess
+import sys
+from pathlib import Path
+
+from PIL import Image, ImageDraw, ImageFont
+
+ROOT = Path(__file__).resolve().parents[1]
+DEMO_DIR = ROOT / "demo"
+CLIPS_DIR = DEMO_DIR / "clips"
+VIDEO_PATH = DEMO_DIR / "loop-engineer-demo.mp4"
+POSTER_PATH = DEMO_DIR / "loop-engineer-demo-poster.png"
+
+WIDTH = 1280
+HEIGHT = 720
+FPS = 24
+DURATION = 23.0
+
+COLORS = {
+ "background": "#080b0f",
+ "surface": "#10151b",
+ "surface_2": "#151b22",
+ "line": "#26303a",
+ "text": "#f1f5f9",
+ "muted": "#94a3b8",
+ "green": "#22c55e",
+ "blue": "#60a5fa",
+ "orange": "#d97757",
+ "yellow": "#fbbf24",
+}
+
+SCENES = [
+ {
+ "start": 2.0,
+ "end": 7.2,
+ "label": "PROVIDER CHECK",
+ "command": "loopeng doctor",
+ "outputs": [
+ ("✓ Node.js v22", "green"),
+ ("✓ Git worktrees available", "green"),
+ ("✓ Claude Code connected", "orange"),
+ ("✓ OpenAI Codex connected", "green"),
+ ("✓ Checks build · test · lint · typecheck", "blue"),
+ ],
+ "interval": 0.48,
+ },
+ {
+ "start": 7.2,
+ "end": 13.4,
+ "label": "SAFE PREVIEW",
+ "command": 'loopeng run --dry-run --task "Add input validation"',
+ "outputs": [
+ ("Configuration valid", "green"),
+ ("Roles: analyst → planner → implementer → tester → reviewer", "text"),
+ ("Quality gates: tests + clean review", "blue"),
+ ("Dry run complete · no providers called", "green"),
+ ("No files changed · no commit · no push", "muted"),
+ ],
+ "interval": 0.58,
+ },
+ {
+ "start": 13.4,
+ "end": 21.2,
+ "label": "CONTROLLED LOOP",
+ "command": 'loopeng run --task "Add input validation"',
+ "outputs": [
+ ("[1/7] Analyzing repository", "blue"),
+ ("[2/7] Creating implementation plan", "blue"),
+ ("[3/7] Isolated worktree created", "blue"),
+ ("[4/7] Implementing scoped changes", "text"),
+ ("[5/7] Tests passed", "green"),
+ ("[6/7] Review clean", "green"),
+ ("[7/7] Final validation", "blue"),
+ ("READY FOR HUMAN REVIEW", "green"),
+ ("Worktree: .loop-engineer/worktrees/run-demo", "muted"),
+ ],
+ "interval": 0.45,
+ },
+]
+
+
+def font(size: int, bold: bool = False) -> ImageFont.FreeTypeFont | ImageFont.ImageFont:
+ candidates = [
+ "/System/Library/Fonts/SFNSMono.ttf",
+ "/System/Library/Fonts/SFNSMonoItalic.ttf",
+ "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf",
+ ]
+ if bold:
+ candidates.insert(0, "/System/Library/Fonts/SFNSMono.ttf")
+ for candidate in candidates:
+ if Path(candidate).exists():
+ return ImageFont.truetype(candidate, size=size)
+ return ImageFont.load_default()
+
+
+FONT_SMALL = font(18)
+FONT_BODY = font(27)
+FONT_HEADER = font(20, bold=True)
+FONT_TITLE = font(57, bold=True)
+FONT_SUBTITLE = font(23)
+
+
+def rounded_rectangle(draw: ImageDraw.ImageDraw, box: tuple[int, int, int, int], radius: int, fill: str, outline: str | None = None, width: int = 1) -> None:
+ draw.rounded_rectangle(box, radius=radius, fill=fill, outline=outline, width=width)
+
+
+def draw_shell(draw: ImageDraw.ImageDraw, label: str) -> None:
+ rounded_rectangle(draw, (52, 54, 1228, 666), 18, COLORS["surface"], COLORS["line"], 2)
+ draw.rounded_rectangle((52, 54, 1228, 112), radius=18, fill=COLORS["surface_2"])
+ draw.rectangle((52, 92, 1228, 112), fill=COLORS["surface_2"])
+ for x, color in [(84, "#fb7185"), (112, "#fbbf24"), (140, "#22c55e")]:
+ draw.ellipse((x - 7, 76 - 7, x + 7, 76 + 7), fill=color)
+ draw.text((174, 67), "loop-engineer · safe fixture demo", font=FONT_SMALL, fill=COLORS["muted"])
+ label_width = draw.textlength(label, font=FONT_SMALL)
+ draw.text((1192 - label_width, 67), label, font=FONT_SMALL, fill=COLORS["green"])
+
+
+def draw_intro(draw: ImageDraw.ImageDraw, t: float) -> None:
+ progress = min(1.0, max(0.0, t / 0.7))
+ title = "LOOP ENGINEER"
+ title_width = draw.textlength(title, font=FONT_TITLE)
+ x = (WIDTH - title_width) / 2
+ draw.text((x, 260), title, font=FONT_TITLE, fill=COLORS["text"])
+ line_width = int(390 * progress)
+ draw.rounded_rectangle((WIDTH // 2 - line_width // 2, 337, WIDTH // 2 + line_width // 2, 343), radius=3, fill=COLORS["green"])
+ subtitle = "Claude Code + OpenAI Codex · one controlled development loop"
+ subtitle_width = draw.textlength(subtitle, font=FONT_SUBTITLE)
+ draw.text(((WIDTH - subtitle_width) / 2, 372), subtitle, font=FONT_SUBTITLE, fill=COLORS["muted"])
+ note = "local-first · isolated worktrees · human review"
+ note_width = draw.textlength(note, font=FONT_SMALL)
+ draw.text(((WIDTH - note_width) / 2, 430), note, font=FONT_SMALL, fill=COLORS["blue"])
+
+
+def draw_scene(draw: ImageDraw.ImageDraw, scene: dict[str, object], t: float) -> None:
+ draw_shell(draw, str(scene["label"]))
+ local_t = t - float(scene["start"])
+ command = str(scene["command"])
+ typed_count = max(0, min(len(command), int((local_t - 0.25) * 32)))
+ typed = command[:typed_count]
+ cursor = "▌" if int(local_t * 3) % 2 == 0 and typed_count < len(command) else ""
+ draw.text((92, 145), "$", font=FONT_BODY, fill=COLORS["green"])
+ draw.text((126, 145), typed + cursor, font=FONT_BODY, fill=COLORS["text"])
+
+ output_start = 0.25 + len(command) / 32 + 0.35
+ interval = float(scene["interval"])
+ outputs = list(scene["outputs"])
+ for index, (line, color_key) in enumerate(outputs):
+ if local_t >= output_start + index * interval:
+ y = 205 + index * 41
+ draw.text((92, y), str(line), font=FONT_BODY, fill=COLORS[str(color_key)])
+
+ footer = "Credentials and real provider sessions are never used in this recording."
+ draw.text((92, 620), footer, font=FONT_SMALL, fill=COLORS["muted"])
+
+
+def draw_outro(draw: ImageDraw.ImageDraw, t: float) -> None:
+ draw_shell(draw, "HUMAN HANDOFF")
+ heading = "Inspect the diff. You decide what ships."
+ draw.text((92, 210), heading, font=FONT_TITLE, fill=COLORS["text"])
+ draw.text((94, 310), "Reports: Markdown + JSON", font=FONT_BODY, fill=COLORS["blue"])
+ draw.text((94, 358), "Worktree: isolated and reviewable", font=FONT_BODY, fill=COLORS["green"])
+ draw.text((94, 406), "Commit: never automatic", font=FONT_BODY, fill=COLORS["muted"])
+ if int(t * 2) % 2 == 0:
+ draw.rectangle((94, 477, 110, 508), fill=COLORS["green"])
+
+
+def frame_at(t: float) -> Image.Image:
+ image = Image.new("RGB", (WIDTH, HEIGHT), COLORS["background"])
+ draw = ImageDraw.Draw(image)
+ if t < 2.0:
+ draw_intro(draw, t)
+ return image
+ for scene in SCENES:
+ if float(scene["start"]) <= t < float(scene["end"]):
+ draw_scene(draw, scene, t)
+ return image
+ draw_outro(draw, t)
+ return image
+
+
+def run(command: list[str]) -> None:
+ result = subprocess.run(command, cwd=ROOT, text=True, capture_output=True)
+ if result.returncode != 0:
+ print(result.stdout, file=sys.stderr)
+ print(result.stderr, file=sys.stderr)
+ raise SystemExit(result.returncode)
+
+
+def render_video() -> None:
+ if shutil.which("ffmpeg") is None:
+ raise SystemExit("FFmpeg is required to render demo media")
+ CLIPS_DIR.mkdir(parents=True, exist_ok=True)
+ command = [
+ "ffmpeg",
+ "-hide_banner",
+ "-loglevel",
+ "error",
+ "-y",
+ "-f",
+ "rawvideo",
+ "-pix_fmt",
+ "rgb24",
+ "-s",
+ f"{WIDTH}x{HEIGHT}",
+ "-r",
+ str(FPS),
+ "-i",
+ "-",
+ "-an",
+ "-c:v",
+ "libx264",
+ "-preset",
+ "medium",
+ "-crf",
+ "20",
+ "-pix_fmt",
+ "yuv420p",
+ "-movflags",
+ "+faststart",
+ str(VIDEO_PATH),
+ ]
+ process = subprocess.Popen(command, cwd=ROOT, stdin=subprocess.PIPE)
+ assert process.stdin is not None
+ try:
+ for frame_number in range(round(DURATION * FPS)):
+ image = frame_at(frame_number / FPS)
+ process.stdin.write(image.tobytes())
+ finally:
+ process.stdin.close()
+ if process.wait() != 0:
+ raise SystemExit("FFmpeg failed while encoding the demo video")
+ frame_at(16.7).save(POSTER_PATH, optimize=True)
+
+
+def render_gif(name: str, start: float, duration: float) -> None:
+ target = CLIPS_DIR / name
+ filter_graph = (
+ "fps=12,scale=960:-2:flags=lanczos,split[s0][s1];"
+ "[s0]palettegen=max_colors=96:stats_mode=diff[p];"
+ "[s1][p]paletteuse=dither=bayer:bayer_scale=3:diff_mode=rectangle"
+ )
+ run(
+ [
+ "ffmpeg",
+ "-hide_banner",
+ "-loglevel",
+ "error",
+ "-y",
+ "-ss",
+ str(start),
+ "-t",
+ str(duration),
+ "-i",
+ str(VIDEO_PATH),
+ "-filter_complex",
+ filter_graph,
+ "-loop",
+ "0",
+ str(target),
+ ]
+ )
+
+
+def main() -> None:
+ render_video()
+ render_gif("01-provider-connections.gif", 1.8, 5.6)
+ render_gif("02-controlled-loop.gif", 7.3, 14.1)
+ print(f"Rendered {VIDEO_PATH.relative_to(ROOT)}")
+ for clip in sorted(CLIPS_DIR.glob("*.gif")):
+ print(f"Rendered {clip.relative_to(ROOT)}")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/demo/requirements.txt b/demo/requirements.txt
new file mode 100644
index 0000000..e7cc6c1
--- /dev/null
+++ b/demo/requirements.txt
@@ -0,0 +1 @@
+Pillow==12.3.0
diff --git a/demo/screenshots/01-dashboard-overview.jpg b/demo/screenshots/01-dashboard-overview.jpg
new file mode 100644
index 0000000..b546c9f
Binary files /dev/null and b/demo/screenshots/01-dashboard-overview.jpg differ
diff --git a/demo/screenshots/02-model-intelligence.jpg b/demo/screenshots/02-model-intelligence.jpg
new file mode 100644
index 0000000..5c44521
Binary files /dev/null and b/demo/screenshots/02-model-intelligence.jpg differ
diff --git a/demo/screenshots/03-quality-gates.jpg b/demo/screenshots/03-quality-gates.jpg
new file mode 100644
index 0000000..f82a2c0
Binary files /dev/null and b/demo/screenshots/03-quality-gates.jpg differ
diff --git a/docs/configuration.md b/docs/configuration.md
index d1c2682..22aba3b 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -14,6 +14,8 @@ Role permissions have fixed safety constraints:
The tester must use `local` in normal configuration. Tests may use the internal `fake` provider.
+LLM role entries accept `model` and an optional `effort`. Supported effort values are `auto`, `low`, `medium`, `high`, `xhigh`, `max` and `ultra`; the chosen provider and model determine which values are valid in the GUI. `auto` leaves the provider default unchanged. Claude receives the value through `--effort`; Codex receives it as `model_reasoning_effort`. The local tester does not use a model or effort.
+
Quality gates can require passing commands, reviewer approval and zero findings at configured severities. The default blocks `critical` and `high`.
The `install` command records a detected install command for future use. The MVP does not run it when `allow_package_install` is false, which is the default.
diff --git a/docs/gui.md b/docs/gui.md
index 06c31fb..c03626e 100644
--- a/docs/gui.md
+++ b/docs/gui.md
@@ -8,12 +8,22 @@ loopeng gui
The browser opens `http://127.0.0.1:4317`. Use `--no-open` on a headless machine or `--port ` when the default port is occupied.
-The dashboard lets you select Claude Code or Codex CLI and a model for each agent role, workflow limits, quality gates, blocking severities and the predefined local build, test, lint and typecheck commands. The tester remains local. Read-only and workspace-write permission profiles cannot be changed in the browser.
+The dashboard lets you connect Claude Code or OpenAI Codex, then select a provider, provider-specific model and intelligence level for each agent role. Codex includes the locally supported Sol, Terra and Luna choices. Claude exposes its stable CLI aliases such as Opus, Sonnet and Haiku. Model availability can still vary by account and workspace policy.
+
+The **Current run** card shows both provider connection states, the active role, provider, model, intelligence level and elapsed thinking time. It displays safe progress metadata rather than private chain-of-thought. When a provider reports a session or usage limit, the card identifies the affected provider and role, shows the reset time when supplied by the CLI and suggests switching that role to the other provider.
+
+You can also configure workflow limits, quality gates, blocking severities and the predefined local build, test, lint and typecheck commands. The tester remains local. Read-only and workspace-write permission profiles cannot be changed in the browser.
+
+## Provider connections
+
+Select **Sign in with Claude** or **Sign in with OpenAI** to start the installed official CLI's browser login. Finish the flow in the browser opened by the CLI; the dashboard refreshes the connection state automatically. A green connection state confirms installation and authentication, not remaining subscription quota. Quota is verified only when the provider serves a real role request.
+
+Loop Engineer does not implement vendor OAuth, receive a callback, inspect credential files or store tokens. If browser login cannot complete, run `claude auth login --claudeai` or `codex login` directly in a terminal so the official CLI can present interactive recovery options.
Dry run is enabled by default. A real run uses the same isolated worktree, command policy, context firewall, secret redaction and report store as `loopeng run`.
## Local security boundary
-The HTTP server accepts only a loopback bind address. Mutating requests require a per-process CSRF token, the exact local origin and JSON content type. Responses use a restrictive Content Security Policy and do not enable cross-origin access. The UI never exposes controls for package installation, network tools, commits or pushes.
+The HTTP server accepts only a loopback bind address. Mutating requests require a per-process CSRF token, the exact local origin and JSON content type. Provider IDs are allowlisted and login commands are fixed argument arrays executed without a shell. Responses use a restrictive Content Security Policy and do not enable cross-origin access. The UI never exposes controls for credentials, package installation, network tools, commits or pushes.
Press `Ctrl+C` in the terminal that started the dashboard to stop the server.
diff --git a/docs/providers.md b/docs/providers.md
index 4308074..85aed88 100644
--- a/docs/providers.md
+++ b/docs/providers.md
@@ -2,11 +2,21 @@
## Claude Code
-The Claude adapter calls the official `claude` binary in print mode with JSON output. Read-only roles receive read tools. Writing roles receive edit tools and `acceptEdits`; the adapter does not grant Bash. Claude Code does not expose a stable non-interactive authentication probe across supported versions, so `doctor` may report the state as unknown.
+The Claude adapter calls the official `claude` binary in print mode with JSON output. The selected model is passed through `--model` and the selected intelligence level through `--effort`. Read-only roles receive read tools. Writing roles receive edit tools and `acceptEdits`; the adapter does not grant Bash. Authentication status is checked with `claude auth status --json` using only its exit code. The dashboard starts subscription login with `claude auth login --claudeai`.
## Codex CLI
-The Codex adapter calls `codex exec --json` and sends the prompt through stdin. It maps permissions to `read-only` or `workspace-write` sandbox modes. `doctor` uses the official `codex login status` command when available.
+The Codex adapter calls `codex exec --json` and sends the prompt through stdin. The selected model is passed through `--model`; intelligence is passed through the `model_reasoning_effort` configuration override. It maps permissions to `read-only` or `workspace-write` sandbox modes. Authentication status is checked with `codex login status`; the dashboard starts browser login with `codex login`.
+
+The GUI catalog is provider-specific. Codex offers Sol, Terra and Luna plus compatible reasoning levels; Ultra is only offered for models whose local Codex catalog supports delegation. Claude offers Automatic, Best, Opus, Sonnet, Haiku and Opus-plan aliases with only compatible effort choices. The server validates every model and intelligence combination again before starting a run.
+
+An authenticated CLI can still have no remaining subscription quota. If a real request reports a session, usage or rate limit, the run fails closed and the dashboard shows the provider, role and vendor-provided reset time. Loop Engineer never estimates quota itself.
+
+## Dashboard sign-in
+
+The **Provider connections** panel delegates sign-in to the installed official CLI. The CLI opens and owns the vendor browser flow, callback and credential storage. Loop Engineer starts a fixed allowlisted command without a shell, discards its output and exposes only installed, connecting and authenticated status.
+
+The dashboard deliberately has no password, API-key, access-token, email or OAuth-code input. For API-key or enterprise automation authentication, configure the official CLI outside Loop Engineer and use its documented credential store.
## Local runner
@@ -16,6 +26,7 @@ The local runner handles the tester role. It executes exact commands from `comma
```bash
claude --version
+claude auth status
codex --version
codex login status
loopeng doctor
diff --git a/docs/security.md b/docs/security.md
index a82108a..f573c73 100644
--- a/docs/security.md
+++ b/docs/security.md
@@ -12,6 +12,12 @@ The process runner calls `spawn` with `shell: false`, caps captured output, supp
Command parsing in the MVP splits on whitespace. Keep allowed commands simple. Put complex logic in a reviewed package script and allowlist `npm run `.
+## Provider authentication
+
+The local dashboard delegates authentication to the installed official Claude Code and OpenAI Codex CLIs. It accepts only the fixed provider IDs `claude` and `codex`, starts fixed login argument arrays with `shell: false`, caps captured output and applies a timeout. CLI output is discarded and is never returned to the browser or written to the run store.
+
+The dashboard never accepts passwords, API keys, OAuth codes or access tokens. It does not read vendor credential files or implement an OAuth callback. The provider CLI owns browser authentication and credential storage. Users who need API-key, SSO, device-code or enterprise automation flows must configure those through the official CLI outside Loop Engineer.
+
## Files and Git
Writing providers receive the managed worktree as their current directory. Loop Engineer creates no commit and sends no push. Cleanup checks marker metadata, refuses paths outside `.loop-engineer/worktrees`, and preserves dirty worktrees unless the user supplies `--force`.
diff --git a/eslint.config.js b/eslint.config.js
index cc49bd0..1f83d92 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -2,7 +2,7 @@ import js from '@eslint/js';
import tseslint from 'typescript-eslint';
export default tseslint.config(
- { ignores: ['dist/**', 'coverage/**', 'node_modules/**'] },
+ { ignores: ['dist/**', 'coverage/**', 'node_modules/**', '.venv-demo/**'] },
js.configs.recommended,
...tseslint.configs.recommended,
{
diff --git a/package.json b/package.json
index a7cfb94..d1cb1d5 100644
--- a/package.json
+++ b/package.json
@@ -1,9 +1,18 @@
{
"name": "loop-engineer",
"version": "0.1.0",
- "description": "Local-first multi-agent orchestrator: assign Claude Code, Codex CLI and local tools to software-engineering roles and run a controlled development loop in an isolated Git worktree.",
+ "description": "Loop Engineer is an open-source, local-first multi-agent software-engineering orchestrator for Claude Code, Codex CLI, and isolated Git worktrees.",
"type": "module",
"license": "MIT",
+ "author": "Botond Csereklye",
+ "homepage": "https://botondcsereklye.github.io/LoopEngineer/",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/BotondCsereklye/LoopEngineer.git"
+ },
+ "bugs": {
+ "url": "https://github.com/BotondCsereklye/LoopEngineer/issues"
+ },
"engines": {
"node": ">=20"
},
@@ -25,7 +34,10 @@
"cli",
"git-worktree",
"local-first",
- "developer-tools"
+ "developer-tools",
+ "agent-orchestration",
+ "software-engineering",
+ "multi-agent"
],
"scripts": {
"build": "tsc -p tsconfig.build.json && node scripts/copy-gui-assets.mjs",
diff --git a/site/assets/social-preview.png b/site/assets/social-preview.png
new file mode 100644
index 0000000..6e7c331
Binary files /dev/null and b/site/assets/social-preview.png differ
diff --git a/site/assets/style.css b/site/assets/style.css
new file mode 100644
index 0000000..3b2cd86
--- /dev/null
+++ b/site/assets/style.css
@@ -0,0 +1,247 @@
+:root {
+ --bg: #ffffff;
+ --bg-soft: #f5f7fa;
+ --text: #1f2937;
+ --text-soft: #4b5563;
+ --heading: #0f172a;
+ --accent: #0369a1;
+ --accent-soft: #e0f2fe;
+ --border: #e2e8f0;
+ --code-bg: #0b1120;
+ --code-text: #e2e8f0;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root {
+ --bg: #0b1120;
+ --bg-soft: #111a2e;
+ --text: #d1d5db;
+ --text-soft: #94a3b8;
+ --heading: #f1f5f9;
+ --accent: #38bdf8;
+ --accent-soft: #0c2a3f;
+ --border: #1e293b;
+ --code-bg: #020617;
+ --code-text: #e2e8f0;
+ }
+}
+
+* {
+ box-sizing: border-box;
+}
+
+body {
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
+ background: var(--bg);
+ color: var(--text);
+ line-height: 1.65;
+}
+
+header.site {
+ border-bottom: 1px solid var(--border);
+ background: var(--bg);
+}
+
+header.site .inner {
+ max-width: 880px;
+ margin: 0 auto;
+ padding: 0.9rem 1.25rem;
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ gap: 0.6rem 1.1rem;
+}
+
+header.site .brand {
+ font-weight: 700;
+ color: var(--heading);
+ text-decoration: none;
+ margin-right: auto;
+ font-size: 1.05rem;
+}
+
+header.site .brand span {
+ color: var(--accent);
+}
+
+header.site nav {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.2rem 1rem;
+ font-size: 0.95rem;
+}
+
+header.site nav a {
+ color: var(--text-soft);
+ text-decoration: none;
+}
+
+header.site nav a:hover,
+header.site nav a[aria-current='page'] {
+ color: var(--accent);
+}
+
+main {
+ max-width: 880px;
+ margin: 0 auto;
+ padding: 2.5rem 1.25rem 4rem;
+}
+
+h1,
+h2,
+h3 {
+ color: var(--heading);
+ line-height: 1.25;
+}
+
+h1 {
+ font-size: 2.1rem;
+ margin: 0 0 0.75rem;
+}
+
+h2 {
+ font-size: 1.45rem;
+ margin-top: 2.5rem;
+}
+
+h3 {
+ font-size: 1.15rem;
+ margin-top: 1.8rem;
+}
+
+a {
+ color: var(--accent);
+}
+
+p.lead {
+ font-size: 1.15rem;
+ color: var(--text-soft);
+ max-width: 46rem;
+}
+
+.hero {
+ padding: 1.5rem 0 0.5rem;
+}
+
+.hero .actions {
+ margin-top: 1.5rem;
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.75rem;
+}
+
+.button {
+ display: inline-block;
+ padding: 0.55rem 1.1rem;
+ border-radius: 8px;
+ text-decoration: none;
+ font-weight: 600;
+ border: 1px solid var(--accent);
+}
+
+.button.primary {
+ background: var(--accent);
+ color: #fff;
+}
+
+.button.secondary {
+ color: var(--accent);
+}
+
+pre {
+ background: var(--code-bg);
+ color: var(--code-text);
+ padding: 1rem 1.25rem;
+ border-radius: 10px;
+ overflow-x: auto;
+ font-size: 0.9rem;
+ line-height: 1.55;
+}
+
+code {
+ font-family: 'SF Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
+}
+
+p code,
+li code,
+td code {
+ background: var(--bg-soft);
+ border: 1px solid var(--border);
+ border-radius: 5px;
+ padding: 0.1rem 0.35rem;
+ font-size: 0.88em;
+}
+
+.table-wrap {
+ overflow-x: auto;
+}
+
+table {
+ border-collapse: collapse;
+ width: 100%;
+ font-size: 0.95rem;
+}
+
+th,
+td {
+ border: 1px solid var(--border);
+ padding: 0.55rem 0.75rem;
+ text-align: left;
+ vertical-align: top;
+}
+
+th {
+ background: var(--bg-soft);
+ color: var(--heading);
+}
+
+.cards {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
+ gap: 1rem;
+ margin-top: 1.5rem;
+ padding: 0;
+ list-style: none;
+}
+
+.cards li {
+ border: 1px solid var(--border);
+ border-radius: 10px;
+ padding: 1rem 1.1rem;
+ background: var(--bg-soft);
+}
+
+.cards li strong {
+ display: block;
+ color: var(--heading);
+ margin-bottom: 0.3rem;
+}
+
+.note {
+ border-left: 4px solid var(--accent);
+ background: var(--accent-soft);
+ padding: 0.75rem 1rem;
+ border-radius: 0 8px 8px 0;
+ margin: 1.5rem 0;
+}
+
+footer.site {
+ border-top: 1px solid var(--border);
+ color: var(--text-soft);
+ font-size: 0.9rem;
+}
+
+footer.site .inner {
+ max-width: 880px;
+ margin: 0 auto;
+ padding: 1.25rem;
+ display: flex;
+ flex-wrap: wrap;
+ gap: 0.5rem 1.5rem;
+ justify-content: space-between;
+}
+
+footer.site a {
+ color: var(--text-soft);
+}
diff --git a/site/changelog.html b/site/changelog.html
new file mode 100644
index 0000000..32adf66
--- /dev/null
+++ b/site/changelog.html
@@ -0,0 +1,93 @@
+
+
+
+
+
+ Loop Engineer Changelog – Releases and Notable Changes
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Loop Engineer does not replace Claude Code or Codex CLI. It orchestrates them — and adds the
+ structure a single agent session does not have.
+
+
+
Loop Engineer vs. a normal Claude Code session
+
+ A long agent chat mixes discovery, implementation, testing, and approval in one context.
+ Loop Engineer splits those responsibilities and gives each phase a narrow contract.
+
+
+
+
+
+
Concern
+
Single agent session
+
Loop Engineer
+
+
+
+
+
Agent access
+
One agent with one permission level for everything
+
+ Read-only roles inspect the repository; writing roles edit only an isolated worktree
+
+
+
+
State between steps
+
One growing chat transcript
+
Schema-validated JSON handoffs; transcripts never become workflow state
+
+
+
Command execution
+
Agent proposes shell commands as it goes
+
Local tester runs only configured allowlisted commands, without a shell
+
+
+
Definition of done
+
The model decides it is finished
+
Tests and review findings must satisfy explicit quality gates
+
+
+
Result
+
Edits land directly in your working tree
+
Markdown report, JSON report, and a reviewable worktree — no commit, no push
+
+
+
Review
+
Same context that wrote the code approves it
+
A separate reviewer role and final judge evaluate the diff
+
+
+
+
+
+
Loop Engineer vs. Codex CLI
+
+ Codex CLI is one of Loop Engineer's providers, not a competitor. Used directly, Codex CLI
+ gives you a capable single-agent session. Loop Engineer assigns Codex CLI (and Claude Code)
+ to specific roles inside a controlled loop:
+
+
+
+ You can mix providers per role — for example Codex as implementer and Claude as reviewer —
+ so the code is never approved by the model that wrote it.
+
+
+ Each role gets the minimum permission it needs: read-only for analysis and review,
+ worktree-write for implementation.
+
+
+ A local, deterministic command runner — not the model — executes your test suite and
+ reports results into the loop.
+
+
+ Provider-signaled session limits are detected and classified as provider unavailability,
+ so a run fails cleanly instead of silently degrading.
+
+
+
+
When a plain session is the better tool
+
+ For a quick question, a one-line fix, or exploratory work, a direct Claude Code or Codex
+ session is faster and entirely sufficient. Loop Engineer earns its overhead when a task
+ needs implementation
+ and verification: a feature with tests, a refactor that must keep the suite green,
+ or changes you want reviewed before they touch your branch.
+
+ Loop Engineer is an open-source, local-first multi-agent software-engineering orchestrator
+ for Claude Code, Codex CLI, and isolated Git worktrees. It assigns AI agents and local tools
+ to controlled roles — analyst, planner, implementer, tester, reviewer, fixer, and final
+ judge — and runs them as one development loop with explicit quality gates.
+
+
+
How does Loop Engineer work?
+
+ A run moves through analyze → plan → implement → test → review → decide, with a
+ bounded fix loop when tests fail or the review finds blocking issues. Read-only roles
+ inspect the repository, writing roles edit an isolated Git worktree, and a local command
+ runner executes allowlisted test commands. Details:
+ how it works.
+
+
+
Is Loop Engineer open source?
+
+ Yes. Loop Engineer is MIT-licensed and developed openly on
+ GitHub. Issues, discussions,
+ and contributions are welcome.
+
+
+
Does Loop Engineer require API keys?
+
+ No. Loop Engineer drives the official Claude Code and Codex CLIs that are already installed
+ and authenticated on your machine. It has no API-key, password, OAuth-code, or token field
+ anywhere. Provider login — including API-key, SSO, device-code, and enterprise flows —
+ happens inside each official CLI, never inside Loop Engineer.
+
+
+
Loop Engineer vs. a normal Claude Code session
+
+ A normal session is one agent, one permission level, and one growing chat. Loop Engineer
+ separates analysis, implementation, testing, and review into distinct roles with minimal
+ permissions, validates every handoff, and lets objective gates — not the model — decide when
+ work is done. See the full comparison.
+
+
+
Loop Engineer vs. Codex CLI
+
+ Codex CLI is a provider inside Loop Engineer, not a competitor. Loop Engineer adds role
+ assignment, worktree isolation, a deterministic local tester, and cross-provider review on
+ top of it — for example Codex writes the code and Claude reviews it. See
+ Loop Engineer vs. Codex CLI.
+
+
+
+ How does Loop Engineer isolate code changes?
+
+
+ Writing agents edit only a detached Git worktree under
+ .loop-engineer/worktrees/. Loop Engineer never commits, never pushes, and never
+ force-resets. You inspect the worktree diff and decide what reaches your branch.
+ loopeng clean removes only managed worktrees and preserves dirty ones unless
+ forced.
+
+
+
+ Which AI providers does Loop Engineer support?
+
+
+ Claude Code (Anthropic) and Codex CLI (OpenAI) as AI providers, plus a local
+ predefined-command runner for tests. Providers are configured per role, so you can mix them
+ freely within one run.
+
+
+
Is Loop Engineer safe?
+
+ Loop Engineer enforces explicit security boundaries: read-only roles for analysis and
+ review, worktree-isolated writes, shell-free allowlisted commands, a credential-free
+ loopback-only dashboard, prompt fencing for repository content, and secret redaction in logs
+ and reports. It is honest about limits too: redaction cannot recognize every custom secret
+ format, and no firewall can prove provider behavior. Read the
+ security model.
+
+
+
How do I install Loop Engineer?
+
+ Install Node.js 20+, Git, and at least one provider CLI, then clone the repository, run
+ npm ci && npm run build && npm link, and use
+ loopeng init, loopeng doctor, and loopeng gui inside
+ your Git repository. Full steps: installation guide.
+
+ Loop Engineer runs a state machine, not a conversation. Each phase has one role, one
+ provider, and one narrow contract.
+
+
+
The controlled loop
+
ANALYZE → PLAN → IMPLEMENT → TEST → REVIEW → DECIDE
+ ↑ |
+ └──────── FIX ←──────┘
+
+ A run starts from the current commit of your repository. The analyst and planner inspect the
+ code with read-only access. The implementer writes changes into an isolated Git worktree.
+ The tester runs your configured commands — build, test, lint, typecheck — without a shell.
+ The reviewer inspects the diff, and the final judge decides whether the quality gates are
+ satisfied. If tests fail or the review finds blocking issues, the fixer gets a bounded
+ number of correction cycles.
+
+
+
Roles and access
+
+
+
+
+
Role
+
Default provider
+
Access
+
+
+
+
+
Analyst
+
Claude Code or Codex
+
Read-only
+
+
+
Planner
+
Claude Code or Codex
+
Read-only
+
+
+
Implementer
+
Claude Code or Codex
+
Worktree write
+
+
+
Tester
+
Local command runner
+
Predefined commands
+
+
+
Reviewer
+
Claude Code or Codex
+
Read-only
+
+
+
Fixer
+
Claude Code or Codex
+
Worktree write
+
+
+
Final judge
+
Claude Code or Codex
+
Read-only
+
+
+
+
+
+
Validated handoffs
+
+ Roles exchange structured JSON that is validated with Zod schemas before it becomes workflow
+ state. Raw chat transcripts never drive the loop. Repository content enters prompts inside
+ untrusted-data fences, so file contents are treated as data rather than instructions.
+
+
+
Stop conditions
+
The orchestrator stops when one of the following happens:
+
+
All quality gates pass (tests green, no blocking review findings).
+
The configured cycle or runtime limit expires.
+
Progress stalls between cycles.
+
A provider becomes unavailable, for example a session limit.
+ Nothing is committed and nothing is pushed. You inspect the worktree, take what you want,
+ and discard the rest with
+ loopeng clean. Continue with the security model or
+ the comparison with plain agent sessions.
+
Local-first multi-agent orchestration for Claude Code and Codex CLI
+
+ Loop Engineer is an open-source, local-first multi-agent software-engineering orchestrator
+ for Claude Code, Codex CLI, and isolated Git worktrees. It assigns each AI agent one
+ narrow role, validates every handoff, and keeps generated changes out of your branch until
+ you approve them.
+
+ Loop Engineer coordinates the official Claude Code and
+ OpenAI Codex CLIs together with local test tooling in one controlled
+ development loop. Instead of a single long agent chat that mixes discovery, implementation,
+ testing, and approval, Loop Engineer splits those responsibilities into roles with narrow
+ contracts: analyst, planner, implementer, tester, reviewer, fixer, and final judge.
+
+
+
+ Local-first
+ Runs entirely on your machine. No cloud account, no API keys, no telemetry. Provider login
+ stays inside the official CLIs.
+
+
+ Isolated Git worktrees
+ Writing agents edit only a detached worktree. Loop Engineer never commits and never
+ pushes.
+
+
+ Objective quality gates
+ Tests and review findings decide when the loop stops — not the model's self-assessment.
+
+
+ Validated handoffs
+ Roles exchange structured, schema-validated JSON instead of raw chat transcripts.
+
+
+
+
How does Loop Engineer work?
+
ANALYZE → PLAN → IMPLEMENT → TEST → REVIEW → DECIDE
+ ↑ |
+ └──────── FIX ←──────┘
+
+ Read-only roles inspect the repository, writing roles edit an isolated worktree, and a local
+ command runner executes only allowlisted test commands. Every run ends with a Markdown
+ report, a JSON report, and a reviewable worktree. Read the full
+ workflow description.
+
+
+
Get started
+
git clone https://github.com/BotondCsereklye/LoopEngineer.git
+cd LoopEngineer
+npm ci && npm run build && npm link
+
+loopeng init
+loopeng doctor
+loopeng gui
+
+ See the installation guide for requirements and provider
+ setup, or jump straight to the FAQ.
+
+
+
+ Loop Engineer is an unofficial open-source project. OpenAI and Anthropic do not sponsor or
+ endorse it. Review generated code and provider output before using either.
+
git clone https://github.com/BotondCsereklye/LoopEngineer.git
+cd LoopEngineer
+npm ci
+npm run build
+npm link
+
+ npm link puts the loopeng command on your PATH. An npm package
+ (npm install -g loop-engineer) is planned; until it ships, installing from
+ source is the supported path.
+
+
+
Set up a project
+
Run these commands inside a Git repository with at least one commit:
+
loopeng init # writes loop-engineer.yml and detects project commands
+loopeng doctor # checks Node.js, Git, providers, and write access
+loopeng gui # opens the local dashboard at http://127.0.0.1:4317
+
+ loopeng doctor verifies Node.js, Git, worktree support, repository state,
+ provider installation and authentication, command detection, instruction files, and write
+ access — so problems surface before your first run.
+
+
+
Connect providers
+
+ The dashboard can start claude auth login --claudeai or
+ codex login. Each official CLI owns its browser flow, callback, and credential
+ store. Loop Engineer receives only installed-and-authenticated status — it has no password,
+ API-key, OAuth-code, or access-token field anywhere.
+
+
+
Run your first task
+
loopeng run --dry-run --task "Add input validation to the settings parser"
+loopeng run --task "Add input validation to the settings parser"
+
+ Start with --dry-run to preview the workflow without calling any provider. Then
+ read how the loop works and the
+ security model.
+
+
+
+
+
diff --git a/site/llms.txt b/site/llms.txt
new file mode 100644
index 0000000..b3a5591
--- /dev/null
+++ b/site/llms.txt
@@ -0,0 +1,24 @@
+# Loop Engineer
+
+> Loop Engineer is an open-source, local-first multi-agent software-engineering
+> orchestrator for Claude Code, Codex CLI, and isolated Git worktrees.
+
+Loop Engineer coordinates the official Claude Code (Anthropic) and Codex CLI
+(OpenAI) command-line tools together with local test tooling in one controlled
+development loop. Each agent gets one role (analyst, planner, implementer,
+tester, reviewer, fixer, final judge), every handoff is schema-validated, and
+writing agents edit only an isolated Git worktree. Tests and review gates
+decide when the loop stops. Loop Engineer never commits, never pushes, and
+requires no API keys — provider login stays inside the official CLIs.
+
+License: MIT. Language: TypeScript (Node.js 20+). Version: 0.1.0.
+
+## Docs
+
+- [Homepage](https://botondcsereklye.github.io/LoopEngineer/): overview and quick start
+- [How it works](https://botondcsereklye.github.io/LoopEngineer/how-it-works.html): roles, workflow, quality gates
+- [Installation](https://botondcsereklye.github.io/LoopEngineer/installation.html): requirements and setup
+- [Security](https://botondcsereklye.github.io/LoopEngineer/security.html): isolation, credentials, Git safety
+- [Comparison](https://botondcsereklye.github.io/LoopEngineer/comparison.html): vs. plain Claude Code sessions and Codex CLI
+- [FAQ](https://botondcsereklye.github.io/LoopEngineer/faq.html): common questions
+- [Repository](https://github.com/BotondCsereklye/LoopEngineer): source code, issues, discussions
diff --git a/site/robots.txt b/site/robots.txt
new file mode 100644
index 0000000..ab6766a
--- /dev/null
+++ b/site/robots.txt
@@ -0,0 +1,4 @@
+User-agent: *
+Allow: /
+
+Sitemap: https://botondcsereklye.github.io/LoopEngineer/sitemap.xml
diff --git a/site/security.html b/site/security.html
new file mode 100644
index 0000000..d8e2a93
--- /dev/null
+++ b/site/security.html
@@ -0,0 +1,133 @@
+
+
+
+
+
+ Loop Engineer Security Model – Isolation, Credentials, and Git Safety
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Loop Engineer is built around explicit boundaries: what each agent can read, what it can
+ write, which commands can run, and what never leaves your machine.
+
+
+
How Loop Engineer isolates code changes
+
+
+ Writing roles (implementer, fixer) edit only a managed, detached Git worktree under
+ .loop-engineer/worktrees/.
+
+
+ Analyst, planner, reviewer, and final judge run with read-only provider permissions.
+
+
+ Loop Engineer never commits, never pushes, never force-resets, and never runs a
+ destructive clean command.
+
+
+ loopeng clean removes only marked managed worktrees and preserves dirty
+ worktrees unless you pass --force.
+
+
+
+
Command execution
+
+ The local tester runs only configured allowlisted commands without a shell. It rejects
+ chaining, pipes, redirects, command substitution, denied binaries, and destructive Git
+ commands. The configuration schema rejects unknown keys, invalid permissions, and unsafe
+ tester assignments.
+
+
+
Credentials
+
+ Provider login stays inside the official Claude Code and Codex CLIs. The local dashboard can
+ only start those login flows; it has no password, API-key, OAuth-code, or access-token
+ field, and the dashboard API never handles credentials. The GUI binds to loopback only, uses
+ a CSRF token, and ships a strict Content Security Policy.
+
+
+
Prompt and data handling
+
+
+ Repository content enters prompts inside untrusted-data fences, so file contents are
+ treated as data rather than instructions.
+
+
Logs and reports redact common key, token, and password formats before storage.
+
Structured role handoffs are schema-validated before they become workflow state.
+
+
+
Honest limitations
+
+ Redaction cannot recognize every custom secret format. Keep
+ .loop-engineer/ private and treat run reports like build logs. The context
+ firewall and redactor reduce risk; they cannot prove provider behavior. Review generated
+ changes before merging them.
+
+
+ The complete security documentation, including the threat model and reporting process, lives
+ in the repository:
+ docs/security.md
+ and
+ SECURITY.md.
+