Your AI agent says "done." Don't believe it.
Your agent can finish a task, report success, and still be wrong. DidWork checks the result independently before your workflow moves on.
Catches
wrong results
$39.99 instead of $49.99? We'll catch it.
Stops
incomplete work
No half-done tasks get through.
Blocks
fake success
No more "it worked" when it didn't.
Lets real
work continue
Verified results move forward.
Agent reported
“The customer has been refunded $49.99.”
Stripe recorded
$39.99
Refund succeeded. Amount didn’t match.
The customer was still owed $10.
Works with your stack
First-party adapters for the tools your software already uses.
Read-only connections, plus any public URL, no connection at all.
Install it where the claim is made
The verdict has to reach the agent at the moment it says “done”: in the editor, in the host, or on the pull request waiting to merge.
Claude Code
The did_verify tool, a session rule, and a Stop gate that blocks ending a turn on an unverified outcome.
/plugin marketplace add didworksh/claude-plugin
Cursor
Writes the MCP config and the rule that makes verifying an outcome the default, not the exception.
npx @didwork/inspect init
Any MCP host
Verification tools for Claude Desktop, your own agent, or anything else that speaks MCP.
npx -y @didwork/mcp
GitHub Actions
A required check that fails the build when a pull request claims an outcome that is not true.
uses: didworksh/verify-action@v1
Made for agents that finish the job
An agent that gets it wrong isn’t lying. It believes its tools. DidWork closes the loop with independent evidence, so “done” means done.
const v = await did.verify({
type: "stripe.refund",
expected: {
payment: "pi_123",
amount: 4999
}
});
"evidence": [{
"source": "stripe",
"observation":
"1 refund(s) found",
"data": [{ "amount": 3999,
"status": "succeeded" }]
}]
{ "status": "failed",
"reason": "AMOUNT_MISMATCH" }
if (v.status !== "verified")
escalate();
// unknown also stops the line
Verification that runs the way production runs
Give your agent the tool.
One command, any MCP host. Then one line of instructions: verify before you report success.claude mcp add didwork \ -e DIDWORK_API_KEY=dk_… \ -- npx -y @didwork/mcp
Connect once, read-only.
Verifications run against your accounts. DidWork never needs the power to cause outcomes, only to prove them.Watch what must stay true.
Cancelled users stay locked out. Checkout keeps working. Signed webhooks, retried for hours.did.watch({
type: "http.ok",
expected: { url, status: 401 },
every: "10m"
})
UNKNOWN is an answer.
Provider down, record invisible, outcome undecidable. DidWork refuses to guess. When it says VERIFIED, that has to be true.Every check on the record.
Claim, evidence, and verdict stored separately: an audit trail for what your software actually did.GET /v1/verifications GET /v1/verifications/:id
Know what a tool can do before the agent calls it.
A tool’s description is intent, not proof. DidWork reads the implementation and reports what it can actually affect, with the line of code as evidence, and says UNKNOWN when it can’t tell.$ npx @didwork/inspect inspect refund_customer HIGH HIGH financial.refund stripe.refunds.create communication.external resend.emails.send update_customer MODERATE DECLARATION MISMATCH admin_action UNKNOWN INSUFFICIENT EVIDENCE
Capabilities on the receipt.
Pass the tools that did the work. The receipt then answers what was requested, what those tools could affect, and whether it actually happened, kept apart from the evidence and never an input to the verdict.did.verify({
type: "stripe.refund",
expected: { payment, amount },
tools: [refundCustomer]
})
Receipts, not vibes
Real failure modes DidWork catches. Each one was reported as a success by the software that caused it.
See every claim type“Refund processed.”
reason: AMOUNT_MISMATCH expected: 4999 observed: 3999
“PR merged, shipping now.”
reason: PR_CLOSED_NOT_MERGED state: closed merged: false
“I’ve resolved the bug.”
reason: ISSUE_REGRESSED status: unresolved substatus: regressed
“Confirmation email sent.”
reason: BOUNCED last_event: bounced
“Ticket closed out.”
reason: ISSUE_CANCELED state: Canceled
“Subscription upgraded.”
reason: PRICE_MISMATCH expected: price_enterprise observed: [price_pro]
Pricing
Start with 250 checks a month. Upgrade for more checks, frequent monitoring, and failure alerts.
Hobbyist
For trying verification on your own projects.
- 250 checks/month; stops at the limit
- Monitor one outcome every hour
- Keep verification evidence for 7 days
- One API key
Pro
For workflows that depend on verified results.
- 2,500 checks/month; $0.01 per extra check
- Monitor unlimited outcomes every 5 minutes
- Email alerts when a watched outcome fails
- Keep verification evidence for a year
- Separate API keys for each environment
FAQ
Verification
What happens when DidWork can’t tell?
You get UNKNOWN, on purpose. Provider unreachable, record not visible, outcome not yet decidable. DidWork refuses to guess. Treat UNKNOWN as “do not proceed yet.” False verification is the failure mode we optimize against hardest.
How do agents actually use it?
Add the MCP server with one command, then one line in the agent’s instructions: after any consequential action, call did_verify before reporting success, and proceed only on verified. SDKs and the raw API do the same job for non-agent code.
Can DidWork tell me what my agent’s tools actually do?
Yes. That’s Capability Trust. npx @didwork/inspect inspect reads the MCP tool handlers in a TypeScript project and reports each tool’s evidenced capabilities (financial.refund, communication.external, data.delete, …) with file:line evidence, a risk level, a separate confidence level, and a DECLARATION MISMATCH when the code exceeds what the tool declares. It runs locally and uploads nothing. Agents get the same answer from the did_inspect_tool MCP tool before they call something consequential. UNKNOWN means “not shown to be safe,” never “low risk.”
What if a provider I need isn’t supported?
http.ok verifies any public URL with no connection at all, your own endpoints included. For first-party adapters, tell us at hello@didwork.sh; Bitbucket, Azure DevOps, and Teams are next.
Access & security
Does DidWork need write access to my accounts?
Never. Adapters read authoritative state: a restricted Stripe key, a fine-grained GitHub token, a read-scoped Linear key. DidWork proves outcomes; it never needs the power to cause them.
How are my credentials stored?
Encrypted at rest with AES-256-GCM, shown only as a last-4 hint after entry, and validated against the provider before we store them. API keys themselves are hashed, so we can’t read them back either.
Billing
What counts as one verification?
One claim checked once. A did.verify() call and one run of a did.watch() cost the same. Requests refused at the free-tier cap are never counted or billed.
What happens at the free limit?
Without a payment method, requests past 250/month return 402 and the watch pauses. No verification is deleted for this reason, and everything resumes the moment billing is set up.
How long is evidence kept?
7 days on Hobbyist, a year on Pro, counted from when the verification ran. Past that the record is deleted permanently, so on Hobbyist, something verified today can’t be produced as proof three weeks from now. Capture verifications with a webhook if you need them to outlive the window.
What does Pro actually add?
Not the answer: every claim type, verdict, and piece of evidence is identical on both plans. Pro lifts what you need once something depends on that answer: unlimited watches down to 5 minutes, a year of evidence, email alerts when a watch turns FAILED, and separate keys per environment.