Bring your existing model to Chap¶
This guide is for you if you already have a forecasting model in R or Python and want to run it in Chap. You keep your code. The guide has three stages:
- Run the model outside Chap. Split it into a train and a predict script that read and write Chap's data format, and check that they work on example data.
- Make it Chap-compatible. Add a short
MLprojectfile and evaluate the model withchap eval. - Package it as a Docker image, so that it can run next to a Chap installation.
You only need Docker for the last stage.
What you do not need
- No separate chapkit install. Installing Chap also installs chapkit, and
chap evalstarts and stops the chapkit service for you. There is nobrew install chapkit. - No Chap server. You do not need to clone chap-core or run its
docker compose up. That stack runs Chap for the Modeling App, and is not needed to develop or evaluate a model. - No
chapkit mlproject migrateand nomain.py. They turn a model into a chapkit service project with its own service code, which most models do not need.
If you do not have a model yet, see Build a new model from a template instead.
Train and predict scripts are a recommendation, not a requirement
The only strict requirement is that your model exposes the chapkit REST API, which Chap uses to send it data and get forecasts back. The train and predict scripts and the MLproject file in this guide are the easiest way to get there: chapkit reads them and provides the API for you. If you are comfortable writing a web service, you can implement the API yourself instead, in any language. See the chapkit documentation and its API reference.
Before you start¶
Follow Set up your machine. You need chap installed, and R if your model is in R.
The R template and the Python template contain a small model that is already set up the way this guide describes. Keep the one for your language open: you will copy files from it.
1. Run the model outside Chap¶
Split the model into a train and a predict script¶
Chap runs your model as two commands:
- train reads a CSV file with historic data and saves a trained model to a file.
- predict loads the trained model, reads the historic data and a CSV file with climate data for the future periods, and writes the forecasts to a CSV file.
Chap passes the file paths as command-line arguments. The templates show the smallest version of this: train.r and predict.r in R, train.py and predict.py in Python.
The input CSV files have the columns time_period, location and disease_cases, plus the covariates your model uses, such as rainfall, mean_temperature and population. See Chap data format. The future data has the same columns, but no disease_cases.
The predict script writes a CSV file with time_period, location and the forecast in a sample_0 column, one row per location and future period. A model that gives several samples writes sample_1, sample_2 and so on.
Run the scripts on example data¶
Copy the template's input folder, with trainData.csv and futureClimateData.csv, into your model's folder. Then run the scripts. For R:
mkdir -p output
Rscript train.R input/trainData.csv output/model.bin
Rscript predict.R output/model.bin input/trainData.csv input/futureClimateData.csv output/predictions.csv
Open output/predictions.csv and check that it has a sample_0 column.
If R says there is no package called 'xgboost' (or another package), install the package and run again:
For a Python model, install the packages it needs in a virtual environment, and keep that environment active in the terminal for this stage and the next. See Virtual environments if this is new to you.
The templates have an isolated_run script that runs both steps. You can copy it and change the file names to make reruns quicker.
2. Make the model Chap-compatible¶
Write the MLproject file¶
Create a file named MLproject (no file extension) in your model's folder. For an R model:
name: my_model
required_covariates:
- rainfall
- mean_temperature
entry_points:
train:
parameters:
train_data: str
model: str
command: "Rscript train.R {train_data} {model}"
predict:
parameters:
historic_data: str
future_data: str
model: str
out_file: str
command: "Rscript predict.R {model} {historic_data} {future_data} {out_file}"
For a Python model, the commands are python train.py ... and python predict.py ....
nameis a short name for your model, without spaces.required_covariateslists the dataset columns the model reads, besidestime_period,locationanddisease_cases. Chap checks that a dataset has them before it runs the model.commandis what Chap runs. Chap replaces the{...}placeholders with file paths. Use these names, since they are the ones Chap knows:train_data,historic_data,future_data,modelandout_file. Put them in the order your scripts expect.
The file has no line that says how to install the model's packages. For now, the model runs with the R or Python and the packages you already have. You add that line at the end of this stage.
If your MLproject already has a docker_env, conda_env or python_env line, Chap cannot use it to run the model as a chapkit service. Remove the line, or keep it and add --run-config.ignore-environment to the chap eval command below.
Evaluate the model with Chap¶
From your model's folder, run:
chap eval --model-name . --dataset-csv https://raw.githubusercontent.com/dhis2-chap/chap-core/master/example_data/laos_subset.csv --output-file eval.nc --plot --run-config.as-chapkit --run-config.ignore-environment
--model-name .means the model in the current folder.--dataset-csvis the data to evaluate on. The example is monthly data for a few provinces in Laos. You can also use your own data in the Chap data format.--run-config.as-chapkitruns the model the same way a Chap server will run it.--run-config.ignore-environmentruns the scripts with the R or Python and the packages you already have, as in stage 1.
Chap trains and tests the model on several periods of the data (a backtest) and writes the results to eval.nc. --plot writes a plot of the forecasts against the real case counts to eval.html. Open it in a browser.
If something goes wrong¶
- A package is missing: install it as in stage 1 and run
chap evalagain. - A required covariate is missing: the dataset does not have a column your
MLprojectlists underrequired_covariates. Use a dataset that has it, or remove it from the list if the model does not need it. - Running an MLproject with docker_env as a chapkit service is not supported: see the end of Write the MLproject file.
- Something else: add
--run-config.debugto thechap evalcommand to see the output of your scripts.
Record the model's packages¶
To run anywhere other than your machine, the model has to say which packages it needs. Add a line to the MLproject that Chap uses to install them:
- R: record the packages with renv (
renv::init(), thenrenv::snapshot()) and addrenv_env: renv.lock. - Python: list the packages in a
pyproject.tomlwith uv (uv init, thenuv add <package>) and adduv_env: pyproject.toml.
Run chap eval again without --run-config.ignore-environment. Chap now installs the packages itself before it runs the model. The Docker image in the next stage installs them the same way.
3. Package the model as a Docker image¶
To run next to a Chap installation, the model is packaged as a Docker image. You need Docker for this stage.
Let an AI coding agent do the work
AI coding agents, such as Claude Code, Codex or GitHub Copilot, are now good at making an existing model Chap-compatible, both stage 2 and this stage. Open the agent in your model's folder and point it to a model that already works with chapkit, and to the documentation. With an agent, you often do not need to do much by hand. For example:
Make this model Chap-compatible, following https://chap.dhis2.org/chap-modeling-platform/external_models/existing_model/. Use https://github.com/chap-models/mlproject_template_r as the example to copy from: add an
MLprojectfile, record the packages with renv, and add theDockerfile,.dockerignore,compose.ymland GitHub workflows. Then check thatchap eval --run-config.as-chapkitworks on the example data.
Use mlproject_template_python for a Python model. The chapkit documentation, and its MLproject runner guide in particular, are also useful to give the agent. Check what the agent changed, and run chap eval yourself before you publish the model.
Copy these files from the template for your language into your model's folder:
| File | What it does | R | Python |
|---|---|---|---|
Dockerfile |
Builds the image from a chapkit base image that runs the MLproject as a chapkit service, and installs the packages from renv.lock or pyproject.toml |
Dockerfile | Dockerfile |
.dockerignore |
Keeps local files such as your installed packages and output/ out of the image |
.dockerignore | .dockerignore |
compose.yml |
Builds and starts the image with one command | compose.yml | compose.yml |
.github/workflows/ci.yml |
Tests the image on GitHub | ci.yml | ci.yml |
.github/workflows/publish-docker.yml |
Publishes the image on GitHub | publish-docker.yml | publish-docker.yml |
To download them all at once, run this in your model's folder. For R:
mkdir -p .github/workflows && for f in Dockerfile .dockerignore compose.yml .github/workflows/ci.yml .github/workflows/publish-docker.yml; do curl -fsSL -o $f https://raw.githubusercontent.com/chap-models/mlproject_template_r/main/$f; done
For Python, replace mlproject_template_r with mlproject_template_python.
The R Dockerfile expects the renv.lock, .Rprofile and renv/ folder that renv::init() created in stage 2. The Python one expects the pyproject.toml that uv init created.
In compose.yml, you can rename the service from mlproject_template_r or mlproject_template_python to your model's name. Then build the image and start it:
The model is now at http://localhost:9090. In another terminal, check that Chap can use it:
chap eval --model-name http://localhost:9090 --run-config.is-chapkit-model --dataset-csv https://raw.githubusercontent.com/dhis2-chap/chap-core/master/example_data/laos_subset.csv --output-file eval.nc
Publish the image¶
GitHub builds and publishes the image for you every time you push to the main branch. If your model is not on GitHub yet, create a new, empty repository on GitHub and push your folder to it, see Git and GitHub. Then commit the new files and push them:
On GitHub, the Actions tab of your repository shows the workflows building, testing and publishing the image as ghcr.io/<your-user>/<your-repo>:latest. See Publish the image in the template tutorial for what to check there.
Next steps¶
- Run the model from the Chap modeling app, see Running Your Own Model.
- Make parts of the model configurable with
user_options, see Model Configuration Options. - Add author and contact details, see Model Metadata.