Keybindings
Table of Contents
Emanix runs EWM — Emacs is the Wayland compositor. There is no separate
window manager or status bar: windowing, workspaces, and the top bar all live in
Emacs. Super (a.k.a. s-, the Windows key) is the compositor modifier; C-c /
C-x are Emacs prefixes. Text editing is modal (Meow).
Two routing rules worth knowing:
Super(s-) keys are intercepted by the compositor — they work from any window, including a focused terminal or browser.C-c/C-xare ordinary Emacs bindings — they only register when a native Emacs buffer has focus, not from a Wayland surface (terminal). That is why the global assistant is ons-i, not aC-cprefix.
There is no non-EWM desktop path. Emanix does not ship a standalone window manager, notification daemon or launcher, because EWM is all three.
1. EWM (compositor — Super keys)
1.1. Frame slots (workspaces)
| Binding | Action |
|---|---|
s-1 … s-9 |
Go to / create slot 1–9 on the current output strip (keyed by number — s-3 never conjures 1 and 2) |
s-0 |
Go to / create slot 10 |
s-r |
Rename the current slot (shows in the top bar) |
s-q |
Close the current slot (mirrors Hyprland's killactive) |
s-t |
New frame after the current one |
Slots are generic — no app is tied to a number. Names are session-local; set them with s-r.
1.2. Focus & movement
| Binding | Action |
|---|---|
s-←/→/↑/↓ |
Move focus between frames |
s-Shift-←/→ |
Move the current frame within the output strip |
s-Ctrl-←/→ |
Move the current frame to another output |
s-Ctrl-↑/↓ |
Move the buffer up / down (buf-move) |
s-Tab / s-Shift-Tab |
Cycle surface buffers (next / previous) |
s-f |
Toggle fullscreen for the focused surface |
1.3. Launchers & assistant
| Binding | Action |
|---|---|
s-d |
App launcher (ewm-launch-app) |
s-w |
Firefox |
s-i |
Search arc — the local retrieval-only config index; works from any slot |
1.4. Session & clipboard
| Binding | Action |
|---|---|
s-l |
Lock session (swaylock) |
s-c / s-v |
Copy / paste (kill-ring-save / yank) |
C-c R |
Restart EWM — saves file buffers, then exits so tty1 autologin relaunches |
C-c R is the one session binding that is NOT a Super key: it is deliberately
a C-c chord so a stray Super press cannot end the session, and it only needs
to fire while Emacs has focus. No reboot is needed to restart the
compositor — ewm.nix launches EWM from the tty1 login shell, which waits on
the Emacs daemon and lets getty's autologin log back in when it exits, so
killing the daemon is the restart.
It avoids save-buffers-kill-emacs, which prompts once per modified buffer and
again per buffer with a live process — a long interactive walk on a daemon that
has been up for days. Instead it saves file buffers unattended and calls
kill-emacs. The trade-off: live processes (ghostel shells, running agents) are
terminated without a prompt, so anything unsaved that is not a file buffer is
lost. If the daemon never starts (30s poll) or dies within 15s, the login hook
writes ${XDG_RUNTIME_DIR:-/run/user/$(id -u)}/ewm-flap and the next login
drops to a plain shell; remove it and log out to re-arm.
The top bar — clock, battery, volume/wifi/cpu/ram/gpu, and the slot list — is
rendered in the Emacs tab-bar (emanix-modeline.el, emanix-ewm-slots.el), not
a separate bar. Compositor bindings live in EWM's ewm-mode-map; the Emanix
additions are in the with-eval-after-load 'ewm block of config.el.
2. Config layout: a loader, a config, and a fallback
~/.config/emacs/ holds four top-level files (early-init.el, init.el,
config.el and fallback.el) plus lisp/. The split is a safety boundary,
not organisation:
| File | Role |
|---|---|
init.el |
93-line loader. Loads config.el inside a condition-case. Must never break, so it is rarely edited. |
config.el |
All actual configuration. Free to be edited and to break. |
fallback.el |
Minimum viable desktop, loaded only when config.el fails. |
Why the loader is a separate file. A signal raised inside a load=ed file
propagates to its caller, so =init.el catches two failures that no guard
inside the config could:
- a read-time failure such as an unbalanced paren — nothing in
config.elruns, so nothing in it can catch anything; - a load-time failure such as a
requirethat signals.
Both happened on 2026-08-10 and both presented identically — no top bar, s-d
dead, no window navigation — because Emacs is the compositor here. EWM itself
survived both, since it starts from --eval on the command line, which Emacs
processes after init.
How to tell you are in the fallback. The tab bar shows a red
⚠ CONFIG FAILED item at the far left. For the reason:
emacsclient -e 'emanix/init-error'
nil is a healthy boot. Anything else is the error that aborted config.el.
What the fallback restores: the top bar (emanix/modeline-mode), the
launcher (C-c o), the emanix/ewm-* slot commands and a theme. Not completion,
meow, magit, org or apheleia — recoverable by fixing config.el, and not the
desktop.
Editing caution. config.el is an out-of-store symlink into the checkout
(liveElisp), so an edit is live on the next Emacs start with no rebuild. That
is why the guard is a runtime one: both 2026-08-10 incidents were uncommitted
live edits, which no build-time or pre-commit check would have caught.
Testing it: ./tests/init-guard.sh reproduces both faults against a temp
copy and asserts the desktop survives each, plus that a healthy config is
unaffected.
3. A note on what the distribution supplies
Two bindings on this page cross the line between the distribution and the flake that consumes it, and the split is deliberate rather than an oversight.
C-c p opens the Pi agent as an Emacs buffer, over ACP. The binding and the
glue (emanix-agent-shell.el) are Emanix, as are the adapter wrappers in
agent-acp/; the pi binary is not. An AI harness is not a decision a
distribution should make for you, so Emanix wires the key and leaves the choice
of agent — or of no agent at all — to your own flake. With no adapter installed
the binding reports the missing adapter rather than failing silently.
C-c C-' does the same for Claude, and s-S-<return> reaches it from any slot.
Theme switching works the other way round. emanix/theme-set lives here and
does the work; the dot-theme-set command that calls it is a consumer script.
The distribution owns the mechanism, the consumer owns the entry point. See
Theming.
4. Emacs — modal editing (Meow)
Editing is select-then-act (Kakoune-style): build a selection, then one key
acts on it. Enter insert with i / a; ESC returns to normal.
| Key | Action |
|---|---|
h j k l |
Move (also starts a selection); H J K L extend it |
w / x |
Mark word / select line (press again, or a digit, to extend) |
d / s / c |
Delete / cut / change the selection |
y / p |
Copy / paste |
u |
Undo (U = undo within selection) |
f / t |
Find / till char forward; F = avy 2-char jump anywhere |
, . [ ] |
Inner / bounds / beginning / end of the thing at point |
Q / X |
Go to line |
SPC |
Leader (SPC ? = full meow cheatsheet) |
Config: meow-normal-define-key in config.el. C-c d is Dirvish, not a line
delete — to delete lines use x (select, repeat to extend) then d.
5. Emacs — commands (C-c / C-x)
Work when a native Emacs buffer is focused.
| Binding | Action |
|---|---|
C-c i i |
Search arc across the whole corpus. s-i does the same from any slot. |
C-c i n |
Search arc in the org-roam vault (ARC's vault scope) |
C-c i o |
Search arc in the NixOS and Home Manager options (ARC's options scope) |
C-c i R |
Reindex every collection (async; progress via message) |
C-c i c |
Cancel a running reindex |
C-c z |
Toggle prose rendering (markdown/org rendered vs. raw source) |
M-g i |
Jump to a heading in this buffer (consult-imenu) |
C-c d |
Dirvish (file manager) |
C-c f |
consult-ripgrep (search project) |
C-s |
consult-line (search buffer) |
C-x b |
consult-buffer (switch buffer) |
M-y |
consult-yank-pop |
C-. |
embark-act |
C-x g |
magit-status |
C-c n f / n i / n c |
org-roam find / insert / capture |
C-c a |
org-agenda |
C-c p |
Pi: open a Pi agent shell (ACP) — needs a pi-acp adapter and pi on PATH |
C-c C-' |
Claude: open a Claude agent shell (ACP); C-u prompts for a directory |
C-c r |
Send the region to the agent shell |
C-c C-c |
Confirm / finish (Org, Pi, etc.) |
Fuller personal reference is in the vault notes Emacs Shortcuts, Emacs Command
Map, and Meow (~/docs/org, the default org-roam root).
5.1. Prose rendering for markdown and org
.md and .org files open in emanix-prose-mode: IBM Plex Sans body text,
serif headings, hidden markup that reappears on the line at point, a centered
90-column reading width, and monospace code blocks and tables.
C-c z— toggle back to plain monospace sourceM-g i— jump to a heading (consult-imenu)TAB/S-TAB— fold a section / the whole outline (markdown-mode's own)
Code blocks and tables stay monospace — tables align by character count, so a
proportional font would break them. The code-block background is read from the
active theme's surface0, so it follows a theme switch with no extra config.
Implementation is emacs/lisp/emanix-prose.el.
7. Theme
Theming is driven from Emacs. C-c v flips dark and light
(emanix/theme-toggle); emanix/theme-set applies a named theme and is the
authority for a switch. The dot-theme-set and dot-theme-toggle commands are
consumer scripts that reach the same mechanism. See
Theming.
8. Ghostty
Ghostty is configured from home/ghostty.nix (written to
~/.config/ghostty/config). It clears the stock keybinds (keybind = clear)
and adds Emacs-style clipboard bindings — super+c / super+v and alt+w /
ctrl+y. Everything else is built-in; see
Ghostty docs for the stock set.
9. Neovim (retired)
Neovim/kickstart is gone — Emacs is the sole editor (see Philosophy).
base/nvim was deleted along with the rest of base/.
10. Zellij
A config is shipped, at zellij/ (config.kdl + layouts/), deployed as
generated config at build time (plugins/ stays an out-of-store symlink). It
clears the stock keybinds
(clear-defaults=true) and remaps pane/focus movement onto h j k l inside
each mode rather than using Zellij's defaults — see config.kdl for the full
map. Plugins zellaude and zellij-forgot are wired in under plugins/.
11. AI tooling
pi from the shell; skills under ~/.pi/agent/skills/. In Emacs, arc (the
local, offline retrieval index) is s-i (search from anywhere) or C-c i (its
command map). C-c i n and C-c i o scope the same search to the org-roam
vault and to the NixOS and Home Manager options. Results land in the
*arc-search* buffer: RET visits the hit, TAB expands the matching
passages, g re-runs the query, s changes the scope, and n / p move.
There is no answer buffer and no capture key.
arc retrieves only what it indexed. When nothing in the scope matches it says so and names the scope it searched; it never writes prose at all, so an invented NixOS option is not possible.