👉 Support this work via GitHub Sponsors by @xenodium (check out my blog)
As you pay for those useful LLM tokens, consider sponsoring development and maintenance of this project.
agent-shell is in its infancy. It’s got rough edges and lots of features to implement still. With your help, I can make this effort more sustainable.
Thank you!
A native Emacs shell to interact with LLM agents powered by ACP (Agent Client Protocol).
With agent-shell, you can chat with the likes of Gemini CLI, Claude Code, or any other ACP-driven agent.
Note: This package is in the very early stages and is likely incomplete or may have some rough edges.
- acp.el: An ACP (Agent Client Protocol) implementation in Emacs lisp.
- agent-shell-manager: Tabulated view and management of
agent-shellbuffers. - agent-shell-sidebar: A sidebar add-on for
agent-shell.
For Anthropic’s Claude Code, follow Zed’s claude-code-acp instructions, typically something like:
npm install -g @zed-industries/claude-code-acpNote: The -g flag is required to install the binary globally so it’s available in your PATH. After installation, verify it’s available by running which claude-code-acp in your terminal.
For OpenAI’s Codex, install zed/codex-acp and ensure the `codex-acp` executable is in PATH.
For Google’s Gemini CLI, be sure to get a recent release supporting the --experimental-acp flag.
For Goose CLI, install goose and ensure the `goose` executable is in PATH.
For Qwen Code, install with:
npm install -g @qwen-code/qwen-code@latestSee https://github.com/QwenLM/qwen-code for details.
agent-shell is powered by built-in comint-shell, via shell-maker, available on MELPA.
Both agent-shell and its dependency acp.el are now available on MELPA.
You can install via:
(use-package agent-shell
:ensure t)This will automatically install the required dependencies (acp.el and shell-maker).
If you are using Doom Emacs and would like to use the package! macro:
(package! shell-maker)
(package! acp)
(package! agent-shell)Run doom sync and restart.
Include require before configuration:
(require 'acp)
(require 'agent-shell)
;; rest of config...Configure authentication for the agent providers you want to use.
Pass environment variables to the spawned agent process by customizing the `agent-shell-*-environment` variable with `agent-shell-make-environment-variables`. The helper accepts key/value pairs and exports them when the agent starts.
(setq agent-shell-anthropic-claude-environment
(agent-shell-make-environment-variables
"ANTHROPIC_API_KEY" (auth-source-pass-get "secret" "anthropic-api-key")
"HTTPS_PROXY" "http://proxy.example.com:8080"))By default, the agent process starts with a minimal environment. To inherit environment variables from the parent Emacs process, use the `:inherit-env t` parameter in `agent-shell-make-environment-variables`:
(setenv "ANTHROPIC_API_KEY" (auth-source-pass-get "secret" "anthropic-api-key"))
(setq agent-shell-anthropic-claude-environment
(agent-shell-make-environment-variables :inherit-env t))This ensures that environment variables like `PATH`, `HOME`, and others from your Emacs session are available to the agent process, while still allowing you to override or add specific variables.
You can load environment variables from .env files using the `:load-env` parameter. This supports both single and multiple files:
;; Load from a single .env file
(setq agent-shell-anthropic-claude-environment
(agent-shell-make-environment-variables
:load-env "~/.env"
"CUSTOM_VAR" "custom_value"))
;; Load from multiple .env files
(setq agent-shell-anthropic-claude-environment
(agent-shell-make-environment-variables
:load-env '("~/.env" ".env.local")
:inherit-env t))The .env files should contain variables in the format `KEY=value`, with one variable per line. Comments (lines starting with `#`) and empty lines are ignored.
For login-based authentication (default):
(setq agent-shell-anthropic-authentication
(agent-shell-anthropic-make-authentication :login t))For API key authentication:
;; With string
(setq agent-shell-anthropic-authentication
(agent-shell-anthropic-make-authentication :api-key "your-anthropic-api-key-here"))
;; With function
(setq agent-shell-anthropic-authentication
(agent-shell-anthropic-make-authentication
:api-key (lambda () (auth-source-pass-get "secret" "anthropic-api-key"))))For alternative Anthropic-compatible API endpoints, configure via environment variables:
(setq agent-shell-anthropic-claude-environment
(agent-shell-make-environment-variables
"ANTHROPIC_BASE_URL" "https://api.moonshot.cn/anthropic"
"ANTHROPIC_MODEL" "kimi-k2-turbo-preview"
"ANTHROPIC_SMALL_FAST_MODEL" "kimi-k2-turbo-preview"))For login-based authentication (default):
(setq agent-shell-google-authentication
(agent-shell-google-make-authentication :login t))For API key authentication:
;; With string
(setq agent-shell-google-authentication
(agent-shell-google-make-authentication :api-key "your-google-api-key-here"))
;; With function
(setq agent-shell-google-authentication
(agent-shell-google-make-authentication
:api-key (lambda () (auth-source-pass-get "secret" "google-api-key"))))For Vertex AI authentication:
(setq agent-shell-google-authentication
(agent-shell-google-make-authentication :vertex-ai t))For login-based authentication (default):
(setq agent-shell-openai-authentication
(agent-shell-openai-make-authentication :login t))For API key authentication:
;; With string
(setq agent-shell-openai-authentication
(agent-shell-openai-make-authentication :api-key "your-openai-api-key-here"))
;; With function
(setq agent-shell-openai-authentication
(agent-shell-openai-make-authentication
:api-key (lambda () (auth-source-pass-get "secret" "openai-api-key"))))For OpenAI API key authentication:
;; With string
(setq agent-shell-goose-authentication
(agent-shell-make-goose-authentication :openai-api-key "your-openai-api-key-here"))
;; With function
(setq agent-shell-goose-authentication
(agent-shell-make-goose-authentication
:openai-api-key (lambda () (auth-source-pass-get "secret" "openai-api-key"))))For OAuth login-based authentication:
(setq agent-shell-qwen-authentication
(agent-shell-qwen-make-authentication :login t))By default, agent-shell includes configurations for all supported agents (Claude Code, Gemini CLI, Codex, Goose, and Qwen Code). You can customize which agents are available through the agent-shell-agent-configs variable.
M-x agent-shell - Start or reuse any of the known agents.
You can select and start any of the known agent shells (see agent-shell-agent-configs) via the agent-shell interactive command and enables reusing existing shells when available. With a prefix argument (C-u M-x agent-shell), it forces starting a new shell session, thus instantiating multiple agent shells.
Start a specific agent shell session directly:
M-x agent-shell-anthropic-start-claude-code- Start a Claude Code agent sessionM-x agent-shell-openai-start-codex- Start a Codex agent sessionM-x agent-shell-google-start-gemini- Start a Gemini agent sessionM-x agent-shell-goose-start-agent- Start a Goose agent sessionM-x agent-shell-qwen-start- Start a Qwen Code agent session
agent-shell provides rudimentary support for running agents and shell commands in containers.
Use agent-shell-container-command-runner to prefix the command that starts the agent, or a shell command that should be run so it is executed inside the container; for example:
(setq agent-shell-container-command-runner '("devcontainer" "exec" "--workspace-folder" "."))Note that any :environment-variables you may have passed to acp-make-client will not apply to the agent process running inside the container. It’s expected to inject environment variables by means of your devcontainer configuration / Dockerfile.
Next, set an agent-shell-path-resolver-function that resolves container paths in the local working directory, and vice versa.
Agent shell provides the agent-shell--resolve-devcontainer-path function for use with devcontainers specifically: it reads the workspaceFolder specified in .devcontainer/devcontainer.json, or uses the default value of /workspaces/<repository-name> otherwise.
(setq agent-shell-path-resolver-function #'agent-shell--resolve-devcontainer-path)Note that this allows the agent to access files on your local file-system. While care has been taken to restrict access to files in the local working directory, it’s probably possible for a malicious agent to circumvent this restriction.
Optional: to prevent the agent running inside the container to access your local file-system altogether and to have it read/modify files inside the container directly, in addition to setting the resolver function, disable the “read/write text file” client capabilities:
(setq agent-shell-text-file-capabilities nil)All of the above settings can be applied on a per-project basis using directory-local variables.
C-c C-c- Interrupt current agent operationTAB and Shift-TAB- Navigate interactive elements
| Custom variable | Description |
|---|---|
| agent-shell-agent-configs | The list of known agent configurations. |
| agent-shell-anthropic-authentication | Configuration for Anthropic authentication. |
| agent-shell-anthropic-claude-command | Command and parameters for the Anthropic Claude client. |
| agent-shell-anthropic-claude-environment | Environment variables for the Anthropic Claude client. |
| agent-shell-completion-mode-hook | Hook run after entering or leaving ‘agent-shell-completion-mode’. |
| agent-shell-container-command-runner | Command prefix for executing commands in a container. |
| agent-shell-cursor-command | Command and parameters for the Cursor agent client. |
| agent-shell-cursor-environment | Environment variables for the Cursor agent client. |
| agent-shell-display-action | Display action for agent shell buffers. |
| agent-shell-embed-file-size-limit | Maximum file size in bytes for embedding with ContentBlock::Resource. |
| agent-shell-file-completion-enabled | Non-nil automatically enables file completion when starting shells. |
| agent-shell-google-authentication | Configuration for Google authentication. |
| agent-shell-google-gemini-command | Command and parameters for the Gemini client. |
| agent-shell-google-gemini-environment | Environment variables for the Google Gemini client. |
| agent-shell-goose-authentication | Configuration for Goose authentication. |
| agent-shell-goose-command | Command and parameters for the Goose client. |
| agent-shell-goose-environment | Environment variables for the Goose client. |
| agent-shell-header-style | Style for agent shell buffer headers. |
| agent-shell-openai-authentication | Configuration for OpenAI authentication. |
| agent-shell-openai-codex-command | Command and parameters for the OpenAI Codex client. |
| agent-shell-openai-codex-environment | Environment variables for the OpenAI Codex client. |
| agent-shell-opencode-authentication | Configuration for OpenCode authentication. |
| agent-shell-opencode-command | Command and parameters for the OpenCode client. |
| agent-shell-opencode-environment | Environment variables for the OpenCode client. |
| agent-shell-path-resolver-function | Function for resolving remote paths on the local file-system, and vice versa. |
| agent-shell-permission-icon | Icon displayed when shell commands require permission to execute. |
| agent-shell-qwen-authentication | Configuration for Qwen Code authentication. |
| agent-shell-qwen-command | Command and parameters for the Qwen Code client. |
| agent-shell-qwen-environment | Environment variables for the Qwen Code client. |
| agent-shell-screenshot-command | The program to use for capturing screenshots. |
| agent-shell-show-config-icons | Whether to show icons in agent config selection. |
| agent-shell-show-welcome-message | Non-nil to show welcome message. |
| agent-shell-text-file-capabilities | Whether agents are initialized with read/write text file capabilities. |
| agent-shell-thought-process-icon | Icon displayed during the AI’s thought process. |
| agent-shell-ui-mode-hook | Hook run after entering or leaving ‘agent-shell-ui-mode’. |
| Binding | Command | Description |
|---|---|---|
| agent-shell | Start or reuse an existing agent shell. | |
| agent-shell–display-buffer | Toggle agent SHELL-BUFFER display. | |
| agent-shell-add-region | Add region to last accessed shell buffer in project. | |
| agent-shell-anthropic-start-claude-code | Start an interactive Claude Code agent shell. | |
| agent-shell-clear-buffer | Clear the current shell buffer. | |
| agent-shell-completion-mode | Toggle agent shell completion with @ or / prefix. | |
| agent-shell-cursor-start-agent | Start an interactive Cursor agent shell. | |
| agent-shell-cycle-session-mode | Cycle through available session modes for the current `agent-shell’ session. | |
| agent-shell-delete-interaction-at-point | Delete interaction (request and response) at point. | |
| agent-shell-fakes-load-session | Load and replay a traffic session from file. | |
| agent-shell-google-start-gemini | Start an interactive Gemini CLI agent shell. | |
| agent-shell-goose-start-agent | Start an interactive Goose agent shell. | |
| agent-shell-help-menu | Transient menu for `agent-shell’ commands. | |
| agent-shell-insert-file | Insert a file into `agent-shell’. | |
| agent-shell-insert-shell-command-output | Execute a shell command and insert output as a code block. | |
| C-c C-c | agent-shell-interrupt | Interrupt in-progress request and reject all pending permissions. |
| agent-shell-jump-to-latest-permission-button-row | Jump to the latest permission button row. | |
| agent-shell-mode | Major mode for agent shell. | |
| agent-shell-new-shell | Start a new agent shell. | |
| S-<return> | agent-shell-newline | Insert a newline, and move to left margin of the new line. |
| C-<down> or M-n | agent-shell-next-input | Cycle forwards through input history. |
| <tab> or TAB | agent-shell-next-item | Go to next item. |
| agent-shell-next-permission-button | Jump to the next button. | |
| agent-shell-openai-start-codex | Start an interactive Codex agent shell. | |
| agent-shell-opencode-start-agent | Start an interactive OpenCode agent shell. | |
| C-<up> or M-p | agent-shell-previous-input | Cycle backwards through input history, saving input. |
| S-TAB or <backtab> | agent-shell-previous-item | Go to previous item. |
| agent-shell-previous-permission-button | Jump to the previous button. | |
| agent-shell-qwen-start | Start an interactive Qwen Code CLI agent shell. | |
| agent-shell-rename-buffer | Rename current shell buffer. | |
| agent-shell-reset-logs | Reset all log buffers. | |
| agent-shell-restore-session-from-transcript | Restore session from file transcript (or HISTORY). | |
| agent-shell-run-all-tests | Run all agent-shell tests in batch mode. | |
| C-x C-s | agent-shell-save-session-transcript | Save shell transcript to file. |
| M-r | agent-shell-search-history | Search previous input history. |
| agent-shell-send-current-file | Insert a file into `agent-shell’. | |
| agent-shell-send-file | Insert a file into `agent-shell’. | |
| agent-shell-send-other-file | Prompt to send a file into `agent-shell’. | |
| agent-shell-send-region | Send region to last accessed shell buffer in project. | |
| agent-shell-send-screenshot | Capture a screenshot and insert it into `agent-shell’. | |
| agent-shell-set-session-mode | Set session mode (if any available). | |
| RET | agent-shell-submit | Submit current input. |
| agent-shell-toggle | Toggle agent shell display. | |
| agent-shell-toggle-logging | Toggle logging. | |
| agent-shell-ui-backward-block | Jump to the previous block. | |
| agent-shell-ui-forward-block | Jump to the next block. | |
| agent-shell-ui-mode | Minor mode for SUI block navigation. | |
| agent-shell-ui-toggle-dialog-block-at-point | Toggle visibility of dialog block body at point. | |
| agent-shell-version | Show `agent-shell’ mode version. | |
| agent-shell-view-acp-logs | View agent shell ACP logs buffer. | |
| agent-shell-view-traffic | View agent shell traffic buffer. |
Before implementing new features, please file a feature request first to discuss the proposal. This helps ensure alignment with the project’s direction and prevents unnecessary work.
As the maintainer, I must be mindful of all features I accept since I inherit the code to maintain it. Some features may be better suited as separate packages (like agent-shell-sidebar).
I’ll gladly promote your package wherever possible.
There are lots of ways to accomplish things in elisp. While the following are merely personal preferences, as maintainer, it really simplifies things for me to try to limit the number of ways to accomplish things.
This project relies on alists for much of its functionality. Sure, we can also use plists, hashtables, etc.
Unless we have a strong argument to use something else, please stick with alists (and : keywords).
'((:species . "Cat")
(:name . "Whiskers")
(:age . 4)
(:color . "Gray")
(:favorite-toy . "Feather Wand"))Accessing and working with lists? Please prefer seq.el, unless we have a strong argument to use an alternative.
(setq animals
(list
'((:species . "Cat")
(:name . "Whiskers")
(:age . 4)
(:color . "Gray"))
'((:species . "Dog")
(:name . "Buddy")
(:age . 6)
(:color . "Brown"))))
(seq-first animals)Accessing and working with alists? Please prefer map.el unless we have a strong argument to use an alternative.
(setq animal (seq-first animals))
(map-elt animal :species)While I’m a fan of cl-defun, please limit cl usage to cl-defun if possible. Nothing against cl-lib. I’m just limiting the surface and number of idioms I need to keep in my head to maintain the codebase. Often, seq.el and map.el can do the job just fine.
cl-defun, on the other hand, please do! I’m a fan of named parameters (yay for self-documenting), so use &key if possible.
(cl-defun describe (&key animal)
"Describe an ANIMAL, which is an alist of properties like :species, :name, :age, :color."
(message "This is a %d-year-old %s %s named %s."
(map-elt animal :age 0)
(map-elt animal :color "Unknown Color")
(map-elt animal :species "Unknown Species")
(map-elt animal :name "Unnamed")))
(describe :animal '((:species . "Cat")
(:name . "Whiskers")
(:age . 4)
(:color . "Gray")))Please try to look for a similar feature in the code base and replicate an existing pattern usage if possible.
Before submitting a PR, please run:
M-x checkdoc- Ensures documentation consistencyM-x byte-compile-file- Identifies compilation warnings
I’m aware, we’re a bit light on tests, but we started adding some tests. If adding a new feature, please try to add tests.
Tests live under the tests directory:
ls tests/*tests.elOpening any file under the tests directory will load the agent-shell-run-all-tests command.
Run tests with M-x agent-shell-run-all-tests.
Made with contrib.rocks.
