Skip to content

Add llamanager plugin - #171

Merged
ItsLemmy merged 10 commits into
noctalia-dev:mainfrom
marccvictoria:add-llamanager
Aug 1, 2026
Merged

Add llamanager plugin#171
ItsLemmy merged 10 commits into
noctalia-dev:mainfrom
marccvictoria:add-llamanager

Conversation

@marccvictoria

Copy link
Copy Markdown
Contributor

Plugin

  • Id: marccvictoria/llamanager
  • New plugin
  • Update to an existing plugin (version bumped in plugin.toml)

What it does

Provides graphical interface for managing local Ollama models, and running queries directly from the launcher.

External dependencies

  • ollama: Used for managing models (ollama list, ollama create, ollama rm, ollama run, ollama --version).
  • Network requests are made only to the local Ollama HTTP server (http://localhost:11434) to retrieve runtime information and download models via /api/ps and /api/pull.

Testing

  • Opened the panel and verified all views render correctly.

  • Used the /ll launcher provider to execute prompts with the configured default model.

  • Downloaded existing models and verified progress notifications, completion handling, and automatic model list refresh.

  • Attempted to download non-existent models and verified error handling.

  • Deleted installed models and verified successful removal and handled failure cases.

  • Created, edited, and deleted modelfiles from the configured Modelfile directory using the modelfile editor.

  • Built custom models from modelfiles using ollama create and verified they appeared in the model library.

  • Tested on Niri

  • Tested on Hyprland

  • Tested on Sway

  • Tested on another compositor:

  • Noctalia version tested against: v5.0.0

  • Plugin API level: 4

Screenshots / Videos

panel

Checklist

  • The directory name matches the part of id after the / in plugin.toml exactly.
  • It ships plugin.toml, README.md, thumbnail.webp, and translations/en.json.
  • README.md follows the
    README template, documents
    every entry id and dependency, and includes exact panel IPC commands and launcher prefixes where applicable.
  • I created thumbnail.webp with the thumbnail generator.
  • version follows semver and is bumped in this PR; plugin_api is the oldest API level this plugin requires.
  • Every non-English translation in this PR uses a locale supported by Noctalia core, and I can read, write, and
    understand that language well enough to review and maintain it (no unreviewed machine/LLM translations).
  • I did not edit catalog.toml; CI generates it.
  • This PR touches exactly one plugin directory.

Code review attestation

Plugins run as trusted, unsandboxed Luau in the user's session. Confirm:

  • The code is readable and not obfuscated, minified, or generated.
  • It does not download and execute remote code.
  • Every network call, filesystem write, and spawned process is something the description above accounts for.
  • I have the right to publish this code under the license declared in plugin.toml.

@ItsLemmy

ItsLemmy commented Aug 1, 2026

Copy link
Copy Markdown
Contributor
  1. blocking - llamanager/registry.luau:283
    Modelfile paths are built by bare concatenation with no path separator:
    modelfilePath .. <name> .. ".modelfile". The same construction appears at
    llamanager/registry.luau:288, llamanager/registry.luau:299, llamanager/registry.luau:311,
    llamanager/panel.luau:64 and llamanager/panel.luau:278.

    modelfile_path is declared as type = "folder" in llamanager/plugin.toml:15, so its value comes from Noctalia's folder picker, which returns a directory path with no trailing separator (the dialog accepts either the selected entry's absolute path or the current directory).
    noctalia.expandPath only expands a leading ~; it does not append a separator.

    With a browsed value of /home/u/ollama_models and a name of foo, every operation resolves to /home/u/ollama_modelsfoo.modelfile. Create writes the file into the parent directory, the editor listing (llamanager/registry.luau:155) still lists the real directory so the file never appears, and edit, delete and "Load into Ollama" all miss. The whole Modelfile Editor feature is non-functional for the documented setup flow.

    This is masked in the submitted demo: assets/panel.gif shows Modelfile Path: /home/marc/ollama_models/, a manually typed value with a trailing slash. Joining with / when the configured directory does not already end in one fixes it.

  2. non-blocking - llamanager/registry.luau:164
    string.format('ollama create "%s" -f "%s"', modelName, modelfilePath) and
    string.format('ollama rm "%s"', modelName) at llamanager/registry.luau:183 are passed to noctalia.runAsync, which executes the string through /bin/sh -lc. modelName is the free text of the "Modelfile Name" input (llamanager/panel.luau:57), so a name containing a double quote, backtick or $(...) breaks out of the quoting and is executed as shell.

    The value is only ever typed by the local user into their own panel, so this is not remotely reachable and there is no sign of intent. It is still unsafe interpolation and should be escaped or moved to an argument-vector invocation.

  3. non-blocking - llamanager/registry.luau:155
    noctalia.listDir returns nil, "not a directory" when the path is missing or unset. With the default empty modelfile_path, ipairs(listDir) on line 157 raises, the state-watch callback aborts before the view switch on line 273, and the "Open Editor" button silently does nothing with no feedback. A nil check with a notification would make the misconfiguration visible.

  4. non-blocking - llamanager/assets/launcher.gif
    launcher.gif is 13.7 MB and panel.gif is 7.5 MB. Combined they are 21 MB, roughly ten times the largest existing asset in the repository (claude-companion/assets/question.gif at 2.1 MB) and larger than the rest of the repository's images put together. Consider trimming, reducing frame count or resolution, or linking the recordings from the PR description instead.

  5. non-blocking - llamanager/README.md:60
    The README states Modelfiles use the suffix .modelfiles, but the code writes and reads .modelfile (llamanager/registry.luau:283). Users following the README will name files that the plugin cannot find.

  6. non-blocking - llamanager/llamanager.luau:1
    launcherModel = noctalia.getConfig("launcher") is read once at script load and is a global rather than a local. Changing the launcher model setting has no effect until the plugin is reloaded.

@ItsLemmy
ItsLemmy marked this pull request as draft August 1, 2026 02:49
@marccvictoria

Copy link
Copy Markdown
Contributor Author

done fixing it now

  1. added a helper that joins the directory and filename regardless of whether the configured path has a trailing
  2. i escaped arguments that are passed to field to treat them as literal strings
  3. i just prevented the Modelfile Editor from opening when the Modelfile path is unset, but i also added validation inside edit()

@marccvictoria
marccvictoria marked this pull request as ready for review August 1, 2026 10:33
@ItsLemmy
ItsLemmy merged commit f228731 into noctalia-dev:main Aug 1, 2026
1 check passed
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.

2 participants