Skip to main content

untaped-ansible

Install it as part of untaped: uv tool install 'untaped[ansible]' or pip install 'untaped[ansible]'. To add it to an existing install, see Getting started.

untaped ansible answers questions about how Ansible roles and projects depend on each other through their requirements files:

Command Question Output
deps ROLE What does ROLE depend on (downstream)? one ansible.dependency row per repo reached, per ROLE ref
impact ROLE What depends on ROLE (upstream)? one ansible.dependent row per repo reached, per ROLE ref
find REPO --root ROOT / --stdin Which roots contain REPO downstream? one ansible.dependency_match row per match
graph TARGET The whole picture, both directions a tree, Mermaid diagram or JSON graph

Downstream works from live GitHub reads. Upstream needs a source: a saved set of orgs, teams or repos whose dependency files untaped scans and caches.

The packaged skill is the full reference: sources and refreshes and graph resolution and output.

Set up

untaped ansible reads GitHub through the github settings, so set a GitHub token first (see GitHub):

untaped config set github.token --prompt

Private repos also need Git access over HTTPS with that token, or over SSH when ansible.git_clone_protocol is ssh.

Save a source, refresh it once, and make it the default so you can leave out --source:

untaped ansible source set platform --org acme --team acme/platform
untaped ansible source refresh platform
untaped config set ansible.default_source platform

ansible.default_source is used by deps, impact, find and graph whenever you give neither --source nor an inline selector. With a source selected, every command reads the cached data and never touches GitHub; pass --live to read downstream dependencies from GitHub anyway.

Scanned files, clone protocol, cache locations and refresh tuning are in the configuration reference.

Show what a role depends on

untaped ansible deps acme/base-role
untaped ansible deps acme/base-role --ref v2.1.0 --depth 2
untaped ansible deps ./roles/web --target-repo acme/web --format json

ROLE is owner/repo, a GitHub URL, a source alias, or a local path (for a subdirectory of a checkout, add --target-repo OWNER/NAME).

Without a source, deps reads GitHub live. With one, it reads the source's cache: a role outside the source gets a "not cached" warning and no rows. Pass --live to read GitHub anyway. The same holds for find and for graph's downstream half. Collections in requirements files are not followed; the command warns once and lists them.

Find what depends on a role

untaped ansible impact acme/base-role
untaped ansible impact acme/base-role --source platform --refresh
untaped ansible impact acme/base-role --ref main --format pipe

impact reads cached source data only: from --source NAME (repeat to combine), from inline selectors, or from ansible.default_source. Pass --refresh (or run source refresh) when you want current data. For a one-off question, use inline selectors instead of a saved source; the scan is cached, so repeating the same command reuses it:

untaped ansible impact acme/base-role --org acme --refresh

Find which roots contain a repository

find REPO walks the downstream graph of each root and prints one row per node of REPO it reaches, and nothing for roots that never reach it. Give roots with --root (repeatable) or through --stdin, and one or more repos to look for:

untaped ansible find acme/base-role --root acme/site@main --root acme/app
printf 'acme/site@main\nacme/app@v2.1.0\nacme/tools\n' \
  | untaped ansible find acme/base-role --stdin
untaped awx job-templates list --organization Default --with-scm --format pipe \
  | untaped ansible find acme/base-role --stdin --format pipe

A root is owner/repo@ref (the ref is optional), a Git URL, a source alias, or a local path. Stdin carries either such lines or --format pipe records naming a repository and ref, such as AWX job templates.

Each ansible.dependency_match row names the root, the matched repo, the dependency file and the shortest path from the root, plus the input record's kind, id and name. Every input record gets its own rows, so a pipeline can join the results back to its inputs.

Draw the graph

untaped ansible graph acme/base-role
untaped ansible graph acme/base-role --direction down --format mermaid --out deps.mmd
untaped ansible graph acme/base-role --direction up --depth 2 --format json

graph shows both directions by default; --direction up shows only what depends on the target and --direction down only what it depends on. Without a source it shows only downstream and warns that upstream was omitted. The tree looks like this:

acme/base-role@main  source platform · unlimited depth

used by
└── acme/site@main                roles/requirements.yml · unpinned

depends on
├── acme/legacy@v1                meta/main.yml
│   └── acme/shared@main [1]      meta/main.yml · unpinned
│       └── acme/leaf@main        requirements.yml
└── acme/users@v1.2.0             requirements.yml
    └── acme/shared@main see [1]  requirements.yml · unpinned

5 repos · 6 edges

The first line names the target, where the data came from and the depth. After each repo comes the file that declares that dependency, plus unpinned when it names no version, or pins X when the declared version differs from the ref it resolved to. A repo marked … with a not read: note is stopped: its own dependencies (or dependents) were not read, because --depth ran out (depth) or its ref is not in the source's cache (not_cached), so the graph beyond it may be incomplete. The graph reference lists every marker.

Flags

deps, impact, find and graph share their options:

  • --source NAME (repeatable) picks saved sources; inline --org, --team and --repo selectors describe a one-off source instead. Without either, ansible.default_source is used.
  • --refresh refreshes the source first; --live reads downstream from GitHub even with a source (impact has no --live).
  • --depth N limits the walk; the default is unlimited.
  • --ref REF picks the target's branch, tag or SHA; without it, what the target depends on is read at its default branch, and --all-refs reads every cached ref instead. What depends on a target always covers all of its refs, since a repo pinning an older tag still uses it.

A table shortens each path to its first and last hop (a → … → z); other formats keep it whole.

Manage sources

untaped ansible source status
untaped ansible source patch platform --add-repo acme/legacy-app --remove-team acme/platform
untaped ansible source remove platform --dry-run

source set NAME creates or replaces a source from --org, --team and --repo; source patch NAME edits it with --add-*, --remove-* and --clear-*. source status shows whether each source is fresh, stale or not_refreshed.

source refresh saves each repo that succeeds. When some repos fail it lists them and exits non-zero; run it again to retry only those. A large refresh that runs low on GitHub API budget stops early, exits 5 and resumes where it left off when you run it again. Backends, rate-limit fallbacks and tuning are in the sources reference.

Source aliases

When a requirements file names a role by Galaxy name rather than a Git URL, map it to its repo:

untaped ansible source-alias set acme.base acme/ansible-role-base
untaped ansible source refresh platform

Source aliases apply when a source is refreshed, which is why the refresh follows.

Read the output

  • stopped on a row or node (depth or not_cached) means the next level beyond that repo was not read: its dependencies for deps, its dependents for impact. Treat the answer as incomplete there.
  • Each repo appears once per root ref, at its shortest path; root_ref says which ROLE ref a row came from.
  • A dependency at repo@v1 and one at repo@main are different nodes; an unpinned dependency points at the dependency's default-branch node.
  • A cycle is found only within the depth you asked for.
  • A malformed or templated dependency file is skipped with a warning; it never fails the command.

Every row field, the tree markers and the JSON graph shape are in the graph reference.

Troubleshooting

  • "no cached source data found": the source was never refreshed. Run the source refresh command the error prints, or add --refresh.
  • An older index is rebuilt: after an upgrade the SQLite cache (ansible.index_path) may be rebuilt empty with a warning. Refresh each source again.

Output

See Scripting and Exit codes.

See also

Metadata

Release files for untaped-ansible 10.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for untaped-ansible 10.0.0
File Size Uploaded Provenance Actions
untaped_ansible-10.0.0.tar.gz 81.9 kB With provenance Details for untaped_ansible-10.0.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for untaped-ansible 10.0.0
File Interpreter ABI Platform Actions
untaped_ansible-10.0.0-py3-none-any.whl Python 3 none any Details for untaped_ansible-10.0.0-py3-none-any.whl

Total release size: 186.4 kB

Release files / untaped_ansible-10.0.0.tar.gz

Download URL untaped_ansible-10.0.0.tar.gz
Size 81.9 kB
Tags Source
SHA-256 checksum
How to use checksums
527c8954ff90b12b43b1813a31f0d7dab3a2c573723c3b680d5f4483b5ca1c4b
BLAKE2b-256 checksum
How to use checksums
c0d37782227414794f76b5fd6660613e94e6092ede924df7dbf50a1bf0f12a23
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release files / untaped_ansible-10.0.0-py3-none-any.whl

Download URL untaped_ansible-10.0.0-py3-none-any.whl
Size 104.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0731df6fe0fc5271185c1c2601732e5008d25591393c27496517f1b403e9e48b
BLAKE2b-256 checksum
How to use checksums
7c1466fcd57a2cf41c24fb848919b310ab0b80b899bcd3567d1fa0dbebf38fd8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Security for untaped-ansible 10.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for untaped_ansible-10.0.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page