Running multiple emacs daemons
I have been using Emacs for several years, and these days I'm using it both for writing code and for working with my email (another post on that soon).
As commonly suggested, I run Emacs in daemon-mode to keep things fast and snappy, with an alias to auto-start the daemon if it's not started, and connect to it if started:
But, this has some problems:
- The buffers for email and code projects get mixed together
- Restarting the emacs server for code (for example) kills the open mail buffers as well
- Emacs themes are global β they cannot be set per frame. For code, I prefer a dark theme (most of the time), but for email, a light theme works better for me (specially for HTML email).
To solve this, I searched for a way to run multiple emacs daemons, selecting which one to connect to using shell aliases, and automatically setting the theme based on the daemon name. Here's my setup to achieve this:
Custom run_emacs function in zshrc:
This function takes an optional argument β the name to be used for the daemon. If not provided, it uses default
as the name. Then, it tries to connect to a running daemon with the
name. And if it's not running, it starts the daemon and then connects to
it. It also passes any additional arguments to emacsclient
.
Custom aliases in zshrc:
The first 3 aliases use the default
daemon. The last one creates a new frame in the mail
daemon and also uses emacsclient
's -e
flag to start notmuch (the email package I use in Emacs).
Emacs config:
This checks the name of the daemon passed during startup, and sets the doom theme accordingly. The same pattern can be used to set any config based on the daemon name.
Note that I'm using doom emacs, but the above method should work with or without any framework for Emacs. Tested with Emacs 27 and 28.
Interactions
I've just found that
if ! emacsclient -s ${server_name} "${@:2}";
doesn't always 'do what I want it to' (i.e. returntrue
on exit), especially when I've entered with no arguments. I changed to usingpgrep
, based partially on something in emacswiki, with a zsh alias using pgrep containingI used to start runit from my .xsession, which would then run the WM, gpg/ssh agents, etc as services, auto-restart them on crash (very useful for WM development), and so on. I remember trying to get either the emacs server or the gpg agent (one or both was misbehaving, can't recall now), to work in this scenario, but at the time there was no way to start a headless server without forking into the background.
runit makes the kinds of scenarios OP describes trivial, given the software in question doesn't go the extra mile to make it harder. The ssh agent will for example allow you to use a named pipe in your home directory rather than a random one in /tmp, which would make it trivial to run two (or twenty) instances. Service instances are trivial to create with symlinks: have a look at how Void Linux spawns getty to get the idea.
I no longer use this setup because while robust, it was difficult to set up on a new machine (too much shell glue), and I switched from Linux to Mac & OpenBSD at some point. Perhaps it'd make sense to package and distribute it somehow, because ultimately it was really good, and I wish X11 desktops handled sessions this way.