Active development: AOM is under active development. APIs, CLI behavior, configuration formats, session formats, and documentation may change without notice. Test it in a non-production environment before relying on it for critical automation.
AI-assisted development: Parts of the code, tests, documentation, and research were developed with assistance from generative AI tools. Maintainers review and accept changes, but users should independently verify behavior, security, and licensing.
A nom-style live view for ansible-playbook. Replaces ansible's stock
log-spew with a compact, persistent status panel that tells you what's
running right now, what's failed, and what's still ahead — without
losing the per-task log above it.
PLAY [Deploy webservers] (webservers, 3 hosts, 12 tasks)
PLAY [Deploy database] (dbservers, 1 host, 4 tasks)
Tags: deploy, install, restart
TASK [Install nginx] ********************************************
ok: [web1]
changed: [web2]
fatal: [web3]: FAILED! => SSH connection failed
─────────────────────────────────
site.yml │ 2/3 hosts │ 8/16 tasks │ ⚠ 1 │ 0:00:42 ●
host ok changed failed on
web1 5 3 0 (idle)
web2 4 4 0 (idle)
web3 0 0 1 (idle)
FAILED: web3 — Install nginx
Render mode:
- Compact (default) — single status panel pinned to the bottom of
your terminal; ansible's normal log streams above it. No alternate
screen, no full takeover. Works in pipes, CI,
tee, anywhere.
Every run is recorded to ~/.local/state/aom/sessions/<id>/ so
aom inspect can replay it later.
Install the latest release without cloning the repository or installing uv:
python3 -m pip install ansible-aom
# Or: pipx install ansible-aomBefore running a playbook, install Ansible and the JSONL callback collection:
python3 -m pip install ansible-core
ansible-galaxy collection install ansible.posixThe package provides AOM and its bundled callback plugins. It does not bundle
ansible-playbook, Ansible collections, SSH, inventories, roles, or playbook
dependencies. ansible-playbook must be available on PATH.
Linux x86_64 users can download aom-linux-x86_64.tar.gz from the
GitHub Releases page, extract it,
and run aom/aom. The bundle includes AOM's Python runtime and dependencies,
but still requires the external Ansible prerequisites above. It is currently
the only standalone binary target; macOS and Windows binaries are not shipped.
On Nix-supported systems:
nix run github:Xyz00777/aomnix run provides AOM, not Ansible or the ansible.posix collection.
The following commands are for working on the source tree:
uv sync --all-extras
uv run pip install -e .Requirements: Python ≥ 3.14, plus a working ansible-playbook on your
$PATH. AOM never imports ansible-core; it shells out and parses the
JSONL callback. The real-Ansible integration smoke tests pass locally with
ansible-core 2.20.11 and 2.21.5. CI is configured to run them against the
latest patch releases in both the 2.20 and 2.21 minor lines. Other versions
may work, but are not currently covered by that matrix.
After install, sanity check:
aom --version
aom --helpaom site.yml # compact view
aom site.yml -i inv.ini --tags deploy # any ansible-playbook flag works
aom site.yml -vvv # ansible verbosity flows throughAnything after the playbook path is forwarded verbatim to
ansible-playbook. AOM never silently rewrites your arguments.
aom inspect # launch interactive TUI session viewer
aom inspect --text # plain-text summary of latest run
aom inspect --changes # list all tasks that reported changed status
aom inspect --changes --diff # include before/after diffs for changed tasks
aom inspect --warnings # list all warnings & deprecations with file locations
aom inspect --changes --host web1 # filter changes to a specific host
aom inspect --changes --json # JSON output for CI / jq pipelines
aom inspect prune --days 30 # delete sessions older than N daysaom replay <session-id> # replay at original cadence
aom replay <session-id> --speed 10 # 10x faster
aom replay <session-id> --speed 0 # as fast as possible (no sleeps)
aom replay latest # replay the most recent sessionRe-stream a recorded session's events.jsonl through the renderer at
the original pacing, scaled with --speed N. Replay reproduces only
the JSONL stream, not AOM-emitted warnings, the preflight summary, or
password-prompt log lines. Session IDs may be a full UUID, a unique
prefix, or latest.
aom rerun # rerun latest session's failed hosts
aom rerun <session-id> --failed # explicit session, failed hosts only
aom rerun <session-id> --unreachable # failed + unreachable hosts
aom rerun --changes-only -y # rerun changed hosts, skip the promptReads a recorded session, derives a host set from
failed / unreachable / changed events, and re-invokes
ansible-playbook with the original args plus a --limit matching
those hosts. By default aom rerun behaves like --failed; flags
compose by union. A pre-existing --limit in the recorded args is
replaced, not intersected, because a rerun to a subset is rarely what
users want. Always prints the planned command line and a warning that
re-running may execute non-idempotent tasks, then prompts for
confirmation unless -y is set.
aom --install-completion bash >> ~/.bashrc
aom --install-completion zsh >> ~/.zshrc
aom --install-completion fish > ~/.config/fish/completions/aom.fishPrints the rc-file snippet for the chosen shell to stdout, then exits.
Powered by argcomplete; tab-completes subcommands (inspect,
replay, rerun), flags, and recorded session IDs from
~/.local/state/aom/sessions/.
| Flag | Effect |
|---|---|
--verbose |
Print AOM diagnostics (resolved ansible-playbook path, env, terminal size), enable DEBUG logging, enable pexpect/event traces, and print post-run [aom-debug] summary. Equivalent to AOM_DEBUG=1. |
--format {compact,json} |
compact (default) streams the nom-style live view. json is silent during the run and emits a single JSON object on stdout at completion, designed for CI and jq pipelines. |
--hide-state <state> |
Suppress per-host lines of the given state from the live compact log. Accepts comma-separated values (e.g. --hide-state ok,skipped) or repeated invocations. Choices: ok, changed, failed, skipped, unreachable. The status panel, recording, and aom inspect are unaffected. |
--no-record |
Disable session recording for this run. No directory is written under ~/.local/state/aom/sessions/. Debug output from --verbose is unaffected. |
--install-completion {bash,zsh,fish} |
Print the rc-file snippet for the given shell to stdout, then exit. Pipe to your rc file (e.g. aom --install-completion bash >> ~/.bashrc). Powered by argcomplete; tab-completes subcommands, flags, and recorded session IDs. |
--version |
Print version and exit. |
--help |
Show built-in help. |
-v is reserved for ansible-playbook. aom site.yml -v raises
ansible verbosity, not AOM verbosity. The AOM debug flag is
--verbose (long form only).
┌──────────────────────┐
ansible-playbook ─────►│ PTY (pexpect) │
+ ansible.posix.jsonl│ │
└──────────┬───────────┘
▼
┌──────────────────────┐
│ PtyStreamParser │ 3-phase:
│ • password prompts │ PRE_RUN_PROMPTS
│ • JSONL events │ EXECUTION
│ • PLAY RECAP │ POST_RUN_RECAP
└──────────┬───────────┘
▼
┌──────────────────────┐
│ RunState │ pure-Python state
│ • plays / tasks │ no I/O, no Textual
│ • dynamic include │ include_tasks grafted
│ expansion │ under parent at runtime
└──────────┬───────────┘
▼
┌─────────────────────┐
│ CompactRenderer │
│ Rich Live panel │
└─────────────────────┘
│
▼
~/.local/state/aom/sessions/<uuidv7>/
├── events.jsonl ← immutable events, including aom_stderr_line
├── meta.json ← playbook, start/end, status
├── diagnostics.json ← derived lifecycle and renderer diagnostics
└── index.db ← optional, disposable inspect index
events.jsonl is the session source of truth. Stderr is stored there as
synthetic aom_stderr_line events; diagnostics.json and index.db are
derived artifacts.
Before the run starts, AOM also fires --list-tasks and --list-hosts
in parallel so the panel shows host count, task count, and the
expected play layout from the very first frame.
| Icon | Meaning | ASCII fallback |
|---|---|---|
● |
ok | * |
◆ |
changed | + |
✖ |
failed | X |
⊝ |
unreachable | ! |
○ |
skipped | o |
◐ |
running | @ |
□ |
pending | . |
ASCII fallback kicks in automatically when LANG / LC_* aren't UTF-8.
| What | Where |
|---|---|
| Session recordings | ~/.local/state/aom/sessions/<uuidv7>/ |
| User config | ~/.config/aom/aom_config.yaml (optional) |
| Inventory auto-detect | ./inventory.ini, ./inventory.yml, ./hosts, … |
If a conventional inventory file sits in your current directory and
you didn't pass -i, AOM prepends -i <file> for you. Pass any
inventory flag explicitly and AOM keeps its hands off.
Configuration layers are merged in this order: built-in defaults,
/etc/aom/aom_config.yaml, ~/.config/aom/aom_config.yaml,
./.aom_config.yaml, an explicit AOM_CONFIG or --config file, then
supported CLI values. The older ~/.config/aom/config.yaml is accepted only
as legacy migration input and is preserved as config.yaml.migrated.
Verbose and setup capture bloat sessions in proportion to the host
count. A 200-host run with --capture-verbose --capture-setup lands
around ~50MB of events.jsonl. At that rate, 100 sessions stack up
to roughly 5GB under ~/.local/state/aom/sessions/.
Reclaim space by pruning old runs:
aom inspect prune --days 30 # delete sessions older than 30 daysThe prune command is safe to run on a schedule; it only removes session directories whose recorded start time is older than the threshold.
src/ansible_aom/— source. SeeARCHITECTURE.mdfor the module map.SPECIFICATION.md— authoritative behaviour spec.TEST_SPECIFICATION.md— every test case, indexed by spec section.AGENTS.md— contributor guide: setup, commands, style, TDD rules.
uv sync --all-extras
uv run pip install -e .
uv run pytest tests/ -q
uv run ruff format && uv run ruff check --fix
uv run mypy src/ansible_aomTDD-first; tests for core/ must pass without ansible-core. See
AGENTS.md for the full rules.
- Pull requests that change application code (
src/,packaging/) or dependencies (pyproject.toml,uv.lock,flake.nix,flake.lock) must bumpproject.versioninpyproject.tomlso it is higher than themainbranch. CI enforces this viascripts/check_version_bump.py. - Documentation-only and test-only changes do not require a version bump.
- Merging to
mainautomatically triggers package creation (Python wheels, sdist, and Linux standalone bundle), creates a GitHub Release with tagv<version>, and publishes to PyPI when application or dependency changes are present.
GPL-3.0-or-later. See LICENSE. AOM is provided as-is, with no warranty.
The repository's reasoning for the GPL treatment of the bundled
callback is documented in ARCHITECTURE.md section 10.1.