Remix.run Logo
Show HN: 9lives – Self-healing test runner that refuses to mask real bugs(github.com)
2 points by ruslan_qm 7 hours ago

I built 9lives because coding agents kept breaking my Playwright tests in the dumbest way: rename a button, the test goes red, and the agent — or I — rewrites a perfectly good test.

9l heal login.spec.ts runs the test, classifies the failure, and heals it in tiers:

Tier 1 is offline and deterministic. When a selector stops matching, 9lives re-finds the element in the page snapshot Playwright captures at failure (data-testid > id > aria-label > text > class — the most stable surviving anchor wins) and rewrites the locator. No LLM, no network, no account. Most selector drift heals in seconds, for free. Unlike Healenium-style tools, it needs no baseline DOM from previous green runs — it works from the failure itself.

Tier 2 uses the subscription you already pay for. For structural changes it shells out to your installed claude / codex / opencode CLI in headless mode, so the fix rides your existing coding-agent plan. No new API key to mint. (Raw ANTHROPIC_API_KEY / OPENAI_API_KEY work too.)

Everything lands as a unified diff you approve (or --yes in CI).

The design decision I care most about: it refuses to heal failing assertions. A failing assertion means behavior changed — possibly a real bug — and auto-rewriting it to force green is exactly how “self-healing” tools mask regressions. 9lives flags those needs-human and stops. Selector drift gets healed; behavior changes get surfaced.

Also in the box: Cypress and Selenium/pytest support (same loop, auto-detected); 9l mcp, a zero-dependency MCP server so Claude Code / Cursor can call heal_test when they break a test mid-session; 9l watch (heal on save) and a pre-commit hook; a GitHub Action that posts the heal diff on PRs; and 9l report, which reads the local heal history and tells you which selectors keep rotting and what to pin instead.

MIT, Python, no account, no telemetry, ~2.5k lines you can read in a sitting. The README demo is fully offline and reproducible. Install: pip install 9lives (or curl -sL 9lives.run | sh, which just uv-tool-installs it — read it first, it’s 40 lines).

Honest limitations: Tier 1 needs the failure-time page snapshot, so Playwright heals best offline — Cypress/Selenium lean more on Tier 2. And if you heal tests against pages you don’t control, read the “Security & trust boundary” section in the README: failure-page content becomes model input in Tier 2.

Built at QualityMax (we sell a test-automation platform; this CLI is standalone and free forever). Would love feedback — especially from anyone who’s been burned by self-healing tools that green-washed real failures.

https://github.com/Quality-Max/9lives