Skip to main content

Unified streaming terminal UI framework (client + server)

Project description

termstream-py

Unified streaming terminal UI framework (client + server)

TermStream is a Python-based framework for building streaming terminal UI applications with WebSocket communication, curses-based browser client, and MCP (Model Context Protocol) agent support.

Installation

pip install termstream-py

Prerequisites

  • Python >= 3.8

Usage

CLI Commands

After installation, the termstream command is available:

# Start the WebSocket server with a Python app module
termstream server -a path/to/your_app.py

# Start the WebSocket server with a YAML configuration file
termstream server -c path/to/your_config.yaml

# Start the WebSocket server from a directory tree (content.md files)
termstream server -d path/to/your_directory/

# Run the terminal browser client
termstream browser -u ws://localhost:8765

# Run MCP server for AI agents
termstream mcp -a path/to/your_app.py --transport stdio
termstream mcp -c path/to/your_config.yaml --transport stdio

CLI Options

server

  • -u, --url - Server WebSocket URL (default: ws://localhost:8765)
  • -a, --app - Path to app module (e.g., myapp.py)
  • -c, --config - Path to YAML configuration file
  • -d, --directory - Path to directory tree for building routes from content.md files

browser

  • -u, --url - Server WebSocket URL (default: ws://localhost:8765)

mcp

  • -a, --app - Path to app module (e.g., myapp.py)
  • -c, --config - Path to YAML configuration file
  • -p, --port - MCP HTTP port (default: 3000)
  • --transport - MCP transport type: stdio or http (default: stdio)

YAML Configuration

Define your server pages in a YAML file instead of code:

host: localhost
port: 8765

pages:
  - path: /home
    title: Home
    widgets:
      - type: heading
        pos: [0, 0]
        text: Welcome to TermStream
        style:
          bold: true
      - type: text
        pos: [2, 0]
        text: Streaming terminal UI framework.
      - type: button
        pos: [4, 0]
        text: "-> Docs"
        action:
          type: navigate
          target: /docs

Widget types: text, heading, button, input

Style options: bold, italic, underline

Action types: navigate (with target path)

Note: Widget id is optional. If omitted, a unique id is auto-generated. Provide an explicit id only for widgets that need server-side updates or input handling.

Directory-Based Configuration

Instead of a YAML file, you can define your application as a directory tree where each directory contains a content.md file:

my_app/
├── content.md          # Root page (/)
├── docs/
│   ├── content.md      # /docs
│   └── api/
│       └── content.md  # /docs/api
└── about/
    └── content.md      # /about

Each content.md file defines the page content using a simple format:

# Page Title
This is some text content on the page.
Another line of text.
> Button Label
$ Input Placeholder

Format rules:

  • First line starting with # becomes a bold HEADING widget (also used as page title)
  • Regular lines become TEXT widgets
  • Lines starting with > become BUTTON widgets
  • Lines starting with $ become INPUT widgets
  • Buttons can include a navigation target using -> /path syntax (e.g., > Go to Docs -> /docs)
  • Empty lines are skipped
  • Subdirectories automatically become child navigation nodes
  • Directories without content.md get a blank page with a warning

Auto-resolving navigation works identically with directory-based configuration — the route hierarchy is built from the directory structure.

Auto-Resolving Navigation

Navigation items are automatically resolved from the route tree — no need to define nav manually. The server inspects all registered routes and builds a hierarchical navigation structure:

/                  → shows: home, docs
/home              → shows: (children of /home, if any)
/docs              → shows: (end of node) — no children

This means you only need to define your page paths and widgets. Navigation is generated automatically based on the URL structure. Leaf pages (with no child routes) display an (end of node) indicator that does nothing when activated.

Example: 3-Level Hierarchy

pages:
  - path: /              # Root
  - path: /console       # Layer 1
  - path: /console/fe3   # Layer 2 (leaf)
  - path: /switch        # Layer 1
  - path: /switch/fe3h   # Layer 2 (leaf)

At /, the nav shows Console and Switch. At /console, the nav shows Fe3. At /console/fe3, the nav shows (end of node).

Python API

from termstream_py import TermStreamServer, Page, Widget, WidgetType

app = TermStreamServer(host="localhost", port=8765)

@app.route("/home")
def home():
    return Page(
        title="Home",
        widgets=[
            Widget("h1", WidgetType.HEADING, (0, 0), "Welcome", bold=True),
            Widget("p1", WidgetType.TEXT, (2, 0), "Streaming terminal UI."),
        ]
    )

Note: Navigation items are auto-resolved from the route tree, so you no longer need to pass nav=[...] to Page().

PageNode Builder API

The PageNode builder provides a hierarchical, tree-based API for constructing complex applications. Pages are organized as a tree of nodes where each node can have child sub-pages:

from termstream_py import (
    TermStreamServer, Page, Widget, WidgetType,
    PageNode, create_page_node, create_server_from_nodes,
    visualise, to_yaml, from_yaml, to_directory, from_directory
)

# Build a hierarchical page tree
home = PageNode("/home", "Home") \
    .with_widget(Widget("h1", WidgetType.HEADING, (0, 0), "Welcome", bold=True))

docs = PageNode("/docs", "Docs") \
    .with_widget(Widget("h1", WidgetType.HEADING, (0, 0), "Documentation", bold=True))

# Add children
home.add_child(docs)

# Convert to server
server = create_server_from_nodes(home)

# Visualize the route tree
print(visualise(home))

# Export to YAML
to_yaml(home, "config.yaml")

# Export to directory structure with content.md files
to_directory(home, "./my_app")

# Load from YAML or directory
root = from_yaml("config.yaml")
root = from_directory("./my_app")

Available functions:

  • PageNode(path, title) — Create a node at the given path
  • create_page_node(path, title) — Factory function for PageNode
  • create_server_from_nodes(root) — Convert a PageNode tree to a TermStreamServer
  • visualise(node) — Print the route tree structure
  • to_yaml(node, path) — Export the tree to a YAML file
  • from_yaml(path) — Load a PageNode tree from YAML
  • to_directory(node, dir_path) — Export the tree to a directory with content.md files
  • from_directory(dir_path) — Load a PageNode tree from a directory structure

MCP Integration

from termstream_py import TermStreamServer, init_mcp_server

app = TermStreamServer(host="localhost", port=8765)

# Initialize MCP server for AI agent integration
mcp_server = init_mcp_server(app)
mcp_server.run(transport="stdio")

Browser Controls

Key Action
→ / ← Switch between Nav and Content panes
↑↓ Focus nav item or content widget
Enter Activate focused element
/ Start search mode (nav pane)
Space / PageDown Scroll down
b / PageUp Scroll up
1-9 Navigate to specific nav item
ESC / Backspace Go back
q Quit

Features

  • WebSocket Server: Stream UI frames to terminal clients
  • Curses Browser: Terminal-based browser with navigation support
  • Auto-Resolving Nav: Navigation generated automatically from route hierarchy
  • Directory-Based Config: Build routes from a directory tree with content.md files
  • MCP Integration: AI agent support via Model Context Protocol
  • YAML Configuration: Define pages and widgets in YAML files
  • Route-based Pages: Define pages using decorators
  • Interactive Widgets: Text, headings, buttons, and input fields

HTTPS / WSS Support

TermStream supports encrypted WebSocket connections (WSS) for secure communication.

Installation

HTTPS requires the cryptography package. Install it with the optional ssl extra:

pip install termstream-py[ssl]

CLI Usage

Auto-generate self-signed certificate (development):

termstream server -c config.yaml --ssl

Use your own certificate:

termstream server -c config.yaml --ssl-cert /path/to/cert.pem --ssl-key /path/to/key.pem

YAML Configuration

host: localhost
port: 8765
ssl: true
ssl_cert: /path/to/cert.pem   # optional; auto-generated if omitted
ssl_key: /path/to/key.pem     # optional; auto-generated if omitted

Browser Client

Connect to WSS servers by using the wss:// scheme:

termstream browser -u wss://localhost:8765

Note: Self-signed certificates are for development only. For production, use certificates from a trusted CA (e.g., Let's Encrypt).

Security Notes

  • HTTPS/WSS: Use --ssl or configure ssl: true in YAML to enable encrypted connections.
  • Origin filtering: Use --allowed-origins to restrict which origins can connect to the WebSocket server.
  • Dynamic app loading: The --app flag executes arbitrary Python code. It can be disabled by setting TERMSTREAM_DISABLE_APP=1. Prefer --config (YAML) or --directory for untrusted content.

Disclosure

Other Versions

TermStream is available in multiple languages. Choose the version that best fits your ecosystem:

Version Package Installation
Python termstream-py pip install termstream-py
Rust termstream cargo install termstream
Node.js termstream npm install termstream

Rust Version

The Rust version (termstream-rust) provides a native binary with high-performance WebSocket server and crossterm-based TUI client. Install via Cargo:

# Install from crates.io
cargo install termstream

# Or build from source
cd termstream-rust
cargo build --release

The Rust version supports the same CLI commands (server, browser, mcp) and YAML configuration format as the Python version.

Node.js Version

The Node.js version (termstream-npm) wraps the Rust binary via npm, providing a drop-in solution for JavaScript/TypeScript projects. Install via npm:

npm install termstream

The npm version automatically compiles the Rust backend during installation and exposes the same CLI interface.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

termstream_py-0.1.1.tar.gz (37.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

termstream_py-0.1.1-py3-none-any.whl (31.9 kB view details)

Uploaded Python 3

File details

Details for the file termstream_py-0.1.1.tar.gz.

File metadata

  • Download URL: termstream_py-0.1.1.tar.gz
  • Upload date:
  • Size: 37.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.9

File hashes

Hashes for termstream_py-0.1.1.tar.gz
Algorithm Hash digest
SHA256 92a0b6f7063e26e8dac5c832edd129cfd0603432d4b51dccb18f60d2cfc2bd65
MD5 7614fb339293bf288c173b5afb070b35
BLAKE2b-256 35a1be8f0fbbddb55d17c6d164395470f1c81997f0e79aae582d73933451d423

See more details on using hashes here.

File details

Details for the file termstream_py-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: termstream_py-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 31.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.9

File hashes

Hashes for termstream_py-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 d6f77834f141024f2e482718b797f2252a2c0b57ec08ec6c7ec3d1040b8fd449
MD5 fc7dbd9fac8a893b82eed73f9ed6ba01
BLAKE2b-256 43ce10a6fe76823995dcee5ff223e5dba9a355aefccf660f39d746f3e435312c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page