Feature · Terminal UI

TUI

Ink components for terminal apps a person and an agent run together: the same controlled state, stable handles and MCP bridge as the browser kit, built for a grid of cells.

React
Browse componentsLearn TUI
npm install @particle-academy/fancy-tui

Needs Node 22, React 19.2 and Ink 7.

The workbenchLive demo
examples/quick-start.tsx
Start here

Quick start

Compose an Ink app with Fancy spacing, theme, and stable surface handles.

HTML preview
Deploy agent
connected
RUN

Ready for instructions.

Tab focus Enter submit Alt+Enter newline
React / Ink
import { render } from "ink";
import { FancyTuiProvider, Header, Panel, Text } from "@particle-academy/fancy-tui";

render(
  <FancyTuiProvider>
    <Header title="Deploy agent" status="connected" />
    <Panel title="Run"><Text>Ready for instructions.</Text></Panel>
  </FancyTuiProvider>
);

Pick an example to read it as semantic HTML beside its React / Ink source. View as console runs the real components in a full-screen terminal.

The live console takes the whole screen

Your browser becomes a terminal in front of a Node service running the real fancy-tui Ink app. Every keystroke goes to it, and self-animating components animate.

↑ ↓ browseEnter drive an interactive one/ searchq back to this page
Every component, as your terminal draws itReal Ink output

Filter, then flip any card to its source. Each frame is rendered by a real terminal emulator from the ANSI the component produced.

Built for terminals people and agents share

A terminal has no DOM for an agent to scrape, so everything an agent does goes through handles and an MCP bridge.

Real Ink, never a picture

Every preview below is the component's actual Ink output, captured to ANSI by fancy-tui's own showcase build and shipped inside the package as showcase/previews.json.

Stable surface handles

createTuiSurfaceRegistry() gives each surface a unique id, a read() and named commands. A duplicate id throws, so an agent never guesses which panel it is addressing.

Agents propose, people confirm

tui_action_invoke runs a command, or, when its policy is propose or confirm, parks it for tui_action_confirm / tui_action_reject. A human-only command refuses an agent outright.

Pushed live, or pulled later

Events land in a durable inbox. Subscribe to have them pushed on the MCP transport, or pull with human_plus_events_list and acknowledge with human_plus_events_ack, per consumer.

Safe Markdown for agent output

The ./markdown renderer turns Markdown into ANSI and strips control characters, ESC included, from untrusted text first, so a reply cannot smuggle in terminal escape sequences.

Keys and clicks, by capability

Alt+Enter inserts a newline everywhere; Shift+Enter only where enhanced keyboard reporting is detected.FancyTuiProvider mounts mouse support, so a clickable box gets clicks once the terminal reports them.

How it fits

fancy-tui is the Ink half; the agent reaches it through the TUI bridge in agent-integrations.

Human+ bridge

An agent drives this surface over MCP, through the same state a person sees, never the DOM.

  • import { registerTuiBridge } from "@particle-academy/agent-integrations/bridges/tui";tools: tui_*

Install

  1. fancy-tuiReact
    npm install @particle-academy/fancy-tui

The packages

Build a terminal app with an agent inside

Read the fancy-tui docs for every component and the surface registry, then wire the TUI bridge so an agent can act on it.