Developer guide
This guide is for contributors who want to extend, debug, or maintain the AVD pipeline — adding device roles, transform outputs, schema fields, or fixing pipeline issues. It assumes familiarity with Python, GraphQL, and Infrahub generators/transforms.
Contributor runtime and validation​
Use Python 3.14.7; the solution supports >=3.14,<3.15. Python 3.11–3.13
support has been removed. Install the committed dependency lock and run unit
tests directly:
uv sync --all-packages --frozen
uv run pytest tests/unit
uv run invoke lint
uv run invoke docs
cd docs
pnpm run typecheck
invoke test also runs integration tests. Integration tests are time-consuming
and must be run manually by the user before claiming full integration
compatibility. Generator changes also require idempotence validation. Unit tests
and image smoke checks do not establish full integration compatibility.
The custom Infrahub image extends /.venv shipped with Infrahub 1.11.5 using
uv sync --no-dev --frozen --inexact, with automatic Python selection. The
image's PATH selects /.venv/bin/python, which uses the Python 3.14.7
interpreter supplied by the image. Keep the solution's Python requirements
compatible with that interpreter. --inexact retains extra packages when
syncing a compatible existing environment; it cannot retain them if a Python
mismatch causes uv to recreate the environment. Verify imports and dependency
consistency with the image smoke checks after building.
Infrahub loads Python generators and transforms into its worker process, where the solution imports PyAVD directly. Infrahub and PyAVD must therefore share the same Python interpreter and compatible dependencies. Installing PyAVD in a separate virtual environment does not make it available to those imports. Using different Python versions requires a separate process or service.
The portal uses python:3.14.7-slim and starts Streamlit with uv run --no-sync.
Semaphore retains its separate Python and Ansible runtime.
Build and check disposable candidate images without starting Compose:
docker build -t avd-infrahub-candidate .
docker build -f Dockerfile.catalog -t avd-portal-candidate .
docker build -t avd-semaphore-candidate semaphore
bash scripts/smoke_images.sh avd-infrahub-candidate avd-portal-candidate avd-semaphore-candidate
The smoke script checks server, worker, and task-manager imports, inherited Infrahub/SDK versions, package consistency, portal health, and Semaphore AVD versions and playbook syntax. Its containers have no external network access; it does not run deployment playbooks or device tests. CI runs this check independently of the E2E job when images or dependencies change.
Start here​
- Architecture Overview — system components, data model hierarchy, and the generator pipeline at a glance.
- AVD Pipeline → Overview — the two-phase pipeline (hostvars → structured config) and the PyAVD version target.
Reference​
- Schemas — every YAML schema file and the kinds it defines.
- Generators — the generator framework, file structure, and per-generator behaviour.
- Transforms — Python and Jinja2 transforms, queries, and content types.
- Checks — proposed-change validation checks, including CloudVision configuration validation.
AVD pipeline​
The AVD pipeline is the technically distinguishing piece of this solution and has its own sub-section:
- Overview — two-phase pipeline + PyAVD version pin.
- Hostvars Reference — the PyAVD-compatible structure produced per device role.
- Transforms —
avd_eos_config,avd_fabric_doc,avd_device_doc. - AvdArtifact & File Storage — the
AvdArtifactnode, child file nodes, checksum-based change detection. - Role Mapping — Infrahub roles → AVD device types.
- Extending the Pipeline — worked examples for new roles, new transform outputs, new hostvar fields.
- Debugging the Pipeline — intermediate-file inspection, single-generator re-runs, common failure modes.
Looking for the operator guides?​
If you want to use the system to provision fabrics and view configurations without modifying code, start with Quick Start and the how-to guides.
Add a seed example​
Put shared dependencies under objects/common/. Create a fabric directory under objects/ with
YAML files ordered by numeric prefix: pools (00), fabric/pods (10), locations (20), services
(30), server profiles (40), server templates (50), and endpoints (60). Any extra dependency,
such as a fabric-specific user, must load before its first reference.
A directory name is its selection identifier. all discovers new directories automatically. Keep
object names unique across directories, and resolve every reference using Common and that example
alone. Shared Hall-A1 supports MultiPod A/B; fabric-specific server profiles must refer to local
VLANs. See the seed catalog.
The unit suite checks selection, load order, standalone references, combined identities, addressing pools, virtual Loopback0 interfaces, and template port capacity:
uv run pytest tests/unit
An optional container-based matrix is prepared in tests/integration/test_seed_selection.py:
Common only, each of the seven fabrics, MultiPod A+B, L2LS+Campus, and all. The matrix shares one
isolated stack and one schema load. Each case creates a branch from the schema-only default branch
and uses invoke load-objects with an explicit selection. Non-branched objects are discovered
from the schema API and removed between cases; branch-aware objects remain isolated.
It registers no repository or triggers. Run it only when integration validation is explicitly
requested, following the repository integration-test workflow.