Published 2026-02-04
tag(s): #yell-at-cloud #programming #emacs
I will be honest: I haven't changed my stance on AI, yet. Maybe I will, maybe the bubble bursts before that happens.[1]
But I am offered free Copilot at work, where there's an upcoming event centered around AI. And the memories of my unemployment spell in 2023 weight enough on my thoughts that I figured that I'd rather take advantage of the opportunity to expose myself to AI, and have some familiarity on how to use it.
All my configuration is public, except the "work config", which sits in a private repository, for obvious reasons. I just finished setting up Copilot, and because documenting things is always a good idea, here is how it went.
There's a ton of options when it comes to LLM integrations in
Emacs. Gptel is the one I remembered seeing
mentioned in /r/emacs, but I ended up installing two other packages
instead: Copilot.el
and Copilot-chat.
Why? because they seemed simpler to configure. 👀
First, I installed Node[2] as instructed in
Copilot.el's README. I went with the MSI installer version.
Then I package-installed both Emacs packages,
executed copilot-install-server and copilot-login, and that was it.
It took me a minute to understand that copilot.el offers only completion and nothing more. I
actually like it that it is so focused.
In contrast, copilot-chat offers a lot more features. But it also "just works", and I
like that it follows the semi-standard design of "provide long input, C-c
C-c". Yay!
This isn't my Linux laptop, but a shared Ubuntu development server, where I run an Emacs
daemon that I installed via Snap.[3] As much as possible I try not to
request package installations, so for Node I downloaded the pre compiled binary, and I dropped
it in ~/.local.
Other than that, everything else worked in the same way than the Windows setup.
Regular readers[4][5] might recall
that I moved away
from use-package a while ago. And also that
I revamped my key
bindings. I remembered both things when setting this up.
Also, usually I wouldn't mix configuration from different packages (the horror! 😱) but in
this case, they really are too closely related not to do it.
Enough intro, here is the sauce:
(require 'copilot)
(require 'copilot-chat)
(defvar-keymap hoagie-copilot-keymap
:doc "Keymap for Work Copilot."
:name "Copilot"
"t" '("toggle copilot" . copilot-mode)
"c" '("complete" . copilot-complete)
"f" '("open chat" . copilot-chat) ;; f for "free form"
"r" '("review region" . copilot-chat-review))
(keymap-set hoagie-shortcut-keymap "c" hoagie-copilot-keymap)
(keymap-set copilot-completion-map "n" #'copilot-next-completion)
(keymap-set copilot-completion-map "p" #'copilot-previous-completion)
(keymap-set copilot-completion-map "TAB" #'copilot-accept-completion)
(keymap-set copilot-completion-map "SPC" #'copilot-clear-overlay)
(setopt copilot-idle-delay 0.5
copilot-chat-frontend 'markdown)
I delayed the completion suggestions a bit, but I am tempted to disable it entirely
(set copilot-idle-delay to nil). Will know for sure when I try
coding something meatier than today.
There's a lot more commands in Copilot-chat, but for the time being, I will M-x
them.