Paseo plugin: a beautiful chat for OMP tools, reasoning, prompts, and tasks
paseo plugin add ABorakati/beautiful-chat --ref mainSecurity status covers commit 5afb2ee13a63. This command tracks main. Refresh the listing before installing if the branch changed.
From the plugin's README
paseo plugin install ABorakati/beautiful-chat
The manifest requires Paseo >=0.8.0. Open Settings → Plugins → Beautiful Chat for the
accent, fonts, frosted glass, and prompt bubble options.
README
A Paseo plugin that redraws the Oh My Pi (OMP) chat stream: tool calls, reasoning, prompts, approvals, and checklists. It replaces the host rendering of OMP timeline items with typed, syntax-aware cards that follow the active Paseo theme.
Every screenshot here is a capture of the real component, rendered by the harness in .showcase/.
One whole turn, top to bottom shows the cards in the order the timeline draws
them.
paseo plugin install ABorakati/beautiful-chat
The manifest requires Paseo >=0.8.0. Open Settings → Plugins → Beautiful Chat for the
accent, fonts, frosted glass, and prompt bubble options.
Terminal frame, Bash syntax, exit code, duration, and the Git brand mark. A command that prints nothing says so rather than showing an empty panel.
The file's own language logo, a wrapped path, line numbers, and a copy button. The path is a link: pressing it shows the file in the machine's file manager.
A read of a .png carries no bytes through the timeline, so the host draws it as an empty code
block with a language badge. This card draws the file instead: a picture mark, the path as a link,
the pixel size and file size read from the header, and an eye control that hides the thumbnail. The
bytes come from the plugin's own daemon-side RPC (file.image), which is the only side that can
reach the file; PNG, JPEG, GIF, WebP, AVIF, BMP, ICO and SVG are recognised, and anything past
3 MB reports its size rather than inlining a data URI.
Diff rendering where adjacent removed and added rows join into one rounded block, and only the marker column carries the red or green.
Live thinking text, a token badge, and numbered steps.
Server badge, transport, input parameters, and the response payload, each syntax-highlighted.
One card per kernel cell: the source that ran, then the text it printed.
Option cards with the recommended badge, the chosen answer marked, and a typed reply labelled as typed rather than shown as a selection.
Subagent name, type, model, and the delegated instructions.
Every hub op is mapped: start, stop, restart, ps, logs, and describe render the
process card with its launch line, readiness, and recent output; send, wait, inbox, and
list render the message card; jobs and cancel render the job snapshot. The cards report;
they carry no buttons, because a plugin cannot restart or cancel anything.
Paseo's own mark leads the card, and the created agent's provider carries its brand mark.
A collapsible trace with a connected step rail, per-step duration, and a token total.
Phase name, per-task status, durations, and a blocked task with its reason.
Risk classification, the exact command, target path, working directory, and the approve or deny actions the host owns.
The authored turn on a raised theme surface with a square tail, a copy button, and the turn's token usage.
Shared by every card that shows code: language detection from the path, line numbers, diff tints, Devicon brand marks, and the file-manager link.
| Setting | Effect |
|---|---|
| Accent colour | Follow the Paseo theme, or pick Jade, Violet, Amber, or Rose. |
| Interface font | Embedded Inter, or the system interface face. |
| Code glyphs | Iosevka with ligatures, or literal glyphs. |
| Frosted glass | Blur card surfaces, or paint them solid. |
| Enhanced prompt bubble | Off hands prompts back to Paseo, whose bubble shows pasted images. |
A file name in a read, write, edit, or code block is a link. Pressing it calls the plugin's own
daemon-side RPC (file.reveal), which resolves the path against the agent's working directory and
asks the platform shell to show it:
| Platform | Behaviour |
|---|---|
| Windows | explorer.exe /select,<file> selects the file. |
| macOS | open -R <file> selects the file in Finder. |
| Other | xdg-open <directory> opens the containing directory. |
A directory path opens that directory. A path the daemon cannot stat does nothing.
A tool the plugin has no typed card for still shows its output in the terminal frame, and a call that printed nothing says so. No card renders an empty panel.
The link cannot open Paseo's own file editor: see the first limitation below.
Measured against @getpaseo/plugin 0.8.0 and the Paseo 0.8.0 desktop build. Each entry names the
evidence and the workaround this plugin uses.
{agentId, theme, host, layout, timestamp, item}, and plugin navigation offers only openSettings, openSurface,
openWorkspacePanel, openAgentPanel, openAgent, and openWorkspace. The host's own file tab
target ({kind:"file", path}, reachable in-app through ?open=file:<path>) is not exposed, and
the paseo:// scheme only carries agent deep links. Workaround: a daemon-side RPC that reveals
the path in the operating system's file manager.text, messageId, and clientMessageId. Pasted
images never reach plugin code, and the daemon timeline row stores the same item, so a server RPC
cannot recover them either. Workaround: the Enhanced prompt bubble setting returns prompts to
the host.undefined is the only opt-out.agentId only, so cwd and workspaceId need a
second lookup through useAgent.^[a-z][a-z0-9._-]*$. A camelCase name such
as revealPath typechecks, then fails the whole plugin at install or reload with
Invalid plugin RPC method.@getpaseo/plugin/client/react-native
ships as export {}; the host injects the implementations. Bundling or testing plugin UI outside
Paseo needs a shim, which is what .showcase/shims provides.PluginTheme exposes surface0–surface2, border,
foreground, foregroundMuted, accent, accentForeground, and three status colours. Every
other surface, including code backgrounds and diff tints, must be derived with alpha; that is what
client/components/theme-tokens.ts exists for.backdrop-filter is
impossible through the style API. Frosted glass is a hand-injected <style> rule matched by a
data attribute.@font-face rule, and
every surface needs a wrapper that escapes the host's own font cascade.react, react/jsx-runtime, react-native, @tanstack/react-query, zod,
@getpaseo/plugin, @getpaseo/plugin/client, @getpaseo/plugin/client/react-native, and
@getpaseo/plugin/client/ui. Anything else throws
Module "x" is not available in plugin client code when the bundle loads, so
react-native-svg and lucide-react-native are out of reach. Lucide icons still work,
because the host renders them: Icon from @getpaseo/plugin/client/react-native takes any
Lucide name. Brand marks are not in Lucide, and React Native's <Image> decodes PNG, JPEG,
GIF, and WebP but never SVG, so a data-URI SVG renders on web and stays blank on iOS and
Android. Those marks ship as PNG rasters in client/components/mark-bitmaps.ts.defineSettings rejects any scope other than host, so
per-workspace or per-agent presentation settings are impossible. This plugin keeps presentation
preferences in client storage instead.beautiful-chat/
paseo-plugin.json # Manifest: id and Paseo requirement
index.client.tsx # Timeline transformers, renderers, settings screen
index.server.ts # Daemon-side RPCs (file.reveal)
shared/
contracts.ts # Data contracts shared by client and server
file-rpc.ts # file.reveal contract
client/
live-renderers.tsx # Timeline item to component mapping
settings-page.tsx # Settings screen
preferences.ts # Client-side presentation preferences
components/ # Cards, syntax block, glyphs, motion, theme tokens
mark-bitmaps.ts # GENERATED PNG rasters of every brand mark
devicon-data.ts # Vendor SVG sources, read only by the generator
lobe-marks.ts # Vendor SVG sources, read only by the generator
.showcase/ # Offline harness used to capture the screenshots
docs/images/ # Screenshots in this README
npm install
npm run typecheck
paseo plugin reload beautiful-chat
Rebuild the screenshots after a visual change:
esbuild .showcase/showcase.tsx --bundle --outfile=.showcase/showcase.js --jsx=automatic \
--alias:react-native=react-native-web \
--alias:@getpaseo/plugin/client/react-native=./.showcase/shims/plugin-react-native.tsx
Then serve .showcase/ and capture each #shot-* element.
MIT
Scanned 15 Sep 2026, 11:46 UTC from ABorakati/beautiful-chat.