← Work

Employment — built within the current role · December 2025

AI ProposalGenerator

Reads your winning documents and drafts what you need next — a bid, a report, a summary.

ROLE  Sole developer of concept and applicationSTATUS  Delivered — late 2025FOR  a humanitarian organization
  • NestJS (TypeScript)
  • Vertex AI — Gemini 2.0 Flash
  • Context caching
  • Google Cloud Storage
  • Prisma + SQLite
  • Docker
  • Tailwind CSS
archive cached server-side once — not re-sent per querycache 1h TTL, refresh on demandRFP input: PDF · scan · text

An organization's strongest asset when bidding for grants is every proposal it has ever won — and nobody rereads them. This tool loads that entire archive into the model's context, so every new RFP is assessed and drafted against the organization's actual track record instead of a blank page.

For hiring managers

This is a working LLM product, one of the AI-integrated systems built at this organization.

  1. The knowledge base — an archive of past winning proposal PDFs in a Google Cloud Storage bucket is loaded into a Vertex AI context cache (Gemini 2.0 Flash) on startup: 1-hour TTL, refreshed on demand, with graceful fallback to uncached generation if the cache can't be built.
  2. Scoped corpora — GCS folder prefixes act as switchable knowledge bases; the operator picks which slice of the archive the model reasons over.
  3. Two operations — a compatibility check ("list matching past proposals and rate the uniqueness of this new request") and proposal generation ("using the style and format of the cached archive, draft a new proposal"). Both prompts live in SQLite via Prisma and are editable in the UI — the operator tunes behaviour without a redeploy.
  4. Multi-modal input — the RFP arrives as a PDF, a scanned image, or pasted text. In a region where tender documents are routinely scans, that matters.
  5. Handover-shape — dockerized with seeded startup, a complete README, and automatic text-direction handling (dir="auto") for mixed Arabic/English content.

It deliberately isn't RAG. The fashionable architecture in 2025 was a retrieval pipeline — chunking, embeddings, a vector store, tuned similarity thresholds. At this corpus size, that machinery has no payoff. Context caching keeps whole documents intact: style, structure, and the eligibility clauses buried in appendices stay in view. There is nothing to chunk, embed, or tune, and cached input tokens bill at a reduced rate.

For clients

Winning grant and tender work is how the organization funds its programmes, and the bottleneck is human attention. The compatibility check answers "have we done something like this before, and how unusual is this request?" before anyone commits days of drafting. The generator then produces a first draft grounded in the organization's own winning style rather than the model's generic idea of a proposal. A person decides what to submit; the tool just gets a first draft onto the page.

The hard problem

Matching the architecture to the corpus

The default assumption in 2025 was that grounding a model in documents means RAG. But a retrieval pipeline has real costs: a chunking strategy to design, embeddings to maintain, thresholds to tune — and chunking severs exactly what matters in proposals, where the winning style is a whole-document property and the clause that disqualifies a bid hides in an appendix. Context caching inverts the trade: the entire archive stays intact and visible to every query, at the price of a hard ceiling — the corpus must fit the model's context window, and the cache has a lifecycle to manage (TTL, refresh on archive change, a 1024-token minimum, and a fallback path when creation fails).

The second hard problem is trust. A fluent draft that misreads a mandatory eligibility criterion is dangerous. Grounding generation in the actual archive makes the output checkable against real past work, and a human makes the submission decision.

Trade-offs

What it cost

DecisionBoughtPaid
Context caching over a RAG pipelineWhole documents intact — style and buried clauses in view; nothing to chunk, embed, or tune; reduced-rate cached tokensCorpus capped by the context window; hourly cache storage cost; an approach that stops scaling where RAG starts
Vertex AI over self-hostedManaged model and caching, no GPU estate to runCloud dependency and per-query cost, in an organization that self-hosts everything else
Prompts as data, editable in UIOperator tunes behaviour without a developerNo versioning beyond a timestamp; a bad edit changes production behaviour instantly
1-hour cache TTL, manual refreshNo invalidation logic to write; refresh is one endpoint callExpiry isn't self-healing — after 60 minutes the cache must be re-initialized manually, a known v1 limitation
Draft, don't submitHuman catches misreadings before they cost a bidThe review remains; only the first draft is automated