Architecture, contract design, trust model and delivery plan for a bounty protocol where an AI agent — not a committee — decides that a developer has been paid.
Retroactive funding works. Verifying it doesn't scale.
Optimism's Retro Funding allocated over 100M OP to builders and proved the thesis: paying for impact after it happens beats paying for promises. But every round runs on human badgeholders reading submissions. Gitcoin distributes tens of millions and still fights sybils with identity heuristics. Both are slow because the same step is manual — someone has to decide whether the work is real.
That step is not actually subjective for most developer work. A merged pull request, a green CI run, a verified contract whose bytecode matches the merged commit — these are checkable facts. They were left to humans because reading a diff and judging whether it satisfies a spec required a human. That constraint no longer holds.
The cost of leaving it manual is concrete for a young chain: a developer who ships today gets paid next quarter, if ever. Ecosystems compete for builders, and payment latency is a recruiting metric.
Four components. Only one of them holds money, and it is the simplest one on purpose.
The agent is the complicated, fallible, upgradeable part. The contract is the simple, immutable part. Keeping intelligence off-chain and custody on-chain means a bug in the agent can misjudge a bounty, and at worst misdirect that one bounty's payout, but cannot drain the escrow, touch other bounties, or alter an amount. That boundary is the whole security argument.
Verification runs as a funnel: cheap deterministic checks reject most work before any model is invoked, and model judgement is confined to the one question that genuinely needs it.
| Stage | Check | Nature |
|---|---|---|
| Provenance | PR exists, targets the bounty's repo, author owns the claiming wallet | Deterministic — GitHub API + signed wallet linkage |
| Integrity | Merged to the default branch by a maintainer, not self-merged; commit is an ancestor of HEAD | Deterministic — rejects the most common gaming vector |
| Execution | CI green on the merge commit; test count and coverage did not regress | Deterministic — CI provider API |
| Deployment | Where the bounty requires it: contract verified on GIWA and bytecode matches the merged commit | Deterministic — explorer + local recompile |
| Substance | Does the diff actually satisfy the bounty spec, or does it merely touch the right files? | Model judgement — the only step requiring an LLM |
| Sybil signals | Recycled code, contribution history, timing patterns across the funder's bounties | Heuristics + model, scored not gated |
Each stage emits a signal; the aggregate produces a confidence score. Only a run that clears
every deterministic gate and exceeds the confidence threshold reaches
settle(). Everything below the threshold is escalated to the funder rather than
auto-rejected — a false negative costs a review, a false positive costs money, so the
asymmetry is deliberate.
The agent hashes the full evidence bundle and passes it to the contract, so any payout can be audited after the fact against what the agent claimed to have seen.
The checks in the bundle are every check run and commit status on the pull request's head
commit, with one exception: mergit/payable. Mergit writes that status itself, next to
the merge button, to tell the maintainer whether merging will pay. It is not CI, so it is left
out of the verdict and out of the hash.
// evidence preimage — stored off-chain, hash recorded on-chain repo:odiseo159-beep/celo-sentinel|task:giwa-escrow-demo|verifier:mergit-agent-v0 // emitted by MergitEscrow.settle() BountySettled(bountyId, developer, verifier, paidToDeveloper, protocolFee, evidenceHash)
MergitEscrow is deployed and source-verified on GIWA Sepolia at
0xffcf20…5879.
It is intentionally small: a bounty is a five-field struct and there are three state
transitions.
postBounty() settle() ∅ ──────────────────▶ Open ─────────────────▶ Settled (locks ETH) │ only verifier, │ before deadline │ refund() └─────────────────▶ Refunded only funder, after deadline
MAX_FEE_BPS) in code, so it cannot be raised on existing escrows.14 tests cover the permission matrix, double-settlement, deadline boundaries, fee arithmetic, isolation between concurrent bounties, and the invariant that the contract retains no dust after settlement.
A complete lifecycle has run on GIWA Sepolia — 0.0005 ETH locked, then released to a developer address by the verifier, 1.5% fee taken, evidence hash recorded. See the settlement transaction.
The honest position: today the verifier is trusted to judge correctly.
It is not trusted with custody, amounts, or timing — the contract removes those. But a funder posting a bounty is trusting that the agent will not name the wrong developer. Claiming otherwise would be dishonest, so here is the actual reduction path.
| Phase | Mechanism | What the verifier can still do wrong |
|---|---|---|
| Now | Bounded permissions + public evidence hash | Name the wrong recipient; detectable after the fact, not preventable |
| Phase 2 deployed, opt-in | Optimistic challenge window — settlement queues for the window the funder chose; the funder can object once before funds move. Deployed and verified as a second escrow. The one carrying the live payments above has no window | Nothing silently: any bad verdict is vetoable by the party who put up the money |
| Phase 3 | Multi-agent quorum — k-of-n independent verifiers with distinct prompts must agree | Requires collusion across independently operated agents |
| Beyond | Verifier bonds slashable on a successful challenge; attestation of the agent's execution | Misjudgement becomes economically irrational |
In the lifecycle executed so far, the funder, verifier and fee recipient are the same address — a single operator demonstrating the mechanism end to end. The developer is a separate party, which is the part that exercises the payout path. Independent funders and agents are Phase 2 work, not a property of the current deployment.
The standard for agent identity exists. Mergit does not use it, and this says why.
ERC-8004, “Trustless Agents” is a Standards Track ERC created in August 2025, authored out of MetaMask, the Ethereum Foundation, Google and Coinbase. It is a Draft. It defines three registries, meant to be deployed as per-chain singletons on any L2:
| Registry | What it holds |
|---|---|
| Identity | An ERC-721 with URIStorage. The token is the agent’s portable handle and resolves to its registration file. |
| Reputation | Feedback left by the clients an agent worked for. |
| Validation | Stake-secured re-execution, zkML proofs or TEE attestation, depending on what the value at risk justifies. |
Checked against GIWA Sepolia, not assumed. The mainnet singletons hold no code here. The
Sepolia-flavoured addresses do hold ERC-1967 proxies, pointing at an implementation that has
code, but a plain name() call against the identity proxy reverts. The vanity
addresses arrived through deterministic deployment; a working ERC-8004 did not.
There is nothing on this chain to register against yet.
Two reasons, and only one of them is timing.
The first is that the registry was deployed and used before any of this was reachable on GIWA. The second matters more: ERC-8004 hangs reputation off agent ids, and a builder record describes a person. The claim Mergit stores is a GitHub login bound to a wallet, with a public proof the agent re-checks against GitHub before every payment. That is an identity assertion about a human contributor, not an autonomous agent advertising a service. Mapping one onto the other would be a standards badge, not a working model.
The verifier is the agent in this system. Today there is one, named in every bounty by the funder who posted it. The day a funder has to choose between verifiers, what they will want is exactly what ERC-8004 describes: a portable id with a public record of what that agent settled and whether anyone objected. That is the part worth adopting, and it becomes useful the day there is more than one agent — not before.
No migration is promised here. The registry is deployed, verified and in use; replacing a working contract to match a Draft would trade something real for something fashionable.
| Layer | Choice and rationale |
|---|---|
| Contracts | Solidity 0.8.24, Hardhat 3, optimizer 200 runs. Verified via the GIWA Blockscout API. |
| Chain | GIWA (OP Stack). EVM-equivalent, so the escrow deploys unchanged from any EVM experience; sub-second blocks keep settlement perceptibly instant. |
| Agent | TypeScript. Deterministic checks against the GitHub and explorer APIs; a single constrained LLM call for diff-vs-spec judgement, with the prompt and evidence bundle persisted per verdict. |
| Chain access | viem — already used in production by the author for x402 machine-to-machine payments, the same primitive class as agent-triggered settlement. |
| Frontend | Static, no build step. Deployed on Vercel. |
| Phase | Status | Deliverable |
|---|---|---|
| 1 · Screening | done | Escrow deployed and verified on GIWA Sepolia; lifecycle settled on-chain; product walkthrough live |
| 2 · Testnet MVP | in progress | Agent v1 against real repositories, the merge triggering it from GitHub Actions, a reusable action, an on-chain identity registry, a challenge window, and funding or claiming from the browser done; a GitHub App and a bounty board next |
| 3 · Mainnet | planned | Stablecoin payouts, first partner protocols posting live bounties, fee switch on |
| Demoday · KBW | scheduled | Merge a pull request on stage; payment lands in seconds |
| Beyond | — | Automated retroactive funding pools; builder reputation graph derived from verified work |
A percentage fee is taken only when a bounty actually settles — no settlement, no fee, so funders risk nothing on bounties nobody fills. Revenue therefore tracks work funded, not speculation. Later phases add fees on retroactive funding pools distributed through the agent, and verified-work history becomes a reputation primitive other protocols can consume.
| Claim | Where to check it |
|---|---|
| Contract deployed and verified | sepolia-explorer.giwa.io/address/0xffcf20…5879 |
| Bounty funded on-chain | postBounty transaction |
| Developer paid, evidence logged | settle transaction |
| Agent verified a real pull request | mergit-demo#1 — merged, CI green, in a public repository with real tests |
| That merge released a payment | settle transaction, 8 September — evidence hash recomputable from the pull request |
| Source, tests and scripts | github.com/odiseo159-beep/mergit |
| Agent source | mergit/agent — what counts as verified, and what it refuses to pay |
| Product walkthrough | mergit.xyz — the walkthrough there is simulated and labelled as such; the agent behind it is not |
Every developer Mergit pays ends up with a page at mergit.xyz/p/<login>. These are the questions that decide whether it is worth anything, including the ones with uncomfortable answers.
Nobody. There is no database. The page reads the escrow events on GIWA Sepolia every time it loads, and the wallet comes from either the registry contract or the README of your own profile repository. Mergit cannot add a line to it, and cannot remove one.
What you were already paid stays. The page reads the commit history of
<login>/<login> and reconstructs which address was published at
which time. A payment counts for an older address when the payment happened while that
address was the one on your profile.
No, and that is exactly why the windows exist. Collecting every address that ever appeared in your README would let anyone add a stranger’s address for one commit, remove it, and inherit their payments. An address only counts for the payments that happened while it was published. A commit you make today cannot reach backwards.
You can fund them, and the page will show them, because they are on chain and hiding them would be lying. They are marked as self-funded and excluded from the totals. The headline number counts what somebody else paid for, and next to it sits the count of distinct funders, which is the number that actually costs something to raise: a second wallet is free, a second person is not.
Whoever funded the bounty, in the metadataURI they passed to
postBounty. It is free text and Mergit does not verify it, which is why
the column says so. What is verified is the evidenceHash in the settlement
event: it commits to the repository, the pull request number, the author, the merge commit
and the CI checks, and anyone can recompute it from the pull request.
You need an address, which is not the same thing. One line naming Mergit and your address in the README of the repository named after you is enough. Nothing to connect, no gas, nothing signed. Registering on chain at /register is the other way, and it costs gas.
Yes. GET /record/<login>.json returns the same record as JSON, with
every payment, the task text marked as funder-written, the evidence hash and the
transaction. It reads the chain at request time, the same as the page.
Said plainly, because a record that oversells itself is worth less than one that does not: