- Emacs Lisp 100%
| screenshots | add README | |
| .gitattributes | add README | |
| .gitignore | initial opencode-mode | |
| AGENTS.md | add AGENTS.md | |
| LICENSE | start | |
| opencode-api.el | support revert message and unrevert | |
| opencode-common.el | implement opencode-visit-last-idle and opencode-select-idle | |
| opencode-sessions.el | support revert message and unrevert | |
| opencode.el | fix opencode-new-worktree | |
| README.org | add README | |
- Installation
- Connecting
- Security
- Project Management
- Session Management
- Chat Sessions
- Notifications
- Commands
- Configuration
An emacs UI to opencode - an open source AI coding agent. This provides two sets of advantages over the official TUI:
- A better TUI and GUI
Emacs is a mature TUI and GUI framework, that while janky in its own way, is
far less janky than the TUIs the new agentic coding tools have written from
scratch. This package builds on a solid foundation of comint, vtable,
diff-mode, markdown-mode, emacs' completion system, and more, to offer a
(IMO) nicer UI. Also if you're an emacs user, the UI is more consistent: goto
next or previous prompt,
comint-kill-output-to-kill-ring, and everything else works the same as in any other repl or shell based on comint mode, completion and filtering works the same as everywhere else in emacs, and everything is just a text buffer where all your usual editing and other commands work as expected. -
Emacs integration
- add any emacs buffer to chat context with
opencode-add-buffer - integration with magit is possible,
opencode-new-worktreewill create a new git branch and worktree for the current project, and start an opencode session in it - use
dabbrev-expandin the chat window to complete long variable or function names from your code buffers
Not much so far, but my initial focus has just been to make a usable UI, while deeper emacs integration will come over time.
- add any emacs buffer to chat context with
Installation
When this package is a bit more stable I'll package it on MELPA, for now install from git. This package depends on magit, plz, and markdown-mode.
Manual
Clone this repository and add it to your load path.
(add-to-list 'load-path "/path/to/opencode.el")
(require 'opencode)
With straight.el
(use-package opencode
:straight (opencode :type git :host codeberg :repo "sczi/opencode.el"))
In Doom Emacs
(package! opencode
:recipe (:host codeberg :repo "sczi/opencode.el"))
Connecting
Automatic
M-x opencode will start a headless opencode server with opencode serve if one
isn't already running, and then open a Session Management buffer for the current
project.
Manual
M-x opencode-connect will prompt for the host and port of an opencode server to
connect to.
Security
This uses opencode's HTTP server, which gives an attacker who finds an XSS in
any *.opencode.ai domain code execution in your opencode process when you visit
the attacker's website or click a link. Also opencode's permission system,
especially for bash, is not nearly as fine-grained as claude's. However, I don't
think this really matters. Any coding agent with the ability to write and
execute code is by design a potential RCE and should be untrusted. One approach
I'd recommend is to develop inside virtual machines or at least unprivileged
containers managed by incus. If you use btrfs or ZFS for your incus storage
pool, then incus copy is almost instant. So you can have a VM with emacs and
opencode and your project, but without secrets or sensitive data, and spawn a
copy to do agent-assisted development in. When you finish, push the changes to a
git repo in a shared folder, and delete the VM. If you only need one copy at a
time, you can just snapshot and restore rather than creating and deleting
copies. Then from your somewhat more secure and non AI-infected development
environment, review and then pull the changes from the shared folder.
Project Management
In opencode, sessions are grouped by project, where each git repository is a
different project. Different git worktrees for the same repository will be
grouped in the same project. Sessions started in directories outside of any git
repository will go in the global / project. opencode-select-project will fuzzy
complete on all projects and open the Session Management buffer for the project
you select.
Session Management
/avph/opencode.el/media/branch/main/screenshots/session_management.png
Here you see a table view with information on all sessions for a given project.
Shortcuts to act on the session at point:
| <c> | Description |
|---|---|
| Key | |
x |
kill session |
R |
rename session |
s |
share session, copies a URL to the clipboard that will give a read-only view of the session |
u |
unshare session |
RET=/=o |
foo |
Buffer-wide shortcuts:
| Key | Description |
|---|---|
n |
new session |
M |
toggle MCP - fuzzy completes on all available MCPs |
U |
unshare all shared sessions for this project |
v |
toggle verbose - whether to show subagent sessions |
Chat Sessions
/avph/opencode.el/media/branch/main/screenshots/session.png /avph/opencode.el/media/branch/main/screenshots/session_with_diff.png
This is what a session buffer looks like. In the modeline at the bottom right we
see the current agent, current model, model variant if one is selected (like
low/medium/high thinking level), the percent of context used up so far, and an
indicator for if the session is idle or busy. User prompts are shown with a blue
margin highlight, information about tool calls in green, and reasoning in brown.
These colors can be configured through the opencode-*-margin-highlight faces.
| Key | Description |
|---|---|
C-c C-y |
yank code block at point |
C-c C-c |
cancel the current request |
C-c x |
delete this session |
TAB |
cycle through available primary agents |
C-c r |
rename this session |
C-c n |
start a new session in the same project |
C-c c |
fuzzy select a child session to open, children are all subagent sessions spawned by this session |
C-c p |
open parent session - when in a subagent session, open the session that spawned it |
C-c f |
select a file to add to context |
C-c b |
select a buffer to add to context |
C-c s |
share session - copy a URL to the clipboard with a read-only view of the session |
C-c u |
unshare session |
C-c U |
unshare all sessions |
C-c m |
select model |
C-c v |
select model variant |
C-c M |
select an MCP to toggle |
C-c F |
fork session from message at point - use this when a model responds badly to avoid polluting context with the bad response |
C-c R |
revert all edits done by this session after the message at point |
/ |
when at the start of a user prompt, select a slash command to run |
Notifications
If a session buffer and frame is not active, emacs will show a notification when that session's response has finished, so that you can go work on other stuff and be notified when the agent has finished.
Commands
| Command | Description |
|---|---|
| opencode | Open opencode sessions control buffer for the current project directory. |
| opencode-connect | Connect to opencode server, prompting for HOST and PORT. |
| opencode-disconnect | Disconnect from opencode server, optionally log EVENT. |
| opencode-select-project | Completing read to prompt which project to select. |
| opencode-select-session | Select among open session buffers. |
| opencode-new-worktree | Create a new git branch, and worktree prompting for a name. |
| opencode-new-session | Create a new session. With a prefix argument it will ask for TITLE. |
| opencode-select-idle | Select a session that hasn’t been visited since it went idle. |
| opencode-visit-last-idle | Open the most recent session to notify as idle. |
Configuration
- Set
opencode-default-modelfor the default model to use when the selected agent doesn't have a default model. The default setting is:
((providerID . "opencode")
(modelID . "big-pickle"))
opencode-hostandopencode-portare the default host and port to use withM-x opencode-connect- the
opencode-facesgroup configures faces used when displaying sessions