A Pi porcelain inside Emacs

The ergonomic agent harness for Emacs.

Pilish is a Pi porcelain inside Emacs: a mnemonic, buffer-native harness where chat stream and prompt composition are separate windows; with all of Emacs wired in.

Step 01 · Pi prerequisite Install the Pi CLI and log in Read the manual
GNU Emacs~/src/acme/Pilish
Session · retry-pass

You

Check the retry loop. Keep cancellation and add backoff.

Assistant

I will keep the cancellation guard and change only the delay.
EDITsrc/net/retry.elcompleted
41 (unless (funcall cancelled-p)
42 (sleep-for retry-delay))
+42 (sleep-for (* retry-delay (expt 2 attempt))))
43 (setq attempt (1+ attempt)))

Backoff now doubles per attempt. Cancellation still exits before sleep.

*pilish-chat:~/src/acme/*Pi-ChatBot
src/net/retry.elpoint at line 42
38(defun retry-request (attempt cancelled-p)
39 (condition-case err
40 (perform-request)
41 (unless (funcall cancelled-p)
42 (sleep-for (* retry-delay (expt 2 attempt))))
43 (setq attempt (1+ attempt)))
44 (retry-request attempt cancelled-p)))
45
46(provide 'retry)
retry.elElisp(42,0)
model-from-pi·high·idle·retry-pass
Add a regression test for the cancellation path.
*pilish-input:~/src/acme/*Pi-InputAll
C-c C-c send / queue · C-c C-s steer · C-c C-k abortq returns to the session

RET opens file rows in tool output, plain paths, and link labels.

Providers

Pilish supports a myriad of models through Pi's model catalog.

API compatibility
OpenAI-compatible
  • Anthropic
  • OpenAI
  • Google
  • Amazon Bedrock
  • OpenRouter
  • DeepSeek
  • Z.ai

The working surface

A session, in four views.

GNU Emacs~/src/acme/Pilish
Session · retry-pass

You

Check the retry loop. Keep cancellation and add backoff.

Assistant

I will keep the cancellation guard and change only the delay.
EDITsrc/net/retry.elcompleted
41 (unless (funcall cancelled-p)
42 (sleep-for retry-delay))
+42 (sleep-for (* retry-delay (expt 2 attempt))))
43 (setq attempt (1+ attempt)))

Backoff now doubles per attempt. Cancellation still exits before sleep.

*pilish-chat:~/src/acme/*Pi-ChatBot
src/net/retry.elpoint at line 42
38(defun retry-request (attempt cancelled-p)
39 (condition-case err
40 (perform-request)
41 (unless (funcall cancelled-p)
42 (sleep-for (* retry-delay (expt 2 attempt))))
43 (setq attempt (1+ attempt)))
44 (retry-request attempt cancelled-p)))
45
46(provide 'retry)
retry.elElisp(42,0)
model-from-pi·high·idle·retry-pass
Add a regression test for the cancellation path.
*pilish-input:~/src/acme/*Pi-InputAll
C-c C-c send / queue · C-c C-s steer · C-c C-k abortq returns to the session
Sessions [current] │ sort:threaded │ (5) │ ?:help
Fix the authentication bug in login.py42 msgs
Refactor DB Layer128 msgs
└─ Let's refactor the database layer to use connection pooling35 msgs
Setup CI/CD89 msgs
Quick question: what's the best way to handle env vars?8 msgs
*pilish-sessions:~/co/project/*Pi-SessionsTop
RET switch · / search · s sort
Tree [all] │ (17) │ ?:help
youWhy is my build failing? It worked yesterday.[restored]
astChecking the build config and recent changes.
youThe build log points at scripts/build.sh. It fails at the linker step.
├─ astReading the build script to check the default target.[kept]
shcd /srv/demo && make -j4 2>&1 | tail -5
ast(aborted)
youLet's commit the fix.
astDone - committed as 4f2a91c.[final-answer]
└─ astTrying the other angle: search the logs first.
youMakefile looks fine. Check the CI cache.
*pilish-tree:~/co/project/*Pi-TreeTop
RET move conversation · f filter · l label

Live work view

01 / LIVE

Live work.

The chat buffer shows the prompt, reply, and file diff above. Write the next prompt in the input buffer below. C-c C-c sends it, or queues it until the current turn finishes. C-c C-s delivers a steering message after the current tool call and interrupts the remaining queued tools. C-c C-k aborts the current response or compaction.

Click RET in the diff. Emacs opens src/net/retry.el at line 42 with point on the edit.
GNU Emacs~/src/acme/Pilish
Session · retry-pass

You

Check the retry loop. Keep cancellation and add backoff.

Assistant

I will keep the cancellation guard and change only the delay.
EDITsrc/net/retry.elcompleted
41 (unless (funcall cancelled-p)
42 (sleep-for retry-delay))
+42 (sleep-for (* retry-delay (expt 2 attempt))))
43 (setq attempt (1+ attempt)))
*pilish-chat:~/src/acme/*Pi-ChatBot
src/net/retry.elpoint at line 42
38(defun retry-request (attempt cancelled-p)
39 (condition-case err
40 (perform-request)
41 (unless (funcall cancelled-p)
42 (sleep-for (* retry-delay (expt 2 attempt))))
43 (setq attempt (1+ attempt)))
44 (retry-request attempt cancelled-p)))
45
46(provide 'retry)
retry.elElisp(42,0)
model-from-pi·high·idle·retry-pass
Add a regression test.
*pilish-input:~/src/acme/*Pi-InputAll
C-c C-c send / queue · C-c C-s steer · C-c C-k abortq returns to the session
02 / MENU

Menu.

C-c C-p opens the main command menu. m selects the model; t selects the thinking level; r opens the session browser; w opens the conversation tree.

GNU Emacs~/src/acme/Pilish
03 / SESSIONS

Sessions.

Every conversation is saved to disk as it runs, grouped by project. RET switches to the session at point; / searches; s cycles the sort: threaded, recent, relevance.

GNU Emacs~/co/project/Pilish
Sessions [current] │ sort:threaded │ (5) │ ?:help
Fix the authentication bug in login.py42 msgs
Refactor DB Layer128 msgs
└─ Let's refactor the database layer to use connection pooling35 msgs
Setup CI/CD89 msgs
Quick question: what's the best way to handle env vars?8 msgs
*pilish-sessions:~/co/project/*Pi-SessionsTop
RET switch · / search · s sort
04 / TREE

Tree.

The tree records every turn and tool call in the current session, including entries outside the active path. RET moves the live conversation to the selected node. f cycles the no-tools, default, user-only, labeled-only, and all filters; l sets or clears a label on the selected node.

GNU Emacs~/co/project/Pilish
Tree [all] │ (17) │ ?:help
youWhy is my build failing? It worked yesterday.[restored]
astChecking the build config and recent changes.
youThe build log points at scripts/build.sh. It fails at the linker step.
├─ astReading the build script to check the default target.[kept]
shcd /srv/demo && make -j4 2>&1 | tail -5
ast(aborted)
youLet's commit the fix.
astDone - committed as 4f2a91c.[final-answer]
└─ astTrying the other angle: search the logs first.
*pilish-tree:~/co/project/*Pi-TreeTop
RET move conversation · f filter · l label

Runtime / surface

Pi runs it. Pilish presents it.

The agent stays in Pi. The working surface belongs to Emacs.

PI Runtime

  • Agent loop and tools
  • Models and authentication
  • Sessions, extensions, providers and resources

PILISH Emacs surface

  • Ordinary chat and input buffers
  • Rendered replies and strict file targets
  • Transient menus and magit-section browsers

Chat behavior

  • Forking from a chat turn creates a separate session that records its parent session.
  • With the default settings, TAB collapses long tool output to 10 lines (5 for bash), completed thinking to one line, and a whole turn to its heading.
  • Long-running commands stream their output while they run.

How the menu works

  • Transient is an Emacs menu system, also used by Magit. Pilish opens it in a temporary window with actions grouped under headings.
  • Unlike a dropdown, you choose an action by typing the key printed beside it. Some entries, such as Attach, open a smaller menu with another key.
  • Evil is optional. With Evil enabled, ? opens the same main menu; ordinary Emacs bindings still work.

Extension UI

Extension commands and tools run. Notifications, confirm/select/input prompts, input prefill and status text are supported. Rich TUI widgets and component headers, footers and editors do not render in Emacs.

MELPA

Three steps to install

Get the runtime first: the Pi CLI, one login.

  1. 01

    Pi CLI

    npm install -g @earendil-works/pi-coding-agent

    Run pi, then use /login.

  2. 02

    Pilish

    M-x package-install RET pilish RET

    Install the MELPA package from Emacs.

  3. 03

    Start

    M-x pilish

    Open a project and begin a session.

Requirements Emacs 29.1+ with tree-sitter · Node 22.19+ · Pi 0.84.2+

Watch the 6:38 narrated demo