Ellama with a custom OpenAI-compatible endpoint
Ellama is the Emacs package that talks to language models without leaving the editor, and it does not implement any provider itself. It delegates to the llm Emacs library, which is why the configuration looks less like a list of settings and more like a Lisp expression.
That indirection is the feature, one interface, many backends, and it is also where the only important decision is made. Ellama does not take a URL. It takes a provider object, and the constructor you call decides both the URL and the request shape.
https://aicomp.ai/v1).
Create one free →
Two constructors that differ by one word
The llm library exposes several constructors, and the two that matter here are easy to confuse:
| Constructor | What it targets |
|---|---|
make-llm-openai | OpenAI's own endpoint |
make-llm-openai-compatible | any endpoint speaking the OpenAI chat format |
The names differ by one word and the resulting behaviour differs entirely. Assign the first one and your requests go to OpenAI's servers no matter what URL you supply, because that constructor's job is to know the provider rather than to accept it. Assign the second and you supply the host, the key and the model explicitly.
The failure is quiet in a specific way: a missing or wrong credential against OpenAI produces an authentication error that reads like a key problem, and the variable you meant to set (the gateway address) is simply not consulted.
The provider object carries all three values
The compatible constructor takes the pieces a gateway needs, and they are all set in one expression:
:url, the endpoint, including the version segment:key(the credential), typically read from an auth source rather than written literally:chat-model— the identifier the endpoint expects on the wire
Reading the key from an auth store is the idiomatic approach and also the one that avoids the class of problem where a key is set, non-empty and wrong because it was written with quoting that survived into the value.
For a private endpoint the key still has to be non-empty, even when the server does not check it. That is a library requirement rather than authentication, and a placeholder is the normal answer.
One default provider, plus an alist of named ones
Ellama separates the default from the set you switch between:
ellama-provideris what a plain invocation uses.ellama-providersis an alist of named providers, which the provider-selection command cycles through.
Setting only the default is fine until you want to compare two models, at which point you need the alist and a name for each entry. Adding entries to the alist does not change the default, and that mismatch, a configured provider that never gets used, looks like a configuration that failed to load.
Sessions write to disk, and the default directory can bite
Ellama saves conversations, and the storage location defaults to somewhere inside your Emacs configuration tree. In a distribution that keeps its config in a format Emacs also tries to parse (the common case being an org-based config directory) the session files land in a directory that the editor then reads, and the result is a hang on startup rather than an error message.
Pointing the sessions directory at a cache location outside the config tree removes the problem entirely. It is a one-line change that is much harder to diagnose after the fact, because the symptom appears in the editor rather than in Ellama.
Agent loops read project instructions
Ellama also runs multi-step agent loops: plan, call tools, read project context, continue from the previous turn. Those loops load instructions from a project file and can invoke reusable prompts, and tool calls are subject to a policy layer that can block reads, writes and shell commands.
That matters for cost more than for correctness. An agent loop resends its context each turn and appends tool output, so the input column grows with the length of the task rather than with the size of the prompt.
What a chat-and-agent editor costs
This is a mixed workload: conversational commands, one-shot transformations over a buffer or region, and the occasional multi-step loop.
A working month runs about 150k input and 45k output tokens a day, which is 3M input and 0.9M output over 20 working days. The output share is higher than a pure completion plugin's, because a chat session produces prose rather than a short insertion.
| Model | Gateway rate in / out per 1M tokens | One day | 20 days |
|---|---|---|---|
| deepseek-v4-pro | $0.66 / $1.98 | $0.19 | $3.76 |
| claude-sonnet-5 | $1.00 / $5.00 | $0.38 | $7.50 |
| qwen3.8-max | $1.00 / $3.00 | $0.29 | $5.70 |
| gpt-5.6-terra | $1.00 / $6.00 | $0.42 | $8.40 |
One day = 150k input + 45k output on this page's workload. 20 days = 3M input and 0.9M output. Rates checked 2026-10-15, gateway rates move with upstream promotions, so verify the current number in your dashboard before committing to a budget.
Mixing a cheap model for buffer transformations with a stronger one for sessions is the usual pattern here. The <a href="/guides/cheapest-models-by-workload/">re-ranked index</a> sorts by workload shape rather than by input price, which is the comparison a mixed client actually needs.
FAQ
FAQ
Does Ellama support any OpenAI-compatible endpoint?
Yes, through the llm library's compatible constructor, which takes an explicit URL, key and chat model. It is not tied to OpenAI or to Ollama, even though those are the two configurations most examples show.
Why does Ellama ignore the URL I set?
Most often the wrong constructor. make-llm-openai targets OpenAI's own endpoint and does not accept a custom host; make-llm-openai-compatible does. The two names differ by one word.
Can I keep several endpoints configured at once?
Yes — ellama-providers is an alist of named providers that the selection command cycles through, while ellama-provider sets the default. Adding to the alist does not change the default.
Does a local endpoint need an API key?
The value has to be non-empty for the client to construct, but a local or unauthenticated server will not check it. A placeholder is expected rather than a misconfiguration.
Why does Emacs hang after I use Ellama?
Check where sessions are written. The default sits inside the configuration tree, and a config directory that Emacs also parses can turn saved session files into a startup hang. Moving the sessions directory out of the config tree resolves it.
Related
- Tools that take one endpoint — the full matrix of clients and how each one names the endpoint
- Base URL not working, the doubled-path failure, which the version segment in
:urlavoids - OpenAI-compatible endpoints — the request shape the compatible constructor targets
- Twinny with a custom endpoint — the other editor integration where two slots behave differently
- CodeCompanion with a custom endpoint (the Neovim counterpart), configured through Lua rather than Lisp
- Official vs gateway prices — how the two price columns on this site are measured