Adding Custom apt, pip, or conda Packages via Install Lists in LabNow AI
You can add custom system, Python, or Conda packages to LabNow AI containers by editing the plain-text install-list files in docker_core/work/ and committing the changes to trigger an automatic rebuild via GitHub Actions.
LabNow AI (labnow-ai/lab-foundation) uses a modular build system where container dependencies are declared in simple text files rather than embedded in Dockerfile RUN commands. By modifying these install lists and leveraging the helper utilities defined in docker_atom/work/script-utils.sh, you can extend base images with any additional software without altering the core build logic.
How Install Lists Work
The LabNow AI build pipeline separates package definitions from installation logic through a set of conventions and helper functions.
The Core Architecture
The system relies on three main components:
- Install-list files — Plain-text files where each line specifies a package name. Files use extensions
.apt,.pip, or.condato indicate the package manager. Comments start with the%character. - Utility script —
docker_atom/work/script-utils.shdefines generic installer wrappers (install_apt,install_pip,install_conda,install_mamba) that parse these lists and invoke the appropriate package manager. - CI/CD Pipeline — The
.github/workflows/build-docker.ymlworkflow monitors these files and automatically rebuilds images when changes are detected.
List Parsing Logic
At build time, the install_apt() function (line 6 of script-utils.sh) processes list files by stripping comments and passing clean package names to apt-get:
apt-get -qq update -yq --fix-missing \
&& apt-get -qq install -yq --no-install-recommends $(cat "$1" | cut -d '%' -f 1)
The cut -d '%' -f 1 command removes any trailing comments, ensuring only the package name reaches the installer. Equivalent logic exists for install_pip() and install_conda() functions within the same file.
Dockerfile Integration
The Dockerfiles invoke these helpers during the build phase. In docker_core/Dockerfile, the installation steps appear at lines 42 and 91:
&& install_apt "/opt/utils/install_list_latex_${profile}.apt" \
&& install_pip "/opt/utils/install_list_PY_${profile}.pip"
After installation, the list_installed_packages() function (lines 60-72 of script-utils.sh) logs all installed components for verification.
Step-by-Step: Adding Your Own Packages
1. Select the Correct Install List
Choose the file that matches your package type and target environment:
| Package Type | Example File Path | Location |
|---|---|---|
System (apt) |
docker_core/work/install_list_PY_base.apt |
docker_core/work/ |
Python (pip) |
docker_core/work/install_list_PY_base.pip |
docker_core/work/ |
| Conda packages | docker_core/work/install_list_core.conda |
docker_core/work/ |
The naming convention follows install_list_<scope>.<ext>, where <ext> is apt, pip, or conda.
2. Add Packages with Comments
Edit the chosen file and add one package per line. Append % followed by a description for inline documentation.
Adding ffmpeg via apt:
# docker_core/work/install_list_PY_base.apt
ffmpeg % Multimedia processing tools
Adding numpy via pip:
# docker_core/work/install_list_PY_base.pip
numpy % Fundamental package for scientific computing
Adding scikit-learn via conda:
# docker_core/work/install_list_core.conda
scikit-learn % Machine-learning toolkit
The first three lines of each template file contain format instructions for future reference.
3. Trigger the Build Pipeline
Commit your changes to the repository:
git add docker_core/work/install_list_PY_base.apt \
docker_core/work/install_list_PY_base.pip \
docker_core/work/install_list_core.conda
git commit -m "Add custom packages: ffmpeg, numpy, scikit-learn"
git push origin main
The GitHub Actions workflow defined in .github/workflows/build-docker.yml detects the file modifications and initiates a new image build automatically.
4. Verify Installation
Once the build completes, validate the packages exist in the new image:
docker run --rm labnow/lab-foundation:latest bash -c "\
ffmpeg -version && \
python -c 'import numpy, sklearn; print(numpy.__version__, sklearn.__version__)'"
For debugging during local development, use the install_echo helper to preview parsed package names without installing:
source /opt/utils/script-utils.sh
install_echo /opt/utils/install_list_PY_base.apt
Complete Dockerfile Integration Example
Below is a minimal reproducible excerpt demonstrating how the install lists integrate into the build process:
# docker_core/Dockerfile (excerpt)
FROM ubuntu:22.04 AS build
# Copy utility script and install lists
COPY docker_atom/work/script-utils.sh /opt/utils/
COPY docker_core/work/install_list_PY_base.apt /opt/utils/
COPY docker_core/work/install_list_PY_base.pip /opt/utils/
# Install packages using the helper functions
RUN set -ex \
&& source /opt/utils/script-utils.sh \
&& install_apt /opt/utils/install_list_PY_base.apt \
&& install_pip /opt/utils/install_list_PY_base.pip \
&& list_installed_packages
The full Dockerfile includes additional layers for CUDA, R, and Julia support. Refer to the complete file at docker_core/Dockerfile in the repository for the comprehensive build sequence.
Summary
- Install lists are plain-text files in
docker_core/work/using.apt,.pip, or.condaextensions. - Comments start with
%; the parser usescut -d '%' -f 1to strip them before installation. - Helper functions in
docker_atom/work/script-utils.shhandle the actual package manager calls. - Automatic rebuilds trigger via GitHub Actions when you commit changes to install-list files.
- Verification uses
list_installed_packages()or manual container testing to confirm successful installation.
Frequently Asked Questions
Can I use install lists to remove packages from a LabNow AI image?
No. The install_apt, install_pip, and install_conda functions only support adding packages. To remove software, you must modify the underlying Dockerfile layers or create a custom downstream image that uses apt-get remove, pip uninstall, or conda remove commands after sourcing the base image.
How does LabNow AI handle version pinning in install lists?
The current implementation passes package names directly to the package managers without explicit version constraints in the list files themselves. For pinned versions, you can specify the version in the list file using standard package manager syntax (e.g., numpy==1.24.0 for pip or numpy=1.24.0 for conda), as the helpers pass these strings directly to the install commands.
What happens if a package in my install list fails to install?
The build fails fast. The helper functions in script-utils.sh use set -e behavior (either explicitly or via the calling Dockerfile's set -ex), meaning any non-zero exit code from apt-get, pip, or conda will halt the Docker build process. Check the GitHub Actions logs in .github/workflows/build-docker.yml to identify the specific package causing the failure.
Can I create new install list files with custom names?
Yes, provided you reference them correctly in the Dockerfile. The install_apt, install_pip, and install_conda functions accept any file path as an argument. Create a new file following the install_list_<scope>.<ext> convention, then add a corresponding RUN instruction in the Dockerfile that points to your new list, similar to how docker_core/Dockerfile references the standard lists at lines 42 and 91.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →