Skip to main content

A security questionnaire arrives with 200 rows. The answers all exist somewhere — in last quarter's SOC 2 report, in a policy doc, in the response you sent a different customer in March. Someone spends a week finding them again.

Everyone has seen an RFP bot that drafts those answers. The hard part isn't drafting. It's what happens on the rows where the evidence isn't there, because a fluent, confident, wrong answer about your own security controls doesn't get caught in review — it gets pasted into a customer's document over your signature.

So this recipe is built around the failure contract rather than the happy path. Only permitted, approved evidence enters the prompt. Every claim keeps its citation. Missing evidence stays unanswered. A person approves before anything leaves.

Questionnairexlsx / docx / CSV
Parse + dedupexact merges only
Client Chatone call per question
Gleanpermission-aware index
Evidence checktopicality + approval
Review + approvehuman gate, audit log
A Glean instance with your company content indexed
A work email for tenant discovery and OAuth sign-in; a CHAT-scoped API token is the fallback
Node 20+
1

Scaffold the project

npx -y tiged@2.12.8 --mode=git gleanwork/glean-cookbook/recipes/rfp-responder rfp-responder
2

Install dependencies

cd rfp-responder && npm install
3

Try it with no credentials

Runs the whole flow against recorded responses and asserts the failure contract: no ungrounded row carries an answer, every answered row carries a citation, and export is gated on approval.

cd rfp-responder && npm run verify:fixture
4

Set credentials

Only for a live run. Use the shipped login flow, then configure the approved source prefixes supplied up front. The app runs as the signed-in user; there is no act-as.

cd rfp-responder && npm run login -- --email "<work-email>"
5

Run it

cd rfp-responder && npm start
6

Verify

Load the questionnaire, confirm the column mapping, and draft. Check that a supported question (SOC 2, encryption at rest) returns a cited answer, and that an unsupported one (ISO 27001, RTO/RPO) is left blank and assigned to an SME rather than answered.

Similarity may rank possible duplicates for review, but must never merge security controls automatically.

A source must be both relevant and explicitly approved for customer-facing use before it can support a draft.

The app runs as the credential owner. Multi-user deployment requires per-user authentication and authorization.

Take it further
  • Add an xlsx and docx reader so real questionnaires can be uploaded directly — the parser here reads CSV to keep the interesting logic legible.
  • Write answers back into the source document with a custom tool instead of exporting, keeping the confirm step and the approval log.
  • Give the answer library its own access control before sharing it across a team. It's a cache of retrieved content, so it can leak across the permission boundary the rest of the app respects.
  • Route "needs SME" rows to their owners automatically, and track which ones came back — the assignment field here is deliberately inert.
  • Combine with permissions-aware retrieval to see the same refusal property in a smaller, single-question app.

Draft answers to a real questionnaire you've had to fill in

Every row is parsed across every tab, exact duplicates are merged, and each row is classified by the evidence behind it: strongly grounded rows get a cited draft, adjacent-evidence rows are flagged for verification, and rows with nothing behind them are left blank. Use a questionnaire your own content can actually speak to.

Ask something your documentation genuinely doesn't cover

Retrieval finds nothing, so the row returns INSUFFICIENT_EVIDENCE and renders as 'needs SME' with no draft text, and accepting it is refused. This is the behaviour to check first — an RFP tool that invents a compliance answer is worse than no tool, because someone will send it to a customer.

Ask something only tangentially covered

Retrieval finds a document that is genuinely on-topic but not authoritative, so the row is flagged weak rather than strong: drafted, but labelled as resting on documentation a person must clear before it goes out.

Run the same questionnaire as a colleague with narrower access

Rows backed by documents that person cannot see collapse to 'needs SME' rather than being answered from elsewhere. Their own credential is the permission boundary — you are not impersonating them, you are each running the app as yourselves and comparing.

View source

Runs the recipe through the Glean cookbook plugin.

At a glance
SurfacesClient API
StatusShowcase
Time~45 min
Required scopes
CHAT