# s-kostyaev/ellama: the build compiles by glob and ignores the dependency order it declares, the parity test runs Docker privileged, and one policy file removes the tool confirmations

> An Emacs Lisp package that puts local and cloud language models into Emacs through the separate llm package, with chat, one-shot commands over a buffer or region, saved and compacted sessions, and agent loops that can read buffers, files, directories, Info nodes, images and audio as context. The security story is a data-loss-prevention module, edit hooks and a block on irreversible actions, with one settings file that switches the per-action confirmation model off.

**s-kostyaev/ellama** — Work with local and cloud LLMs from Emacs.

- Repository: https://github.com/s-kostyaev/ellama
- Stars: 961 · Forks: 65
- Language: Emacs Lisp
- License: GPL-3.0
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/s-kostyaev-ellama

## The build compiles by glob and ignores the dependency order it declares

The Makefile opens by defining a variable listing ten source files in what its own comment calls an order based on the packages dependency graph. The first entry is the data-loss-prevention module, then the tools module, then skills, then the main file, then evaluation, context, transient menus, blueprints, community prompts and the manual. The build recipe then ignores that variable. It ends by handing byte-compile a shell glob over the source files, which means the files are compiled in whatever order the shell sorts them into, and a shell sorts them alphabetically, putting the main file last. So the declared order and the compiled order are not the same sequence, and the recipe gives no hint that the variable is there. Whether that matters depends on whether any of those files need another to be byte-compiled, which the comment implies the author believed. Either the glob happens to work because the macros resolve at runtime, or the variable is left over from an earlier recipe.

## The build loads your init file and the tests do not

Two recipes invoke Emacs in batch mode and the difference between them is one flag. The detailed test target passes a clean-start flag, so it starts with no user configuration, adds the current directory to the load path, and loads the main file followed by a hand-written list of test files. The build target passes no such flag, so it starts Emacs with whatever init file the developer happens to have. That is an asymmetry with a real consequence: the test run is hermetic and reproducible on any machine, while the byte-compilation result depends on the packages and advice already loaded on the machine doing the compiling. Both recipes also go out of their way to filter the load path, removing any entry matching a versioned Org directory in the installed package store, which stops a locally installed Org from shadowing the one either recipe intends. That care about one specific shadowing source, combined with an unfiltered init file in the build, is a slightly uneven level of paranoia.

## Twenty-one make targets, ten of which check files rather than behaviour

The phony list has twenty-one entries and the distribution across them is the interesting part. Eight are checks: compile warnings, the Lisp sources, the readme, the news file, custom variables, commands, duplicate keys in the transient menu, and copyright headers. Two more refill the readme and the news file from somewhere, which is how an Org document stays in step with the code. Three concern the sandbox parity suite, including one that builds a container image locally and one that runs it on Linux specifically. What is left is the build, three test variants, a formatter, a manual target, a documentation check and a hook installer. The three checks worth naming are the ones that guard against drift specific to this kind of package: a custom-variable check catches a documented option that no longer exists, a duplicate-key check catches a transient menu where two bindings collide, and a copyright check catches the header requirement that a package archive imposes.

## The parity test runs its container with the privileged flag

Three of the make targets are about a sandbox parity suite, and they are configured through three overridable variables rather than being hard-coded. The image name defaults to a local tag ending in the mutable word latest. The Dockerfile path points at a file in the docker directory with linux in its name. And the run flags default to removing the container afterwards and running it privileged. That last default is the one to notice. A privileged container has far more access to the host than an unprivileged one, and the flag is a reasonable setting for a sandbox-conformance test that needs to observe syscall or namespace behaviour, which is exactly the kind of test this project is running. It is also the default every contributor gets from typing make. The three variables exist so the setting can be changed, and the visible documentation does not mention them.

## One policy file removes the tool confirmation prompts

The agent setup function is where the security model lives, and the documentation of it is unusually precise. Called with no arguments it enables every tool, enforces the data-loss-prevention checks, blocks irreversible actions and lengthens the agent loops. Called with a path to a policy settings file, the comment describes a different profile: normal tool confirmations are skipped, ordinary data-loss-prevention input findings are allowed rather than asked about, output findings are redacted, and irreversible actions are still blocked. So the policy file does not weaken everything, and the one control it cannot switch off is the block on irreversible actions. What it does remove is the per-action prompt, which is the difference between a loop that stops and asks and one that runs to the end of its checklist. That is a defensible design for long unattended runs, and it means the security of that run is the security of the policy file.

## The agent reads instructions from a file inside the repository it is working in

For tool-using agents, the package reads project instructions from a file the project convention puts at the repository root, and it can load reusable skills and blueprint prompts alongside them. Context is described as first-class, and a request can include buffers, files, directories, Info nodes, selections, images and audio files. Read those two facts together and the trust boundary is visible. The instruction file lives inside the working tree, so it arrives with a clone, and a clone is exactly how most people acquire code they did not write. The context mechanism accepts a whole directory. The documented safeguards act on what the agent does rather than on what the agent reads: filesystem checks, edit hooks and data-loss-prevention scans that can block or warn on reads, writes, shell commands and tool output. A separate module sits at the root for evaluation and is not described in the visible command list, which is the other place worth reading before enabling tools.

## Auto-scrolling means advising two core functions

The recommended configuration block is short, and four of the lines change behaviour beyond adding a keybinding. There is a key bound to the main entry point, a hook that sends the last message when a specific org-mode key sequence is pressed, an option that turns on automatic scrolling, and two header-line global modes, one for context and one for the session, both enabled. The scrolling option is the interesting one, because the optional settings block shows what it takes: two advice definitions, one added before the precision pixel scroll function to disable it and one added after the end-of-buffer function to re-enable it. So the advertised auto-scroll feature is implemented by advising two built-in Emacs functions, and the documentation prints the advice forms rather than hiding them. The same block also sets an output language, an automatic session-naming scheme driven by the model, and two separate display hooks, one that shows the chat buffer in a full frame and one that puts instant output at the bottom.

## Eleven source files at the root, and no package declaration among them

The whole project is flat at the repository root, which is the right shape for a package archive: eleven Lisp files, each named after the feature it provides, covering tools, the data-loss-prevention module, skills, context, evaluation, transient menus, blueprints, community prompts, the manual and the main entry point, plus a Texinfo manual and a licence fragment. What the file list does not show is a package declaration file, which is the file that tells the package manager where to get the dependency the project needs. The dependency is real and central, since the whole provider layer is the separate llm package rather than something written here, and the badges at the top of the readme point at three different archives: the standard one, a community one and a stable snapshot of that community one. Installing is a single command through the package manager. Confirm for yourself how the dependency is declared, because that is the one piece of the layout this listing does not account for.

## Conclusion

This is a mature Emacs package rather than a weekend integration, and the evidence is in the consistency tooling rather than in the feature list: eight of the twenty-one make targets exist to catch documentation drifting away from the code, which is the failure mode Emacs packages actually suffer from. Three things to check before you turn on the agent loops. Ellama reads project instructions from a file inside the repository it is working in, and it can be pointed at a whole directory as context, so a repository you did not write contains instructions and data the loop will act on; read the file before you run the loop, not after. Supplying an srt settings file removes the per-action tool confirmations, which is the difference between asking you every time and trusting a policy document, so read that file as carefully as you would read a prompt injection. And the parity test target runs its container with the privileged flag by default, so do not run the full make suite on a machine where that matters. For chat, translation, summarisation and one-shot questions over a region, the defaults are conservative and the provider layer is the separate llm package, which is the right place for that abstraction to live.

## FAQ

### What does ellama need to work with a model?

The separate llm package, which provides the provider layer. Ellama is not tied to one backend: the same commands are configurable for OpenAI-compatible endpoints, OpenAI, Claude, Gemini, Vertex, GPT4All and LlamaCpp, and a local Ollama model works. By default Ellama uses the first available Ollama model, and providers that offer extra capabilities get streaming, model lists, image and audio input, tool calls, token limits and interactive model switching.

### How do I install ellama?

From the standard package archive, with a single package-install command entered in Emacs. The readme carries badges for three archives, the standard one, a community one and a stable snapshot of it. The whole install is short enough to state in full, and it is written as a source block in the original document.

### What does the agentic coding setup actually enable?

Calling the setup function with no arguments enables all tools, enforces data-loss-prevention checks, blocks irreversible actions and uses longer agent loops. Passing a path to a policy settings file changes the profile: normal tool confirmations are skipped, ordinary input findings are allowed, output findings are redacted, and irreversible actions are still blocked.

### What context can an ellama request include?

Buffers, files, directories, Info nodes, selections, images and audio files. Chat sessions can be saved, resumed, renamed, and compacted either by hand or automatically before they run past the model context window. For tool-using agents the package also reads project instructions from the repository root and can load reusable skills and blueprint prompts.

## Sources

- [Issues](https://github.com/s-kostyaev/ellama/issues)
- [License: GPL-3.0](https://github.com/s-kostyaev/ellama/blob/main/LICENSE)
- [README](https://github.com/s-kostyaev/ellama/blob/main/README.md)
- [s-kostyaev/ellama on GitHub](https://github.com/s-kostyaev/ellama)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/s-kostyaev-ellama
