JetBrains IDE plugin

Go to definition, for Ansible variables.

Ctrl-click a variable and Yamlix lists every place it is defined — ordered by the one that actually applies at your caret.

Go to definition11 definitions · stag-web-1 · caret at site-playbook.yml:42
app_porteffective8500
  • 8500set_factroles/app/tasks/main.ymlapplies here
  • 8100include_varsroles/app/vars/Darwin.yml
  • 8090role varsroles/app/vars/main.yml
  • 8070vars_filesvars/common.yml
  • 8060play varssite-playbook.yml
  • 8050host_varsinventories/stag/host_vars/stag-web-1.yml
  • 8040group_varsinventories/stag/group_vars/canary.yml
  • 8030group_varsinventories/stag/group_vars/webservers.yml
  • 8020group_varsinventories/stag/group_vars/platform.yml
  • 8010group_vars/allinventories/stag/group_vars/all.yml
  • 8000role defaultsroles/app/defaults/main.yml
reached bysite-playbook.yml
hostsstag-web-1, stag-web-2
Ctrl-click app_port in the plugin's test fixture, on host stag-web-1. Eleven definitions are in scope; the set_fact at the top is the one that applies there.

Reconstruction of the go-to-definition list, not a screenshot. The order is by what applies at the caret, not alphabetical or by file.

Why the answer is hard

The winner moves with the caret

Precedence is not a property of a variable. It is a property of a position in a play.

Below is the same variable in the same repository, read at four positions in one playbook, for two hosts. The first two rows agree. The third does not, because the set_fact that produces 8500 sits behind a when: that is true on staging and false on production.

Same file. Same line. Two answers. Grep cannot tell you which one you are about to ship, and neither can reading the precedence table, because the table does not know where your caret is.

app_port read at four positions in site-playbook.yml, for two hosts in two inventories. The third and fourth rows disagree because the set_fact that produces 8500 sits behind a when: that is false on production.
Caret positionIn the playstag-web-1prod-web-1Winning level
site-playbook.yml:21pre_tasks, before any role has run80908090role vars
roles/app/tasks/main.yml:11inside the role, after include_vars81008100include_vars
roles/app/tasks/configure.yml:4after a set_fact guarded by when:85008100set_fact on stag, include_vars on prod
site-playbook.yml:41post_tasks, after every role85008100set_fact on stag, include_vars on prod

What it does

Four things, in the places you already look

  • Ctrl-click a variable

    ⌘-click on macOS

    Lists every definition site, ordered by what applies at the caret rather than alphabetically. The definition you are looking for is the one your eye lands on first, not the one that happens to start with an early letter.

  • Ctrl-click everything else

    and Find Usages, for the way back

    Jump to roles, include_role, include_tasks, vars_files, include_vars, template and copy sources, notify handlers, and hosts: patterns into both INI and YAML inventories. Find Usages goes the other way — from a definition to everything that reads it.

  • Quick Documentation

    Shows the effective value per inventory and per host, collapsing the hosts that agree. Where twenty hosts resolve to the same value and one does not, you see two rows, and the interesting one is not buried.

  • A tool window for the open file

    Lists every variable the file uses and defines, its effective value, and each definition site under the Ansible precedence level it sits at. Definitions that lost are folded behind one row, so the list stays the length of the question rather than the length of the repository. It also shows which playbooks reach the file, and which hosts that means.

    Open an inventory instead and it lists that inventory's groups: host counts, child groups, the group_vars that apply, and every play whose hosts: pattern selects each group — including the groups nothing targets.

There is also completion for variable names and hosts: patterns, and an inspection that reports roles, includes and file references resolving to nothing.

The design decision

Unresolved is an answer

Some things cannot be known from a repository. The plugin says so instead of picking one.

Gathered facts, register, hostvars, lookup(), vault: none of these exist until the play runs. Where a value depends on them, Yamlix reports it as unresolved and shows the raw template exactly as written, rather than expanding it into a value that may be wrong.

The same rule holds for a fact-templated include_vars. Its target is not one file but a set, so the plugin lists every candidate and promotes none of them. The variable still resolves — to the highest-precedence definition that does not depend on run time — and the candidates are shown alongside it.

A tool that guesses correctly nine times out of ten cannot be trusted the tenth time, which is the time you needed it. Yamlix would rather show you a template than a plausible number.

Ansible variablesno facts gathered
app_porteffective8090
  • 8100include_varsroles/app/vars/Darwin.ymlneeds facts
  • 8200include_varsroles/app/vars/RedHat.ymlneeds facts
  • 8090role varsroles/app/vars/main.ymlapplies here

Extra vars (-e) override everything and are not visible from a repository.

app_port with no facts supplied. The include_vars target is templated on a fact, so both candidate files are listed and neither is chosen.

Getting it

Install

Requires a JetBrains IDE, build 2025.2 or newer. No upper bound is declared.

Awaiting approval

The plugin has been submitted to the JetBrains Marketplace and is awaiting moderation. Until the listing is live, install the release zip from disk.

Download the latest release from GitHub

  1. Download the plugin zip from the GitHub releases page.
  2. In the IDE, open Settings, then Plugins.
  3. Open the gear menu beside the Marketplace tab and choose Install plugin from disk…
  4. Select the downloaded zip and restart the IDE when prompted.

This page will describe the Marketplace route instead once the listing is approved.

Where it runs

Verified by the JetBrains Plugin Verifier against

  • IntelliJ IDEA Community
  • IntelliJ IDEA Ultimate
  • PyCharm
  • GoLand

Runs in

Yamlix depends only on the platform and the bundled YAML support, so it runs in any JetBrains IDE, not only IntelliJ IDEA. The four products above are the ones actually tested; the rest are expected to work but have not been verified.

If it does not fit your project

There is no one way to lay out an Ansible project

Yamlix works out your project's structure rather than assuming a convention. It has not seen every arrangement.

All of these are normal, and they are not the only options

  • ansible.cfg at the repository root — or in a subdirectory, or not present at all
  • one inventory file, or a directory per environment, or both at once
  • roles/ beside the playbooks, or a roles_path pointing somewhere else entirely
  • collections vendored under collections/ansible_collections/
  • several unrelated Ansible projects sharing one repository
  • playbooks run from a wrapper script that changes directory first

If a variable is reported as undefined when it plainly is defined, or roles and inventories that exist are not being found, that is usually the layout detection rather than the resolution — and it is worth reporting.

Open an issue with your project's structure: the directory tree from the repository root, plus your ansible.cfg, is normally enough to reproduce it. A link to the repository, if it is public, is better still. Working around it on your side is the wrong fix; I would rather teach the plugin the layout.

Open an issue with your layout

What it is not

It is not a linter, and it does not replace ansible-lint. It is not a replacement for the official Red Hat Ansible plugin either — that one knows about modules, syntax and playbook structure, and Yamlix does not try to.

Yamlix answers one question those tools do not: given this file, this host and this position, which definition of this variable applies. Run it alongside them.

What it does to your project

Nothing. Yamlix reuses the platform's YAML support rather than registering a file type of its own, so it does not claim *.yml and does not change how your files open. Ansible context is detected structurally, per file.

It never shells out to ansible, makes no network calls, and collects no data of any kind. There is no telemetry to opt out of, and this site carries no analytics or third-party scripts.