Construct rich terminal interfaces using Textual for multi-pane dashboards with CSS styling and Python Prompt Toolkit for interactive line editing with completions. Covers widget composition, key bindings, TUI testing strategies, and WSL2 layout quirks. Engage when building IDE-style interfaces, REPL shells, or dashboard applications.
View on GitHubAeyeOps/aeo-skill-marketplace
aeo-python
aeo-python/skills/agent-tui-expert/SKILL.md
January 25, 2026
Select agents to install to:
npx add-skill https://github.com/AeyeOps/aeo-skill-marketplace/blob/main/aeo-python/skills/agent-tui-expert/SKILL.md -a claude-code --skill agent-tui-expertInstallation paths:
.claude/skills/agent-tui-expert/# Agent TUI Expert
Expert guidance for building professional Terminal User Interfaces in Python.
## CRITICAL: WSL2 Users Read First
**If developing in WSL2, read [references/wsl2-platform-issues.md](references/wsl2-platform-issues.md) BEFORE starting.**
WSL2 has a critical bug (Microsoft/WSL#1001) where horizontal terminal resize does not propagate SIGWINCH signals. This breaks Textual resize handling and requires a specific workaround using `ioctl TIOCGWINSZ` polling. The reference file contains battle-tested solutions that took 12+ hours to discover.
## When to Use This Skill
- Building full-screen TUI applications with multiple panes
- Creating IDE-like layouts (file tree, editor, terminal)
- Adding command input with history and auto-completion
- Building interactive REPLs or shell interfaces
- Implementing keyboard navigation and shortcuts
- Testing TUI applications with automated interactions
## Decision Tree
```
Need multi-pane, full-screen UI?
├─ YES → Use Textual
│ (widgets, containers, CSS styling, message passing)
│
Need advanced line editing, history, completions?
├─ YES → Use Prompt Toolkit
│ (PromptSession, FileHistory, Completers, key bindings)
│
Need both?
└─ Use Textual with Suggester API for input completion
Or embed prompt_toolkit patterns in custom widgets
```
## Quick Reference
### Textual Minimal App
```python
from textual.app import App, ComposeResult
from textual.widgets import Static, Header, Footer
class MyApp(App):
CSS = """
Screen { align: center middle; }
#content { border: solid $primary; padding: 1 2; }
"""
BINDINGS = [("q", "quit", "Quit"), ("d", "toggle_dark", "Dark Mode")]
def compose(self) -> ComposeResult:
yield Header()
yield Static("Hello, Textual!", id="content")
yield Footer()
def action_toggle_dark(self) -> None:
self.dark = not self.dark
if __name__ == "__main__":
MyApp().run()
```
### Prompt Toolkit Minimal Prompt
```python
fro