1
0
Fork 0
forked from infra/ansible
infra-ansible/AGENTS.md
Justin Wheeler 5c766e21a0 🤖 docs: Add AGENTS.md with project conventions for AI coding agents
Without guardrails, AI tools generate PRs that ignore Fedora Infra's
conventions — wrong file extensions (`.yaml` vs `.yml`), missing
`vars_files` triplets, broken idempotency, relative paths instead of the
required hardcoded `/srv/web/infra/ansible/` layout, and suggestions to
"fix" intentional patterns like the `vars/all/*.yaml` exception or the
`fedora_messaging_callback.py` custom plugin.

AGENTS.md gives AI agents the same context a new human contributor would
get from reading README.md, CONVENTIONS, STYLEGUIDE, and
`.ai_review/project.md` — but in a single file that AI tools
automatically load before generating code. This means AI-assisted PRs
should arrive already following our linting rules, architectural
patterns (OpenShift app vs group playbook), staging/prod conventions
(`_stg` group_vars, `env`/`env_suffix`), and tag discipline.

The file also includes the Fedora AI-Assisted Contribution Policy
requirements, ensuring AI agents prompt contributors to include the
Assisted-by: commit message trailer and respect the project's rules on
accountability, transparency, and human-final review.

The net effect is fewer round-trips in review: maintainers spend less
time explaining the same conventions repeatedly and can focus review on
whether the change is correct, not whether it follows the style guide.

Assisted-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Justin Wheeler <jwheel@redhat.com>
2026-03-30 21:52:51 +00:00

6.4 KiB

AGENTS.md

This file provides guidance to AI coding agents when working with code in this repository.

Project Overview

Ansible automation for the entire Fedora Project infrastructure. Manages hundreds of bare-metal hosts, VMs, and OpenShift 4 applications across production and staging environments. The control host is batcave01 (/srv/web/infra/ansible public, /srv/private/ansible private).

Repository is hosted at https://forge.fedoraproject.org/infra/ansible

Linting

Run yamllint on changed files:

yamllint path/to/file.yml

Run ansible-lint on changed files:

ansible-lint path/to/file.yml

CI runs both linters on changed files only (Forgejo Actions on quay.io/fedora/fedora:latest). The community.zabbix collection is installed before ansible-lint runs.

Linting configuration

  • yamllint (.yamllint.yaml): 2-space indentation (warning level), line-length disabled, octal values forbidden, truthy values restricted to true/false/yes/no, templates directories ignored.
  • ansible-lint (.ansible-lint): Runs in offline mode. Skipped rules: yaml, role-name[path], var-naming[no-role-prefix], no-changed-when, ignore-errors. Uses mock_modules and mock_roles to pass syntax checks without all dependencies.

Architecture

Directory structure

  • playbooks/groups/ — One playbook per service group (multi-host). Filename should be descriptive.
  • playbooks/hosts/ — One playbook per unique host. Filename MUST be FQDN.yml.
  • playbooks/openshift-apps/ — ~60 OCP4 application deployments.
  • playbooks/manual/ — Admin-only playbooks, never run by cron.
  • playbooks/include/ — Shared playbook fragments (proxy, virt, cert).
  • roles/ — 134 roles. Flat structure with some namespacing (openshift/, openshift-apps/, awx/, rabbit/).
  • roles/base/ — Applied to ALL managed hosts. Changes here have maximum blast radius.
  • inventory/ — Host definitions, group_vars/ (150 files), host_vars/, and zzz-inventory.config (constructed inventory plugin, loads last due to zzz- prefix).
  • vars/all/ — Fedora release cycle variables. Changed every ~6 months during branching/release. Incorrect values break builds across the entire infrastructure.
  • vars/global.yml — Global vars (paths, SSL, base packages).
  • tasks/ — Reusable task snippets included in playbooks.
  • library/ — Custom Ansible modules (delete_old_oci_images.py, virt_boot, etc.).
  • callback_plugins/ — Custom callbacks (fedora_messaging_callback.py, logdetail.py). Don't suggest replacing these.
  • main.yml — Master playbook importing all group/host playbooks. Used with -t tag to run specific tags across all hosts. Nightly --check --diff cron runs all playbooks.

Two main deployment patterns

OpenShift app pattern (dominant for new services):

  1. Playbook in playbooks/openshift-apps/<app>.yml targets os_control[0]:os_control_stg[0]
  2. Uses composable openshift/* roles: project, object, keytab, secret-file, imagestream, route, rollout
  3. App templates in roles/openshift-apps/<app>/templates/
  4. Uses gather_facts: false (runs oc commands on control node, not on apps)

Group playbook pattern (traditional VM services):

  1. Playbook in playbooks/groups/<group>.yml with hosts: matching inventory group
  2. Must include standard vars_files (see below)

Staging vs Production

Same inventory, not separate inventories. Staging hosts use _stg suffixed group_vars files. Controlled by:

  • env"production" or "staging"
  • env_suffix"" for prod, ".stg" for staging

Fedora AI-Assisted Contribution Policy

This repository is part of the Fedora Project and subject to the Fedora AI-Assisted Contributions Policy. Key requirements:

  • Accountability: The human contributor is always the author and is fully accountable for the entirety of AI-assisted contributions. All submissions must meet project standards for quality, license compliance, and utility.
  • Transparency: Use of AI tools MUST be disclosed when the significant part of the contribution is taken from a tool without changes. For git contributions, use an Assisted-by: commit message trailer (e.g., Assisted-by: ChatGPTv5 or Assisted-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>).
  • No AI-only judgments: AI MUST NOT be used as the sole or final arbiter for substantive or subjective judgments on contributions, nor for evaluating a person's standing in the community. Automated objective validation (CI/CD, testing, linting) is permitted.

When generating commit messages, always include the Assisted-by: trailer naming the specific AI model and version used.

Coding Conventions

Required vars_files in all group/host playbooks

vars_files:
  - /srv/web/infra/ansible/vars/global.yml
  - "{{ private }}/vars.yml"
  - /srv/web/infra/ansible/vars/{{ ansible_distribution }}.yml

These hardcoded paths are the production layout on batcave01. Do not make them relative or configurable.

Style rules

  • Use .yml not .yaml for file extensions. Exception: vars/all/*.yaml is historical — don't "fix" this.
  • Add .j2 extension to all Jinja2 templates. A .yml file in templates/ without .j2 won't render Jinja expressions.
  • 2-space YAML indentation. Line length is not enforced.
  • Prefer readable multi-line module args over single-line module: name=x arg=y format.
  • Standard tags: packages (installs/removes packages), config (installs config files).
  • build and rollout tags use never to prevent accidental execution.
  • All playbooks must be idempotent — they can be run at any time by the nightly cron.

Common pitfalls

  • Forgetting to update multiple files in vars/all/ together during release transitions (e.g., branching requires FedoraBranched.yaml, 00-FedoraCycleNumber.yaml, FedoraBranchedBodhi.yaml, and Frozen.yaml).
  • Breaking idempotency — generates noise in nightly --check --diff and masks real drift.
  • OpenShift apps must target os_control[0]:os_control_stg[0], not all control nodes.

Domain terminology

  • batcave01 — Ansible control host
  • FAS/IPA — Fedora Account System (identity provider)
  • Koji — Build system (VM-based, not OpenShift)
  • Bodhi — Update management (runs on OpenShift)
  • dist-git/src.fedoraproject.org — Package source repositories
  • fedora-messaging/RabbitMQ — AMQP message bus connecting services