Guide

Make Claude Code keep going until the tests pass

Coding agents stop when they think they’re done, often with a test still failing. In wisp you give the task a goal, Done when all tests pass and the login page works on a phone. After every round wisp checks the work itself: it runs the tests and has a read-only model read the diff. Until the goal holds, the agent gets the task back with what’s missing. It works on Claude Code, Codex, opencode, Cursor and the rest.

Source on GitHub

Free and open source · Claude Code, Codex, Cursor CLI, opencode, Antigravity CLI, Grok Build, Copilot CLI · macOS, Linux, Windows (beta) · Node 20+

A wisp task working toward its goal: the condition, a progress bar at 60% (+30 since the last round), Round 3 of 10, and what the last check found still missing

Why agents stop early

An agent ends its turn when its own reading of the task says it’s finished. It may have skipped the slow test suite, fixed the case it was shown and not the one next to it, or reported success on a build it never ran. The usual fix is to read the report, run the tests yourself and type “the auth tests still fail, keep going”, several times over. A goal hands that loop to wisp.

Write a Done when that can be checked

Turn on Goal in the prompt box and a Done when line opens under the prompt. Write what has to be true, not what to do:

Pick how many rounds it gets: 3, 5, 10 or 20. On a task that’s already running or finished, type /goal <condition> in the reply box; an idle task is checked right away, since it may already hold.

What wisp checks after each round

  1. The tests. wisp runs the project’s test command itself. Only tests that passed before the change count as failures.
  2. The diff. A cheap model, read-only, in the task’s folder, reads everything that changed since the goal was set, and can open any file.
  3. The agent’s report, as a claim. It goes in last and is labelled as what the agent says, not as evidence.

The checker answers met, not yet or can’t be done, with why. A met needs evidence it saw for itself and tests that don’t disagree; otherwise it counts as not yet. Not yet sends the task back with what’s missing and the next step.

Rounds, stalls and the one ping

The task stays in Working through every round. A band on top of it shows the goal, a progress bar with how much the last round moved it, Round 3 of 10, and the last check in the checker’s words; the row in the list shows a ring and 3/10. It lands in Needs you, with one notification, when the goal is:

OutcomeWhenWhat you can do
Metthe checker saw it hold, tests passingShip it
Can’t be doneit needs access or a decision only you have, or contradicts itselfread why, change the goal
Out of roundsstill not met after the last roundResume goal for another set of rounds
Stalledtwo rounds changed nothing, or got the same next step with no progresssteer it with a follow-up, then resume

Stop pauses the goal. A follow-up of yours keeps it, and it’s checked again after your turn.

Goals on Codex, opencode and Cursor

wisp checks the work outside the agent, so a goal works the same on every harness it runs: Claude Code, Codex, opencode, Cursor, Antigravity, Grok and Copilot. The agent is told its goal every turn and that it will be checked. With Auto, a task handed to a stronger model takes its goal, and the rounds it has left, along.

wisp "/goal every test in test/auth passes"        # the condition is the task
curl -X PUT localhost:4477/api/sessions/$ID/goal \
  -H 'content-type: application/json' \
  -d '{"text":"npm run build has no warnings","max":5}'

Questions

Does it cost more?
Each round is another agent turn, plus a test run and a short call to a cheap model. Pick fewer rounds for small tasks; a stalled goal pauses on its own instead of using them up.
What if my project has no tests?
The checker still reads the diff and the files. Write a goal it can verify by reading, like a page that fits 390px or an endpoint that returns 404 for unknown ids.
Can I change the goal mid-way?
Yes. Edit goal… in the band, More, the right-click menu or ⌘K changes the words and keeps the rounds it has used. /goal drop, or Drop goal, removes it.