What the agent does
In a role like geerlingguy/ansible-role-docker, the first finding is that nothing is pinned. There is no requirements.yml, meta/main.yml declares dependencies: [] and min_ansible_version: 2.15.1, and the CI workflow installs ansible, molecule, molecule-plugins[docker] and docker with an unpinned pip3 install. So the agent first works out which collections the role really uses. Most tasks call ansible.builtin modules by their full name (apt, file, package, deb822_repository, systemd_service), but tasks/setup-RedHat.yml uses ini_file and tasks/setup-Suse.yml uses zypper_repository and ansible.legacy.zypper. Those short names resolve to community.general, which arrives only with the full ansible package, not with ansible-core.
It writes a requirements.yml that names community.general at the newest release that supports the role's min_ansible_version, installs it with ansible-galaxy collection install -r requirements.yml, and pins the Python test tooling the same way so a later run installs what this one proved. Where a module is better called by its full name (community.general.ini_file instead of ini_file), it changes the task, because that is the line ansible-lint's fqcn rule flags once the collection is explicit.
Then it runs the checks. The repository's .ansible-lint skips yaml, risky-shell-pipe and role-name, and its CI lint job runs only yamllint, so ansible-lint has not been holding the role to anything. The agent runs ansible-lint with the repository's own config and fixes what the upgrade surfaces, keeping fixes that change behaviour out of the pull request. It runs molecule test on the default scenario, whose molecule.yml starts geerlingguy/docker-${MOLECULE_DISTRO:-rockylinux9}-ansible:latest as a privileged container with systemd, converges the role, runs converge a second time for idempotence and then verify.yml, which checks docker version, systemctl is-active docker and a docker pull hello-world.
CI tests seven distros (rockylinux10, ubuntu2404, ubuntu2204, debian13, debian12, fedora43, opensuseleap15). The agent runs at least one Debian-family and one RedHat-family distro through MOLECULE_DISTRO, because ini_file only runs on RedHat and the zypper tasks only on SUSE, and says which distros it did not run. A collection bump that breaks a converge is left out, with the failing task's output.
Start it with one API call
POST https://api.prix.dev/o/{org}/sessions with this body:
{
"agent": "codex",
"input": "Find every collection this Ansible role uses, including modules called by short name that resolve outside ansible-core, and pin them in a new requirements.yml at the latest versions compatible with the role's min_ansible_version. Install them with ansible-galaxy collection install -r requirements.yml and pin the Python test tools in CI the same way. Run ansible-lint with the repository's .ansible-lint and fix the findings the upgrade raises. Run molecule test on the default scenario with MOLECULE_DISTRO set to at least one Debian-family and one RedHat-family image. Leave out any upgrade that breaks the build or tests and say why, and open a pull request with one line per bump and a list of distros you did and did not run.",
"resources": [
{
"url": "https://github.com/your-org/your-app"
}
]
}- Get an API key. In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
- Send the request. POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
- Read what came back. Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.
What comes back
The pull request adds requirements.yml with each collection and its version, changes the CI install step to use it and to pin ansible, molecule and molecule-plugins, and rewrites short module names to their full collection names where ansible-lint asked for it. Its description has one line per pinned or bumped dependency, the lint findings it fixed with the rule each one came from, and the molecule distros it ran.
Before merging, a reviewer reads the converge and idempotence output for each distro in the run's transcript and checks the distros listed as not run, since the opensuseleap15 path is the only one that exercises zypper_repository. A pinned community.general also means the role now states a dependency it always had, which is worth a line in the changelog for anyone installing it from Galaxy.
Run it on every new community.general release
Collections release on their own schedule, so start one run when community.general or ansible-core publishes a release your role cares about, or on a weekly cron in your own scheduler. Each start is one POST /o/{org}/sessions with the same body; a key with a webhook URL gets run.completed when the pull request is ready and run.failed when it is not.
Because requirements.yml now holds exact versions, each later run is a small diff from a known-good set instead of whatever pip resolved that day.
The use case this job follows, with its automation and trigger: Upgrade dependencies weekly.
Why run it on Rush?
molecule test needs Docker with privileged containers and cgroup access, pulls a distro image per platform, and runs the role twice per distro. That is slow to run by hand and awkward to run in a shared CI runner while you iterate on lint fixes. In Rush the agent does it in its own sandbox, and every ansible-lint and molecule invocation, with its output, stays in the transcript at GET /o/{org}/sessions/{id}/messages.
Several roles can be upgraded at once, one run each, within the key's concurrency limit. Each comes back as a pull request whose description names what was proven on which distro, so a maintainer reviews evidence instead of rerunning the matrix to find out.
Frequently asked questions
My role has no requirements.yml. Will it create one?
Yes, when the role uses modules outside ansible-core. In geerlingguy.docker, ini_file and zypper_repository come from community.general, so the agent adds that collection with a version. If every module were ansible.builtin, there would be nothing to pin and the pull request would say so.
Will it run every distro in my CI matrix?
It runs the ones the request names, and the request above asks for at least one Debian-family and one RedHat-family image. The pull request lists the distros it did not run, so CI covers the rest and a reviewer knows which paths are proven by the run.
Will it turn on ansible-lint rules I skip?
No. It runs ansible-lint with your .ansible-lint, so skipped rules such as yaml and role-name stay skipped. It fixes findings the upgrade raises under your own config and lists them by rule.
Does it publish a new role version to Galaxy?
No. It opens a pull request and stops. Your release workflow publishes after the merge, as it does today.