Autonomous dependency upgrader powered by LangGraph and LLMs
Project description
loopgrade
Autonomous dependency upgrader powered by LangGraph and LLMs. Upgrades your dependencies one at a time, runs your tests, commits what works, reverts what breaks — without you touching anything.
The Problem
You have a project with 20 dependencies. Half of them are outdated. Running ncu -u or pip install --upgrade upgrades all of them at once — and when something breaks, you have no idea which package caused it.
So you don't upgrade. The deps rot. Security patches pile up.
loopgrade fixes this.
It upgrades one dependency at a time, runs your test suite after each upgrade, commits if it passes, reverts if it fails, and moves on to the next one. When it's done, it gives you a full report of what was upgraded, what failed, and why.
How It Works
loopgrade is built on Loop Engineering — the practice of designing autonomous systems that work toward a goal without human prompts. Instead of you babysitting an AI agent turn by turn, loopgrade designs the loop once and lets it run.
The core loop is a LangGraph StateGraph — a stateful, cyclical graph that carries a shared state object through every node. Each node reads what it needs from state, does one job, and writes back only what changed.
See docs/agent.md for the full agent architecture diagram, node descriptions, tool definitions, and LLM prompts.
Conflict Resolution
Version conflicts are detected before any file is touched — not discovered after tests fail.
How conflicts are detected
For npm, loopgrade runs:
npm install axios@1.7.2 --dry-run
For pip:
pip install numpy==2.0.0 --dry-run
Both commands hit the resolver without touching anything on disk.
Three outcomes
none — no conflicts, proceed to upgrade normally.
resolvable — a constraint exists but a safe version is available. Example: you want numpy 2.0.0 but scipy 1.11.0 requires numpy < 2.0. loopgrade finds numpy==1.26.4 (the highest version satisfying all constraints) and uses that instead of the absolute latest. The result is logged as "upgraded with adjustment."
hard — no version of the package can satisfy all constraints simultaneously. loopgrade skips it immediately — zero test attempts wasted — and logs the exact reason plus a suggestion for what the developer should do manually.
What a hard conflict looks like in the report
## Failed / Skipped
- webpack: 4.46.0 → 5.91.0
reason: hard conflict — html-webpack-plugin 4.x requires webpack<5
suggestion: upgrade html-webpack-plugin to 5.x first, then retry webpack
Retry Policy
Each dependency gets up to 3 attempts. The retry logic is intelligent — not just "try the same thing again."
Attempt 1 → try absolute latest version
↓ fail
Attempt 2 → try safe_version from resolver (if available)
↓ fail
Attempt 3 → try one minor version below latest
↓ fail
→ skip + flag for manual review
Early exit conditions — these skip the dep immediately, no attempts wasted:
same_error_streak >= 3— identical error across retries means retrying is pointlessconflict_info.type == "hard"— mathematically impossible, skip before any attemptretry_count >= max_retries_per_dep— out of attempts
Global hard cap — max_iterations in config (default: 20). When hit, the run ends regardless of how many deps remain. This is your cost guardrail — no surprise LLM bills from infinite loops.
The State Report
loopgrade writes loopgrade-state.md to your project root after every single dependency — win, lose, or skip. You can open it any time during a run and see live progress:
# loopgrade run — 2026-07-07 14:32
## Progress: 3/8 deps processed
## Upgraded
- lodash: 4.17.19 → 4.17.21
- express: 4.17.1 → 4.18.2
## Upgraded with adjustment
- numpy: 1.24.0 → 1.26.4 (wanted 2.0.0, constrained by scipy==1.11.0)
## Failed / Skipped
- webpack: 4.46.0 → 5.91.0
reason: hard conflict — html-webpack-plugin 4.x requires webpack<5
suggestion: upgrade html-webpack-plugin to 5.x first, then retry webpack
- axios: 0.27.0 → 1.7.2
reason: 3 attempts failed — response structure migration needed in code
suggestion: update all axios call sites to use new response format before upgrading
## Remaining
- dotenv, jest, eslint, prettier, typescript
Installation
Prerequisites
- Python 3.10+
- Git initialized in your project (
git init) - Your test suite must pass before running loopgrade (
npm testorpytestexits 0) - For npm projects:
npm-check-updatesinstalled globally (npm install -g npm-check-updates) - A Groq or Gemini API key (both have free tiers)
Install loopgrade
pip install loopgrade
Or install from source:
git clone https://github.com/yourusername/loopgrade
cd loopgrade
pip install -e .
Quick Start
# 1. go to your project
cd my-project
# 2. initialize loopgrade (creates config + .env)
loopgrade init
# 3. add your API key to .env
echo "GROQ_API_KEY=your_key_here" >> .env
# 4. run it
loopgrade run
Note: The default configuration assumes a Node.js project (
npm test). If you are using Python, be sure to editloopgrade.config.jsonand change"package_manager": "pip"and"test_command": "pytest"(or whatever you use for testing) before runningloopgrade run.
That's it. loopgrade will scan your deps, upgrade them one at a time, and report back.
CLI Reference
loopgrade init
Creates loopgrade.config.json and .env in your current directory with sensible defaults.
loopgrade init
loopgrade run
Runs the full autonomous upgrade loop.
loopgrade run # standard run
loopgrade run --dry-run # show what would be upgraded, no changes
loopgrade run --only axios # upgrade one specific package
loopgrade run --config path/to/config # use a different config file
Before starting, loopgrade validates:
- A git repo exists in the current directory
- Your test suite currently passes (if tests are already failing, loopgrade won't run — fix them first)
loopgrade status
Pretty-prints the current loopgrade-state.md with rich formatting.
loopgrade status
Configuration Reference
loopgrade.config.json — place this in your project root.
{
"llm_provider": "groq",
"model": "llama-3.3-70b-versatile",
"max_iterations": 20,
"max_retries_per_dep": 3,
"package_manager": "npm",
"test_command": "npm test",
"skip_major_versions": false,
"skip": []
}
| Field | Type | Default | Description |
|---|---|---|---|
llm_provider |
string | "groq" |
LLM provider to use. Options: "groq", "gemini" |
model |
string | "llama-3.3-70b-versatile" |
Model name. See provider docs for options |
max_iterations |
int | 20 |
Hard cap on total iterations across all deps. Your cost guardrail |
max_retries_per_dep |
int | 3 |
Max attempts per dependency before skipping |
package_manager |
string | "npm" |
Package manager. Options: "npm", "pip" |
test_command |
string | "npm test" |
Command loopgrade runs to verify each upgrade |
skip_major_versions |
bool | false |
If true, skip any dep with a major version bump |
skip |
array | [] |
List of package names to skip entirely e.g. ["react", "typescript"] |
Environment Variables
Create a .env file in your project root (loopgrade reads it automatically):
# use one of these depending on your configured provider
GROQ_API_KEY=your_groq_key_here
GEMINI_API_KEY=your_gemini_key_here
Getting API keys:
- Groq (recommended — fast, cheap, generous free tier): console.groq.com
- Gemini: aistudio.google.com
Supported Package Managers
| Package manager | Dep file | Install command | Test discovery |
|---|---|---|---|
| npm | package.json |
npm install |
configured via test_command |
| pip | requirements.txt |
pip install -r requirements.txt |
configured via test_command |
More package managers (yarn, pnpm, poetry, cargo) are planned — contributions welcome.
Why loopgrade over just running ncu -u?
ncu -u |
loopgrade | |
|---|---|---|
| Upgrades all deps at once | Yes | — |
| Tests after each upgrade | — | Yes |
| Reverts on failure | — | Yes |
| Attributes which dep broke things | — | Yes |
| Detects version conflicts before trying | — | Yes |
| Finds safe version ceiling for conflicts | — | Yes |
| Explains why something failed | — | Yes |
| Suggests manual steps for hard failures | — | Yes |
| Your codebase always left in working state | — | Yes |
Project Structure
loopgrade/
├── loopgrade/
│ ├── cli.py # typer CLI — run / init / status
│ ├── config.py # load + validate loopgrade.config.json
│ ├── agents/
│ │ ├── __init__.py
│ │ ├── graph.py # LangGraph graph assembly + routing
│ │ ├── state.py # LoopgradeState TypedDict
│ │ └── nodes/
│ │ ├── __init__.py
│ │ ├── scan.py # scan_deps node
│ │ ├── pick.py # pick_next node
│ │ ├── upgrade_node.py # upgrade_node — pre-upgrade LLM call
│ │ ├── upgrade.py # run_upgrade node
│ │ ├── test.py # run_tests node
│ │ ├── verifier_node.py# verifier_node — post-test LLM call
│ │ ├── commit.py # commit_success node
│ │ ├── revert.py # revert_dep node
│ │ ├── skip.py # skip_dep node
│ │ ├── state_writer.py # write_state node
│ │ ├── conflict_check.py
│ │ └── conflict_resolve.py
│ │
│ ├── tools/
│ │ ├── registry.py # get latest versions from npm / PyPI
│ │ ├── files.py # edit package.json / requirements.txt
│ │ ├── runner.py # run install + test commands
│ │ ├── git.py # commit / revert
│ │ └── conflicts.py # dry-run conflict detection + safe version finder
│ │
│ └── providers/
│ ├── base.py # abstract LLM interface
│ ├── groq.py # Groq implementation
│ └── gemini.py # Gemini implementation
│
└── test-fixtures/
├── node-app/ # intentionally outdated Node app for testing loopgrade
│ ├── package.json
│ ├── index.js
│ └── index.test.js
└── python-app/ # intentionally outdated Python app for testing loopgrade
├── requirements.txt
├── main.py
└── test_main.py
Further Reading
- How Loop Engineering works — the architectural pattern loopgrade is built on
- Configuration deep dive — all config options with examples
- Quick reference — supported package managers, test fixtures, and FAQ
Contributing
Contributions are welcome — especially:
- Additional package manager support (yarn, pnpm, poetry, cargo)
- Additional LLM providers (OpenAI, Ollama for local models)
- Better conflict resolution strategies
- CI/CD integration (GitHub Actions support)
To get started:
git clone https://github.com/yourusername/loopgrade
cd loopgrade
pip install -e ".[dev]"
# run tests against the fixtures
cd test-fixtures/node-app && npm install && npm test
cd test-fixtures/python-app && pip install -r requirements.txt && pytest
Please open an issue before starting work on a large feature so we can align on the approach.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file loopgrade-0.1.0.tar.gz.
File metadata
- Download URL: loopgrade-0.1.0.tar.gz
- Upload date:
- Size: 27.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
df7eb45c36211d0c6362ec26da7e9a26472c7a3706deb1ffaa3573d5985f2bd3
|
|
| MD5 |
e3e68183893c355a5b8b6036df876412
|
|
| BLAKE2b-256 |
e300b1d5428b97c4fb7e563b5863be5a434c9ca0f791e0afe58dd1e2baf54338
|
File details
Details for the file loopgrade-0.1.0-py3-none-any.whl.
File metadata
- Download URL: loopgrade-0.1.0-py3-none-any.whl
- Upload date:
- Size: 30.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4fc48accfd0831941c44f7262b90d6f9bac565fcf2e4d649157fc1694975446f
|
|
| MD5 |
86bdc952dc08dd95ebe115bf889c230f
|
|
| BLAKE2b-256 |
b3a74de4eb991ed308bfd9ad808635fd2071e50ac51bcdba3b62cfd2898533eb
|