parllama measures coverage on one module and declares pydantic twice
TUI for Ollama and other LLM providers
At a glance
- What is it?
- paulrobello/parllama is a terminal interface for Ollama and cloud model providers, built on Textual and Rich. Its own repository files say the most about it: the coverage target measures a single secrets module, the manifest lists both pydantic and its core alongside two HTTP clients, the Makefile still exports a pipenv variable in a uv project, and the newest release is nearly three months behind the last commit.
- Who is it for?
- Use it if you want a keyboard-driven interface over a local Ollama install and several cloud providers in one place, and you are willing to live with a template execution feature that runs code from an allowlist. Do not treat its quality signals as evenly distributed, because the one automated measurement in the build covers the secrets module rather than the interface.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 37 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 10, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Coverage is measured on the secrets manager and nothing else
The Makefile has a test target and a coverage target, and the coverage target names one module:
coverage:
$(run) pytest --cov=parllama.secrets_manager --cov-report=term-missingSo the automated measurement of how much of the code the tests exercise is scoped to the secrets manager. That is the single most security-sensitive module in a tool whose whole job involves holding API keys for eight providers, and measuring it in isolation is a defensible choice. It is also the only place the number is taken, which means the interface layer, the provider integrations, the session store and the template execution engine are all unmeasured by that command.
The rest of the tool configuration is broader. There is a separate type checker configuration, a separate test runner configuration, and a separate lint and format configuration, plus a pre-commit hook file and a lock file. A project with three analysis tools and a lock file usually reports a coverage figure somewhere, and here the figure that gets reported is the one for a single file.
That does not make the tests bad. It makes the coverage number mean something much narrower than a reader is likely to assume, which is worth knowing before treating it as a quality signal.
The manifest declares pydantic twice and carries two HTTP clients
The dependency list has a redundancy worth naming. The validation library is declared, and its own compiled core is declared next to it as a direct requirement with its own floor. That library already depends on its core, so pinning the core independently constrains the resolver to satisfy two constraints where one would do, and it is the shape that produces a resolution failure when the two floors disagree.
The same list also declares a modern HTTP client and the older requests library, so the project has two ways to make an outbound call. A third arrives transitively, because the multi-provider router in the list does its own HTTP work.
Then there are the four heavyweight framework entries. One is a local runtime client, one is a multi-provider router, one is an application framework for building model pipelines, and one is the Docker client. Four separate ways to reach a model, in a program whose stated purpose is to put a terminal interface in front of them. Each is individually defensible, since a router and a local client cover genuinely different backends, but the interface layer is then choosing between four abstractions rather than one.
The remaining entries are ordinary: an HTML parser, an image library, a time-zone library, a humanised-time formatter, a semantic-version parser, a terminal file picker, dotenv loading, rich console output and the Textual toolkit itself, all with floors and no upper bounds.
The Makefile exports a pipenv variable in a project built on uv
The build file defines its commands as variables and then routes every one of them through a single runner, which is tidy. It also exports an environment variable that belongs to a different package manager entirely, setting a pipenv verbosity flag to a quiet value in a project whose runner is uv and whose installer is uv.
The line is harmless at runtime, because pipenv is not installed and nothing reads the variable. It is a leftover, and leftovers like this are cheap to carry and easy to misread, since a variable named for one tool appearing in another tool's build is exactly the kind of thing that makes someone debug the wrong thing.
There is a second leftover right above it: a commented-out line that would set a link mode for the runner that is not currently used. Both lines sit in the preamble, before any target, so they are easy to skim past.
The targets themselves are mostly conveniences around the runner: help, clearing the cache, restoring defaults, the terminal toolkit's own key tester, border and colour sample displays, a console, and a dev mode that launches the toolkit in development. Two are Windows-under-Linux-specific and both point the application at a model server on the other side of the boundary by constructing a URL from the machine's dot-local hostname and the local runtime's default port, which is a neat trick that depends on name resolution working.
The screenshots section is one sentence and the only video is six versions old
The table of contents promises a screenshots section, and the section that exists contains a single sentence saying dark mode, light mode and custom themes are supported. There are no images in it.
For an interface-first tool that is a real gap. The feature list spends considerable space on things only a picture can settle: rubber-band overscroll, blurred page transitions, a springy navigation puck, frosted chrome that samples what is behind it rather than tinting it, and adaptive colours pulled from the current artwork. None of that can be judged from prose.
The videos section fares no better. It holds one link, labelled as the version 0.3.5 demo. The current release line is 0.9.2, so the only moving image attached to this project predates the current version by six minor releases and whatever changed in them.
The rest of the documentation is unusually thorough, which makes these two omissions stand out. The contents list runs to about thirty-five entries covering three separate quick-start workflows, a secrets vault, a configuration reference held in a separate document, remote instances, Windows under Linux, custom prompts, a memory system, template execution, themes, a help screen held in the source tree, a contribution guide, a FAQ and a roadmap with separate current and future sections. Two badge links to the package index sit side by side with identical destinations and no text, and a single donation link sits below the description.
Quantizing an already quantized model is a documented error
Model quantization gets the clearest error documentation in the whole project, and it is worth quoting the shape of it. The local runtime's own create-model interface accepts a quantization level, with two named examples given to reduce size and memory. The important caveat follows immediately: native quantization only works on a full-precision base model, in either single or double precision form. Attempting to quantize a model that is already quantized returns an error, and the example given is a small popular model that ships already quantized.
That is a genuinely useful piece of documentation, because the failure is otherwise confusing, since the operation looks identical in both cases.
The route for models that are not available through the local runtime is where the dependency list grows. You are told to download a downloader from the releases area of a separate project, install Docker Desktop, and then pull a published container image:
docker pull ollama/quantizeSo converting a Hugging Face model costs you a third-party binary fetched from a releases page, a desktop container runtime on your machine, and a network pull, before any quantization happens. None of that is a problem to have; it is simply three dependencies outside the tool that the one-line description does not mention.
The install path pipes a script into a shell and the last line stops mid-word
Installation is presented as a set of alternatives through the uv tool ecosystem, and there are four of them: install the tool from the package index, run it without installing, install from the GitHub URL, and upgrade an existing installation with an upgrade flag combined with a force flag. Before any of that, the bootstrap is a single line that downloads an install script and pipes it into a shell:
curl -LsSf https://astral.sh/uv/install.sh | shThat is the standard way to install that tool and it is worth naming rather than hiding, because it is the step with the least review and the widest effect, and it runs before the project installs anything.
Two things about the surrounding documentation are uneven. The contents list offers both a pipx section and a uv section as separate install paths, while the visible part of the page shows only the uv variants, so the contents and the body disagree about how many installers exist. And the final visible command in that sequence is cut off in the middle of a word, so the upgrade instruction a reader reaches last is incomplete.
The Windows notes are good, incidentally. Where the project needs a POSIX-style tool on Windows, it says so and names a package manager that installs it, both for the interpreter and for the make command that contributors need.
Three agent instruction files, four Python versions, no release in twelve weeks
The repository root carries three dot-prefixed directories for coding agents and three matching instruction files at the top level, one per agent, alongside a general agent file. So the same onboarding guidance is maintained in six places for tools that read different filenames. That is a real maintenance cost with no compensating benefit for anyone who does not use those agents, and it is the kind of thing that drifts quietly because nobody notices when one copy stops matching.
Alongside them sit a design document, three separate analysis configurations as noted earlier, a test configuration, a hook configuration, a lock file, and a make-driven wrapper around the runner.
The version story is the part with a date on it. The newest release is 0.9.2 from early July, with 0.9.1 and 0.9.0 cut ninety-six minutes apart on the same evening five days earlier. The last commit to the default branch is in early September. So there has been no release in roughly twelve weeks while the branch moved, and the contents page's own release section stops at the same July version. The manifest is marked as a beta, and its version field is declared dynamic, which means the number comes from the tag rather than from a file anyone edits.
Whether that is a deliberate slow-down or a stalled release process is not stated. A tool that stores sessions, prompts and an encrypted key vault is the kind of project where twelve weeks of unreleased changes on the default branch is worth a question before you upgrade.
Editorial conclusion
Use it if you want a keyboard-driven interface over a local Ollama install and several cloud providers in one place, and you are willing to live with a template execution feature that runs code from an allowlist. Do not treat its quality signals as evenly distributed, because the one automated measurement in the build covers the secrets module rather than the interface. Before you install, check three things: that your Python is 3.11 or newer and that Ollama is already running, since both are prerequisites rather than bundled; that you read the template execution and secrets sections before pointing it at a real API key; and that you accept four overlapping model frameworks as dependencies, since the resolver will pull all of them before the interface starts.
Frequently asked questions
What is parllama?
A terminal user interface for Ollama and other language model providers, built with Textual and Rich plus the author's separate core library. It needs Python 3.11 or newer and an existing Ollama install, and it runs on Windows, Windows under Linux, macOS and Linux.
Does parllama work with cloud providers as well as Ollama?
Yes. The feature list names Ollama alongside OpenAI, Anthropic, Groq, xAI, OpenRouter, DeepSeek and a multi-provider router, and the documentation has separate quick-start sections for an Ollama chat workflow, an image chat workflow and an OpenAI provider chat workflow. Providers can be enabled or disabled and their keys and endpoints managed from inside the app.
Can parllama quantize models?
Two paths. Ollama's own create-model interface accepts a level such as q4_K_M or q5_K_M, and that only works on a full-precision base model, so quantizing an already quantized model returns an error. For models from HuggingFace the documented route needs a third-party downloader, Docker Desktop, and a pulled container image.
How do I install parllama?
With the uv tool installer in one command, or without installing at all through uvx, or from the GitHub URL, and an existing installation is upgraded with the same tool using an upgrade and force flag. The bootstrap step for that installer is itself a command that pipes a downloaded script into a shell.
How does parllama handle API keys and memory?
Keys are managed through a secrets vault documented as its own section, backed by a dedicated secrets manager module that is the one module the project's coverage target measures, and by a cryptography dependency. A separate memory system keeps persistent user context across conversations and updates it using a model.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/paulrobello-parllama)