Docs, parameters,
references.
Everything you need to reason about what EpiChat will and won't do: the architecture, the workflow and its tools, the parameters, networks and interventions, the diagnostics, the data sources, and the roadmap.
Architecture
EpiChat is a web app with a conversational agent and a private simulation service. The model handles language; tools write the configuration, apply the data and run the simulation, so a fetched number or a literature estimate is never retyped by the model.
Browser ──SSE──▶ web app (Next.js on Vercel)
│ agent loop: Claude (Opus 5.5 by default) · nine tools · web search and fetch
│ Supabase: sign-in · consent · conversations · runs · events · feedback
│ public data: UN Population Data Portal · WHO GHO · World Bank Data360
▼
sim service (FastAPI · Python 3.12 · private, reached only by the web app)
│ validate (schema v2) → build the Starsim 3.7.2 model → run in a child process
│ up to 5 replicates · up to 2 repairs · diagnostics · Word and PDF export
▼
series · statistics · diagnostics → cards, charts and "Try next" replies
The web agent replaced the v0.3 template pipeline for the pilot. The Python package, its command-line interface and the Streamlit prototype remain in the repository.
Workflow
A conversation moves through six stages, shown under the chat as a step strip. The stage follows from the tools that ran, not from the model's say-so; the model writes only the suggested replies.
| Stage | What happens | Tools |
|---|---|---|
| Understand | The disease, the place and the question; the database's cited parameters; a question back when something is missing | lookup_disease · web search and fetch |
| Configure | A validated configuration; β calibrated to the R₀ | configure_simulation · describe_parameters |
| Ground in data | The country's ages, births and deaths, contact matrix, household size, vaccination coverage and hospital capacity | fetch_demographics · fetch_vaccination_coverage · fetch_health_system |
| Run | Starsim on the private service, one to five replicates | run_simulation |
| Interpret | The run's diagnostics; fixes and interventions as suggested replies; what changed since the previous run | diagnostics |
| Report | A report built from the stored runs; a link to share | write_report |
Agent tools
Nine tools, plus the model provider's web search and web fetch. Each result appears in the conversation as a card.
| Tool | What it does |
|---|---|
| lookup_disease | Reads a disease's cited parameters, each with a status: a usable consensus, estimates without an agreed value, held back under review, or nothing yet. |
| configure_simulation | Creates or edits the configuration, passing only what changed: the model, the R₀ (β is calibrated to it), durations, fatality, seeding, interventions, a fit, a chosen reference, and any other parameter by its registry path. Everything is validated at once; an error names the parameter. |
| describe_parameters | Lists every parameter of the current model and network with its value, bounds, unit, source and literature range. |
| fetch_demographics | UN World Population Prospects for a country: the age pyramid (switching to the age-structured network), birth and death rates, the population for scaling, the contact matrix and the household size. The R₀ is held where it was when the new network can carry it. |
| fetch_vaccination_coverage | WHO routine coverage for a disease and country, applied as immunity at the start, or as a day-0 campaign when the database has the vaccine's efficacy. |
| fetch_health_system | World Bank hospital beds, physicians, nurses and UHC coverage; sets a treatment's daily capacity from the beds. |
| run_simulation | Runs the configuration and returns the series, the statistics (scaled to the real population when demographics were fetched) and the diagnostics. |
| write_report | Writes the report's summary, meaning, limitations and next steps; its tables and figures come from the stored results. |
| remember | Keeps a one-line note about the participant (a role, a situation, a preference) for later conversations. |
Disease models
Six compartmental models, chosen from the disease or named directly.
| Model | Compartments | Use case | Model-specific parameters |
|---|---|---|---|
| SIR | S → I → R | Acute infection, lasting immunity | — |
| SEIR | S → E → I → R | A latent period (measles, mumps) | latent period · presymptomatic transmissibility |
| SIS | S → I → S | No lasting immunity (gonorrhea) | immunity boost and waning after an infection (sis_imm_boost, sis_waning; 0 by default) |
| SIRS | S → I → R → S | Waning immunity | immunity duration |
| SEIRS | S → E → I → R → S | Latent period and waning | latent period · presymptomatic transmissibility · immunity duration |
| SEIAR | S → E → I|A → R | Asymptomatic transmission | latent period · presymptomatic transmissibility · asymptomatic share (0.3) · their transmissibility (0.5) |
All six take an infectious period (a mean with a distribution and its spread; a new scenario's periods are gamma with an illustrative spread), susceptibility by age and personal variation in susceptibility. All but SIS take a case fatality ratio, overall or by age group.
Disease database
A literature-backed database (epichat/data/disease_parameters.json)
covers 16 diseases. For each parameter it keeps a consensus value with
its range and the individual published estimates, each with its title,
year and link. The agent reads a status with every value and is told
never to quote a number the database holds back. In the app's Data
section every single-number estimate has a "Use this value" button; the
tool then reads the value and its citation from the reference data, so
neither can be mistyped, and the value carries the paper's title for as
long as it stands.
| Disease | R₀ | Incubation (days) | Infectious (days) | Fatality |
|---|---|---|---|---|
| Cholera | 2.1 0.8–7.3 | 2 0.5–5 | 5 1–10 | — |
| COVID-19 | 9.5 5.5–24 | 5.8 5–6.7 | 8 6–10 | 0.9% 0.7–1.16% |
| Dengue | 4.74 1–103 | 6 3–14 | 4 2–5 | — |
| Ebola | 1.95 1.34–2.53 | estimates only | 7 4–10 | 50% 25–90% |
| Hepatitis A | 2.5 1.71–5.6 | 28 14–50 | 21 7–28 | 0.4% 0.3–0.5% |
| Influenza | 1.28 1.19–1.37 | 2 1–4 | 7 6–8 | under review |
| Measles | 15 12–18 | 12 7–21 | 8 | 1.5% 0.5–6% |
| Meningococcal | ≥ 1.03 | 3.5 1–10 | under review | 12% 6–15% |
| Mpox | 2.52 1.37–3.677 | 10 3–17 | 21 1–28 | — |
| Mumps | 10 4–19.3 | 17 12–25 | 7 | 0.027% 0.016–0.038% |
| Pertussis | 14.5 5.3–17 | 8.5 4–21 | 21 21–35 | 0.8% 0.67–0.8% |
| Polio | 6 5–7 | 8 4–35 | 6 2–10 | — |
| RSV | 3 1.2–9 | 5 2–8 | 6 3–28 | — |
| Rubella | 5.5 2–8 | 17 12–23 | 14 11–16 | 0.005% |
| Tuberculosis | 2.1 0.24–4.3 | 180 14–730 | 14 14–365 | — |
| Varicella | 8 5.5–10 | 15 14–16 | 6.5 6–7 | 0.0028% 0.002–0.0036% |
The typical value, then the consensus range in grey. "Under review": held back until a reviewer checks it. "Estimates only": cited estimates without an agreed value. A dash: not in the database yet. The fields the database still lacks are listed in the review list; until they have cited values, the intervention effects (school closure, distancing, masks, a behaviour response) and the variation in susceptibility are illustrative assumptions, and the app labels them so.
Parameters
One registry (epichat/params/registry.py) describes every
parameter once: its path, label, unit, bounds, default, the models and
networks it applies to, and the database field it comes from. The
schema that validates a run and the web app's schema both read it, and
the app's Parameters section is generated from it. A tag after each
value says where it came from: the database, fetched data, a default,
an illustrative assumption, set in chat, set by the run, or a chosen
reference.
| Parameter | Default | Range | Meaning |
|---|---|---|---|
| disease.model | sir | six models | Chosen from the disease |
| disease.beta | calibrated | 0.001–1,000 per year | Transmission rate, set from the R₀ you give |
| disease.dur_inf | 10 days, gamma | 0.5–365 days | Infectious period: a mean, a distribution and a spread; the agent's scenarios use gamma with an illustrative spread, from the database's range when it has one |
| disease.dur_exp | — | 0.1–1,000 days | Latent period (SEIR, SEIRS, SEIAR) |
| disease.dur_immune | — | 7–36,500 days | Immunity duration (SIRS, SEIRS) |
| disease.p_death | 0 | 0–1 | Case fatality ratio |
| disease.seed | 0.05% of agents | a share, or a number of agents | Initial infections. A share is a draw per agent: five of 10,000 on average, so below 10,000 agents the agent seeds a number instead |
| disease.initial_immune_frac | 0 | 0–0.99 | Share immune at the start |
| disease.rel_sus_cv | 0 | 0–2 | Variation in susceptibility between people |
| network.network_type | random | random · age_structured · hybrid | Who meets whom |
| network.n_contacts | 4 per day | 1–100 | Contacts per day on the random network |
| demographics.use_demographics | off | on · off | Births and deaths; on once a country's rates are fetched |
| run.n_agents | 10,000 | 10–1,000,000 | Simulated people; results scale to the real population |
| run.sim_dur_years | 1 year | 0.01–20 years | Duration |
| run.n_replicates | 1 | 1–5 | Runs with different seeds; the median run with a 10–90% band |
| run.rand_seed | 1 | any integer | Seed of the first replicate, for reproducibility |
The registry holds many more, by tier (core, advanced, expert): the contact matrix, the hybrid layers' sizes and transmissibilities, susceptibility and fatality by age group, presymptomatic transmissibility, every intervention field. Ask the agent "what can I change?" to list them for your scenario.
Networks
Random
Fresh contacts every day, a constant number or Poisson-distributed, optionally lasting several days. The R₀ formula is exact when contacts do not last.
Age-structured
Three age groups (under 18, 18 to 64, 65 and over) mixing by a 3×3 contact matrix: POLYMOD's European defaults, or the country's Prem et al. 2021 matrix once its demographics are fetched (177 countries). The R₀ formula is exact. The measured R₀ is not available on this network, because Starsim's mixing pools do not record who infected whom.
Hybrid: households, schools, workplaces and community
Four layers as in Covasim, with the country's mean household size (UN, 189 countries) and the layers' sizes and transmissibilities as parameters. The R₀ formula is approximate here, so a short pilot run, in which only the seeds transmit, measures it and adjusts β.
At the same R₀ the final size is close on every network: the networks differ in who meets whom and in what the interventions act on.
Interventions
Six types, combined freely, named in the configuration vaccine, treatment, seasonality, contact_reduction, transmission_reduction and behavior_response. Every effect size is an illustrative assumption unless the database carries it, and the app labels it so.
Vaccine
Routine (a yearly probability for each eligible person) or a campaign (the coverage reached evenly over a window), with an efficacy, leaky or all-or-nothing protection, an age range and a protection duration. Coverage fetched from WHO becomes immunity at the start, or a day-0 campaign when the database has the vaccine's efficacy.
Treatment
A share of infectious people treated each day, after a delay, with an efficacy and an optional daily capacity, which the health-system data sets from the country's hospital beds. In SEIAR it can treat symptomatic cases only.
Seasonality
A yearly cycle in transmission: scale is its size (0.2 moves transmission between 80% and 120% of β) and shift moves the peak through the year.
Contact reduction
One layer's contacts scaled over a window. A school closure is the school layer of the hybrid network at scale 1; distancing scales every layer. The random and age-structured networks take every layer only.
Transmission reduction
Every contact's transmissibility scaled over a window, such as masks.
Behaviour response
Transmission falls as the share of people infectious rises, averaged over the last week by default, and recovers as it falls: people being careful, not a measure. It flattens the peak, but because it relaxes it cannot keep the total far below the herd immunity threshold in a long run.
Fit · limits on spread
A run can be fitted to one outcome you know: the attack rate, the peak day or the peak size. The service searches the transmission rate (or the network multiplier) in at most eight runs and reports what it reached. To match a known attack rate while the R₀ stays where it was set, the fit can move the variation in susceptibility or the behaviour response instead.
Without an intervention an epidemic reaches the share the final-size equation gives for its R₀, on every network (89% at R₀ 2.5): only the depletion of susceptibles stops it. Two mechanisms limit spread without a dated measure, both off by default and both named by the agent as assumptions when it offers them: variation in susceptibility (the most susceptible are infected first, so at a coefficient of variation of 1 the epidemic ends near 60%) and the behaviour response.
Diagnostics
After every run the service reads the full series and returns diagnostics, each with levers: a set of parameter values, kept within the registry's bounds and the literature range, or intervention entries. The agent offers at most three as suggested replies, a warning's fixes before any intervention, applies the one you choose, reruns, and says what changed.
| Diagnostic | Fires when |
|---|---|
| early_fadeout | The seeding infected nobody, or the outbreak died out early: fewer infections than twice the seeds, or under 1% of the agents when nothing held transmission down from day 0 |
| instant_peak | The peak is the seeding itself |
| unfinished | The run ended before the epidemic did |
| cfr_out_of_range | The case fatality ratio is outside the literature range |
| final_size_gap | The attack rate does not match the configured R₀ |
| sharp_curve | Every period is the same for everyone, which sharpens the curve |
| fatality_on_all_infections | The fatality ratio applies to every infection, asymptomatic ones included |
| no_reinfection | Immunity outlasts the run, so waning cannot be seen |
| high_variance | The replicates disagree widely |
| well_mixed | Nearly everyone was infected; it offers the two limits on spread |
| r0_gap | The measured R₀ is far from the configured one |
| what_if | The run had an epidemic: up to four interventions to try (a vaccination campaign, a school closure, distancing, masks, a behaviour response), each starting the day 1% of the agents had been infected, leaving out what the scenario already has |
Outputs
- Charts. Four views of every run: compartments, new infections, cumulative infections and deaths. With replicates, the median run and a 10–90% band.
- The details panel. Scenario, Data (the fetched values with citations and the literature reference list), Parameters (every value with its source), Runs, Report, Activity and Profile.
- Reports. The agent's summary, meaning, limitations and next steps; tables and figures from the stored runs; every data source. Download as Word, PDF, HTML or Markdown.
- Share links. A read-only copy of the conversation at that moment, without your email.
- Memory. One-line notes about you (a role, a situation, a preference) that carry into later conversations; you can see and edit them in your profile.
- Feedback. A thumbs up or down on any reply.
Data sources
Public sources receive only a country code.
| Source | Fetched or bundled | Provides |
|---|---|---|
| UN World Population Prospects 2024 | Fetched (UN Population Data Portal) | Birth and death rates, total population, age shares |
| WHO Global Health Observatory | Fetched | Routine vaccination coverage |
| World Bank Data360 | Fetched | Hospital beds, physicians, nurses, UHC coverage index |
| Disease parameter database | Bundled | Cited parameters for 16 diseases |
| UN WPP 2024 population by single year of age | Bundled | The agents' ages: 237 countries and areas, 2024 and 2030 |
| UN WPP 2024 projected birth rates | Bundled | Birth rates after a multi-year run's first year, 2020–2050 |
| Prem et al. 2021 contact matrices | Bundled | 177 countries, aggregated to three age groups with each country's pyramid |
| UN household size | Bundled | Mean household size, 189 countries |
Privacy · the study
During the pilot EpiChat is open to study participants with an Emory email address, who sign in with an emailed code. Using it is taking part in the study: at first sign-in a consent screen says what is recorded, among other things your email address and the kind of participant you are, your conversations, the agent's summarized reasoning, how you use the app, your browser and device type, your profile answers and what the agent remembers about you, and how often a link you share is opened, and it asks you to agree. Your messages go to Anthropic's Claude API to produce replies; simulation settings go to the project's own simulation service. The data is kept for the duration of the study on servers in the United States, and deleting a conversation hides it from you but keeps it for the study. Each participant has a daily turn limit, and the project has a monthly spending cap.
Query tips
The agent understands a wide range of phrasing. A few useful patterns:
| You say | EpiChat does |
|---|---|
| "Model a measles outbreak in Kenya" | Looks measles up, configures it, and offers to fetch Kenya's demographics and vaccination coverage |
| "R₀ of 2.5" | Calibrates β to it; exact on the random and age-structured networks |
| "80% are vaccinated" | Immunity at the start for 80% |
| "a vaccination campaign in the third month" | A vaccine campaign over a window |
| "close schools for a month" | A contact reduction on the school layer of the hybrid network |
| "everyone wears masks" | A transmission reduction, its size labelled as an assumption |
| "people get careful as cases rise" | A behaviour response |
| "we saw about 30% infected" | A fit to that attack rate |
| "run it five times" | Five replicates with a 10–90% band |
| "what can I change?" | describe_parameters: every parameter with its value, bounds and source |
| The "Use this value" button on an estimate | That estimate applied with its citation |
| "write a report" | write_report, then a download |
| A question in Spanish, French, Chinese… | Replies in that language; buttons stay in English |
| "what is the latest on mpox in Kinshasa?" | A web search before it configures anything |
Roadmap
The data roadmap, in priority order, and where each phase stands. Impact is how much it moves the scientific needle.
| # | Phase | Data · notes | Status | Impact |
|---|---|---|---|---|
| 1 | Country demographics | UN WPP 2024 · World Bank | Done | High |
| 2 | Country contact matrices | Prem et al. 2021 (177 countries) | Done | High |
| 3 | Households, schools and workplaces | UN household size (189 countries) · the hybrid network | Done | Medium |
| 4 | Age-specific severity | Fatality by age is a parameter; cited values are in literature review | In progress | High |
| 5 | Calibration against surveillance data | A run fits one known outcome today; fitting a reported case series is next | In progress | Very High |
| 6 | STI and multi-route transmission | DHS sexual module · NATSAL · CDC NHBS | Later | Medium |
| 7 | Geospatial metapopulation | WorldPop · OAG · OSM | Later | High |
Beside the data roadmap: cited effect sizes for the interventions, testing and isolation as interventions, a benchmark and validation study against expert-coded models, and an open release with a preprint.
Risks · mitigations
| Risk | Mitigation |
|---|---|
| Invalid simulation code | The model never writes code; tools pass structured values through one registry and schema |
| Parameter hallucination | Values come from you, the database, fetched data or a chosen reference, each tagged with its source; out-of-range values are flagged; illustrative assumptions are labelled; held-back values are never quoted |
| Wrong R₀ on a structured network | β calibrated exactly on the random and age-structured networks; on the hybrid network a pilot run measures it and adjusts β |
| Implausible results | Diagnostics on every run, each with suggested fixes |
| Execution failure | Up to two automatic repairs of the configuration, with a visible repair log |
| Runaway runs and cost | A 120-second run limit, a cap of 500,000 agent-years per run, a daily turn limit per participant and a monthly budget |
| API instability | Starsim pinned at 3.7.2; a fixed simulation baseline in the test suite |