Skip to content
 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

152 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

emacs-opencode

An Emacs client for OpenCode. Start servers, open sessions, chat, stream responses, and manage agents — all from native Emacs buffers.

Note: This project is a work-in-progress. It is ready for daily use but does not yet have full feature parity with the OpenCode TUI. See TODO.org for a rough roadmap.

Demo

CleanShot.2026-06-23.at.11.37.12.mov

Quickstart

Requirements:

  • Emacs 29+
  • The opencode CLI on your $PATH (install docs)
  • The Emacs package request
  • bun or node recommended for performant SSE streaming; curl is used as a fallback

Clone the repository and add it to your load-path:

(add-to-list 'load-path "/path/to/emacs-opencode")
;; Install `request' from MELPA first, e.g. M-x package-install RET request RET.
(require 'emacs-opencode)

Or install with straight.el:

(use-package request
  :straight t)

(use-package emacs-opencode
  :straight (:type git :host github :repo "jdormit/emacs-opencode"))

Run M-x opencode in a project directory to create a new session. Type a prompt and press C-c C-c to send it. Use C-c C-a to choose an agent, C-c C-l to choose a model/provider, and C-c C-o to run an OpenCode slash command.

For a one-shot prompt without opening a session buffer first, use M-x opencode-ask.

To return to an existing session, use M-x opencode-open-session. To send a prompt to an existing session from another buffer, use M-x opencode-send-to-session or M-x opencode-send-context-to-session.

Session Features

Session buffers are normal Emacs buffers with an editable input area at the end. They support:

  • Streaming responses and tool output.
  • Agent, model/provider, and variant selection from the header-line controls.
  • Slash commands: type /command args or run C-c C-o.
  • Shell prompts: type !command to send shell output through OpenCode’s shell prompt endpoint.
  • Subagent mentions: type @agent and complete with C-<tab>.
  • Collapsible long shell/tool output: press RET, TAB, or click the collapse indicator.
  • Subagent navigation: press RET, TAB, or click on a task/subagent block to open its child session.
  • Reasoning/thinking blocks are hidden by default and can be toggled per buffer with C-c C-t when the OpenCode server has reasoning parts for the session.
  • Compact a session on demand with C-c C-x. Compaction keeps the transcript visible in the buffer and inserts a boundary marker showing where earlier messages were summarized for future model context.
  • Fork a session with C-c C-f. When point is on a user message, the new session starts before that message; when point is on an assistant message, it starts before the user message that prompted that response. When point is in the input area, the whole session is forked.
  • Inline handling for OpenCode permission requests and questions via the minibuffer.

Context commands include the active region when one is selected; otherwise they include the 10 lines around point plus file and line metadata when available.

Commands and Keybindings

Global Commands

CommandDescription
opencodeNew session in a project directory
opencode-askNew session with a prompt
opencode-ask-contextualNew session with prompt + buffer context
opencode-open-sessionOpen an existing session
opencode-send-to-sessionSend a prompt to an existing session
opencode-send-context-to-sessionSend prompt + context to an existing session
opencode-mcp-statusShow current OpenCode MCP server status
opencode-shutdownStop server for a directory
opencode-shutdown-allStop all servers

All commands auto-detect the current project root. Use a prefix argument (C-u) to choose a directory manually.

Session Buffer Keybindings

KeyCommand
C-c C-cSend input
C-c C-kInterrupt active prompt
C-c C-aSelect agent
C-c C-nNext agent
C-c C-pPrevious agent
C-c C-lSelect model/provider
C-c C-vSelect model variant
C-c C-]Next variant
C-c C-[Previous variant
C-c C-oRun a slash command
C-c C-tToggle reasoning/thinking blocks
C-c C-xCompact session
C-c C-fFork session
C-c C-rRefresh agents
C-<tab>Completion-at-point (slash commands)

Under evil-mode, TAB and S-TAB (or <backtab>) cycle to the next and previous agent in normal and insert states.

Lisp API

opencode-run

Run a one-shot opencode run prompt asynchronously from elisp, without opening a session buffer. Useful for scripting and building your own commands on top of OpenCode.

(opencode-run PROMPT CALLBACK
              &key model agent command dangerously-skip-permissions)

PROMPT is the message string to send. CALLBACK is invoked when the process finishes. Its arity is inspected automatically: a callback that accepts two or more arguments receives (OUTPUT SUCCESS-P), while a single-argument callback receives just OUTPUT. OUTPUT is the model’s plain-text answer (the formatted header and ANSI control sequences OpenCode writes to standard error are discarded, and trailing whitespace is trimmed). SUCCESS-P is non-nil when the process exited successfully.

The keyword arguments map to the corresponding opencode run CLI flags:

KeywordFlag
:model--model
:agent--agent
:command--command
:dangerously-skip-permissions--dangerously-skip-permissions

The command runs in default-directory; bind it to control where OpenCode runs.

(let ((default-directory "~/my-project/"))
  (opencode-run "How many Rs are in strawberry?"
                (lambda (output success-p)
                  (when success-p
                    (message "%s" output)))
                :agent "build"))

Customization

Options and faces are in the emacs-opencode customize group. Common options:

VariableDefaultDescription
opencode-server-command"opencode"Executable name or path
opencode-server-host"127.0.0.1"Server bind address
opencode-server-port4096Server port (auto-picks a free port if busy)
opencode-server-environmentnilAlist of env vars for server processes
opencode-ready-timeout5Seconds to wait for server startup
opencode-session-list-limit1000Max sessions requested for completion
opencode-session-default-agent"plan"Default agent for new sessions
opencode-session-default-variantnilDefault model variant
opencode-session-input-prompt"❯ "Prompt string in session buffers
opencode-session-show-reasoningnilShow reasoning/thinking blocks by default
opencode-session-bash-output-max-lines10Max lines of bash output shown by default
opencode-session-completion-providers(list ...)Completion-at-point providers for input
opencode-session-spinner-frames(list ...)Spinner animation frames
opencode-session-spinner-interval0.1Seconds between spinner frames
opencode-session-header-retry-message-max60Max length for retry messages in header

SSE and diagnostics options:

VariableDefaultDescription
opencode-sse-backendautoPrefer JS bridge, fall back to curl
opencode-sse-curl-command"curl"Curl executable for fallback streaming
opencode-sse-log-outputnilLog raw SSE output to the process buffer
opencode-sse-log-max-size1048576Max bytes kept in SSE log buffer
opencode-sse-profile-enablednilCollect SSE performance timing data
opencode-sse-profile-ring-size1000Number of event profile records to keep
opencode-sse-profile-slow-gap-threshold-ms50.0Threshold for recording slow chunk gaps
opencode-sse-profile-slow-gap-ring-size200Number of slow gap records to keep

Faces (opencode-session-user-face, opencode-session-assistant-face, opencode-session-tool-face, opencode-session-compaction-face, etc.) can be customized via M-x customize-group RET emacs-opencode.

Deep Emacs Integration

With a small amount of configuration, the OpenCode agent can interact with your live Emacs session: reading buffers, evaluating elisp, running compilation commands, and more. There are a few ways to wire this up, depending on how much access you want the agent to have and how you prefer to manage tools.

Two useful starting points:

  • emacs-mcp-server exposes Emacs primitives as MCP tools. This is the most direct way to give OpenCode structured access to buffers, diagnostics, elisp evaluation, and related operations.
  • emacsclient skill shows a lighter-weight pattern where the agent uses emacsclient to evaluate elisp or run commands against an existing Emacs server.

Configure either approach however you prefer, then point OpenCode at an Emacs-specific instruction file so the agent knows those tools are available.

Emacs-specific OpenCode Config

Create a dedicated config file (e.g. ~/.config/opencode/opencode.emacs.jsonc) that loads instructions telling the agent it’s running inside Emacs:

// ~/.config/opencode/opencode.emacs.jsonc
{
  "$schema": "https://opencode.ai/config.json",
  "instructions": [
    "~/.config/opencode/instructions/emacs.md"
  ]
}

If you use an MCP server, add its mcp entry to this config using the setup recommended by that server. If you use emacsclient, make sure Emacs is running as a server and emacsclient is on the PATH inherited by OpenCode.

And the instructions file:

<!-- ~/.config/opencode/instructions/emacs.md -->
# Emacs Session Instructions

You are running inside Emacs. You have access to the Emacs environment via
the available Emacs integration tools, such as MCP tools or emacsclient. Use
them whenever it would be best for the task at hand, e.g. reading buffers,
evaluating elisp, fetching diagnostics, or running user-facing shell commands
(tests, compilation) via `compile`.

Wiring It Together

Use opencode-server-environment to point the server process at the Emacs-specific config and pass any secrets that MCP servers or tools need:

(use-package emacs-opencode
  :straight (:type git :host github :repo "jdormit/emacs-opencode")
  :commands (opencode opencode-open-session opencode-ask opencode-ask-contextual)
  :custom
  (opencode-server-environment
   `(("OPENCODE_CONFIG" . ,(expand-file-name "~/.config/opencode/opencode.emacs.jsonc"))
      ;; Pass any additional env vars your MCP servers need:
      ("TAVILY_API_KEY" . "..."))))

With this setup, every OpenCode server started from Emacs will load the Emacs-specific config and instructions. The agent will know it’s running inside Emacs and can use whichever Emacs integration tools you configured.

About

OpenCode client for Emacs

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages