It finds the bug,
writes the test,
and hands you the fix.
Ferret hunts real defects in your codebase before they ship. Off-by-one, null deref, races, the unhandled reject. For each one you get a failing test that reproduces it and a proposed fix, not a vague warning.
Free on one repo. No card, no trial clock.
function get(id: string): Promise<User> { const pending = inflight.get(id); if (pending) return pending; const p = fetchUser(id); inflight.set(id, p); return p.then((user) => { inflight.delete(id); // never runs if p rejects return user; });}failing test written
poisons the cache on reject
fix ready
clear entry in .finally()
The bug is already in your repo. It is just waiting for the right input.
Reviews read the code. Nobody runs the edge case. So the defect ships, sits quiet, and pages someone at the worst possible hour.
5×
more expensive to fix a bug in production than in the branch that introduced it
The math every on-call engineer already knows
~30%
of defects slip past code review because a human is reading, not executing, the code
Reviews catch style. Runtime catches truth.
3:47am
the hour the null deref you shipped on Friday finally pages someone
The bug was in the diff. Nobody ran the edge case.
Three moves, from the whole codebase to a merged fix.
Ferret follows the tunnel end to end. It never stops at a warning.
- 01
Analyze deeply
Ferret reads the whole tunnel, not the diff in isolation. It builds a model of your call graph, data flow, and the invariants each function quietly assumes, then goes looking for where those assumptions break.
call graphdata flowinvariants - 02
Flush out defects
It corners the real ones: off-by-one, null deref, unhandled rejection, races, and the edge case nobody wrote a test for. No taste-based nits. Every catch is something that would actually fail at runtime.
off-by-onenull derefunhandled rejectrace - 03
Hand over test plus fix
For each defect you get a failing test that reproduces it and a proposed diff that makes it pass. Read it, run it, merge it. The catch comes with the receipt, not a warning label.
failing testproposed diffone-click apply
One catch, three parts. Toggle through them.
This is a real defect Ferret finds: an in-flight cache that poisons itself when a fetch fails. Here is the bug, the test it wrote to prove it, and the fix it proposed.
const inflight = new Map<string, Promise<User>>(); export function createUserCache(fetchUser: (id: string) => Promise<User>) { return { get(id: string): Promise<User> { const pending = inflight.get(id); if (pending) return pending; const p = fetchUser(id); inflight.set(id, p); // BUG: delete runs only if the await resolves. A rejected // fetch is never cleared, so it is cached and replayed. return p.then((user) => { inflight.delete(id); return user; }); }, };}What Ferret saw
The in-flight map entry is only removed after a successful await. When fetchUser rejects, the rejected promise stays in the map and every future get(id) replays the same failure. One flaky request poisons the id until the process restarts.
Repro
get(id) once while the network blips, then again after it recovers. The second call never retries.
Everything a catch comes with.
No warning-only findings. Each item here is something Ferret can prove and, usually, fix.
Deep defect analysis
Ferret traces values across files and functions to find bugs that only appear when three conditions line up. It reasons about what the code does, not what the comments claim.
A failing test per bug
Every catch ships with a test that reproduces it and goes red on your current code. If Ferret can't write a failing test, it does not call it a bug.
✗ test fails on current code
✓ test passes after the fix
no test, no catch
Fixes as diffs
You get a proposed patch, scoped to the defect, in the style of the surrounding code. Apply it as-is or use it as a head start.
Edge-case and race detection
Empty inputs, boundary values, concurrent writes, retries that never resolve. Ferret goes hunting in the corners on-call gets paged from.
CI integration
Run Ferret on every pull request. It comments the catch inline, blocks on new defects if you want, and stays quiet when the burrow is empty.
Drop it in CI. It hunts every pull request.
Add the action and Ferret comments each catch inline with the failing test and the fix. Block on new defects if you want. When the burrow is empty, it stays quiet.
# .github/workflows/ferret.ymlname: ferreton: [pull_request] jobs: hunt: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: ferret-dev/hunt@v1 with: # Fail the check only when Ferret writes a failing test # that reproduces a new defect on this branch. fail-on: new-defects token: ${{ secrets.FERRET_TOKEN }}# or run it locally before you pushnpx ferret hunt --diff mainWhat teams say after the first catch.
Ferret opened a PR with a failing test for a race in our billing retry loop. We had shipped that code eight months ago. It had been double-charging about one account a week and we could not reproduce it. The test reproduced it on the first run.
Dana Okafor
Staff Engineer, payments
The thing I trust is that it never cries wolf. If Ferret flags something, there is a red test attached. My reviewers stopped arguing about whether a warning was real, because there are no warnings, only reproductions.
Marco Reyes
Eng Lead, platform
Free on one repo. Fair on the rest.
Start with a single repo at no cost. Scale to the whole team when you are ready. Self-host when the code cannot leave the building.
Free
Point Ferret at a single repo and watch it hunt. No card, no trial clock.
Start hunting- One repository
- Hunts on demand and on pull requests
- Failing test plus proposed fix per catch
- TypeScript, JavaScript, Python, Go, Ruby
- Community support
The whole loop, on one repo, at no cost.
Team
Every repo, every pull request, the whole team. Billed per active engineer.
Start hunting- Unlimited repositories
- CI checks with inline catches and fix diffs
- Isolated per-repo sandbox, never trained on
- Edge-case and race detection
- Slack and GitHub notifications
- Priority support
Billed per active engineer. Quiet repos cost nothing.
Enterprise
Run the whole hunt inside your own network. Your code never crosses the boundary.
Talk to us- Everything in Team
- Self-hosted, air-gapped option
- SSO and SCIM, SAML
- Audit logs and role-based access
- Dedicated support and SLA
- Security review and DPA
For teams where the code cannot leave the building.
All plans include the full loop: analysis, failing test, proposed fix. See the full comparison.
Questions from the trailhead.
Still unsure whether Ferret earns its keep? Start with the free repo and let a catch answer for it. Or ask us anything.