Use this skill when the task is fundamentally about building or changing a Textual app, not merely printing Rich output or writing a non-interactive CLI.
Start by classifying the app
Pick the closest shape before writing code:
Single-screen shell
One main view with panels, tables, forms, or logs. Prefer containers plus built-in widgets.
Multi-screen workflow
Large context changes, separate flows, or drill-down views. Prefer Screen / ModalScreen.
Multi-mode admin app
Persistent top-level areas such as “dashboard / jobs / settings / logs”. Prefer named MODES, screen stacks, and command palette support.
Data explorer
Records plus details, filters, or side panes. Prefer DataTable, details panel, responsive breakpoints, and keyboard navigation.
Document or filesystem tool
Prefer DirectoryTree, MarkdownViewer, TextArea, Tree, and delivery APIs for export/download.
Chat / streaming / long-running task UI
Prefer a scrollable transcript or log plus @work / workers for background operations.
If the user has not chosen an architecture, choose one and proceed.
Default engineering stance
- Prefer built-in widgets first. Only hand-roll behaviour when a built-in widget clearly does not fit.
- Keep the
App thin. Move screen-specific logic into Screen classes and reusable composite widgets.
- Prefer
.tcss files over inline CSS once styling grows beyond a toy example.
- Use IDs and semantic classes deliberately so styling and Pilot tests stay stable.
- Design for narrow terminals first, then add split panes and breakpoint-driven layouts.
- Leave behind tests whenever behaviour changes.
Choose the right Textual primitive
- Use
Screen when navigation changes the user’s working context.
- Use
ModalScreen for short interruptions: confirmations, pickers, destructive actions.
- Use
ContentSwitcher for wizard steps or one-screen subflows.
- Use named
MODES when the app has durable top-level areas with separate navigation stacks.
- Use command palette providers when there are many actions, bindings, or discoverability matters.
- Use workers for network, subprocess, parsing, search, sleeps, or anything that may block input.
See:
- Architecture decision tree
- Screens, modes, and command palette
Widget-first selection rules
Before inventing custom widgets, check the widget atlas.
Common defaults:
DataTable for record-heavy views
DirectoryTree for filesystem navigation
MarkdownViewer for rich document views
TextArea for editing
TabbedContent for grouped settings or alternate panes
Log / RichLog for live output
SelectionList, OptionList, ListView, Tree, Select, Switch, Input, Button for most interaction needs
Reactivity and workers
Use the playbook in reactivity and workers.
Core rules:
- Put fast derived state in
compute_*, but keep it cheap and side-effect free.
- Use
watch_* for UI reactions, not blocking work.
- Use
var when you want state without automatic refresh machinery.
- Use
set_reactive before mount when initial state changes should not trip watchers early.
- Move blocking work into
@work or run_worker(...).
- Use
exclusive=True for stale-search cancellation and similar “latest request wins” flows.
- For thread workers, update the UI via messages or
call_from_thread.
Browser, dev loop, and delivery
Textual may run in a terminal or be served to a browser. Build with both in mind when relevant.
- Use
textual run --dev while iterating.
- Use
textual console and devtools when behaviour is unclear.
- Use
textual serve when browser parity matters.
- Prefer
deliver_text, deliver_binary, or deliver_screenshot for browser-friendly exports and downloads.
- Use
open_url when handing off to the user’s browser is appropriate.
See:
- Browser and delivery guide
- Packaging and CI
Testing is part of the feature
Default output after any non-trivial change:
- one smoke test with
run_test()
- one behaviour test for the changed flow
- one narrow-terminal or alternate-size test when layout matters
- one snapshot test when the view structure matters visually
See testing matrix.
When working on an existing project
Start with the scripts, then refine by hand:
python scripts/inspect_textual_project.py <project>
python scripts/audit_textual_project.py <project>
- Generate scaffolds or tests only after you understand the existing structure.
Use the audit to catch:
- oversized
App classes
- blocking handlers
- missing breakpoints
- missed built-in widget opportunities
- missing command palette or delivery APIs
- missing Pilot tests
Bundled scripts
scripts/scaffold_textual_app.py
Generate starter apps, TCSS, tests, optional pyproject.toml, and CI workflow.
scripts/inspect_textual_project.py
Inventory app classes, screens, widgets, bindings, IDs, workers, and styling.
scripts/audit_textual_project.py
Heuristic architecture/performance/test audit for an existing Textual project.
scripts/generate_pilot_tests.py
Emit starter smoke and behaviour tests for an existing app.
scripts/dump_dom_and_bindings.py
If Textual is installed, launch an app under run_test() and dump DOM and active bindings.
scripts/emit_textual_pyproject.py
Generate a packageable Hatch-based pyproject.toml.
scripts/emit_github_actions_ci.py
Generate a GitHub Actions workflow for Textual tests.
scripts/build_upstream_pattern_atlas.py
Summarise a local Textual repo snapshot into references/repo-map.md and references/upstream-pattern-atlas.md.
scripts/self_check.py
Compile scripts and scaffold all bundled templates as a package validation step.
Bundled starter templates
Available scaffolds:
dashboard
form
chat
data-explorer
file-browser
settings
wizard
log-monitor
editor
admin-modes
download-demo
List them with:
python scripts/scaffold_textual_app.py --list-templates
Generate one with:
python scripts/scaffold_textual_app.py \
--template data-explorer \
--module my_app \
--class-name MyApp \
--app-title "My App" \
--output-dir .
Output checklist
Before you finish, aim to leave behind:
- a clear app structure
- stable IDs/classes for styling and tests
- TCSS separated from Python unless the app is tiny
- background work off the main event path
- keyboard-discoverable actions
- responsive layout decisions
- at least a smoke test and one behaviour test
- notes on how to run the app in dev mode
Read next as needed
- Architecture decision tree
- Widget selection atlas
- Reactivity and workers
- Screens, modes, and command palette
- Browser and delivery
- Testing matrix
- Anti-patterns
- Packaging and CI
- Repository map
- Upstream pattern atlas
1---2name: textual-tui3description: Build, refactor, debug, test, and package Python terminal user interfaces with Textual. Use when the user wants a TUI, terminal dashboard, admin console, multi-screen workflow, keyboard-first tool, data explorer, file browser, markdown or log viewer, editor, command palette, browser-served console app, or a migration from curses/Rich-only UI to Textual—even if they never say “Textual”. Covers TCSS and themes, built-in widgets, screens and modes, reactive state, workers, browser delivery APIs, and pytest Pilot or snapshot testing.4license: Proprietary5---6
7Use this skill when the task is fundamentally about **building or changing a Textual app**, not merely printing Rich output or writing a non-interactive CLI.
8
9## Start by classifying the app
10
11Pick the closest shape before writing code:
12
131. **Single-screen shell**
14 One main view with panels, tables, forms, or logs. Prefer containers plus built-in widgets.
15
162. **Multi-screen workflow**
17 Large context changes, separate flows, or drill-down views. Prefer `Screen` / `ModalScreen`.
18
193. **Multi-mode admin app**
20 Persistent top-level areas such as “dashboard / jobs / settings / logs”. Prefer named `MODES`, screen stacks, and command palette support.
21
224. **Data explorer**
23 Records plus details, filters, or side panes. Prefer `DataTable`, details panel, responsive breakpoints, and keyboard navigation.
24
255. **Document or filesystem tool**
26 Prefer `DirectoryTree`, `MarkdownViewer`, `TextArea`, `Tree`, and delivery APIs for export/download.
27
286. **Chat / streaming / long-running task UI**
29 Prefer a scrollable transcript or log plus `@work` / workers for background operations.
30
31If the user has not chosen an architecture, choose one and proceed.
32
33## Default engineering stance
34
35- Prefer **built-in widgets first**. Only hand-roll behaviour when a built-in widget clearly does not fit.
36- Keep the **`App` thin**. Move screen-specific logic into `Screen` classes and reusable composite widgets.
37- Prefer **`.tcss` files** over inline `CSS` once styling grows beyond a toy example.
38- Use **IDs and semantic classes** deliberately so styling and Pilot tests stay stable.
39- Design for **narrow terminals first**, then add split panes and breakpoint-driven layouts.
40- Leave behind **tests** whenever behaviour changes.
41
42## Choose the right Textual primitive
43
44- Use **`Screen`** when navigation changes the user’s working context.
45- Use **`ModalScreen`** for short interruptions: confirmations, pickers, destructive actions.
46- Use **`ContentSwitcher`** for wizard steps or one-screen subflows.
47- Use **named `MODES`** when the app has durable top-level areas with separate navigation stacks.
48- Use **command palette providers** when there are many actions, bindings, or discoverability matters.
49- Use **workers** for network, subprocess, parsing, search, sleeps, or anything that may block input.
50
51See:
52- [Architecture decision tree](references/architecture-decision-tree.md)
53- [Screens, modes, and command palette](references/screens-modes-command-palette.md)
54
55## Widget-first selection rules
56
57Before inventing custom widgets, check [the widget atlas](references/widget-selection-atlas.md).
58
59Common defaults:
60- `DataTable` for record-heavy views
61- `DirectoryTree` for filesystem navigation
62- `MarkdownViewer` for rich document views
63- `TextArea` for editing
64- `TabbedContent` for grouped settings or alternate panes
65- `Log` / `RichLog` for live output
66- `SelectionList`, `OptionList`, `ListView`, `Tree`, `Select`, `Switch`, `Input`, `Button` for most interaction needs
67
68## Reactivity and workers
69
70Use the playbook in [reactivity and workers](references/reactivity-and-workers.md).
71
72Core rules:
73- Put fast derived state in `compute_*`, but keep it cheap and side-effect free.
74- Use `watch_*` for UI reactions, not blocking work.
75- Use `var` when you want state without automatic refresh machinery.
76- Use `set_reactive` before mount when initial state changes should not trip watchers early.
77- Move blocking work into `@work` or `run_worker(...)`.
78- Use `exclusive=True` for stale-search cancellation and similar “latest request wins” flows.
79- For thread workers, update the UI via messages or `call_from_thread`.
80
81## Browser, dev loop, and delivery
82
83Textual may run in a terminal or be served to a browser. Build with both in mind when relevant.
84
85- Use `textual run --dev` while iterating.
86- Use `textual console` and devtools when behaviour is unclear.
87- Use `textual serve` when browser parity matters.
88- Prefer `deliver_text`, `deliver_binary`, or `deliver_screenshot` for browser-friendly exports and downloads.
89- Use `open_url` when handing off to the user’s browser is appropriate.
90
91See:
92- [Browser and delivery guide](references/browser-and-delivery.md)
93- [Packaging and CI](references/packaging-and-ci.md)
94
95## Testing is part of the feature
96
97Default output after any non-trivial change:
98
991. one smoke test with `run_test()`
1002. one behaviour test for the changed flow
1013. one narrow-terminal or alternate-size test when layout matters
1024. one snapshot test when the view structure matters visually
103
104See [testing matrix](references/testing-matrix.md).
105
106## When working on an existing project
107
108Start with the scripts, then refine by hand:
109
1101. `python scripts/inspect_textual_project.py <project>`
1112. `python scripts/audit_textual_project.py <project>`
1123. Generate scaffolds or tests only after you understand the existing structure.
113
114Use the audit to catch:
115- oversized `App` classes
116- blocking handlers
117- missing breakpoints
118- missed built-in widget opportunities
119- missing command palette or delivery APIs
120- missing Pilot tests
121
122## Bundled scripts
123
124- `scripts/scaffold_textual_app.py`
125 Generate starter apps, TCSS, tests, optional `pyproject.toml`, and CI workflow.
126
127- `scripts/inspect_textual_project.py`
128 Inventory app classes, screens, widgets, bindings, IDs, workers, and styling.
129
130- `scripts/audit_textual_project.py`
131 Heuristic architecture/performance/test audit for an existing Textual project.
132
133- `scripts/generate_pilot_tests.py`
134 Emit starter smoke and behaviour tests for an existing app.
135
136- `scripts/dump_dom_and_bindings.py`
137 If Textual is installed, launch an app under `run_test()` and dump DOM and active bindings.
138
139- `scripts/emit_textual_pyproject.py`
140 Generate a packageable Hatch-based `pyproject.toml`.
141
142- `scripts/emit_github_actions_ci.py`
143 Generate a GitHub Actions workflow for Textual tests.
144
145- `scripts/build_upstream_pattern_atlas.py`
146 Summarise a local Textual repo snapshot into `references/repo-map.md` and `references/upstream-pattern-atlas.md`.
147
148- `scripts/self_check.py`
149 Compile scripts and scaffold all bundled templates as a package validation step.
150
151## Bundled starter templates
152
153Available scaffolds:
154- `dashboard`
155- `form`
156- `chat`
157- `data-explorer`
158- `file-browser`
159- `settings`
160- `wizard`
161- `log-monitor`
162- `editor`
163- `admin-modes`
164- `download-demo`
165
166List them with:
167
168```bash
169python scripts/scaffold_textual_app.py --list-templates
170```
171
172Generate one with:
173
174```bash
175python scripts/scaffold_textual_app.py \
176 --template data-explorer \
177 --module my_app \
178 --class-name MyApp \
179 --app-title "My App" \
180 --output-dir .
181```
182
183## Output checklist
184
185Before you finish, aim to leave behind:
186
187- a clear app structure
188- stable IDs/classes for styling and tests
189- TCSS separated from Python unless the app is tiny
190- background work off the main event path
191- keyboard-discoverable actions
192- responsive layout decisions
193- at least a smoke test and one behaviour test
194- notes on how to run the app in dev mode
195
196## Read next as needed
197
198- [Architecture decision tree](references/architecture-decision-tree.md)
199- [Widget selection atlas](references/widget-selection-atlas.md)
200- [Reactivity and workers](references/reactivity-and-workers.md)
201- [Screens, modes, and command palette](references/screens-modes-command-palette.md)
202- [Browser and delivery](references/browser-and-delivery.md)
203- [Testing matrix](references/testing-matrix.md)
204- [Anti-patterns](references/anti-patterns.md)
205- [Packaging and CI](references/packaging-and-ci.md)
206- [Repository map](references/repo-map.md)
207- [Upstream pattern atlas](references/upstream-pattern-atlas.md)