pi-emote
v0.2.10
Published
Animated pixel-art emote widget for pi TUI
Maintainers
Readme
CGx's pi-emote
Currently looking to expand the emotes gallery! If you have an emote set you'd like to submit, please make a PR!
Animated pixel-art emote that lives in the top-right corner of your pi TUI session. Reacts to what the agent is doing — thinking, talking, reading, writing, using tools, etc.

Supports Kitty, iTerm2, and ASCII rendering.
Gallery
Community-contributed emote sets. Submit yours via PR!
Image Sets
| Avatar | Name | Contributor |
|--------|------|-------------|
| | default | @cgxeiji |
| | aza_choi | @shennguyenrs |
| | aza_choi_nobg | @shennguyenrs |
| | red | @cgxeiji |
ASCII Sets
| Avatar | Name | Contributor |
|--------|------|-------------|
| (^ ◡ ^)/ | ascii | @cgxeiji |
| ʕ•̫͡•ʔ | ascii-bear | @LCorleone |
Install
pi install git:github.com/cgxeiji/pi-emoteStates
| State | Trigger |
|-------|---------|
| hi | Session start |
| idle | Nothing happening (blinks occasionally) |
| think | Reasoning tokens streaming |
| talk | Text response streaming |
| read | read tool / reading tool output |
| write | write or edit tool |
| tool | Any other tool |
| success | Successful tool execution |
| failure | Failed tool execution |
| compact | Context compaction |
Config
Drop a config.json in one of these paths (highest priority wins):
~/.pi/agent/extensions/pi-emote/config.json— your global prefs.pi/extensions/pi-emote/config.json— project override
Only include what you want to change:
{
"size": 12,
"emotes": [
{ "model": "*claude*", "emote-set": "my-avatar" }
]
}See config.json in the extension root for all defaults.
Multiplexers
pi-emote can render image avatars through tmux using DCS passthrough. When tmux is detected, pi-emote auto-detects the outer terminal and picks the right image protocol.
tmux Setup
Add these to your tmux.conf:
# Required — allow image sequences to pass through to the outer terminal
set -g allow-passthrough on
# Required — detect outer terminal when attaching from a different terminal
set -ga update-environment TERM
set -ga update-environment TERM_PROGRAM
# Recommended — reduces flicker during animation
set -sg escape-time 0Then restart tmux completely:
tmux kill-server && tmuxWithout allow-passthrough, pi-emote defaults to ASCII and shows a one-time warning with setup instructions.
Experimental Multiplexer Support
| Outer Terminal | Protocol | Status | |----------------|----------|--------| | Ghostty | kitty-unicode | ✅ Stable, pane-safe, auto-detected | | kitty | kitty-unicode | ⚠️ Untested, pane-safe, auto-detected | | iTerm2 | iterm2 | ⚠️ Experimental, opt-in only (pane bleed in multi-pane layouts) | | WezTerm | iterm2 | ⚠️ Experimental, opt-in only (not verified) |
The outer terminal is detected via tmux show-environment TERM_PROGRAM, which reflects the currently attached terminal.
Ghostty and kitty use the kitty-unicode renderer (Unicode placeholders) which is pane-safe — images stay within their pane and clean up on session switch. This is the default when auto-detected.
iTerm2 and WezTerm use DCS passthrough for the iTerm2 image protocol. This works but has known limitations: images can bleed into adjacent panes and persist when switching sessions. Not enabled by default — opt in explicitly:
{
"terminals": [
{ "match": "tmux", "render": "iterm2" }
]
}Other Multiplexers
zellij and screen are not yet supported and default to ASCII.
Manual Override
Force a specific renderer:
{
"terminals": [
{ "match": "tmux", "render": "kitty-unicode" }
]
}Available render values for tmux: "auto", "kitty-unicode", "kitty", "iterm2", "ascii".
"auto"— detect outer terminal; uses kitty-unicode for Ghostty/kitty, ASCII for others"kitty-unicode"— pane-safe Unicode placeholders (Ghostty, kitty)"kitty"— classic DCS passthrough (single-pane only, experimental)"iterm2"— iTerm2 DCS passthrough (single-pane only, experimental)"ascii"— text fallback
Custom Emotes
Emote sets live in emotes/<set-name>/ with PNG frames per state:
emotes/my-avatar/
├── idle/*.png
├── think/*.png
├── talk/*.png
├── read/*.png
├── write/*.png
├── tool/*.png
└── ... # hi, success, failure, compactNot all states are required. Missing ones just won't animate.
Where to put them
pi-emote searches in order:
.pi/extensions/pi-emote/emotes/<name>/(project)~/.pi/agent/extensions/pi-emote/emotes/<name>/(user)- Extension built-in → falls back to
default
Map models to sets
Glob patterns against model ID, last match wins:
{
"emotes": [
{ "model": "*", "emote-set": "default" },
{ "model": "*claude*", "emote-set": "my-avatar" },
{ "model": "*haiku*", "emote-set": "haiku-avatar" }
]
}In this example, claude models use my-avatar, but haiku ones use haiku-avatar.
See emotes/default/emotes.json for per-set frame config (blink frames, talk weights).
License
MIT
