urwid
Console user interface library for Python — provides full-featured TUI (terminal UI) widget toolkit for building interactive terminal applications. urwid features: widget library (Text, Button, Edit, CheckBox, RadioButton, Listbox, Columns, Pile, Frame), Canvas abstraction for terminal rendering, MainLoop event handling, signal/slot system for widget events, palette system for 16/256/true-color terminal colors, Unicode and wide character support, mouse support, raw and cbreak modes, screen adapters (raw, curses, web), flow and box layout widgets, and ScrollBar, GridFlow, Padding widgets. More powerful than curses, simpler than Qt TUI frameworks.
Score Breakdown
⚙ Agent Friendliness
🔒 Security
Terminal UI library with no network calls. No security concerns. urwid.web_display provides browser-based terminal emulation — do not expose publicly without authentication. Terminal input should be validated before processing commands.
⚡ Reliability
Best When
Interactive terminal applications requiring widget-based UI — urwid provides the most complete Python TUI widget library for applications like file managers, config tools, monitoring dashboards.
Avoid When
Simple output/formatting (use rich), web UIs, static scripts, or when blessed/curses is sufficient for basic terminal control.
Use Cases
- • Agent interactive menu — import urwid; choices = ['Option A', 'Option B', 'Exit']; body = [urwid.Text('Choose:')]; body += [urwid.Button(c, on_press=handler) for c in choices]; listbox = urwid.ListBox(urwid.SimpleFocusListWalker(body)); urwid.MainLoop(listbox, palette).run() — TUI menu; agent builds interactive menu for terminal configuration tools
- • Agent form input — edit = urwid.Edit('Name: '); pile = urwid.Pile([edit, urwid.Button('Submit')]); urwid.connect_signal(button, 'click', submit_handler) — form widgets; agent collects user input through terminal forms; Edit captures text; CheckBox/RadioButton for selections; signal system triggers callbacks
- • Agent progress dashboard — txt = urwid.Text('Status: idle'); progress = urwid.ProgressBar('pb.normal', 'pb.complete', 0, 100); pile = urwid.Pile([txt, progress]); loop = urwid.MainLoop(pile, palette); loop.set_alarm_in(0.1, update) — live TUI dashboard; agent displays real-time status in terminal; set_alarm_in for periodic updates without blocking
- • Agent log viewer — walker = urwid.SimpleListWalker([]); listbox = urwid.ListBox(walker); frame = urwid.Frame(listbox, header=urwid.Text('Logs')); walker.append(urwid.Text(new_log_line)); walker.set_focus(len(walker)-1) — scrollable log viewer; agent terminal application shows streaming log output with scroll
- • Agent multi-pane TUI — left = urwid.LineBox(urwid.ListBox(items)); right = urwid.LineBox(urwid.Text('Details')); columns = urwid.Columns([left, right]); frame = urwid.Frame(columns, header=urwid.Text('App'), footer=urwid.Text('q=quit')) — split-pane layout; agent builds full-screen terminal UI with navigation panels
Not For
- • Simple output formatting — urwid is full TUI framework; for simple colored output use rich or termcolor
- • Web or GUI applications — urwid targets terminal; for web use Flask/FastAPI; for GUI use tkinter/PyQt
- • Non-interactive scripts — urwid's value is in interaction; for static terminal output use print/rich
Interface
Authentication
No auth — local terminal UI library.
Pricing
urwid is LGPL 2.1 licensed. Free for all use; LGPL applies if modifying urwid itself.
Agent Metadata
Known Gotchas
- ⚠ Exit MainLoop by raising urwid.ExitMainLoop — to stop the event loop: raise urwid.ExitMainLoop() inside any callback; do NOT call sys.exit() or loop.stop() — these leave terminal in bad state; urwid.ExitMainLoop is the clean exit; agent code exit handlers must use raise urwid.ExitMainLoop() in callback functions connected to quit buttons
- ⚠ Box widgets require size constraints, flow widgets do not — urwid.Text is a flow widget (determines own height); urwid.ListBox is a box widget (requires explicit size or maxrow); Pile of flow widgets works; Pile containing box widget requires weight tuple: urwid.Pile([('weight', 1, listbox)]); agent code WidgetError usually means mixing box/flow incorrectly
- ⚠ Palette must be defined before MainLoop — colors are defined as palette list: [('name', 'dark red', 'white'), ...]; pass to MainLoop: urwid.MainLoop(widget, palette=palette); using undefined palette name falls back to defaults silently; agent code applying colors: urwid.Text(('error', 'message')) where 'error' is palette entry name
- ⚠ SimpleListWalker vs SimpleFocusListWalker — SimpleListWalker for non-focusable lists (text items); SimpleFocusListWalker required for focusable widgets (buttons, edits) inside ListBox; using wrong walker causes focus errors; agent code with interactive list items: urwid.ListBox(urwid.SimpleFocusListWalker(buttons))
- ⚠ MainLoop.draw_screen() needed after external updates — when updating widget state outside urwid callbacks (e.g., from a thread): loop.draw_screen() must be called to refresh; or use loop.set_alarm_in(0, callback) to trigger redraw from main thread; direct widget updates from threads without draw_screen cause visual artifacts
- ⚠ urwid blocks the main thread — MainLoop.run() is blocking; agent code needing background work must use asyncio loop adapter or threads with thread-safe callbacks; urwid.AsyncioEventLoop for asyncio integration; background threads must communicate via loop.set_alarm_in(0, callback) for thread-safe UI updates; never update widgets directly from background threads
Full Evaluation Report
Comprehensive deep-dive: security analysis, reliability audit, agent experience review, cost modeling, competitive positioning, and improvement roadmap for urwid.
AI-powered analysis · PDF + markdown · Delivered within 30 minutes
Package Brief
Quick verdict, integration guide, cost projections, gotchas with workarounds, and alternatives comparison.
Delivered within 10 minutes
Score Monitoring
Get alerted when this package's AF, security, or reliability scores change significantly. Stay ahead of regressions.
Continuous monitoring
Scores are editorial opinions as of 2026-03-06.