ECA (Editor Code Assistant) Emacs is an AI-powered pair-programming client for Emacs.
Inspired by lsp-mode’s JSONRPC handling, it connects to an external eca server process to provide interactive chat, code suggestions, context management and more.
It's everything automatic and smooth as UX and re-usability across editors is the main goal of ECA.
For more details about ECA, check ECA server.
- Emacs 28.1 or later
- Custom
ecaserver binary- Server is already automatically downloaded for UX reasons unless you set
eca-custom-command
- Server is already automatically downloaded for UX reasons unless you set
- whisper.el for Speech-to-Text support (optional)
M-x package-install eca
(package! eca :recipe (:host github :repo "editor-code-assistant/eca-emacs" :files ("*.el")))- Run
M-x ecato start the eca process and initialize the workspace.
- eca-emacs will check for
eca-custom-command; - if not set, will check for a
ecaon$PATH; - if not found, will download
ecaautomatically and cache it.
- The dedicated chat window
<eca-chat>pops up. - Type your prompt after the
>and press RET. - Attach more context auto completing after the
@.
Not all, but most relevant functions and variables:
eca-chat-add-context-to-system-prompt: Add file/dirs to system prompt checking multiple modes with range support.eca-chat-add-context-to-user-prompt: Add file/dirs to user prompt checking multiple modes with range support.eca-chat-add-filepath-to-user-prompt: Add filepath mention only to user prompt checking multiple modes with range support.eca-chat-tool-call-accept-all: Acceppt all pending tool calls in chat.eca-chat-tool-call-accept-next: Acceppt next pending tool call in chat.eca-chat-tool-call-reject-next: Reject next pending tool call in chat.eca-chat-send-prompt: In case you wanna send prompts programatically in elisp.eca-chat-toggle-window: toggle chat window.eca-open-global-config: Open ECA global config file.
eca-extra-args: customize extra args to server to help debug like("--verbose")or("--log-level" "debug").eca-chat-usage-string-format: to customize what shows on mode-line for usage like costs and tokens.eca-chat-use-side-window: customize whether chat window is a side-window or a normal buffer.eca-chat-window-side: customize the chat window side.eca-chat-window-width: customize the chat window width.eca-chat-window-height: customize the chat window height.eca-chat-diff-tool: customize viewing diffs, defaults to ediff.
You can access transient_ menu with commonly commands via M-x eca-transient-menu or by pressing C-c . in eca's windows.
| Feature | key |
|---|---|
| Chat: clear | C-c C-l |
| Chat: reset | C-c C-k |
| Chat: talk | C-c C-t |
| Chat: Select behavior | C-c C-b |
| Chat: Select model | C-c C-m |
| Chat: Go to MCP details | C-c C-, |
| Chat: Accept next tool call | C-c C-a |
| Chat: Reject next tool call | C-c C-r |
| Chat: prev prompt history | C-↑ |
| Chat: next prompt history | C-↓ |
| Chat: go to prev block | C-c ↑ |
| Chat: go to next block | C-c ↓ |
| Chat: go to prev user msg | C-c C-↑ |
| Chat: go to next user msg | C-c C-↓ |
| Chat: toggle expandable content | C-c Tab |
| MCP: Go to chat | C-c C-, |
Enable eca-completion-mode and call eca-complete.
If you have whisper.el installed you can use the eca-chat-talk
command (or use the C-t keybinding) to talk to the Editor Code
Assistant. This will record audio until you press RET. Then, the
recorded audio will be transcribed to text and placed into the chat
buffer.
We recommend to use the small, it is a good trade-off between
accuracy and transcription speed.
(use-package whisper
:custom
(whisper-model "small"))Calling M-x eca with prefix C-u will ask for what workspaces to start the process.
Check before the server troubleshooting.
-
Verify environment: Check what environment variables are available to Emacs:
M-x eval-expression RET process-environment RET
-
Test ECA manually: Try running ECA from terminal to verify it works:
eca --help
-
Reset ECA: Clear the workspace and restart:
M-x eca-chat-reset M-x eca ; Start fresh
-
Check ECA installation: Verify ECA is available on your PATH or set
eca-custom-command:(setq eca-custom-command "/path/to/your/eca/binary")
-
Enable debug logging: Add extra arguments for debugging:
(setq eca-extra-args '("--verbose" "--log-level" "debug"))
-
Check environment variables: Test if your API keys are available in Emacs:
M-x eval-expression RET (getenv "ANTHROPIC_API_KEY") RET
Install and configure exec-path-from-shell to import your shell environment into Emacs:
(use-package exec-path-from-shell
:init
;; Specify the environment variables ECA needs
(setq exec-path-from-shell-variables
'("ANTHROPIC_API_KEY"
"OPENAI_API_KEY"
"OLLAMA_API_BASE"
"OPENAI_API_URL"
"ANTHROPIC_API_URL"
"ECA_CONFIG"
"XDG_CONFIG_HOME"
"PATH"
"MANPATH"))
;; For macOS and Linux GUI environments
(when (memq window-system '(mac ns x))
(exec-path-from-shell-initialize)))see - this comment
If Flyspell is causing slowdowns during LLM streaming, you can enable spell-checking only while typing and disable it on submit by adding this to your personal Emacs config:
(defun my/eca-chat-flyspell-setup ()
"Enable Flyspell during typing and disable on submit in `eca-chat-mode`."
(when (derived-mode-p 'eca-chat-mode)
;; Disable Flyspell when submitting prompts
(add-hook 'pre-command-hook
(lambda ()
(when (and (memq this-command '(eca-chat--key-pressed-return
eca-chat-send-prompt-at-chat))
flyspell-mode)
(flyspell-mode -1)))
nil t)
;; Re-enable Flyspell when typing
(add-hook 'pre-command-hook
(lambda ()
(when (and (eq this-command 'self-insert-command)
(not flyspell-mode))
(flyspell-mode 1)))
nil t)))
(add-hook 'eca-chat-mode-hook #'my/eca-chat-flyspell-setup)How it works:
Submit (Enter/Return): Disables Flyspell just before sending your prompt or programmatic send, preventing spell-checking overhead during streaming.
Typing: Re-enables Flyspell on any character insertion (self-insert-command), giving you real-time spell checking while composing.
Contributions are very welcome, please open a issue for discussion or pull request.
