Keybindings
Table of Contents
- 1. EWM (compositor —
Superkeys) - 2. Config layout: a loader, a config, and a fallback
- 3. A note on what the distribution supplies
- 4. Emacs — modal editing (Meow)
- 5. Emacs — commands (
C-c/C-x) - 6. Emacs — windows, terminal and other keys
- 7. Emacs — code navigation and LSP
- 8. Theme
- 9. Ghostty
- 10. Neovim (retired)
- 11. AI tooling
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 — asks for confirmation, saves file buffers, then exits the session |
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 ends the session when it exits. Then getty's autologin
(opt-in per host) logs back in; without it you get a login prompt, and EWM
restarts on your next tty1 login. Killing the daemon is the restart.
It asks one yes-or-no-p question first, then 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 (the distribution's default; a consumer can rebind it) |
, . [ ] |
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 in an org buffer (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 org and markdown
.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. .md files open
in markdown-modern-mode, a separate tree-sitter-based major mode that renders
markdown inline.
C-c z— toggle back to plain monospace source (org)C-c +/C-c -/C-c 0— enlarge, shrink, reset the document's text size (Emacs's text scaling, per buffer, so another document keeps its own size)M-g i— jump to a heading (consult-imenu)TAB/S-TAB— fold a section / the whole outline (org's own in org buffers; markdown-modern's in.mdbuffers)
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.
6. Emacs — windows, terminal and other keys
Bound in config.el and available whenever a native Emacs buffer has focus.
| Binding | Action |
|---|---|
C-c ? |
The welcome buffer (orientation, shown once per machine); M-x emanix-guides lists every guide |
C-c w |
Window-layout map: u / r undo / redo the layout, s / v split below / right, d delete window, o delete the others, = balance, m swap windows (ace), w / j save layout to / jump to a register; C-c w C-h lists them |
M-h / M-j / M-k / M-l |
Focus the window left / down / up / right (windmove); the shifted M-H … M-L swap windows instead. A ghostel buffer keeps these keys for its program |
S-←/→/↑/↓ |
Resize the window |
C-x o |
ace-window — jump to a window by letter when there are three or more |
C-c t |
ghostel terminal buffer; C-u C-c t opens a new one |
C-c o |
App launcher (the same as s-d under EWM) |
C-c K |
Kill every buffer in a named group (emanix/kill-buffer-group; prompts for the group) |
C-c c |
Run the consumer's calendar-sync tool from $EMANIX_BIN_DIR |
C-c b |
consult-bookmark |
Three more Super bindings come with the compositor. s-<return> opens a Ghostty
terminal in the current slot. s-m slides every frame off screen and back, and
s-e opens the focused text field in an Emacs buffer (C-c C-c sends it back,
C-c C-k cancels). The last two are upstream EWM's.
8. 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.
9. 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.
10. Neovim (retired)
Neovim/kickstart is gone — Emacs is the sole editor (see Philosophy).
base/nvim was deleted along with the rest of base/.
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.