Supply-chain disruption intelligence — predicting how a single supplier failure cascades through a dependency network, using a custom Randomized Zero Forcing engine.
If a supplier fails today, how fast does the disruption cascade through the dependency network — and which single failure collapses it fastest? zeroforce answers the propagation question that supplier scorecards don't, using a custom Randomized Zero Forcing (RZF) engine that computes exact Expected Propagation Time (EPT) from every node.
- Math core:
packages/zeroforce/— built first; math-correctness gates CI. - Spec:
.agents/project_specifications.md· Design:ARCHITECTURE.md· Run/deploy:docs/RUNBOOK.md· Security:SECURITY.md· Build log:PROGRESS.md.
- Multi-tier extraction — turns a company/product/sector into a weighted directed dependency graph: tier-0 focal firm → tier-1 suppliers → tier-2 components → tier-3 raw materials, with redundancy and single-source risks made explicit.
- Whiteboard photo → graph — upload a photo of a hand-drawn supply chain; Gemini vision reads the boxes and arrows into a draft graph, you confirm/edit it, then the model researches the named entities to fill in weights, tiers, and citations.
- Exact propagation — the RZF engine computes EPT and an impact score
(
reachable nodes / EPT) for every node, ranks the most dangerous, and separates pure sinks. - Interactive dashboard — tier-laid-out graph (sector emoji per node, a 5-segment energy bar encoding impact percentile, edge labels showing dependency weight), impact-ranked table, executive risk report, citations, and validation notes.
- Cascade animation — select a node → simulate the disruption spreading round by round; nodes glow red by per-round disruption probability, with a play/pause/scrub timeline.
- What-if — change an edge weight (e.g. dual-source a supplier) and see the EPT deltas live in the ranking table; sibling edges rebalance so the graph stays valid.
- Explainer videos — select a node → a ≤10s MP4 with Gemini-written voiceover + captions over a data-driven Manim cascade animation (rendered MP4s persist on disk).
- History — every analysis is saved; a sidebar lists past runs to reopen.
make # installs everything + runs backend (:8080) and frontend (:3000) together
# open http://localhost:3000 — Ctrl-C tears down bothA single make (default target) installs the uv Python workspace, the Gemini SDK
(google-genai), the video toolchain (Manim + ffmpeg/cairo/pango via Homebrew, best-effort),
and the frontend npm deps — then launches both servers in one process group, so one Ctrl-C
kills both. Re-run with make dev to skip reinstalling, or make backend / make web
separately.
Before the first run, pick a mode in .env.local (copy .env.example):
cp .env.example .env.local
# keyless offline demo — no credentials, no network:
# ZEROFORCE_MODE=fake
# real analysis with a Gemini API key (easiest):
# ZEROFORCE_MODE=prod
# GEMINI_API_KEY=AIza... # from https://aistudio.google.com/apikeyOne runtime — Gemini — behind a single env var, ZEROFORCE_MODE:
| Mode | LLM | Web grounding | Storage | Setup |
|---|---|---|---|---|
prod (default) |
Gemini (gemini-3.5-flash) |
built into Gemini (Google Search) | SQLite (or Firestore) + in-proc cache (or Redis) | API key or GCP ADC |
fake |
deterministic | deterministic | SQLite / in-memory | nothing |
fake is an offline, deterministic test double — no keys, no network — used by tests/CI
and for a quick keyless local demo. prod calls Gemini and supports two auth paths (the
app code only depends on a provider protocol, never a vendor SDK directly):
-
Gemini Developer API key (easiest). Set
GEMINI_API_KEY(anAIza…key from AI Studio) in.env.local. Used if present. -
GCP Vertex AI via ADC. Leave
GEMINI_API_KEYunset and authenticate once:make adc # = gcloud auth application-default loginProject is auto-detected (
GCP_PROJECT→GOOGLE_CLOUD_PROJECT→gclouddefault → ADC); region defaults tous-central1; the project needs the Vertex AI API enabled.
Model override: GEMINI_MODEL (default gemini-3.5-flash). If a call 404s, that model isn't
enabled for your key/project — try gemini-2.5-flash.
All env vars (see .env.example); all optional except the mode/auth above.
| Var | Default | Purpose |
|---|---|---|
ZEROFORCE_MODE |
prod |
prod (Gemini) or fake (offline) |
GEMINI_API_KEY / GOOGLE_API_KEY |
— | Developer API key; selects key-auth over ADC |
GCP_PROJECT / GCP_REGION |
auto / us-central1 |
Vertex project + region (ADC path) |
GEMINI_MODEL |
gemini-3.5-flash |
model id override |
ZEROFORCE_DB |
./data/zeroforce.db |
SQLite path (:memory: for ephemeral) |
ZEROFORCE_API_TOKEN |
— | optional single bearer token; unset = open auth |
ZEROFORCE_CORS_ORIGINS |
* (fake) / locked (prod) |
comma-separated allowed origins |
ZEROFORCE_RATE_LIMIT_PER_MINUTE |
30 (prod) / off (fake) |
per-client cap on cost-heavy endpoints |
ZEROFORCE_MEDIA_DIR |
./data/media |
where rendered MP4s/WAVs are written |
GEMINI_TTS_MODEL / GEMINI_TTS_VOICE |
gemini-2.5-flash-preview-tts / Kore |
video voiceover |
Base path /api/v1. Cost-heavy endpoints (analyze, simulate, whatif, upload,
vision, video) are rate-limited in prod.
| Method | Endpoint | Purpose |
|---|---|---|
| POST | /analyze |
start an analysis (async → {id,status,poll}; sync 200 when wait=true && max_nodes≤10) |
| GET | /analyses/{id} |
poll a job: pending | running | done | failed |
| GET | /analyses |
history of saved analyses |
| POST | /vision |
whiteboard photo (multipart) → DraftGraph (boxes + arrows) |
| POST | /upload |
PDF upload (PII-redacted) → extracted text |
| POST | /simulate |
Monte-Carlo cascade from one or more starting nodes |
| POST | /whatif |
apply edge-weight edits → baseline/modified EPT + deltas |
| GET | /sectors |
BEA 15-sector example bundle |
| POST | /video |
start a node explainer render (async → {id,status,poll}) |
| GET | /video/{id} |
poll a render job |
| GET | /video/{id}/file |
the rendered MP4 (served from disk; survives restarts) |
| GET | /health · /version |
liveness + build/mode/model info |
/analyze accepts an optional seed_graph (a confirmed DraftGraph from /vision), which
drives a seed-aware extraction instead of inventing the topology.
Three layers (full design in ARCHITECTURE.md):
- Extraction — Gemini two-pass: ground (Google Search) → structure (typed schema). A
deterministic
fakeprovider mirrors the contract offline. - Computation — the RZF engine computes exact EPT per node via Markov-chain DP over bitmask states, on the subgraph reachable from each seed. Built first; math gates CI.
- Presentation — Next.js 14 dashboard: graph, ranking, cascade animation, what-if, report, video.
Backend = six logical services (gateway, extractor, validator, engine, reporter,
orchestrator), each a pure-logic core.py + a thin FastAPI app, wired through a
ServiceClient abstraction (in-process by default; HTTP for docker-compose / Cloud Run).
make test # uv run pytest -q + frontend vitest
uv run pytest -q # Python suite: engine oracles + backend + parity (~123 tests)The engine's gating oracles — hand-computed graph, Monte Carlo differential, and
pure-Python↔numba parity — trust the source paper zero. The §4.6 closed-form formulas are
kept xfail until verified against the paper body; see ARCHITECTURE.md for
why that discipline is the project's most important safety mechanism.
packages/zeroforce RZF engine (built first; gating oracle suite)
packages/schemas shared Pydantic API models
packages/providers LLM/vision/TTS abstraction (fake + gemini) + factory
services/backend 6 service cores + FastAPI apps + orchestrator + storage + observability + ratelimit
apps/web Next.js 14 dashboard
infra/ Dockerfiles, docker-compose.dev, Terraform (Cloud Run, Firestore, …)
data/ BEA 15-sector bundle; rendered media under data/media
Engine → backend pipeline → infra-as-code → interactive frontend → security/correctness
hardening, plus whiteboard-photo vision, explainer videos, and live what-if. prod runs
against Gemini via API key or Vertex/ADC. Cloud deployment is written as Terraform/Docker but
not applied. See PROGRESS.md.
- Ardihant Kaul
- Ali Malik
- Justin Lee
- Yingjie Zhao