Loopr is a live dashboard for loop engineering. You write down what "good" looks like as a rubric, a maker builds an attempt, a checker grades that attempt against your rubric, and the two keep trading passes until every criterion clears the bar you set. The whole thing plays out on screen as it happens.
Here is the interesting part. In the default mode the backend never calls an LLM.
Your own connected Claude does the work, using its own tools and subscription, and
it pushes results onto the dashboard through the loopr MCP server. So anyone
watching sees the loop run live: the orchestrator's output, every subagent it
spawns, the score trend, the open findings, and the graded artifact itself.
If you would rather not drive it by hand, there is an autonomous mode
(LOOPR_MODE=api) where the backend runs the maker and checker agents itself on
an Anthropic API key.
- Open the dashboard and write your loop goal: what you want built or researched.
- Add a rubric. Type a few criteria, or import a whole rubric file. Set a target score and a safety cap on how many times it may iterate.
- Press Submit. That hands the finished spec to the loop as the job to run.
- Your connected Claude picks it up, does the work, grades itself honestly against the rubric, and iterates until it either hits the target or reaches the cap. You watch it converge, pass by pass.
You need Python 3.11 or newer and Node 18 or newer.
git clone https://github.com/homayounsrp/loopr.git && cd loopr
bash scripts/setup.sh # backend venv + deps, frontend deps, writes .env
bash scripts/start.sh # backend on :8000, frontend on :3000Then open http://localhost:3000 (it sends you to the dashboard).
The repo ships a project-scoped .mcp.json, so Claude Code finds the loopr
server on its own. Open the project folder in Claude Code and approve it when
asked (/mcp lists it). It points at the backend on http://localhost:8000.
Prefer to register it by hand, or run it on a different machine or port?
claude mcp add loopr \
-e LOOPR_URL=http://localhost:8000 \
-- ./backend/.venv/bin/python ./backend/app/mcp_server.pyOn Windows the interpreter lives at backend\.venv\Scripts\python.exe, so edit
the command in .mcp.json to match.
Once it is connected, just tell Claude what you want, something like "research the
last 3 days of AI agent news and land it on the dashboard." Claude reads the job
with get_workspace, does the work, and pushes results back with the tools listed
below.
Pressing Submit also puts a durable job on the backend. It survives restarts and reconnects, and it waits there until an orchestrator claims it, so a Submit is never lost. If you want a connected Claude to pick up every Submit on its own, point it at the poller:
python3 scripts/await_job.py # blocks until you Submit, then claims the jobIt prints the goal, rubric, target, and cap, and your Claude takes it from there.
Reading the job: get_workspace, get_dashboard_state, get_section_html.
Producing and grading: save_build, save_scores, save_critique, save_findings.
Live output: emit_output, which gives the orchestrator one pane and every
subagent its own.
Planning and control: set_plan, set_gate (a human checkpoint), set_schedule,
set_agents.
Configuration: set_rubric, set_target, set_loop_cap, send_brief (the goal).
Memory and lifecycle: export_state, resume_state, clear_outputs, reset, stop.
None of this works unless the backend is running, since the MCP server is a thin proxy over the backend's REST API.
Everything smart lives in the Python backend. The frontend is a thin viewer that streams state over a WebSocket and draws it.
backend/app/
domain/models.py Pydantic models (Snapshot, EvalResult, Finding, and friends)
state.py FactoryState: the shared state, rubric, builds, history, findings, gate, job queue
engine.py LooprEngine: applies each push, derives status, broadcasts snapshots
main.py FastAPI app, the /ws/factory WebSocket plus the /api/* REST control plane
mcp_server.py the loopr MCP server (stdio) that proxies /api/* for a Claude client
agents/ the maker and checker steps for api mode, plus the LLM client
sanitize.py strips <script> out of any pushed HTML
frontend/src/
lib/types.ts wire types that mirror the Snapshot
lib/useFactory.ts one auto reconnecting WebSocket hook
app/loopr/page.tsx the dashboard itself
scripts/
setup.sh, start.sh one command setup and run
dashctl.py a shell driver for the same REST API, handy when the MCP is not connected
await_job.py waits for a Submit and claims the job (the auto start poller)
.env is created from .env.example on first setup. Every value has a sensible
default, so an empty file runs in client mode.
| Variable | Default | What it does |
|---|---|---|
LOOPR_MODE |
client |
client means the backend makes no LLM calls and you drive it. api means the backend runs the agents itself. |
LOOPR_MODEL |
claude-sonnet-4-6 |
the default model in api mode |
ANTHROPIC_API_KEY |
unset | only needed in api mode. An OAuth token in ANTHROPIC_AUTH_TOKEN works too. |
The frontend talks to ws://localhost:8000/ws/factory by default. Override it with
NEXT_PUBLIC_WS_URL (and NEXT_PUBLIC_API_URL for the REST calls) in
frontend/.env.local. The MCP server and dashctl.py read LOOPR_URL, which
defaults to http://localhost:8000.
