Configuration
You almost never need to edit any of this. npx codeloop initwrites sensible defaults that work for 95 % of projects. Open this page only when you want to override the defaults — everything below is optional.
Every CodeLoop knob is in a small set of files under .codeloop/ in your project root, plus a handful of environment variables. npx codeloop initseeds sensible defaults — this page documents everything you can change.
File layout
your-project/
├── .codeloop/
│ ├── config.json # core config (this page)
│ ├── plugins.json # custom CLI runners — see /docs/plugins
│ ├── figma.json # Figma frame map — see /docs/design-compare
│ ├── sections.json # multi-section state — see /docs/multi-section
│ ├── baselines/ # visual baselines — see /docs/visual-review
│ └── runs/ # local artifact directory (gitignored)
├── designs/ # local design references (optional)
├── .cursor/
│ ├── mcp.json # auto-generated
│ └── rules/*.mdc # auto-generated
└── .claude/
├── settings.local.json # auto-generated
└── agents/* # auto-generatedconfig.json — full reference
{
"project_type": "auto",
"runners": {
"build": { "command": "npm run build", "timeout_ms": 60000 },
"lint": { "command": "npm run lint", "timeout_ms": 30000 },
"test": { "command": "npm test", "timeout_ms": 120000 }
},
"evidence": {
"target_app": "Photometry DB"
},
"screenshots": {
"enabled": true,
"tool": "playwright",
"base_url": "http://localhost:3000",
"wait_for": "networkidle",
"full_page": true,
"viewports": [
{ "name": "mobile", "width": 375, "height": 812 },
{ "name": "tablet", "width": 768, "height": 1024 },
{ "name": "desktop", "width": 1440, "height": 900 }
],
"urls": ["/", "/about", "/checkout"]
},
"visual_review": {
"threshold": 0.02,
"baseline_dir": ".codeloop/baselines",
"ignore_regions": [
{ "screen": "home", "rect": [0, 0, 1440, 64] }
]
},
"design_compare": {
"threshold": 0.85,
"scoring": "weighted_lab"
},
"recording": {
"enabled": true,
"max_duration_ms": 300000,
"fps": 30
},
"gate_check": {
"min_confidence": 0.94,
"require_all_tests": true,
"allow_lint_warnings": true,
"visual_severity": "warning",
"design_severity": "warning"
},
"sections": {
"enabled": false,
"spec_file": "docs/specs/_master.md",
"acceptance_dir": "docs/acceptance"
}
}Field reference
| Field | Default | Description |
|---|---|---|
project_type | "auto" | Auto-detect from project files. Override with flutter, react, nextjs, vue, angular, django, rails, xcode, android, dotnet. |
runners.<name>.command | Auto-detected | Shell command to run for this check. build, lint, and test are first-class; add custom names for additional checks. |
runners.<name>.timeout_ms | 60000 / 120000 | Hard timeout per runner. |
evidence.target_app | Auto-detected on init | The window title (or process name) of the desktop application CodeLoop should attach to for screenshots, video capture, and codeloop_interact. Auto-populated by npx codeloop init from AssemblyName (.NET) / PRODUCT_NAME (Xcode) / android:label (Android) / productName (Electron / Tauri) / displayName (React Native) / name (Flutter pubspec.yaml). When set on a desktop project, codeloop_capture_screenshot refuses to capture the IDE silently — it only attaches to the named app. 0.1.49 hardening: required for every desktop-UI framework, not just .NET/Xcode/Android. |
screenshots.enabled | true | Enable screenshot capture for UI projects. |
screenshots.tool | "playwright" | playwright, puppeteer, maestro (Flutter), simctl (iOS), adb (Android), screencapture (macOS native), powershell (Windows native). |
screenshots.base_url | http://localhost:3000 | Where the dev server lives during verify. |
screenshots.wait_for | "networkidle" | load, domcontentloaded, networkidle, or a CSS selector to wait for. |
screenshots.full_page | true | Capture the full scrollable page (vs. just the viewport). |
screenshots.viewports | mobile / tablet / desktop | Per-viewport capture matrix. |
screenshots.urls | From codeloop_discover_screens | Explicit URL list. If absent, CodeLoop crawls. |
visual_review.threshold | 0.02 | Pixel-difference fraction allowed before a diff fails. See Visual review. |
visual_review.baseline_dir | .codeloop/baselines | Where canonical baselines live. |
visual_review.ignore_regions | [] | Per-screen rectangles to exclude from diffing. Useful for timestamps, ads, A/B variants. |
design_compare.threshold | 0.85 | Minimum match score against Figma frames. See Design compare. |
design_compare.scoring | weighted_lab | pixel, weighted_lab, or structural. |
recording.enabled | true | Allow codeloop_start_recording on this project. |
recording.max_duration_ms | 300000 | Hard cap on a single recording. |
recording.fps | 30 | Target frames-per-second. |
gate_check.min_confidence | 0.94 | Minimum overall score to pass the gate. |
gate_check.require_all_tests | true | Block on any failing test, not just touched-file tests. |
gate_check.allow_lint_warnings | true | Lint warnings count as info, not blocker. |
gate_check.visual_severity | warning | Set to blocker to fail the gate on visual regressions. |
gate_check.design_severity | warning | Set to blocker to fail the gate on design drift. |
sections.enabled | false | Turn on multi-section orchestration. |
sections.spec_file | docs/specs/_master.md | Master spec path. |
sections.acceptance_dir | docs/acceptance | Per-section acceptance directory. |
Platform recipes
Flutter
{
"project_type": "flutter",
"runners": {
"build": { "command": "flutter build apk --debug" },
"test": { "command": "flutter test" },
"lint": { "command": "dart analyze" }
},
"screenshots": {
"tool": "maestro",
"device": "Pixel_6_API_33"
}
}Next.js / React
{
"project_type": "nextjs",
"runners": {
"build": { "command": "npm run build" },
"test": { "command": "npx jest" }
},
"screenshots": {
"tool": "playwright",
"base_url": "http://localhost:3000",
"urls": ["/", "/dashboard", "/settings"]
}
}Vue / Nuxt
{
"project_type": "vue",
"runners": {
"build": { "command": "npm run build" },
"test": { "command": "npx vitest run" }
}
}Django / Rails / Go (via plugin)
For non-built-in stacks, use .codeloop/plugins.jsonto wire your existing CLI test runner into the loop. Plugins behave exactly like first-party runners — failures count toward the gate and surface in the dashboard.
iOS (Xcode)
{
"project_type": "xcode",
"runners": {
"build": { "command": "xcodebuild -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 15'" },
"test": { "command": "xcodebuild test -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 15'" }
},
"screenshots": { "tool": "simctl" }
}Android (gradle)
{
"project_type": "android",
"runners": {
"build": { "command": "./gradlew assembleDebug" },
"test": { "command": "./gradlew test" }
},
"screenshots": { "tool": "adb", "device": "emulator-5554" }
}.NET / WPF
{
"project_type": "dotnet",
"runners": {
"build": { "command": "dotnet build" },
"test": { "command": "dotnet test" }
},
"screenshots": { "tool": "powershell" }
}Desktop-app mode (0.1.49+)
Whenever codeloop init detects a desktop UI framework, it sets evidence.target_app in config.jsonand every screenshot / video / interaction call from then on attaches to THAT process — not the IDE, not the primary monitor.
Frameworks classified as desktop-app projects (and therefore covered by this auto-protection):
- .NET — WPF, WinForms, MAUI, Avalonia, WinUI, UWP (anything with
<UseWPF>true</UseWPF>,<UseWindowsForms>true</UseWindowsForms>, MAUI / Avalonia / WinUI SDK refs, or<OutputType>WinExe</OutputType>). Pure ASP.NET / Blazor Server projects are not considered desktop-app projects — they ship as web apps. - Xcode — any iOS / macOS / tvOS / watchOS project.
- Android — any project with an
AndroidManifest.xmlorbuild.gradle(.kts)at the root. - Node desktop wrappers — Electron (
electrondependency), Tauri (@tauri-apps/cli), React Native (react-native), Expo (expo). - Flutter desktop — any Flutter project with a
windows/,macos/, orlinux/sub-target.
If the target app is not running when codeloop_capture_screenshot is called, CodeLoop attempts to launch it via launch_app. On Windows that includes parsing <OutputPath> and <BaseOutputPath> out of the picked .csproj, and a fallback to Get-StartApps for MSIX / Microsoft Store apps.
Run codeloop_self_testas your first MCP call on any new desktop project — it walks the auto-detection, target-app resolution, and PNG decoder paths in < 1 s and tells you exactly which preflight check would have failed.
codeloop_interact coords reference (0.1.49+)
codeloop_interact accepts a coords enum that tells the MCP server how to interpret x / y:
| Mode | Meaning | When the agent picks it |
|---|---|---|
auto (default) | Heuristic — if (x,y) falls inside the target window’s client rect, treat as window-relative; otherwise treat as screen-absolute. | Most common case. Safe default. |
window | Coordinates are relative to the target window’s client area. CodeLoop adds the window origin (and applies the inverse DPI factor) before sending the click. | Agent inspected the window via accessibility tree / browser DOM and computed in window space. |
screen | Coordinates are absolute screen pixels. CodeLoop sends them through unchanged. | Agent already computed in screen space. |
screenshot | Coordinates were computed against the captured PNG that CodeLoop returned. CodeLoop scales by (actual_window_width / screenshot_width) and adds the window origin (and inverse DPI). Pass screenshot_path so CodeLoop can read the dimensions. | The MCP transport sometimes downscales screenshots; this mode unwinds that. |
DPI awareness: window_bounds on the capture response now includes dpi_x and dpi_yfor high-DPI displays (Retina, 200 % Windows scaling, Linux GDK_SCALE).codeloop_interact applies the inverse factor in window and screenshotmodes so a click on a 4K monitor at 200 % lands at the right pixel.
Environment variables
| Variable | Required | Description |
|---|---|---|
CODELOOP_API_KEY | Yes | Your CodeLoop API key. |
CODELOOP_API_URL | No | Override backend URL. Defaults to https://api.codeloop.tech. |
CODELOOP_PROJECT_DIR | No | Force the project root path. Auto-written into .cursor/mcp.json by npx codeloop init as a workspace pin. 0.1.49 hardening: at MCP boot, CodeLoop validates that this path exists on disk and contains .codeloop/config.json; if stale (e.g. you renamed the workspace), it logs a single warning and falls back to discovery instead of getting wedged. Re-run npx codeloop init from the new path to refresh the pin. |
CODELOOP_MODE | No | cloud (default) or local (self-host). |
CODELOOP_OFFLINE | No | true skips backend calls; usage queues locally. |
CODELOOP_LOG_LEVEL | No | debug, info, warn, error. |
FIGMA_API_TOKEN | For Figma compare | Personal access token for the Figma REST API. See Design compare. |
DASHBOARD_PORT | No | Override the default 3737 port for the local dashboard. |
BACKEND_URL | No | Read by codeloop doctor to verify backend reachability. |
Plugin configuration
Drop a .codeloop/plugins.json in the project root to wire any CLI test runner into the verify suite. See the full schema in Plugin SDK. Plugin entries appear next to first-party runners in codeloop_verify output and contribute to the gate score.
Multi-section configuration
Enable sections.enabled = true and create per-section spec / acceptance files. codeloop_section_status reads and writes the state machine; see Multi-section orchestration for the full lifecycle.
Design references
Two paths:
- Figma —
.codeloop/figma.json+FIGMA_API_TOKENenv var. See Design compare. - Local PNG —
designs/<screen>/<viewport>.png. No credentials, no network.
OSS plan project marker
If you applied for the free OSS plan via /oss-application, your approval ties the API key to your repo. There is no per-project config to add — the backend resolves the plan from the key itself.
Self-host configuration
Point CODELOOP_API_URL at your stack and set CODELOOP_MODE=local. See Self-host runbook for the full Docker Compose env reference.
Next Steps
- Tool Reference — understand each tool's capabilities
- CLI reference — invoke any of these from the terminal
- Plugin SDK — wire any test runner into the loop
- FAQ — common questions