WhyStuck
by loopgepa
README.md
<div align="center">
# WhyStuck
*Diagnose the loop. Propose the fix. You approve.*
[](https://github.com/loopgepa/whystuck/actions/workflows/ci.yml)
[](LICENSE)
[](https://pypi.org/project/whystuck/)
[](https://github.com/loopgepa/whystuck/stargazers)
[](https://github.com/loopgepa/whystuck/discussions)
**Works with**



`Local-only` · `No telemetry`
[Install](#install) · [How it works](#how-it-works) · [Why not X?](#why-not-just-x) · [Status](#status) · [Roadmap](#roadmap) · [Docs](#documentation) · [Discuss](https://github.com/loopgepa/whystuck/discussions)
</div>
<p align="center">
<img src="docs/assets/whystuck-demo.gif" alt="WhyStuck diagnosing a repeatedly failing bugfix loop from local traces and proposing a reversible, approval-gated fix" width="840">
</p>
<p align="center"><em>Live recording of <code>examples/bugfix-loop/demo.py</code> — reproducible via <code>vhs assets/demo/demo.tape</code>. No API key, nothing leaves the machine.</em></p>
> **Your coding agent re-ran `npm install` 40 times and you didn't notice.**
> WhyStuck records why a repeated agent loop keeps failing, shows you the failure
> mode with a confidence level, and proposes a small, reversible patch — to the
> verifier, retry policy, stop condition, or skill — that you approve before
> anything is written.
**WhyStuck is the diagnosis-and-repair layer for [loop engineering](docs/how-it-works.md).**
2026's agent-dev stack goes prompt → context → harness → *loop* engineering: you
stop prompting the agent turn-by-turn and design the act→verify→retry→stop cycle
that drives it ([ADTmag](https://adtmag.com/articles/2026/07/01/loop-engineering-emerges-as-developers-put-ai-coding-agents-on-repeat.aspx)).
Loop scaffolders help you *build* a loop; WhyStuck tells you *why it keeps failing
and what to change*. Every named alternative — Latitude, LangSmith, Braintrust,
Langfuse — is cloud SaaS for production apps; **none does local, zero-telemetry,
coding-agent-session loop diagnosis.** WhyStuck's reflective-mutation approach
builds on [GEPA](https://arxiv.org/abs/2507.19457) (Genetic-Pareto, ICLR 2026
Oral); the measured GEPA optimization itself arrives in
[v0.2](docs/v0.2-eval-benchmark.md), which wraps `gepa-ai/gepa`.
**The diagnosis is deterministic — it spends ~0 model tokens; only the proposed
fix uses your agent's own model.** No API key to diagnose, nothing uploaded, and
it stays out of your request hot path.
---
## Install
> Requires [`uv`](https://astral.sh/uv). If `uvx` isn't found:
> `curl -LsSf https://astral.sh/uv/install.sh | sh`
**One command — configures Claude Code, Codex, and Cursor:**
```bash
uvx whystuck setup
```
The wizard writes each client's MCP config **and** a short usage rule — so your
agent knows to diagnose a stuck loop *before* it thrashes — merges into any
existing config, and is safe to re-run. Choose clients/scope with
`--all` · `--claude` · `--cursor` · `--codex` · `--global` · `--yes`.
It registers WhyStuck as a local stdio MCP server (no `pip install`, no venv) and
stores traces under `$XDG_DATA_HOME/whystuck` — **outside your repo**, never
committed by accident.
<details><summary>Prefer to wire a single client up by hand?</summary>
```bash
claude mcp add whystuck -- uvx whystuck # Claude Code
codex mcp add whystuck -- uvx whystuck # Codex CLI
```
Cursor / any MCP client — add to your `mcp.json`:
```json
{ "mcpServers": { "whystuck": { "command": "uvx", "args": ["whystuck"] } } }
```
Then paste one line into `AGENTS.md` / `CLAUDE.md` / `.cursor/rules` so the agent
reaches for it automatically (the wizard does this for you). See [AGENTS.md](AGENTS.md).
</details>
> **Pre-launch:** `whystuck` isn't on PyPI yet, so `uvx …` won't resolve. Run the
> wizard from a clone instead:
> ```bash
> git clone https://github.com/loopgepa/whystuck && cd whystuck
> uv run whystuck setup --from-source "$PWD"
> ```
<details><summary>Try it offline first — no API key, nothing written</summary>
```bash
git clone https://github.com/loopgepa/whystuck && cd whystuck
uv run python examples/bugfix-loop/demo.py
```
Prints the full flow: 8 traces → "repair repeats the original patch" (confidence:
medium, gene: `verifier_rubric`) → proposed variant → dry-run promotion.
</details>
## How it works
```text
declare loop ─▶ run it (worker + verifier) ─▶ clean local trace (JSONL)
│
failure diagnosis ◀── aggregate ◀───────┘ (deterministic + confidence)
│
reflective fix (≤3 genes, evidence-backed) ─▶ dry-run diff ─▶ you approve ─▶ reversible promote
```
1. **Declare** a loop — its *genome* of genes (skill, verifier rubric, retry
policy, stop condition, …).
2. **Run / record** it: the offline command+verifier runner emits a clean trace,
or your agent records session traces.
3. **Diagnose**: failures are clustered and ranked with a **deterministic**
confidence (`n<5`→low, `≥15 ∧ cluster≥0.5`→high) — no LLM in the analysis.
4. **Propose**: your agent reflects on the evidence and proposes a ≤3-gene patch.
5. **Preview** the exact diffs (dry-run writes nothing), then **approve** — the
write is atomic and reversible, with a rollback record.
**WhyStuck runs the loop, so every knob it tunes is real, and every trace is
clean by construction — and it never writes without your approval.**
## Why not just X?
| | WhyStuck | Latitude / LangSmith / Braintrust / Langfuse |
|---|---|---|
| Runs | **On your machine** | Cloud SaaS |
| Data | **Never leaves it, no telemetry** | Uploaded to a backend |
| Scope | **Your local coding-agent loops** | Production LLM apps |
| Output | **A reversible patch you approve** | Dashboards / auto-PRs |
Nobody else pairs *local + zero-telemetry + coding-agent-session scope +
reversible, approval-gated repair*. Fuller breakdown: [docs/comparison.md](docs/comparison.md).
## Status
Developed in the open once solid; the trust chain and diagnosis pipeline are built
and tested.
| Component | State |
|---|---|
| Loop genome + local store (XDG) | ✅ |
| Command+verifier runner (offline) | ✅ |
| Deterministic diagnosis + confidence | ✅ |
| Reflective mutation (≤3 genes, safety-guarded) | ✅ |
| Dry-run + reversible promotion + rollback | ✅ |
| FastMCP stdio server (6 tools) | ✅ |
| Claude Code plugin (3 skills, 3 agents) | ✅ |
| Auto-trigger hook (thrash detection + session capture) | ✅ |
| Evaluation library + GEPA wrapper (`whystuck[eval]`) | 🟡 v0.2-alpha |
| LLM worker + output→apply→verify wiring (real-repo scoring) | 🟡 v0.2-alpha |
| Optimize + frontier MCP tools (gated on the extra) | 🟡 v0.2-alpha |
**2088 tests**, all local and offline; `ruff` + `mypy --strict` (on `src/`) + docs `--strict` clean.
## Configure
The server is zero-config. Point any MCP client at it:
```json
{ "mcpServers": { "whystuck": { "command": "uvx", "args": ["whystuck"] } } }
```
Storage location is overridable with `WHYSTUCK_HOME` (default
`$XDG_DATA_HOME/whystuck`). No API keys — the v0.1 runner is fully offline.
## MCP tools & safety boundary
Six focused tools: `diagnose`, `run_loop`, `propose_fix`, `promote`, `save_loop`,
and the internal `record_trace`. The boundary is mechanical: **`promote` is
dry-run by default and only writes on an explicit approval flag; proposals are
capped at 3 genes; budget caps can't be weakened; promotion paths can't escape
the project directory.** Full threat model: [SECURITY.md](SECURITY.md).
## Roadmap
See [ROADMAP.md](ROADMAP.md).
- ✅ **v0.1** — diagnose recurring loop failures, propose reversible fixes; a
PostToolUse hook auto-detects thrash and captures session traces
- 🟡 **v0.2-alpha** — eval library + GEPA wrapper + LLM-backed worker built
(`whystuck[eval]`, gated MCP tools); remaining: the output→apply→verify wiring
for real repos + the benchmark writeup
- 📋 **v0.3** — plugin marketplace listing (manifest ready), MCP-registry submission
## Research artifact
This repository is the supporting artifact for a **three-paper series** on optimizing
generate–critique–refine loops. Start at **[docs/papers/README.md](docs/papers/README.md)** — it
says which paper answers which question.
| | paper | in one line |
|---|---|---|
| **I** | *Whether Optimizing the Loop Beats Optimizing the Prompt Depends on One Number* | Evolving a loop's verifier beats evolving its generation prompt **only when enough first drafts are already correct**: +0.060 held-out at p₀ = 0.267, nothing measurable at p₀ = 0.067, a 0.102 swing across the axis |
| **II** | *What a Checker Cannot Buy Is the Repair* | A **perfect** inference-time checker scores **0.042 below** a mere text-statistics tool and is indistinguishable from a near-random one; concrete measured repair instructions are worth +0.0613. No optimizer anywhere in the design |
| **III** | *Your Loop Optimizer Is Not Optimizing Your Loop* | Pointing an optimizer at a component is not the same as optimizing it. Our first fifteen contrast runs had a critique gene **byte-identical to the seed in 15/15** winning genomes. Print one integer per component |
- **[Every experiment, and the command that produced it](docs/EXPERIMENTS.md)** — one script spends
money and it refuses to without `--yes`; everything else is $0 and offline.
- **[How to reproduce it](docs/papers/REPRODUCE.md)** — offline checks, all $0: every number in
every paper re-derived from the artifacts, bit-for-bit cassette replay, a positive control proving
the harness detects an effect when one exists, and a proof that the three-way split lost no claim.
- Results, cassettes and pre-registrations for every run are committed, including the superseded
ones, labelled as such.
## Documentation
- [The three papers](docs/papers/README.md) — which paper answers which question
- [Every experiment and its command](docs/EXPERIMENTS.md) — the map from a claim to a script
- [How it works](docs/how-it-works.md) — loop engineering, the genome, the pipeline
- [Getting started](docs/getting-started.md)
- [Trust & safety](docs/safety.md) · [SECURITY.md](SECURITY.md)
- [v0.2 eval/benchmark design](docs/v0.2-eval-benchmark.md)
- [Comparison](docs/comparison.md) · [Competitive & launch notes](docs/COMPETITIVE-AND-LAUNCH.md)
- [Design records (ADRs)](DECISIONS.md) · [Implementation spec](IMPLEMENTATION.md)
## Where to find WhyStuck
| Channel | Install | Notes |
|---|---|---|
| PyPI | `uvx whystuck` | primary; zero-install via `uv` |
| MCP registry | auto-discovered | via `server.json` (feeds mcp.directory, Glama) |
| GitHub | `git clone` | source + examples |
## Contributing
Highest-impact area right now: **real loop examples** beyond the bugfix loop
(an orchestrator/triage loop). See [CONTRIBUTING.md](CONTRIBUTING.md) and the
[`good first issue`](https://github.com/loopgepa/whystuck/labels/good%20first%20issue) label.
## License
Apache-2.0 for the code — see [LICENSE](LICENSE).
The papers under `docs/papers/` are licensed **CC BY 4.0** instead — see
[docs/papers/shared/LICENSE](docs/papers/shared/LICENSE). Two separate grants: a patent grant and NOTICE
requirement make no sense for a document, and the papers are meant to be redistributed and
built upon. CC BY 4.0 is also the licence selected for the arXiv submissions.
---
<div align="center">
Built by <a href="https://github.com/vladimirrott">Vladimir Rotariu</a>. · Ideas, war stories — <a href="https://github.com/loopgepa/whystuck/discussions">come say hi</a>.
</div>
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues