<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title>dtg</title><id>https://example.com/feeds/tags/emacs.xml</id><subtitle>Tag: emacs</subtitle><updated>2026-10-15T19:24:52Z</updated><link href="https://example.com/feeds/tags/emacs.xml" rel="self" /><link href="https://example.com" /><entry><title>Emacs as an Agentic Coding Environment</title><id>https://example.com/emacs-as-an-agentic-coding-environment.html</id><author><name>Dylan Gleason</name></author><updated>2026-10-15T14:51:00Z</updated><link href="https://example.com/emacs-as-an-agentic-coding-environment.html" rel="alternate" /><content type="html">&lt;p&gt;After evaluating and using agentic coding tools for the better part of
the year, and now finally integrating them into my development
workflow, the most salient question inevitably came to mind: how do I
make this work in &lt;a href=&quot;https://www.gnu.org/software/emacs/&quot;&gt;Emacs&lt;/a&gt;?&lt;/p&gt;
&lt;h2&gt;Background: My Emacs Journey&lt;/h2&gt;
&lt;p&gt;I am an Emacs lifer. Other than Notepad or TextEdit, I can't recall
using another editor before it, and it was &lt;em&gt;the&lt;/em&gt; editor I wrote my
first line of code in. Since picking up Emacs, I've seen numerous
editors and IDEs over the years, but none of them stuck with me or
interested me as much as Emacs.&lt;/p&gt;
&lt;p&gt;I can't place the exact date, but my journey with Emacs started back
in the late aughts. Unsurprisingly, my first encounter with it
coincided with my first experience using Linux. Back then—I think it
was in 2008 or 2009—the netbook craze was in full swing, so I bought
an Asus EEE PC on a lark, then quickly discovered how underpowered it
was running the preinstalled OEM version of Windows 7. I decided to
give Linux a try and installed &lt;a href=&quot;https://xubuntu.org/&quot;&gt;Xubuntu&lt;/a&gt;, which
was suitable for my low-spec netbook.&lt;/p&gt;
&lt;p&gt;My main machine at the time was a 1st gen Intel Macbook Pro, which I
bought in 2006. I was using it primarily for digital audio projects,
and though I wasn't yet into programming, my interest in audio
technology brought me within close proximity to it. Later, influenced
by a fellow audio technology enthusiast, programmer, and friend, I
eventually started using
&lt;a href=&quot;https://supercollider.github.io/&quot;&gt;SuperCollider&lt;/a&gt;, which opened up an
entirely new world to me.&lt;/p&gt;
&lt;p&gt;After installing Xubuntu on my netbook, my first order of business was
to install SuperCollider and continue my audio experiments
there. However, SuperCollider, being primarily a MacOS focused
project, did not ship their SCIDE integrated development environment
to Linux. The only two options were Vim and—you guessed it—Emacs. For
better or for worse (some might say worse… and they might have
a point 😅), I chose Emacs.&lt;/p&gt;
&lt;p&gt;The rest, as they say, is history.&lt;/p&gt;
&lt;h2&gt;Using Claude Code and Codex CLIs with Vterm&lt;/h2&gt;
&lt;p&gt;Back to the topic at hand. My first attempt at integrating Claude and
ChatGPT found me running Claude Code and Codex (respectively) using
&lt;a href=&quot;https://github.com/akermu/emacs-libvterm&quot;&gt;vterm&lt;/a&gt;, a modern terminal
emulator for Emacs. On second thought… allow me one more,
brief diversion into Emacs terminals before we get into vterm.&lt;/p&gt;
&lt;h3&gt;A Brief Technical Note on Emacs Terminals&lt;/h3&gt;
&lt;p&gt;Proper terminal emulation has long been considered the missing link
for Emacs users wanting to do everything from within Emacs, as most of
the available options are pretty limited.&lt;/p&gt;
&lt;p&gt;For example, the built-in
&lt;a href=&quot;https://github.com/emacs-mirror/emacs/blob/master/lisp/term.el&quot;&gt;term&lt;/a&gt;
is written in Emacs Lisp, which runs in a single thread. It creates a
shell sub-process that in turn allocates a pseudo terminal for
receiving and interpreting shell commands. Emacs handles user input,
which it then parses and sends as a string to the sub-process.&lt;/p&gt;
&lt;p&gt;From there, an event handler function called a &lt;em&gt;process filter&lt;/em&gt;
handles output generated by the sub-process. Roughly, the process
filter:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;processes each byte, one at a time, transforming each byte into an Emacs text object,&lt;/li&gt;
&lt;li&gt;applies faces for color and styling,&lt;/li&gt;
&lt;li&gt;updates the cursor position, handles scrolling, etc.,&lt;/li&gt;
&lt;li&gt;then renders the output to the buffer.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is slow when compared to a purpose-built terminal emulator app,
which can take advantage of multiple operating system threads and are
designed to stream large volumes of text quickly. Terminal emulator
apps also implement a much larger subset of terminal escape codes than
&lt;code&gt;term&lt;/code&gt;, so they are much better suited to running rich TUI
applications like Claude Code or Codex.&lt;/p&gt;
&lt;h3&gt;Enter Vterm&lt;/h3&gt;
&lt;p&gt;Emacs vterm, which is itself based on &lt;a href=&quot;https://www.leonerd.org.uk/code/libvterm/&quot;&gt;libvterm&lt;/a&gt;,
addresses a lot of these issues.  In short, it gets around the
limitations of Elisp terminals by delegating emulation to an efficient
C library, which Emacs loads as a &lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_node/elisp/Dynamic-Modules.html&quot;&gt;dynamic module&lt;/a&gt;.
Vterm fully controls parsing of terminal escape codes and maintains
the state of the terminal, tracking whether the virtual terminal screen
needs to be updated and periodically writing updates in batches to the
Emacs buffer.&lt;/p&gt;
&lt;p&gt;It's about as smooth of a terminal emulation experience as you're
likely to get from within Emacs.&lt;/p&gt;
&lt;h3&gt;Configuration&lt;/h3&gt;
&lt;p&gt;To install vterm, I first needed to install a number of dependencies
described in the &lt;code&gt;README&lt;/code&gt; From there, adding the dependency via
&lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_mono/use-package.html&quot;&gt;use-package&lt;/a&gt;
is as simple as the following bit of elisp:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elisp&quot;&gt;(use-package vterm
  :ensure t)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From there, it is just a matter of firing up a terminal and running
Claude or Codex as one normally would.&lt;/p&gt;
&lt;h3&gt;Testing&lt;/h3&gt;
&lt;p&gt;While this generally works well enough, it wasn't long before some
annoyances started to appear. For example, Claude seems to use the
&lt;code&gt;/tui fullscreen&lt;/code&gt; setting by default, and while this works great in a
dedicated terminal emulator app, it causes problems in Emacs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;vterm scrollback doesn't work. while this isn't a problem for native
terminals, this doesn't really work with vterm due to Claude Code's
alternate screen buffer design.&lt;/li&gt;
&lt;li&gt;claude's scrollback is limited to 2000 lines.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The alternative that I landed on was to just use the &lt;code&gt;/tui default&lt;/code&gt;
setting, which at least allows me to scroll back—although, even there,
I need to enable &lt;code&gt;vterm-copy-mode&lt;/code&gt; if Claude is in the middle of
writing something, as vterm will automatically scroll to newly written
output. Additionally, to avoid quickly exhausting the scrollback
limit, I needed to update my config accordingly:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elisp&quot;&gt;(use-package vterm
  :ensure t
  :init
  ;; Increase max scrollback so it isn't quickly exhausted
  ;; for longer sessions.
  (setq vterm-max-scrollback 100000))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are still yet other annoyances, for example redrawing issues
causing line heights to shift and seemingly lose focus on prompt
inputs, among others. This seems to happen quite often when resizing
the window containing the vterm buffer, and it creates an absolute
visual mess.&lt;/p&gt;
&lt;p&gt;It seemed like there has to be something else out there.&lt;/p&gt;
&lt;h2&gt;More Bells and Whistles with Claude Code IDE&lt;/h2&gt;
&lt;p&gt;By the time I arrived at &lt;a href=&quot;https://github.com/manzaltu/claude-code-ide.el&quot;&gt;Claude Code IDE&lt;/a&gt;
for Emacs, I was using Claude Code for the majority of my agentic
coding &amp;quot;needs&amp;quot;, and was hoping to find a solution that addressed many
of the problems I encountered using the vanilla vterm and claude setup I
described earlier. From the &lt;code&gt;README&lt;/code&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Claude Code IDE for Emacs provides native integration with Claude
Code CLI through the Model Context Protocol (MCP). […]
Transforms Claude into a true Emacs-aware AI assistant that works
within your existing workflow and can interact with your entire
Emacs ecosystem.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sounds promising.&lt;/p&gt;
&lt;h3&gt;Configuration&lt;/h3&gt;
&lt;p&gt;Installing Claude Code IDE via &lt;code&gt;use-package&lt;/code&gt; is also straightforward:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elisp&quot;&gt;(use-package claude-code-ide
  :ensure t
  :vc (:url &amp;quot;https://github.com/manzaltu/claude-code-ide.el&amp;quot; :rev :newest)
  :bind ((&amp;quot;C-c '&amp;quot; . claude-code-ide-menu))
  :config
  (claude-code-ide-emacs-tools-setup))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note, since the package is not available via MELPA, I have to
explicitly set the version control host and point it at the author's
Github repository. I've also added a key binding to bring up the IDE
menu, which uses &lt;a href=&quot;https://github.com/magit/transient&quot;&gt;Transient&lt;/a&gt;.
Also, in order to enable MCP integration between Emacs and Claude, I
instruct Emacs to evaluate the &lt;code&gt;claude-code-ide-emacs-tools-setup&lt;/code&gt;
function after the &lt;code&gt;claude-ide-package&lt;/code&gt; loads.&lt;/p&gt;
&lt;h3&gt;Testing&lt;/h3&gt;
&lt;p&gt;Claude Code IDE definitely improves upon the vanilla vterm setup I
described earlier.&lt;/p&gt;
&lt;p&gt;The first thing I noticed after starting a new session interactively
via &lt;code&gt;claude-code-ide&lt;/code&gt;, Emacs opens and displays a vterm buffer running
Claude in a side window, and it shows the current file I am visiting,
which is a nice touch.&lt;/p&gt;
&lt;p&gt;The automatic layout Claude Code IDE chooses is not ideal on my 14&amp;quot;
laptop, as it occupies most of the Emacs frame. Adjusting via
&lt;code&gt;(enlarge|shrink)-window-horizontally&lt;/code&gt; works, but this still seems to
intermittently cause the redrawing issues mentioned above.&lt;/p&gt;
&lt;p&gt;Also, since I am used to hiding buffers with &lt;code&gt;delete-window&lt;/code&gt;,
&lt;code&gt;delete-other-window&lt;/code&gt; etc, which don't work in this setup, I instead
invoke the &lt;code&gt;claude-code-ide-menu&lt;/code&gt; function interactively and use the
&lt;code&gt;w&lt;/code&gt; key to quickly toggle the side window. This is just a minor
workflow adjustment, and the transient menu is nice enough that this
isn't a major issue for me.&lt;/p&gt;
&lt;p&gt;Some of the more interesting bits with this setup is the MCP
integration with Emacs, which allows Claude to interact with various
Emacs capabilities from within Claude Code. Querying Claude code about
those capabilities, it shows the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;| Tool                       | Use it for                                  |
|----------------------------|---------------------------------------------|
| `imenu-list-symbols`       | Outline of a file: functions, headings      |
| `xref-find-references`     | Where an identifier is used                 |
| `xref-find-apropos`        | Search symbols by pattern                   |
| `treesit-info`             | Tree-sitter syntax tree at a spot in a file |
| `project-info`             | Project root and metadata from project.el   |
| `mcp__ide__getDiagnostics` | flycheck/flymake errors and warnings        |
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For example, running &lt;code&gt;project-info&lt;/code&gt; at the prompt (notably, it is not
a slash command) reports various info regarding the project, including
the project root, and the number of files contained within the
project. Neat.&lt;/p&gt;
&lt;p&gt;Prompting Claude to run &lt;code&gt;xref&lt;/code&gt; for a file within an Elixir project I
am working in doesn't yield much:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;|   Tool                    | Query            | Result                                    |
|---------------------------|------------------|-------------------------------------------|
| `xref-find-references`    | `compare_answer` | No references found                       |
| `xref-find-apropos`       | `batchim`        | One hit: korean.ex:125, `def has_batchim?`|
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In my tests, Claude cannot detect whether the Emacs language server is
running, so I tell them that eglot is indeed running. Claude suggests
that the MCP tool itself is problematic, so I ran
&lt;code&gt;xref-find-references&lt;/code&gt; for the &lt;code&gt;compare_answer&lt;/code&gt; function from within
the buffer containing the relevant file, with eglot running, and sure
enough it found many references to it in other project files. It seems
like this particular MCP tool is not quite there yet, unless I am
doing something wrong (which is probable).&lt;/p&gt;
&lt;p&gt;That said, I don't think I would use many of these tools via a Claude
query anyway. If I am running &lt;code&gt;xref-find-references&lt;/code&gt; or
&lt;code&gt;imenu-list-symbols&lt;/code&gt;, I am most certainly doing that from within the
source code buffer as I am bopping around the code.&lt;/p&gt;
&lt;p&gt;I do like the idea of using a transient interface to interact with the
Claude process, and it is nice to be able to send a prompt from within
the minibuffer to get around the usual multiline prompt annoyances (I
always forget to use &lt;code&gt;C-j&lt;/code&gt; instead of &lt;code&gt;Shift+Return&lt;/code&gt;). But a lot of
the problems with vterm and claude I described above still exist here,
and the split between the transient interface and the claude terminal
buffer creates a workflow that feels a bit disjoint.&lt;/p&gt;
&lt;p&gt;Overall, though, it is a net improvement over the previous solution. I
also understand that, supposedly, the &lt;a href=&quot;https://codeberg.org/akib/emacs-eat&quot;&gt;Eat&lt;/a&gt;
terminal emulator provides a better experience with Claude Code IDE
when compared to vterm, particularly with regard to the line-wrapping
woes I experienced with the latter. But I have yet to try it out.&lt;/p&gt;
&lt;h2&gt;Local Coding Agents with Ollama and Aidermacs&lt;/h2&gt;
&lt;p&gt;While settling into a reasonable workflow with Claude Code IDE, I also
wanted to explore local LLMs for agentic coding. Armed with a new
Macbook Pro with 24GB of RAM, I figured it was time to give it a try.&lt;/p&gt;
&lt;p&gt;The first solution I explored for a local LLM setup was
&lt;a href=&quot;https://aider.chat/&quot;&gt;Aider&lt;/a&gt;, an agentic coding application written in
Python. It supports both cloud-based backends like Claude, as well as
local models hosted via &lt;a href=&quot;https://ollama.com/&quot;&gt;Ollama&lt;/a&gt;, or apparently
any other model that supports an OpenAI compatible API. And,
naturally, there is an Emacs project called
&lt;a href=&quot;https://github.com/MatthewZMD/aidermacs&quot;&gt;Aidermacs&lt;/a&gt;, which integrates
Aider with Emacs.&lt;/p&gt;
&lt;h3&gt;Configuration&lt;/h3&gt;
&lt;p&gt;First, I needed to install Aider, per the docs:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-command&quot;&gt;python -m pip install aider-install
aider-install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, as per usual, I installed aidermacs via &lt;code&gt;use-package&lt;/code&gt;. Since I
wanted to use aider with a local Ollama server, I specify a hook
function to tell aider where the Ollama API base URL is located:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elisp&quot;&gt;(use-package aidermacs
  :ensure t
  :bind ((&amp;quot;C-c a&amp;quot; . aidermacs-transient-menu))
  :hook
  ((aidermacs-before-run-backend . (lambda ()
                                     (setenv &amp;quot;OLLAMA_API_BASE&amp;quot; &amp;quot;http://localhost:11434&amp;quot;)))))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Aidermacs implements a simple shell written in Emacs Lisp using
&lt;a href=&quot;https://www.gnu.org/software/emacs/manual/html_node/emacs/Shell-Prompts.html&quot;&gt;Comint&lt;/a&gt;
mode. While certainly not as fast as vterm, it is not meant to be a terminal
emulator and it doesn't need to be. It feels a lot more Emacs-y a
result. Aidermacs also exposes a transient interface, similar to
Claude Code IDE, which I found myself using a quite a bit when adding
files to the agent's context (this becomes important when dealing with
local models and context length limitations; more on that below).&lt;/p&gt;
&lt;h3&gt;Testing&lt;/h3&gt;
&lt;p&gt;Ultimately, the headaches of dealing with Aidermacs really had little
to do with Aidermacs as such, and more to do with working with highly
constrained, under-resourced local model. I had to do a lot of tuning
so that it was &amp;quot;usable&amp;quot; for agentic coding (which is to say, barely,
at least outside of smaller, tightly constrained tasks).&lt;/p&gt;
&lt;p&gt;By default, Ollama's &lt;a href=&quot;https://docs.ollama.com/context-length&quot;&gt;context length&lt;/a&gt; term
is very small for anything less than 24 GB of GPU addressable RAM;
with my 24 GB of unified memory the context is limited to 4k tokens,
so the model I was working with, &lt;code&gt;qwen3-coder:30b&lt;/code&gt;, would keep showing
me an error like this after every prompt:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Empty response received from LLM. Check your provider account?

Tokens: 1.6k sent, 0 received.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Basically the context is exhausted and the model sends back an empty
reply. I was able to resolve this issue specifying the &lt;code&gt;num_ctx&lt;/code&gt;
parameter in the &lt;code&gt;.aider.conf.yaml&lt;/code&gt; for the project:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;model: ollama_chat/qwen3-coder:30b
  extra_params:
    num_ctx: 32768 # This can be set globally via `OLLAMA_CONTEXT_LENGTH`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Trying again, the fans really started to kick into high gear on my
laptop. I noticed the Aidermacs shell prompt just kept spinning, but
when inspecting the Ollama server via &lt;code&gt;ollama ps&lt;/code&gt;, there was no
Qwen3-Coder process running. I checked the activity monitor and it
showed resident memory nearly maxed out. Since I neglected to inspect
the Ollama logs, it wasn't clear what Ollama was up to, whether it was
attempting to read/write swap or something else entirely—but my system
started slowing to a crawl so I was desperately trying to kill the
Ollama server process. Oops.&lt;/p&gt;
&lt;p&gt;On a subsequent attempt, I tried a more reasonable value of 16,384
tokens. The system no longer falls over, though the CPU still works
very hard. The results are fine, but nothing to get too excited about.&lt;/p&gt;
&lt;p&gt;That said, it does seem OK for very simple things. A unit test here, a
short shell script there. The other day I had it write a simple
waveform plotter, which worked out reasonably well, even though it
used Matplotlib instead of the GNU Plot, despite instructing it to use
the latter. 🤦&lt;/p&gt;
&lt;p&gt;With respect to Aidermacs as such, an interesting workflow
consideration is that Aider tightly integrates with Git and therefore
assumes you want to use Git. If the directory you are working in
doesn't contain a Git repo, it will ask you to create one. It also
automatically commits every change. If a particular commit doesn't
really do what it says it does, which seems to be the norm when
working with local LLMs, you're gonna be typing the &lt;code&gt;/undo&lt;/code&gt; command a
lot. While you can disable auto-commits, the Aider documentation
recommends against it.&lt;/p&gt;
&lt;p&gt;Given my frustrations with the local LLM output and my mild irritation
at Aider's opinionated workflow preferences, I put Aidermacs down for
a bit and retreated to Claude's warm embrace. And for this next,
albeit brief, phase, I stopped experimenting and decided to use a
setup that was a bit more familiar.&lt;/p&gt;
&lt;h2&gt;Terminal Emacs with Ghostty, Tmux and Claude Code&lt;/h2&gt;
&lt;p&gt;OK, I let Claude dictate the process in this brief, Emacs GUI-less
interregnum. But I went with a reliable, well-worn solution: cracking
open a good, proper terminal emulator in &lt;a href=&quot;https://ghostty.org/&quot;&gt;Ghostty&lt;/a&gt;, dusting off my
&lt;a href=&quot;https://github.com/dylangleason/dotfiles/blob/master/dot_config/tmux/tmux.conf&quot;&gt;tmux config&lt;/a&gt;,
and running Emacs and Claude in separate tmux windows. Hey, it
works—and font rendering and terminal colors in Ghostty look pretty
dang good. But still, after about a solid week using this setup, I
found myself longing for GUI Emacs. Surely, there's got to be
something else I can try, in my never-ending quest for Emacs
glory…&lt;/p&gt;
&lt;h2&gt;Agent-shell and a Unified Emacs Experience&lt;/h2&gt;
&lt;p&gt;After hearing from a fellow Emacs user and their own experience going
through a similar journey, they recommended that I look at
&lt;a href=&quot;https://github.com/xenodium/agent-shell&quot;&gt;agent-shell&lt;/a&gt;, so I did
precisely that.&lt;/p&gt;
&lt;p&gt;From the README, Emacs agent-shell is billed as&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A native Emacs shell to interact with LLM agents powered by ACP
(Agent Client Protocol).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Rather than relying on a vendor-specific TUI, agent-shell uses ACP;
ACP is to agents what LSP (Language Server Protocol) is to programming
languages. In other words, it solves the problem of each editor having
to implement custom integrations for various agents, as long as the
client and the API server used to interact with the agent implement
the protocol.&lt;/p&gt;
&lt;p&gt;Like Aidermacs, &lt;code&gt;agent-shell&lt;/code&gt; uses the familiar comint to implement
it's shell functionality, and it also supports a transient interface
for interaction, so we're in familiar Emacs territory.&lt;/p&gt;
&lt;h3&gt;Configuration&lt;/h3&gt;
&lt;p&gt;For Claude Code, I needed to install an separate, external
&lt;a href=&quot;https://github.com/agentclientprotocol/claude-agent-acp&quot;&gt;ACP client&lt;/a&gt;
to interact with the Claude Code agent. Via &lt;code&gt;npm&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-command&quot;&gt;npm install -g @agentclientprotocol/claude-agent-acp
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As per usual, I then installed the package via my Emacs init file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-elisp&quot;&gt;(use-package agent-shell
  :ensure t
  :config
  ;; Uses login-based authentication by default
  (setq agent-shell-anthropic-authentication
        (agent-shell-anthropic-make-authentication :login t)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Seeing that &lt;code&gt;agent-shell&lt;/code&gt; supports multiple different models, I also
wanted to test it with my local LLM setup, which is exposed via the
OpenCode ACP client, which I install via my package manager:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-command&quot;&gt;sudo port install opencode
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Some additional configuration is required to make it work with Ollama,
by adding the latter as provider to the OpenCode configuration at
&lt;code&gt;~/.config/opencode/opencode.json&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;{
  &amp;quot;$schema&amp;quot;: &amp;quot;https://opencode.ai/config.json&amp;quot;,
  &amp;quot;permission&amp;quot;: {
    &amp;quot;edit&amp;quot;: &amp;quot;ask&amp;quot;,
    &amp;quot;bash&amp;quot;: &amp;quot;ask&amp;quot;,
    &amp;quot;webfetch&amp;quot;: &amp;quot;allow&amp;quot;
  },
  &amp;quot;provider&amp;quot;: {
    &amp;quot;ollama&amp;quot;: &amp;quot;qwen3-coder:30b&amp;quot;,
    &amp;quot;npm&amp;quot;: &amp;quot;@ai-sdk/openai-compatible&amp;quot;,
    &amp;quot;options&amp;quot;: {
      &amp;quot;baseURL&amp;quot;: &amp;quot;http://localhost:11434&amp;quot;
    },
    &amp;quot;models&amp;quot;: {
      &amp;quot;qwen3-coder:30b&amp;quot;: {
        &amp;quot;name&amp;quot;: &amp;quot;Qwen3-Coder 30b&amp;quot;
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A dummy API key also needs to be configured, apparently:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;{
  &amp;quot;ollama&amp;quot;: {
    &amp;quot;type&amp;quot;: &amp;quot;api&amp;quot;,
    &amp;quot;key&amp;quot;: &amp;quot;ollama&amp;quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With my configuration in place, I am ready to go.&lt;/p&gt;
&lt;h3&gt;Testing&lt;/h3&gt;
&lt;p&gt;While I haven't spent too much time with &lt;code&gt;agent-shell&lt;/code&gt;, I am already
feeling like this is possibly the best solution for me, at least for
now. Similar to Aidermacs, the comint-based shell and transient
interface gives it a distinctly Emacs feel. Naturally, I spent most of
my time with the Claude ACP client, and it worked wonderfully.&lt;/p&gt;
&lt;p&gt;In particular, the shell felt comfortable and interactive enough
without feeling cluttered. Tool prompts are rendered in the shell as
buttons, which can either be clicked (useful for graphical Emacs) or
executed via single key bindings. For example, when the agent writes
code and proposes a change, it presents an option to view the diff. If
I click the &lt;code&gt;v&lt;/code&gt; key, I am presented with an easy to read diff that I
can accept or reject. And, like Aidermacs, the output isn't prone to
weird text rendering issues and line height shifts as seen in vterm.&lt;/p&gt;
&lt;p&gt;I also had a bit more luck running local agents this time around when
pairing &lt;code&gt;qwen3-coder:30b&lt;/code&gt; with the OpenCode provider. While it is
still a far cry from Claude Code, I tuned my Ollama configuration well
enough by this point that it worked OK for smaller coding tasks. To be
clear, this has little to do with &lt;code&gt;agent-shell&lt;/code&gt;. And, at least until
either my hardware or the technology improves, I think I will continue
to get better use out of local LLMs when using them as chat
interfaces, e.g. with &lt;a href=&quot;https://github.com/s-kostyaev/ellama&quot;&gt;Ellama&lt;/a&gt;,
rather than as coding agents.&lt;/p&gt;
&lt;p&gt;Still, like Aidermacs, it's nice to know that I can use both local and
other LLMs with this solution. If I want to spin up a Claude Code or
Codex session alongside a local one, it's as easy as invoking
&lt;code&gt;agent-shell&lt;/code&gt; interactively (or the &lt;code&gt;agent-shell-help-menu&lt;/code&gt;) and
starting another session with the desired provider. Unlike Aidermacs,
it also doesn't assume I want to use Git for every project.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;For a long-time Emacs user such as myself, there are now a lot of
options for working with coding agents without leaving the confines of
Emacs.&lt;/p&gt;
&lt;p&gt;While vterm paired with the Claude Code CLI is a perfectly workable
solution, the small annoyances with terminal emulation within Emacs
started to grate. Aidermacs seemed like a good alternative, given its
comint and transient style interface, but my frustration getting it to
work using local LLMs and it's opinionated workflow constraints
steered me away.&lt;/p&gt;
&lt;p&gt;After a brief return to running Emacs side-by-side with Claude Code
via Ghostty and tmux, I found Agent Shell, which, like Aidermacs, can
integrate with multiple LLM providers and uses a more Emacs native
feel. Unlike Aidermacs, it doesn't impose a Git-centric workflow and
the shell itself is a bit more interactive and user friendly.&lt;/p&gt;
</content></entry></feed>