Note: https://yfu.tw/blog/en/open-model-harness/ — I now use
omp(Oh My Pi), and it is the only CLI actively checked against. Some omp-specific features (live-prompt window/cursor sync, clipboard image paste, selection-change notifications) require my fork, Axiweave/oh-my-pi, rather than upstream omp.
Claude Code IDE for Emacs provides project-aware terminal sessions for Claude Code, Codex, OpenCode, Pi, and Oh My Pi, with shared session management, terminal integration, and window workflows. Claude Code additionally has native integration through the Model Context Protocol (MCP), creating a bidirectional bridge between Claude and Emacs that can leverage Emacs features—from LSP and project management to custom Elisp functions.
This project is a fork of manzaltu/claude-code-ide.el and has substantially diverged with a session sidebar/manager, persistent layouts, activity tracking, expanded transient workflows, and Ghostel-only terminal support. The project name is provisional; please open an issue with naming suggestions.
- CC Manager global and repo-local sidebars, quick slots, and persistent per-session layouts
- CLI-aware start, continue, and resume workflows for Claude Code, Codex, OpenCode, Pi, and Oh My Pi; see Basic Commands
- Session state indicators in the CC Manager: Oh My Pi reports idle, working, needs-input, done, and failed over MCP; other agents use output-driven idle and working detection
- Ghostel-only terminal integration, with
vtermandeatsupport removed; see Terminal Backend Configuration - Expanded transient navigation and file-reference workflows; see Basic Commands and Session Customization
- Remote Worktree Management: explicit remote Worktree list, open, and create through the manager, plus remove/move/merge/push/prune through remote Magit
- Automatic project detection and session management
- Terminal integration with full color support using
ghostel - Image-aware
s-v/H-vpaste for local Claude Code, Codex, and Oh My Pi, plus the verified remote OMP route - CLI-specific start, continue, and resume commands for Claude Code, Codex, OpenCode, Pi, and Oh My Pi
- Claude Code MCP protocol implementation for IDE integration
- Tool support for file operations, editor state, and workspace info
- Extensible MCP tools server for accessing Emacs commands (xrefs, tree-sitter, project info, e.g.)
- Diagnostic integration with Flycheck and Flymake
- Advanced diff view with ediff integration (modify suggestions before applying)
- Tab-bar support for proper context switching
- Selection and buffer tracking for better context awareness
This package enables Claude Code to leverage the full power of Emacs through MCP tools integration. Claude can directly access and utilize Emacs capabilities including:
- Language Server Protocol (LSP) integration through xref commands for intelligent code navigation (eglot, lsp-mode and others)
- Tree-sitter for syntax tree analysis and understanding code structure at the AST level
- Imenu for structured symbol listing and navigation within files
- Project integration for project-aware operations
- Any Emacs command or function can be exposed as an MCP tool, allowing Claude to:
- Perform project-wide searches and refactoring
- Access specialized modes and their features
- Execute custom Elisp functions tailored to your workflow
This deep integration means Claude Code understands your project context and can leverage Emacs’ extensive ecosystem to provide more intelligent and context-aware assistance.
Claude Code automatically knows which file you’re currently viewing in Emacs
Claude Code can access and work with selected text in your buffers
Integrated ediff view for code changes, with Claude Code able to directly access diagnostic data (errors, warnings, etc.) from opened files
Automatically mention and reference selected text in Claude conversations
Resume previous Claude Code conversations with the –resume flag
- Emacs 28.1 or higher
- A supported coding-agent CLI installed and available in PATH: Claude Code (
claude, the default), Codex (codex), OpenCode (opencode), Pi (pi), or Oh My Pi (omp) ghostelpackage (for terminal support)
Follow the installation instructions at Claude Code Documentation.
Currently, this package is in early development.
To install using emacs-version >= 30 and use-package with the vc binding:
(use-package claude-code-ide
:vc (:url "https://github.com/axiweave/claude-code-ide.el" :rev :newest)
:bind ("C-c C-'" . claude-code-ide-menu) ; Set your favorite keybinding
:config
(claude-code-ide-emacs-tools-setup)) ; Optionally enable Emacs MCP toolsTo install using use-package and straight.el:
(use-package claude-code-ide
:straight (:type git :host github :repo "axiweave/claude-code-ide.el")
:bind ("C-c C-'" . claude-code-ide-menu) ; Set your favorite keybinding
:config
(claude-code-ide-emacs-tools-setup)) ; Optionally enable Emacs MCP toolsIn packages.el:
(package! claude-code-ide
:recipe (:host github :repo "axiweave/claude-code-ide.el"))In config.el:
(use-package! claude-code-ide
:bind ("C-c C-'" . claude-code-ide-menu) ; Set your favorite keybinding
:config
(claude-code-ide-emacs-tools-setup)) ; Optionally enable Emacs MCP toolsAfter saving the above, run: doom sync in the terminal.
The easiest way to interact with Claude Code IDE is through the transient menu interface, which provides visual access to all available commands. Simply run M-x claude-code-ide-menu to open the interactive menu.
With a C-u prefix, launch suffixes s/S, d/D, c/C, and r/R prompt for claude, codex, opencode, pi, or omp for that new session only. Uppercase suffixes still explicitly bypass permissions.
| Command | Description |
|---|---|
M-x claude-code-ide-menu | Open transient menu with all Claude Code commands |
M-x claude-code-ide-emacs-tools-setup | Set up built-in MCP tools (e.g. xref, project) |
M-x claude-code-ide | Start Claude Code for the current project |
M-x claude-code-ide-send-prompt | Send prompt to Claude from minibuffer input |
M-x claude-code-ide-continue | Continue most recent conversation in directory |
M-x claude-code-ide-resume | Resume Claude Code with previous conversation |
M-x claude-code-ide-stop | Stop Claude Code for the current project |
M-x claude-code-ide-switch-to-buffer | Switch to project’s Claude buffer |
M-x claude-code-ide-list-sessions | List all active Claude Code sessions and switch |
M-x claude-code-ide-manager-toggle-sidebar | Toggle the default CC Manager sidebar |
M-x claude-code-ide-manager-toggle-global-sidebar | Toggle the global CC Manager sidebar |
M-x claude-code-ide-manager-toggle-repo-sidebar | Toggle the repo-local CC Manager sidebar |
M-x claude-code-ide-manager-focus | Focus the default CC Manager sidebar |
M-x claude-code-ide-manager-focus-global | Focus the global CC Manager sidebar |
M-x claude-code-ide-manager-focus-repo | Focus the repo-local CC Manager sidebar |
M-x claude-code-ide-manager-refresh | Refresh the CC Manager live session list |
M-x claude-code-ide-check-status | Check if Claude Code CLI is installed and working |
M-x claude-code-ide-insert-at-mentioned | Send selected text to Claude prompt |
M-x claude-code-ide-send-escape | Send escape key to Claude terminal |
M-x claude-code-ide-insert-newline | Insert newline (LF for omp, \ + Enter otherwise) |
M-x claude-code-ide-toggle | Toggle visibility of Claude Code window |
M-x claude-code-ide-toggle-recent | Toggle most recent Claude window globally |
M-x claude-code-ide-show-debug | Show the debug buffer with WebSocket messages |
M-x claude-code-ide-clear-debug | Clear the debug buffer |
Use @ in claude-code-ide-menu to reference the current file.
The path is relative to the receiving Session directory.
Selected lines retain the #L316 or #L316-320 suffix.
For a Session on v12mac at /Users/yufu/v12x, the remote file
/rpc:v12mac:/Users/yufu/v12x/packages/core/lib/executor.ts becomes
@packages/core/lib/executor.ts#L316 when line 316 is selected.
A file outside that directory uses its absolute host-local path without the RPC prefix.
The RPC destination must exactly match the Session’s configured destination.
Different destinations, unsupported remote routes, and missing Session context produce an error before insertion.
The action does not resolve SSH aliases or establish new connections.
Local behavior and the separate # action remain unchanged.
The f, F, and h actions browse the Session host through the editor transport
and send a path without the editor’s remote connection prefix.
f searches the Session directory on that host, and h the account home directory.
f and F send a path relative to the Session directory, and h an absolute path.
Set claude-code-ide-file-reference-picker-function to a flat search such as fd
through consult to pick a file by search for f instead of by directory.
A prefix argument, and h, keep the read-file-name prompt.
Claude Code IDE automatically detects your project using Emacs’ built-in project.el. Each project gets its own Claude Code instance with a unique buffer name like *claude-code[project-name]*.
You can run multiple Claude Code instances simultaneously for different projects. Use claude-code-ide-list-sessions to see all active sessions and switch between them.
- Running
claude-code-idewhen a session is already active will toggle the window visibility - The window can be closed with standard Emacs window commands (
C-x 0) without stopping Claude - Use
claude-code-ide-toggle-recentto toggle the most recent Claude window from anywhere, regardless of your current project context. This is useful when you’re outside a project directory but want to quickly hide/show Claude
Agent processes normally die with Emacs. With zmx installed, the package can run each agent CLI inside a zmx session. The process then survives Emacs restarts, buffer kills, and dropped connections. You can detach in Emacs and reattach from a plain terminal, or the reverse. See the zmx guide for setup, attachment, lifecycle, and troubleshooting details.
Enable it globally:
(setq claude-code-ide-use-zmx t)How it works:
- New sessions run as
zmx attach <name> <agent-command>. Names followcci-<agent>-<project>-<id>(seeclaude-code-ide-zmx-session-prefix). - On session start, matching zmx sessions for the project and agent are offered for reattach, with a “Create new session” option. Continue and resume offer only matching sessions with zero attached clients.
- When cc-manager is hidden, reattachment from Start keeps it hidden and preserves the editor windows. The terminal opens in the configured side window. When cc-manager is visible, reattachment uses its managed layout.
M-x claude-code-ide-attachlists all zmx sessions, including ones started outside Emacs, and adopts the selection into a full session with idle tracking and manager visibility.- Killing the terminal buffer detaches only. Closing its window only hides the terminal.
M-x claude-code-ide-stopasks before it kills the zmx session. That stops the agent for every attached client. From a terminal, usezmx attach <name>andzmx kill <name>.
Known limitation: environment variables such as the Claude Code MCP port are frozen when the zmx session is created. If you reattach from a different Emacs instance, or after an Emacs restart, port-based integrations (MCP, SSE) break for that session. Plain terminal use of the agent is unaffected. Exception: Oh My Pi rediscovers the Emacs SSE endpoint and reconnects on its own, so selection sync and session state resume after an Emacs restart.
The zmx integration follows the design of emacs-term-sessions (GPL-3+), which provides general-purpose persistent terminals on top of zmx. This package implements only the small agent-session subset itself, so there is no dependency. Use emacs-term-sessions when you want persistent shells beyond coding agents.
Remote attachment connects to an existing zmx session through SSH. It never starts an Agent or creates a remote zmx session. See the remote guide for host setup, attachment, Project views, cleanup, and troubleshooting details.
Reattachment works with stock zmx. Emacs runs zmx attach <name> false to adopt an existing session.
If a target disappears after discovery or a reconnect check, the false guard ends the replacement session immediately.
No shell, Agent, or persistent replacement remains.
This guard applies to local adoption and remote reattachment.
Ordinary local session creation stays unchanged.
See the attach guard contract for the verified versions.
Configure exact SSH destinations:
(setq claude-code-ide-remote-hosts '("my-agent-host" "user@another-host"))The default list is empty. Your SSH configuration owns authentication, ports, jump hosts, and trusted host keys. Prepare these outside Emacs. Remote control requests cannot prompt for passwords or accept new host keys. Each control request has a 30-second deadline.
The remote executable is zmx from the remote command environment’s PATH. claude-code-ide-zmx-program controls only local zmx. Remote attachment does not require a local zmx or Agent executable.
- Run
C-u M-x claude-code-ide-attach. - Select a configured host.
- Select an existing Agent.
Use C-u M-x claude-code-ide-attach-all for bulk attachment. Use C-u M-x claude-code-ide-attach-select for marked selection. Without a prefix, these commands keep their local behavior. Bulk attachment names entries that lack usable metadata. Individual attachment permits manual Agent identification and remote-directory text entry. Neither value becomes a remote launch command.
Remote rows appear only in the global manager. Flat labels retain [HOST] PROJECT after rename. Grouped headings retain the host and project. Matching paths and zmx names on different hosts remain separate targets.
Selecting a connected row opens its terminal. Selecting a disconnected row does not contact its host. Press c to reattach explicitly with the same Session ID. Refresh, startup, and restored layouts never reconnect automatically.
A remote Attach process can end because the Agent exited or because the link dropped.
When an Attach process ends, Emacs asks the host once with zmx list --short.
A missing target proves the Agent exited, so Emacs removes the row.
A listed target, a failed check, or a slow check keeps the disconnected row.
An explicit detach never contacts the host.
Press s on a connected remote row to start a fresh Agent on that exact host and directory. The direct interactive SSH path creates a new zmx target without a Worktree operation. Remote S and prefixed s remain unavailable because remote launch ignores local CLI options.
A successful attachment requests project metadata asynchronously. A metadata failure does not undo attachment.
Press ? m in the manager to refresh cached Git metadata for one configured host.
The command uses known connected and disconnected rows. It does not discover or reattach Agents.
Ordinary G refresh, startup, layout restore, view changes, and navigation never request remote metadata.
Metadata requests reject control characters, including DEL and C1 controls. Git response paths must have canonical absolute syntax. Emacs does not resolve these paths on the local filesystem. A malformed response rejects the whole batch. Failure reports identify the host and affected directories. Metadata failures preserve the last valid cache and do not close terminals.
Before reattaching a remembered remote row, Emacs checks the exact target with zmx list --short.
A missing target or failed SSH check stops attachment before a terminal starts.
Fresh attachments use discovery results without another SSH check.
If the attach client exits during setup, Emacs reports an error instead of success.
Press D or X to detach the local client and remove its manager row.
For a disconnected remote row, these commands remove only local history and the saved layout without contacting the host.
Neither command stops the remote agent.
Press K to Stop the exact selected target.
Stop asks for confirmation and names the host, target, and effect on all clients.
After Stop, Emacs removes the row only when zmx confirms the kill and a separate request confirms absence.
A timeout or ambiguous result leaves the row intact.
Emacs never retries a kill.
Remote attachment uses the Ghostel backend, the package’s only terminal backend. Remote layouts show only the terminal unless you enable optional remote Project views. Remote project launch, Treemacs actions, text transfer, MCP, and SSE setup remain outside this mode. Remote companions support Magit, Dired, or an ordinary Ghostel shell, matching the selected layout preset. Use their normal commands for interactive Git, file access, or shell commands.
If attachment fails, inspect the host-qualified error. Check SSH authentication, trusted host keys, and remote PATH. A missing target remains disconnected. Emacs never replaces it with a new agent session. See the validation guide for backend coverage and the live acceptance procedure.
Remote Project views require an installed compatible tramp-rpc client and its configured server binary on the remote host.
Install and configure them separately. The package does not download, build, install, update, or deploy either component.
Configure SSH credentials and host keys before use because automatic preparation cannot prompt.
Enable each exact host separately:
(setq claude-code-ide-remote-hosts '("my-agent-host")
claude-code-ide-remote-project-view-hosts '("my-agent-host")
claude-code-ide-remote-project-cleanup-hosts nil)claude-code-ide-remote-hosts remains the access approval list.
claude-code-ide-remote-project-view-hosts does not approve a host by itself.
Changing either Project-view option starts no remote work.
The first managed display shows the terminal in an ordinary window. It then starts Project-view preparation in the background. The feature checks the current RPC connection and remote directory before it uses the configured status provider. The provider uses Magit when available and its normal Dired fallback otherwise. A failure leaves the terminal usable and reports the host, failed phase, and corrective action.
shell-left and shell-right use these same two host lists. There is no separate remote-shell approval list.
Remote shells follow the installed RPC client’s PTY policy and Ghostel’s remote shell preferences.
That policy can use a direct SSH PTY or an RPC PTY.
An unsupported remote host produces an explanation instead of a local shell.
See the remote guide for exact host admission, companion identity, and lifecycle details.
Project-view identity includes the exact host, canonical Worktree or directory, companion kind, captured provider, and requested directory.
Different provider identities can share a native buffer. Cleanup preserves that buffer while another registered owner uses it.
The feature reuses every surviving matching buffer without refreshing it.
Use the view’s native g command when you want a refresh.
Close a Project-view window to suppress its automatic display for that Session.
This suppression survives navigation and remote reattachment in the current Emacs process.
Press manager R to reset the full layout and clear suppression.
A fresh preparation worker runs a health check.
A reset or mirror that reuses a live companion shell starts no worker or connection.
Open the manager menu with ?, then press C to cancel only the pending Project-view attempt.
Cancellation does not detach the terminal or close a shared RPC connection.
claude-code-ide-remote-project-cleanup-hosts independently permits conservative local buffer cleanup.
Cleanup runs only after successful manager D or X detach.
It can close only an unmodified Magit or Dired view that this feature created for the detached Session.
It retains reused, custom, modified, shared, source-file, process, temporary, and uncertain buffers.
It also retains buffers with unknown local kill or query hooks.
Cleanup never saves, prompts, makes a remote request, or closes an RPC connection.
Terminal close, network loss, Stop, and Emacs exit do not run this cleanup.
Remote Worktree management extends remote Agent attachment with explicit remote Worktree list, open, and create actions, plus the remove, move, merge, push, and prune actions available through remote Magit. Every action targets one exact Configured host and one absolute remote repository path. It never scans a host for repositories and never substitutes a local target when an action refuses.
- Worktree: a main or linked working directory of one Git repository on one host.
- Worktree backend:
laneorwt(Worktrunk), selected per repository the same way as local worktree creation. - Remote agent and Session: as defined in Existing Remote Agents.
- Worktree operation: one requested action (list, open, create, remove, move, merge, push, or prune) with a captured host, targets, and reported steps. Its result can remain unknown after observation ends.
- Outcome check: an explicit, read-only re-examination of an operation’s remote state.
See CONTEXT.md for the full glossary.
Press W in the sidebar, or in the main transient’s manager section, to open the Remote Worktree menu (claude-code-ide-manager-remote-worktree-menu):
| Key | Command | Effect |
|---|---|---|
o | claude-code-ide-manager-open-remote | Always choose a Configured host and repository, select a Worktree, then reuse/attach/start its Agent. The repository picker lists recent paths for that exact host and also accepts a new absolute path as minibuffer input. A prefix argument starts an explicit sibling Agent. |
w | claude-code-ide-manager-new-remote-worktree | Choose a Configured host and repository, ask one new name, create the Worktree, and start the configured Agent. A prefix argument creates only, then opens remote Magit without an Agent. |
r | claude-code-ide-remote-worktree-show | Display a retained operation’s result. Makes no remote request. |
On an existing remote Session row or inside an existing remote Magit buffer, plain o (claude-code-ide-manager-open) and w (claude-code-ide-manager-new-worktree) already use that context’s exact host and repository, skipping the extra prompts. C-u o there starts an explicit sibling Agent; C-u w there creates the Worktree only.
The manager remembers at most 20 successfully requested repository paths per exact host, with the newest path first. It stores this history with manager persistence. Cancelled input and refused requests do not change it. A restored path never causes remote access.
Each command returns an operation ID rather than a path or session object. Every result stays attached to its captured host, so identical paths on two hosts never share a Session match or a result.
claude-code-ide-remote-launch-config is an alist keyed by exact Configured host. Each value can override the Agent executable, Agent arguments, launch environment, or fresh-launch shell:
(setq claude-code-ide-remote-launch-config
'(("my-agent-host" :executable "claude" :args ("--model" "sonnet"))
("ramhorn"
:environment ("SKIP_TMUX=1")
:shell "/usr/bin/zsh"
:shell-args ("-lic"))))The default executable is the globally selected Agent’s standard command name. Remote arguments and environment assignments default to empty lists. Local executable paths, local CLI flags, and local MCP settings are never inherited.
:environment is an optional part of the shell preference. It is a list of literal NAME=VALUE strings. Names must be unique shell variable names. The reserved ZMX_SESSION and ZMX_SESSION_PREFIX names are invalid. Each assignment initializes the configured shell before startup files run. The resulting value reaches the fresh Agent unless those files replace it. This lets ramhorn set SKIP_TMUX=1 before its startup files select a terminal multiplexer.
:shell and :shell-args form an optional pair. The shell path must be absolute. The nonempty argument list must tell that shell to execute the package command that follows it. The package does not append -c. For zsh, ("-lic") loads login and interactive startup files before it executes the command.
These settings apply only when a fresh sibling or Worktree Agent starts on that exact host. A host without them keeps direct launch. Attach, reattach, detach, and Stop never apply them.
Worktree preparation resolves the Agent in the selected environment. The owned zmx bootstrap then initializes that environment before the runner validates and starts the Agent. The control protocol uses a fixed locale and private permissions. The runner restores the shell’s locale and umask when it starts the Agent.
Remote Lane and Worktrunk sections in Magit render an explicit snapshot; they never run a synchronous backend command while rendering. Request a fresh snapshot with M-x claude-code-ide-remote-worktree-refresh, or the corresponding refresh key in the magit-lane or magit-worktrunk transient on a remote Worktree. Ordinary manager navigation, automatic idle refresh, and startup never contact a host for this listing.
The manager provides list, open, and create only.
Remote Magit supplies the supported remove, move, merge, push, and prune actions.
Backend commands and native Magit move capture use the same protected operation boundary.
Native Magit push capture uses it only when claude-code-ide-remote-worktree-capture-native-push is non-nil (default nil); otherwise Magit pushes natively.
Native capture preserves selected force flags, destination interpretation, and resolved publication refs before execution.
See magit-lane and magit-worktrunk for each backend’s operation table and prerequisites.
Lane refuses movement because it owns a fixed tree location.
No backend moves a Worktree between hosts.
Worktrunk merge records landing and cleanup separately. A new blocking Agent can prevent cleanup after successful landing. Results retain that landing, and an explicit retry never repeats it.
Only a selected Lane backend uses the Lane initialization setting. Its instruction-file change still requires separate approval. Worktrunk rejects explicit Lane-only initialization options.
A known Agent in an affected Worktree blocks removal, movement, history rewriting, and cleanup, even when idle or detached. A merge check covers both the source and destination Worktree. Failed Agent discovery, or an affected Agent whose identity cannot be resolved, blocks the action instead of assuming it is safe. Stop the Agent explicitly first, then retry: no Worktree action stops an Agent as a side effect, and force never bypasses this check.
Protection includes canonical descendant directories, including nested repositories and submodules. Sibling paths with the same prefix do not match.
Progress appears without a focus change.
Messages identify requests that cannot replace the selected result.
Every result stays available through r in the Remote Worktree menu or M-x claude-code-ide-remote-worktree-show.
The results buffer provides these controls:
| Key | Effect |
|---|---|
g | Check outcome: an explicit, read-only re-examination of the captured host and target. Never mutates, retries, launches an Agent, or approves a hook. |
r | Retry: submits only a step Check outcome proved both unfinished and safe to attempt. Disabled otherwise. This is a new mutation with fresh confirmation, never a replay of a completed or uncertain step. |
c | Cancel observation: stops local observation. It never stops or rolls back an already-submitted remote operation. |
a | Recover attachment: attaches the Agent an operation already started, when only that step remains. |
v | Recover view: reopens the remote view an operation already produced. |
s | Select: choose which retained operation the buffer displays. |
q | Close: closes the results buffer. The operation record and any remote work continue. |
Check outcome distinguishes completed, still running, confirmed unfinished, partially completed, and still unknown results.
A matching directory or a missing response alone never proves completion.
An entered command with a nonzero exit shows failed, even when its effects leave the overall outcome unknown.
Retry never repeats an entered failed step.
You can inspect the same operation’s results while its owned attachment or Project-view completion continues. If an unrelated view owns focus at completion, the results show a deferred continuation and retain its recovery target. After you close results or cancel observation, only an explicit recovery action can attach a terminal or change the Project view.
Normal completion requests removal of an eligible completed operation resource after it retains terminal proof. It keeps unknown, partial, running, and live-bootstrap resources. Check outcome never removes resources.
Remote Worktree management lives in claude-code-ide.el and calls into magit-lane or magit-worktrunk only when that package is loaded and its binary resolves on the selected host. Neither backend package requires claude-code-ide at load time; a remote-aware backend command reports that claude-code-ide is not loaded instead of doing partial work.
Remote Project views opened by create-only or remote Magit actions need the same optional tramp-rpc client as Optional Remote Project Views, currently Emacs 30.1 or later. Remote listing, creation, and launch through the results buffer still target Emacs 28.1 or later without that client.
Local worktree, Agent, and Magit workflows keep their existing behavior. No new host prompt, confirmation, or launch step is inserted into a local action.
claude-code-ide-manager-toggle-sidebar opens a dedicated left sidebar for Sessions.
Existing commands, including claude-code-ide-list-sessions, keep their behavior.
CC Manager supports two scope families:
- a global manager across live Sessions and remembered remote rows
- a repo-local manager keyed by the current Git root
Generic commands such as claude-code-ide-manager-toggle-sidebar and claude-code-ide-manager-focus use claude-code-ide-manager-default-target to choose which scope to target. Explicit global and repo-local commands remain available when you want to bypass that policy.
The manager can:
- Show flat rows or host-qualified project groups in the global manager
- Show repo-local sessions with branch-first labels by default, falling back to basename when detached
- Keep pinned Sessions above unpinned Sessions within each project in grouped view
- Keep one manual order across flat and grouped global views
- Edit and pin the complete session order for one manager scope
- Restore per-session window layouts when you switch back
- Put the sidebar cursor on the current Session when focus enters the sidebar
New manager layouts and explicit resets use claude-code-ide-manager-layout-preset.
Each preset selects the companion type and side. The old separate side preference no longer controls layouts.
| Preset | Companion | Side |
|---|---|---|
magit-left (default) | Configured Git view | Left |
magit-right | Configured Git view | Right |
dired-left | Dired | Left |
dired-right | Dired | Right |
shell-left | Ordinary Ghostel shell | Left |
shell-right | Ordinary Ghostel shell | Right |
The Agent stays on the other side with its existing buffer and backend.
The default Git provider uses Magit when available, with Dired as its fallback.
The Dired presets always open the exact Session directory directly.
The shell presets create ordinary terminals, not additional managed Agent Sessions.
Manager state can persist across Emacs restarts through persist.el.
See Switching Behavior for saved-layout precedence and shell lifetime.
The Magit presets temporarily retain claude-code-ide-manager-status-buffer-function for custom Git content.
Dired and shell presets ignore this setting.
You can reach the manager in two ways:
- Run
M-x claude-code-ide-manager-toggle-sidebarto toggle the sidebar- pass a positive prefix argument to force open and focus
- pass a negative prefix argument to force hide
- Run
M-x claude-code-ide-manager-toggle-global-sidebarto always target the global manager - Run
M-x claude-code-ide-manager-toggle-repo-sidebarto always target the repo-local manager for the current Git root - Open the main transient and use:
tto toggle the default manager sidebarTto toggle the global manager sidebaroto toggle the repo-local manager sidebarnto move to the next manager session and switch to itpto move to the previous manager session and switch to itPto pin or unpin the current active manager sessionEto edit and pin the complete order for the selected manager scope1..9to switch to manager slots 1 through 90to switch to manager slot 10Mto focus the manager windowGto refresh the local Session list without network requests
- Press
?in the sidebar to open its manager menu.vtoggles flat and grouped global viewsftoggles the focused viewC-jandC-kmove between project groupsmrefreshes cached project metadata for one configured remote hostoopens a project or worktree: in the global view it asks for the project, then for the worktree when the project has more than one. A target with a Session switches to it.C-u ostarts a sibling Session at once. Otherwise the Start/Continue/Resume menu appears.wcreates a worktree and starts the default Agent in it. In the global view the project comes from the row under point, and is asked only when point is on no row. It asks for one name that becomes the branch and the tree.C-u wcreates the tree and opensmagit-statuswithout an Agent.
claude-code-ide-worktree-backend selects the tool that creates a worktree: lane (copy-on-write trees under .lane/trees/ through magit-lane) or wt (Worktrunk, through magit-worktrunk). A repository that already has a .lane/ store always uses lane. Otherwise a directory-local value wins, then the git config key claude-code-ide.worktree-backend, then the global default. Neither Magit package is required at load time. The command reports the missing package or binary before it asks for a name.
With lane, a repository without a .lane/ store gets a bare one, created silently. Every lane command works on it, including note and why. What it lacks is the AGENTS.md protocol block that tells agents to use lane memory. Set claude-code-ide-lane-init-protocol to t to get one question before lane init instead, which writes that block, or run lane init by hand later. Names that already exist as a branch, or as a lane, are refused before anything is created.
claude-code-ide-manager-open-directory is the public entry for other packages: given a local directory it switches to its Session, or starts the default Agent there. magit-lane and magit-worktrunk bind a on their rows and transients to it.
The sidebar shows live Sessions. The global manager also retains disconnected remote rows.
- Flat global rows show the project basename
- Grouped global rows show a branch or directory label below a host-qualified project heading
- Repo-local manager rows use
claude-code-ide-manager-repo-label-strategy, which defaults to branch-first with basename fallback - The full project path is available via hover text and in the echo area when point moves onto the row
- The currently active session row is highlighted
- The left gutter shows
📌for pinned rows - Visible rows are assigned quick slots
1..9, 0from top to bottom
Quick slots are derived from the current visible order. They are not stored separately, so pinning or reordering a row immediately changes which session each slot selects.
Press v to toggle the global manager between flat and grouped views.
Repo-local managers keep their existing view.
The manager saves the global view choice when persistence is enabled.
Press f to toggle the focused view.
It shows only Sessions that need attention, numbered from 1, and the number keys follow those numbers.
Set claude-code-ide-manager-focused-view to choose the view at startup.
The f key changes only the running Emacs and never saves the setting.
A Session that you handled leaves after you switch to another Session.
A Session that waits for input stays.
In the focused view, G shows every Session for one Avy pick and then returns to the focused view.
Git worktrees share one project heading when their canonical Git common directories match.
Separate Git directories stay separate, even when project paths match.
The host remains part of every remote group identity.
Remote non-Git and unresolved groups use exact directory text.
Thus /a/b and /a/b/ remain separate unresolved groups until metadata resolves them.
For a separate Git directory, the heading uses that directory’s basename.
Matching heading names also show their paths. A remaining collision shows the group identity.
Headings do not accept Session actions. There are no project-wide actions.
Rows use cached branch names, with directory names when no branch is available.
Custom names appear after that label.
C-j and C-k choose the first row of the next or previous project group and wrap at the end.
Selecting a disconnected row does not connect or change the active Session.
Press c to reattach explicitly.
Grouped moves and editor Apply reorder only positions already occupied by the affected group in the flat sequence.
For example, moving A2 above A1 changes A1 B1 A2 B2 to A2 B1 A1 B2.
The first successful grouped move or Apply creates shared order keys when needed.
Those keys also fix the fallback order of other rows in the shared flat sequence.
Toggling views does not change the order.
Group order is stored for the global scope. Remote and local groups mix freely.
M-P and M-N move the current row’s project group up or down.
M-p and M-n move a group when the row is the only row of that group.
A group move never changes row order keys, so the flat view keeps its order.
A group with no stored position follows the stored groups, sorted by heading name.
In grouped global view, E includes live and disconnected rows under project headings.
M-p and M-n move rows only within the same project.
M-P and M-N move a complete project block with its rows.
Each group has one heading line, which shows [HOST] PROJECT for a remote group.
Headings are writable so Evil V, d, and p can move a heading with all its rows.
Paste complete project blocks between other blocks. Each Session must remain under its original heading.
Apply rejects changed heading text or identity, duplicate or missing headings or rows, edited labels, and changed project membership.
Failure leaves the editor, pins, and order unchanged.
Each row reserves a left gutter so the session names stay aligned whether or not a marker is present.
- Oh My Pi rows show the state the agent reports over MCP:
?when a dialog waits for you (approval,asktool, extension prompt),✓when a turn finished,✗when a turn failed,⚙︎while working, and no marker when idle - Viewing a
✓or✗row’s session clears the marker;?stays until the agent reports again !clears output-idle bells and acknowledges completed or failed results for all live sessions, even with output-idle monitoring disabled. Working and input-request states stay visible.- A clear before the first agent report remembers a pending acknowledgment across reconnects. A working or input-request report resets the acknowledgment, so later results appear.
- Rows without an agent report fall back to output detection: idle-enabled rows that are currently idle show
🔔, rows with recent output show⚙︎ - Pinned rows show
📌in that gutter when no state marker applies - State markers take priority over output markers, which take priority over the pin marker
- Rows with no marker keep the same alignment with blank gutter padding
- Row faces: red
claude-code-ide-manager-attention-session-faceis reserved for?and✗,✓uses the blueclaude-code-ide-manager-done-session-face, working rows use the greenclaude-code-ide-manager-working-session-face, and output-detected idle rows use the amberclaude-code-ide-manager-idle-session-face - State highlighting applies only to non-current rows
- The current session keeps
claude-code-ide-manager-current-session-faceeven when it is idle
🔔 project-a project-b
M-x claude-code-ide-manager-next-priority-session focuses the next unvisited session’s terminal from any window, including when the sidebar is hidden.
It uses the current manager scope, or the configured default scope when no sidebar is visible.
It includes offscreen rows but excludes sessions without a live process and buffer.
The command uses this priority order:
- Reported
needs-input - Reported
failed - Reported
done - Output-idle with tracking enabled and no reported state
- Reported
working, or output-working with tracking enabled and no reported state - Other states, including reported
idle
Reported state takes precedence over output flags.
Within each priority, the command preserves sidebar pin and manual order.
The current session counts as visited.
New sessions join the current pass, and state changes can promote unvisited sessions.
A visited session that changes to needs-input, failed, or done becomes eligible again within the pass.
A new output-idle bell also renews a visited session when tracking is enabled and no reported state masks it.
The command selects these changed sessions and unvisited sessions in the same priority order.
After these visits, it returns to the first interrupted session before starting another pass.
Repeated unchanged reports and unchanged bells do not interrupt the pass.
Clearing a bell cancels its pending interruption.
The return target must remain live and eligible. A manual visit to that target completes the return.
Global and repository scopes keep separate passes, shared across frames until Emacs restarts.
A manual switch counts when that session is current at the next priority command.
The normal switch path acknowledges done and failed but leaves needs-input unchanged.
The package does not assign a global key to this command.
Existing Avy selection and row-order navigation stay unchanged.
M-x claude-code-ide-manager-next-uncleared-session uses the same priority order but skips the final group of cleared or unmarked sessions.
It still includes working sessions.
Acknowledged results leave this cycle, while unresolved input requests remain eligible for later passes.
This command keeps its own pass for each scope, separate from claude-code-ide-manager-next-priority-session.
If no other uncleared session remains, it reports a user error without changing focus.
Neither command changes the other’s visits or global key binding.
Both forward commands select the agent’s window after the switch, even when a saved layout would restore editor focus.
M-x claude-code-ide-manager-previous-priority-session and M-x claude-code-ide-manager-previous-uncleared-session walk back through the sessions the matching pass left, most recent first.
They skip sessions that left the scope and keep the forward pass’s visits.
These commands do not force the agent window.
Focus follows the target session’s saved layout, exactly as slot switching and manager row selection do, so the user returns to the buffer they last used there.
That is the agent window when they left it selected, or when the saved buffer is gone.
If no earlier session remains, they report a user error without changing focus.
When point is in the manager buffer:
nmoves to the next row, cycling to the first row after the last, and switches to itpmoves to the previous row, cycling to the last row before the first, and switches to itRETswitches to the session at pointglabels visible session names with Avy and focuses the selected session, likeRETSPCswitches to the session at pointPtoggles pin state for the selected rowEopens the complete pin-order editor for the selected manager scopesstarts a sibling session with the current CLI;Sstarts one with explicit permissions bypassC-u sorC-u Sprompts for a one-session CLI selection (uppercase also bypasses permissions)aadopts a zmx session viaclaude-code-ide-attach(see Persistent Sessions with zmx)Wopens the Remote Worktree menu for a Configured hostDorXdetaches the selected zmx-backed session and removes its row without stopping the agent, even when disconnectedcexplicitly reattaches the selected disconnected remote targetKconfirms Stop for the exact selected targetRresets the selected session to the configured layout preset, replacing a missing or exited companion shellM-pmoves the selected row up within its current pinned or unpinned groupM-nmoves the selected row down within its current pinned or unpinned groupM-porM-nmoves the project group instead when the row is its group’s only rowM-PandM-Nmove the selected row’s project group up or down in grouped global viewvtoggles flat and grouped global viewsftoggles the focused view: only Sessions that need attention, numbered from 1C-jmoves to the next project in grouped global viewC-kmoves to the previous project in grouped global view? mrefreshes cached project metadata for one configured remote hostGrefreshes the sidebar without network requests. In the focused view,Gshows every Session for one Avy pick instead, and? Gstill refreshes1..9jump directly to the corresponding visible slot0jumps to slot 10
g and C-u g search only the selected manager window. Labels start at each session name’s first character. ESC and C-g cancel selection.
Pins stay above unpinned rows within each project in grouped view. Flat view keeps all pinned rows above unpinned rows. Row moves never cross a pin boundary.
Press E in the sidebar or main transient to open the pin-order editor. You can also run M-x claude-code-ide-manager-edit-pin-order.
The flat and repo-local editors list Sessions that were live when the editor opened. The grouped global editor also includes disconnected remote rows. Each Session has one numbered row.
M-pmoves the current row up and renumbers all rowsM-nmoves the current row down and renumbers all rowsM-Pmoves the current group block up with its rows and renumbers all rowsM-Nmoves the current group block down with its rows and renumbers all rows- In Evil mode, use
V,d, andpto move complete rows within a project or complete project blocks - Stale row numbers are allowed
C-c C-cvalidates every opening row and heading, clears scope pins, and applies the displayed order- Empty lines between rows are allowed
C-c C-kdiscards all edits
Apply requires every opening row exactly once with unchanged visible text. It infers pin order from physical row order and ignores displayed numbers. Hidden session keys identify rows, so equal visible names remain distinct.
Do not recreate rows by typing their text. Typed rows do not contain the required hidden session key.
Sessions started after the editor opens stay outside its snapshot. Apply leaves those sessions unpinned, so the configured fallback sort still orders them.
The manager saves and restores layout per session key.
When you switch from one managed session to another:
- The current layout is captured for the session you are leaving
- If the target session already has a saved layout, that layout is restored
- Otherwise the manager builds the configured
claude-code-ide-manager-layout-preset(see CC Manager for the six preset values) - Focus returns to the last selected window for that session when possible
- If the previous focused window no longer exists, focus falls back to the Claude session buffer
If the target session buffer is gone by the time you switch, the manager refreshes itself and aborts cleanly instead of leaving stale sidebar state behind.
A saved layout always wins over the configured preset. Changing claude-code-ide-manager-layout-preset never touches an existing saved layout or a running companion shell.
Press R to discard the saved layout and rebuild the current preset explicitly. Only this explicit reset, or a brand-new session with no saved layout, starts a new companion shell.
Saved shell layouts and explicit shell resets reuse the Session’s live owned Ghostel shell.
The shell survives navigation, Agent Stop, and detach.
If an exited shell buffer remains, restoration preserves its output.
If the buffer is missing, restoration keeps the Agent usable without starting a replacement.
Both cases show reset guidance. Press R with a shell preset to start a replacement.
The manager persists its own metadata with persist.el. This is separate from the live Claude session registry.
When persistence is enabled, the manager remembers:
- pinned state
- manual ordering
- saved layout snapshots
- last selected buffer for layout restore
- remote host, exact zmx target, Agent identification, and custom name
- flat or grouped global view
- cached project identity and branch metadata
After restart, remembered remote rows start disconnected. Their labels, pinning, ordering, selection, and saved layouts remain local metadata. Press c to reattach. A removed host stays visible in history, but Emacs requires current host configuration before remote access.
With persistence disabled, disconnected rows remain available during the current Emacs session. A later Emacs session does not restore them. Each computer has independent history. Another Emacs can discover the same remote Agent without access to this history.
Manager-specific options:
| Variable | Description | Default |
|---|---|---|
claude-code-ide-manager-persist-state | Persist manager metadata across Emacs restarts | t |
claude-code-ide-manager-window-width | Width of the left manager side window | 22 |
claude-code-ide-manager-repo-label-strategy | Visible label strategy for repo-local rows | branch-or-basename |
claude-code-ide-manager-repo-include-nested | Include nested git roots in repo-local scope | nil |
claude-code-ide-manager-default-target | Default target for generic manager commands | global |
claude-code-ide-manager-layout-preset | Layout preset for new and explicitly reset layouts | magit-left |
claude-code-ide-manager-status-buffer-function | Custom content provider used by magit-left and magit-right | claude-code-ide-manager-magit-status-buffer |
When claude-code-ide-use-ide-diff is enabled (default), Claude’s code suggestions are displayed using Emacs’ powerful ediff interface. This provides two key advantages:
- Visual diff comparison - See exactly what Claude wants to change with side-by-side or unified diff views
- Interactive editing - You can modify Claude’s suggestions before applying them
- When Claude suggests code changes,
ediffopens automatically - The ediff control buffer becomes active (a small window with ediff commands)
- Buffer A shows the current code, Buffer B shows Claude’s suggestion
- You can modify Buffer B to refine Claude’s proposed changes
- Press
qin the ediff control buffer to quit - When prompted, choose whether to accept the changes (
yorn) - If you accept (
y), any changes from Buffer B will be sent back to Claude to be applied on the original file
This allows you to refine Claude’s suggestions before they’re applied, ensuring the final code meets your exact requirements.
| Variable | Description | Default |
|---|---|---|
claude-code-ide-cli-path | Supported CLI to run (claude, codex, opencode, pi, or omp) | "claude" |
claude-code-ide-buffer-name-function | Function for buffer naming | claude-code-ide--default-buffer-name |
claude-code-ide-cli-debug | Enable CLI debug mode (-d flag) | nil |
claude-code-ide-cli-extra-flags | Additional CLI flags (e.g. “–model”) | "" |
claude-code-ide-bypass-permissions-by-default | Lowercase transient launch actions bypass permissions when available | t |
claude-code-ide-use-with-editor | Use the current Emacs instance as $EDITOR for new sessions | t |
claude-code-ide-debug | Enable debug logging | nil |
claude-code-ide-terminal-initialization-delay | Initialization delay for terminals | 0.1 |
claude-code-ide-log-with-context | Include session context in log messages | t |
claude-code-ide-debug-buffer | Buffer name for debug output | "*claude-code-ide-debug*" |
claude-code-ide-use-side-window | Use side window vs regular buffer | t |
claude-code-ide-window-side | Side for Claude window | 'right |
claude-code-ide-window-width | Width for side windows (left/right) | 90 |
claude-code-ide-window-height | Height for side windows (top/bottom) | 20 |
claude-code-ide-focus-on-open | Focus Claude window when opened | t |
claude-code-ide-focus-claude-after-ediff | Focus Claude window after opening ediff | t |
claude-code-ide-show-claude-window-in-ediff | Show Claude window during ediff | t |
claude-code-ide-use-ide-diff | Use IDE diff viewer instead of terminal | t |
claude-code-ide-switch-tab-on-ediff | Switch to Claude’s tab when opening ediff | t |
claude-code-ide-system-prompt | Custom system prompt to append | nil |
claude-code-ide-enable-mcp-server | Enable MCP tools server | nil |
claude-code-ide-mcp-server-port | Port for MCP tools server | nil (auto-select) |
claude-code-ide-mcp-server-tools | Alist of exposed Emacs functions | nil |
claude-code-ide-diagnostics-backend | Diagnostics backend (auto/flycheck/flymake) | 'auto |
claude-code-ide-prevent-reflow-glitch | Prevent terminal reflow glitch (bug #1422) | t |
With claude-code-ide-use-with-editor enabled, editor commands such as C-g in Claude Code and Codex open their prompt buffer in the current Emacs instance.
The package routes files matching claude-code-ide-prompt-buffer-patterns to the current window.
The unbound command claude-code-ide-session-send-control-g sends C-g through Ghostel for users who want a dedicated keybinding.
For Oh My Pi Sessions, C-g and RET in terminal-input mode carry a per-Emacs nonce, and claude-code-ide-session-send-control-g carries it too.
The Agent then opens its prompt buffer in the Emacs that pressed the key, even when another Emacs started the Session or attached it over a remote host.
The prompt buffer opens in the window that received the key, and that window gets its previous buffer back when the prompt is closed.
A key binding that selects another window first opens the prompt there and keeps the Agent terminal visible.
This needs an Agent started after the upgrade. Copy mode and line mode keep their own keys, so a line-mode /todo edit still uses $EDITOR.
The package owns session buffer setup and idle monitoring. Your configuration can extend those behaviors through public hooks and reader functions:
claude-code-ide-session-modeandclaude-code-ide-session-mode-mapare package-ownedclaude-code-ide-session-setup-hookruns in each session buffer for local UI or workflow setupclaude-code-ide-session-idle-delaycontrols the idle timeout before a session is considered idle; it defaults to 5 secondsclaude-code-ide-session-idle-default-enabledenables or disables idle monitoring by defaultclaude-code-ide-session-idle-enabledis the buffer-local switch for whether idle monitoring is activeclaude-code-ide-session-idle-pis the buffer-local current idle state for the session bufferclaude-code-ide-session-idle-suppressed-predicatecan suppress idle notifications for a session bufferclaude-code-ide-session-idle-hookruns with the session buffer when idle is detectedclaude-code-ide-session-command-reader-functionreads the command inserted byclaude-code-ide-session-insert-commandclaude-code-ide-session-file-reference-reader-functionreads the file reference inserted byclaude-code-ide-session-insert-file-reference
;; Personal session-buffer setup
(add-hook 'claude-code-ide-session-setup-hook
(lambda ()
(setq-local truncate-lines t)
(visual-line-mode -1)))
;; Enable idle monitoring and add your own notification behavior
(setq claude-code-ide-session-idle-default-enabled t
claude-code-ide-session-idle-delay 5)
(add-hook 'claude-code-ide-session-idle-hook
(lambda (buffer)
(when (buffer-live-p buffer)
(message "Claude Code session idle: %s" (buffer-name buffer)))))
;; Optional: suppress idle notifications for selected session buffers
(setq claude-code-ide-session-idle-suppressed-predicate
(lambda (buffer)
(get-buffer-window buffer t)))
;; Optional: customize how inserted commands and file references are read
(setq claude-code-ide-session-command-reader-function
(lambda (_buffer)
(my/read-ai-command-string))
claude-code-ide-session-file-reference-reader-function
(lambda (_buffer)
(my/read-file-reference-string nil t)))Claude Code buffers open in a side window by default. You can customize the placement:
;; Open Claude on the left side
(setq claude-code-ide-window-side 'left)
;; Open Claude at the bottom with custom height
(setq claude-code-ide-window-side 'bottom
claude-code-ide-window-height 30)
;; Open Claude on the right with custom width
(setq claude-code-ide-window-side 'right
claude-code-ide-window-width 100)
;; Don't automatically focus the Claude window
(setq claude-code-ide-focus-on-open nil)
;; Keep focus on ediff control window when opening diffs
(setq claude-code-ide-focus-claude-after-ediff nil)
;; Hide Claude window during ediff for more screen space
(setq claude-code-ide-show-claude-window-in-ediff nil)
;; Disable IDE diff viewer to show diffs in terminal instead
(setq claude-code-ide-use-ide-diff nil)Or, if you’d prefer to use a regular window:
;; Use regular window instead of side window
(setq claude-code-ide-use-side-window nil)Claude Code IDE uses Ghostel as its only terminal backend. There is no setting to choose a different terminal.
The ghostel backend supports session creation, core input dispatch, idle/working-state tracking, and the resize/reflow guard.
Install Ghostel and its matching native module before creating Agent or companion terminals. Other package features do not require Ghostel. This package never installs a native module automatically.
After the Ghostel-only upgrade, restart Emacs before using terminal commands. The package does not convert or reuse buffers from removed terminal integrations.
The ghostel backend is tested against Ghostel v0.50.0 (its removed pre-0.50.0 APIs are no longer referenced). To check the installed version, run M-x ghostel-debug and read the Module version: line, or evaluate (ghostel--module-version) in a Ghostel buffer. Ghostel checks the Elisp/native-module pairing against ghostel--minimum-module-version at load time and warns on mismatch.
The bypass flags are --dangerously-skip-permissions for Claude Code, --dangerously-bypass-approvals-and-sandbox for Codex, --auto for OpenCode, none for Pi, and --auto-approve for Oh My Pi.
For new local omp and omp-dev processes in Ghostel, the launch frame selects the image protocol:
- Graphical Emacs sets
PI_FORCE_IMAGE_PROTOCOL=kitty. - Terminal Emacs sets
PI_FORCE_IMAGE_PROTOCOL=offfor readable image descriptions, including inside iTerm2 or tmux.
This policy does not change Pi, standalone omp, or the parent Emacs environment. Moving a buffer, redrawing, or reattaching zmx does not change a running process’s protocol. Start a fresh omp process to use the current frame’s policy.
Claude Code IDE includes a brief initialization delay when launching terminals to ensure proper layout rendering:
;; Adjust the terminal initialization delay (default is 0.1 seconds)
(setq claude-code-ide-terminal-initialization-delay 0.15)
;; Or disable it entirely (may cause visual glitches)
(setq claude-code-ide-terminal-initialization-delay 0)This delay prevents display artifacts such as misaligned prompts and incorrect cursor positioning that can occur when terminal emulation is initializing. The default 100ms delay is imperceptible but ensures reliable terminal startup.
Claude Code IDE adds custom keybindings to the terminal for easier interaction:
| Keybinding | Command | Description |
|---|---|---|
S-<return> | claude-code-ide-insert-newline | Insert a newline in the prompt |
C-c C-c | claude-code-ide-session-send-interrupt | Send interrupt to the session |
C-<escape> | claude-code-ide-send-escape | Send escape key to cancel operations |
s-v / H-v | claude-code-ide-session-paste-clipboard | Paste text, local CLI images, or images through the verified remote OMP route |
These keybindings are automatically set up for the Ghostel backend and only apply within Claude Code terminal buffers.
Local Claude Code, Codex, and OMP keep their direct C-v clipboard path.
Remote OMP uses the existing terminal connection with matching Ghostel 0.54.0 native support, the verified OMP receiver, and lossless zmx input backpressure.
Stock zmx 0.8.1 can discard large input when its queue fills. See the remote guide for the candidate requirements.
Generic OSC 5522 support alone is not sufficient.
Other remote CLIs keep their previous behavior and receive no new capability message.
Valid text paste and keybinding precedence remain unchanged.
The remote attachment must own zmx input. If another client owns input, type normally in the intended Session before another image paste. An old unmarked attachment must reattach. After a timeout or disconnect, inspect the Agent before another paste because delivery can remain unconfirmed. The package never retries or sends a file-path substitute. See the remote guide for requirements and the acceptance record for measured results and open checks.
Claude Code IDE includes a temporary workaround for a known Claude Code bug (#1422) where terminal reflows during window resizes can cause uncontrollable scrolling. This workaround is enabled by default for the Ghostel backend, but can be disabled if needed:
;; Disable the terminal reflow glitch prevention (not recommended until bug is fixed)
(setq claude-code-ide-prevent-reflow-glitch nil)The workaround will be removed once the upstream bug is fixed.
Claude Code IDE supports both Flycheck and Flymake for code diagnostics. By default, it will automatically detect which one is active:
;; Let Claude Code automatically detect the active diagnostics backend
(setq claude-code-ide-diagnostics-backend 'auto) ; default
;; Or force a specific backend
(setq claude-code-ide-diagnostics-backend 'flycheck)
(setq claude-code-ide-diagnostics-backend 'flymake)You can customize how Claude Code buffers are named:
(setq claude-code-ide-buffer-name-function
(lambda (directory)
(if directory
(format "*Claude:%s*" (file-name-nondirectory (directory-file-name directory)))
"*Claude:Global*")))You can pass additional flags to the Claude Code CLI:
;; Use a specific model
(setq claude-code-ide-cli-extra-flags "--model opus")
;; Pass multiple flags
(setq claude-code-ide-cli-extra-flags "--model opus --no-cache")
;; Flags are added to all Claude Code sessionsNote: These flags are appended to the Claude command after any built-in flags like -d (debug) or -r (resume).
You can append a custom system prompt to Claude’s default prompt, allowing you to customize Claude’s behavior for specific projects or contexts:
;; Set a custom system prompt
(setq claude-code-ide-system-prompt "You are an expert in Elisp and Emacs development.")
;; Or configure it per-project using dir-locals.el
;; In .dir-locals.el:
((nil . ((claude-code-ide-system-prompt . "Focus on functional programming patterns and avoid mutations."))))
;; Set via the transient menu: M-x claude-code-ide-menu → Configuration → Set system promptWhen set, this adds the --append-system-prompt flag to the Claude command. Set to nil to disable (default).
To enable debug mode for Claude Code CLI (passes the -d flag):
(setq claude-code-ide-cli-debug t)To enable debug logging within Emacs (logs WebSocket messages and JSON-RPC communication):
(setq claude-code-ide-debug t)Then view debug logs with:
M-x claude-code-ide-show-debug- Show the debug bufferM-x claude-code-ide-clear-debug- Clear the debug buffer
The debug buffer shows:
- WebSocket connection events
- All JSON-RPC messages (requests/responses)
- Error messages and diagnostics
- General debug information with session context
Using git worktrees is the recommended way for running multiple Claude Code instances on different branches of the same project. This allows you to develop features or fix bugs in parallel:
# Create a new worktree for a feature branch
git worktree add ../myproject-worktree feature-branch;; Start Claude Code in the main project
find-file /path/to/myproject
M-x claude-code-ide
;; Start another Claude Code instance in the worktree
find-file /path/to/myproject-worktree
M-x claude-code-ideEach worktree is treated as a separate project by project.el, allowing you to have independent Claude Code sessions with their own buffers (e.g., *claude-code[myproject]* and *claude-code[myproject-worktree]*).
Claude Code IDE includes built-in MCP tools that expose Emacs functionality to Claude, enabling powerful code navigation and analysis capabilities:
xref-find-references- Find all references to a symbol throughout the projectxref-find-apropos- Find symbols matching a pattern across the entire projecttreesit-info- Get tree-sitter syntax tree information for deep code structure analysisimenu-list-symbols- List all symbols (functions, classes, variables) in a file using imenuproject-info- Get information about the current project (directory, files, etc.)
To enable these tools, add to your configuration:
;; Set up the built-in Emacs tools
(claude-code-ide-emacs-tools-setup)Once enabled, Claude can use these tools to navigate your codebase. For example:
- “Find the definition of function foo”
- “Show me all places where this variable is used”
- “What type of AST node is under the cursor?”
- “Analyze the parse tree of this entire file”
- “List all functions and variables in this file”
- “How many files are in this project?”
You can expose your own Emacs functions to Claude through the MCP tools system. This allows Claude to interact with specialized Emacs features, custom commands, or domain-specific functionality.
Define tools using the claude-code-ide-make-tool function:
(claude-code-ide-make-tool
:function #'function-name ; The Emacs function to call
:name "tool_name" ; Name for Claude to use (snake_case recommended)
:description "..." ; Human-readable description
:args '((:name "param1" ; List of argument specifications
:type string ; Type: string, number, integer, boolean, etc.
:description "..." ; What this parameter does
:optional t))) ; Optional parameters marked with :optional tAvailable argument types: string, number, integer, boolean, array, object, null
;; Define a context-aware function that operates in the session's project
(defun my-project-grep (pattern)
"Search for PATTERN in the current session's project."
(claude-code-ide-mcp-server-with-session-context nil
;; This executes with the session's project directory as default-directory
(let* ((project-dir default-directory)
(results (shell-command-to-string
(format "rg -n '%s' %s" pattern project-dir))))
results)))
;; Define and register the tool (automatically added to claude-code-ide-mcp-server-tools)
(claude-code-ide-make-tool
:function #'my-project-grep
:name "my_project_grep"
:description "Search for pattern in project files"
:args '((:name "pattern"
:type string
:description "Pattern to search for")))
;; Enable Emacs tool MCP server
(claude-code-ide-emacs-tools-setup)The claude-code-ide-mcp-server-with-session-context macro ensures your tool executes in the correct project context.
This project is licensed under the GNU General Public License v3.0 or later. See the LICENSE file for details.
Claude® is a registered trademark of Anthropic, PBC. Claude Code is an application developed by Anthropic, PBC.
- Claude Code CLI
- Claude Code VS Code Extension
- claudecode.nvim - Neovim integration




