QuoteShield: Turn a Client's WhatsApp Message into a Watertight Scope of Work published: true
This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle What I Built Every freelancer has had this message: "Need an app that tracks my clients β who owes me money, project s
This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle
What I Built
Every freelancer has had this message:
"Need an app that tracks my clients β who owes me money, project status, invoice dates. Simple UI, maybe mobile friendly too. Nothing too fancy."
"Nothing too fancy" usually turns into three extra screens, a login system, "can you also host it?", and six rounds of "small changes". Most of the work you never get paid for comes from scope creep, and scope creep comes from a scope nobody wrote down.
QuoteShield fixes that. You paste whatever the client sent you (a WhatsApp message, a rambling email, a voice-note transcript) and in a few seconds you get a professional scope of work:
- Deliverables specific enough that both sides know when each one is done. Not "Shop page" but "E-commerce shop page with product grid, category filters, cart and Razorpay checkout".
- Milestones with testable outcomes instead of "Development".
- A "Not Included" list, which does most of the protecting: hosting, SEO, copywriting, post-launch support, everything a client quietly assumes is free.
- Binding assumptions that name what the client must deliver and by when.
- An hours estimate and a revision policy that defines what actually counts as a revision.
You can choose a tone (Professional, Friendly or Strict), add your hourly rate to see a live cost range, add your own constraints ("I only do React, no SEO"), and copy the result as plain text or Markdown to paste straight into a proposal.
It also gives each scope a health score out of 100 based on how complete it is, so you can see a thin one before you send it.
Who pays for this? Freelancers and small agencies who quote work every week. One avoided scope argument pays for a year of a small subscription.
Demo
π Live: https://quoteshield-ten.vercel.app
Try one of the built-in examples, or paste a real client message you've received.
Code
βοΈ QuoteShield
Paste a chaotic client brief β a WhatsApp message, a rambling email, a voice-note transcript β and get a professional scope of work in seconds: specific deliverables, testable milestones, a thorough "not included" list, binding assumptions, an hours estimate and a revision policy.
Live: https://quoteshield-ten.vercel.app
Stack
- Frontend: React + Vite (Vercel)
- Backend: FastAPI (Render)
-
AI: open-weight
gpt-oss-20bon Groq, with automatic fallback togpt-oss-120b
Run locally
Backend
cd backend pip install -r requirements.txt # get a free key at https://console.groq.com export GROQ_API_KEY=your_key # PowerShell: $env:GROQ_API_KEY="your_key" uvicorn main:app --reload --port 8000
Frontend
cd frontend npm install # point at your local backend (defaults to the hosted one) echo VITE_API_URL=http://localhost:8000 > .env.local npm run dev
Deploy
-
Render (root
backend): buildpip install -r requirements.txt, startuvicorn main:app --host 0.0.0.0 --port $PORT, env varGROQ_API_KEY. OptionalGROQ_MODELSto override the model list. -
Vercel (root
frontend): frameworkβ¦
How I Built It
Frontend: React + Vite with CSS Modules, deployed on Vercel. A dark UI with the tone selector, rate calculator, example briefs and the scope document view with its health score.
Backend: FastAPI deployed on Render. It does more than pass the request along:
- A strict prompt. The model gets seven rules: no vague words like "premium" or "clean" without defining them, every milestone needs a testable outcome, assumptions must name who delivers what and by when, and so on. This is the biggest factor in output quality.
-
A model fallback chain. The backend tries
gpt-oss-20bfirst and falls back togpt-oss-120b. The list is an environment variable, so swapping models takes no code change. - JSON mode with a retry. It asks for structured JSON. If the model rejects JSON mode or returns something that won't parse, it retries in plain mode, then moves to the next model.
-
Output normalization. LLMs sometimes return
"60-80"for hours, an object where a string should be, or"exclusions"instead of"not_included". The backend reshapes everything into one fixed schema, so the frontend never gets a broken scope.
Render hosts the API. A pinned .python-version keeps builds reproducible, the Groq key lives in Render's environment settings, and the frontend sends a wake-up ping to the Render service when the page loads, so the free tier's cold start is usually over before the user clicks Generate.
The road here (the part I learned the most from)
QuoteShield started fully local: Mistral 7B on Ollama, on my laptop's CPU. The output was decent, but each scope took 60β90 seconds and nobody else could use it.
So I moved inference to an open-weight model on Groq, and a lot broke along the way:
- Render picked Python 3.14, which had no prebuilt
pydantic-corewheel, so the build tried to compile Rust and failed. Pinning Python 3.11 fixed it. - CORS preflight requests got
400until the middleware was set up correctly. - The Groq SDK clashed with the installed
httpxversion (unexpected keyword argument 'proxies'), so I dropped the SDK and call the API directly. - The first model I switched to had already been decommissioned, and so had the second one.
That last one is why the fallback chain exists. A product that depends on one hosted model ID can break without notice, so the code now expects models to come and go.
Why Does Open Innovation Matter?
No lock-in. I've had a model retired out from under me twice while building this project. Because QuoteShield runs on open-weight models, a retirement is a config change. If a provider drops a model or changes its pricing, I can point at another host or run the same weights myself. With a closed model, the provider's decision would end the product.
I can go back to running it myself. The first version ran on Mistral 7B entirely on my laptop. A freelancer who doesn't want client briefs leaving their machine can do the same thing, because open weights make that possible.
The costs work for a small product. gpt-oss-20b costs fractions of a cent per scope. That means I could offer a free tier and still charge a cheap subscription without losing money on every request, which is what a side project needs.
The weights are inspectable. With open weights you can fine-tune on your own past proposals so scopes match how you quote. That's the next step for QuoteShield.
Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.