AI generated
Also covers programmatic access for scripts and AI agents via emacs --batch.
C-h)The starting point is always C-h (the Help prefix). If you remember nothing else, remember C-h C-h, it shows you all the help commands.
C-h) ¶C-h is the gateway to everything. Press it and wait, which-key will show you all available subcommands. Or press C-h C-h for the interactive help menu.
C-h C-h (or C-h ?) runs help-for-help, which shows all available help commands. Basically the meta-help. C-h C-q toggles a cheat sheet of common commands via help-quick-toggle.
These are the commands you’ll use 90% of the time.
C-h f (describe-function) gives you documentation for a function, with completion. C-h v (describe-variable) shows documentation and the current value of a variable. C-h k (describe-key) tells you what command a key sequence runs, with full docs. C-h o (describe-symbol) gives you everything about a symbol, the function docs, variable docs, and face docs all combined. C-h m (describe-mode) describes the current major mode and all active minor modes. C-h b (describe-bindings) lists every active keybinding in the current buffer. C-h x (describe-command) is like C-h f but restricted to interactive commands. And C-h w (where-is) tells you which key(s) run a given command.
Beyond those eight, there is a whole collection of help commands worth knowing about.
C-h c (describe-key-briefly) shows the command name for a key in the echo area without opening a popup. C-h a (apropos-command) finds commands matching a pattern. C-h d (apropos-documentation) searches documentation strings. C-h i (info) opens the Info manual browser. C-h r (info-emacs-manual) jumps directly to the Emacs manual. C-h R (info-display-manual) lets you choose a manual by name. C-h S (info-lookup-symbol) looks up a symbol in the language-appropriate manual. C-h F (Info-goto-emacs-command-node) finds a command in the Emacs manual. C-h K (Info-goto-emacs-key-command-node) finds a key in the Emacs manual.
For general orientation: C-h t (help-with-tutorial) runs the interactive Emacs tutorial, C-h p (finder-by-keyword) browses packages by category, C-h P (describe-package) gives documentation for a specific package, C-h l (view-lossage) shows the last 300 keystrokes so you can replay what you just did, and C-h e (view-echo-area-messages) shows the message history.
There is also C-h . (display-local-help) for showing help-echo text at point, C-h n (view-emacs-news) for release notes, and the internationalization helpers: C-h C (describe-coding-system), C-h I (describe-input-method), and C-h L (describe-language-environment).
Emacs ships with several standalone documents accessible directly from the help system. C-h t is the interactive tutorial available in 20+ languages. C-h n (or C-h C-n) shows release notes for the current version. C-h C-f opens the FAQ, C-h C-p opens known issues and workarounds, C-h C-d explains how to debug Emacs itself, and C-h C-a shows version, license, and credits. There is also C-h h which opens the HELLO file, showing character set display samples in many languages.
Emacs has 39 describe-* commands. The essential eight are covered above. Here are the rest, grouped by what they inspect.
describe-function shows the docstring, arglist, type specifier, keybindings, source file, and obsolescence info. describe-variable shows the value, docstring, buffer-local status, safe-local-variable status, and custom type. describe-symbol combines everything: function docs, variable docs, and face docs for the same symbol. describe-command is like describe-function but limited to interactive commands.
describe-key gives full docs for the command bound to a key sequence. describe-key-briefly just shows the command name in the echo area. describe-bindings lists all active keybindings, covering minor mode, major mode, and global bindings. describe-keymap shows all bindings in a specific named keymap. describe-prefix-bindings shows what follows after a prefix key, so for example C-x C-h shows everything available after C-x. This works with any prefix: C-c C-h, M-g C-h, and so on. describe-personal-keybindings shows your custom bind-key and use-package :bind overrides.
describe-mode shows the current major mode plus all active minor modes with docs. describe-minor-mode gives documentation for a specific minor mode. describe-minor-mode-from-indicator lets you identify a minor mode from its mode-line lighter, and describe-minor-mode-from-symbol does the same by symbol name.
This group covers character-level inspection. describe-char tells you everything about the character at point: unicode, properties, overlays, face, and font. describe-text-properties shows all text properties at point. describe-face gives face attributes like foreground, background, font family, and weight. describe-font shows low-level font metrics. describe-fontset reveals which fonts cover which character ranges. describe-syntax shows the syntax table, meaning which characters are treated as words, punctuation, and so on. describe-categories shows the character category table. describe-char-fold-equivalences shows case-fold equivalences for a character. describe-buffer-case-table shows buffer case conversion rules. describe-current-display-table shows how characters render.
describe-coding-system gives encoding details (UTF-8, latin-1, etc.), describe-current-coding-system shows the active encoding for the current buffer or process, describe-input-method shows how an input method maps keystrokes to characters, describe-language-environment covers language support including charsets, encodings, input methods, and samples, and describe-character-set shows characters in a specific charset.
describe-package shows package metadata, dependencies, status, and description. describe-theme gives color theme documentation and face assignments. describe-widget shows widget and button properties at point. describe-icon shows icon properties.
When you don’t know the exact name, apropos searches by pattern. There are 9 apropos commands, each searching different things.
apropos-command (C-h a) searches names of interactive commands. apropos-documentation (C-h d) searches the documentation strings of all symbols. apropos-user-option (available from the menu) searches names of defcustom variables. Then there are the M-x variants: apropos searches names of functions, variables, and faces. apropos-function searches function names including non-interactive ones. apropos-variable searches all variable names. apropos-value searches values of variables and function definitions. apropos-library finds symbols defined in a specific library file. And apropos-local-variable and apropos-local-value search buffer-local variables and their values.
A single word like "buffer" matches anything with "buffer" in the name. Multiple words like "buffer read only" match symbols containing at least two of those words. If the pattern contains ^$*+?.\[, it’s treated as a regular expression. There is also a synonym system, so "find" also matches "open" and "edit" (configurable via apropos-synonyms).
C-h a font finds all commands with "font" in their name. C-h d overlay finds all symbols whose docstring mentions "overlay". M-x apropos-library RET python shows everything defined in python.el. M-x apropos-value RET "utf-8" finds all variables whose value contains "utf-8".
Each result shows the symbol name (which is clickable), type indicators (c for command, f for function, m for macro, v for variable, u for user option, a for face), key bindings if any, and the first line of the docstring. Click any symbol name to see its full documentation.
Info is the primary documentation format for GNU software. Emacs ships with the complete Emacs Manual and the Emacs Lisp Reference Manual, plus 30+ subsystem manuals.
C-h i opens the top-level directory with all manuals. C-h r jumps directly to the GNU Emacs Manual. C-h R lets you choose a specific manual by name. C-h F finds a command’s section in the manual. C-h K finds a key’s section in the manual. C-h S looks up a symbol in the language-appropriate manual.
There are several ways to search within Info. i searches the manual’s index for a topic, which is the best approach for finding specific items. , jumps to the next index match. I is a virtual index, searching all index entries with a regexp. s does full-text search within the current manual. And M-x info-apropos searches indices across all installed Info manuals.
Index search (i) is better than text search (s) because the index is curated, it points to the most relevant section for each topic. Text search finds every mention, which is mostly noise.
info-lookup-symbol (C-h S) ¶This one is underused but quite powerful. It’s language-aware: in an Elisp buffer, it searches the Elisp Reference Manual index. In a C buffer, it searches the C library manual. In a Python buffer, it searches the Python manual (if installed).
So in an Elisp buffer with cursor on mapcar, you do C-h S mapcar RET and it opens the Elisp manual at the mapcar definition.
Type C-h R TAB to see all available manuals. A typical Emacs 30 installation includes Emacs, Elisp, Org, Gnus, Tramp, CC Mode, Eglot, Flymake, use-package, ERT, Calc, Ediff, Info, ERC, Eshell, and many more.
Jotain ships its own Info manual ((jotain)) alongside the bundled Emacs manuals. C-h i d m Jotain RET opens it; it covers installation, the module layout, the Nix build layer, and the full Nix module option reference. M-x consult-info includes it in cross-manual search. For NixOS / nix-darwin / Home Manager users the manual is pre-wired via INFOPATH; for source checkouts, run just info to build result-info/ and init-docs.el picks it up automatically.
These features show information without you explicitly asking for it.
ElDoc displays function signatures and variable types in the echo area as you type. It’s enabled globally by default via global-eldoc-mode. So while typing (mapcar |), the echo area shows mapcar: (FUNCTION SEQUENCE).
Key settings: eldoc-idle-delay controls seconds before showing (default 0.5), eldoc-echo-area-use-multiline-p controls multi-line display, and M-x eldoc-doc-buffer shows full docs in a dedicated buffer.
After pressing a prefix key like C-x, if you pause, a popup shows all available continuations with descriptions. This is built into Emacs 30.
which-key-idle-delay controls the seconds before the popup appears (default 1.0), and which-key-popup-type controls whether it displays as a minibuffer, side-window, or frame. There are also useful commands: M-x which-key-show-major-mode shows all major mode bindings, and M-x which-key-show-minor-mode-keymap shows bindings for a specific minor mode.
When using M-x, C-h f, or C-h v with completion, each candidate shows a type indicator (c for command, f for function, m for macro, v for variable, u for user option, a for face) and the first line of its docstring. This turns completion into a discovery tool, you type a partial name and browse what exists.
Jotain narrows the M-x candidate list via read-extended-command-predicate, set in init-core to command-completion-default-include-p. A command opts in by listing applicable modes after the interactive argument descriptor — (interactive nil foo-mode) for a no-argument command, (interactive "p" foo-mode bar-mode) for one that reads a prefix argument and applies in either mode — and then only appears in M-x when one of those modes is active. Untagged commands are always shown, and typing a full command name still runs it whether or not the filter would hide it. Two stricter predicates ship with Emacs if you want fewer candidates: command-completion-using-modes-and-keymaps-p (only commands tied to active modes or active keybindings) and command-completion-using-modes-p (only commands explicitly tagged for a mode).
C-h . (display-local-help) shows the help-echo text property at point. Many UI elements like buttons, links, and mode-line indicators have this property.
M-x shortdoc shows common functions organized by topic with live examples and expected output. Available groups in Emacs 30 include: string (string manipulation), list (list operations), alist (association lists), sequence (generic sequences with seq-map, seq-filter, seq-reduce, etc.), number (arithmetic), vector, regexp (regular expressions), buffer (buffer manipulation), process (process management), file-name (filename operations), file (file I/O), hash-table, keymaps, text-properties, overlay, symbol, comparison, and map (the map library).
Each entry shows the function signature, a brief description, and a live example.
M-x customize is not just for configuration, it’s also a documentation browser. Every defcustom variable shows its type, valid values, default, and a full description.
customize shows top-level customization groups. customize-browse gives you a hierarchical tree of all option groups. customize-group shows all options in a specific group. customize-variable gives a single variable with full docs and type. customize-face shows a face with preview and attribute editor. customize-apropos finds options matching a pattern, and there are also customize-apropos-faces and customize-apropos-groups for faces and groups specifically.
customize-browse is particularly useful for discovery. It lets you explore what Emacs can do by browsing option hierarchies. Categories like programming, faces, editing, and convenience reveal features you never knew existed.
When you’re looking for a needle in a haystack, search.
C-s (isearch-forward) does incremental search, C-r (isearch-backward) does reverse incremental search, C-M-s (isearch-forward-regexp) does regexp search, and M-x occur shows all lines matching a regexp in a clickable buffer.
M-x grep runs grep with results in a clickable buffer. M-x rgrep does recursive grep with directory and file filtering. M-x lgrep greps in a single directory. C-x p g (project-find-regexp) searches across the current project, and C-x p f (project-find-file) finds files by name in the project.
multi-occur runs occur across multiple buffers, and multi-occur-in-matching-buffers runs occur in buffers matching a name regexp.
M-x man views a Unix man page (requires external man command), and M-x woman does the same without external dependencies, the name stands for "WithOut Man". Both give hyperlinked, formatted output inside Emacs.
M-x eww opens a URL or searches the web inside Emacs. M-x eww-open-file opens a local HTML file.
C-h p (finder-by-keyword) browses packages by category keyword. M-x list-packages shows a tabulated list of all available packages. C-h P (describe-package) gives full documentation for a specific package.
M-: (eval-expression) lets you evaluate any Elisp expression and see the result. This is the most powerful introspection tool, you can query anything.
;; What mode is this buffer in? M-: major-mode RET ;; What's the value of a variable? M-: tab-width RET ;; What key runs a command? M-: (where-is-internal 'save-buffer) RET ;; What command is on a key? M-: (key-binding (kbd "C-x C-s")) RET
debug-on-entry lets you step through a function, seeing every call and return value. debug-on-variable-change breaks when a variable changes, so you can find who’s mutating state. trace-function logs every call to a function with arguments and return values. edebug-defun instruments a function for step-by-step execution with breakpoints. And profiler-start / profiler-report give you CPU and memory profiling to find what’s slow.
C-h l (view-lossage) shows the last 300 keystrokes and commands. C-h e (view-echo-area-messages) shows the message log with recent message calls.
These are the building blocks. Use them in M-:, in *scratch*, or in batch mode.
;; Get a function's docstring (documentation 'mapcar t) ;; Get a variable's docstring (documentation-property 'tab-width 'variable-documentation) ;; Get the arglist of a function (help-function-arglist 'mapcar) ;; → (FUNCTION SEQUENCE)
;; Which file defines a function? (symbol-file 'python-mode 'defun) ;; → "python" ;; Which file defines a variable? (symbol-file 'tab-width 'defvar) ;; Is this a C primitive or Elisp? (subrp (symbol-function 'forward-char)) ;; → t (C) (subrp (symbol-function 'forward-word)) ;; → nil (Elisp) ;; Is it native-compiled? (subr-native-elisp-p (symbol-function 'forward-word)) ;; Where is a library file? (locate-library "org") ;; → "/path/to/org.elc"
;; Find all functions with a prefix (apropos-internal "^font-lock-" #'functionp) ;; Find all commands with a prefix (apropos-internal "^describe-" #'commandp) ;; Find all user options in a prefix (apropos-internal "^org-" #'custom-variable-p)
;; What command is on a key? (key-binding (kbd "C-x C-f")) ;; → find-file ;; What keys run a command? (where-is-internal 'find-file) ;; → ([24 6] [open] ...) ;; Human-readable: (mapconcat #'key-description (where-is-internal 'find-file) ", ") ;; → "C-x C-f, <open>, ..."
;; The property list reveals metadata the docs don't mention: (symbol-plist 'font-lock-mode) ;; Properties like: safe-local-variable, permanent-local, risky-local-variable, ;; side-effect-free, byte-compile, compiler-macro ;; Check if a variable is safe as a file-local variable (get 'tab-width 'safe-local-variable) ;; Get the customize type (shows all valid values) (require 'cus-edit) (custom-variable-type 'font-lock-maximum-decoration)
;; Does this Emacs have native compilation? (featurep 'native-compile) ;; Does it have tree-sitter? (featurep 'treesit) ;; What features are loaded? features ;; → (rmc iso-transl tooltip ...) ;; Build configuration system-configuration-options emacs-version system-type
;; What mode + minor modes activate for a .py file?
(with-temp-buffer
(setq buffer-file-name "/tmp/test.py")
(set-auto-mode)
(cons major-mode
(seq-filter (lambda (m) (and (boundp m) (symbol-value m)))
minor-mode-list)))
For scripts, CI, and AI agents. Two approaches: batch mode (standalone) and emacsclient (persistent).
emacs --batch --evalemacsclient --evalemacs --batch --eval ¶This starts a fresh Emacs, evaluates code, and exits. No GUI, no user config, no persistent state.
# Get a function's documentation
emacs --batch --eval '(princ (documentation '\''mapcar t))' 2>/dev/null
# Find what command a key runs
emacs --batch --eval '(princ (key-binding (kbd "C-x C-f")))' 2>/dev/null
# Find what keys run a command
emacs --batch --eval '(princ (mapconcat #'\''key-description (where-is-internal '\''find-file) ", "))' 2>/dev/null
# List all functions matching a prefix
emacs --batch --eval '(princ (mapconcat #'\''symbol-name (apropos-internal "^font-lock-" #'\''functionp) "\n"))' 2>/dev/null
# Get a function's arglist
emacs --batch --eval '(princ (help-function-arglist '\''make-overlay))' 2>/dev/null
# Find where a function is defined
emacs --batch --eval '(princ (symbol-file '\''python-mode '\''defun))' 2>/dev/null
# Check if a feature exists
emacs --batch --eval '(princ (featurep '\''native-compile))' 2>/dev/null
# Get build configuration
emacs --batch --eval '(princ system-configuration-options)' 2>/dev/null
# Simulate opening a file and list active modes
emacs --batch --eval '(progn
(with-temp-buffer
(setq buffer-file-name "/tmp/test.py")
(set-auto-mode)
(let ((modes (list major-mode)))
(dolist (m minor-mode-list)
(when (and (boundp m) (symbol-value m))
(push m modes)))
(princ (mapconcat #'\''symbol-name modes "\n")))))' 2>/dev/null
# Load a library first, then query
emacs --batch --eval '(progn
(require '\''auth-source)
(princ (documentation '\''auth-source-search t)))' 2>/dev/null
When output would be too large for stdout, write to a file:
emacs --batch --eval '(with-temp-file "/tmp/emacs-result.txt"
(dolist (fn (apropos-internal "^overlay-" #'\''functionp))
(insert (format "%s: %s\n\n" fn (documentation fn)))))' 2>/dev/null
# Then read it
cat /tmp/emacs-result.txt
emacsclient --eval ¶This connects to a running Emacs server. It’s faster since there is no cold start, and it has access to user config and loaded state.
# Requires: M-x server-start or emacs --daemon first emacsclient --eval '(documentation '\''mapcar t)' emacsclient --eval '(buffer-list)'
emacs --batch --eval takes about 0.5-1.0s to start (cold), doesn’t require a running server, has no state persistence between calls, doesn’t load user config, and is best for scripts, CI, and standalone queries. emacsclient --eval starts in about 0.1s (warm), requires a running server, shares state with the running Emacs, has user config loaded, and is best for interactive workflows where you want to leverage existing state.
There is no state between calls, so each invocation is a fresh process. If you need to chain operations, use (progn ...). There is no GUI, so functions that require interactive input will silently fail. The cold start adds about 0.5-1.0s overhead per call, so for many queries it’s better to use one emacs --batch invocation with multiple operations. Output goes to stdout/stderr, use princ for stdout and 2>/dev/null to suppress startup messages. Libraries are not loaded by default, so use (require 'library) or --load file.el for non-default libraries.
C-h t is the interactive tutorial available in 20+ languages. C-h n shows the release notes (stored in etc/NEWS through etc/NEWS.30). C-h C-f is the FAQ. C-h C-p covers known issues and workarounds. C-h C-d explains how to debug Emacs with GDB. C-h C-a shows version, license, and credits. C-h h shows character set samples in many scripts. And there are printable quick-reference cards in etc/refcards/.
Emacs Lisp source files serve as documentation through three mechanisms.
Commentary sections at the top of each file explain the module’s purpose and design:
;;; Commentary: ;; A grab-bag of basic Emacs commands not specifically related to some ;; major mode or to file-handling.
Find them with M-x find-library then search for ;;; Commentary:.
Docstrings on every function and variable are accessible via C-h f and C-h v, or programmatically via (documentation 'symbol t).
Defcustom declarations show the type, valid values, and group for every user option:
(defcustom make-backup-files t "Non-nil means make a backup of a file the first time it is saved. This can be done by renaming the file or by copying. ..." :type 'boolean :group 'backup)
The lisp/ directory contains the Elisp standard library (1,587 .el files). Under it, lisp/progmodes/ has programming language modes like python.el and js.el, lisp/emacs-lisp/ has the Elisp language infrastructure (byte-compiler, cl-lib, seq, map), and lisp/net/ has networking code (Tramp, EWW, URL). lisp/org/ contains Org mode. The src/ directory has the C core, covering the Lisp interpreter, display engine, and buffer management. doc/emacs/ has the Emacs Manual texinfo sources, doc/lispref/ has the Elisp Reference texinfo sources, and doc/misc/ has 70+ subsystem manual texinfo sources. etc/NEWS* has the version-by-version changelog.
What a function does: C-h f function-name. What a variable controls: C-h v variable-name. What a key does: C-h k then press the key. What key runs a command: C-h w command-name. What this mode provides: C-h m. All keybindings right now: C-h b. Everything about a symbol: C-h o symbol-name.
Functions you can’t name: C-h a partial-name or C-h d keyword. Read the manual on a topic: C-h i then i topic. Find a command in the manual: C-h F command-name. How a function is implemented: C-h f function-name then s to jump to source. What functions exist for X: M-x shortdoc or M-: (apropos-internal "^prefix-" #'functionp). What options exist for X: M-x customize-group or M-x customize-apropos. What packages do X: C-h p or M-x list-packages. What changed in this version: C-h n. A Unix command’s manual: M-x man or M-x woman. What just happened: C-h l for keystrokes or C-h e for messages. From a script or AI agent: emacs --batch --eval '(princ (documentation '\''fn t))' 2>/dev/null.