Copilot.el is an Emacs plugin for GitHub Copilot.
This plugin is unofficial, however it makes use of the official @github/copilot-language-server provided by Microsoft.
Note
You need access to GitHub Copilot to use this plugin. The service introduced a free layer in early 2025.
copilot.el
requires Emacs 27+.
@github/copilot-language-server requires Node.js 22+.
Setup copilot.el
as described in the next section.
Install the copilot server by M-x copilot-install-server
.
Login to Copilot by M-x copilot-login
. You can also check the status by running M-x copilot-diagnose
(NotAuthorized
means you don't have a valid subscription).
Enjoy!
Add package definition to ~/.doom.d/packages.el
:
(package! copilot :recipe (:host github :repo "copilot-emacs/copilot.el" :files ("*.el")))
Configure copilot in ~/.doom.d/config.el
:
;; accept completion from copilot and fallback to company (use-package! copilot :hook (prog-mode . copilot-mode) :bind (:map copilot-completion-map ("<tab>" . 'copilot-accept-completion) ("TAB" . 'copilot-accept-completion) ("C-TAB" . 'copilot-accept-completion-by-word) ("C-<tab>" . 'copilot-accept-completion-by-word)))
Strongly recommend to enable childframe
option in company
module ((company +childframe)
) to prevent overlay conflict.
If pressing tab to complete sometimes doesn't work you might want to bind completion to another key or try:
(after! (evil copilot) ;; Define the custom function that either accepts the completion or does the default behavior (defun my/copilot-tab-or-default () (interactive) (if (and (bound-and-true-p copilot-mode) ;; Add any other conditions to check for active copilot suggestions if necessary ) (copilot-accept-completion) (evil-insert 1))) ; Default action to insert a tab. Adjust as needed. ;; Bind the custom function to <tab> in Evil's insert state (evil-define-key 'insert 'global (kbd "<tab>") 'my/copilot-tab-or-default))
If you would love to configure indentation here, this is an example config that may work for you:
(use-package! copilot :hook (prog-mode . copilot-mode) :bind (:map copilot-completion-map ("<tab>" . 'copilot-accept-completion) ("TAB" . 'copilot-accept-completion) ("C-TAB" . 'copilot-accept-completion-by-word) ("C-<tab>" . 'copilot-accept-completion-by-word) ("C-n" . 'copilot-next-completion) ("C-p" . 'copilot-previous-completion)) :config (add-to-list 'copilot-indentation-alist '(prog-mode 2)) (add-to-list 'copilot-indentation-alist '(org-mode 2)) (add-to-list 'copilot-indentation-alist '(text-mode 2)) (add-to-list 'copilot-indentation-alist '(closure-mode 2)) (add-to-list 'copilot-indentation-alist '(emacs-lisp-mode 2)))
Edit your ~/.spacemacs
to include the GitHub Copilot layer this will setup everything for you:
;; =================== ;; dotspacemacs/layers ;; =================== ;; add or uncomment the auto-completion layer ;; add the GitHub Copilot layer dotspacemacs-configuration-layers '( ... auto-completion github-copilot ... )
For details about the default bindings please refer to the Spacemacs documentation for the github-copilot layer.
Option 1: Load via use-package (recommended)straight.el
:
(use-package copilot :straight (:host github :repo "copilot-emacs/copilot.el" :files ("*.el")) :ensure t)
quelpa
+ quelpa-use-package
:
(use-package copilot :quelpa (copilot :fetcher github :repo "copilot-emacs/copilot.el" :branch "main" :files ("*.el")))
(use-package copilot :vc (:url "https://github.com/copilot-emacs/copilot.el" :rev :newest :branch "main"))
Use :map
, :hook
, and :config
to customize copilot.el
via use-package
.
Please make sure you have these dependencies installed (available in ELPA/MELPA):
editorconfig
f
After installing those, clone this repository then insert the below snippet into your config file.
(add-to-list 'load-path "/path/to/copilot.el") (require 'copilot)Option 1: Use
copilot-mode
to automatically provide completions
(add-hook 'prog-mode-hook 'copilot-mode)
To customize the behavior of copilot-mode
, please check copilot-enable-predicates
and copilot-disable-predicates
.
You need to bind copilot-complete
to some key and call copilot-clear-overlay
inside post-command-hook
.
Use tab to accept completions (you may also want to bind copilot-accept-completion-by-word
to some key):
(define-key copilot-completion-map (kbd "<tab>") 'copilot-accept-completion) (define-key copilot-completion-map (kbd "TAB") 'copilot-accept-completion)4. Configure LSP Settings
You can configure the underlying LSP settings by changing copilot-lsp-settings
. The complete list of available options can be found here.
Here we set the GitHub Enterprise server to https://example2.ghe.com
, exchange the URL with your own server.
(setopt copilot-lsp-settings '(:github-enterprise (:uri "https://example2.ghe.com"))) ;; allows changing the value without restarting the LSP (setq copilot-lsp-settings '(:github-enterprise (:uri "https://example2.ghe.com"))) ;; alternatively
You have to restart the LSP (M-x copilot-diagnose
) when using setq
to change the value. When logging in, the URL for the authentication flow should be the same as the one set in copilot-lsp-settings
.
Copilot.el detects the programming language of a buffer based on the major-mode name, stripping the -mode
part. Resulting languageId should match table here. You can add unusual major-mode mappings to copilot-major-mode-alist
. Without the proper language set suggestions may be of poorer quality.
(add-to-list 'copilot-major-mode-alist '("enh-ruby" . "ruby"))
In this section you'll find a listing of all the essential interactive commands provided by copilot.el
. It's important to note that by default copilot-mode
doesn't setup any keybindings for its completion commands, so you'll have to do this yourself - as shown in the "Configurations" section.
Tip
You don't need to memorize the list as you can always do M-x copilot-
followed TAB or refer to the mode's menu in Emacs's menubar.
Check the current status of the plugin. Also you can check logs in the *copilot events*
buffer and stderr output in the *copilot stderr*
buffer.
Login to GitHub, required for using the plugin.
Enable/disable copilot-mode
.
Try to complete at the current point.
copilot-accept-completionAccept the current completion.
Clear copilot overlay in the current buffer.
copilot-accept-completion-by-line / copilot-accept-completion-by-wordSimilar to copilot-accept-completion
, but accept the completion by line or word. You can use prefix argument to specify the number of lines or words to accept.
Cycle through the completion list.
Log out from GitHub.
Tip
Use M-x customize-group
RET copilot
to see all available configuration options.
The version of the @github/copilot-language-server to use. If set to nil
, the latest version will be installed.
Time in seconds to wait before starting completion (default to 0). Note that Copilot itself has a ~100ms delay because of network communication. You can disable it completely by setting it to nil
:
(setq copilot-idle-delay nil)copilot-enable-predicates / copilot-disable-predicates
A list of predicate functions with no argument to enable/disable triggering Copilot in copilot-mode
.
A list of predicate functions with no argument to enable/disable showing Copilot's completions in copilot-mode
.
A list of commands that won't cause the overlay to be cleared.
Format: '(:host "127.0.0.1" :port 7890 :username: "user" :password: "password")
, where :username
and :password
are optional.
For example:
(setq copilot-network-proxy '(:host "127.0.0.1" :port 7890))
Register a handler to be called when a request of type method is received. Return JSON serializable as result or calling jsonrpc-error
for errors. readmore
For example:
; Display desktop notification if emacs is built with d-bus (copilot-on-request 'window/showMessageRequest (lambda (msg) (notifications-notify :title "Emacs Copilot" :body (plist-get msg :message))))
Register a listener for copilot notifications.
For example:
(copilot-on-notification 'window/logMessage (lambda (msg) (message (plist-get msg :message))Wrong Position of Other Completion Popups
This is an example of using together with default frontend of company-mode
. Because both company-mode
and copilot.el
use overlay to show completion, so the conflict is inevitable. To solve the problem, I recommend you to use company-box
(only available on GUI), which is based on child frame rather than overlay.
After using company-box
, you have:
In other editors (e.g. VS Code
, PyCharm
), completions from copilot and other sources can not show at the same time. But I decided to allow them to coexist, allowing you to choose a better one at any time.
If you are using whitespace-mode
, make sure to remove newline-mark
from whitespace-style
.
copilot-log-max
(to e.g. 1000) and enable debug log (setq copilot-server-args '("--stdio" "--debug"))
, then paste related logs in the *copilot events*
, *copilot stderr*
and *copilot-language-server-log*
buffer.M-x toggle-debug-on-error
to enable stack trace).These projects helped me a lot:
Just like the copilot plugin for Intellij or VS Code?
Please take a look at copilot-chat.el
Note
It's possible that chat functionality will be added to copilot.el
as well down the road. PRs welcome!
Current maintainer(s): @bbatsov, @emil-vdw, @jcs090218, @rakotomandimby.
Retired maintainer: @zerolfx.
copilot.el is distributed under the MIT license.
Copyright © 2022-2025 copilot-emacs maintainers and contributors.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4