diff --git a/.github/workflows/publish-docker.yaml b/.github/workflows/publish-docker.yaml
new file mode 100644
index 0000000..22e6946
--- /dev/null
+++ b/.github/workflows/publish-docker.yaml
@@ -0,0 +1,61 @@
+name: Publish docker on GHCR
+
+on:
+ push:
+ branches: [main]
+ workflow_dispatch:
+ inputs:
+ force_docker_build:
+ description: 'Force Docker build (skip change detection)'
+ required: true
+ type: boolean
+ default: false
+ skip_docker_build:
+ description: 'Skip Docker build (use last built image)'
+ required: true
+ type: boolean
+ default: false
+
+jobs:
+ publish-docker:
+ name: Publish docker
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ packages: write
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Check if Docker build needed
+ id: changes
+ uses: dorny/paths-filter@v3
+ with:
+ filters: |
+ docker:
+ - 'binder/Dockerfile'
+ - 'binder/environment.yml'
+
+ - name: Login to GitHub Container Registry
+ if: >
+ (!inputs.skip_docker_build) &&
+ (inputs.force_docker_build || steps.changes.outputs.docker == 'true')
+ uses: docker/login-action@v3
+ with:
+ registry: ghcr.io
+ username: ${{ github.actor }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Build the Docker image
+ if: >
+ (!inputs.skip_docker_build) &&
+ (inputs.force_docker_build || steps.changes.outputs.docker == 'true')
+ uses: docker/build-push-action@v6
+ with:
+ context: .
+ file: binder/Dockerfile
+ tags: |
+ ghcr.io/pythonhealthdatascience/llm_simpy_models:latest
+ push: true
+
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 927dbc9..fc6c591 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). Dates formatted as YYYY-MM-DD as per [ISO standard](https://www.iso.org/iso-8601-date-and-time-format.html).
+## v1.0.3 - 2025-12-02
+
+Add docker image and hosted on GitHub Container Registry.
+
+### Added
+
+* Add `Dockerfile` which builds conda environment and runs the app.
+* Add GitHub action which builds Docker image and pushes to GitHub Container Registry.
+
+### Changed
+
+* Explained how to use Docker (and venv) in README.
+
## v1.0.2 - 2025-03-25
Add note about `st.spinner()` to the home page.
diff --git a/CITATION.cff b/CITATION.cff
index a8bc246..c87aeda 100644
--- a/CITATION.cff
+++ b/CITATION.cff
@@ -29,5 +29,5 @@ repository-code: 'https://github.com/pythonhealthdatascience/llm_simpy_models'
abstract: >-
The SimPy models and apps generated by LLMs, deployed as a single app.
license: MIT
-version: '1.0.2'
-date-released: '2025-03-25'
\ No newline at end of file
+version: '1.0.3'
+date-released: '2025-12-02'
\ No newline at end of file
diff --git a/README.md b/README.md
index 657fdcb..edc071a 100644
--- a/README.md
+++ b/README.md
@@ -39,6 +39,8 @@ For a full record of the generation of these models, please refer to: https://gi
## 🌐 Creating the environment
+### conda
+
The project uses `conda` to manage dependencies. Navigate your terminal to the directory containing the code and run:
```
@@ -51,7 +53,53 @@ This will create a conda environment called `gen_simpy_apps`. To activate:
conda activate gen_simpy_apps
```
-This environment is a simplified version of that from the [llm_simpy](https://github.com/pythonhealthdatascience/llm_simpy) repository, containing only the dependencies required for running the apps.
+This environment is a simplified version of that from the [llm_simpy](https://github.com/pythonhealthdatascience/llm_simpy) repository, containing only the dependencies required for running the models and apps.
+
+### venv
+
+Another option is to use `venv`. You can build the environment by running:
+
+```
+python -m venv venv
+```
+
+Then install the packages using:
+
+```
+pip install -r requirements.txt
+```
+
+`venv` cannot control which python version is used, it will just use one on system. You can check what this is by running:
+
+```
+venv/bin/python --version
+```
+
+You can find the version of python used for the models and app in the `binder/environment.yaml` file.
+
+### Docker
+
+Alternatively, a docker environment has been provided.
+
+You can build the image by running:
+
+```
+docker build -f binder/Dockerfile -t gen_simpy_apps .
+```
+
+Another option is to pull the image from the GitHub Container Registry:
+
+```
+docker pull ghcr.io/pythonhealthdatascience/llm_simpy_models:latest
+```
+
+Once you have the build image, you can then run the container:
+
+```
+docker run -p 8501:8501 gen_simpy_apps
+```
+
+Open your browser to to view the app.
diff --git a/binder/Dockerfile b/binder/Dockerfile
new file mode 100644
index 0000000..1f4f878
--- /dev/null
+++ b/binder/Dockerfile
@@ -0,0 +1,26 @@
+FROM mambaorg/micromamba:latest
+
+# Needed for micromamba activation in Dockerfile RUN commands
+ARG MAMBA_DOCKERFILE_ACTIVATE=1
+
+# Workdir inside container
+WORKDIR /app
+
+# Copy only env first to leverage layer caching
+COPY binder/environment.yml /tmp/environment.yml
+
+# Create the conda env
+RUN micromamba env create -f /tmp/environment.yml && \
+ micromamba clean --all --yes
+
+# Now copy the rest of the project
+COPY . /app
+
+# Default environment name; adjust if changes in environment.yml
+ENV CONDA_DEFAULT_ENV=gen_simpy_apps
+ENV PATH=/opt/conda/envs/gen_simpy_apps/bin:$PATH
+
+EXPOSE 8501
+
+# Use shell-form so the env is active via MAMBA_DOCKERFILE_ACTIVATE
+CMD ["streamlit", "run", "Home.py", "--server.address=0.0.0.0", "--server.port=8501"]