Skip to main content
Jeffy Loop

Validate Behavioural checks Claude Code Platform License: MIT

Quick Install  ·  Usage  ·  How it works  ·  The receipts  ·  Headless  ·  White paper  ·  STE100 description

A Claude Code loop that finds bugs in your repo, fixes them, and proves every fix before it commits. Maintainers have merged 68 of its patches.

The model writes the patch. The harness around it decides whether that patch can be trusted. Jeffy Loop is a verification harness for Claude Code: type /jeffy and it audits your codebase, finds a problem, fixes it, checks the fix, and commits the result locally, one task at a time. It keeps going until the codebase passes a fresh audit.

The harness is deliberately hard to fool. If a fix breaks your tests, it is undone. Nothing is ever pushed. A standard run counts as complete only when a fresh audit is clean, your tests pass again, and an adversarial review by a second AI agent with no part in the run signs off. The goal is fixes that survive scrutiny.

There is a real-world test for that. Maintainers with no stake in this project have merged 68 of its pull requests, each filed from a local clone, into projects run by NVIDIA, Arm, Meta, Tesla, Google, Apple, Microsoft, Netflix, Apache, Palo Alto Networks, Oracle, IBM, HashiCorp, Cisco, Uber, Square, Cloudflare, and more. See them all.

A run: /jeffy audits the codebase, then fixes one finding per iteration with a check that ran and passed and a local commit, until a fresh audit is clean, the evaluator agrees and the tests pass.

The record

Jeffy was run against 132 open-source projects with no connection to this repository, each judged by its own test suite. Every run is published, failures included.

Projects tested Converged Failed PRs merged PRs open Issues filed
132 103 28 68 17 4

Converged: the closing audit came back clean and the loop's adversarial evaluator, a fresh-context sub-agent, countersigned it, a standard this repository set and checks itself. That happened in 103 projects across 13 languages with no language-specific analyzer. Failed: the run spent the budget declared before it started without converging, or, for libuv, was abandoned before it had one. That leaves PapaParse, an audit held to the same method rather than a loop run, which the receipts page counts as Fixed alongside the 103.

See every project, every patch, and every failure

Quick Install

You need Claude Code, signed in once, and git. Each installer checks for everything else and asks before installing jq.

Install Jeffy with pip

Step 1. Install the package.

pip install jeffy-loop

Step 2. Install Jeffy as a Claude Code skill.

jeffy install

Install Jeffy with uv

You need uv. If you do not have it, pip install uv gets it.

Step 1. Install the package.

uv tool install jeffy-loop

Step 2. Install Jeffy as a Claude Code skill.

jeffy install

Install Jeffy by cloning the repo locally

Mac and Linux

git clone https://github.com/lenamonj/jeffy-loop.git
cd jeffy-loop
./install.sh

Windows PowerShell

git clone https://github.com/lenamonj/jeffy-loop.git
cd jeffy-loop
powershell -ExecutionPolicy Bypass -File .\install.ps1

The -ExecutionPolicy Bypass form runs the installer on a machine where PowerShell scripts are disabled by default and changes no policy.

Running Jeffy

Open Claude Code in the project you want to improve and type /jeffy 10 into the session.

Five ways to start a run: /jeffy for ten iterations, /jeffy 5, /jeffy 12 with a focus directive, /jeffy 5 --highs for a High hunt, and /jeffy 10 --max-time 2h.

Start a new session for each run, so each run reads its state files with a clean context.

A High hunt fixes only the Highs and stops at the first audit that finds none, so it is usually the faster run.

Usage covers every flag.

What the engine enforces

Each rule is enforced by the iteration prompt, the state files or the Stop hook, and each can be checked in this repository. How.

Rule What it means
A finding needs proof The loop must point at the defect and prove it with a check that runs.
Three gates decide done A fresh audit with no High or Medium findings, an adversarial evaluator's countersignature, and a shell re-run of your tests. In one greenfield build the evaluator was invoked 8 times and rejected 7. A High hunt skips the evaluator and never claims convergence.
No convergence over unswept surface The Stop hook refuses to converge while any row of the public-surface checklist is unswept, and a row reopens when its code changes.
Lessons become checks A rule learned once binds every later iteration. The engine passes at least 477 behavioural checks on each of Linux, Windows and macOS. How the loop improves itself.

Trust model

Question Answer
What runs One Stop hook, skills/jeffy/hooks/stop-hook.sh, plus the small library beside it in skills/jeffy/hooks/lib/. With no live Jeffy state file it exits at once and does nothing.
What it can touch The loop acts through your Claude Code session with that session's permissions. Its no-push rule lives in the iteration prompt, so never allowlist push or force operations for it. Usage, Blast radius.
What the installer writes Two skill folders under ~/.claude/skills and one hook entry in ~/.claude/settings.json. Upgrading and removing them.
How to stop it /cancel-jeffy ends a run at any time.

A receipt on an obsidian desk, sealed in terracotta wax pressed with the Jeffy Loop mark.

Independent Validation - The Receipts

Each finding below was accepted upstream by the project's own maintainers.

Merged by Finding
NVIDIA go-nvml #207 - merged in 12 days
The buffer handed to dlinfo for a library's directory was allocated with zero bytes, so the first Path() on a library opened by soname wrote past it and the next dlclose crashed

k8s-device-plugin #2002 - merged in 13 days
An empty deviceListStrategy list in the config file passed validation, and the container started with no GPU access and no error

nvidia-container-toolkit #2108 - merged in 11 days
A GPU id repeated in the visible devices request left an empty device in the list, and in CDI mode the container failed to start with an unresolvable device

go-nvml #206 - merged in 30 days
Shutdown() called nvmlShutdown() whether or not the library had loaded, so on a host without libnvidia-ml.so.1 the shutdown paired with a failed Init() took the process down with a symbol lookup error instead of returning ERROR_UNINITIALIZED
Arm astc-encoder #668 - merged in 28 days
On F16C builds float16_to_float(vint4) packed the half-float codes with signed saturation, so every negative half decoded as NaN and a half-float normal map compressed differently on AVX2 than on SSE4.1
Meta stylex #1850 - merged in 17 days
stylex.positionTry emitted every declaration twice, one of them with the property name as its own value, and an RTL variant for every rule

stylex #1849 - merged in 17 days
Configuring a custom importSources on the rollup plugin or unplugin narrowed the compile gate, so ordinary @stylexjs/stylex modules stopped reaching the compiler and the custom source was never transformed
Tesla vehicle-command #479 - merged in 15 days
The proxy read every client request body with no size limit, so any client that reached the listener could drive memory allocation without bound
Google snappy #257 - merged in 1 day
Every release build compressed a 4 GiB input into a stream whose header claimed 0 bytes

benchmark #2294 - merged in 7 days
The complexity report gave its BigO coefficient in nanoseconds whatever time unit the benchmark declared

brotli #1537 - merged in 45 days
brotli --rm deleted its input and exited 0 after the output write had failed, because the only flush sat in a metadata copy whose failure returned silently; the close now flushes, reports the failure and keeps the input
Apple swift-log #504 - merged in 2 days
A documented no-op setter asserted instead

swift-log #503 - merged in 5 days
A handler implementing only log(event:) overflowed the stack on the SwiftLog 1.0 entry point

swift-protobuf #2164 - merged in 15 hours
The project's own CMake build of protoc-gen-swift had not compiled since June

swift-format #1286 - merged in 4 days
Formatting in place replaced the file, so a 0600 source came back 0644 and a read-only one lost its bit

swift-metrics #244 - merged in 4 days
The package's own test kit crashed on a repeated dimension name

swift-certificates #317 - merged in 16 days
A /0 iPAddress name constraint matched nothing, so a CA barred from every IP address by 0.0.0.0/0 and ::/0 exclusions still verified a leaf with an IP SAN
Microsoft mimalloc #1385 - merged in 8 hours
The zeroing allocator returned uninitialized memory above the small-size threshold

snmalloc #878 - merged in 2 hours
The header-only build recipe named a CMake target removed in 2021 and include paths that resolved nowhere

GSL #1271 - merged in 4 days
The documented conversion from an iterator to its const_iterator was an access error at every use

GSL #1272 - merged in 9 days
dyn_array_iterator declared random access but had no relational operators, no -> and no n + it, so std::sort over a dyn_array did not compile
Netflix zuul #2213 - merged in 17 days
HttpQueryParams.get lower-cased the lookup key against names stored verbatim, so every query parameter with an uppercase letter in its name came back empty
Apache commons-text #768 - merged in 2 days
A StringMatcher overload forwarded the buffer end as its start

commons-csv #633 - merged in 3 days
The record counter's Javadoc said headers were not counted while the constructor's header was

commons-lang #1784 - merged in 1 day
Fraction.add and subtract overflowed on operands not in lowest terms, or returned them unreduced

commons-lang #1783 - merged in 1 day
MethodUtils.invokeMethod threw on an instance of any non-public class, every JDK collection factory result included

commons-lang #1787 - merged in 6 hours
Fraction's zero shortcuts returned the other operand unreduced, and threw where the reduced result fits

commons-codec #443 - merged in 9 days
The Git tree-id builder sorted entries by UTF-16 code units where Git sorts UTF-8 bytes, so a name outside the Basic Multilingual Plane gave a different id from git write-tree
Palo Alto Networks docusaurus-openapi-docs #1625 - merged in 31 days
A query or header parameter declared explode: true with a scalar value was enumerated as an object, so status=available went out as status= in the API explorer request and its code snippet, and a null header threw

docusaurus-openapi-docs #1624 - merged in 31 days
clean-api-docs deleted every *.json in the output directory and all of schemas/, so a hand-authored _category_.json went with the generated files

docusaurus-openapi-docs #1626 - merged in 31 days
Every copy of the docs spelled the credential-persistence option authPersistance while the theme reads authPersistence, so a site set to false still wrote reader API keys and passwords to sessionStorage
Oracle macaron #1466 - merged in 3 days
The build spec dropped the JDK version read from the JAR whenever the artifact recorded no language version
IBM sarama #3740 - merged in 14 days
The round-robin balancer never returned when the topics map held a topic no consumer group member subscribed to

fp-go #236 - merged in 10 hours
A provider graph that referred back to itself deadlocked the dependency injector forever with no diagnostic; it now reports the chain that closes the circle
HashiCorp hcl #841 - merged in 18 days
hclwrite's Expression.Variables returned nothing for an object value and RenameVariablePrefix left its references untouched, so a rename tool silently missed every variable inside an object
Cisco libsrtp #821 - merged in 4 days
Encrypted packets carrying no authentication tag failed to unprotect, because the key lookup stepped a full tag length back from the packet end to find the key identifier
Uber h3 #1235 - merged in 39 days
gridRing zeroed the caller's output buffer with a width computed from k before checking k, so a negative k became a size near 1.8e19 and the write ran off the end of the buffer; the domain check now runs first
Square kotlinpoet #2380 - merged in 4 days
String literals it emitted turned CRLF into LF, and raw strings in a constant context let newlines pick up indentation

kotlinpoet #2382 - merged in 4 days
A class in the default package got a ClassName whose toString() threw

kotlinpoet #2391 - merged in 19 days
trimTrailingNewLine() rewrote the last String argument of any trailing placeholder, so initializer("%S", "cheese ") emitted a literal denoting "cheese" and nothing reported the change
Cloudflare circl #700 - merged in 1 day
The PKI marshal functions panicked on the library's own post-quantum keys instead of returning an error

circl #699 - merged in 1 day
The hybrid KEM derived a different key pair from the same seed on a random subset of calls
JetBrains kotlinx-datetime #650 - merged in 90 minutes
Deprecation quick-fixes pointed developers at the wrong replacement

kotlinx-datetime #649 - merged in 4 days
The Unicode pattern parser dropped the escaped quote inside a literal
Node.js ada #1244 - merged in 12 minutes
The URL parser Node.js ships reported host_end one byte short
Canonical (Ubuntu) pebble #938 - merged in 16 days
With more than one service or check, the metrics endpoint repeated each # HELP and # TYPE family and the Prometheus parser rejected the whole response

pebble #937 - merged in 43 days
Appending a layer that parsed but failed plan validation left the daemon's live layer list changed, because slices.Insert shifted the existing slice in place before validation ran; the insert now goes into a copy
natsort natsort #196 - merged in 8 days
The locale sentinel meant to sort last was three ASCII bytes, so PyICU keys sorted after it (19 million PyPI downloads a month)
uuid-rs uuid #907 - merged in 6 days
The UUIDv7 counter lost its top four bits to the version nibble (179 million crates.io downloads in the last 90 days)

Fixed upstream on our report

Each finding below was reproduced by the project's own maintainers, who shipped a fix of their own instead of merging ours.

Fixed by Finding Report to fix
Shopify toxiproxy #770
A slicer toxic with the default attributes recursed until the daemon died with a stack overflow on the first byte through the proxy; a maintainer shipped his own guard and 400 validation in #774 and closed ours as handled there
30 days
Cisco libsrtp #822
The autotools configure aborted on stock Ubuntu because pkg-config was forced static, so no OpenSSL build was possible; reported with either patch offered, and another contributor's #823 citing the report was merged
3 days
Apache casbin #1752
Set comparisons sorted live policy rows in place, so later Enforce calls returned the wrong answer; the maintainer closed the issue and our patch pointing at his own commit, which drops the sort for a counting map
8 days
Google osv-scanner #3107
Vulnerability grouping was order dependent: a record that only linked two existing groups when it arrived last left them split, so one alias could appear in two groups of a scan; the maintainer rewrote the grouper around a union-find in his own pull request, resolving the issue
16 days

Private security

Reported to Outcome Answered in
Anthropic A security issue in claude-code-action, scored Low (2.3), reported through their program and reproduced and triaged by their own security team. The details stay unpublished at their request until the report resolves. Scored Low (2.3) in 6 days

Contributor agreements signed

Documentation

Page What it covers
Usage Flags, rounds and budgets, High hunt, scoped mode, cancelling, upgrading, uninstalling, and what to know before a first run
How it works The run lifecycle, what the engine enforces, the full rule set, what a converged stop looks like, and how the loop improves itself
Headless runs Running budgeted rounds unattended from bash or PowerShell
The receipts Every open-source target with its outcome, the merged patches, the greenfield builds
Contributing The validator and the review bar
White paper For readers new to agent loops: how loops got here, every rule from first principles, and what this method still cannot do
STE100 description Description and operation in ASD-STE100 Simplified Technical English: the components, the start, the audit, the fix cycle, and the end of a run, in three pages

License

MIT

Metadata

Release files for jeffy-loop 1.26.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for jeffy-loop 1.26.4
File Size Uploaded Provenance
jeffy_loop-1.26.4.tar.gz 145.8 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for jeffy-loop 1.26.4
File Interpreter ABI Platform
jeffy_loop-1.26.4-py3-none-any.whl Python 3 none any Details

Total release size: 301.4 kB

Release files / jeffy_loop-1.26.4.tar.gz

Download URL jeffy_loop-1.26.4.tar.gz
Size 145.8 kB
Tags Source
SHA-256 checksum
How to use checksums
9d5684d23da46f96213e9c660dddaa542cbe7aa7542db1f85c4ebc1f5cce631d
BLAKE2b-256 checksum
How to use checksums
dbe8bd1a014de4cbf3d13be410ac2fb8b8a051e29bf8e3911c5ac03c61c7c23f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Release files / jeffy_loop-1.26.4-py3-none-any.whl

Download URL jeffy_loop-1.26.4-py3-none-any.whl
Size 155.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4f85158315d6ab81b6e90f98336d5a273ca74b8cc151294849af2e59b88d9869
BLAKE2b-256 checksum
How to use checksums
fbf3dcd7ba705824c847ce261490cefe6ffea3a0ad3de7e83841cc64cb10850b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

Security for jeffy-loop 1.26.4

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for jeffy_loop-1.26.4.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page