A public-sector RFP is not a writing problem. It's an evidence problem.
Demo: 2:04 walkthrough · Code: github.com/shreepalgoyal/bidroom · Signed report: View sample report
The failure mode nobody demos
Every AI writing tool looks impressive when you give it an RFP.
Feed it a 90-page tender, and it will return fluent, confident prose in seconds.
That's exactly the problem.
A bid team has four weeks, hundreds of requirements, and a library of case studies that may or may not prove what the sales team wants to claim.
The dangerous failure isn't a missing answer. It's an answer that sounds true, cites the wrong evidence, and gets discovered after the contract is awarded.
The bid is lost, the contract is challenged, and nobody can reconstruct why the claim was made in the first place.
Generic AI makes this worse because it optimizes for prose rather than proof.
A language model will happily turn a SOC 2 report into an answer for an ISO/IEC 27001 requirement because both are "security certifications."
They are not the same thing.
So I built BidRoom around one rule:
Every compliance claim must cite an approved evidence record. Agents can propose evidence, but only a named human can approve it, and only the bid lead can sign the submission.
That single constraint changes the shape of the entire workflow.
Gaps stop being embarrassing and become first-class objects with owners. Approval stops being a chat reaction and becomes an auditable action.
And the final artifact isn't just a document. It's a compliance matrix that a team can actually defend during a bid review.
The room
BidRoom is built on Switch, with OpenCode as the agent runtime and the Mattermost rooms provisioned by Switch as the shared workspace.
One Switch template (switch/bidroom.template.yaml) creates:
-
Five agents:
scout,matcher,evidence,writer, andredteam, each with its own role prompt and tool access. -
Two linked rooms:
Bid: Northwind City Councilfor the client workflow, andnorthwind-evidence-deskfor evidence review. - The runbook, relay rules, and kickoff message, so the room explains itself to a new team member.
The agents share one checkout, so .bidroom/ on disk is the only shared state.
Switch provides the identities, rooms, and relay. Without it, there is no room, no agent identity, and no place for the human approval gate to live.
The relay is explicit and one-directional:
scout → matcher → human approval → writer → redteam → human sign-off
Agents never approve evidence, and they never sign submissions.
The runbook makes this clear, and the CLI enforces it.
The pipeline
Each agent has a specific responsibility.
1. Scout: Understand the RFP
Scout reads the RFP and extracts the requirement register.
For the bundled Northwind City Council tender (NCC-2026-114), which covers a resident services portal, that means identifying 77 requirements:
- 65 mandatory requirements
- 12 scored requirements
It also identifies the five most difficult mandatory requirements, helping the bid lead understand where the team needs to spend its time.
2. Matcher: Find relevant evidence
Matcher scores every requirement against the evidence library.
The initial matching approach uses token overlap across requirement text, tags, and categories, with additional qualifier penalties.
For example, if a requirement explicitly names a standard or product such as ISO/IEC 27001, IDOX, IPv6, WCAG, PSBAR, or Open Government Licence, the score is penalized when the evidence record doesn't reference that specific qualifier.
This is what prevents a SOC 2 record from being treated as proof of ISO/IEC 27001 compliance.
A similar-sounding claim isn't automatically relevant evidence.
3. Evidence: Turn gaps into reviewable records
Evidence turns identified gaps into Markdown records with frontmatter containing:
- ID
- Claim
- Tags
- Categories
- Owner
- Last verified date
- Source
- Approval state
It then posts the approval queue to the evidence review room.
This is the only agent that can add records to the evidence library, and it can only create them in an unapproved state.
The agent can propose evidence. It cannot approve its own proposal.
4. Writer: Draft from approved evidence
Writer creates the bid response using approved evidence records only.
Every claim includes a citation.
If evidence is missing, the gap remains visible with an owner and a next action.
No record, no sentence.
This is an important distinction: the writer isn't allowed to invent a convincing answer just because the requirement needs one.
5. Redteam: Challenge the draft
Redteam reviews the generated draft against the evidence library.
Unsupported claims become blockers rather than mere writing suggestions.
It also calculates a readiness score, helping the bid lead distinguish between:
- "The writing looks good."
- "The submission is actually defensible."
Those are two very different things.
The human gate is code, not a prompt
This is the part I cared about most.
I didn't want human approval to be something an agent could simulate by writing "Approved" in a chat message.
Approval is a CLI command requiring a named person:
bidroom evidence approve E-DEL-09 \
--by "Priya Raman" \
--note "Checked Delivery report v4 section 3: top-20 transactions complete end to end."
Sign-off is a separate command:
bidroom signoff --by "Priya Raman" \
--note "Reviewed the matrix, draft and red-team findings." \
--accept-gaps
The --accept-gaps option isn't a bypass.
It requires a written reason, and the final report lists every accepted gap by ID.
The signature also pins the approved evidence library using a SHA-256 digest.
If someone edits an approved record afterward, the report marks the signature as stale.
There's another deliberate restriction: the MCP server exposes no approval or sign-off tool.
That means an agent cannot approve its own evidence, even if someone prompts it to try.
That's the entire product thesis:
The interesting work isn't generating text. It's deciding what counts as proof, and who is allowed to say so.
The numbers
The bundled example uses a synthetic but realistic UK local-government RFP.
It ships with 54 evidence records.
Here's what happened after six human approvals:
| Metric | Baseline | After six human approvals |
|---|---|---|
| Compliant | 50 | 57 |
| Partial | 6 | 6 |
| Needs approval | 2 | 2 |
| Gap | 19 | 12 |
| Coverage | 68.8% | 77.9% |
| Approved evidence | 46 | 52 |
| Readiness | 55/100 | 70/100 |
| Blockers | 19 | 0 |
The six records that closed gaps were actual reviewable files covering:
- The top-20 transactions journey.
- The single digital front door.
- The IDOX Uniform integration.
- A 60k-user load test.
- The assisted-digital route.
- The open-data extract.
They were imported as unapproved records on purpose, so the human approval step would be visible.
Two records remained unapproved as well:
- The AI search pilot was still in its sandbox stage.
- The delegated-access consent wording was still under legal review.
A demo that approves everything isn't a demonstration of an approval gate.
Eight mandatory gaps also remain, each with an owner and a disclosed next step. These include ISO/IEC 27001 certification, UK GDPR/DPA/PSBAR evidence, IPv6, digital-skills workshops, gainshare, and submission or commercial items the council hasn't answered yet.
The report shows them.
That's the point.
What surprised me
Qualifier penalties did more for trust than any prompt
The first version of the matcher was too generous.
It matched "security certification" to "security certification" and produced a beautiful but incorrect compliance matrix.
Adding named-standard penalties changed that.
The system became more cautious about what it considered relevant evidence, and that made the output much more useful.
Gaps are a feature, not a failure state
Initially, gaps looked like something the system needed to eliminate.
But once every gap had an owner and a next action, the team's attention shifted away from arguing about prose and toward closing evidence gaps.
The compliance matrix became the actual product.
The human gate needs a scripted replay
Judges and reviewers shouldn't have to manually approve six records just to see the final signed result.
So I added:
bidroom demo --full
It replays the human's part of the workflow:
- Imports the six evidence records.
- Records the approvals by name.
- Generates the draft.
- Runs the red-team review.
- Completes sign-off.
It produces the same result: 57 compliant, 6 partial, 2 needing approval, 12 gaps, 77.9% coverage, 70/100 readiness, and zero blockers.
The approval gate is still enforced through the same CLI command.
The demo just makes the entire process reproducible with one command.
The agents are most useful before the prose
Scout and Matcher performed work that would otherwise have taken me around two days.
Writer was fast, but it was only trustworthy because the evidence layer existed first.
That was probably my biggest takeaway from building BidRoom.
The quality of AI-generated writing matters, but the quality of the evidence behind it matters much more.
Run it yourself
You can clone the repository and run the bundled example locally.
git clone https://github.com/shreepalgoyal/bidroom.git
cd bidroom
python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"
# Full replay: baseline, six human approvals, draft, red team, sign-off
.venv/bin/bidroom demo --out demo-output --force --full
# Baseline only
.venv/bin/bidroom demo --out demo-baseline --force
To run the actual multi-agent room:
- Import
switch/bidroom.template.yamlin Switch Console → Templates. - Set
directoryto the shared checkout. - Set
repo_urlto your fork. - Create the group.
The complete setup instructions, including the OpenCode version note and Mattermost troubleshooting, are in docs/SETUP.md.
The project currently includes 19 tests, including an end-to-end test that runs the full demo and verifies the signed result.
No API key is required to run the bundled example.
What I would build next
There are still several areas I'd like to improve.
1. Evidence expiry
The last_verified field already exists, but nothing currently forces a re-check before a bid.
A stale evidence library should block sign-off, not just generate a warning.
2. Per-claim provenance
The report currently pins the entire approved evidence library with a digest.
The next step would be a per-claim hash, allowing reviewers to trace an individual sentence back to its exact evidence record.
3. Real RFP ingestion
The bundled example uses Markdown.
Real public-sector tenders arrive as PDFs, spreadsheets, and web portals. Building a reliable ingestion pipeline for those formats is one of the next major challenges.
4. Team roles
One bid lead is enough for a demo.
Real bids involve security reviewers, commercial reviewers, delivery leads, and other stakeholders.
The approval gate should understand these different responsibilities instead of treating every approval as interchangeable.
Final thoughts
BidRoom was built for Flip the Switch - Track 01: Best Business Workflow.
The project explores a simple idea: AI agents can do a lot of the work involved in preparing a complex bid, but they shouldn't be the authority on whether a claim is true or whether a submission is ready.
Five agents, a real compliance matrix, a signed report, and a human who has to mean it.
Watch the 2:04 walkthrough or explore the source code on GitHub.
I'd be interested to hear how others are approaching human approval, evidence traceability, and reliable multi-agent workflows.
Top comments (0)