Recipe Development Guide
This guide covers how to create, modify, and validate recipe metadata.
Quick Start: Contributing a Recipe
New to recipe development? Follow these minimal steps to contribute:
1. Copy an existing overlay (details)
2. Edit criteria and components (criteria, components)
3. Run tests (details)
4. Open PR (best practices)
- Include test output showing recipe generation works
- Explain why the recipe is needed (new hardware, workload, platform)
Overview
Recipe metadata files define component configurations for GPU-accelerated Kubernetes deployments using a base-plus-overlay architecture with three composition mechanisms — single-parent inheritance, explicit mixin composition, and criteria-wildcard matching:
- Base values (
overlays/base.yaml) - universal defaults - Intermediate recipes (
eks.yaml,eks-training.yaml) - shared configurations for categories - Leaf recipes (
gb200-eks-ubuntu-training.yaml) - hardware/workload-specific overrides - Mixins (
mixins/*.yaml) - composable fragments (OS constraints, platform components) that leaf overlays reference viaspec.mixinsinstead of duplicating content - Criteria-wildcard overlays (
gb200-any-training.yaml) - cross-cutting overlays picked up automatically by the resolver when their wildcard criteria match the query, without being referenced viaspec.baseorspec.mixins - Inline overrides - per-recipe customization without new files
Recipe files in recipes/ are embedded at compile time. Integrators can extend or override using the --data flag (see Advanced Topics).
For query matching and overlay merging internals, see Data Architecture.
Recipe Structure
Multi-Level Inheritance
Recipes use spec.base to inherit configurations. Chains progress from general (base) to specific (leaf):
Intermediate recipes (partial criteria) capture shared configs:
Leaf recipes (complete criteria) match user queries:
Leaf recipes with mixins compose shared fragments:
Mixins use kind: RecipeMixin and carry only constraints and componentRefs. They live in recipes/mixins/ and are applied after inheritance chain merging. See Data Architecture for details.
Cross-cutting overlays with wildcard criteria apply across one criteria dimension without being referenced via spec.base or listed in spec.mixins. The resolver can return multiple independent maximal-leaf overlays for a single query, so a service: any overlay is picked up alongside the service-specific maximal leaf and its inheritance chain:
Only use this pattern when the content is truly uniform across the wildcard dimension — if values diverge per service, keep them inline in each service-specific overlay. See Data Architecture for when to use wildcard overlays vs mixins.
Merge order: base.yaml (lowest) → intermediate → leaf → mixins (highest)
Merge rules:
- Constraints: same-named overridden, new added
- ComponentRefs: same-named merged field-by-field, new added
- Criteria: not inherited (each recipe defines its own)
- Mixin constraints/components must not conflict with the inheritance chain or other mixins
Component Types
Helm components (most common):
Kustomize components
A component must have either helm OR kustomize configuration, not both.
Component Configuration
Configuration Patterns
Pattern 1: ValuesFile only (large, reusable configs)
Pattern 2: Overrides only (small, recipe-specific configs)
Pattern 3: Hybrid (shared base + recipe tweaks)
Value Merge Precedence
Values merge from lowest to highest precedence:
Deep merge: only specified fields replaced, unspecified preserved. Arrays replaced entirely (not element-by-element).
Example:
File Naming Conventions
File names are for human readability—matching uses spec.criteria, not file names.
Overlay naming: {accelerator}-{service}-{os}-{intent}-{platform}.yaml (platform always last)
Constraints and Validation
Constraints
Constraints validate deployment requirements against cluster snapshots:
Common measurement paths
Operators: >=, <=, >, <, ==, !=, or exact match (no operator)
Add constraints when: recipe needs specific K8s features, driver versions, OS capabilities, or hardware. Skip when universal or redundant with component self-checks.
Validation Phases
Optional multi-phase validation beyond basic constraints:
Phases: deployment, performance, conformance (readiness constraints are evaluated implicitly)
Testing
Working with Recipes
Adding a New Recipe
When: new platform, hardware, workload type, or combined criteria
Steps:
- Create overlay in
recipes/overlays/with criteria and componentRefs - If the recipe shares OS constraints or platform components with other overlays, reference existing mixins via
spec.mixinsinstead of duplicating (or create new mixins inrecipes/mixins/) - Create component values files if using
valuesFile - Run tests:
make test - Test generation:
aicr recipe --service eks --accelerator gb200 --format yaml
Example:
Updating Recipes
Updating versions:
Adding components:
Test changes: aicr recipe --service eks --accelerator gb200 --format yaml
Best Practices
Do:
- Use minimum criteria fields needed for matching
- Keep base recipe universal and conservative
- Use mixins for shared OS constraints or platform components instead of duplicating across leaf overlays
- Always explain why settings exist (1-2 sentences)
- Follow naming conventions (
{accel}-{service}-{os}-{intent}-{platform}) - Run
make testbefore committing - Test recipe generation after changes
Don’t:
- Add environment-specific settings to base
- Over-specify criteria (too narrow = fewer matches)
- Create duplicate criteria combinations
- Duplicate OS or platform content across leaf overlays (use mixins instead)
- Skip validation tests
- Forget to update context when values change
Testing and Validation
Automated Tests
Tests in pkg/recipe/yaml_test.go validate:
- Schema conformance (YAML structure)
- Criteria enum values (service, accelerator, intent, OS, platform)
- File references (valuesFile, dependencyRefs)
- Constraint syntax (measurement paths, operators)
- No duplicate criteria
- Merge consistency
- No dependency cycles
Running Tests
Test Workflow
- Create recipe file in
recipes/ - Run
make testto validate - Test generation:
aicr recipe --service eks --accelerator gb200 --format yaml - Inspect bundle:
aicr bundle -r recipe.yaml -o ./test-bundles
Tests run automatically on PRs, main pushes, and release builds.
Advanced Topics
External Data Sources
Integrators can extend or override embedded recipe data using the --data flag without modifying the OSS codebase. This enables:
- Custom recipes for proprietary hardware
- Private component values with organization-specific settings
- Extended registries with internal Helm charts
- Rapid iteration without rebuilding binaries
Directory structure
Usage:
Precedence: Embedded data (lowest) → External data (highest)
Behavior:
- Overlays: Same
metadata.namereplaces embedded - Registry: Merged; same-named components replaced
- Values: External valuesFile references take precedence
Validation:
Regional registry overrides
A handful of components ship images from regional, account-scoped container registries rather than a single public URI. The clearest example today is the AWS EFA device plugin, whose canonical home is <account>.dkr.ecr.<region>.amazonaws.com/eks/aws-efa-k8s-device-plugin — a per-region private ECR that every EKS node is auto-authorized to pull from. AWS publishes these add-ons regionally for three reasons: pulls go over the AWS internal backbone (no NAT egress), no Docker Hub / public-registry rate limits, and the image stays available even when the public internet or another region is degraded.
AICR ships a sensible default for each such image (e.g., us-west-2 for aws-efa), but customers deploying in a different region need to override the registry’s region segment. Two override paths cover the common cases:
Bundle-time override (single region per bundle). Use --set to bake a specific region into the bundle:
Install-time override (one bundle, many regions). Use --dynamic to declare the path as install-time-fillable, then provide the value via helm install --set (or your GitOps tool):
--dynamic is supported with helm and argocd-helm deployers; argocd does not support it (use argocd-helm instead). See Dynamic Install-Time Values for the broader pattern.
Partition-aware variants. Standard AWS uses account ID 602401143452. GovCloud and China use different accounts and URI suffixes:
Substitute the appropriate account and suffix in the --set / install-time value.
Troubleshooting
Debug overlay matching:
Common issues:
Validation:
See Also
- Data Architecture - Recipe generation process, overlay system, query matching algorithm
- Bundler Development Guide - Creating new bundlers
- CLI Reference - CLI commands for recipe and bundle generation
- API Reference - Programmatic recipe access