Pimacs is an Emacs client for Pi Coding Agent. For release history, see the changelog.
Pimacs is an Emacs client for Pi Coding Agent. It provides an interactive interface to the Pi Coding Agent directly from Emacs.
First, install the Pi agent using npm:
npm install -g --ignore-scripts @earendil-works/pi-coding-agent
Pimacs does not yet support authentication configuration. To configure your provider, run pi in a terminal, then run /login in Pi.
pimacs.el ¶Add the following to your Emacs configuration:
(use-package pimacs
:ensure t
:vc (:url "git@github.com:ananthakumaran/pimacs.el.git"
:rev :newest)
:commands (pimacs-chat))
Run M-x pimacs-chat from any file in your project to start a Pimacs chat
session. Use a prefix argument (C-u M-x pimacs-chat) to open a
transient where you can set a session name and root directory. Setting a root
directory starts the chat there instead of using project.el to find the
project root. Run M-x pimacs-switch-session to switch between any
active chat sessions.
The chat buffer is read-only except for the prompt input area. Use RET to submit a prompt and C-j to insert a newline. Press i from anywhere in the chat buffer to move point to the prompt input area.
Slash commands support completion in the prompt buffer. Type / and press C-M-i (or any key bound to completion) to see available commands.
In addition to the commands listed below, extension commands, prompt templates, and skills registered with the Pi agent can also be invoked via slash commands. These are fetched automatically from the agent and included in the completion list.
Angle brackets <> denote required arguments, square brackets
[] denote optional arguments.
| Command | Arguments | Description |
|---|---|---|
/compact | [prompt] | Manually compact context, optionally with custom instructions. |
/clone | Duplicate the current active branch into a new session. | |
/copy | Copy last assistant message to clipboard. | |
/cycle-model | Cycle through available models. | |
/cycle-thinking-level | Cycle through thinking levels. | |
/exit | Quit pimacs. | |
/export | [file] | Export session to HTML. |
/fork | Create a new session from a previous user message. | |
/model | Switch models. | |
/name | <name> | Set session display name. |
/new | Start a new session. | |
/quit | Quit pimacs. | |
/reload | Reload extensions, skills and prompts. | |
/resume | Pick from previous sessions. | |
/session | Show session file, ID, messages, tokens, and cost. | |
/set-auto-compaction | Set auto compaction. | |
/set-auto-retry | Set auto retry. | |
/set-follow-up-mode | Set follow-up mode. | |
/set-steering-mode | Set steering mode. | |
/set-thinking-level | Set thinking level. |
Type @ followed by a partial file path to trigger file name
completion in the prompt buffer. The completion backend is controlled
by pimacs-file-completion-backend.
Prefix a command with ! to run it in Bash. Use !! to
run a command without adding it to the conversation context.
! echo "hello"
You can send contextual information from any buffer to the Pimacs chat prompt.
| Command | Description |
|---|---|
pimacs-send-region | Append the selected region to the prompt input. |
pimacs-send-filename | Append the current buffer’s filename (prefixed with @) to the prompt input. |
pimacs-send-flycheck-errors | Append the Flycheck errors at point to the prompt input. Falls back to all current errors in the buffer when there are none at point. |
You can attach images to your prompt to provide visual context to the
agent. Images are displayed as thumbnail previews above the prompt
input area and are sent along with your message. The agent may also
render images inline in its responses, for example when using the
read tool on a file that contains images.
The following image formats are supported:
Drag an image file from your file manager and drop it into the Pimacs
chat buffer, or paste a supported image from the clipboard via
yank-media. To remove an attached image, click on the
thumbnail with the mouse, or place point on it and press
backspace or delete.
The header line displays session context and model information. The
mode line displays the current agent state. Customize them with the
pimacs-header-line-format and pimacs-mode-line-format
defcustoms. Both accept strings and state components; use
:spacer to right-align following components.
(setq pimacs-header-line-format
'(:context_usage :spacer
(:model face font-lock-function-name-face)))
See pimacs-header-line-format for available components. A
component may also be a function that receives the current state plist.
Extension status text can be placed in either state line with a
(:status STATUS-KEY ...) component. STATUS-KEY is the key used by
the extension’s status update. Text properties after the key customize the
status at that placement.
(setq pimacs-header-line-format
'(:context_usage " " (:status "xyz-status" face font-lock-warning-face)
:spacer :model))
By default, status text also appears beside the prompt. To display a status
only in a state line, add its key to pimacs-status-widget-hidden-keys.
(setq pimacs-status-widget-hidden-keys '("xyz-status"))
Use pimacs-switch-session to switch between active Pimacs chat
sessions using completion. Use pimacs-list-sessions to display all
active chat sessions in a sortable tabulated list. Press RET to visit
the session on the current line and g to refresh the list. Select a
column header to sort by that column.
Customize the list’s columns and initial sort order with
pimacs-list-sessions-table and pimacs-list-sessions-sort-key.
To run Pi inside a sandbox, customize pimacs-executable and
pimacs-flags:
(setq pimacs-executable "nono")
(setq pimacs-flags '("run" "--silent" "--profile" "pi" "--allow-cwd" "--" "pi"
"--tools" "read,bash,edit,write,grep,find,ls"))
Emacs starts Pi in RPC mode.
In this setup, Pi handles the agent logic while Emacs provides the
user interface. Some features, such as /login and
/logout, are not
supported
because they are not currently exposed through the RPC API.
| Key | Command | Description |
|---|---|---|
| RET | pimacs-visit-item | Jump to the source location at point; with a prefix argument, open in another window |
| C-g | pimacs-abort | Abort the current operation |
| TAB, C-i | pimacs-toggle-section | Toggle visibility of the section at point |
| n, M-n | pimacs-goto-next-section | Move to the next section |
| N | pimacs-goto-next-user-message | Move to the next user message |
| p, M-p | pimacs-goto-previous-section | Move to the previous section |
| P | pimacs-goto-previous-user-message | Move to the previous user message |
| l, M-g l | pimacs-goto-last-section | Jump to the most recent section |
| i | pimacs-focus-prompt | Focus the prompt input field |
| q | pimacs-quit-chat | Quit the chat buffer |
| Key | Command | Description |
|---|---|---|
| C-g | pimacs-abort | Abort the current operation |
| M-p | pimacs-previous-prompt | Recall the previous prompt from history |
| M-n | pimacs-next-prompt | Recall the next prompt from history |
| C-r | pimacs-search-prompt | Search prompt history |
| RET | widget-field-activate | Send the current prompt |
| M-RET | pimacs-send-prompt-alternate | Send the prompt using the alternate streaming behavior |
| M-g l | pimacs-goto-last-section | Jump to the most recent section |
Status keys to hide from the default status widget.
Hidden statuses remain available to (:status STATUS-KEY ...) components
in pimacs-header-line-format and pimacs-mode-line-format.
'project ¶Completion backend for prefixed file paths in prompts.
project uses project-files to list files in the current project.
file uses file-name-all-completions to list files under the project root.
500 ¶Maximum number of prompt history entries to keep.
100 ¶Maximum number of recent sessions to list when resuming a session.
'followUp ¶Default streaming behavior for prompts.
steer: Queue the message while the agent is running. It is delivered
after the current assistant turn finishes executing its tool calls,
before the next LLM call.
followUp: Wait until the agent finishes. Message is delivered only
when agent stops.
'(("model" pimacs-select-model 0 "Switch models")
("new" pimacs-new-session 0 "Start a new session")
("reload" pimacs-reload 0 "Reload extensions, skills and prompts")
("resume" pimacs-resume 0 "Pick from previous sessions")
("compact" pimacs-compact 1 "Manually compact context, optionally with custom instructions")
("set-auto-compaction" pimacs-set-auto-compaction 0 "Set auto compaction")
("set-auto-retry" pimacs-set-auto-retry 0 "Set auto retry")
("session" pimacs-session-stats 0 "Show session file, ID, messages, tokens, and cost")
("name" pimacs-set-session-name 1 "Set session display name")
("set-thinking-level" pimacs-set-thinking-level 0 "Set thinking level")
("cycle-model" pimacs-cycle-model 0 "Cycle through available models")
("cycle-thinking-level" pimacs-cycle-thinking-level 0 "Cycle through thinking levels")
("set-steering-mode" pimacs-set-steering-mode 0 "Set steering mode")
("set-follow-up-mode" pimacs-set-follow-up-mode 0 "Set follow-up mode")
("fork" pimacs-fork 0 "Create a new session from a previous user message")
("clone" pimacs-clone 0 "Duplicate the current active branch into a new session")
("copy" pimacs-copy 0 "Copy last assistant message to clipboard")
("export" pimacs-export 1 "Export session to HTML")
("quit" pimacs-quit-chat 0 "Quit pimacs")
("exit" pimacs-quit-chat 0 "Quit pimacs"))
Alist mapping slash command names to command specs.
Each entry is (NAME COMMAND MAX-ARGS DESCRIPTION) where NAME is the command string without the leading slash, COMMAND is a command symbol, MAX-ARGS is 0 or 1 indicating the number of optional string arguments the command accepts, and DESCRIPTION is a short description string.
'(("read" . pimacs--insert-read-args)
("write" . pimacs--insert-write-args)
("edit" . pimacs--insert-edit-args)
("bash" . pimacs--insert-bash-args)
("grep" . pimacs--insert-grep-args)
("find" . pimacs--insert-find-args)
("ls" . pimacs--insert-ls-args))
Alist mapping tool names to inserter functions.
Each entry is (TOOL-NAME . FUNCTION) where FUNCTION is called with ARGS plist to insert formatted tool call arguments.
'(("bash" . pimacs--insert-bash-result)
("read" . pimacs--insert-read-result)
("write" . pimacs--insert-write-result)
("edit" . pimacs--insert-edit-result)
("grep" . pimacs--insert-grep-result)
("find" . pimacs--insert-find-result)
("ls" . pimacs--insert-ls-result))
Alist mapping tool names to result inserter functions.
Each entry is (TOOL-NAME . FUNCTION) where FUNCTION is called
with (CONTENT DETAILS ARGS) to insert the tool execution result.
CONTENT is a list of content items. Use pimacs--insert-content to render
it, or pimacs--content-text to extract text from content.
'(("read" . pimacs--visit-read-result)
("write" . pimacs--visit-write-result)
("edit" . pimacs--visit-edit-result)
("grep" . pimacs--visit-grep-result))
Alist mapping tool names to result visitor functions.
Each entry is (TOOL-NAME . FUNCTION) where FUNCTION is called with (DETAILS ARGS) to visit the relevant location of the tool result.
'(("read" . pimacs--visit-read-call)
("write" . pimacs--visit-write-call)
("edit" . pimacs--visit-edit-call))
Alist mapping tool names to call visitor functions.
Each entry is (TOOL-NAME . FUNCTION) where FUNCTION is called with (ARGS) to visit the relevant location of the tool call.
'() ¶Alist mapping custom message types to inserter functions.
Each entry is (CUSTOM-TYPE . FUNCTION) where FUNCTION is called with the message plist to insert the custom message content.
t ¶Whether to pop to the chat buffer after sending region, filename or errors.
t ¶Whether to keep the input area at the bottom as new chat content is added.
'(("Session" . (:session_name face font-lock-type-face))
("Provider" . :provider)
("Model" . :model)
("State" . (:agent_state face font-lock-constant-face))
("Context" . (:context_usage face shadow))
("Messages" . :total_messages)
("Cost" . (:cost face shadow))
("Project" . (:project_root face shadow)))
Columns displayed by pimacs-list-sessions.
Each entry is (HEADER . COMPONENT). COMPONENT uses the same format as an
entry in pimacs-header-line-format.
'("Session" . nil) ¶Initial sort order for pimacs-list-sessions.
The car is a header from pimacs-list-sessions-table. A non-nil cdr sorts
in descending order.
2 ¶The number of seconds to wait for a sync response.
"pi" ¶Pi command executable name.
'() ¶List of extra environment variables to use when starting pimacs.
'() ¶List of additional flags to provide when starting pimacs.
nil ¶When non-nil, log all RPC JSON to pimacs-log-rpc-file.
(expand-file-name "pimacs.el.log" (temporary-file-directory)) ¶File to write RPC JSON log entries to.
t ¶Whether to render ANSI colors in widget and status output.
'(:context_usage " (" :compaction_mode ")" :spacer "(" :provider ") " :model " • " :thinking_level) ¶Format of the Pimacs chat header line.
Strings are displayed literally. Functions are called with the state
plist and their returned values are displayed. A keyword component can
include text properties using propertize syntax. For example:
"(:model face font-lock-function-name-face)". A status component has
form (:status STATUS-KEY PROPERTY VALUE...); it displays the text set
by an extension with STATUS-KEY and accepts optional text properties.
For example: (:status "xyz-status" face font-lock-warning-face).
The following keywords are replaced with state information.
Session state keywords:
:modelModel identifier.
:providerModel provider.
:thinking_levelThinking level.
:session_nameSession name.
:project_rootProject root directory.
:compaction_modeauto or manual.
:message_countMessage count.
:pending_message_countPending message count.
Session statistics keywords:
:user_messagesUser message count.
:assistant_messagesAssistant message count.
:tool_callsTool call count.
:tool_resultsTool result count.
:total_messagesTotal message count.
:input_tokensInput token count.
:output_tokensOutput token count.
:cache_read_tokensCache-read token count.
:cache_write_tokensCache-write token count.
:cache_hit_percentTotal cache hit percentage.
:total_tokensTotal token count.
:costSession cost.
:context_usageContext tokens and context window.
:context_tokensContext token count.
:context_windowContext window size.
UI keywords:
:agent_stateCurrent agent state.
:spinnerActive agent spinner.
:spacerSpace that right-aligns all following entries.
Status components:
(:status STATUS-KEY ...) Extension status text for STATUS-KEY.
Use at most one :spacer.
'(" Pimacs " :agent_state :spinner) ¶Format of the Pimacs mode-line entry.
See pimacs-header-line-format for available components.
t ¶Whether to align markdown tables while rendering assistant output.
2 ¶Automatically hide older chat sections beyond this count. This helps reduce clutter by collapsing earlier responses when the conversation grows long. When nil, auto hiding is disabled and no sections are hidden automatically.
"\n\n" ¶String inserted between sections to control the visual gap. Increase or decrease this value to adjust spacing between sections.
'(pimacs-section-fringe-bitmap> . pimacs-section-fringe-bitmapv) ¶Fringe bitmaps used to indicate section visibility.
The car is used for hidden sections and the cdr for visible sections. Set this to nil to disable fringe indicators.