共享 AI 代理工作流基础设施,用于可重用的本地和远程开发循环。
AI 翻译
Shared AI agent workflow infrastructure for reusable local and remote development loops
插件JavaScript · TypeScriptGitHub @mfittko自行安装运营者未确认
试用过了吗? 点一下就好,无需登录。
正在加载完整 README。 以下为已保存的摘录。
Turn a GitHub issue into a merged PR autonomously, up to a human-approval checkpoint.
Harness-agnostic by design. The same dev loop runs three ways over one shared core (packages/core): as a Claude Code plugin, as a Pi extension, and as a standalone CLI. Routing, gates, and phases are defined once in the core; the plugin and extension are thin integrations over that shared workflow.查看完整 README ↗dev-loops ships reviewed, tested PRs with the highest autonomy that is still safe. Deterministic gates and a judge decide; humans decide only what tooling cannot, or what the repo requires.
Turn a GitHub issue into a merged PR autonomously, up to a human-approval checkpoint.
Harness-agnostic by design. The same dev loop runs three ways over one shared core (packages/core): as a Claude Code plugin, as a Pi extension, and as a standalone CLI. Routing, gates, and phases are defined once in the core; the plugin and extension are thin integrations over that shared workflow.
A dev loop takes a GitHub issue through seven lifecycle phases — from intake to merge — with deterministic routing, self-correcting review gates, and autonomous execution until a human approves. The phase is always consultable from the deterministic state model in packages/core/src/loop/lifecycle-state.mjs.
| Phase | What happens |
|---|---|
issue_intake | Normalize the issue, confirm scope, detect linked PRs |
refinement | Elaborate the spec, run a bounded audit, harden acceptance criteria |
implementation | Build the accepted scope on a feature branch or via Copilot |
draft_gate | Gate review at the draft→ready boundary before marking the PR ready |
feedback_resolution | Fix, reply to, and resolve review threads on GitHub |
pre_approval_gate | Final gate review: verify evidence, CI, and unresolved threads |
merge | Merge the PR and write the retrospective checkpoint |
The public routing contract is the Public Dev Loop Contract.
dev-loop is the single public entrypoint. Drive it in natural language — it resolves the authoritative current state, picks the correct internal strategy, and routes deterministically. You never name internal strategies.
start dev loop on issue 112 # start work on an issue
auto dev loop on issue 112 # run autonomously to the human-approval checkpoint
continue dev loop on PR 88 # continue follow-up on an open PR
See the canonical shorthand mapping in the Public Dev Loop Contract.
dev-loop (natural language) is the catch-all router — reach for the named commands below only when you want a direct, unrouted entrypoint. The syntax differs by harness:
/loop-start, /loop-auto, …/dev-loops start, /dev-loops auto, …| Command | Claude Code | Pi | Does |
|---|---|---|---|
| start | /loop-start <issue> | /dev-loops start <issue> | Start a dev loop on an issue |
| auto | /loop-auto <issue> | /dev-loops auto <issue> | Run autonomously to the human-approval checkpoint |
| continue | /loop-continue [issue|pr] | /dev-loops continue [issue|pr] | Continue; bare resumes the in-progress board item |
| start-spike | /loop-start-spike <question> | /dev-loops start-spike <question> | Time-boxed spike (or --file <path>) |
| info | /loop-info <issue|pr> | /dev-loops info <issue|pr> | Read-only state summary |
| status | /loop-status | /dev-loops status | Readiness check (gh auth, git repo, subagent) |
| enqueue | /loop-enqueue <issue|pr|text> | — | Queue an issue/PR, or capture an idea as a grilled issue |
| grill | /loop-grill <issue|plan> [--auto] | — | Socratic Q&A grill of an issue or plan before the loop |
| queue-status | /loop-queue-status | — | Show the queue board grouped by column |
| review | /loop-review <pr> | — | Run a standalone, on-demand review pass over a PR (no gate obligations) |
| review-ui | /loop-review-ui <pr> | — | Review a PR in a running-app UI loop |
Beyond the per-issue loop entrypoints, the Pi /dev-loops command and the dev-loops CLI also expose standalone utilities: help, status, doctor, gates (status is the same readiness check as loop-status above). hide works only inside Pi — the dev-loops hide CLI subcommand is recognized but intentionally exits non-zero (session-local Pi UI behavior). Everything above is also available as a skill/agent — inside Pi, hand work to the dev-loop skill rather than calling internal routed skills (local-implementation, copilot-pr-followup, final-approval) directly.
/loop-review-ui/loop-review-ui <pr> reviews a PR by proving the change in the running app from an isolated worktree, rather than reading the diff alone. It runs the loop resolve → provision/boot → auth+drive → diagnose → report → teardown: it provisions a worktree for the PR head and boots the app, authenticates and drives the changed UI flows (capturing a screenshot + state + snapshot per step), maps captured failures back to the diff, posts a head-pinned pending PR review plus a self-contained screenshot artifact, then tears down — always emitting a side-effect ledger.
When to use it vs. the standard review angle: reach for /loop-review-ui when a change is only really provable by exercising it in a browser — a rendered flow, a create/edit/upload interaction, or a swallowed server error the UI hides behind a success state. It is the running-app sibling of, not a replacement for, the diff-reading review angle or the Copilot gate; those still run for logic, structure, and correctness. It requires a per-project run/auth recipe in .devloops and runs end-to-end on any harness; only the report-artifact hosting is harness-aware. On Claude Code the self-contained artifact gets a zero-setup hosted link (Claude Artifacts); off-Claude the same artifact is still produced but emitted unhosted with a stated reason (a hosted GitHub-native link is a tracked follow-up), never a hard stop. See the UI-Review Run/Auth Recipe Contract to wire a consuming repo.
All examples pin to <version> = the dev-loops version you installed; keep the CLI, plugin, and extension on the same version so behavior can't drift.
The repo ships a plugin rooted at .claude/ (manifest at .claude/.claude-plugin/plugin.json) exposing the dev-loop agents, skills, and hooks. Install it from the bundled marketplace catalog:
/plugin marketplace add mfittko/dev-loops # register the marketplace
/plugin install dev-loops@dev-loops # install the plugin
Or load it directly for a single session without installing:
claude --plugin-dir .claude
Installed from npm, point at the bundled copy: claude --plugin-dir node_modules/dev-loops/.claude.
The hooks provide the gh pr ready draft-gate guard, an opt-in read-only boundary for the main agent (DEVLOOPS_MAIN_AGENT_READONLY=1), and an opt-in coordinator→worker delegation boundary — a dispatched dev-loop coordinator delegates tracked-repo-file mutations and targeted code-verification/build checks to a worker subagent rather than running them inline (DEVLOOPS_COORDINATOR_READONLY=1). The hook blocks known inline verification commands; local full-repository validation (bun run verify) is requested only through dev-loops gate resolve-validation on a clean commit, not delegated as a direct worker command. Skill references to a consumer repo's own PLAN.md / AGENTS.md resolve against that repo, by design.
The dev-loop coordinator agent sets experimental.cacheTtl: 1h in its frontmatter. The coordinator often waits more than 5 minutes for its child agents, and the 1-hour prompt cache keeps its context warm across those waits. No other agent sets the key, so short-lived roles keep the cheaper 5-minute default. The key needs Claude Code v2.1.248 or later. Claude Code ignores the key for subagents while a subscription draws on usage credits.
Auto-mode permission rules. The gate verdict post is the sanctioned gate path. The Claude Code auto-mode classifier can still deny it (observed reason "[CI Bypass]"), and it can deny the ready flip ready-for-review.mjs (observed reason "[Auto-Mode Bypass]"). Add an allow rule to permissions.allow in the project .claude/settings.json for each form the agents use:
Bash(dev-loops gate upsert-verdict:*) for the CLI verdict post;Bash(node scripts/github/upsert-checkpoint-verdict.mjs:*) for the bare script verdict post, with the script path exactly as the agent types it;Bash(node scripts/github/ready-for-review.mjs:*) for the bare script ready flip;Bash(dev-loops-run:*) for the launcher form dev-loops-run scripts/.... This repo's own .claude/settings.json carries it.Observed during the v1.0.5 drain: only an exact command prefix matched, and a mid-pattern wildcard such as Bash(node scripts/github/*.mjs:*) did not match. In the same drain, an ask rule on the bare form did not gate the launcher form: with Bash(dev-loops-run:*) allowed, Bash(node scripts/github/merge-pr.mjs:*) did not prompt for dev-loops-run scripts/github/merge-pr.mjs. For a merge or filing prompt, add the launcher-form ask rules Bash(dev-loops-run scripts/github/merge-pr.mjs:*) and Bash(dev-loops-run scripts/github/create-issue.mjs:*).
Gate reviewers write their findings artifacts under tmp/gate-reviews/ with the Write tool. The Write tool path needs no allow rule. The classifier denies a Bash write of an artifact (redirect, heredoc, tee, or an inline script), observed with reasons "[Self-Approval]" and "[CI Bypass]". A Write(...) or Edit(...) path rule does not apply to a Bash command. A reviewer's blocked artifact goes through dev-loops-run scripts/github/emit-reviewer-blocked.mjs under the Bash(dev-loops-run:*) rule above.
Consumer entry contract. The plugin ships prompts, skills, agents, and hooks, plus a hand-authored .claude/package.json + .claude/package-lock.json that pin the published dev-loops npm package to the release version. Claude Code's native plugin dependency auto-install runs npm ci --ignore-scripts at cache time, landing the full toolchain under .claude/node_modules/dev-loops/ (only the manifest and lockfile are committed — never node_modules). Every generated skill/command/agent invocation runs through the dev-loops-run launcher on the plugin bin/ PATH, which resolves the dev-loops root in order: a live source checkout found by walking up from the current directory always wins unconditionally (so local edits are dogfooded with no release), else a live source checkout found by walking up from the launcher's own real binary location, else the auto-installed .claude/node_modules/dev-loops, else a loud hard-stop that names the unresolved wrapper — never a raw node scripts/*.mjs against the checkout, and never a silent raw-gh fallback. The single-source CLI subcommand reference is tracked in issue #1376.
pi install npm:dev-loops@<version> # global, pinned npm package
pi install -l npm:dev-loops@<version> # project-local (.pi/settings.json)
You can also install from git:
pi install git:github.com/mfittko/dev-loops@<tag-or-sha> # global
pi install -l git:github.com/mfittko/dev-loops@<tag-or-sha> # project-local
Once a project is trusted, Pi auto-installs missing packages on startup. Install pi-subagents the same way when the repo relies on async loop behavior.
Run the CLI version-pinned:
npx dev-loops@<version> --help
A global npm install -g dev-loops is an optional bare-shell convenience only — it is not version-pinned, updates independently of the plugin/extension, and can silently drift out of sync (#833/#1036). Prefer the pinned npx invocation.
Universal:
>=24gh installed and authenticated for GitHub/Copilot workflowsFor contributors and CI:
1.4.1 exactly — the repository's package manager, workspace installer, script runner, and unit-test runnerbun install --frozen-lockfile from a clean checkout; bun.lock is the only supported dependency lockfileThis split is deliberate: published packages and the public CLI continue to install and execute with Node >=24 and do not require Bun. npm remains the registry client for packing, publishing, dist-tags, registry queries, and provenance.
Pi-harness only:
pi-subagents for async workflow behavior@earendil-works/pi-coding-agent and @earendil-works/pi-tuiDefaults ship in packages/core/src/config/extension-defaults.yaml. A repo-local .pi/dev-loop/defaults.* layer merges on top of them when present, then consumer repos override everything in a .devloops file at the repo root (.devloops.yaml / .yml / .json are also accepted); .devloops is authoritative when present. The legacy .pi/dev-loop/settings.* and overrides.* fallbacks were removed at the v1.0.0 cut (ADR 0017) and no longer load; move any such file's contents into .devloops.
npx dev-loops@<version> gates # print what reviewers will check
Key surfaces:
requireCi CI-precondition toggle (gates.draft.requireCi, gates.preApproval.requireCi; default true). Set a gate's requireCi: false to opt that gate out of the CI precondition — e.g. a repo with no CI can run the loop end-to-end instead of blocking at the gate.refinement.maxCopilotRounds caps Copilot re-review rounds (default 5). Set maxCopilotRounds: 0 to disable the Copilot gate entirely — local-harness-only review (draft_gate → pre_approval_gate), useful when the repo has no Copilot reviewer configured. By default one converged Copilot review stands for later heads, and pre_approval_gate reviews each head; set refinement.requireCopilotConvergenceAtLatestHead: true to open a new Copilot cycle for every significant post-convergence change.uiReview surface configures the /loop-review-ui route (per-project run/boot command, login recipe, log/exception patterns)postMerge.actions declares local actions (sync checkout, restart a local service, smoke check) a harness hook runs sequentially, in order, after the dev-loop's merge succeeds. Each action needs name + run; optional onlyIfChanged scopes it to the merged PR's changed files (plain substring matching, not a glob/regex — a pattern matches when any changed file path contains it), verify polls a command until it exits 0, and timeoutMs/verifyTimeoutMs/verifyIntervalMs bound the run/verify/poll timing. Absent (the default) means no action runs. See packages/core/src/loop/run-post-merge-actions.mjs for the runner and scripts/loop/run-post-merge-actions.mjs for the CLI both harness hooks invoke.Full details: the shipped defaults in packages/core/src/config/extension-defaults.yaml and the loader in packages/core/src/config/config.mjs.
From 1.0, dev-loops follows semantic versioning for its public surface — breaking changes to it bump the major version:
.devloops configuration surface — gate angles, personas, gates.* (including each gate's requireCi toggle and gates.preApproval.requireCi), refinement.*, uiReview.*, postMerge.*, autonomy.*, and workflow.*. The authoritative validator is the config loader in packages/core/src/config/config.mjs; schemas/dev-loop-config.schema.json is generated from it (node scripts/generate-config-schema.mjs) and covers the full file-level surface — only cross-field refinements stay zod-only.dev-loop command and skill surface — the natural-language dev-loop router and the named /loop-* entrypoints.Internal strategy names, script internals, and undocumented helpers are not part of the stable surface and may change in a minor release. New config keys and gate angles are additive (minor); removing or repurposing an existing one is a breaking change (major).
A deterministic container image with all required tooling for dev-loop operation.
docker build -t dev-loops .
| Variable | Purpose | Required |
|---|---|---|
GH_TOKEN | GitHub token for gh CLI and API calls | Yes |
OPENAI_API_KEY | LLM provider key (only for pi / LLM-backed operations) | No |
Smoke test the image with a minimal read-only info call:
docker run --rm -e GH_TOKEN="$GH_TOKEN" dev-loops dev-loops loop info --repo mfittko/dev-loops --issue 1
Verify the toolchain is reachable:
docker run --rm dev-loops node --version
docker run --rm dev-loops pi --version
docker run --rm dev-loops dev-loops --version
docker run --rm dev-loops gh --version
The Dockerfile pins exact versions for Node.js (base image), Bun 1.4.1, the pi CLI, pi extensions, and gh CLI; paired with the committed bun.lock and a frozen Bun install, repeat builds produce functionally identical toolchains. Node remains present because it is the shipped consumer runtime and runs the Playwright browser suite.
Runtime patterns:
# Interactive Pi sharing host config (sessions, models, settings write back to ~/.pi)
docker run -it --rm -e GH_TOKEN="$GH_TOKEN" -v "$HOME/.pi:/home/node/.pi" dev-loops pi
# Interactive Pi, clean (ephemeral ~/.pi; provider auth via env)
docker run -it --rm -e GH_TOKEN="$GH_TOKEN" -e OPENAI_API_KEY="$OPENAI_API_KEY" dev-loops pi
# Full dev-loop over a live repo worktree mounted at /workspace
git clone --mirror [email protected]:owner/repo.git /tmp/mirror
git --git-dir=/tmp/mirror worktree add /tmp/run /tmp/mirror/main
docker run -it --rm -e GH_TOKEN="$GH_TOKEN" -v "$HOME/.pi:/home/node/.pi" -v /tmp/run:/workspace dev-loops pi
bun install --frozen-lockfile
bun run test:docs # example targeted check for documentation changes
Choose targeted checks with resolveTargetedValidation(changedPaths) as described in the validation policy. For an authorized full local PR-gate run, use node cli/index.mjs gate resolve-validation --profile full-repository --repo <owner/name> --pr <number> --gate <gate> --head-sha <full SHA> from the PR worktree.
CI installs the exactly pinned Bun 1.4.1 and uses bun install --frozen-lockfile. It splits the complete Bun test inventory into four parallel, timing-balanced shards, runs docs and workflow validators separately, and joins them through a fail-closed verify gate. The conditional Playwright/WebKit viewer smoke remains a Node-run browser test and runs only when its bounded viewer surface or smoke-path dependencies change.
Upgrading from before the rename to dev-loops? The package name, repo slug, and all PI_* environment variables changed (the env vars are a clean break — no aliases). See the migration guide.
uiReviewMode: vision) review loop/loop-review-ui