Model or dataset
Michaelliv/pi-generative-ui avatar
Michaelliv/pi-generative-ui

pi-generative-ui: giving a coding agent native windows instead of fenced code blocks

Claude.ai's generative UI — reverse-engineered, rebuilt for pi. Interactive HTML/SVG widgets in native macOS windows.

1,162 stars78 forksTypeScriptLicense varies

At a glance

What is it?
Michaelliv's TypeScript extension rebuilds Claude.ai's widget system for the pi agent, including the design guidelines, the streaming pipeline and the native window layer.
Who is it for?
What makes this repository worth reading is that it treats a closed feature as an engineering problem with an inspectable answer. The guideline extraction is documented well enough to reproduce, the streaming contract is written down as a four line lifecycle, and the window layer sits on top of system WebKit instead of a browser runtime.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository last received commits 130 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 11, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The feature being rebuilt is a tool call, not a renderer

The project description states the aim plainly: Claude.ai's generative UI, reverse-engineered and rebuilt for pi. The mechanism it targets is specific. On claude.ai, asking Claude to visualise something triggers a tool called `show_widget`, which returns an HTML fragment that renders inline in the conversation. Because the HTML arrives as tool call parameters, it streams token by token, so cards and sliders materialise while the model is still writing them.

A coding agent has no such affordance. It has a terminal, so the natural fallback is a fenced code block describing a chart and hoping the reader assembles it. The README's framing is that the extension makes the LLM choose instead: explanatory requests trigger widgets, code and text requests stay in the terminal.

Only two tools are registered. `visualize_read_me` loads design guidelines lazily, and `show_widget` produces the HTML fragment. That small surface is the whole contract between model and window, and it is a reasonable thing to study if you are building anything similar.

The design guidelines were extracted, not written

The most interesting paragraph in the README describes where the rules come from. They are not hand written by this project. Any claude.ai conversation can be exported as JSON, and the export includes full tool call payloads, which include the complete `read_me` results holding Anthropic's own design system instructions.

The stated procedure: trigger `read_me` with each module combination, export the conversation, parse the JSON, split the responses into deduplicated sections, then verify byte-level accuracy against the originals. The claimed result is 72KB of production rules covering typography, colour palettes, streaming-safe CSS, Chart.js configuration and SVG diagram work.

Five modules load on demand, and the sizes are given: `interactive` at 19KB for sliders, metric cards and live calculations, `chart` at 22KB for Chart.js setup and number formatting, `mockup` at 19KB for component tokens and skeleton loading, `art` at 17KB for SVG illustration and Canvas animation, and `diagram` at 59KB for flowcharts and architecture diagrams. Lazy loading is why the largest module does not cost every request.

There is a question this raises that the README does not address. The extraction method is described as producing byte-identical output, but the repository holds a copy of someone else's system prompt material, and the MIT licence in `package.json` is the licence for the code. If you plan to reuse these modules, that is worth checking before you build on them.

Streaming tokens into a window without thrashing the DOM

The streaming architecture is documented as a short event lifecycle, and it is the part of the design most worth copying. The extension hooks pi's `toolcall_start`, `toolcall_delta` and `toolcall_end` events, and a `WidgetSession` owns one Glimpse window for the duration of a single `show_widget` call.

The event mapping is given directly in the README:

bash
pi install npm:pi-generative-ui

Two details make this more than a pipe. Chunks are debounced at 150ms, which batches rapid token updates so the window repaints on a human timescale rather than per token. And the DOM is diffed with morphdom instead of being replaced, so only changed nodes update, newly inserted nodes get a 0.3 second fade, and scripts run exactly once on the final chunk rather than on every intermediate parse.

The page side is real TypeScript. `runtime/` holds `index.ts` for boot, `bridge.ts` for the host channel and RPC layer, and `morph.ts` for the diff and script execution, and `build.mjs` bundles them with esbuild into a single IIFE inlined into the shell HTML. The protocol is a typed discriminated union: content messages flow host to page carrying `html` and a `final` flag, and `user-message` or `rpc-call` flow back. The README is explicit that this replaced `escapeJS` and eval strings standing in for business logic.

Display-only widgets, and why the tool call returns early

The v0.3.0 release is a full rewrite and it changed the central contract, which is the clearest sign of what the author thinks the feature is for. Windows are now display-only, and the release notes list `window.glimpse.send(data)` as a no-op, with widgets described as intentionally display-only.

The reason is visible in the streaming description. The agent's tool call resolves the moment the final HTML lands, and the window stays open until the user dismisses it. Earlier behaviour had the agent waiting on a long interaction timeout, and the rewrite removes that wait entirely. If you are using this as an agent, a chart cannot hand a value back to the model's context, so anything that needs a number returned has to be handled in the surrounding conversation instead.

Interactivity inside the window is a different matter and remains supported: sliders, hover states, animations and controls driving the widget's own DOM all work. Features needing host capability go the other way, through `window.__glimpseUI.rpc(method, params)`, with features registering a name and handler once and a 30 second default timeout. SVG export is the shipped example, where hovering any `<svg>` raises a menu that copies to the clipboard or saves through the native dialog.

The v0.2.1 release documents a bug worth remembering about that path: diagrams using pre-built CSS classes such as `c-blue` and `c-teal` rendered as solid black boxes because the WKWebView had no stylesheet defining them. The fix injected a full stylesheet with colour ramp classes, text classes, utility classes, CSS variables and pre-styled form elements.

Cross-platform support rests on one native window library

The window layer is Glimpse, described as a native micro-UI library that opens a WKWebView window in under 50ms through a small Swift binary. The stated advantages are concrete: no Electron, no browser tab, nothing beyond the system WebKit at runtime.

That was a macOS story originally, and the v0.3.0 notes describe cross-platform window support arriving through `[email protected]` with platform shims for macOS, Linux and Windows. The install requirements are spelled out in the README, and they are not light. Glimpse 0.8 compiles a tiny native binary on `postinstall`, which needs Xcode Command Line Tools on macOS, Rust plus GTK4 or WebKitGTK development packages on Linux, or the .NET 8 SDK and the WebView2 Runtime on Windows. Linux also has a Chromium fallback if you would rather skip the native build.

The `package.json` shows how thin the dependency surface is. Two runtime dependencies, `glimpseui` at `^0.8.1` and `morphdom` at `^2.7.4`, with four pi packages as peers under the `@earendil-works` scope at `^0.78.0`, and TypeScript, esbuild and vitest in development. Scoping the peers to a fork is its own migration note, and the v0.3.0 breaking changes list the move from `@mariozechner/*` to `@earendil-works/*` alongside the peer bump.

The published payload is small by design: the `files` array contains only `.pi/`, and a `pi` block registers `.pi/extensions/generative-ui` as the extension entry point. The scripts are `build:runtime`, `test`, `test:watch`, `typecheck` and `prepare`, and the tree adds a `tests/` directory with a vitest config.

What the repository leaves to you

Some things a reader wants are simply absent from what the project publishes. The README describes the tools, the streaming lifecycle and the guideline modules, and the tree confirms a `CHANGELOG.md`, a `.github/` directory and a `tests/` folder, but there is no documented policy for what a widget is allowed to do, no versioning contract for the guidelines themselves, and no note on how a model is expected to choose between the five modules.

The numbers the project reports are worth recording as a baseline. GitHub shows 1,162 stars, 77 forks and 3 open issues, TypeScript as the primary language, MIT as the licence, and a default branch of `main`. The last push is dated 2026-06-03, which is the same day as v0.3.0, so the rewrite is the current state of the tree rather than something in progress.

On testing, the release notes are the source: a 34 test suite and a cross-platform CI matrix, plus npm release CI added for future tagged releases. There is no coverage figure published, and no published list of which parts of the streaming pipeline those 34 tests cover, so if you extend the extension you would be extending it without a visible safety net in the places that matter most, namely the debounce timing and the script-executes-once rule.

Editorial conclusion

What makes this repository worth reading is that it treats a closed feature as an engineering problem with an inspectable answer. The guideline extraction is documented well enough to reproduce, the streaming contract is written down as a four line lifecycle, and the window layer sits on top of system WebKit instead of a browser runtime. The v0.3.0 rewrite shows the author was willing to break the earlier API to get a typed protocol and cross-platform support rather than accumulate shims. Two limits are worth planning around. Widgets are display-only, so a chart cannot feed a value back into the agent's context, and the whole pipeline leans on a pi host and a Glimpse build that must compile on your machine first. If you want a coding agent to draw rather than describe, this is the reference implementation to start from, and the 34 test suite gives you somewhere to point your own questions about it.

Frequently asked questions

What does generative UI mean?

It means the model returns interface code as part of its answer rather than describing an interface in text. On claude.ai this happens through a `show_widget` tool whose HTML fragment renders inline and streams as tokens arrive. This project rebuilds that pattern for pi so a coding agent can open a real HTML application in a native window instead of printing a code block.

How do I install pi-generative-ui?

Run `pi install npm:pi-generative-ui` in pi. The extension then registers two tools, `visualize_read_me` and `show_widget`, which the model calls automatically when a request calls for a visual explanation. Glimpse 0.8 or newer is required.

Can widgets send data back to the agent?

No. Widgets are display-only from the agent's point of view, and `window.glimpse.send(data)` is a no-op since v0.3.0. Interactivity inside the window, including sliders and hover states, works normally, and features that need the host use a typed RPC channel with a 30 second timeout.

Does pi-generative-ui work on Linux and Windows?

Yes, through `[email protected]` with platform shims for all three operating systems. Glimpse compiles a small native binary on install, so Linux needs Rust and GTK4 or WebKitGTK development packages unless you use the Chromium fallback, and Windows needs the .NET 8 SDK and the WebView2 Runtime.

Official sources

  1. Issues
  2. Michaelliv/pi-generative-ui on GitHub
  3. README
  4. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/michaelliv-pi-generative-ui.svg)](https://hysenlabs.com/projects/michaelliv-pi-generative-ui)