loopwithai-runner
v0.9.3
Published
Local runner for Loop with AI — executes your project's queued agent jobs (report/implement/drift) on your machine using your own AI CLI (Claude, Antigravity, or a custom agent), can START your dev server itself (LOOPAI_DEV) and expose it via a public pre
Maintainers
Readme
Loop with AI runner (loopwithai-runner)
Executes agent jobs on your machine. When someone clicks "Ask agent" / "Request report" in the app,
a job is queued; this runner polls, claims it, runs your local AI CLI, and posts the result back — the
"app requests → your localhost agent delivers" loop. No inbound connection needed (pull-based). Works with
Claude (default), Antigravity (agy), or a custom CLI — see SYNCEFFORTS_AGENT below.
Run
# published to npm — no clone/download; npx fetches + runs it (Node.js 18+):
SYNCEFFORTS_API_KEY=se_live_... SYNCEFFORTS_PROJECT_ID=<project id> npx -y loopwithai-runner
# or from source in this folder (Node built-ins only):
SYNCEFFORTS_API_KEY=se_live_... \
SYNCEFFORTS_PROJECT_ID=<project id> \
node runner.mjs- Requires the Claude CLI (
claude) installed and logged in — the runner pipes each job's prompt toclaude -p. Point at a different binary/wrapper withSYNCEFFORTS_CLAUDE_CMD. - Test the loop without Claude: add
SYNCEFFORTS_DRY=1— it claims jobs and posts a stub result, so you can verify the round-trip before wiring real inference.
Two job modes
Chosen per request in the app's New-request modal:
report(default) — Claude writes an analysis/report; the Markdown is posted back to the app. No code changes. This runner needs nothing special.implement— Claude edits your repository in place (following the project rules), then the runner appends a change report (new commits + diffstat + untracked files) to the result. To serve implement jobs, start the runner at/with your repo:SYNCEFFORTS_API_KEY=se_live_... \ SYNCEFFORTS_PROJECT_ID=<project id> \ SYNCEFFORTS_REPO=/path/to/your/repo \ node /path/to/syncefforts/runner/runner.mjsIt runs
claude -p --permission-mode bypassPermissionsin that repo. It never commits or pushes — changes are left in your working tree; you review and commit them (localhost-first).bypassPermissionsis required so a headless run doesn't hang on an approval prompt; it's your own machine. Override withSYNCEFFORTS_PERMISSION(e.g.acceptEdits) if you want narrower autonomy — but note stricter modes can stall a non-interactive run on tool prompts.
Env
| var | default | purpose |
|---|---|---|
| SYNCEFFORTS_API_KEY | — | org key (app → your project → API keys) |
| SYNCEFFORTS_PROJECT_ID | — | project to serve |
| SYNCEFFORTS_API_URL | deployed se-api | API base |
| SYNCEFFORTS_CLAUDE_CMD | claude | Claude CLI (reads prompt on stdin via -p) |
| SYNCEFFORTS_AGENT | claude | which agent CLI to run: claude | antigravity | custom. Fixed once at startup — a running runner never switches agents (so existing Claude runners never change). |
| SYNCEFFORTS_AGENT_MODEL | — | which model the chosen agent runs on (passed to the CLI's --model). Claude: an alias (opus/sonnet/haiku/fable) or full id; Antigravity: a name from agy models (e.g. "Gemini 3.1 Pro (High)") or a slug (gemini-3.5-flash); custom: whatever its model flag takes. Fixed once at startup like the agent. Blank ⇒ no flag ⇒ the CLI's own default (so an unset model keeps the Claude command byte-identical). |
| SYNCEFFORTS_ANTIGRAVITY_CMD | agy | Antigravity CLI, ≥1.1.5 (prompt via stdin → headless print mode, --print-timeout 15m, --dangerously-skip-permissions to auto-approve implement jobs). Install + sign it in separately. |
| SYNCEFFORTS_AGENT_MODEL_FLAG | --model | the custom adapter's model flag (used only when SYNCEFFORTS_AGENT_MODEL is set) |
| SYNCEFFORTS_AGENT_CMD / _ARGS / _APPROVE_ARGS / _PROMPT (stdin|file|arg) | — | the custom adapter |
| SYNCEFFORTS_REPO | current dir | repo dir for implement jobs (agent's cwd) |
| SYNCEFFORTS_PERMISSION | bypassPermissions | Claude permission mode for implement jobs |
| SYNCEFFORTS_POLL_MS | 5000 | poll interval |
| SYNCEFFORTS_DRY | — | 1 = stub result, don't call the agent |
Multiple agents: one runner runs one agent. To use Claude and Antigravity, start a second runner
with SYNCEFFORTS_AGENT=antigravity — the atomic job /claim lets them coexist. Which agents the app's
Connect screen offers is a per-project toggle (Project Settings → AI Agents); it drives the generated
command only, never a running runner.
Model choice (SE-038): a runner also fixes ONE model (SYNCEFFORTS_AGENT_MODEL) at startup, layered
on the agent. The Connect surfaces (header popover, onboarding wizard, AgentGuide) offer a model dropdown
per agent from a shared catalog (src/lib/agentModels.js) and append SYNCEFFORTS_AGENT_MODEL=… to the
generated command; Project Settings → AI Agents sets the per-agent default the dropdowns pre-select.
Blank = the CLI's default, so a runner started without it behaves exactly as before. To run the same agent
on two different models, start two runners with different SYNCEFFORTS_AGENT_MODEL.
Documentation loop (keeps the knowledge base current)
Every prompt now carries project memory from /context — existing Knowledge docs (with ids), recent
Decisions, and open Tasks — not just rules, so the agent works with institutional context instead of
blind.
After a successful implement job, the runner runs a second, credit-free local-Claude pass that
reviews the actual diff and records what changed via POST /projects/:id/document:
- Knowledge — updates the relevant doc in place (by id), or creates one for a genuinely new area.
- Decisions — appends one only when a real architectural/technical choice was made (context + decision + rejected alternatives).
- Tasks — marks the linked task done / in-progress, or files a follow-up the work surfaced.
Everything is written to the project's Knowledge / Decisions / Tasks, attributed to the runner in the Activity feed, and appended to the job result as a 📚 Documentation updated section — fully editable or reversible in the app. The pass is conservative (empty change → nothing recorded).
Toggle: on by default; turn it off per project in Project settings → Modules → Auto-document
(settings.modules.autodoc = false).
What it does per job
GET /projects/:id/jobs?status=pending→ for each,POST …/claim(atomic; skips if another runner grabbed it).- Builds a prompt = the project's rules + project memory (knowledge/decisions/open tasks from
/context) + the job's instruction + any referenced issue → runs Claude (in the repo for implement jobs). POST …/resultwith the Markdown output — plus, for implement jobs, the git change report and the documentation summary — (or…/failon error). The app's Agents view shows it live; the result is attributed to this key's title.
The runner honors the operating contract: it works under the project's rules and records output as job results. It does not edit rules, and for implement jobs it does not commit/push on your behalf.
