Live: https://kairos-592105719190.us-central1.run.app
Multi-agent pipeline: evidence agent (retrieval) -> arbitration agent (reconciles agreement/disagreement) -> workplace agent (drafts an accommodation note from logged history) -> trend endpoint (BigQuery-backed).
All seven hormonal life stages are live: PMS/PMDD, PCOS, fertility, pregnancy, postpartum, menopause, and post-menopause. Puberty was deliberately excluded -- out of scope for the working-professionals audience this is built for. Adding a stage means one new corpus file + one registry line, no changes to the agents themselves -- that's what this build proves, across all seven stages rather than just one or two.
Real Gemini, real Firestore, and real BigQuery are all live and verified end-to-end, both locally and on the deployed Cloud Run service. The project also runs in a fully mocked mode with zero GCP setup, which is how it was built and tested before credentials existed -- see "Local development" below.
curl -X POST https://kairos-592105719190.us-central1.run.app/ask \
-H "Content-Type: application/json" \
-d '{"question": "is HRT safe for hot flashes?", "life_stage": "menopause", "user_id": "demo-user"}'Or just open the URL above in a browser for the actual frontend -- life-stage selector, question box, agreement/disagreement display, workplace-note and trends panels.
- Evidence agent (
app/agents/evidence_agent.py) -- retrieves the most relevant entries from a curated, life-stage-specific corpus via keyword matching - Arbitration agent (
app/agents/arbitration_agent.py) -- reasons about agreement, disagreement, and recency across retrieved sources; returns a structured (Pydantic-validated) answer - Workplace agent (
app/agents/workplace_agent.py) -- turns a user's recent logged questions into a short, professional accommodation note, deliberately instructed never to list specific symptoms
Corpora live in app/corpus/ (pms_pmdd.py, pcos.py, fertility.py,
pregnancy.py, postpartum.py, menopause.py, post_menopause.py),
each with 8 entries including at least one deliberate old-vs-new or
myth-vs-fact conflict pair. app/corpus/__init__.py is the registry
mapping life_stage to its corpus -- the only place a new stage needs
to be wired in.
- Gemini API (
gemini-3.6-flash) for evidence and arbitration reasoning - FastAPI + Pydantic for the backend and structured agent I/O
- Firestore for operational symptom-log storage
(
app/storage/firestore_client.py) - BigQuery for trend analysis over logged entries, written via a
direct dual-write from the API layer (
app/storage/bigquery_client.py) - Cloud Run for deployment -- one containerized service serving both the API and the frontend
- Vanilla HTML/CSS/JS frontend (
static/index.html), served as a static file from the same FastAPI app -- no separate frontend hosting needed
Everything also runs fully mocked with zero GCP setup -- useful for quick local changes without touching real cloud resources:
- No
GEMINI_API_KEY-> Gemini calls return a deterministic stub - No
GOOGLE_CLOUD_PROJECT-> Firestore/BigQuery fall back to a local JSON file atdata/symptom_log.json
python3.11 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
uvicorn main:app --reloadTo run against the real backend locally instead:
export GEMINI_API_KEY="your-key-here"
export GOOGLE_CLOUD_PROJECT="your-project-id"
gcloud auth application-default login
python3 -m uvicorn main:app --reload --port 8002This requires a Firestore database (Native mode, Standard edition) and
a BigQuery dataset symptom_log with a table entries (schema:
user_id STRING, life_stage STRING, question STRING, confidence
STRING, timestamp TIMESTAMP) already created in your GCP project.
No local Docker install needed -- Cloud Run builds the container from
the included Dockerfile via Cloud Build.
gcloud run deploy kairos \
--source . \
--region us-central1 \
--allow-unauthenticated \
--set-env-vars GEMINI_API_KEY="your-key-here",GOOGLE_CLOUD_PROJECT="your-project-id"Re-running the same command redeploys a new revision of the same service at the same URL -- it does not create a second deployment.
If the Cloud Build step fails with a permissions error touching the default compute service account, grant it the builder role once per project:
gcloud projects add-iam-policy-binding your-project-id \
--member="serviceAccount:PROJECT_NUMBER-compute@developer.gserviceaccount.com" \
--role="roles/cloudbuild.builds.builder"- Pydantic schemas incl.
life_stage(7 stages), symptom log, workplace note, trends (app/schemas.py) - Seven curated corpora with deliberate old-vs-new conflict pairs
(
app/corpus/) - Corpus registry (
app/corpus/__init__.py) - Evidence, arbitration, and workplace agents (
app/agents/) - Real Gemini API integration (
gemini-3.6-flash) - Real Firestore-backed symptom logging
- Real BigQuery-backed trend analysis (dual-write from the API layer)
-
/ask,/workplace-note,/trends/{user_id},/healthendpoints - Frontend served at
/(static/index.html) - Dockerfile + live Cloud Run deployment
- Verified end-to-end over real HTTP, all 7 life stages, both locally and on the deployed URL, against real Gemini/Firestore/BigQuery
- Replace keyword-matching retrieval with embedding-based search (Vertex AI Vector Search) as the corpus grows
- Real clinical review of corpus content, with proper citations -- current entries are placeholder paraphrases written to prove the pipeline's reasoning works, not a reviewed clinical corpus
- An eighth life-stage module to further stress-test the config-only-extension architecture
- Firestore-to-BigQuery streaming export as a production replacement for the current direct dual-write
- Corpus entries are placeholder paraphrases for pipeline-testing. Replace with genuinely reviewed summaries and cite real sources before any real-world use.
- The arbitration agent's prompt explicitly forbids diagnosis -- keep
that instruction if you edit it (
app/agents/arbitration_agent.py). - The workplace agent's prompt explicitly forbids listing specific
symptoms in the note -- same caution applies if you edit it
(
app/agents/workplace_agent.py).