A beautiful terminal UI for running Ansible playbooks — without memorizing a single flag.
curl -sL https://raw.githubusercontent.com/congzhangzh/ansible-tui/main/install.sh | bash
./ansible-tuiNo Node.js. No Python runtime. No background services. Just one binary.
deno run --allow-read --allow-run --allow-write --allow-env --import-map https://raw.githubusercontent.com/congzhangzh/ansible-tui/main/deno.json https://raw.githubusercontent.com/congzhangzh/ansible-tui/main/app.tsx
deno run -R --allow-read --allow-run --allow-write --allow-env --import-map https://raw.githubusercontent.com/congzhangzh/ansible-tui/main/deno.json https://raw.githubusercontent.com/congzhangzh/ansible-tui/main/app.tsx
Running ansible-playbook precisely is harder than it looks:
# Which tags were in that play again?
ansible-playbook -i inventory.yml site.yml \
--limit "web01,web02" \
--tags "deploy,restart" \
--check --diffYou end up grepping YAML files, copy-pasting hostnames, and manually composing
--tags lists — every time.
Heavy orchestrators like AWX or Semaphore solve this at the cost of a Kubernetes cluster, a PostgreSQL database, and a background daemon.
Ansible TUI is the middle ground: a zero-dependency, single-file executable that gives you a visual interactive selector right in your terminal.
┌──────────────────────────────────────────────────────────────────────────┐
│ 🚀 Ansible TUI Runner ✓ Last run succeeded │
│ │
│ ┌──── Hosts (2/3) ─────┐ ┌──── Playbook (4/7 tasks) ─────────────────┐ │
│ │ ❯ [x] webservers(2/2)│ │ ❯ ▼ [x] Deploy Application │ │
│ │ [x] web01 │ │ ▼ [~] Install packages [apt] │ │
│ │ [x] web02 │ │ ❯ [x] Install nginx │ │
│ │ [ ] dbservers (0/1)│ │ [x] Install certbot │ │
│ │ [ ] db01 │ │ ▼ [x] Deploy code [deploy] │ │
│ └──────────────────────┘ │ [x] Sync files │ │
│ │ [x] Restart services │ │
│ ┌─ Command Preview ──────────────────────────────────────────────────┐ │
│ │ ansible-playbook -i inventory.yml playbook.yml --limit web01,web02 │ │
│ │ --tags apt,deploy --check ON --diff off │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ [Tab] Switch [Space] Toggle [a] All Hosts [e] Expand All [r] Run │
└──────────────────────────────────────────────────────────────────────────┘
| Ansible TUI | AWX / Semaphore | ansible-playbook CLI |
|
|---|---|---|---|
| Setup | Single binary | K8s + DB required | ✓ Already there |
| Visual host/task picker | ✓ | ✓ | ✗ |
| Live output streaming | ✓ | ✓ | ✓ |
| State saved across runs | ✓ | ✓ | ✗ |
| Works offline / in SSH | ✓ | ✗ | ✓ |
| Zero dependencies | ✓ | ✗ | ✓ |
| Tag-aware selection | ✓ | Partial | Manual |
# Auto-discover inventory.yml and playbook.yml from CWD or parent dir
ansible-tui
# Explicit paths
ansible-tui /path/to/inventory.yml /path/to/playbook.yml
# Clean start — ignore saved state
ansible-tui --clean
ansible-tui -C
# Show version
ansible-tui --versionAuto-discovery checks both . and .. for:
- Inventory:
inventory.yml,inventory.yaml,hosts.yml,hosts.yaml,hosts - Playbook:
playbook.yml,playbook.yaml,site.yml,site.yaml
# One line, run from anywhere (no clone)
deno run --allow-read --allow-run --allow-write --allow-env --import-map https://raw.githubusercontent.com/congzhangzh/ansible-tui/main/deno.json https://raw.githubusercontent.com/congzhangzh/ansible-tui/main/app.tsxFrom a local clone (uses local deno.json):
deno run --allow-read --allow-run --allow-write --allow-env app.tsx| Key | Action |
|---|---|
Tab |
Switch between Hosts / Playbook panel |
↑ ↓ |
Move cursor |
PgUp PgDn |
Page up / down |
Space |
Toggle checkbox (play/block toggles all children) |
→ / Enter |
Expand play or block |
← |
Collapse (on task/block: jump to parent) |
a |
Select / deselect all hosts |
e |
Expand all / collapse all plays & blocks |
| Key | Action |
|---|---|
c |
Toggle --check (dry-run) |
d |
Toggle --diff (show changes) |
r |
Run ansible-playbook |
s |
Toggle smart tag filtering (smartTags on/off) |
p |
Print command and exit (for piping/scripting) |
q |
Quit |
| Key | Action |
|---|---|
↑ ↓ / PgUp PgDn |
Scroll |
Enter |
Back to selection |
q |
Quit |
- Parse — Reads
inventory.ymlfor host groups andplaybook.ymlfor plays/tasks (recursively expandsblock:structures, respects inherited tags) - Select — Interactive split-pane TUI: left pane for host targeting
(
--limit), right pane for task/tag selection (--tags) - Run — Spawns
ansible-playbookas a child process; output streams live inside the TUI with ANSI color support - Iterate — Press
Enterafter a run to return to selection with all choices intact. Tweak and re-run instantly.
- Items tagged
neverare shown with a(never)indicator and their tag is never added to--tagsautomatically - If a play itself has
[never, some-tag], selecting any task in that play will includesome-tagin--tags - Tags are rendered in cyan for quick identification
- By default, smart tag filtering is enabled:
- The playbook is expected to have child blocks/tasks inherit parent tags.
- When you select a task, only tags that are more specific than all ancestors
are added to
--tags. If a task has no more specific tags than its parents, its full tag set is used and this likely indicates the playbook could use more granular tags. - You can disable this behavior per-project by setting
"smartTags": falsein.ansible-tui.jsonnext to your inventory file.
Selections (hosts, tasks, expanded plays, --check/--diff flags) are saved to
.ansible-tui-state.json next to your inventory. Restored automatically on next
launch. Use --clean to start fresh.
Deno (recommended):
git clone https://github.com/congzhangzh/ansible-tui
cd ansible-tui
deno compile --allow-read --allow-run --allow-write --allow-env -o ansible-tui app.tsxNode.js / tsx:
npm install
npm start # runs via tsxIssues and PRs welcome. This is intentionally a single-file app — all logic
lives in app.tsx to keep it easy to audit, fork, and run without a build step.