modelcar-maker 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. modelcar_maker-0.4.0/.agents/skills/dev-workflows/SKILL.md +70 -0
  2. modelcar_maker-0.4.0/.dockerignore +14 -0
  3. modelcar_maker-0.4.0/.github/workflows/build-push-main.yml +50 -0
  4. modelcar_maker-0.4.0/.github/workflows/release.yml +90 -0
  5. modelcar_maker-0.4.0/.gitignore +21 -0
  6. modelcar_maker-0.4.0/AGENTS.md +59 -0
  7. modelcar_maker-0.4.0/Containerfile +20 -0
  8. modelcar_maker-0.4.0/LICENSE +14 -0
  9. modelcar_maker-0.4.0/PKG-INFO +150 -0
  10. modelcar_maker-0.4.0/README.md +127 -0
  11. modelcar_maker-0.4.0/pyproject.toml +57 -0
  12. modelcar_maker-0.4.0/setup.cfg +4 -0
  13. modelcar_maker-0.4.0/src/modelcar_maker/__init__.py +154 -0
  14. modelcar_maker-0.4.0/src/modelcar_maker/__version__.py +24 -0
  15. modelcar_maker-0.4.0/src/modelcar_maker/cli/__init__.py +3 -0
  16. modelcar_maker-0.4.0/src/modelcar_maker/cli/cli.py +177 -0
  17. modelcar_maker-0.4.0/src/modelcar_maker/download/__init__.py +3 -0
  18. modelcar_maker-0.4.0/src/modelcar_maker/download/hf_download.py +35 -0
  19. modelcar_maker-0.4.0/src/modelcar_maker/image/__init__.py +17 -0
  20. modelcar_maker-0.4.0/src/modelcar_maker/image/common.py +41 -0
  21. modelcar_maker-0.4.0/src/modelcar_maker/image/olot.py +389 -0
  22. modelcar_maker-0.4.0/src/modelcar_maker/image/podman.py +188 -0
  23. modelcar_maker-0.4.0/src/modelcar_maker/image/template.py +29 -0
  24. modelcar_maker-0.4.0/src/modelcar_maker/image/types.py +57 -0
  25. modelcar_maker-0.4.0/src/modelcar_maker/templates/Containerfile.j2 +20 -0
  26. modelcar_maker-0.4.0/src/modelcar_maker/util/__init__.py +7 -0
  27. modelcar_maker-0.4.0/src/modelcar_maker/util/config.py +34 -0
  28. modelcar_maker-0.4.0/src/modelcar_maker/util/defaults.toml +17 -0
  29. modelcar_maker-0.4.0/src/modelcar_maker/util/helpers.py +18 -0
  30. modelcar_maker-0.4.0/src/modelcar_maker/util/logging.py +33 -0
  31. modelcar_maker-0.4.0/src/modelcar_maker.egg-info/PKG-INFO +150 -0
  32. modelcar_maker-0.4.0/src/modelcar_maker.egg-info/SOURCES.txt +47 -0
  33. modelcar_maker-0.4.0/src/modelcar_maker.egg-info/dependency_links.txt +1 -0
  34. modelcar_maker-0.4.0/src/modelcar_maker.egg-info/entry_points.txt +2 -0
  35. modelcar_maker-0.4.0/src/modelcar_maker.egg-info/requires.txt +11 -0
  36. modelcar_maker-0.4.0/src/modelcar_maker.egg-info/scm_file_list.json +42 -0
  37. modelcar_maker-0.4.0/src/modelcar_maker.egg-info/scm_version.json +8 -0
  38. modelcar_maker-0.4.0/src/modelcar_maker.egg-info/top_level.txt +1 -0
  39. modelcar_maker-0.4.0/tests/conftest.py +70 -0
  40. modelcar_maker-0.4.0/tests/integration/test_build_real.py +178 -0
  41. modelcar_maker-0.4.0/tests/integration/test_cli.py +92 -0
  42. modelcar_maker-0.4.0/tests/unit/test_download.py +59 -0
  43. modelcar_maker-0.4.0/tests/unit/test_helpers.py +33 -0
  44. modelcar_maker-0.4.0/tests/unit/test_image_olot.py +293 -0
  45. modelcar_maker-0.4.0/tests/unit/test_image_podman.py +211 -0
  46. modelcar_maker-0.4.0/tests/unit/test_image_template.py +82 -0
  47. modelcar_maker-0.4.0/tests/unit/test_process.py +362 -0
  48. modelcar_maker-0.4.0/tmp/.gitkeep +0 -0
  49. modelcar_maker-0.4.0/tox.ini +85 -0
@@ -0,0 +1,70 @@
1
+ ---
2
+ name: dev-workflows
3
+ description: Manage Python development environment setup, code formatting, linting, and testing for this project. Use when creating or modifying Python files, setting up the project, or verifying changes.
4
+ metadata:
5
+ author: modelcar-maker
6
+ version: "1.0"
7
+ ---
8
+
9
+ # Dev Workflows
10
+
11
+ ## Environment Setup
12
+
13
+ Before doing any development work, ensure the virtual environment exists and dependencies are installed:
14
+
15
+ 1. Create the virtual environment with Python 3.12:
16
+ ```bash
17
+ uv venv -p 3.12
18
+ ```
19
+
20
+ 2. Install the project in editable mode with dev dependencies:
21
+ ```bash
22
+ uv pip install -e ".[dev]"
23
+ ```
24
+
25
+ If `.venv/` is missing or Python version is wrong, start with step 1. If dependencies are missing, run step 2.
26
+
27
+ ## Code Formatting
28
+
29
+ Before finishing any task that creates or modifies Python files, run the formatter:
30
+
31
+ ```bash
32
+ uv run tox -e format
33
+ ```
34
+
35
+ This runs isort (import sorting) and black (code formatting). Do not skip formatting even for "small" changes. Do not ask the user before running format — just do it.
36
+
37
+ ## Linting
38
+
39
+ After formatting, or before committing, verify that lint passes:
40
+
41
+ ```bash
42
+ uv run tox -e lint
43
+ ```
44
+
45
+ This runs black --check, isort --check-only, flake8, and mypy. Fix any failures that arise.
46
+
47
+ ## Testing
48
+
49
+ After making changes, run the test suite:
50
+
51
+ ```bash
52
+ uv run tox -e py312
53
+ ```
54
+
55
+ This runs pytest against the test suite and verifies everything passes.
56
+
57
+ ## Full Verification Workflow
58
+
59
+ For a complete check before considering a task done, run all default environments:
60
+
61
+ ```bash
62
+ uv run tox
63
+ ```
64
+
65
+ This runs `py311`, `py312`, `py313`, and `lint`. Fix any failures before finishing.
66
+
67
+ ## Troubleshooting
68
+
69
+ - If the formatter is not available, install dev dependencies: `uv pip install -e ".[dev]"`
70
+ - If formatting changes create new lint issues, fix them inline
@@ -0,0 +1,14 @@
1
+ .github
2
+ .tox
3
+ .venv
4
+ tests
5
+ tox.ini
6
+ .mypy_cache
7
+ .pytest_cache
8
+ uv.lock
9
+ models
10
+ tmp
11
+ charts
12
+ AGENTS.md
13
+ .agents
14
+ src/modelcar_maker.egg-info
@@ -0,0 +1,50 @@
1
+ name: Build & Push (main branch)
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+
8
+ permissions: {}
9
+
10
+ jobs:
11
+ test:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - uses: actions/setup-python@v6
16
+ with:
17
+ python-version: "3.12"
18
+ - run: python -m pip install tox
19
+ - run: tox run -e py312
20
+
21
+ lint:
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - uses: actions/checkout@v4
25
+ - uses: actions/setup-python@v6
26
+ with:
27
+ python-version: "3.12"
28
+ - run: python -m pip install tox
29
+ - run: tox run -e lint
30
+
31
+ container:
32
+ needs: [test, lint]
33
+ runs-on: ubuntu-latest
34
+ permissions:
35
+ packages: write
36
+ steps:
37
+ - uses: actions/checkout@v4
38
+ - uses: docker/login-action@v4
39
+ with:
40
+ registry: ghcr.io
41
+ username: ${{ github.actor }}
42
+ password: ${{ secrets.GITHUB_TOKEN }}
43
+ - uses: docker/setup-buildx-action@v4
44
+ - uses: docker/build-push-action@v7
45
+ with:
46
+ context: .
47
+ file: ./Containerfile
48
+ push: true
49
+ tags: ghcr.io/${{ github.repository_owner }}/modelcar-maker:main
50
+ provenance: false
@@ -0,0 +1,90 @@
1
+ name: Release (PyPI + GitHub Release + Container)
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "*.*.*"
7
+
8
+ permissions: {}
9
+
10
+ jobs:
11
+ test:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - uses: actions/setup-python@v6
16
+ with:
17
+ python-version: "3.12"
18
+ - run: python -m pip install tox
19
+ - run: tox run -e py312
20
+
21
+ lint:
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - uses: actions/checkout@v4
25
+ - uses: actions/setup-python@v6
26
+ with:
27
+ python-version: "3.12"
28
+ - run: python -m pip install tox
29
+ - run: tox run -e lint
30
+
31
+ build:
32
+ needs: [test, lint]
33
+ runs-on: ubuntu-latest
34
+ steps:
35
+ - uses: actions/checkout@v4
36
+ - uses: actions/setup-python@v6
37
+ with:
38
+ python-version: "3.12"
39
+ - run: python -m pip install tox
40
+ - run: tox run -e build
41
+ - uses: actions/upload-artifact@v7
42
+ with:
43
+ name: dist
44
+ path: dist/
45
+
46
+ publish:
47
+ needs: [build]
48
+ runs-on: ubuntu-latest
49
+ permissions:
50
+ contents: write
51
+ steps:
52
+ - uses: actions/checkout@v4
53
+ - uses: actions/download-artifact@v8
54
+ with:
55
+ name: dist
56
+ path: dist/
57
+ - run: pip install --user --upgrade "packaging>=24.2" twine
58
+ - run: twine upload --skip-existing dist/*.whl dist/*.tar.gz
59
+ env:
60
+ TWINE_USERNAME: __token__
61
+ TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
62
+ - uses: softprops/action-gh-release@v3
63
+ with:
64
+ files: |
65
+ dist/*.whl
66
+ dist/*.tar.gz
67
+ generate_release_notes: true
68
+
69
+ container:
70
+ needs: [test, lint]
71
+ runs-on: ubuntu-latest
72
+ permissions:
73
+ packages: write
74
+ steps:
75
+ - uses: actions/checkout@v4
76
+ - uses: docker/login-action@v4
77
+ with:
78
+ registry: ghcr.io
79
+ username: ${{ github.actor }}
80
+ password: ${{ secrets.GITHUB_TOKEN }}
81
+ - uses: docker/setup-buildx-action@v4
82
+ - uses: docker/build-push-action@v7
83
+ with:
84
+ context: .
85
+ file: ./Containerfile
86
+ push: true
87
+ tags: |
88
+ ghcr.io/${{ github.repository_owner }}/modelcar-maker:${{ github.ref_name }}
89
+ ghcr.io/${{ github.repository_owner }}/modelcar-maker:latest
90
+ provenance: false
@@ -0,0 +1,21 @@
1
+ # Python development things
2
+ .venv
3
+ .tox
4
+ __version__.py
5
+ *.pyc
6
+ *.egg-info
7
+ build
8
+ dist
9
+ *.env
10
+ uv.lock
11
+
12
+ # Preserve Containerfiles, even if not other files
13
+ models/*/*
14
+ !models/*/Containerfile
15
+
16
+ # working directory
17
+ tmp/*
18
+ !tmp/.gitkeep
19
+
20
+ # Keep a local config for myself
21
+ config.toml
@@ -0,0 +1,59 @@
1
+ # modelcar-maker
2
+
3
+ ## Purpose
4
+
5
+ A CLI tool that downloads Hugging Face models and packages them as OCI container images ("modelcars"), placing each model file in its own layer for efficient distribution.
6
+
7
+ ## Key Concepts
8
+
9
+ - **Modelcar**: A minimal container image containing a downloaded Hugging Face model, tagged with `{normalized-model}-modelcar`.
10
+ - **Backends**:
11
+ - `podman`: Traditional container build using a generated Containerfile.
12
+ - `olot`: Uses OCI Layer On Top to stack model files as OCI layers directly, avoiding a traditional container build.
13
+ - **Layers per file**: Each model file becomes an individual image layer for deduplication and selective pulling.
14
+
15
+ ## Modules
16
+
17
+ | Module | Description |
18
+ |---|---|
19
+ | `cli/cli.py` | Typer CLI. `build` command accepts model, registry, backend, push/cleanup flags. |
20
+ | `__init__.py` | Core `process()` workflow: download -> build -> push -> cleanup. |
21
+ | `download/hf_download.py` | Downloads models via `huggingface_hub.snapshot_download`. Extracts commit hash from metadata. |
22
+ | `image/podman.py` | Podman backend: renders Containerfile, runs `podman build/push/image rm`. |
23
+ | `image/olot.py` | OLOT backend: pulls base image into OCI layout, adds model files as layers with `olot`, pushes with `oras-py`. |
24
+ | `image/template.py` | Renders `Containerfile.j2` with model files, labels, and base image. |
25
+ | `image/common.py` | Shared utilities: `_image()` (image ref naming), `list_model_files()`, file filtering. |
26
+ | `image/types.py` | Dataclasses (`BuildArgs`, `BuildResult`, `PushArgs`, `RmArgs`) and `Backend` enum. |
27
+ | `util/config.py` | Dynaconf settings. Loads `defaults.toml`, system/user/cwd config, env vars (`MODELCAR_MAKER_*`). |
28
+ | `util/helpers.py` | `normalize()` (repo ID -> safe tag/folder), `Truthy` string class. |
29
+ | `util/logging.py` | Logger factory with verbosity-controlled stderr handler. |
30
+
31
+ ## Usage
32
+
33
+ ```bash
34
+ # Build and push a single model
35
+ modelcar-maker build meta-llama/Llama-3.2-3B-Instruct --push
36
+
37
+ # Build all default models with olot backend
38
+ modelcar-maker build --backend olot
39
+
40
+ # Build without pushing, clean up after
41
+ modelcar-maker build BAAI/bge-large-en-v1.5 --no-push --image-clean-up --model-clean-up
42
+ ```
43
+
44
+ ## Configuration
45
+
46
+ Config is layered via Dynaconf:
47
+
48
+ 1. `src/modelcar_maker/util/defaults.toml` (built-in defaults)
49
+ 2. `/usr/share/modelcar-maker/config.toml`
50
+ 3. `/etc/modelcar-maker/config.toml`
51
+ 4. `~/.config/modelcar-maker/config.toml`
52
+ 5. `./config.toml` (project root)
53
+ 6. Environment variables (`MODELCAR_MAKER_*`)
54
+
55
+ Key settings: `image.registry`, `image.repository`, `image.backend`, `image.push`, `image.cleanup`, `models.default` (list), `models.cleanup`.
56
+
57
+ ## Development
58
+
59
+ Load the `dev-workflows` skill before creating or modifying Python files, setting up the project, or verifying changes. That skill contains the canonical instructions for environment setup, formatting, linting, and testing.
@@ -0,0 +1,20 @@
1
+ FROM registry.access.redhat.com/ubi9/python-312:latest
2
+
3
+ WORKDIR /opt/app-root/src
4
+
5
+ RUN pip install --no-cache-dir pip-tools
6
+
7
+ COPY --chown=1001:1001 pyproject.toml ./
8
+
9
+ RUN pip-compile pyproject.toml && \
10
+ pip install --no-cache-dir -r requirements.txt
11
+
12
+ COPY --chown=1001:1001 ./ ./
13
+
14
+ RUN pip install --no-cache-dir .
15
+
16
+ WORKDIR /modelcar-maker
17
+ ENV HF_TOKEN ""
18
+
19
+ ENTRYPOINT ["modelcar-maker"]
20
+ CMD []
@@ -0,0 +1,14 @@
1
+ ISC License (ISC)
2
+ Copyright (c) 2025, James Harmison <jharmison@redhat.com>
3
+
4
+ Permission to use, copy, modify, and/or distribute this software for any purpose
5
+ with or without fee is hereby granted, provided that the above copyright notice
6
+ and this permission notice appear in all copies.
7
+
8
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
10
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
12
+ OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
13
+ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
14
+ THIS SOFTWARE.
@@ -0,0 +1,150 @@
1
+ Metadata-Version: 2.4
2
+ Name: modelcar-maker
3
+ Version: 0.4.0
4
+ Summary: A tool to build modelcar images with layers per file
5
+ Author-email: James Harmison <jharmison@redhat.com>
6
+ License-Expression: ISC
7
+ Project-URL: Source, https://github.com/jharmison-redhat/modelcar-maker
8
+ Project-URL: Documentation, https://github.com/jharmison-redhat/modelcar-maker
9
+ Classifier: Operating System :: POSIX :: Linux
10
+ Requires-Python: >=3.11
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: dynaconf<3.3.0,>=3.2.13
14
+ Requires-Dist: typer<0.26.0,>=0.25.1
15
+ Requires-Dist: huggingface-hub<1.18.0,>=1.17.0
16
+ Requires-Dist: olot[oras-py]<0.2.0,>=0.1.17
17
+ Provides-Extra: dev
18
+ Requires-Dist: tox; extra == "dev"
19
+ Requires-Dist: pytest; extra == "dev"
20
+ Provides-Extra: podman
21
+ Requires-Dist: Jinja2<3.2,>=3.1.6; extra == "podman"
22
+ Dynamic: license-file
23
+
24
+ # modelcar-maker
25
+
26
+ Downloads Hugging Face models and packages them as minimal OCI container images with one file per layer. Designed for
27
+ use with KServe as [Modelcar images](https://kserve.github.io/website/docs/model-serving/storage/providers/oci).
28
+
29
+ ## Install
30
+
31
+ Requires Python 3.11+.
32
+
33
+ ```bash
34
+ pip install modelcar-maker
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ ```
40
+ modelcar-maker [OPTIONS] [MODEL]
41
+ ```
42
+
43
+ | Argument / Option | Description |
44
+ | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
45
+ | `MODEL` | Hugging Face model repo ID (e.g., `meta-llama/Llama-3.2-3B-Instruct`). Optional if `models.default` is configured. |
46
+ | `--registry` | Registry for the output image. Default: `quay.io`. |
47
+ | `-r`, `--repository` | Repository within the registry. Default: `jharmison/models`. |
48
+ | `--backend` | Build backend. Default: `olot`. The `podman` backend requires extra dependencies (included via `pip install modelcar-maker[podman]`) |
49
+ | `--base-image` | Base OCI image. Default: `registry.access.redhat.com/ubi10/ubi-micro:10.2`. |
50
+ | `--arch` | Target architecture(s). Repeat for multiple. Default: `amd64`, `arm64`. |
51
+ | `--pull` / `--no-pull` | Pull base image if a newer version is available. Default: `--pull`. |
52
+ | `--push` / `--no-push` | Push the image after building. Default: `--push`. |
53
+ | `-a`, `--authfile` | Path to Docker/podman auth config for registry push. |
54
+ | `--image-clean-up` / `--no-image-clean-up` | Remove local container image after push. Default: off. |
55
+ | `--model-clean-up` / `--no-model-clean-up` | Remove downloaded model files after build. Default: off. |
56
+ | `--skip-if-exists` / `--no-skip-if-exists` | Skip if the tag already exists at the registry. Default: on. |
57
+ | `-v` | Increase logging verbosity. Repeat for more. |
58
+ | `-V` | Print version and exit. |
59
+
60
+ **Image tag format:** `{registry}/{repository}/{normalized-model}-modelcar`
61
+
62
+ The model repo ID is normalized for use as a tag: slashes become `--`, dots become `_`, and the string is lowercased.
63
+ For example, `meta-llama/Llama-3.2-3B-Instruct` produces tag `meta-llama--llama_3-2-3b-instruct-modelcar`.
64
+
65
+ **Examples:**
66
+
67
+ ```bash
68
+ # Build and push a model
69
+ modelcar-maker meta-llama/Llama-3.2-3B-Instruct
70
+
71
+ # Build locally without pushing
72
+ modelcar-maker BAAI/bge-large-en-v1.5 --no-push
73
+
74
+ # Explicit multi-arch build with cleanup
75
+ modelcar-maker mistralai/Mistral-7B --arch amd64 --arch arm64 --image-clean-up --model-clean-up
76
+ ```
77
+
78
+ ## Configuration
79
+
80
+ Settings are resolved in layer order (later layers override earlier ones):
81
+
82
+ 1. Built-in defaults ([`defaults.toml`](src/modelcar_maker/util/defaults.toml))
83
+ 2. `/usr/share/modelcar-maker/config.toml`
84
+ 3. `/etc/modelcar-maker/config.toml`
85
+ 4. `~/.config/modelcar-maker/config.toml`
86
+ 5. `./config.toml` (current working directory)
87
+ 6. Environment variables with prefix `MODELCAR_MAKER_`
88
+
89
+ Any setting can be overridden via environment variable by uppercasing the section and key and joining with underscores.
90
+ For example:
91
+
92
+ | Env Var | Overrides |
93
+ | ------------------------------- | ---------------- |
94
+ | `MODELCAR_MAKER_IMAGE_REGISTRY` | `image.registry` |
95
+ | `MODELCAR_MAKER_IMAGE_PUSH` | `image.push` |
96
+ | `MODELCAR_MAKER_MODELS_DEFAULT` | `models.default` |
97
+
98
+ **Example `config.toml`:**
99
+
100
+ ```toml
101
+ [image]
102
+ registry = "quay.io"
103
+ repository = "myorg/models"
104
+ push = true
105
+ architectures = ["amd64"]
106
+
107
+ [models]
108
+ default = ["meta-llama/Llama-3.2-3B-Instruct", "BAAI/bge-large-en-v1.5"]
109
+ ```
110
+
111
+ Setting default models allows running `modelcar-maker` with no arguments to build all listed models.
112
+
113
+ ## Running as a Container
114
+
115
+ The tool is available as a container image at `ghcr.io/jharmison-redhat/modelcar-maker:latest` (versioned tags also
116
+ available).
117
+
118
+ ```bash
119
+ podman run --rm ghcr.io/jharmison-redhat/modelcar-maker:latest --help
120
+ ```
121
+
122
+ For authenticated pushes, mount a credential file. For gated downloads, provide the `HF_TOKEN` environment variable:
123
+
124
+ ```bash
125
+ podman run --rm \
126
+ -v "$HOME/.docker/config.json:/config.json" \
127
+ -e HF_TOKEN="$HF_TOKEN" \
128
+ ghcr.io/jharmison-redhat/modelcar-maker:latest \
129
+ --authfile /config.json \
130
+ meta-llama/Llama-3.2-3B-Instruct
131
+ ```
132
+
133
+ To persist downloaded model files across runs, mount a volume at `/modelcar-maker`:
134
+
135
+ ```bash
136
+ podman run --rm \
137
+ -v modelcar-cache:/modelcar-maker \
138
+ -v "$HOME/.docker/config.json:/config.json" \
139
+ -e HF_TOKEN="$HF_TOKEN" \
140
+ ghcr.io/jharmison-redhat/modelcar-maker:latest \
141
+ --authfile /config.json \
142
+ --skip-if-exists \
143
+ meta-llama/Llama-3.2-3B-Instruct
144
+ ```
145
+
146
+ `docker` may work but is untested.
147
+
148
+ ## License
149
+
150
+ ISC. See [LICENSE](LICENSE).
@@ -0,0 +1,127 @@
1
+ # modelcar-maker
2
+
3
+ Downloads Hugging Face models and packages them as minimal OCI container images with one file per layer. Designed for
4
+ use with KServe as [Modelcar images](https://kserve.github.io/website/docs/model-serving/storage/providers/oci).
5
+
6
+ ## Install
7
+
8
+ Requires Python 3.11+.
9
+
10
+ ```bash
11
+ pip install modelcar-maker
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ ```
17
+ modelcar-maker [OPTIONS] [MODEL]
18
+ ```
19
+
20
+ | Argument / Option | Description |
21
+ | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
22
+ | `MODEL` | Hugging Face model repo ID (e.g., `meta-llama/Llama-3.2-3B-Instruct`). Optional if `models.default` is configured. |
23
+ | `--registry` | Registry for the output image. Default: `quay.io`. |
24
+ | `-r`, `--repository` | Repository within the registry. Default: `jharmison/models`. |
25
+ | `--backend` | Build backend. Default: `olot`. The `podman` backend requires extra dependencies (included via `pip install modelcar-maker[podman]`) |
26
+ | `--base-image` | Base OCI image. Default: `registry.access.redhat.com/ubi10/ubi-micro:10.2`. |
27
+ | `--arch` | Target architecture(s). Repeat for multiple. Default: `amd64`, `arm64`. |
28
+ | `--pull` / `--no-pull` | Pull base image if a newer version is available. Default: `--pull`. |
29
+ | `--push` / `--no-push` | Push the image after building. Default: `--push`. |
30
+ | `-a`, `--authfile` | Path to Docker/podman auth config for registry push. |
31
+ | `--image-clean-up` / `--no-image-clean-up` | Remove local container image after push. Default: off. |
32
+ | `--model-clean-up` / `--no-model-clean-up` | Remove downloaded model files after build. Default: off. |
33
+ | `--skip-if-exists` / `--no-skip-if-exists` | Skip if the tag already exists at the registry. Default: on. |
34
+ | `-v` | Increase logging verbosity. Repeat for more. |
35
+ | `-V` | Print version and exit. |
36
+
37
+ **Image tag format:** `{registry}/{repository}/{normalized-model}-modelcar`
38
+
39
+ The model repo ID is normalized for use as a tag: slashes become `--`, dots become `_`, and the string is lowercased.
40
+ For example, `meta-llama/Llama-3.2-3B-Instruct` produces tag `meta-llama--llama_3-2-3b-instruct-modelcar`.
41
+
42
+ **Examples:**
43
+
44
+ ```bash
45
+ # Build and push a model
46
+ modelcar-maker meta-llama/Llama-3.2-3B-Instruct
47
+
48
+ # Build locally without pushing
49
+ modelcar-maker BAAI/bge-large-en-v1.5 --no-push
50
+
51
+ # Explicit multi-arch build with cleanup
52
+ modelcar-maker mistralai/Mistral-7B --arch amd64 --arch arm64 --image-clean-up --model-clean-up
53
+ ```
54
+
55
+ ## Configuration
56
+
57
+ Settings are resolved in layer order (later layers override earlier ones):
58
+
59
+ 1. Built-in defaults ([`defaults.toml`](src/modelcar_maker/util/defaults.toml))
60
+ 2. `/usr/share/modelcar-maker/config.toml`
61
+ 3. `/etc/modelcar-maker/config.toml`
62
+ 4. `~/.config/modelcar-maker/config.toml`
63
+ 5. `./config.toml` (current working directory)
64
+ 6. Environment variables with prefix `MODELCAR_MAKER_`
65
+
66
+ Any setting can be overridden via environment variable by uppercasing the section and key and joining with underscores.
67
+ For example:
68
+
69
+ | Env Var | Overrides |
70
+ | ------------------------------- | ---------------- |
71
+ | `MODELCAR_MAKER_IMAGE_REGISTRY` | `image.registry` |
72
+ | `MODELCAR_MAKER_IMAGE_PUSH` | `image.push` |
73
+ | `MODELCAR_MAKER_MODELS_DEFAULT` | `models.default` |
74
+
75
+ **Example `config.toml`:**
76
+
77
+ ```toml
78
+ [image]
79
+ registry = "quay.io"
80
+ repository = "myorg/models"
81
+ push = true
82
+ architectures = ["amd64"]
83
+
84
+ [models]
85
+ default = ["meta-llama/Llama-3.2-3B-Instruct", "BAAI/bge-large-en-v1.5"]
86
+ ```
87
+
88
+ Setting default models allows running `modelcar-maker` with no arguments to build all listed models.
89
+
90
+ ## Running as a Container
91
+
92
+ The tool is available as a container image at `ghcr.io/jharmison-redhat/modelcar-maker:latest` (versioned tags also
93
+ available).
94
+
95
+ ```bash
96
+ podman run --rm ghcr.io/jharmison-redhat/modelcar-maker:latest --help
97
+ ```
98
+
99
+ For authenticated pushes, mount a credential file. For gated downloads, provide the `HF_TOKEN` environment variable:
100
+
101
+ ```bash
102
+ podman run --rm \
103
+ -v "$HOME/.docker/config.json:/config.json" \
104
+ -e HF_TOKEN="$HF_TOKEN" \
105
+ ghcr.io/jharmison-redhat/modelcar-maker:latest \
106
+ --authfile /config.json \
107
+ meta-llama/Llama-3.2-3B-Instruct
108
+ ```
109
+
110
+ To persist downloaded model files across runs, mount a volume at `/modelcar-maker`:
111
+
112
+ ```bash
113
+ podman run --rm \
114
+ -v modelcar-cache:/modelcar-maker \
115
+ -v "$HOME/.docker/config.json:/config.json" \
116
+ -e HF_TOKEN="$HF_TOKEN" \
117
+ ghcr.io/jharmison-redhat/modelcar-maker:latest \
118
+ --authfile /config.json \
119
+ --skip-if-exists \
120
+ meta-llama/Llama-3.2-3B-Instruct
121
+ ```
122
+
123
+ `docker` may work but is untested.
124
+
125
+ ## License
126
+
127
+ ISC. See [LICENSE](LICENSE).
@@ -0,0 +1,57 @@
1
+ [project]
2
+ name = "modelcar-maker"
3
+ dynamic = ["version"]
4
+ requires-python = ">=3.11"
5
+ authors = [{ name = "James Harmison", email = "jharmison@redhat.com" }]
6
+ description = """\
7
+ A tool to build modelcar images with layers per file\
8
+ """
9
+ license = "ISC"
10
+ license-files = ["LICENSE"]
11
+ readme = "README.md"
12
+ classifiers = ["Operating System :: POSIX :: Linux"]
13
+ dependencies = [
14
+ "dynaconf >=3.2.13,<3.3.0",
15
+ "typer >=0.25.1,<0.26.0",
16
+ "huggingface-hub >=1.17.0,<1.18.0",
17
+ "olot[oras-py] >=0.1.17,<0.2.0",
18
+ ]
19
+
20
+ [project.optional-dependencies]
21
+ dev = ["tox", "pytest"]
22
+ podman = ["Jinja2 >=3.1.6,<3.2"]
23
+
24
+ [project.urls]
25
+ Source = "https://github.com/jharmison-redhat/modelcar-maker"
26
+ Documentation = "https://github.com/jharmison-redhat/modelcar-maker"
27
+
28
+ [project.scripts]
29
+ modelcar-maker = "modelcar_maker.cli:cli"
30
+
31
+ [tool.setuptools.package-data]
32
+ modelcar_maker = ["defaults.toml", "Containerfile.j2"]
33
+
34
+ [tool.setuptools_scm]
35
+ write_to = "src/modelcar_maker/__version__.py"
36
+
37
+ [build-system]
38
+ requires = ["setuptools>=80", "setuptools-scm>=8"]
39
+ build-backend = "setuptools.build_meta"
40
+
41
+ [tool.black]
42
+ skip-string-normalization = false
43
+ line-length = 120
44
+ target-version = ["py311"]
45
+
46
+ [tool.isort]
47
+ profile = "black"
48
+ force_single_line = true
49
+ line_length = 120
50
+ src_paths = ["src", "tests"]
51
+
52
+ [tool.pytest.ini_options]
53
+ markers = ["slow: marks tests as slow (deselect with -m 'not slow')"]
54
+
55
+ [tool.pyright]
56
+ venvPath = "."
57
+ venv = ".venv"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+