Browser pixels. Terminal controls. One shared page.

A real browser.
Right inside OpenTUI.

Embed a live Electron page in your terminal UI. Humans click and type through Kitty-native pixels while agents attach to the exact same page over CDP.

Read the docs
  • MIT licensed
  • Bun + Node
  • Local by design
ghostty — opentui-browser live
A real opentui-browser session running in Ghostty, scrolling the shared page
Actual terminal capture Electron → RGBA → Kitty
hidden Electron BrowserWindow top-down RGBA file Kitty graphics protocol terminal image placement

The differentiator

One page. Two operators.

This is not a screenshot stream or a separate automation browser. The terminal and the agent meet on the same live page, with the same navigation, storage, cookies, and state.

Human OpenTUI input

Sees the live page in the terminal and owns focus, keyboard, pointer, and scroll.

Agent Chrome DevTools Protocol

Inspects DOM, reads network activity, and operates the exact page the human can see.

From zero to browser surface

Drop it into your render tree.

Create the OpenTUI renderer, add one BrowserRenderable, then start it. The surface owns its managed runtime by default and closes it when you are done.

  1. 1 Install the package and its OpenTUI peer.
  2. 2 Add a surface with ordinary OpenTUI sizing.
  3. 3 Start it, focus it, and navigate.
Explore the full API
browser.ts TypeScript
import { createCliRenderer } from "@opentui/core"
import { BrowserRenderable } from "opentui-browser"

let finish!: () => void
const done = new Promise<void>((resolve) => { finish = resolve })

const renderer = await createCliRenderer({
  screenMode: "alternate-screen",
  exitOnCtrlC: true,
  onDestroy: finish,
})

const browser = new BrowserRenderable(renderer, {
  url: "https://example.com",
  width: "100%",
  height: "100%",
  border: true,
  title: " browser ",
})

renderer.root.add(browser)

try {
  await browser.start()
  browser.focus()
  await done
} finally {
  try {
    await browser.close()
  } finally {
    renderer.destroy()
  }
}

Designed like infrastructure

Smooth at the surface. Strict underneath.

01

Feels native to the TUI

Keyboard, paste, pointer, wheel, hover, focus, and browser cursor feedback flow through one focusable OpenTUI renderable.

02

One runtime, many pages

Keep long-lived pages in one managed Electron sidecar. Present the active page while background pages stay alive at 1 fps.

03

Built for shared control

Every page exposes its exact loopback CDP endpoint and target ID, so a person and an agent can operate the same live page.

04

Ownership you can reason about

Processes, pages, presentations, profiles, frame files, timers, and Kitty images all have explicit cleanup boundaries.

05

Bounded by design

Latest-frame scheduling keeps producer-driven work finite across frames, pointer moves, wheel input, resizing, and placement.

06

Promise-first. Effect-ready.

Use the direct Promise API everywhere, or opt into scoped Electron and BrowserSurface services from opentui-browser/effect.

Current target

Built for local terminals.

Full compatibility notes
Runtime
Bun 1.3+ or Node.js 26.3+
OpenTUI
core 0.4.x
Graphics
Kitty protocol
Tested
Ghostty · alternate screen

Building an agentic terminal?

Give OpenCode the same browser you can see.

@neriousy/opencode-browser adds automatic browser control and Chrome DevTools MCP registration on top of this shared-page foundation.

View the integration

Ready when your renderer is

Put the web in your terminal.

One install. One renderable. One real browser page.

View on npm