Stop asking AI
if your project
is done.

Make it prove it. Closure grades your agent’s work against what the feature owes, using your own test results.

No LLM inside. Same inputs, same verdict.

$30 once · No account · Runs on your machine

Works with Claude Desktop, Cursor, Claude Code, the ChatGPT app and any local MCP client.

“All tests pass”
isn’t the same
as “it’s done.”

A passing invitation test shows that a valid link creates a membership. It leaves three questions open.

Does an expired link still work? Does a revoked invitation still work? Can a repeated request create two memberships? Passing the happy path doesn’t answer them.

The invitation flow, as one happy-path test sees itIllustration
  1. Invitation sentapi.invitations.create
  2. Email deliverednotify.transport
  3. Link openedapi.invitations.accept
  4. Membership createddb.memberships
  5. checked by this test
  • Does an expired link still work?SEND.004 · 549d6926unproven
  • Does a revoked invitation still work?REVOKE.001 · 2af84dfeunproven
  • Can a repeated request create two memberships?RACE.020 · f116fed0stale
Illustration. The three branches are real obligations in the recorded fixture plan, with the state the engine gave each one. Touchpoints are the catalog’s.

What this feature actually owes.

Closure gives your agent a requirement and the proof it will accept.

The shipped fixture expands one selection into 58 obligations. This is one of them, with its grading rules, exactly as the agent receives it.

selectionteams can invite people58 obligations5 provenNo LLM. Same inputs, same verdict.
closure next · a3bb0264POLICY.TENANT_ISOLATION.ISO.001 tier 4 (hoisted to the skeleton) CRITICALAUDIT.EVENTSbehavioralUNPROVEN

Requirement

For every actor A and tenant T where A is not a member of T, no operation performed by A returns or mutates any audit_event owned by T.

Why you owe this

<- POLICY.TENANT_ISOLATION@2.0.0 selector matched resource audit_event of AUDIT.EVENTS

Proof that will be accepted

evidence kind   test.property (primary), test.example (fallback)
negative control REQUIRED. This obligation is critical, so a passing
  test is not admissible on its own. You must also show the test FAILS when the
  implementation is perturbed. Suggested perturbation: drop.authz
  Record which perturbation you used and that the test failed under it.
name the test  so that it contains the literal string [a3bb0264]
               (that is how a passing test binds back to this obligation)

How it will be graded

1. closure test --repo .
2. the report at .closure/test-report.json is read for a passing test matching [a3bb0264]
3. the files that test depends on are hashed; the proof expires when they change
Nothing else counts. The grader is deterministic and this is its whole rubric.

Authority

You may change implementation, tests, migrations, configuration in fixtures/example-saas You may not change this obligation, its catalog entry, its bindings, its tier, or the evidence kinds it accepts. If you cannot satisfy it as written, that is a report to file, not a requirement to soften.

Recorded · 2026-10-11 from closure next on fixtures/example-saas, the fixture Closure ships with. The whole envelope, including what to do when blocked.
  1. Choose the features. A versioned catalog supplies their requirements.
  2. Check the evidence. Each requirement is PROVEN, UNPROVEN, STALE or INADMISSIBLE, from your test results.
  3. Hand the agent one task. The proof that counts, and what it may not change.

Would this test fail
if the protection
disappeared?

Closure removes the protection in an isolated copy and reruns the test. If it still passes, the evidence is inadmissible.

How a control is graded
closure verify-control · TUTORIAL.AUTHORIZATION.ROLE.001Recorded · 2026-10-11
  1. as written

    protects administrator actions

    export const allowed = role => Boolean(role);
  2. perturbed · unconditional-access
    - export const allowed = role => Boolean(role);
    + export const allowed = role => true;
  3. rerun

    protects administrator actionsstill passes

    INADMISSIBLE

  1. repaired test
    + assert.equal(allowed("guest"), false);
  2. rerun, perturbed

    protects administrator actionsfails

    CONTROL VERIFIED

  3. release-check

    RELEASE(closure-tutorial) = READY

Recorded from closure demo as shipped, then with its solution applied. Full output

Closure says no.
And says why.

Done is not a feeling. It is a list of clauses, pinned to the commit, and the failing ones name what is still owed.

On the shipped fixture, 5 of 58 obligations are proven and 3 clauses block. The grid beneath is every obligation the verdict counted, in the state the engine gave it.

Read the full ledger
closure done, then every obligation it countedRecorded · 2026-10-11

DONE(example-saas) = FALSE

  1. every obligation required at the declared targets is proven32 unproven, of which 0 inadmissible and 2 stale
  2. every capability reaches its target levelAUDIT.EVENTS T0/T1, BILLING.SEAT_ACCOUNTING T0/T1, COLLAB.INVITATION T0/T3, EMAIL.DELIVERY T0/T3, IDENTITY.ACCOUNT T0/T4, ORG.MEMBERSHIP T0/T1, SCENARIOS T0/T1
  3. every required scenario traverses end to end0 of 3 traversable
7 clauses satisfied, 1 advisory
  • advisory: proofs at full strength3 proven at fallback strength (weaker kind, partial surface, or self-attested control)
  • something is owed58 obligations selected
  • no obligation rests on unverified evidencesupporting input digests were checked; control strength is reported separately
  • no capability is targeted deeper than the catalog specifiescatalog is deep enough for every target
  • no unresolved gap objectsclosure reached a fixpoint with no conflicts
  • no contested obligations0 open
  • no blocking provisional obligations0 open
  • no pending weakening or exclusion requeststhese are the only changes a human must approve; everything else the engine derives

This verdict is a property of the repository at this commit, not of this run.

required
58
proven
5

One square per obligation, grouped by the feature that owes it.

  • AUDIT.EVENTS
  • BILLING.SEAT_ACCOUNTING
  • COLLAB.INVITATION
  • EMAIL.DELIVERY
  • IDENTITY.ACCOUNT
  • ORG.MEMBERSHIP
  • SCENARIOS
  • proven
  • stale
  • unproven
  • critical
Recorded from fixtures/example-saas, the fixture Closure ships with. Full output and why each feature is owed

What the checks uncovered.

Three codebases, all green before Closure ran.

A Next.js and Supabase SaaS
obligations
94/94
controls
90/90
tests
~1,800
forced a change
2
date
2026-08-19
A single-operator PWA behind a public tunnel

A “..” segment survived encoding in a management proxy.

obligations
16/16
forced a change
1
Closure itself

DONE = TRUE, release READY.

obligations
90/90
controls
47/47
tests
430
date
2026-10-08

Authored from the run reports of the author’s own projects; the marked cells show a count, not a position. Run reports

Your agent grades
its own homework.
Closure doesn’t let it.

closure next hands the agent one requirement, the proof that will count, and what it may not change.

The catalog lives outside the graded repository; an obligation found inside it is refused.

closure nextRecorded · 2026-10-11
your repository
  • implementation/
  • tests/
  • migrations/
  • configuration/
may change
a3bb0264CRITICALUNPROVEN
For every actor A and tenant T where A is not a member of T, no operation performed by A returns or mutates any audit_event owned by T.
  • obligation
  • catalog entry
  • bindings
  • tier
  • evidence kinds
may not change
  • test.property
  • negative control
  • [a3bb0264] in the test name
Recorded envelope, drawn as a map. Full envelope

Works with the agent you already use.

  • Claude Desktop
  • Cursor
  • Claude Code
  • ChatGPT app (Codex)
  • Windsurf
  • Gemini CLI
  • Hermes

A local MCP server. Claude Desktop installs it as an extension; everywhere else, closure mcp-config --repo . --client cursor (or claude-code, codex) prints the entry in your app’s own form. Setup for each app.

closure-engine · stdioRecorded · 2026-10-11
your machine
your agentany local MCP client
closure mcp
  • closure_doctor
  • closure_status
  • closure_plan
  • closure_next
  • closure_explain
your repository+ catalog
View the printed configuration
{
  "mcpServers": {
    "closure": {
      "command": "node",
      "args": [
        "closure",
        "mcp",
        "--repo",
        "fixtures/example-saas",
        "--catalog",
        "catalog",
        "--selection",
        "fixtures/example-saas/.closure/selection.yaml",
        "--timeout",
        "1800000"
      ]
    }
  }
}

Printed by closure mcp-config for the fixture; absolute paths shortened.

Recorded: one call over the local server, no agent in the loop.

DONE applies to the selected scope.

Closure grades the requirements the selected catalog supplies, against evidence at that commit. It does not discover scenarios the catalog lacks, and a verified control shows sensitivity to one perturbation, not general correctness.

selection
“teams can invite people”
catalog
closure-profile@0.1.0saas-core@0.1.1
engine
0.2.3 at 910439e
graph
5f7285fa42
recorded
2026-10-11

Before you buy

Runs on
Node.js 24 or newer, on your machine, except in Claude Desktop, which brings its own. Your project’s own toolchain and test runner must be installed.
Reads
Jest JSON and JUnit XML reports. Runners are detected for JavaScript, TypeScript, Python, Go, Rust, Java, Kotlin, C#, PHP and Ruby.
You write
The selection: which features your product owes. closure init drafts the bindings; you review them. Your own agent can draft catalog entries; the engine never trusts the draft.
It runs
Your test command locally, and declared controls in an isolated copy of your repository. Nothing leaves your machine.
Catalog
saas-core ships with it. Your project’s own catalog lives beside your repository and loads with --catalogs.

Before you start.

Is Closure another coding agent?

No. Closure has no LLM. It evaluates requirements and evidence, and a coding agent, or a person, writes the code.

Does it replace my tests or CI?

No. It reads your test results and runs negative controls to check the evidence you selected.

What does $30 include?

The framework for one user and this version, for as long as you like: the catalogs, the local MCP server, the Claude Desktop extension and the command-line tools. Delivered by email within one business day, with a 14-day refund window. Future versions are not promised.

Can it know every requirement my project needs?

No. The verdict covers the requirements in the catalog you selected. Its coverage report counts HTTP routes; it is not an inventory of every product behaviour. See the field guide.

Less “one more thing.”
More finished.

$30 USD · one-time purchase. Delivered by email within one business day, with a 14-day refund window. Stripe shows the final total before you pay.

License termsRefunds & deliverySupport

Your first run, after delivery.

Install the emailed package, then run the included demo: a passing test, rejected evidence, a repair, and the resulting verdict. Then follow the setup guide to connect your project and its test results.

npm install --global ./closure-engine-0.2.0.tgz
closure demo --out closure-demo