Skip to content

Add support for Modelfile: parse Modelfile and apply directives#628

Open
Pnkcaht wants to merge 3 commits intodocker:mainfrom
Pnkcaht:feat/packaging-from-modelfile
Open

Add support for Modelfile: parse Modelfile and apply directives#628
Pnkcaht wants to merge 3 commits intodocker:mainfrom
Pnkcaht:feat/packaging-from-modelfile

Conversation

@Pnkcaht
Copy link
Contributor

@Pnkcaht Pnkcaht commented Feb 4, 2026

What I Did

  • Added support for Modelfile in the package command.
  • Parses the Modelfile and applies its directives to packageOptions.
  • CLI flags take precedence over Modelfile values.
  • Paths are normalized and validated.
  • Safe handling of path traversal.
  • Type checks for file vs directory for each instruction.
  • Supports aliases like SAFETENSORS-DIR, CHAT-TEMPLATE, MM-PROJ, CONTEXT, etc.

Releated Issue

Closes #613

Before / After

Before

docker model package --gguf /absolute/path/model.gguf --license /absolute/path/LICENSE ...
  • Required providing all options via CLI.
  • Error-prone with long commands and many paths.
  • No centralized configuration.

After

docker model package -f Modelfile

Modelfile example

GGUF ./model.gguf
LICENSE ./LICENSE
SAFETENSORS-DIR ./safetensors
CHAT-TEMPLATE ./template.jinja
MM-PROJ ./projector.mmproj
CONTEXT 8192
DIR-TAR assets
FROM existing-model
  • Supports relative and absolute paths.
  • CLI flags still have higher priority.
  • Aliases are automatically mapped.

Diagram

flowchart TD
    A[Start: CLI command] --> B{Modelfile provided?}
    B -- No --> C[Use CLI flags only]
    B -- Yes --> D[Parse Modelfile line by line]
    D --> E{Instruction type}
    E -- Source (GGUF/DDUF/SAFE) --> F[Set opts.<field> if empty]
    E -- License/Chat/MMProj --> G[Append or set path]
    E -- Context/CTX --> H[Set context size if unset]
    E -- DIR-TAR --> I[Append relative paths]
    F & G & H & I --> J[Finalized options]
    J --> K[Initialize Builder]
    K --> L[Package Model]
    L --> M{Push?}
    M -- Yes --> N[Push to registry]
    M -- No --> O[Load into Model Runner]
    N & O --> P[End: Success]
Loading

Missing / Optional Considerations

The following optional fields may cause issues if used incorrectly but are not required:

--license /path/to/file        # must be absolute; multiple allowed
--chat-template /path/to/file  # must be absolute; Jinja template
--mmproj /path/to/file         # multimodal projector
--context-size <number>        # must be positive and <= MaxInt32
--dir-tar <relative/path>      # must be relative; cannot contain ".."
  • If omitted, the builder will still work:

    • dir-tar missing → no additional tar archives included.
    • chat-template or mmproj missing → feature ignored.
    • license missing → no license embedded.
  • Users can specify these either via Modelfile or CLI flags.

…tives

Signed-off-by: pnkcaht <samzoovsk19@gmail.com>
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @Pnkcaht, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the docker model package command by introducing support for a Modelfile. This allows users to define model packaging configurations in a dedicated file, simplifying complex commands and improving maintainability. The implementation prioritizes CLI flags, ensures secure and validated path handling, and supports various directives for model sources, assets, and parameters, making the packaging process more flexible and less error-prone.

Highlights

  • Modelfile Support: Introduced support for a Modelfile in the docker model package command, allowing users to define packaging configurations in a dedicated file.
  • Directive Parsing and Application: Implemented logic to parse Modelfile directives (e.g., GGUF, LICENSE, CONTEXT) and apply them to package options, with CLI flags retaining higher precedence.
  • Robust Path Handling: Added comprehensive path normalization, validation, and security checks, including prevention of path traversal, and type checks for files versus directories.
  • Instruction Aliases: Included support for common aliases for directives like SAFETENSORS-DIR, CHAT-TEMPLATE, MM-PROJ, and CONTEXT to enhance user experience.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • cmd/cli/commands/package.go
    • Added a new --file or -f flag to specify the path to a Modelfile.
    • Modified the source validation logic to recognize Modelfile as a valid primary source for model packaging.
    • Implemented the applyModelfile function to parse the Modelfile line by line, handling directives, aliases, and applying values to package options while respecting CLI flag precedence.
    • Introduced normalizePath function for resolving relative paths, cleaning them, and preventing path traversal vulnerabilities.
    • Added helper functions needsPath to identify path-expecting instructions and contains for slice membership checks.
    • Integrated math, strconv, and strings packages for numerical parsing and string manipulation required by Modelfile processing.
Activity
  • The author Pnkcaht initiated this pull request to introduce Modelfile support for the package command.
  • The PR description provides a detailed breakdown of the changes, including before/after examples, a Mermaid diagram illustrating the workflow, and a list of supported directives and their behaviors.
  • This pull request aims to close issue Add support for Modelfile #613, indicating it addresses a previously identified need or feature request.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for Modelfile to configure model packaging, which is a great feature for improving user experience and centralizing configuration. The implementation correctly parses the Modelfile, handles various directives and their aliases, and prioritizes CLI flags over file-based options. The code includes good error handling with informative messages.

I've identified a few areas for improvement:

  • The path normalization logic is overly restrictive, preventing the use of valid absolute or relative paths that point outside the Modelfile's directory.
  • The validation for DIR_TAR paths can incorrectly reject valid paths.
  • A long conditional statement for path type validation could be refactored for better readability.

My detailed comments provide specific suggestions to address these points. Overall, this is a solid contribution that will significantly enhance the package command.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • The new applyModelfile helper doesn’t appear to be invoked anywhere in the command flow, so Modelfile directives may never actually be applied; consider wiring it into RunE (or equivalent) before the options are validated/used.
  • The normalizePath logic currently rejects any path that resolves outside the Modelfile’s directory (via the filepath.Rel check), which conflicts with the stated support for absolute paths and may unnecessarily block legitimate absolute locations; consider either relaxing this constraint or scoping the traversal check to only disallow .. in relative paths.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new `applyModelfile` helper doesn’t appear to be invoked anywhere in the command flow, so Modelfile directives may never actually be applied; consider wiring it into `RunE` (or equivalent) before the options are validated/used.
- The `normalizePath` logic currently rejects any path that resolves outside the Modelfile’s directory (via the `filepath.Rel` check), which conflicts with the stated support for absolute paths and may unnecessarily block legitimate absolute locations; consider either relaxing this constraint or scoping the traversal check to only disallow `..` in relative paths.

## Individual Comments

### Comment 1
<location> `cmd/cli/commands/package.go:673-682` </location>
<code_context>
+
+// normalizePath resolves relative paths relative to the Modelfile's directory and cleans them.
+// Rejects path traversal attempts.
+func normalizePath(path, baseDir string) (string, error) {
+	if !filepath.IsAbs(path) {
+		path = filepath.Join(baseDir, path)
+	}
+
+	abs, err := filepath.Abs(path)
+	if err != nil {
+		return "", err
+	}
+
+	cleanPath := filepath.Clean(abs)
+	// Extra security: reject any '..' segments after normalization
+	rel, err := filepath.Rel(baseDir, cleanPath)
+	if err != nil {
+		return "", err
</code_context>

<issue_to_address>
**🚨 suggestion (security):** Consider normalizing `baseDir` to an absolute, cleaned path before calling `filepath.Rel`.

`normalizePath` converts `path` to an absolute path, but `baseDir` may still be relative (e.g., if `opts.modelfile` was relative). Using a relative `baseDir` in `filepath.Join` and later `filepath.Rel` makes the traversal check dependent on the current working directory and can yield unexpected `Rel` results or errors. Normalizing `baseDir` with `filepath.Abs`/`filepath.Clean` first would make the traversal check more reliable and independent of CWD.

Suggested implementation:

```golang
	// normalizePath resolves relative paths relative to the Modelfile's directory and cleans them.
	// Rejects path traversal attempts.
	func normalizePath(path, baseDir string) (string, error) {
		// Normalize baseDir to an absolute, cleaned path so checks are independent of CWD.
		baseAbs, err := filepath.Abs(baseDir)
		if err != nil {
			return "", err
		}
		baseClean := filepath.Clean(baseAbs)

		if !filepath.IsAbs(path) {
			path = filepath.Join(baseClean, path)
		}

		abs, err := filepath.Abs(path)
		if err != nil {
			return "", err
		}

		cleanPath := filepath.Clean(abs)
		// Extra security: reject any '..' segments after normalization
		rel, err := filepath.Rel(baseClean, cleanPath)
		if err != nil {
			return "", err
		}

```

If there are any other callers that construct `baseDir` assuming it is relative to the current working directory, those assumptions are now explicitly enforced by `filepath.Abs(baseDir)` inside `normalizePath`. No further code changes should be required, but it may be worth double‑checking any tests that rely on the previous, CWD-dependent behavior.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@Pnkcaht
Copy link
Contributor Author

Pnkcaht commented Feb 4, 2026

Since I'm working on other issues, I haven't added the optional elements I mentioned in the description yet. However, I will add them and submit a new PR or update this one if it's not merged. The code needs to be perfect, so if you find any errors, even the smallest ones, please let me know. Thank you.

Signed-off-by: pnkcaht <samzoovsk19@gmail.com>
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds excellent support for using a Modelfile to configure the docker model package command. This greatly improves the user experience by allowing for centralized, reusable model packaging configurations. The implementation is robust, correctly handling path resolution, prioritizing CLI flags, and including important security checks for path traversal. The code is well-structured, with clear separation of concerns into helper functions. My review focuses on a few minor areas for improvement to align with common Go idioms and enhance maintainability, such as defining static data at the package level and improving an error message for better user feedback. Overall, this is a well-executed and valuable addition.

@ericcurtin
Copy link
Contributor

ericcurtin commented Feb 4, 2026

Since this has heavy influence from Ollama, I propose docker model create.

About the point on working on many issues. If you want to pursue this, you need to actively own it. That means every bug, issue, concern etc. must be promptly addressed by you (and you have to strive to keep up with Ollama syntax). If you need this feature and have the capacity to own this indefinitely, please continue.

@Pnkcaht
Copy link
Contributor Author

Pnkcaht commented Feb 4, 2026

understand the ownership concern and I’m comfortable actively maintaining this feature — addressing bugs, feedback, and keeping the behavior aligned where appropriate.

I’m already a regular contributor across other CNCF/Docker-related projects (like MCP and Cagent), and I intend to apply the same level of care here. I’m happy to iterate on naming (docker model create vs the current approach) and scope to better fit the project direction.

If at any point this feature no longer aligns with the roadmap, I’m open to adjusting or narrowing it accordingly. Let me know what level of scope and ownership you’d be comfortable with for merging this.

Signed-off-by: pnkcaht <samzoovsk19@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for Modelfile

2 participants