npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@makingstuffs/devloop

v0.1.0

Published

A scripted agentic dev loop: intake -> triage -> dev agent -> checks -> independent review -> PR

Downloads

14

Readme

devloop

A scripted agentic dev loop. devloop takes a task from a one-line description to an open pull request by running a fixed, auditable control flow:

task → intake → triage → [ dev agent → checks → independent review ]* → human gate → ship (push + PR)

Install

# Install globally:
npm install -g @makingstuffs/devloop

# One-off usage without installing:
npx @makingstuffs/devloop <command>

The command is devloop.

What devloop is (workflow, not agent)

devloop is not an autonomous agent that decides its own next step. It is a deterministic workflow — plain TypeScript control flow — that calls an LLM in exactly four judgment slots and nowhere else:

  1. Intake — turn a free-text task (or a spec file) into a structured TaskSpec.
  2. Triage — turn the spec into a dev brief, an independent review rubric, and an autonomy recommendation.
  3. Dev — the coding executor (headless Claude Code) makes the actual changes.
  4. Review — an independent reviewer judges the diff against the rubric.

Every decision that controls the loop — whether checks passed, whether the review verdict is a pass, whether to iterate again, whether to escalate, whether a guardrail forces a human gate, what to commit, when to push — is made by code from structured inputs. An LLM never decides continuation, and never has its output concatenated into a shell command.

Quick start

# 1. Install the prerequisites (see Auth model below):
#    - Claude Code CLI, authenticated (`claude`)
#    - GitHub CLI, authenticated (`gh auth login`)
#    - No API key needed by default — judgment slots use your Claude Code login.
#      (A provider API key is only needed if you point a slot at anthropic:/openai:/google:.)

# 2. In the target repo, write a default config and gitignore .devloop/:
devloop init

# 3. Run a task end-to-end (interactive intake, then autonomous where safe):
devloop run "Add a /health endpoint that returns 200 with a test"

# Or from a written spec, forcing a human gate before shipping:
devloop run "ignored when --spec is given" --spec ./task.md --gate

# Or exercise the whole pipeline with no API keys, binaries, or network:
devloop run "Try the pipeline" --dry-run

Auth model

By default devloop needs no API key at all. Both the dev executor and the judgment slots run through your local Claude Code login:

  • The dev executor authenticates itself. The coding agent is the headless Claude Code CLI, which uses its own login (claude — subscription or API, whatever you have configured). devloop does not pass it a key.
  • The judgment slots default to claude-cli:*. Intake, triage, and review (and the commit-message call) default to model strings like claude-cli:claude-opus-4-8, which run claude -p through the same Claude Code login — subscription auth, no API key. As a bonus, the CLI reports total_cost_usd, so these judgment calls are priced in real dollars in the run totals.
  • Provider API keys are only needed if you swap a slot to the AI SDK. Point a slot at anthropic:/openai:/google: (a one-line config change) and that provider's key must be present in the environment:
    • ANTHROPIC_API_KEY for anthropic:*
    • OPENAI_API_KEY for openai:*
    • GOOGLE_GENERATIVE_AI_API_KEY for google:*

Note — do not pass --bare to the CLI. devloop never does, and neither should you when reasoning about it: --bare skips the keychain read that subscription auth depends on, so a claude-cli:* call would fail with "Not logged in · Please run /login". The judgment calls also run with --setting-sources "" and --tools "" so they load none of the target repo's settings or tools — a judgment call is pure generation and stays independent of the code it is judging.

--dry-run needs none of the above: no keys, no claude/gh binaries, and no network.

Flags

devloop run <task> [options]

| Flag | Meaning | | ---- | ------- | | --spec <file> | Structure a pre-written spec document instead of interactive intake. | | --gate | Force a human gate before shipping (tighten-only; see below). | | --auto | Ratify an autonomous ship. Can only ever confirm an already-auto plan — it can never loosen a gate. | | --model <id> | Override the dev executor model id for this run. | | --config <path> | Use a specific config file (default: devloop.config.json in the cwd). | | --dry-run | Exercise the full pipeline with no API keys, binaries, or network. Makes a real branch, commit, diff, and run directory, but stubs the LLM/dev/checks and never pushes or opens a PR. |

devloop init writes a default devloop.config.json and adds .devloop/ to the target repo's .gitignore.

Config reference

devloop init writes a commented devloop.config.json. Every field has a default, so a {} config is valid.

  • baseBranch (default "main") — the branch work targets and diffs against.
  • branchPrefix (default "agent/") — prefix for generated work branches (<prefix><kebab-slug>-<shortid>).
  • models — the model for each slot:
    • intake, triage, review are provider-agnostic "provider:modelId" strings. They default to claude-cli:* (e.g. "claude-cli:claude-opus-4-8"), which runs the judgment call through your local Claude Code login — subscription auth, no API key — and prices it in real dollars. You can also point them at the AI SDK: "anthropic:claude-opus-4-8", "openai:gpt-5", "google:gemini-2.5-pro" (those need the provider's env key).
    • devDefault / devEscalation are raw Claude Code model ids for the executor. On the first failed review, the loop escalates the dev model from devDefault to devEscalation exactly once.
    • Swapping is a one-line change per slot, e.g. move review from the subscription CLI to OpenAI by editing one string:
      "review": "openai:gpt-5"   // was "claude-cli:claude-opus-4-8"
      (When you swap to anthropic:/openai:/google:, ensure the matching provider key is in your environment.)
  • checks — an ordered list of { name, cmd } deterministic checks run after each dev iteration (e.g. typecheck, lint, test). Any failure blocks the review.
  • guardrailsprotectedPaths (globs), maxDiffLines, maxDiffChars, dependencyChangesRequireGate. See Guardrails philosophy.
  • loopmaxIterations, devTimeoutMinutes, budgetUsd (the loop escalates before starting an iteration that would exceed the budget).
  • claude — headless executor settings: allowedTools, permissionMode, and maxBudgetUsd. Note: the installed Claude Code CLI has no --max-turns; maxBudgetUsd is the per-dev-run spend cap that replaces turn caps.

Guardrails philosophy (tighten-only)

Autonomy can only ever be tightened, never loosened. Triage may recommend auto, but any of the following forces a human_gate, and such gating is sticky for the rest of the run:

  • a changed file matches a protectedPaths glob;
  • the diff exceeds maxDiffLines or maxDiffChars;
  • a dependency manifest/lockfile changed (when dependencyChangesRequireGate);
  • you passed --gate.

Nothing — not --auto, not a triage recommendation — can turn a human_gate back into auto. --auto only ratifies a plan that was already auto. An oversized diff (over maxDiffChars) escalates outright, because the reviewer must never silently truncate the evidence it judges.

Run artifacts

Every run writes to .devloop/runs/<timestamp>-<slug>/ in the target repo (gitignored by devloop init):

.devloop/runs/2026-07-07T10-30-00-add-a-health-endpoint/
  spec.json            # the TaskSpec produced by intake
  plan.json            # the TriagePlan (brief, rubric, autonomy, risks)
  events.jsonl         # one JSON line per state transition (audit trail)
  result.json          # terminal status: shipped | escalated | gate_declined | ship_failed | dry-run-shipped
  HANDOFF.md           # written on escalation or a declined gate — what a human must do
  iteration-1/
    dev-result.json    # the executor's structured result (incl. session id)
    checks.txt         # each check's status, command, and output
    verdict.json       # the independent review verdict
    feedback.md        # the deterministic feedback fed to the next iteration
  iteration-2/ ...

The dev executor's session id is recorded in each dev-result.json; the same id appearing in a later iteration is the proof that the loop resumed the prior session rather than starting cold.

Exit codes

| Code | Meaning | | ---- | ------- | | 0 | Shipped (PR opened), or --dry-run completed. | | 1 | Hard error (bad config, missing binary, dirty tree, cancelled intake, push/PR failure). | | 2 | Escalated to a human (loop gave up, or the human gate was declined). The branch and run artifacts are preserved. |

Cost semantics

The dev-run cost is summed in USD by the loop (the executor reports total_cost_usd per run) and printed on every terminal path after the loop — shipped, escalated, gate-declined, or ship-failed.

Judgment calls are priced too when they run via claude-cli:* (the default). The CLI reports total_cost_usd, so intake/triage/review and the commit-message call become real dollars: intake + triage spend counts against the loop budget, and review + commit-message spend is added to the final total. The cost line then shows the grand total with a breakdown:

Total cost: $1.77 (dev $1.42 + judgment $0.35)

result.json carries both the grand total (costUsd) and the judgment portion (judgmentCostUsd).

If you swap a slot to an AI SDK provider (anthropic:/openai:/google:), that call reports token usage but no price — it is logged to events.jsonl as a judgment_usage event and the historical unpriced caveat is kept for it:

Total dev cost: $1.42 (judgment-call token usage is recorded, unpriced, in events.jsonl)

⚠️ Security warning — the dev agent runs real shell in your repo

If Bash is in claude.allowedTools and you do not require per-command approval, the dev agent can execute arbitrary shell commands in the target repository. That is the price of unattended operation: the loop hands the executor a task and lets it work without a human confirming each command. A malicious or merely mistaken instruction can therefore delete files, exfiltrate secrets, or run anything your shell can run.

For your first trials, run devloop inside a container, a VM, or on a throwaway clone of a repo that has nothing to lose — never point it at a repo with secrets or production credentials until you trust your configuration. If you want tighter control, remove Bash from allowedTools (the agent keeps Read/Edit/Write) or use a permissionMode that requires approval.

Everything devloop itself runs is built as an argument array — no LLM output is ever interpolated into a shell string. The only place a shell string is executed is your own checks commands, which come from your trusted config. The warning above is specifically about what the dev executor may do with the tools you grant it.

Contributing / Development

Clone the repo and install dependencies:

git clone https://github.com/makingstuffs/devloop.git
cd devloop
npm install

Run the test suite and type-checker:

npm test            # vitest run (160 tests)
npm run typecheck   # tsc --noEmit

Build compiled output:

npm run build       # tsc -p tsconfig.build.json → dist/

Run from source (no build step — uses tsx directly):

npm run dev -- init
npm run dev -- run --dry-run "test task"
npm run dev -- --help

The bin/devloop.mjs shim registers tsx and imports src/cli.ts directly, so there is no build step for contributors during day-to-day development.