My AI prosecutor proved that a 150% coupon turns a $100 cart into −$50. Then my AI judge caught the defense's "fix" for a rounding bug and proved it was still broken.

No human reviewer had looked at the PR yet. And I didn't write a single line of application code to build the court.

This is Code Court, my project for the Flip the Switch Hackathon (DevTools Academy × Switch AI). Three AI agents put a GitHub pull request on trial inside a Discord channel, and my team is the jury.

The judge's final ruling in Discord

The problem with one reviewer

Code review usually means one reviewer, human or AI, reading a diff and saying "looks good." That reviewer has blind spots. It's easy to approve a PR because its description sounds right. And when an AI reviewer is confidently wrong, nobody pushes back.

Courtrooms solved this problem centuries ago. You don't trust one person's opinion. You make one side attack, one side defend, and a neutral judge check the evidence.

So I built that for pull requests.

Meet the court

Role Who Job
🧑‍⚖️ Judge @judge agent Opens the case, reads the diff, rules on every charge
⚔️ Prosecutor @prosecutor agent Hunts for bugs, missing validation and missing tests, citing file:line
🛡️ Defense @defense agent Answers each charge: CONCEDE, MITIGATE or CONTEST
👥 Jury My team, the humans Votes ⚖️ to accept the ruling or ❌ to overturn it

All three agents run on Claude Opus 5.5 through the Claude Code provider in Switch, on my own laptop. Switch bridges them into a Discord channel called #courtroom, where each agent shows up with its own name and its own @mention.

The flow looks like this:

Developer opens a PR ↓ @judge case: <PR link> (posted in Discord #courtroom) ↓ Judge opens court → calls @prosecutor → charges filed ↓ @defense answers each charge → plea entered ↓ @judge rules: SUSTAINED / OVERRULED + verdict + fix list ↓ Team votes ⚖️ or ❌ → a human merges or fixes on GitHub 

A real trial, start to finish

To test it, I made a small demo repo and opened a PR: "Add coupon discounts to checkout". It adds an applyCoupon() function and claims that "existing callers keep working unchanged."

function applyCoupon(total, discountPercent) { const discount = total * (discountPercent / 100); return Math.round((total - discount) * 100) / 100; } 

Looks harmless, right? Here's what happened in the courtroom.

⚖️ Court is in session (3:41 PM)

I typed one line in Discord:

@judge case: https://github.com/httpsravi/code-court-demo/pull/1 

The judge read the diff, summarised it, and called the prosecution.

Filing the case in Discord

⚔️ The prosecution (3:42 PM)

The prosecutor came back with three numbered charges, each with a severity and a line number:

Charge 1 — No validation of the discount (severity: high): checkout.js:24 accepts any value for discountPercent. If it's 150 the total comes out negative (a $100 cart becomes −$50), a negative value adds a surcharge, and NaN or a stray string makes the total NaN.

It also caught that my PR description was lying. Every total is now rounded, so "existing callers unchanged" was false. And it found that Math.round(x*100)/100 gets half-cents wrong: 1.005 becomes 1, not 1.01. The third charge: no tests at all.

Recommendation: FIX FIRST.

🛡️ The defense (3:45 PM)

This is the part I'm proudest of. The defense isn't a yes-man. Its prompt says: "Never defend a real security hole or data-loss bug; concede it. A defense that admits weak points is more convincing."

So it conceded charge 1 straight away and suggested a validation check. On charge 2 it mitigated: rounding money to the cent is the right behaviour, and the existing tests use whole-dollar carts, so they still pass. Then it offered a fix for the rounding bug:

Math.round(Number.EPSILON + x * 100) / 100 

Plea: MERGE WITH FIXES.

🔨 The ruling (3:52 PM)

Then the judge did something I didn't expect. It didn't just pick the more convincing side. It ran the edge cases itself, including the defense's fix:

Careful: the defense's suggested fix, Math.round(Number.EPSILON + x*100), still gives 1. I tested it. Math.round((x + Number.EPSILON) * 100) / 100 gives 1.01.

The defense's fix looked right and came with a confident explanation, and it was wrong. If I'd had a single AI reviewer, I'd probably have copied that fix straight into my code.

You can check it yourself in Node:

const x = 1.005; Math.round(x * 100) / 100; // 1 original bug Math.round(Number.EPSILON + x * 100) / 100; // 1 defense's fix: still wrong Math.round((x + Number.EPSILON) * 100) / 100; // 1.01 judge's fix 

All three charges were SUSTAINED. Verdict: MERGE WITH FIXES, with a 4-step checklist: validate 0–100, fix the rounding, correct the PR description, and add tests for 0%, 20%, 100%, out-of-range values and the 1.005 case.

My jury voted ⚖️. The whole trial took 11 minutes.

How I built it with zero code

Code Court has no application code. The whole "source" is three prompts and some settings in Switch:

  1. Started a Local Switch server in Switch Console. It runs on my own machine.
  2. Connected the Claude Code provider.
  3. Created three agents (judge, prosecutor, defense) and wrote a system prompt for each: its role, the exact output format, and hard rules like "never merge, close, approve, comment on, or push to anything on GitHub."
  4. Created a Discord bot with 8 permissions, connected it under Messaging apps → Discord, and posted in #courtroom to create the bridged room.
  5. Invited the agents with !invite-agent @judge and so on.

The prompts matter most. A few rules made the biggest difference:

  • Cite or it didn't happen. Every charge needs a file:line.
  • No invented facts. If an agent can't verify something, it has to say so.
  • One round each. The judge calls each side once, so the agents never loop.
  • Hands off GitHub. The agents only read. Humans merge.

What broke (and how I fixed it)

Not everything worked the first time:

  • The server wouldn't start, and the error was misleading. The error message quoted an old line from the log, not the real cause. Retrying fixed it.
  • Switch couldn't see Claude Code. An old install had left a broken claude on my PATH. Adding the real install folder to PATH fixed it.
  • The "Only me" trap. My judge called the defense and got "not permitted." The "Only me" setting blocks your own agents too. Switching to "Only me and my agents" fixed it.
  • Replies hide in threads. Each agent answers in a Discord thread, and the judge doesn't always notice. So today a human nudges each stage: tag @defense, then ask @judge for the verdict.

That last one turned into a feature. Every stage gets a human check, and nothing moves forward without a person.

Why this works better than one reviewer

  • Adversarial beats agreeable. A dedicated attacker and a dedicated defender bring up more than one reviewer, and they make the trade-offs explicit.
  • Agents check each other. The judge caught a wrong fix that the defense proposed in good faith.
  • Humans keep the final say. The AI argues. The team decides.

What's next

  • Auto-advance the stages, so the judge calls the defense and rules without a nudge.
  • Post the ruling to GitHub as a PR review.
  • A GitHub Action that files a case automatically when a PR opens.

Try it yourself

Everything, including all three prompts, the setup guide and the full transcript, is open source:

GitHub logo httpsravi / code-court

⚖️ AI agents put your pull requests on trial. A judge, prosecutor and defense debate every PR in Discord, and your team is the jury. Built with Switch for the Flip the Switch Hackathon 2026.

Code Court: AI agents put your pull requests on trial

Code Court ⚖️

AI agents put your pull requests on trial.

Built with Switch Discord GitHub Flip the Switch Hackathon 2026

🎬 Watch the demo video · 📝 Read the blog post · 🧾 See the demo PR

The judge's ruling on PR #1 in the Discord courtroom

Paste a pull request link into Discord and three AI agents hold a trial. One argues against the PR, one defends it, and a judge checks both sides against the real diff before ruling. Your team is the jury and has the final say.































Role Who Job
🧑‍⚖️ Judge

@judge agent
Opens the case, reads the diff, rules on every charge, gives a verdict and a fix list
⚔️ Prosecutor

@prosecutor agent
Hunts for bugs, missing validation, security issues and missing tests, citing file:line
🛡️ Defense

@defense agent
Answers each charge with CONCEDE, MITIGATE or CONTEST, and enters a plea
👥 Jury
Your team, the humans Votes ⚖️ to accept the ruling or ❌ to overturn it, then merges or fixes by
…





👉 Demo PR on trial: https://github.com/httpsravi/code-court-demo/pull/1

If you build your own court, I'd love to see what charges your prosecutor files. Drop a comment! ⚖️