Overview
Agent Loop — Manage autonomous AI coding agents from web or CLI. Runs on Mac or VPS. Supports Claude Code, OpenAI Codex, and Cursor runtimes. Modes for development, planning, project management, and custom tasks. CodeRabbit integration for code reviews. Real-time log streaming. One-command VPS deployment.
Key Features
- Autonomous GitHub issue processing with priority-based ordering
- Mobile-friendly web dashboard with real-time log streaming
- Multiple modes: Developer, Developer (custom task), Plan, Project Manager
- Three runtimes: Claude Code, OpenAI Codex, and Cursor
- Issue selector — pick a specific issue or let the agent auto-select
- CodeRabbit pre-PR code review
- Current issue tracking with clickable links in the dashboard
- Settings UI for managing API keys with validation status
- Multi-instance support — run several agents in parallel
- Git worktree isolation — agents never touch your main checkout
- One-command deployment to Linode VPS
- Webhook notifications (Slack / Discord)
- Timeout protection, failure limits, and log retention
Quick Start
1. Clone & Install
git clone https://github.com/dekadem/agentloop
cd agentloop
npm install
2. Configure Environment
cp .env.example .env
# Edit .env with your keys
3. Run the Dashboard
# Development (auto-reload)
npm run dev
# Production
npm start
Open http://localhost:3000 — log in with the AUTH_TOKEN you set in .env.
4. Run the Agent (CLI)
# Auto-detect runtime, default prompt
./agent-loop.sh
# Specific runtime + model
./agent-loop.sh --runtime claude -m claude-opus-4.6
# Process a remote repo
./agent-loop.sh --runtime claude --repo https://github.com/user/repo
Environment Variables
| Variable | Required | Description |
|---|---|---|
AUTH_TOKEN | Yes | Bearer token for dashboard auth. Pick any random string. |
ANTHROPIC_API_KEY | Yes* | API key for the Claude Code CLI runtime. Starts with sk-ant-. |
OPENAI_API_KEY | Yes* | API key for the OpenAI Codex CLI runtime. Starts with sk-. |
GITHUB_TOKEN | Yes | GitHub Personal Access Token with repo scope. |
CODERABBIT_API_KEY | No | CodeRabbit API key for pre-PR code reviews. Starts with cr-. |
PORT | No | Dashboard server port. Default: 3000. |
Web Dashboard
The dashboard is a mobile-first single-page app at the server root. It supports:
- Login — authenticates with your
AUTH_TOKEN, stored inlocalStorage - Agent list — newest first, with live status badges and current issue tracking
- Start new agent — repo dropdown, runtime/model selection, mode picker, optional issue selector
- Modes — Developer (auto/specific issue), Developer (custom task), Plan, Project Manager
- Issue tracking — shows which issue the agent is working on with a link to GitHub
- Live logs — real-time log streaming via SSE, auto-opens for running agents
- Settings — edit API keys with validation status indicators
- Form memory — previous choices are pre-selected on next use
- Stop agent — kills the process group and cleans up lock files
- Auto-refresh — agent list refreshes every 15 seconds
API Reference
All /api/* endpoints require authentication. Pass your token as:
Authorization: Bearer <AUTH_TOKEN>
# or query param:
?token=<AUTH_TOKEN>
List all agent instances.
Response
[{
"id": "1",
"pid": 12345,
"repo": "https://github.com/user/repo",
"model": "claude-opus-4.6",
"runtime": "claude",
"startedAt": "2026-02-22T10:00:00.000Z",
"status": "running",
"exitCode": null
}]
Start a new agent instance.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
repo | string | Yes | GitHub repo URL |
model | string | No | Model name (default: claude-opus-4.6) |
runtime | string | No | claude, codex, or cursor (default: claude) |
mode | string | No | dev, dev-custom, plan, or pm |
issue | string | No | Specific issue number to work on (dev mode only) |
instanceId | string | No | Custom instance ID |
maxIterations | number | No | Max iterations, 0 = unlimited |
prompt | string | No | Custom prompt text |
Response (201)
{
"id": "1",
"pid": 12345,
"repo": "https://github.com/user/repo",
"model": "claude-opus-4.6",
"runtime": "claude",
"status": "running"
}
Stop a running agent. Kills the entire process group.
Response
{ "id": "1", "status": "stopped" }
Retrieve agent log files.
| Query Param | Description |
|---|---|
file | Optional. Return a specific log file by name. |
Without file, returns the 20 most recent log files and the content of the latest one.
Server-Sent Events stream of the latest log file. Events:
| Event | Data |
|---|---|
log | { text, file } — new log content |
status | { status, pid } — agent status |
heartbeat | Status update (every 2 s) |
List GitHub repos accessible to the authenticated user.
Response
[{ "nameWithOwner": "user/repo", "url": "https://github.com/user/repo" }]
List open issues for a repo, excluding WIP/DONE/NEEDS_HUMAN labels.
Response
[{ "number": 5, "title": "Fix login bug" }]
Get current environment variables (values masked).
Validate API keys against their respective services. Returns { ok, message } per key.
Update environment variables. Values containing •••• are ignored (keeps existing). The service auto-restarts after saving.
Collects status.md dashboards from all known repos in .repos/.
CLI Options
./agent-loop.sh [options]
| Flag | Default | Description |
|---|---|---|
--runtime <rt> | auto | Runtime: claude, codex, copilot, cursor, or auto |
--repo <url> | — | GitHub repo URL to clone (server use) |
--id <id> | auto | Instance ID (lock-file based) |
-n <count> | 0 | Max iterations (0 = unlimited) |
-m <model> | per runtime | Model to use |
-p <file> | prompt.txt | Prompt file path |
-d <seconds> | 60 | Delay between iterations |
-t <seconds> | 2700 | Timeout per agent run (45 min) |
--max-failures <n> | 3 | Max consecutive failures before stopping |
--webhook <url> | — | Slack/Discord webhook URL |
--dry-run | — | Print the command without executing |
-h, --help | — | Show help |
Examples
# Desktop with Cursor
./agent-loop.sh --runtime cursor -m claude-4.6-opus
# Server, 5 iterations, custom prompt
./agent-loop.sh --runtime claude --repo https://github.com/user/repo \
-n 5 -p prompts/prompt_qa.txt
# Second parallel instance with webhook
./agent-loop.sh --id 2 --webhook https://hooks.slack.com/services/XXX
Runtimes
| Runtime | CLI | Default Model | Use Case |
|---|---|---|---|
claude | claude | claude-opus-4 | Server or desktop. Uses ANTHROPIC_API_KEY. Default from dashboard. |
codex | codex | gpt-5.2-codex | Server or desktop. Uses OPENAI_API_KEY. |
copilot | copilot | gpt-5.2-codex | Server or desktop. Uses GitHub Copilot subscription via gh. Multi-model. |
cursor | cursor | auto | Desktop only. Uses Cursor subscription. |
auto | Auto-detect | — | Tries cursor first, falls back to claude. |
Prompt System
Prompts define what the agent does each iteration. They live in the prompts/ directory and are plain text files passed to the AI runtime.
| File | Role | Description |
|---|---|---|
prompt.txt |
Developer | Default. Picks the highest-priority GitHub issue, implements a fix, runs CodeRabbit review, creates a PR, waits for CI, addresses review comments, and labels the issue DONE. |
prompt_custom_task.txt |
Developer (custom) | Template for custom tasks. Wraps the user's task description with the PR/CI/review workflow. Used by the "Developer (custom task)" mode. |
prompt_productplanner.txt |
Product Planner | Browses the codebase and goal.md, identifies improvements, and creates new GitHub issues. |
prompt_projectmanager.txt |
Project Manager | Reviews open issues, assigns priority labels, and closes non-applicable issues. |
prompt_qa.txt |
QA Tester | Opens the PR preview URL, performs UI tests, and reports results as a PR comment. |
Default Workflow (prompt.txt)
- Pick issue — lists open issues excluding WIP/DONE/NEEDS_HUMAN; prioritises by label then age (or uses a specific issue if selected)
- Implement — fetches full issue with comments, labels WIP, creates a plan, writes code
- Pre-review — runs CodeRabbit on uncommitted changes, fixes critical findings
- Open PR — runs
tools/create-pr.sh --issue N - Wait for CI —
gh pr checks --watch; labels NEEDS_HUMAN on failure - Address reviews — fetches review comments, pushes fixes, re-checks CI
- Done — labels DONE, removes WIP
Dashboard Modes
| Mode | Description |
|---|---|
| Developer | Auto-selects or uses a specific issue, runs the full dev workflow |
| Developer (custom task) | User describes the task, agent implements it with PR/CI/review workflow |
| Plan | Browses codebase, creates new GitHub issues for improvements |
| Project Manager | Reviews issues, assigns priority labels, closes irrelevant ones |
tools/create-pr.sh
Creates a branch, commits staged changes, pushes, and opens a GitHub PR.
./tools/create-pr.sh [options] <branch> <commit-msg> [pr-title] [base-branch]
| Option | Description |
|---|---|
--issue <N> | Link PR to GitHub issue (adds "Closes #N") |
--auto-merge | Enable squash auto-merge after creation |
tools/setup-branch-protection.sh
Configures a GitHub repo for safe auto-merge:
- Enables auto-merge in repo settings
- Sets branch protection on
main: required CI checks, 1 approving review, dismiss stale reviews
./tools/setup-branch-protection.sh [owner/repo]
tools/pr-review-comments.sh
Fetches and formats PR review comments (top-level reviews + inline file comments). Requires jq.
./tools/pr-review-comments.sh [pr-number]
Deployment
One-command Linode deploy
python3 deploy-linode.py \
--linode-token YOUR_LINODE_API_TOKEN \
--anthropic-key sk-ant-... \
--github-token ghp_... \
--repo https://github.com/user/repo
Creates a Nanode ($5/mo), installs everything, starts the dashboard. Optional: --region, --coderabbit-key.
Update production
./update-production.sh root@YOUR_SERVER_IP
Manual setup (any Ubuntu/Debian VPS)
sudo ./setup-server.sh
What it installs
- Node.js 22 — from NodeSource
- Git and GitHub CLI (
gh) - Claude Code CLI, OpenAI Codex CLI
- CodeRabbit CLI
- Caddy — reverse proxy with automatic HTTPS
What it configures
- Creates an
agentloopsystem user - Installs to
/opt/agentloopwithnpm install - Creates
.envfrom.env.example - Creates a systemd service with
Restart=always - Prepares a Caddyfile for your domain
Architecture
┌─────────────────────────────────┐
│ Your Phone / Browser │
└────────────────┬────────────────-┘
│ HTTPS
┌────────────────▼─────────────────┐
│ Caddy (reverse proxy) │
└────────────────┬─────────────────-┘
│ :3000
┌──────────────────────▼──────────────────────┐
│ Hono Server (Node.js) │
│ ┌──────────┐ ┌──────────┐ ┌───────────┐ │
│ │ REST API │ │ SSE Logs │ │ Static UI │ │
│ └────┬─────┘ └────┬─────┘ └───────────┘ │
└───────┼─────────────┼───────────────────────-┘
│ spawn │ read
┌─────────▼─────────┐ │
│ agent-loop.sh │ │
│ ┌──────────────┐ │ │
│ │ Claude Code │ │ │
│ │ Codex/Cursor │ │ │
│ └──────┬───────┘ │ │
│ │ gh CLI │ │
└─────────┼────────-┘ │
│ │
┌──────────────▼──┐ ┌──────▼───────┐
│ GitHub (repos, │ │ Log files │
│ issues, PRs) │ │ (.repos/) │
└─────────────────┘ └──────────────┘
Directory Structure
agentloop/
├── server/
│ ├── index.ts # Hono API server
│ └── public/
│ ├── index.html # Dashboard UI
│ └── docs.html # This documentation
├── prompts/
│ ├── prompt.txt # Default developer prompt
│ ├── prompt_custom_task.txt # Custom task template
│ ├── prompt_productplanner.txt
│ ├── prompt_projectmanager.txt
│ └── prompt_qa.txt
├── tools/
│ ├── create-pr.sh # PR creation + auto-merge
│ ├── setup-branch-protection.sh
│ └── pr-review-comments.sh
├── lib/
│ └── common.sh # Shared shell utilities
├── agent-loop.sh # Main orchestration script
├── setup-server.sh # VPS provisioning
├── deploy-linode.py # One-command Linode deploy
├── update-production.sh # Update production server
├── Caddyfile # Reverse proxy config
├── .env.example # Environment template
├── package.json # Node.js dependencies
└── .repos/ # Cloned repos (runtime)
└── <owner>/<repo>/
├── logs/agent/ # Agent logs + status
└── .worktrees/ # Git worktrees per worker