Series · 7 parts Published June 4, 2026

Proposal generator

A serverless generator that turns a short brief — client, what they need, rough budget — into a polished first-draft sales proposal: a cover, an understanding of the need, a proposed approach, a timeline, and a price summary, pulled from your own templates and past winning proposals, in your voice. You edit and send; nothing reaches a client without sign-off. Seven posts on the same system — one diagram at a time — with an engineering reference at the end.

  1. 01

    A proposal generator on AWS for a few dollars a month

    The whole system on one page — a brief intake, a generator, and a delivery piece, plus the parts they share for every proposal.

  2. 02

    How a proposal brief gets captured

    Three lanes feed a brief in — a short web form, a forwarded email thread that gets read into a brief, and a one-line Slack command — all tidied into the same clean brief for one-tap start.

  3. 03

    How a proposal gets drafted

    A build job reads the brief, finds your closest past proposals, computes the price in plain Python, then writes the five sections in one grounded model call. The numbers are never the model’s to invent.

  4. 04

    How a proposal stays on brand

    Voice rules, banned-claim checks, a price-and-date guard that re-reads the draft, and the four gates between a fresh draft and the moment it’s shown to you for sign-off.

  5. 05

    How a proposal gets sent

    Three actions on the Approve button: approve (render a branded PDF and email it), edit (open the doc, revise, re-approve), and discard (archive the brief). Every action is logged.

  6. 06

    What the proposal generator costs

    A few dollars a month at SMB volume. One Sonnet draft call per proposal dominates the bill; storage, retrieval, and the build steps are slivers.

  7. 07

    Engineering reference: the proposal generator architecture

    Same system, drawn purely for engineers. Service names, resource identifiers, region, Bedrock model IDs, Lambda inventory, IAM scopes, the S3 Vectors setup, EventBridge config, and the DynamoDB schemas.

What is a proposal generator?
A small serverless system that turns a short brief — client name, what they need, and a rough budget — into a complete first-draft sales proposal: a cover, an understanding of the need, a proposed approach, a timeline, and a price summary. It writes in your voice, pulling from your own templates and past winning proposals. You edit the draft and send it; nothing reaches a client without your sign-off.
How much does it cost to run?
About $3/month at typical small-business volume (around 30 proposals a month). The fixed cost is essentially zero. The variable cost is dominated by the Bedrock draft call that writes the proposal; everything else — storage, the build Lambda, retrieval over past proposals — is a few cents. At 150 proposals a month the bill lands around $12.
Which AWS services does it use?
Lambda (Python 3.14, arm64) with Function URLs for the brief form and the approve button, EventBridge for the build steps, DynamoDB on-demand, S3 (with versioning) for past proposals and finished PDFs, SES outbound, S3 Vectors for retrieval over your past proposals, Secrets Manager, CloudWatch Logs (7-day retention), AWS Budgets, and Bedrock (Claude Sonnet 4.6 for the draft, Claude Haiku 4.5 for the cheap classify steps, Titan Text Embeddings V2 for retrieval). No API Gateway, no NAT Gateway, no always-on compute.
Where does the content come from?
From a Google Drive folder you control. One sub-folder holds your section templates (a cover format, a scope shell, a standard timeline), one holds your past proposals (the ones that won), and one short doc holds your pricing rules and voice notes. A drive-sync Lambda mirrors the folder to S3 every 15 minutes; the generator reads from S3 and retrieves the most relevant past sections to ground each new draft.
Does it use AI?
Yes, where it earns its place. A cheap Haiku 4.5 call tidies and classifies the brief. Titan embeddings find the closest past proposals. Then one Sonnet 4.6 call writes the full draft, grounded on your templates and retrieved past sections. The pricing math itself is plain Python — no model touches the numbers. And no draft is ever sent automatically; a human edits and approves every one.
Why won’t it invent prices or promises?
The price summary is computed by plain Python from your rate card and the brief’s budget, not written by the model. The draft only restates the computed numbers; a guard checks that every price and date in the prose matches the computed values before the draft is shown. If the model writes a number that isn’t grounded, the guard flags it and the draft is held for a human to fix.
What happens when I approve a draft?
Three buttons on every draft: Approve renders the proposal to a branded PDF, saves it to the Drive folder, and emails it to the client via SES. Edit opens the draft in the linked Google Doc to revise, then re-approve. Discard logs it and archives the brief. Every action is recorded in the pg-audit DynamoDB table with timestamp, brief id, action, by-user, and a before-and-after snapshot, so a sent proposal can always be traced back to the brief it came from.
All posts