Upload any construction dataset and get instant, explainable predictions of project risk — schedule duration, delay likelihood, and the factors driving each outcome. Groundwork maps unfamiliar columns automatically, trains a model on the spot, and turns the results into plain-English reports through Claude.
Why this exists. Construction data lives in silos — schedules in one system, costs in another, permits in a third — and most tools require a fixed schema. Groundwork ingests any construction CSV, figures out what the columns mean, and produces usable risk intelligence without a data-science team in the loop.
- Schema-agnostic ingestion. Drop in a CSV with unknown columns. Claude reads the headers and a sample of rows and maps each column to a role (target, numeric feature, categorical feature, date, or drop).
- Automatic target resolution. If no numeric outcome exists, Groundwork derives one
— e.g. permit duration from
issuance_date − filing_date— instead of failing. - On-the-fly modelling. A Random Forest regressor trains on the uploaded data and reports MAE and R² on a held-out split.
- Explainability. SHAP values decompose every prediction; Claude translates them into a readable narrative ("borough workload is the biggest driver, adding ~4 days").
- Cold-start comparison. Each prediction is shown against a no-history baseline, so users can see how much the historical signal actually helps.
- Risk analytics. Group-level deviation-from-average views highlight which categories run slower or faster than the norm, with weak/meaningful-driver flags.
- Conversational analysis. A data-aware chat answers questions grounded in the uploaded dataset.
Groundwork is a full-stack application with a clean frontend/backend separation — the Python ML logic is served through an API rather than embedded in the UI.
┌─────────────────────┐ HTTP/JSON ┌─────────────────────┐
│ React (Vite) │ ───────────────► │ FastAPI backend │
│ frontend │ ◄─────────────── │ (Python) │
│ · upload & forms │ │ · column mapping │
│ · charts / SHAP │ │ · model training │
│ · risk analytics │ │ · SHAP + reports │
└─────────────────────┘ └──────────┬──────────┘
│
┌──────────────────┴──────────────────┐
│ Random Forest + SHAP │ Claude │
│ (scikit-learn) │ API │
└─────────────────────────┴────────────┘
Backend endpoints
| Method | Route | Purpose |
|---|---|---|
GET |
/ |
Health check |
POST |
/upload |
Parse CSV → Claude maps columns → train model → return stats |
POST |
/predict |
Run prediction + SHAP + Claude risk report for given inputs |
POST |
/chat |
Answer questions grounded in the loaded dataset |
Frontend — React 18, Vite, plain CSS design system (light/dark themes), Lucide icons Backend — FastAPI, Uvicorn ML — scikit-learn (Random Forest), SHAP for explainability, pandas / NumPy AI — Anthropic Claude (Sonnet) for column mapping, SHAP interpretation, and reports
Two processes: a Python backend and a React frontend.
- Python 3.12 with the packages in
backend/requirements.txt - Node.js 18+ and npm
- An Anthropic API key (entered in the app at runtime — never stored)
cd backend
pip install -r requirements.txt
python -m uvicorn main:app --reload --port 8000The API runs at http://localhost:8000.
Note on dependencies. SHAP is pinned to
0.46.0and NumPy to<2.0; newer SHAP requires NumPy 2.x, which conflicts with the pandas/pyarrow build in many environments. Installing fromrequirements.txthandles this.
cd frontend
npm install
npm run devThe app runs at http://localhost:5173.
- Enter your Anthropic API key via the header badge.
- Upload a construction CSV (NYC / Chicago permits, project logs, contractor records…).
- Review the mapped columns, run a prediction, and explore the risk analytics.
A few decisions worth calling out, since they reflect how the app handles real, messy data rather than a clean demo set:
- Robust type coercion. Columns an LLM labels "numeric" often contain codes like
96-15. Each is validated; columns that don't convert are rerouted to categorical or dropped, so a single dirty column can't crash training. - Target leakage guard. When the target is derived from two dates, features built from the end date are removed — otherwise the model would "cheat" and report a meaningless near-perfect score.
- Identifier filtering. Grouping columns that are near-unique per row (addresses, BINs) are excluded from analytics, since averaging by an ID conveys nothing.
- Keys never touch the codebase. The API key is supplied at runtime and passed per-request to the local backend; it is never written to disk or committed. This keeps the repository safe to make public.
- User-selectable prediction target (choose the outcome, or a derived duration)
- Sample dataset / demo mode for evaluation without an API key
- Geospatial risk view for datasets with coordinates
- Deployment (backend → Render/Railway, frontend → Vercel/Netlify)
Groundwork began as an investigation into the cold-start problem in construction analytics: new projects have no history, so early risk prediction is hard. The app demonstrates one practical answer — borrow signal from similar historical projects, map heterogeneous data automatically, and keep every prediction explainable.