DEV Community

dengyier
dengyier

Posted on

When AI Agents Ship Code: A Protocol for Verifiable Execution

Last month I merged a bug fix an AI agent wrote. It looked right. The agent said tests passed. I deployed it.

Two hours later, production caught fire.

Not because the agent was wrong — because I never verified anything. I just trusted it.


The problem isn't "can agents do things." It's "can agents prove what they did."

Every multi-agent framework today solves the same problem: make agents talk to each other.

MCP connects agents to tools. A2A connects agents to agents. LangChain, CrewAI, AutoGen orchestrate the dance. The tooling is incredible.

But here's what nobody solved: when agent #2 says "I reviewed the patch" or "tests passed," there's no protocol-level way to verify that claim.

Agent #3 just has to trust agent #2. The middleware just has to trust both. You — the human — just have to trust the pipeline.

That works in demos. It doesn't work in production.


Three questions that kept me up at night

When I started digging into this, I kept coming back to three questions:

1. Was this action even authorized?

An agent shouldn't be able to just decide to run rm -rf or push to production. Every tool call should carry machine-checkable proof that a specific role said "yes, within scope, within quota."

2. Is there a causal chain from the patch to the test results?

If an agent says "I tested the patch and it passed," you should be able to trace backwards: the test run → the patch it tested → the authorization to apply that patch → the work order that started it all. No gaps. No "I swear, bro."

3. Can a third party verify everything without trusting anyone?

This is the acid test. If verifying an agent's work requires logging into the agent's machine, reading its logs, and trusting its middleware, then you haven't really verified anything — you've just moved the trust around.

A real verification protocol should let an independent party replay the entire evidence chain offline, with nothing but the evidence bundle and public keys.


What I built

OpenWorkProof is a protocol layer (not a framework) that sits between agents and their tools. It doesn't replace MCP or A2A — it adds accountability on top of connectivity.

Here's what happens for every tool call:

Step 1: Authorization before execution

Before an agent touches any tool, a PolicyDecision is signed:

from openworkproof import policy

auth_ctx = policy.derive_authorization_context(
    work_order=work_order,
    grants=grants,
    receipts=receipts,
    request=signed_request,
    arguments=args,
    execution_facts=facts,
    checkpoint=checkpoint,
)
decision = policy.authorize_tool_call(auth_ctx)
# decision.allowed == False → deny receipt, don't execute
Enter fullscreen mode Exit fullscreen mode

Every decision binds: who authorized it (role + Ed25519 key), what tool they authorized, within what scope and quota, and when the authorization window expires.

If the agent wasn't authorized? The tool call never happens. Period.

Step 2: Signed execution receipt with causal chain

Once the tool runs, it produces an ActionReceipt that chains back to the authorization:

  • Which PolicyDecision authorized it
  • What evidence it produced (diff, test report, benchmarks)
  • What quota it consumed
  • What its parent receipts are (causal graph, not timeline)

You can't skip steps. You can't fabricate history. The causal graph enforces exact parent sets — if step 5 claims step 3 as its parent but step 3 never happened, verification fails at the protocol level.

Step 3: Offline third-party verification

This is the part I'm most proud of. Any third party can replay the entire chain with zero trust:

from openworkproof.acceptance import verify_acceptance_bundle

result = verify_acceptance_bundle(
    work_order=work_order,
    report=report,
    effective_grants=grants,
    receipts=receipts,
    committed_evidence=evidence,
    acceptance_receipt=signed,
    public_keys=keys,
)
# Pure function. Zero I/O. Deterministic.
Enter fullscreen mode Exit fullscreen mode

No database connections. No access to the agent's machine. No trust in any participant. Just the evidence bundle and the public keys. If the chain is internally consistent, it passes. If not, it fails — and tells you exactly where.


The six-role model

I settled on six roles after realizing that "agent" is too vague for accountability:

Role Responsibility
Maintainer Creates the WorkOrder, issues root CapabilityGrant
Manager Issues scoped child grants, composes multi-step proofs
Developer Executes authorized tool calls, produces ActionReceipts
Verifier Independently re-runs tests, cross-checks results
Sidecar Assigns trusted execution facts (container ID, SHA, etc.)
Acceptor Signs final accept/reject with an external key

Key constraint: grants only attenuate. When you delegate from Maintainer → Manager → Developer, permissions can only shrink, never expand. A sub-grant can't grant more access than the parent had. This is the principle of no-cloning authority — it prevents privilege escalation at the protocol level.

The state machine flows: running → locally_verified → proof_ready → awaiting_human → accepted


Does it actually work? Two real bugs.

I didn't test this on toy examples. I tested it on two real open-source issues:

Bug 1: Rich #4196 — terminal formatting

Rich is a popular Python terminal formatting library (50k+ stars). Bug #4196 was a rendering edge case. I built a full 9-step evidence chain:

WorkOrder → Grant issuance → PolicyDecision → repo_read → apply_patch → run_tests → evidence publication → acceptance bundle → offline verification

Every step signed. Every step traceable. Third-party verifier confirmed the chain without touching any live system.

Bug 2: Dify #33013 — LLM application platform

Different project type entirely — a TypeError in Dify's QuestionClassifierNode. Same protocol worked without modification. This proves the protocol isn't coupled to one kind of codebase, one kind of bug, or one kind of test suite.

2,283 tests. 0 failures. Apache-2.0.


Honest limitations (v1.0)

This is a protocol, not a product. Here's what it doesn't do yet:

  • Only repo_read, apply_patch, and run_tests have complete handler implementations — other tool types need handler closures
  • No formal security audit
  • The Sidecar role still requires manual execution-fact assignment
  • No hosted verification dashboard (yet)

The protocol core is solid. The implementation proves it. The surface area is limited — intentionally, at this stage.


Where this fits in the ecosystem

There's an interesting dynamic happening in AI agent infrastructure right now:

Layer What it solves Who's building it
Identity "Who is this agent?" Catena Labs, GenLayer
Connectivity "How do agents talk?" MCP, A2A
Orchestration "What should agents do?" LangChain, CrewAI, AutoGen
Verification "Did agents do what they claim?" OpenWorkProof

The verification layer is the one nobody has cracked yet. And it's about to become non-negotiable — the EU AI Act's high-risk provisions are already in effect, requiring provable authorization, constraint, and accountability for AI systems.

An analogy I keep coming back to: OAuth defined how humans authorize applications, and that created the Okta/Auth0 market. OpenWorkProof defines how humans authorize AI agents — and verify what they did. Same pattern, different domain.


What I'd love feedback on

I'm posting this because I want to know if I'm solving a real problem or just the one I hit:

  • Does the six-role model map to your agent setup, or is it overengineered?
  • Is offline third-party verification actually useful, or is "trust the middleware" good enough for your use case?
  • What tool call handlers would you need first — beyond repo_read, apply_patch, and run_tests?

I'm not here to sell anything. The project is open-source (Apache-2.0), the repo is public, and I'm genuinely interested in whether other teams are hitting the same verification wall.


GitHub: dengyier/OpenWorkProof

Interactive demo: 9-step evidence chain for Rich #4196

pip install openworkproof
Enter fullscreen mode Exit fullscreen mode

Top comments (5)

Collapse
 
kikashy profile image
Brian Jin

I like the separation between execution and independently verifiable evidence of what happened. Where do you see the substantive decision criteria behind a PolicyDecision living - inside the protocol implementation, or in a separately versioned and testable policy artifact?

Collapse
 
dengyier profile image
dengyier

Brian, great question — and it's one we've wrestled with internally. The short answer is: both, but with a strict separation of concerns.

The PolicyDecision itself — the signed, auditable receipt that says "this action is authorized under this policy" — is a protocol-level artifact. It lives in the receipt chain, is versioned by the protocol schema, and its structure is enforced by the OWP implementation. You can't have a valid PolicyDecision that doesn't conform to the schema, just as you can't have a valid HTTP request that doesn't conform to the spec.

But the substantive decision criteria — the actual rules that determine whether an action is permitted — live in a separately versioned, testable policy artifact. In our current implementation, this is a JSON policy document (the policy.json or capability_grant object) that is referenced by digest in the PolicyDecision receipt. The policy artifact is:

Versioned independently of the protocol schema. A PolicyDecision from v0.1 of the protocol can reference a policy artifact at v3.2, and the verifier checks both version constraints independently.
Testable in isolation. The policy artifact can be evaluated against a mock request without touching the receipt chain, making it possible to unit-test authorization logic separately from cryptographic plumbing.
Auditable by reference. The verifier doesn't need the full policy text in the receipt — just its digest. The policy artifact is fetched (or already cached) at verification time, and its digest is checked against the reference in the PolicyDecision.
This separation matters because the two artifacts have different trust properties. The PolicyDecision receipt proves who authorized what, when, and under which policy digest. The policy artifact defines what the rules actually are. If you conflate them — putting the full policy text inside the receipt — you bloat the chain and make policy updates expensive (every policy change requires re-signing all historical receipts). If you separate them, the receipt chain stays lean, and policy evolution is independent.

A subtlety: the policy artifact is itself signed (by the Authorizer role), so it's not just a loose JSON file. The verifier checks: (1) the PolicyDecision signature proves the Authorizer approved this action, (2) the policy digest in the PolicyDecision matches the signed policy artifact, and (3) the action parameters satisfy the policy rules. Three independent checks, three independent failure modes.

Does that map to what you were imagining, or were you thinking of a different boundary — e.g., embedding the policy criteria in a smart-contract-like layer?

The repo is at github.com/dengyier/OpenWorkProof if you want to trace how PolicyDecision and CapabilityGrant interact in the current implementation. The test_policy_decision.py suite covers the digest-matching and version-checking paths.

Collapse
 
kikashy profile image
Brian Jin

Yes - that maps closely to the boundary I had in mind.

The distinction I’m exploring is one step inside the substantive policy artifact. A CapabilityGrant can answer whether this actor has authority to perform an action, while some enterprise decisions also require a separate judgment over evidence, rules, exceptions, missing information, and escalation conditions before that authority should actually be exercised.

That is where I’m experimenting with JPS - a separately versioned and testable judgment artifact that can produce a deterministic disposition such as approve, deny, unresolved, or escalate.

Your design suggests an interesting interoperability test: let JPS produce the judgment, then let OWP bind the exact policy version, facts/disposition, and authorized action into the PolicyDecision and receipt chain.

The falsifiers would be the interesting part - change the pack version, substitute facts, replay an old decision, or change the execution arguments after approval and see whether an independent verifier detects the broken binding.

That would keep the responsibilities clean:

JPS - what should happen under these facts and rules

OWP - who authorized it, what actually happened, and whether the evidence chain still verifies

I’m going to explore that boundary experimentally.

Collapse
 
purehub profile image
PureHub

Great question! Verifying AI agent work is crucial for trust. I build PureHub, a privacy-first open-source tool collection, and while it doesn't do AI verification, it does offer tools for cryptographic signing and verification that might complement your workflow. For your specific protocol, I'd suggest checking out existing standards like Sigstore or Rekor for transparency logs. What's your main challenge—ensuring the agent's identity or the integrity of the work output?

Collapse
 
dengyier profile image
dengyier

Thanks for the pointer, PureHub! You're right that Sigstore and Rekor are highly relevant reference points — they've solved a big chunk of the supply-chain transparency problem for traditional software. The OWP protocol draws on similar principles (signed digests, immutable log chains, key-bound identity), but we had to extend the model in two specific directions for the AI agent case:

  1. Identity alone isn't enough. In Sigstore, identity is "who pushed this container image." In OWP, it's "which agent, acting under which policy, with which capability grant, issued this command." The challenge is that AI agents are delegated actors — their authority is scoped and time-bound, and the verifier needs to independently confirm that scope hasn't been exceeded. So identity is the starting point, not the endpoint.

  2. Output integrity needs to be re-executable, not just signed. A signed container image is a static artifact. A signed AI action receipt is a claim about a dynamic execution. The verifier must be able to independently reconstruct the execution environment (from container_image_digest + command_digest) and re-execute to verify, not just check the signature. That's where the protocol's recomposition design comes in.

Rekor's transparency log model is close to what we want for the receipt chain, but we'd need to extend it to support retraction — the ability to mark a previously accepted receipt as REFUTED without rewriting the original record. That's a unique requirement for agents that run continuously and may produce results that degrade over time (stale context, changed state, etc.).

Your PureHub tools for cryptographic signing and verification might actually be a good fit for the lower-level receipt operations in OWP. We'd be curious to compare notes — especially if there's a clean way to integrate your signing primitives into a role-bound capability grant system. If you're interested, the OWP MCP server is available on PyPI and glama.ai. and the full source is on GitHub: github.com/dengyier/OpenWorkProof. A quick pip install open-work-proof + pip install mcp_server will get you to a local verifier. We'd love your take on whether it extends cleanly.