- Overview
- Architecture
- Key Bindings Reference
- Prefix Keys
- Global Key Bindings
- Completion & Search Bindings
- Mwim Bindings
- Highlight Symbol Bindings
- Theme Bindings
- Undo Tree Bindings
- Project Management Bindings
- Treemacs Bindings
- Avy Bindings
- Git Bindings
- Multiple Cursors Bindings
- Vterm Bindings
- AI Agent Bindings
- Claude Code IDE Bindings
- Readonly / View-Mode Bindings
- Org Mode Bindings
- Core Files
- Feature Modules
- init-theme.el
- init-completion.el
- init-which-key.el
- init-recentf.el
- init-dired.el
- init-lsp.el
- init-web.el
- init-hydra.el
- init-highlight-symbol.el
- init-avy.el
- init-ace-window.el
- init-mwim.el
- init-undo-tree.el
- init-project.el
- init-treemacs.el
- init-git.el
- init-multiple-cursors.el
- init-rainbow-delimiters.el
- init-vterm.el
- init-agent-shell.el
- init-claude-code-ide.el
- init-readonly.el
- init-tramp.el
- Adding New Modules
- Usage Guide
- Troubleshooting
Skemacs is a modular, high-performance Emacs configuration framework. Key features:
- Independent modules: Each module is fully self-contained (package declaration + config + keybindings)
- Startup timing: Every module’s load time is recorded; view with
M-x skemacs/show-load-times - Error isolation: A single module failure won’t break others (
condition-casewrapped) - Flexible management: Enable/disable modules via config lists, no need to delete files
- Dynamic splash screen: Real-time loading progress displayed at startup; stats summary above the table, error details (or “no error”) below
- Smart startup mode:
emacs/emacs dirshows splash and waits for Enter;emacs fileskips the wait and opens the file directly - Deferred package init:
package-initializeis deferred until first package install for fast startup - Centralized prefix keys: Prefix keys defined in
core-keybindings.el, modules bind under them - use-package :bind: All custom bindings viewable via
M-x describe-personal-keybindings
~/.emacs.d/ ├── early-init.el # GC optimization + native-comp + disable package autoload ├── init.el # Entry point (custom.el → core → splash → modules → Enter/file) ├── core/ # Core infrastructure (no third-party dependencies) │ ├── core-load-paths.el # Path constants + load-path setup │ ├── core-module.el # Module loading system (timing + error isolation + splash) │ ├── core-packages.el # use-package + package.el (deferred initialization) │ ├── core-ui.el # Basic UI (toolbar/menubar/scrollbar etc.) │ ├── core-editor.el # Editing behavior (parens, selection, folding etc.) │ ├── core-funcs.el # Utility functions (navigation, window, clipboard) │ └── core-keybindings.el # Prefix key definitions + global keybindings ├── modules/ # Feature modules (each file is self-contained) │ ├── init-theme.el # Theme management (modus + doom + ef + catppuccin) │ ├── init-completion.el # Minibuffer completion (Vertico + Orderless + Marginalia + Consult + Embark) │ ├── init-dired.el # Dired enhancements (omit mode) │ ├── init-lsp.el # LSP configuration (lsp-bridge) │ ├── init-recentf.el # Recent files + ibuffer │ ├── init-highlight-symbol.el # Symbol highlighting │ ├── init-hydra.el # Operation panels (hydra) │ ├── init-avy.el # Quick jump (avy: char/word/line jump) │ ├── init-ace-window.el # Window quick-jump (ace-window) │ ├── init-mwim.el # Smart line beginning/end (mwim) │ ├── init-project.el # Project management (built-in project.el) │ ├── init-treemacs.el # File tree sidebar (treemacs) │ ├── init-git.el # Git integration (magit + diff-hl) │ ├── init-undo-tree.el # Undo/redo tree with hydra panel │ ├── init-multiple-cursors.el # Multi-cursor editing with hydra panel │ ├── init-rainbow-delimiters.el # Rainbow parentheses │ ├── init-vterm.el # Terminal emulator (vterm) │ ├── init-web.el # Web development (web-mode) │ ├── init-which-key.el # Key discovery (which-key) │ ├── init-agent-shell.el # AI Agent integration (agent-shell + ACP) │ ├── init-claude-code-ide.el # Claude Code IDE integration (MCP) │ ├── init-readonly.el # Default read-only browsing (view-mode) │ └── init-tramp.el # Remote file access via TRAMP (SSH) [disabled] ├── themes/ # Local theme files (modus-themes, loaded via custom-theme-load-path) │ ├── modus-themes.el # Modus themes core library │ ├── modus-operandi-tinted-theme.el # Light theme (warm tinted background) │ └── modus-vivendi-tritanopia-theme.el # Dark theme (black background) ├── lsp-bridge-langserver/ # LSP server override configs (vtsls replaces typescript-language-server) ├── banners/ # Startup banner files ├── setup-lsp.sh # LSP environment setup script (Node.js + Python + lsp-bridge) ├── setup-agents.sh # ACP agent adapter setup script (Claude Code + Cursor + Gemini) └── custom.el # Emacs custom-file + module control (skemacs-disabled-modules etc.)
The startup flow adapts based on how Emacs is invoked:
# Normal mode (emacs / emacs . / emacs ~/dir) early-init.el → init.el → custom.el → splash → core/*.el → modules/*.el → Press Enter → dired # File mode (emacs file.txt / emacs -nw file.txt) early-init.el → init.el → custom.el → splash → core/*.el → modules/*.el → open file (no wait)
early-init.el— Set GC threshold to 800MB, disable package autoload, hide UI elementsinit.el— Bootstrapcore/intoload-path, require core-load-paths and core-modulecustom.el— Load user customizations (skemacs-disabled-modulesetc.) before module loadingskemacs--splash-init— Display banner, stats placeholder (“Loading modules…”), and table header in*skemacs*bufferskemacs-load-core-module— Load remaining core files (each line appears in real-time)skemacs-load-all-modules— Scanmodules/directory, load each (real-time display)emacs-startup-hook— Restore GC to 16MB, finalize splash screen, detect startup mode:- Normal mode (no file argument): wait for Enter, then dismiss splash and open
dired - File mode (file argument detected): skip wait, dismiss splash and switch to file buffer
- Normal mode (no file argument): wait for Enter, then dismiss splash and open
The module system is provided by core/core-module.el:
| Variable / Function | Description |
|---|---|
skemacs-module-list | Module list to load; nil = auto-scan modules/ |
skemacs-disabled-modules | Disabled module list (highest priority) |
skemacs-load-times | Timing data (("name" . seconds) ...) |
skemacs-module-errors | Error records (("name" . "message") ...) |
skemacs-load-module | Load a single module (condition-case isolation) |
skemacs-load-all-modules | Load all enabled modules |
skemacs--started-with-file-p | Detect if Emacs was started with a file argument |
skemacs/show-load-times | Interactive command: show formatted timing report |
Timing report example (M-x skemacs/show-load-times):
Startup Timing Report ──────────────────────────────────────────────────────── Module Time Status ──────────────────────────────────────────────────────── core-packages 59ms OK core-ui 6ms OK core-editor 4ms OK core-funcs 589us OK core-keybindings 839us OK ──────────────────────────────────────────────────────── Total: 71ms | 5 loaded | 0 disabled | 0 errors
Prefix keys are defined in core-keybindings.el. Modules bind commands under these prefixes:
| Prefix | Keymap Name | Purpose |
|---|---|---|
C-j | skemacs-prefix | Main prefix |
C-j o | skemacs-org-prefix | Org-related |
C-j p | skemacs-project-prefix | Project mgmt |
C-j s | skemacs-search-prefix | Search (Consult) |
C-j f | skemacs-filetree-prefix | File tree (Treemacs) |
C-j g | skemacs-git-prefix | Git (Magit) |
C-j j | skemacs-jump-prefix | Jump (Avy) |
C-j v | skemacs-terminal-prefix | Terminal (Vterm) |
C-j a | skemacs-agent-prefix | AI Agent (agent-shell) |
C-j c | skemacs-claude-prefix | Claude Code IDE (MCP) |
C-j T | skemacs-theme-prefix | Theme management |
C-j l | (lsp-bridge bindings) | LSP commands |
C-j u | (hydra-undo-tree) | Undo tree panel |
C-j m | (multiple-cursors) | Multi-cursor commands |
C-j h | (highlight-symbol) | Symbol highlight |
C-x w | skemacs-window-prefix | Window ops |
C-x b | skemacs-buffer-prefix | Buffer ops |
These keybindings depend on no third-party packages, defined in core-keybindings.el:
| Key | Function | Description |
|---|---|---|
M-n | skemacs/next-ten-lines | Move 10 lines down |
M-p | skemacs/previous-ten-lines | Move 10 lines up |
C-o | pop-global-mark | Jump back to prev mark |
M-/ | dabbrev-expand | Text completion |
| Key | Function | Description |
|---|---|---|
C-j C-k | kill-whole-line | Kill entire line |
C-c C-y | skemacs/copy-to-clipboard | Copy to clipboard |
| Key | Function | Description |
|---|---|---|
C-x o | ace-window | Quick jump window |
C-x w h | windmove-left | Move to left window |
C-x w j | windmove-down | Move to below window |
C-x w k | windmove-up | Move to above window |
C-x w l | windmove-right | Move to right window |
C-x w s | split-window-below | Split horizontally |
C-x w v | split-window-right | Split vertically |
C-x w S | skemacs/split-window-horizontally | Split & switch down |
C-x w V | skemacs/split-window-vertically | Split & switch right |
C-x w r | hydra-window-resize/body | Window resize panel |
In the resize panel (C-x w r), press keys repeatedly to adjust window size:
| Key | Function | Description |
|---|---|---|
h | skemacs/shrink-window-horizontally | Shrink horizontally |
l | skemacs/enlarge-window-horizontally | Enlarge horizontally |
j | skemacs/shrink-window | Shrink vertically |
k | skemacs/enlarge-window | Enlarge vertically |
q | quit | Exit resize panel |
| Key | Function | Description |
|---|---|---|
C-x b b | consult-buffer ¹ | Switch buffer (+ recentf + bookmark) |
C-x b n | next-buffer | Next buffer |
C-x b p | previous-buffer | Previous buffer |
C-x b k | kill-buffer | Kill buffer |
C-x b r | recentf-open | Recent files (completing-read) |
C-x b R | recentf-open-files | Recent files (list window) |
C-x b l | ibuffer | Buffer list (ibuffer) |
¹ Enhanced by init-completion.el; falls back to switch-to-buffer if module disabled.
| Key | Function | Description |
|---|---|---|
C-j n | display-line-numbers-mode | Toggle line numbers |
C-j r | skemacs/toggle-line-numbers-type | Toggle relative/absolute |
C-j t | skemacs/show-load-times | Show load times |
Provided by init-completion.el (Vertico + Orderless + Marginalia + Consult + Embark).
M-x and all completing-read prompts are automatically enhanced:
| Component | Effect |
|---|---|
| Vertico | Vertical candidate list in minibuffer |
| Orderless | Space-separated fuzzy matching (e.g. fn js → find-file-js) |
| Marginalia | Annotations next to candidates (docstring, type, keybinding) |
| Savehist | Persist minibuffer history across sessions |
| Key | Function | Description |
|---|---|---|
C-j s s | consult-line | Search lines in current buffer |
C-j s r | consult-ripgrep | Ripgrep search in project |
C-j s f | consult-find | Find file by name |
C-j s g | consult-grep | Grep search |
C-j s o | consult-outline | Jump to heading/outline |
C-j s i | consult-imenu | Jump to symbol (imenu) |
C-j s I | consult-imenu-multi | Jump to symbol (cross-buffer) |
C-j s b | consult-bookmark | Open bookmark |
The same commands are also available under Emacs standard prefixes:
| Key | Function | Description |
|---|---|---|
M-g g | consult-goto-line | Go to line number |
M-g o | consult-outline | Jump to outline heading |
M-g i | consult-imenu | Jump to symbol |
M-g I | consult-imenu-multi | Jump to symbol (cross-buffer) |
M-s l | consult-line | Search lines in buffer |
M-s r | consult-ripgrep | Ripgrep search in project |
M-s f | consult-find | Find file by name |
M-s g | consult-grep | Grep search |
| Key | Function | Description |
|---|---|---|
C-. | embark-act | Context menu on current candidate |
C-; | embark-dwim | Execute default action |
C-h B | embark-bindings | Show all embark key bindings |
M-A | marginalia-cycle | Cycle annotation detail (minibuffer) |
| Key | Function | Description |
|---|---|---|
RET | vertico-directory-enter | Enter directory / open file |
DEL | vertico-directory-delete-char | Delete path component |
M-DEL | vertico-directory-delete-word | Delete word in path |
Provided by init-mwim.el. Smart C-a / C-e that cycles between code boundaries and line boundaries.
| Key | Function | Description |
|---|---|---|
C-a | mwim-beginning | 1st press: beginning of code; 2nd press: line start |
C-e | mwim-end | 1st press: end of code (before comments); 2nd press: line end |
Provided by init-highlight-symbol.el. Automatically highlights all occurrences of the symbol under cursor in prog-mode buffers.
| Key | Function | Description |
|---|---|---|
C-j h n | highlight-symbol-next | Jump to next same symbol |
C-j h p | highlight-symbol-prev | Jump to previous same symbol |
C-j h h | highlight-symbol-at-point | Toggle highlight current symbol |
C-j h r | highlight-symbol-query-replace | Rename symbol in buffer |
Provided by init-theme.el. Manages themes with system dark/light mode auto-detection.
| Key | Function | Description |
|---|---|---|
C-j T T | skemacs/switch-theme | Choose theme (completing-read) |
C-j T n | skemacs/cycle-theme | Cycle to next theme in list |
C-j T t | skemacs/toggle-light-dark | Toggle between light and dark theme |
Provided by init-undo-tree.el. Replaces Emacs default linear undo with a tree-based undo system. Uses hydra panel for quick undo/redo operations.
| Key | Function | Description |
|---|---|---|
C-j u | hydra-undo-tree/body | Open undo tree hydra panel |
In the undo tree panel (C-j u):
| Key | Function | Description |
|---|---|---|
p | undo-tree-undo | Undo |
n | undo-tree-redo | Redo |
v | undo-tree-visualize | Visualize undo tree |
q | quit | Exit panel |
Provided by init-project.el. Uses Emacs built-in project.el (28+) for project management based on version control (Git etc.) root detection.
| Key | Function | Description |
|---|---|---|
C-j p p | project-switch-project | Switch to another project |
C-j p f | project-find-file | Find file in project |
C-j p g | project-find-regexp | Regexp search in project |
C-j p d | project-dired | Dired at project root |
C-j p b | project-switch-to-buffer | Switch buffer within project |
C-j p c | project-compile | Compile in project |
C-j p e | project-eshell | Eshell at project root |
C-j p k | project-kill-buffers | Kill all project buffers |
C-j p ! | project-shell-command | Shell command at project root |
C-j p & | project-async-shell-command | Async shell command |
Provided by init-treemacs.el. File tree sidebar for project navigation.
| Key | Function | Description |
|---|---|---|
C-j f t | treemacs | Toggle treemacs sidebar |
C-j f s | treemacs-find-file | Locate current file in tree |
C-j f d | treemacs-select-directory | Select directory |
C-j f a | treemacs-add-project-to-workspace | Add project to workspace |
Provided by init-avy.el. Fast cursor jumping to any visible position via avy.
| Key | Function | Description |
|---|---|---|
C-; | avy-goto-word-1 | Type 1 char, jump to word beginning |
C-' | avy-goto-char-2 | Type 2 chars, jump to match |
M-g g | avy-goto-line | Jump to any visible line |
M-g w | avy-goto-word-1 | Jump to word beginning |
| Key | Function | Description |
|---|---|---|
C-j j c | avy-goto-char | Jump to any character |
C-j j w | avy-goto-word-1 | Jump to word beginning |
C-j j l | avy-goto-line | Jump to any line |
C-j j t | avy-goto-char-timer | Timed char search (0.5s timeout) |
Provided by init-git.el. Full Git integration via Magit.
| Key | Function | Description |
|---|---|---|
C-j g g | magit-status | Open Magit status panel |
C-j g l | magit-log-current | Current branch log |
C-j g b | magit-blame-addition | File blame (line-by-line) |
C-j g d | magit-diff-buffer-file | Diff current file |
C-j g f | magit-log-buffer-file | Log for current file |
C-j g s | magit-stage-file | Stage current file |
C-j g u | magit-unstage-file | Unstage current file |
Provided by init-multiple-cursors.el. Multi-cursor editing with C-j m prefix.
| Key | Function | Description |
|---|---|---|
C-j m n | mc/mark-next-like-this | Mark next occurrence |
C-j m p | mc/mark-previous-like-this | Mark previous occurrence |
C-j m a | mc/mark-all-like-this | Mark all occurrences |
C-j m l | mc/edit-lines | Cursor on each selected line |
C-j m s | mc/mark-all-in-region-regexp | Mark by regexp in region |
C-j m N | mc/skip-to-next-like-this | Skip current, mark next |
C-j m P | mc/skip-to-previous-like-this | Skip current, mark previous |
C-j m 0 | mc/insert-numbers | Insert incremental numbers |
C-j m \vert | mc/vertical-align | Align cursors by input char |
C-S-<mouse-1> | mc/toggle-cursor-on-click | Toggle cursor at click point |
Provided by init-vterm.el. High-performance terminal emulator via vterm (based on libvterm C library).
| Key | Function | Description |
|---|---|---|
C-j v v | vterm | Open new vterm terminal |
C-j v t | skemacs/vterm-toggle | Toggle vterm (switch to existing or create new) |
C-j v o | vterm-other-window | Open vterm in another window |
Provided by init-agent-shell.el. AI coding agent integration via agent-shell powered by ACP (Agent Client Protocol).
| Key | Function | Description |
|---|---|---|
C-j a a | agent-shell | Start/reuse any Agent |
C-j a c | agent-shell-anthropic-start-claude-code | Start Claude Code |
C-j a u | agent-shell-cursor-start-agent | Start Cursor Agent |
C-j a g | agent-shell-google-start-gemini | Start Gemini CLI |
C-j a n | agent-shell-new-shell | New Agent Shell |
C-j a i | agent-shell-insert-file | Insert file as context |
Shell-internal keybindings:
| Key | Function | Description |
|---|---|---|
RET | submit prompt | Send prompt to agent |
M-J | insert newline | Newline without sending |
C-c C-c | agent-shell-interrupt | Interrupt current operation |
TAB | next item | Navigate to next element |
S-TAB | previous item | Navigate to previous element |
Provided by init-claude-code-ide.el. Native Claude Code CLI integration via claude-code-ide, powered by MCP (Model Context Protocol). Creates a bidirectional bridge between Claude and Emacs, enabling Claude to access LSP, xref, tree-sitter, and other Emacs capabilities.
| Key | Function | Description |
|---|---|---|
C-j c c | claude-code-ide | Start/switch Claude Code |
C-j c m | claude-code-ide-menu | Open command menu (transient) |
C-j c p | claude-code-ide-send-prompt | Send prompt from minibuffer |
C-j c r | claude-code-ide-resume | Resume previous session |
C-j c k | claude-code-ide-continue | Continue most recent conversation |
C-j c s | claude-code-ide-list-sessions | List all active sessions |
C-j c t | claude-code-ide-toggle | Toggle window visibility |
C-j c T | claude-code-ide-toggle-recent | Toggle most recent (global) |
C-j c @ | claude-code-ide-insert-at-mentioned | Mention selected text |
C-j c q | claude-code-ide-stop | Stop Claude Code |
Terminal-internal keybindings (in Claude Code vterm buffer):
| Key | Function | Description |
|---|---|---|
M-RET | claude-code-ide-insert-newline | Insert newline in prompt |
C-\ | claude-code-ide-send-escape | Send escape key |
Provided by init-readonly.el. All files opened via find-file enter view-mode (read-only browsing) by default. Press C-x C-q to exit read-only and start editing.
| Key | Function | Description |
|---|---|---|
SPC | scroll down | Scroll one page down |
DEL | scroll up | Scroll one page up |
d / u | half-page down/up | Scroll half page |
n / p | next/previous line | Move by line |
< | beginning-of-buffer | Jump to buffer start |
> | end-of-buffer | Jump to buffer end |
| Key | Function | Description |
|---|---|---|
s | isearch-forward | Incremental search |
r | isearch-backward | Reverse incremental search |
/ or \ | regex search | Regular expression search |
| Key | Function | Description |
|---|---|---|
q | quit | Exit view-mode and close buffer |
e | exit | Exit view-mode, keep buffer |
C-x C-q | read-only-mode | Exit read-only, enter editing mode |
| Key | Function | Description |
|---|---|---|
C-j o o | skemacs/open-org-directory | Open ~/org dir |
C-j o a | org-agenda | Org Agenda |
C-j o c | org-capture | Org Capture |
C-j o l | org-store-link | Store link |
C-j o i | org-insert-link | Insert link |
C-j o C-p | iimage-mode | Image preview |
C-j o <up> | org-priority-up | Increase priority |
C-j o <down> | org-priority-down | Decrease priority |
Loaded by Emacs 27+ before init.el and before GUI initialization:
- Set GC threshold to 800MB (reduce pauses during startup)
- Disable
package.elautomatic loading - Native compilation optimization (Emacs 28+)
- Disable toolbar/menubar/scrollbar early (avoid GUI flicker)
Entry point:
- Record startup time
- Bootstrap
core/intoload-path - Load
custom.elearly (module control variables take effect before loading) - Initialize splash screen with banner
- Load core modules (real-time display in splash)
- Load feature modules (real-time display in splash)
- On
emacs-startup-hook: restore GC, show summary, detect startup modeemacs/emacs dir→ wait for Enter, then open diredemacs file→ skip wait, directly open file buffer
Defines path constants (skemacs-dir, skemacs-core-dir, skemacs-modules-dir, skemacs-local-dir, skemacs-themes-dir, skemacs-cache-dir), ensures directories exist, adds them to load-path. Also registers themes/ in custom-theme-load-path for local theme discovery.
Module loading system with dynamic splash screen. See Module System section.
Splash screen layout:
Banner
[ Press Enter to continue ]
Emacs XX.X | Skemacs Configuration | Starting time: X.XXXs
Total: XXXms | N loaded | N disabled | N errors ← stats summary
────────────────────────────────────────────────────────
Module Time Status
────────────────────────────────────────────────────────
core-packages 59ms OK
...
────────────────────────────────────────────────────────
no error ← or error details
During loading, “Loading modules…” is shown in the stats position and replaced with actual statistics after all modules finish loading. Error details (if any) or “no error” are displayed below the table.
Package manager configuration:
- Tsinghua mirror sources (GNU + NonGNU + MELPA)
- MELPA official as fallback
use-packageinitialization (always-ensure,expand-minimally)- Deferred
package-initialize: only runs when first package install is needed - Network proxy (commented out by default, enable as needed)
Basic UI configuration:
- Platform detection (
skemacs-is-mac,skemacs-is-linux,skemacs-is-windows) - Disable startup welcome screen
- Confirm before quit
- Disable toolbar / menubar / scrollbar
- Column number display, pixel scroll, silent bell
Editing behavior:
- Auto-pair brackets (
electric-pair-mode) - Paren highlighting (
show-paren-mode) - Selection replacement (
delete-selection-mode) - Code folding (
hs-minor-mode) - Auto-revert files (
global-auto-revert-mode)
Utility functions (skemacs/ namespace):
- Navigation:
next-ten-lines,previous-ten-lines - Window:
split-window-vertically,split-window-horizontally,shrink/enlarge-window - Clipboard:
copy-to-clipboard(cross-platform macOS/Linux/Windows) - Display:
toggle-line-numbers-type(relative/absolute) - Org:
open-org-directory
Defines prefix keys and global keybindings independent of packages. See Key Bindings Reference.
All modules reside in modules/ and are loaded alphabetically. Each is self-contained with package declarations, configuration, and keybindings.
Theme management with system appearance auto-detection. Supports both local themes (bundled in themes/) and third-party theme packages (auto-installed via use-package).
On macOS, automatically detects system dark/light mode at startup via AppleInterfaceStyle. Configurable via:
| Variable | Default | Description |
|---|---|---|
skemacs-dark-theme | modus-vivendi-tritanopia | Theme used when system is dark |
skemacs-light-theme | modus-operandi-tinted | Theme used when system is light |
skemacs-default-theme | (auto-detected) | Startup theme based on system mode |
skemacs-theme-list | (all available themes) | Candidate list for theme switching |
| Source | Themes |
|---|---|
| Local (Modus) | modus-operandi-tinted (light), modus-vivendi-tritanopia (dark) |
| doom-themes | doom-one, doom-vibrant, doom-dracula, doom-gruvbox, doom-nord, etc. |
| ef-themes | ef-autumn, ef-spring, ef-summer, ef-winter, ef-dark, ef-light, etc. |
| catppuccin | catppuccin (mocha flavor) |
| Function | Description |
|---|---|
skemacs/switch-theme | Interactive theme selection (completing-read) |
skemacs/cycle-theme | Cycle to next theme in skemacs-theme-list |
skemacs/toggle-light-dark | Toggle between light and dark theme |
skemacs/load-theme | Load a specific theme by symbol name |
See Theme Bindings for keybindings.
Modern minibuffer completion framework replacing the default completing-read UI:
| Package | Role |
|---|---|
| vertico | Vertical candidate list UI in the minibuffer |
| vertico-directory | Path-aware navigation (DEL deletes path component) |
| orderless | Flexible matching: space-separated terms, any order |
| marginalia | Rich annotations beside candidates |
| consult | Enhanced search, navigation, and buffer commands |
| embark | Context-actions on candidates (like a right-click menu) |
| embark-consult | Integration bridge between Embark and Consult |
| savehist | Persist minibuffer history across sessions (built-in) |
See Completion & Search Bindings for all keybindings.
Displays available keybinding hints after pressing a prefix key. Uses Emacs 30+ built-in which-key.
Tracks recently opened files (recentf-mode) and provides ibuffer as an enhanced buffer list.
| Key | Command | Description |
|---|---|---|
C-x b r | recentf-open | Recent files (completing) |
C-x b R | recentf-open-files | Recent files (list) |
C-x b l | ibuffer | Buffer list |
Dired enhancements: auto-enable dired-omit-mode to hide clutter files (.DS_Store, Thumbs.db, etc.).
LSP integration via lsp-bridge for code intelligence (completion, diagnostics, navigation). Includes language server setup script (setup-lsp.sh) which:
- Installs Node.js, Volar, vtsls, and TypeScript
- Creates Python virtual environment for lsp-bridge dependencies
- Clones lsp-bridge source code
- Generates langserver override configs (
lsp-bridge-langserver/) to use vtsls instead oftypescript-language-serverfor TypeScript, JavaScript, TSX, and JSX files
Web development support via web-mode for HTML, CSS, JSX, Vue, and template files.
Highlights all occurrences of the symbol under cursor in prog-mode buffers via the highlight-symbol package.
- Auto-highlights after 0.3s idle time
- Jump between occurrences with
C-j h n/C-j h p - Query-replace symbol in buffer with
C-j h r
See Highlight Symbol Bindings for all keybindings.
Fast cursor jumping to any visible position via avy. Type a few characters and avy overlays hint characters on all matching positions — press the hint to jump there instantly.
- Searches across all visible windows (
avy-all-windows t) - Uses home row keys (
a s d f g h j k l) for hint characters - Background dimming for better hint visibility
avy-goto-char-timertimeout: 0.5s (configurable viaavy-timeout-seconds)
See Avy Bindings for keybindings.
Quick window jumping via ace-window. Replaces the built-in other-window on C-x o:
- When 2 windows: jumps directly to the other window
- When 3+ windows: displays a numbered label on each window for quick selection
- Uses home row keys (
a s d f g h j k l) for window labels
| Key | Function | Description |
|---|---|---|
C-x o | ace-window | Jump to window (replaces default) |
Smart line beginning/end navigation via mwim (Move Where I Mean). Enhances the default C-a and C-e behavior:
C-a(mwim-beginning): first press moves to beginning of code (skipping indentation), second press moves to actual line start (column 0)C-e(mwim-end): first press moves to end of code (before trailing comments), second press moves to actual line end
See Mwim Bindings for keybindings.
Tree-based undo/redo via undo-tree, replacing Emacs default linear undo. Provides a hydra panel (C-j u) for quick undo/redo operations and a visual undo tree browser.
global-undo-tree-modeenabled globally- Auto-save undo history disabled (
undo-tree-auto-save-history nil) - Depends on
hydra(:after hydra)
See Undo Tree Bindings for keybindings.
Project management via Emacs built-in project.el (28+). Automatically detects project root via version control (Git etc.) and provides project-scoped file finding, searching, compilation, and buffer management.
Beyond default VC-based detection, the following marker files are also recognized as project roots:
| Marker File | Language/Tool |
|---|---|
.project | Custom marker |
Makefile | Make |
package.json | Node.js |
Cargo.toml | Rust |
go.mod | Go |
pyproject.toml | Python |
pom.xml | Java (Maven) |
build.gradle | Java (Gradle) |
When switching projects (C-j p p), a menu is displayed with available actions:
| Key | Action |
|---|---|
f | Find file |
g | Find regexp |
d | Dired |
e | Eshell |
b | Switch buffer |
c | Compile |
See Project Management Bindings for all keybindings.
File tree sidebar via treemacs. Provides a project-aware file explorer with Git status integration, file watching, and directory collapsing.
| Package | Role |
|---|---|
| treemacs | File tree sidebar (main package) |
| treemacs-magit | Git status integration (after magit operations) |
| treemacs-icons-dired | Treemacs icons in dired buffers (GUI only) |
| Setting | Value | Description |
|---|---|---|
treemacs-width | 35 | Sidebar width in characters |
treemacs-is-never-other-window | t | C-x o skips treemacs window |
treemacs-collapse-dirs | 3 | Collapse up to 3 consecutive single-child dirs |
treemacs-follow-mode | t | Auto-follow current buffer |
treemacs-filewatch-mode | t | Auto-refresh on filesystem changes |
treemacs-indent-guide-style | 'line | Show indentation guide lines |
Note: treemacs-icons-dired only activates in GUI Emacs (display-graphic-p). In terminal Emacs it is skipped to avoid garbled icons without Nerd Font.
See Treemacs Bindings for keybindings.
Git integration via Magit (full Git client) and diff-hl (gutter modification markers).
| Package | Role |
|---|---|
| magit | Complete Git porcelain: stage, commit, push, pull, rebase, blame, log |
| diff-hl | Fringe/margin markers showing added/changed/deleted lines |
- Magit status opens in the same window (no split)
- Commit message editor sets
fill-columnto 72 with indicator line diff-hlenabled globally; auto-refreshes after magit operations- In terminal Emacs,
diff-hluses margin mode (no fringe available)
See Git Bindings for keybindings.
Multi-cursor editing via multiple-cursors, with keybindings under C-j m prefix.
| Package | Role |
|---|---|
| multiple-cursors | Create and manage multiple cursors simultaneously |
- Select a word or region
- Use
C-j m n/C-j m pto incrementally add cursors on matching occurrences - Use
C-j m N/C-j m Pto skip unwanted matches - Use
C-j m ato mark all matches at once - Use
C-j m lto place a cursor on each line of a selected region - Type normally — all cursors edit simultaneously
- Press
C-gto exit multi-cursor mode
Additional entry point: C-S-<mouse-1> toggles a cursor at click position.
See Multiple Cursors Bindings for all keybindings.
Colorizes nested parentheses/brackets/braces by depth via rainbow-delimiters. Each nesting level gets a distinct color, making it easy to visually match delimiters. Especially useful for Lisp-family languages.
- Enabled automatically in all
prog-modebuffers - No keybindings (purely visual enhancement)
High-performance terminal emulator via vterm, based on the libvterm C library. Supports full terminal features (colors, cursor movement, scrolling) with performance far exceeding ansi-term.
First-time loading auto-compiles the C module. System requirements:
| OS | Install Command | Notes |
|---|---|---|
| macOS | brew install cmake libtool | libtool installs as glibtool; system Apple libtool is incompatible |
| Ubuntu | sudo apt install cmake libtool-bin |
| Setting | Value | Description |
|---|---|---|
vterm-max-scrollback | 10000 | Maximum scrollback lines |
vterm-kill-buffer-on-exit | t | Auto-close buffer when shell exits |
vterm-shell | $SHELL or /bin/zsh | Use system default shell |
vterm-buffer-name-string | "vterm: %s" | Buffer naming pattern |
skemacs/vterm-toggle (C-j v t) provides smart switching:
- If currently in vterm: switch back to previous buffer
- If not in vterm: switch to an existing vterm buffer, or create a new one
See Vterm Bindings for keybindings.
AI coding agent integration via agent-shell, powered by ACP (Agent Client Protocol). Provides a native Emacs comint-mode shell to interact with multiple AI agents through a unified interface.
| Agent | ACP Adapter | Binary | Description |
|---|---|---|---|
| Claude Code | @zed-industries/claude-code-acp | claude-code-acp | Anthropic Claude Code |
| Cursor Agent | @blowmage/cursor-agent-acp | cursor-agent-acp | Cursor IDE agent |
| Gemini CLI | @google/gemini-cli | gemini | Google Gemini (--experimental-acp) |
ACP adapters are installed into the project-local nodejs/ directory via setup-agents.sh:
cd ~/.emacs.d && bash setup-agents.shThis uses the same built-in Node.js (nodejs/bin/node) as setup-lsp.sh. Adapter binaries are installed to nodejs/bin/.
To avoid conflicts with other Node.js versions in system $PATH, the module does not modify global exec-path or $PATH. Instead:
agent-shell-*-commandis set to the full path of each binary (e.g.nodejs/bin/claude-code-acp)agent-shell-*-environmentprovides an independentPATHfor each agent subprocess, ensuring#!/usr/bin/env noderesolves to the project-localnodejs/bin/node
Each agent requires one-time authentication before first use:
| Agent | Method |
|---|---|
| Claude Code | Login-based OAuth (browser opens automatically on first start) |
| Cursor Agent | Pre-authenticate via cursor-agent login in terminal |
| Gemini CLI | Login-based OAuth (browser opens automatically on first start) |
Alternatively, API keys can be set via environment variables (ANTHROPIC_API_KEY, GEMINI_API_KEY).
See AI Agent Bindings for keybindings.
Native Claude Code CLI integration via claude-code-ide, powered by MCP (Model Context Protocol). Unlike simple terminal wrappers, this creates a bidirectional bridge between Claude and Emacs — Claude can access Emacs’ LSP, xref, tree-sitter, imenu, and project features through MCP tools.
| Feature | Description |
|---|---|
| MCP Tools | Claude accesses xref, tree-sitter, imenu, project info via MCP |
| IDE Diff (ediff) | Visual diff with interactive editing before applying changes |
| Multi-project | Each project gets its own Claude session, auto-detected |
| Diagnostics | Flycheck/Flymake integration for error awareness |
| Selection tracking | Claude knows your current file and selected text |
| Side window | Claude opens in a configurable side window (default: right) |
Installed via use-package :vc from GitHub (requires Emacs 30+). No manual setup needed beyond having the Claude Code CLI in $PATH.
| Setting | Value | Description |
|---|---|---|
claude-code-ide-terminal-backend | 'vterm | Terminal backend (vterm or eat) |
claude-code-ide-use-side-window | t | Use side window |
claude-code-ide-window-side | 'right | Window position |
claude-code-ide-window-width | 90 | Window width (columns) |
claude-code-ide-focus-on-open | t | Auto-focus on open |
claude-code-ide-use-ide-diff | t | Use ediff for code changes |
Enabled via claude-code-ide-emacs-tools-setup in :config. Built-in tools:
| Tool | Description |
|---|---|
xref-find-references | Find all references to a symbol in project |
xref-find-apropos | Find symbols matching a pattern across project |
treesit-info | Get tree-sitter syntax tree information |
imenu-list-symbols | List all symbols in a file |
project-info | Get project directory, files, etc. |
See Claude Code IDE Bindings for keybindings.
Default read-only file browsing via Emacs built-in view-mode. All files opened via find-file (C-x C-f) automatically enter view-mode, preventing accidental edits. Press C-x C-q to exit read-only mode and start editing.
- Prevents accidental changes to files you’re only reading
- Provides convenient single-key navigation (
SPC,n,p,q, etc.) - Zero dependencies — uses Emacs built-in
view-mode
See Readonly / View-Mode Bindings for all keybindings.
[Disabled by default] — Remote file access via Emacs built-in TRAMP (Transparent Remote Access, Multiple Protocols). Transparently edit files on remote servers as if they were local.
Use C-x C-f (or C-x d for directories) and enter a remote path:
| Path Format | Description |
|---|---|
/ssh:user@host:/path/to/file | Basic SSH access |
/ssh:user@host#2222:/path | Non-default port |
/ssh:myalias:/path | SSH config alias |
/ssh:user@host\vert{}sudo:host:/etc/conf | Remote sudo editing |
/sudo::/etc/hosts | Local sudo |
/ssh:user@jump\vert{}ssh:user@target:/p | Multi-hop (jump host) |
| Setting | Value | Description |
|---|---|---|
tramp-default-method | "ssh" | Default connection method |
tramp-verbose | 1 | Minimal logging (0=silent, 10=most verbose) |
remote-file-name-inhibit-cache | nil | Enable file name cache for performance |
tramp-use-ssh-controlmaster-options | t | Reuse SSH ControlMaster connections |
Remote paths also disable vc (version control) queries to avoid slow Git lookups over SSH.
Remove "init-tramp" from skemacs-disabled-modules in custom.el.
For best performance, configure SSH connection multiplexing in ~/.ssh/config:
Host *
ControlMaster auto
ControlPath ~/.ssh/sockets/%r@%h-%p
ControlPersist 600
Provides repeatable operation panels via the hydra package. Currently includes:
A sticky panel for adjusting window size. Press C-x w r to enter, then use h/j/k/l repeatedly to resize, q to quit.
| Key | Function | Description |
|---|---|---|
h | skemacs/shrink-window-horizontally | Shrink horizontally |
l | skemacs/enlarge-window-horizontally | Enlarge horizontally |
j | skemacs/shrink-window | Shrink vertically |
k | skemacs/enlarge-window | Enlarge vertically |
q | quit | Exit resize panel |
Create a new file in modules/ following this template:
;;; init-xxx.el --- Short description -*- lexical-binding: t -*-
;;; Commentary:
;; Describe the module's purpose and included packages.
;;; Code:
(use-package some-package
:ensure t
:defer t ; Lazy load when possible
:hook (some-mode . some-package-mode) ; Or use :commands
:bind
(("C-j x" . some-command) ; Keybindings defined in module
:map some-mode-map
("C-c x" . another-command))
:init
;; which-key description (if which-key is loaded)
(with-eval-after-load 'which-key
(which-key-add-key-based-replacements "C-j x" "description"))
:config
(setq some-option t))
(provide 'init-xxx)
;;; init-xxx.el ends hereAll .el files in modules/ are loaded in alphabetical order.
Add to custom.el (loaded before modules):
(setq skemacs-module-list
'("init-theme"
"init-which-key"
"init-completion"
"init-navigation"))Add to custom.el:
(setq skemacs-disabled-modules
'("init-vterm"
"init-treemacs"))- Install Emacs 29.1+
- Clone/copy this config to
~/.emacs.d/ - Install system dependencies for vterm (terminal emulator):
# macOS brew install cmake libtool # Ubuntu sudo apt install cmake libtool-bin
- (Optional) Install ACP agent adapters for AI coding agents:
cd ~/.emacs.d && bash setup-agents.sh
- Start Emacs — packages install automatically when modules need them
- Add feature modules in
modules/as needed - Set up Org directory:
mkdir -p ~/org
C-;— Jump to word beginning (type 1 char)C-'— Jump to position (type 2 chars)C-j j t— Timed char search (type then wait)M-g g— Jump to any visible line
C-j s s— Search lines in current bufferC-j s r— Ripgrep search across projectC-j s f— Find file by nameC-j s o— Jump to outline headingC-j s i— Jump to symbol (imenu)C-.— Context actions on any candidate (Embark)
C-j p p— Switch to another projectC-j p f— Find file in current projectC-j p g— Regexp search in projectC-j p d— Dired at project rootC-j p b— Switch buffer within projectC-j p c— Compile in project
C-x o— Quick jump to window (ace-window)C-x w v/s— Split windowsC-x w h/j/k/l— Navigate between windowsC-x w r— Resize panel (h/j/k/l to adjust, q to quit)C-x b b— Switch buffer (Consult: includes recentf + bookmarks)
C-j f t— Toggle treemacs sidebarC-j f s— Locate current file in treeC-j f a— Add project to workspace
C-j m n/C-j m p— Add cursors on next/previous matchC-j m a— Mark all same occurrencesC-j m l— One cursor per lineC-S-click— Toggle cursor at mouse position
C-j g g— Open Magit status panelC-j g l— View current branch logC-j g b— Blame current fileC-j g d— Diff current fileC-j g s/C-j g u— Stage / unstage current file
C-j v v— Open new terminalC-j v t— Toggle terminal (switch to existing or create new)C-j v o— Open terminal in another window
C-j a a— Start or reuse any AI agent (selection menu)C-j a c— Start Claude Code sessionC-j a u— Start Cursor Agent sessionC-j a g— Start Gemini CLI sessionC-j a i— Insert file as contextC-j a n— Start a new agent shell (even if one exists)
C-j c c— Start or switch to Claude Code (project-aware)C-j c m— Open command menu (transient)C-j c p— Send prompt from minibufferC-j c r— Resume previous sessionC-j c k— Continue most recent conversationC-j c t— Toggle Claude window visibilityC-j c @— Mention selected text in promptC-j c s— List all active sessions
C-j o a— View agendaC-j o c— Quick captureC-j o o— Open org directory
C-x a i R— Reload configC-j t— View module load times
- Automatically printed to
*Messages*after startup M-x skemacs/show-load-times— Open dedicated report bufferC-j t— Shortcut access
| Phase | gc-cons-threshold | Notes |
|---|---|---|
| During startup | 800MB | Reduce GC pauses, fast startup |
| After startup | 16MB | Normal operation, free memory |
emacs --debug-init— View full error backtraceemacs -Q— Test with vanilla Emacs- Check
*Messages*and*Warnings*buffers - Module errors won’t break startup; they’re recorded in
skemacs-module-errors
C-h k— Describe what a key doesC-h b— List all current bindingsC-h B— Embark bindings overview (if init-completion loaded)M-x describe-personal-keybindings— View all:bindcustom bindings
M-x skemacs/show-load-times— Find the slowest module- Modules marked
SLOW(>0.5s) need optimization - Try adding
:defer tto slow modules for lazy loading
- Check network connection and proxy settings
M-x package-refresh-contents— Refresh package index- Delete
~/.emacs.d/elpa/and restart - Uncomment proxy settings in
core-packages.el