GitHub Copilot 33da0e335c fix: use pyte terminal emulator for screenshot rendering
Replaces simple carriage return handling with pyte terminal emulator
to properly interpret all ANSI escape sequences including cursor
positioning. This fixes the tmux status bar 'creeping up' issue in
screenshots.

Adds pyte dependency to pyproject.toml.

Resolves TODO item #2.
2026-01-24 10:23:31 +00:00
2026-01-21 23:53:57 +00:00
2026-01-21 23:53:57 +00:00
2026-01-21 23:53:57 +00:00
2026-01-21 23:53:57 +00:00
2026-01-21 23:53:57 +00:00
2026-01-21 23:53:57 +00:00
2026-01-21 23:53:57 +00:00
2026-01-21 23:53:57 +00:00
2026-01-21 23:53:57 +00:00
2026-01-21 23:53:57 +00:00

textual-webterm

Icon

Serve terminal sessions and Textual apps over the web with a simple CLI command.

This is heavily based on textual-web, but specifically focused on serving a persistent terminal session in a way that you can host behind a reverse proxy (and some form of authentication).

Built on top of textual-serve, this package provides an easy way to expose terminal sessions and Textual applications via HTTP/WebSocket with automatic reconnection support.

Features

  • 🖥️ Web-based terminal - Access your terminal from any browser
  • 🐍 Textual app support - Serve Textual apps directly from Python modules
  • 🔄 Session reconnection - Refresh the page and reconnect to the same session
  • 🎨 Full terminal emulation - Colors, cursor, and ANSI codes work correctly
  • 📐 Auto-sizing - Terminal automatically resizes to fit the browser window
  • 🚀 Simple CLI - One command to start serving

Non-Features

  • No Authentication - this is meant to be used inside a dedicated container, and you should set up an authenticating reverse proxy like authelia
  • No Encryption (TLS/HTTPS) - again, this is meant to be fronted by something like traefik or caddy

Quick Start

Serve a Terminal

Serve your default shell:

textual-webterm

Serve a specific command:

textual-webterm htop

Serve a Textual App

Serve a Textual app from an installed module:

textual-webterm --app mypackage.mymodule:MyApp

Serve a Textual app from a Python file:

textual-webterm --app ./calculator.py:CalculatorApp

Options

Specify host and port:

textual-webterm --host 0.0.0.0 --port 8080 bash

Then open http://localhost:8080 in your browser.

Landing pages

You can serve a landing page with multiple terminal tiles driven by a YAML manifest:

- name: My Service
  slug: my-service
  command: docker logs -f my-service

Run with:

textual-webterm --landing-manifest landing.yaml

You can also point to a docker-compose file; services with the label webterm-command become tiles. For example:

services:
  db:
    image: postgres
    labels:
      webterm-command: docker exec -it db psql

Start with:

textual-webterm --compose-manifest compose.yaml

When a landing manifest is provided, the root (/) shows the grid; clicking a tile opens a dedicated terminal session in a new tab. Without a manifest, the server operates in single-terminal mode.

CLI Reference

Usage: textual-webterm [OPTIONS] [COMMAND]

  Serve a terminal or Textual app over HTTP/WebSocket.

  COMMAND: Shell command to run in terminal (default: $SHELL)

Options:
  -H, --host TEXT               Host to bind to [default: 0.0.0.0]
  -p, --port INTEGER            Port to bind to [default: 8080]
  -a, --app TEXT                Load a Textual app from module:ClassName
                                Examples: 'mymodule:MyApp' or './app.py:MyApp'
  -L, --landing-manifest PATH   YAML manifest describing landing page tiles
                                (slug/name/command).
  -C, --compose-manifest PATH   Docker compose YAML; services with label
                                "webterm-command" become landing tiles.
  --version                     Show the version and exit.
  --help                        Show this message and exit.

Development

Setup (Makefile-first)

git clone https://github.com/rcarmo/textual-webterm.git
cd textual-webterm

# Install with dev dependencies via Makefile
make install-dev

Common tasks (use Makefile)

  • Lint: make lint
  • Format: make format
  • Tests: make test
  • Coverage (fail_under=80): make coverage
  • Full check (lint + coverage): make check

Notes

  • WebSocket protocol (browser <-> server) is JSON: ["stdin", data], ["resize", {"width": w, "height": h}], ["ping", data].
  • Static assets are provided by textual-serve; this project does not add custom static files.
  • /screenshot.svg replays the terminal buffer to SVG via Rich; width can be set with ?width=120 and is clamped for safety.

Requirements

  • Python 3.9+
  • Linux or macOS

License

MIT License - see LICENSE for details.

  • Textual - TUI framework for Python
  • textual-serve - Serve Textual apps on the web
  • Rich - Rich text formatting for terminals
S
Description
No description provided
Readme 122 MiB
Languages
Go 51.5%
TypeScript 31%
JavaScript 14.8%
Shell 1.2%
Makefile 0.8%
Other 0.7%