SkillAgentSearch skills...

Copilot.el

An unofficial Copilot plugin for Emacs.

Install / Use

/learn @copilot-emacs/Copilot.el
About this skill

Quality Score

0/100

Supported Platforms

GitHub Copilot

README

JCS-ELPA MELPA MELPA Stable CI GitHub Sponsors

Copilot.el

Copilot.el is an Emacs plugin for [GitHub Copilot][]. It provides inline completions (ghost text), an interactive chat interface, and Next Edit Suggestions — all powered by the official [@github/copilot-language-server][].

The plugin talks to the Copilot language server over JSON-RPC, using jsonrpc.el directly rather than going through an LSP client like eglot. This is a deliberate choice — most of the Copilot protocol is non-standard LSP, and a single global server is shared across all buffers and projects. See doc/design.md for the full rationale.

[!NOTE]

You need access to [GitHub Copilot][] to use this plugin. The service introduced a free tier in early 2025.

Requirements

copilot.el requires Emacs 27+ and the following packages (installed automatically from MELPA):

  • editorconfig
  • jsonrpc
  • compat
  • track-changes

[@github/copilot-language-server][] requires Node.js 22+.

Quick Start

(use-package copilot
  :ensure t
  :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)))

Then run M-x copilot-install-server and M-x copilot-login. That's it!

Installation

MELPA

The simplest way to install copilot.el is from MELPA:

(use-package copilot
  :ensure t)

Or M-x package-install RET copilot RET.

Emacs 30+ (use-package :vc)

(use-package copilot
  :vc (:url "https://github.com/copilot-emacs/copilot.el"
            :rev :newest
            :branch "main"))

Emacs 27-29 (straight / quelpa)

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")))

Manual

Clone this repository, make sure the dependencies listed in Requirements are installed, then:

(add-to-list 'load-path "/path/to/copilot.el")
(require 'copilot)

Doom Emacs

<details>

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 '(clojure-mode 2))
  (add-to-list 'copilot-indentation-alist '(emacs-lisp-mode 2)))
</details>

Spacemacs

<details>

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.

</details>

After installing the package, run M-x copilot-install-server to install the language server, then M-x copilot-login to authenticate. You can verify everything works with M-x copilot-diagnose (NotAuthorized means you don't have a valid subscription).

Configuration

Completion trigger

Use copilot-mode to automatically provide completions in a buffer:

(add-hook 'prog-mode-hook 'copilot-mode)

Or enable it globally with global-copilot-mode:

(global-copilot-mode)

To customize when completions trigger, see copilot-enable-predicates and copilot-disable-predicates. To customize when completions are displayed, see copilot-enable-display-predicates and copilot-disable-display-predicates.

Alternatively, you can call copilot-complete manually and use copilot-clear-overlay in post-command-hook to dismiss completions.

Chat

copilot-chat opens an interactive chat with GitHub Copilot using the conversation/* LSP methods. The chat buffer streams responses in real time and automatically provides the current buffer as context.

;; Start a chat (or send a follow-up if one is already open)
M-x copilot-chat

;; Send selected code with an optional prompt
M-x copilot-chat-send-region

Key bindings in the *copilot-chat* buffer:

  • C-c RET or C-c C-c — send a follow-up message
  • C-c C-k — cancel streaming, or reset if idle
  • q — quit the chat window

Customization:

  • copilot-chat-model — model to use for chat (default nil, meaning server default)

[!TIP]

Install markdown-mode for rich markdown rendering (headings, code blocks, emphasis, etc.) in the chat buffer. Without it, only basic highlighting is used.

For a more feature-rich chat experience, take a look at copilot-chat.el.

[!WARNING]

copilot-chat.el (the chep package) and copilot.el both provide an Emacs feature called copilot-chat, so they cannot be installed at the same time. Having both will cause autoload errors such as "failed to define function copilot-chat-display". If you want to use the chat built into copilot.el, make sure chep/copilot-chat.el is uninstalled, and vice versa.

Next Edit Suggestions (NES)

NES predicts the next edit you'll want to make anywhere in the file, based on your recent editing patterns. Unlike inline completions (ghost text at the cursor), NES suggestions can replace or delete existing text at any location.

[!NOTE]

NES requires copilot-language-server version 1.434.0 or newer. Run M-x copilot-reinstall-server to upgrade if needed.

Enable copilot-nes-mode in a buffer to start receiving suggestions. It can coexist with copilot-mode:

(add-hook 'prog-mode-hook #'copilot-nes-mode)

When a suggestion is pending:

  • TAB — accept the suggestion (jumps to it first if far away, applies on second press)
  • C-g — dismiss the suggestion

Customization variables:

  • copilot-nes-idle-delay — seconds of idle time before requesting a suggestion (default 0.5)
  • copilot-nes-auto-dismiss-move-count — cursor movements before auto-dismissing (default 3)
  • copilot-nes-auto-dismiss-distance — max lines between point and suggestion before auto-dismissing (default 40)

Keybindings

copilot-mode does not set any keybindings by default. Use copilot-completion-map (active while a completion overlay is visible) to bind keys:

(keymap-set copilot-completion-map "<tab>" #'copilot-accept-completion)
(keymap-set copilot-completion-map "TAB" #'copilot-accept-completion)
(keymap-set copilot-completion-map "C-<tab>" #'copilot-accept-completion-by-word)
(keymap-set copilot-completion-map "C-TAB" #'copilot-accept-completion-by-word)
(keymap-set copilot-completion-map "M-n" #'copilot-next-completion)
(keymap-set copilot-completion-map "M-p" #'copilot-previous-completion)

Fish-style keybindings

If you use company-mode or `

Related Skills

View on GitHub
GitHub Stars2.3k
CategoryDevelopment
Updated4d ago
Forks171

Languages

Emacs Lisp

Security Score

95/100

Audited on Mar 31, 2026

No findings