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 npm install termstream-npm

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-npm

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.2.tar.gz (37.5 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.2-py3-none-any.whl (31.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: termstream_py-0.1.2.tar.gz
  • Upload date:
  • Size: 37.5 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.2.tar.gz
Algorithm Hash digest
SHA256 f813dea2d2168ecd57eda3310743a7ccaaf055ca8d400b4c3970d69fbe08e55b
MD5 0696f16e4cdd33c283f2b8e06a1a47d7
BLAKE2b-256 d0bbbbcb5c9426d4c5013f648f408ae5c9d8c09a9cd6b2e5f4e4994f61cec81a

See more details on using hashes here.

File details

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

File metadata

  • Download URL: termstream_py-0.1.2-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.2-py3-none-any.whl
Algorithm Hash digest
SHA256 0d59b86716d82595eb10c6de698e3a8e99c996e81f0d62a27d906dabb990fa82
MD5 d2ecca2cf86279f363403655c4f22d00
BLAKE2b-256 59367319f5fcfc405f9c79a49c324195d912fea1aab8c1ffea45b74edeba3d86

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