Piou
A CLI tool to build beautiful rich text command-line interfaces with type validation.
Install / Use
/learn @Andarius/PiouREADME
Piou
A CLI tool to build beautiful command-line interfaces with type validation.
Quick Example
from piou import Cli, Option
cli = Cli(description='A CLI tool')
@cli.command(cmd='foo', help='Run foo command')
def foo_main(
bar: int = Option(help='Bar positional argument (required)'),
baz: str = Option('-b', '--baz', help='Baz keyword argument (required)'),
foo: str | None = Option(None, '--foo', help='Foo keyword argument'),
):
"""
A longer description on what the function is doing.
"""
pass
if __name__ == '__main__':
cli.run()
Installation
pip install piou
Or with uv:
uv add piou
Or with conda:
conda install piou -c conda-forge
Raw Formatter
By default, Piou uses Rich for beautiful terminal output. If you prefer plain text output, you can use the raw formatter:
# Force raw output via environment variable
PIOU_FORMATTER=raw python your_cli.py --help
Documentation
Full documentation is available at andarius.github.io/piou.
Features
- FastAPI-like developer experience with type hints
- Custom formatters (Rich-based by default)
- Nested command groups / sub-commands
- Derived options for reusable argument patterns
- Async command support
- Type validation and casting
- Interactive TUI mode with command suggestions and history
- Structured JSON help (
--help-json) for tooling and programmatic CLI discovery
Why Piou?
I could not find a library that provided:
- The same developer experience as FastAPI
- Customization of the interface (to build a CLI similar to Poetry)
- Type validation / casting
Typer is the closest alternative but lacks the possibility to format the output in a custom way using external libraries (like Rich).
Piou provides all these possibilities and lets you define your own Formatter.
Async Commands
Commands can be async functions — piou detects coroutines and runs them automatically, no manual asyncio.run() needed:
from piou import Cli, Option
cli = Cli(description='Async example')
@cli.command(cmd='fetch', help='Fetch data')
async def fetch(url: str = Option(help='URL to fetch')):
import niquests
async with niquests.AsyncSession() as client:
r = await client.get(url)
print(r.status_code)
if __name__ == '__main__':
cli.run()
This works the same way for commands inside command groups.
Interactive TUI Mode
Piou includes an optional interactive TUI (Text User Interface) mode powered by Textual. This provides a rich terminal experience with command suggestions, history, and inline completions.
Installation
pip install piou[tui]
# With auto-reload support for development
pip install piou[tui-reload]
Usage
Enable TUI mode by setting tui=True when creating your CLI:
from piou import Cli, Option
cli = Cli(description='My Interactive CLI', tui=True)
@cli.command(cmd='hello', help='Say hello')
def hello(name: str = Option(..., help='Name to greet')):
print(f'Hello, {name}!')
if __name__ == '__main__':
cli.run()
Or via the --tui flag:
python my_cli.py --tui
Or via the PIOU_TUI=1 environment variable:
PIOU_TUI=1 python my_cli.py
TUI Features
- Command suggestions: Type
/to see available commands with descriptions - Subcommand navigation: Use
:to navigate subcommands (e.g.,/stats:uploads) - Inline completions: See argument placeholders as you type
- Command history: Navigate previous commands with up/down arrows (persisted across sessions)
- Rich output: ANSI colors and formatting preserved in output
- Keyboard shortcuts:
Tab- Confirm selected suggestionUp/Down- Navigate suggestions or historyCtrl+C- Clear input (press twice to exit)Escape- Quit
- Dev mode: Auto-reload commands when source files change (see below)
Dev Mode with Auto-Reload
For faster development iteration, enable dev mode to automatically reload your commands when source files change:
pip install piou[tui-reload]
Then use the --tui-reload flag:
python my_cli.py --tui-reload
Or via environment variable:
PIOU_TUI_DEV=1 python my_cli.py --tui
When enabled, Piou watches your command source files and hot-reloads them on save. You can also toggle reload mode at runtime with the /tui-reload command.
To run custom code after each reload (e.g., refresh cached data), use the @cli.tui_on_reload decorator:
@cli.tui_on_reload
def on_reload():
print('Code reloaded!')
Advanced Example: HTTP Benchmark
The TUI mode supports mounting custom Textual widgets for rich interactive displays. This example benchmarks HTTP libraries with live progress grids:
<img alt="HTTP Benchmark TUI" src="https://github.com/Andarius/piou/raw/master/docs/static/bench_1000.gif" width="700"/>See examples/http_bench_tui.py for the full implementation using TuiContext and custom widgets.
Development
Running Tests
uv run pytest
Generating Documentation
# Build docs
uv run --group docs mkdocs build
# Serve locally
uv run --group docs mkdocs serve
Generating Screenshots and GIFs
Terminal recordings are created with VHS. Install it first:
# Ubuntu/Debian
sudo apt install vhs ttyd
# macOS
brew install vhs
# Or via Go
go install github.com/charmbracelet/vhs@latest
Then generate recordings from tape files:
vhs docs/static/tui-demo.tape
Tape files are located in docs/static/ and define scripted terminal sessions that produce GIFs.
Related Skills
node-connect
351.2kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
claude-opus-4-5-migration
110.6kMigrate prompts and code from Claude Sonnet 4.0, Sonnet 4.5, or Opus 4.1 to Opus 4.5
frontend-design
110.6kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
model-usage
351.2kUse CodexBar CLI local cost usage to summarize per-model usage for Codex or Claude, including the current (most recent) model or a full model breakdown. Trigger when asked for model-level usage/cost data from codexbar, or when you need a scriptable per-model summary from codexbar cost JSON.
