Claudemacs
AI Pair Programming with Claude Code in Emacs
Install / Use
/learn @cpoile/ClaudemacsQuality Score
Category
Development & EngineeringSupported Platforms
README
Claudemacs
AI pair programming with Claude Code in Emacs.
https://github.com/user-attachments/assets/a7a8348d-471c-4eec-85aa-946c3ef9d364
What makes this project different? Simplicity
- Let your LLM cli shine in the terminal
- No agents, MCP, or IDE integration -- these eat up context
Features
- Multi-tool support: Use Claude, Codex, Gemini, or other AI coding tools via configurable tool registry
- Multiple instances: Run multiple sessions of the same tool per workspace (claude, claude-2, etc.)
- Broadcast to all sessions: Use
C-uprefix to send actions to all active sessions - Workspace-aware sessions: Project-based sessions with Doom/Perspective workspace support (see Sessions)
- Session management: Switch between sessions, switch to "other" session, kill specific sessions
- System notifications: OS notifications with sound when awaiting input (see System Notifications)
- Terminal fixes: Use
uto unstick input box and reset buffer issues (see Tips) - Session resume: Resume previous sessions with tool-specific resume flags
- Execute request with context: Send request with file and line/region context
- Fix error at point: Send flycheck error to Claude with context
- Implement comment at point: Extract comment text and ask Claude to implement it
- Add file or current file: Add files with Claude's @ symbol convention
- C-g sends Esc: Old habits die hard
- Option: Swap RET and M-RET: Optionally swap keys (Claude maps RET to submit, M-RET to newline)
- Option: S-RET as newline: May be more natural
- Option: Shell environment loading: Load shell rc files for PATH and environment variables
- Transient interface: Easy-to-use menu system (default:
C-c C-e)
Table of Contents
Installation
Prerequisites
- Install Claude Code CLI
- Install the eat package in Emacs
Package Installation
Doom Emacs
Add to your packages.el:
(package! claudemacs
:recipe (:host github :repo "cpoile/claudemacs"))
Then in your config.el:
(use-package! claudemacs)
use-package with built-in :vc (Emacs 30+)
(use-package claudemacs
:vc (:url "https://github.com/cpoile/claudemacs"))
use-package with vc-use-package
(use-package claudemacs
:vc (:fetcher github :repo "cpoile/claudemacs"))
straight.el
(straight-use-package
'(claudemacs :type git :host github :repo "cpoile/claudemacs"))
Manual Installation
Clone this repository and add to your Emacs configuration:
;; Add to load path
(add-to-list 'load-path "/path/to/claudemacs")
;; Load the package
(require 'claudemacs)
Setup
Use your preferred keybinding (I use C-c C-e). I'd recommend adding it to the relevant mode-maps, instead of using a global-set-key, since that will override the very useful C-c C-e keybind in the eat-semi-char-mode-map (see Using Eat Mode section below).
(require 'claudemacs)
(define-key prog-mode-map (kbd "C-c C-e") #'claudemacs-transient-menu)
(define-key emacs-lisp-mode-map (kbd "C-c C-e") #'claudemacs-transient-menu)
(define-key text-mode-map (kbd "C-c C-e") #'claudemacs-transient-menu)
(define-key python-base-mode-map (kbd "C-c C-e") #'claudemacs-transient-menu)
;; Set a big buffer so we can search our history.
(with-eval-after-load 'eat
(setq eat-term-scrollback-size 400000))
Other useful tweaks:
;; If you want it to pop up as a new buffer. Otherwise, it will use "other buffer."
;; Personally, I use the default "other buffer" style.
(add-to-list 'display-buffer-alist
'("^\\*claudemacs"
(display-buffer-in-side-window)
(side . right)
(window-width . 0.33)))
;; Turn on autorevert because Claude modifies and saves buffers. Make it a habit to save
;; before asking Claude anything, because it uses the file on disk as its source of truth.
;; (And you don't want to lose edits after it modifies and saves the files.)
(global-auto-revert-mode t)
System Notifications
First, set claude config set --global preferredNotifChannel terminal_bell.
-- Mac --
For Mac, you need to do some setup to make notifications work.
- Run the built in
Script Editorprogram, start a new script, and rundisplay notification "Test notification" with title "Test Title" sound name "Frog" - Accept the notification permissions. (Or go into System Settings -> Notifications -> Script Editor and allow notifications there.)
Now you should receive System notifications when Claude Code is waiting for input, or when done.
Unfortunately, clicking on the notification doesn't bring you to Emacs. Open to ideas on how to fix that.
-- Linux --
For Linux systems using notify-send, notifications will automatically dismiss by default instead of persisting in the system tray. You can control this behavior with:
;; Auto-dismiss notifications (default: t)
(setq claudemacs-notification-auto-dismiss-linux t)
;; Keep notifications in system tray
(setq claudemacs-notification-auto-dismiss-linux nil)
;; Play sound with notifications (requires canberra-gtk-play)
;; Common sound IDs: "message-new-instant", "bell", "dialog-error", "dialog-warning"
(setq claudemacs-notification-sound-linux "message-new-instant")
;; Disable sound
(setq claudemacs-notification-sound-linux "")
-- Windows --
I have not tested on windows, so would appreciate any help there (PRs welcome).
Fonts
Claude Code uses many non-standard unicode characters during its thinking animations, and emojis for its summaries. They look nice, but some of them aren't included in a typical font set (even one patched with Nerd Fonts). So you'll need to add fallbacks.
The fallbacks will differ based on your system.
-- Mac --
;;
;; font insanity for Claudemacs
;;
(defun my/setup-custom-font-fallbacks-mac ()
(interactive)
"Configure font fallbacks on mac for symbols and emojis.
This will need to be called every time you change your font size,
to load the new symbol and emoji fonts."
(setq use-default-font-for-symbols nil)
;; --- Configure for 'symbol' script ---
;; We add fonts one by one. Since we use 'prepend',
;; the last one added here will be the first one Emacs tries.
;; So, list them in reverse order of your preference.
;; Least preferred among this list for symbols (will be at the end of our preferred list)
(set-fontset-font t 'symbol "Hiragino Sans" nil 'prepend)
(set-fontset-font t 'symbol "STIX Two Math" nil 'prepend)
(set-fontset-font t 'symbol "Zapf Dingbats" nil 'prepend)
(set-fontset-font t 'symbol "Monaco" nil 'prepend)
(set-fontset-font t 'symbol "Menlo" nil 'prepend)
;; Most preferred for symbols -- use your main font here
(set-fontset-font t 'symbol "JetBrainsMono Nerd Font Mono" nil 'prepend)
;; --- Configure for 'emoji' script ---
;; Add fonts one by one, in reverse order of preference.
;; Least preferred among this list for emojis
(set-fontset-font t 'emoji "Hiragino Sans" nil 'prepend)
(set-fontset-font t 'emoji "STIX Two Math" nil 'prepend)
(set-fontset-font t 'emoji "Zapf Dingbats" nil 'prepend)
(set-fontset-font t 'emoji "Monaco" nil 'prepend)
(set-fontset-font t 'emoji "Menlo" nil 'prepend)
;; (set-fontset-font t 'emoji "Noto Emoji" nil 'prepend) ;; If you install Noto Emoji
;; Most preferred for emojis -- use your main font here
(set-fontset-font t 'emoji "JetBrainsMono Nerd Font Mono" nil 'prepend))
;; to test if you have a font family installed:
; (find-font (font-spec :family "Menlo"))
;; Then, add the fonts after your setup is complete:
(add-hook 'emacs-startup-hook
(lambda ()
(progn
(when (string-equal system-type "darwin")
(my/setup-custom-font-fallbacks-mac)))))
-- Linux --
(defun my/setup-custom-font-fallbacks-linux ()
(interactive)
"Configure font fallbacks on linux for symbols and emojis.
This will need to be called every time you change your font size,
to load the new symbol and emoji fonts."
(setq use-default-font-for-symbols nil)
;; --- Configure for 'symbol' script ---
;; We add fonts one by one. Since we use 'prepend',
;; the last one added here will be the first one Emacs tries.
;; So, list them in reverse order of your preference.
;; Least preferred among this list for symbols (will be at the end of our preferred list)
;; (set-fontset-font t 'symbol "FreeSerif" nil 'prepend)
;; (set-fontset-font t 'symbol "NotoSansSymbols2" nil 'prepend)
;; (set-fontset-font t 'symbol "NotoSansCJKJP" nil '
