
agnosticv-catalog-builder
by rhpds
SKILL.md
name: agnosticv-catalog-builder description: Create or update AgnosticV catalog files (common.yaml, dev.yaml, description.adoc, info-message-template.adoc)
context: main model: sonnet
Skill: agnosticv-catalog-builder
Name: AgnosticV Catalog Builder Description: Create or update AgnosticV catalog files for RHDP deployments Version: 2.0.1 Last Updated: 2026-01-22
Purpose
Unified skill for creating and updating AgnosticV catalog configurations. Handles everything from full catalog creation to updating individual files like description.adoc or info-message-template.adoc.
When to Use This Skill
Use /agnosticv-catalog-builder when you need to:
- Create a complete new RHDP catalog item
- Generate just description.adoc from Showroom content
- Create info-message-template.adoc for user data display
- Update catalog files after Showroom content changes
- Set up infrastructure provisioning for workshops/demos
Prerequisites:
- RHDP account with AgnosticV repository access
- AgnosticV repository cloned locally (
~/work/code/agnosticv) - Git configured with SSH access to GitHub
- For description generation: Showroom content in
content/modules/ROOT/pages/
Skill Workflow Overview
Step 0: Prerequisites & Scope Selection
↓
├─ Full Catalog → Steps 1-10 (infrastructure + all files)
├─ Description Only → Steps 1-3 (extract from Showroom)
└─ Info Message Template → Steps 1-2 (user data template)
Step 0: Prerequisites & Scope Selection (FIRST)
CRITICAL: Start by asking what the user wants to generate.
Ask for Scope
🏗️ AgnosticV Catalog Builder
What would you like to create or update?
1. Full Catalog (common.yaml, dev.yaml, description.adoc, info-message-template.adoc)
└─ For: New catalog from scratch with infrastructure setup
2. Description Only (description.adoc)
└─ For: Generate/update description from Showroom content
3. Info Message Template (info-message-template.adoc)
└─ For: Display user data from your workload CI
Your choice [1-3]:
Ask for AgnosticV Repository Path
Q: What is your AgnosticV repository directory path?
Example paths:
- ~/work/code/agnosticv/
- ~/projects/agnosticv/
Your AgV path: [Enter full path]
Validate path exists:
ls -la /path/to/agnosticv/agd_v2/
Git Workflow Setup (REQUIRED FOR ALL MODES)
IMPORTANT: Always pull latest and create a new branch.
🔧 Git Workflow Setup
Before we start, let's ensure you're working on a clean branch.
I'll do the following:
1. Pull latest changes from main
2. Create a new feature branch for your catalog
Branch naming: Use descriptive names WITHOUT 'feature/' prefix
Good: add-ansible-ai-workshop
Good: update-ocp-pipelines-description
Bad: feature/add-workshop
Execute git workflow:
cd /path/to/agnosticv
# Check current branch
current_branch=$(git rev-parse --abbrev-ref HEAD)
# If not on main, warn user
if [[ "$current_branch" != "main" ]]; then
echo "⚠️ You're currently on branch: $current_branch"
echo "We need to switch to main first."
read -p "Switch to main and pull latest? [Y/n] " confirm
if [[ ! "$confirm" =~ ^[Nn] ]]; then
git checkout main
fi
fi
# Pull latest
echo "📥 Pulling latest changes from main..."
git pull origin main
# Ask for branch name
echo ""
echo "Q: What should we name your branch?"
echo " (Use format: add-<catalog-name> or update-<catalog-name>-description)"
read -p "Branch name: " branch_name
# Validate branch name doesn't have feature/
if [[ "$branch_name" =~ ^feature/ ]]; then
echo "⚠️ Remove 'feature/' prefix. Just use: ${branch_name#feature/}"
read -p "Branch name (without feature/): " branch_name
fi
# Create branch
echo "🌿 Creating branch: $branch_name"
git checkout -b "$branch_name"
MODE 1: Full Catalog Creation
When selected: User chose option 1 (Full Catalog)
Step 1: Catalog Discovery (Search Existing)
Search for similar catalogs to learn from or use as reference.
📖 Catalog Discovery
Let me search for existing catalogs to help you.
Q: What keywords describe your catalog?
(Examples: ansible, openshift ai, pipelines, gitops)
Keywords:
Search logic:
cd $AGV_PATH/agd_v2
# Search by keywords in:
# - Directory names
# - common.yaml display names
# - description.adoc content
find . -type f -name "common.yaml" | while read file; do
dir=$(dirname "$file")
name=$(grep "^name:" "$file" | cut -d':' -f2-)
echo "$dir: $name"
done | grep -i "$keywords"
Present results and ask:
Found similar catalogs:
1. agd_v2/ansible-aap-workshop/
└─ Ansible Automation Platform Self-Service
2. agd_v2/openshift-gitops-intro/
└─ OpenShift GitOps Introduction
Do you want to:
A. Create new catalog from scratch
B. Use one as reference (copy structure)
C. Just browse and continue
Choice [A/B/C]:
Step 2: Category Selection (REQUIRED)
📂 Category Selection
RHDP catalogs MUST have exactly one category:
1. Workshops - Multi-user hands-on learning with exercises
2. Demos - Single-user presenter-led demonstrations
3. Labs - General learning environments
4. Sandboxes - Self-service playground environments
5. Brand_Events - Events like Red Hat Summit, Red Hat One
Q: Which category? [1-5]:
Validate: Must be one of: Workshops, Demos, Labs, Sandboxes, Brand_Events (exact match)
Important validation rules:
- Workshops/Brand_Events → Must set multiuser: true
- Demos → Must set multiuser: false (single-user only)
Step 3: UUID Generation (REQUIRED)
🔑 UUID Generation
Every catalog needs a unique RFC 4122 compliant UUID.
Generating UUID...
Generate and validate:
# Generate lowercase UUID
new_uuid=$(uuidgen | tr '[:upper:]' '[:lower:]')
# Check for collisions
echo "Generated: $new_uuid"
echo "Checking for collisions..."
# Search all common.yaml files
grep -r "asset_uuid: $new_uuid" $AGV_PATH/agd_v2/
if [[ $? -eq 0 ]]; then
echo "⚠️ Collision detected! Regenerating..."
# Regenerate until unique
fi
Step 4: Infrastructure Selection
🏗️ Infrastructure Selection
Choose your OpenShift deployment type:
1. CNV Multi-Node (Standard - Recommended for most)
└─ Full OpenShift cluster on CNV pools
└─ Best for: Multi-user workshops, complex workloads
└─ Component: agd-v2/ocp-cluster-cnv-pools/prod
2. SNO (Single Node OpenShift)
└─ Single-node cluster for lightweight demos
└─ Best for: Quick demos, single-user environments, edge demos
└─ Component: agd-v2/ocp-cluster-cnv-pools/prod (cluster_size: sno)
3. AWS (Cloud-based VMs)
└─ VM-based deployment on AWS
└─ Best for: GPU workloads, AWS-specific features, bastion-only demos
└─ Component: Custom (requires bastion + instances configuration)
4. CNV VMs (Cloud VMs on CNV)
└─ Virtual machines on CNV infrastructure
└─ Best for: RHEL demos, edge appliances, non-OpenShift workloads
└─ Component: Custom (cloud_provider: openshift_cnv, config: cloud-vms-base)
Q: Infrastructure choice [1-4]:
Set configuration based on choice:
- CNV Multi-Node:
config: openshift-workloads
cloud_provider: none
clusters:
- default:
api_url: "{{ openshift_api_url }}"
api_token: "{{ openshift_cluster_admin_token }}"
__meta__:
components:
- name: openshift
display_name: OpenShift Cluster
item: agd-v2/ocp-cluster-cnv-pools/prod
parameter_values:
cluster_size: multinode
host_ocp4_installer_version: "4.20"
ocp4_fips_enable: false
num_users: "{{ num_users }}"
- SNO:
config: openshift-workloads
cloud_provider: none
clusters:
- default:
api_url: "{{ openshift_api_url }}"
api_token: "{{ openshift_cluster_admin_token }}"
__meta__:
components:
- name: openshift
display_name: OpenShift Cluster
item: agd-v2/ocp-cluster-cnv-pools/prod
parameter_values:
cluster_size: sno
host_ocp4_installer_version: "4.20"
ocp4_fips_enable: false
- AWS:
cloud_provider: aws
config: cloud-vms-base
# Define security groups and instances
security_groups:
- name: BastionSG
rules:
- name: SSH
from_port: 22
to_port: 22
protocol: tcp
cidr: "0.0.0.0/0"
rule_type: Ingress
instances:
- name: bastion
count: 1
image: RHEL-10.0-GOLD-latest
flavor:
ec2: t3a.large
security_groups:
- BastionSG
- CNV VMs:
cloud_provider: openshift_cnv
config: cloud-vms-base
instances:
- name: bastion
count: 1
image: rhel-9.6
cores: 8
memory: 16G
image_size: 200Gi
Step 5: Authentication Setup
🔐 Authentication Method
How should users authenticate to OpenShift?
1. htpasswd (Simple username/password - Most common)
└─ Workload: agnosticd.core_workloads.ocp4_workload_authentication_htpasswd
2. Keycloak SSO (Enterprise authentication - For AAP/complex setups)
└─ Workload: agnosticd.core_workloads.ocp4_workload_authentication_keycloak
Q: Authentication method [1-2]:
Set workload based on choice:
- htpasswd:
workloads:
- agnosticd.core_workloads.ocp4_workload_authentication_htpasswd
# ... other workloads
# htpasswd configuration
common_password: "{{ (guid[:5] | hash('md5') | int(base=16) | b64encode)[:8] }}"
ocp4_workload_authentication_htpasswd_admin_user: admin
ocp4_workload_authentication_htpasswd_admin_password: "{{ common_password }}"
ocp4_workload_authentication_htpasswd_user_base: user
ocp4_workload_authentication_htpasswd_user_password: "{{ common_password }}"
ocp4_workload_authentication_htpasswd_user_count: "{{ num_users | default('1') }}"
ocp4_workload_authentication_htpasswd_remove_kubeadmin: true
- Keycloak:
workloads:
- agnosticd.core_workloads.ocp4_workload_authentication_keycloak
# ... other workloads
# Keycloak configuration
common_password: "{{ (guid[:5] | hash('md5') | int(base=16) | b64encode)[:8] }}"
ocp4_workload_authentication_keycloak_namespace: keycloak
ocp4_workload_authentication_keycloak_channel: stable-v26.2
ocp4_workload_authentication_keycloak_admin_username: admin
ocp4_workload_authentication_keycloak_admin_password: "{{ common_password }}"
ocp4_workload_authentication_keycloak_num_users: "{{ num_users }}"
ocp4_workload_authentication_keycloak_user_username_base: user
ocp4_workload_authentication_keycloak_user_password: "{{ common_password }}"
ocp4_workload_authentication_keycloak_remove_kubeadmin: true
Step 6: Workload Selection
🧩 Workload Selection
I'll recommend workloads based on your catalog.
Q: What technologies will users learn? (comma-separated)
Examples: ansible aap, openshift ai, gitops, pipelines
Technologies:
Workload recommendation engine:
Based on keywords, suggest from workload-mappings.md:
ansibleoraap→rhpds.aap25.ocp4_workload_aap25aiorgpu→rhpds.nvidia_gpu.ocp4_workload_nvidia_gpugitopsorargocd→rhpds.openshift_gitops.ocp4_workload_openshift_gitopspipelines→rhpds.openshift_pipelines.ocp4_workload_openshift_pipelinesshowroom→rhpds.showroom.ocp4_workload_showroom(always recommended)
Present recommendations:
Recommended workloads:
✓ rhpds.ocp4_workload_authentication.ocp4_workload_authentication (selected - auth)
✓ rhpds.showroom.ocp4_workload_showroom (recommended - guide)
rhpds.aap25.ocp4_workload_aap25 (suggested - ansible)
rhpds.openshift_gitops.ocp4_workload_openshift_gitops (suggested - gitops)
Select workloads (comma-separated numbers, or 'all'):
Step 7: Showroom Repository Detection
📚 Showroom Content
Q: Do you have a Showroom repository for this catalog? [Y/n]
If YES:
Q: Showroom repository URL:
Example: https://github.com/rhpds/showroom-ansible-ai
URL:
If NO:
ℹ️ You can add the Showroom URL later in common.yaml
Step 8: Catalog Details
📝 Catalog Details
Q: Display name (appears in RHDP UI):
Example: Ansible Automation Platform with OpenShift AI
Name:
Q: Short name (lowercase, hyphens, descriptive):
Example: ansible-aap-ai-workshop
Short name:
Q: Brief description (1-2 sentences):
This appears in the catalog listing.
Description:
Validate directory doesn't exist:
if [[ -d "$AGV_PATH/agd_v2/$short_name" ]]; then
echo "⚠️ Directory already exists: $short_name"
echo "Choose a different name."
fi
Step 8a: Repository Setup
📦 Repository Configuration
Ask about Showroom repository:
Q: Do you have a Showroom repository created for this catalog? [Y/n]
If NO:
📚 Create Showroom Repository
Use the Showroom Nookbag template to create your repository:
Repository: https://github.com/rhpds/showroom_template_nookbag
Instructions:
1. Visit: https://github.com/rhpds/showroom_template_nookbag
2. Follow the README to generate your showroom repository
3. Recommended naming: {short-name}-showroom
4. Create in: github.com/rhpds organization
Example:
Use the nookbag template to create your repository:
https://github.com/rhpds/showroom_template_nookbag
Once created, come back and re-run this skill with the repository URL.
⏸️ Pausing - Create your Showroom repository first.
If YES:
Q: Showroom repository URL:
Example: https://github.com/rhpds/ansible-aap-ai-showroom
Showroom URL:
Ask about custom Ansible collection:
Q: Will this catalog use a custom Ansible collection? [Y/n]
ℹ️ Custom collections are needed when:
- Creating new workloads specific to this catalog
- Sharing workload logic across multiple catalogs
- Building reusable automation components
If YES:
Collection naming: rhpds.{short-name}
Repository: https://github.com/rhpds/rhpds.{short-name}
Note:
- Collection must be created in github.com/rhpds organization
- Will be added to requirements_content in common.yaml
- Use this for catalog-specific workloads
Example structure:
rhpds.{short-name}/
├── galaxy.yml
├── roles/
│ └── ocp4_workload_{catalog_feature}/
└── README.md
If NO:
✓ Using standard collections only (agnosticd.core_workloads, agnosticd.showroom, etc.)
Step 9: Multi-User Configuration
👥 Multi-User Setup
Auto-set based on category:
- Workshops / Brand_Events: Multiuser REQUIRED
- Demos: Single-user only (multiuser: false)
- Labs / Sandboxes: Ask user
If multi-user (Workshops/Brand_Events):
Q: How many concurrent users (maximum)?
Typical range: 10-60
Default: 30
Max users [default: 30]:
Set in common.yaml:
__meta__:
catalog:
multiuser: true
workshopLabUiRedirect: true # Auto-enable for workshops
parameters:
- name: num_users
description: Number of users to provision within the environment
formLabel: User Count
openAPIV3Schema:
type: integer
default: 3
minimum: 3
maximum: 60
Worker scaling formula (if CNV/SNO):
# Auto-scale workers based on num_users
openshift_cnv_scale_cluster: "{{ (num_users | int) > 3 }}"
# Per-user resource calculation
# Example: 1 worker per 5 users (adjust based on workload)
worker_instance_count: "{{ [(num_users | int / 5) | round(0, 'ceil') | int, 1] | max if (num_users | int) > 3 else 0 }}"
ai_workers_cores: 32
ai_workers_memory: 128Gi
If single-user (Demos):
__meta__:
catalog:
multiuser: false # Demos are always single-user
# NO workshopLabUiRedirect for demos
Step 10: Generate Files
Now generate all four files:
10.1: Generate common.yaml
Modern catalog structure (2026+):
---
#include /includes/agd-v2-mapping.yaml
#include /includes/sandbox-api.yaml
#include /includes/catalog-icon-openshift.yaml # or catalog-icon-project-dance, catalog-icon-rh-ai-2025
#include /includes/terms-of-service.yaml
#include /includes/access-restriction-rh1-2026-devs.yaml # Optional - for restricted catalogs
#include /includes/parameters/purpose.yaml
#include /includes/parameters/salesforce-id.yaml
#include /includes/parameters/num-users-salesforce.yaml # If multi-user
#include /includes/secrets/ocp4_ai_offline_token.yaml
#include /includes/secrets/s3-rhpds-private-bucket.yaml
# -------------------------------------------------------------------
# --- Catalog Item: <Display Name>
# -------------------------------------------------------------------
# ===================================================================
# Repository Tag
# Tag for all repositories that are used in this config.
# ===================================================================
tag: main # Override in prod.yaml, event.yaml with specific tag (e.g., <short-name>-1.0.0)
# -------------------------------------------------------------------
# Mandatory Variables
# -------------------------------------------------------------------
config: openshift-workloads
cloud_provider: none
software_to_deploy: none
openshift_cnv_scale_cluster: true
clusters:
- default:
api_url: "{{ openshift_api_url }}"
api_token: "{{ openshift_cluster_admin_token }}"
# -------------------------------------------------------------------
# Platform
# -------------------------------------------------------------------
platform: rhpds
# -------------------------------------------------------------------
# CNV Specific (if using CNV pools)
# -------------------------------------------------------------------
bastion_instance_image: rhel-9.6
bastion_cores: 2
bastion_memory: 4Gi
# Worker scaling formula
worker_instance_count: "{{ [2, ((num_users | int / 5.0) | round(0, 'ceil') | int) + 1] | max }}"
ai_workers_cores: 32
ai_workers_memory: 128Gi
# -------------------------------------------------------------------
# Common Password
# -------------------------------------------------------------------
common_password: "{{ (guid[:5] | hash('md5') | int(base=16) | b64encode)[:8] }}"
# -------------------------------------------------------------------
# Student User on Bastion (if needed)
# -------------------------------------------------------------------
install_student_user: true
student_name: lab-user
student_sudo: true
# -------------------------------------------------------------------
# Custom collections for this environment
# -------------------------------------------------------------------
requirements_content:
collections:
- name: https://github.com/agnosticd/core_workloads.git
type: git
version: main
- name: https://github.com/agnosticd/showroom.git
type: git
version: v1.3.9
# Add other collections as needed
# -------------------------------------------------------------------
# Workloads
# -------------------------------------------------------------------
workloads:
- agnosticd.core_workloads.ocp4_workload_authentication_htpasswd
- agnosticd.showroom.ocp4_workload_showroom_ocp_integration
- agnosticd.showroom.ocp4_workload_showroom
# Add technology-specific workloads
# ===================================================================
# Workload: ocp4_workload_authentication_htpasswd
# ===================================================================
ocp4_workload_authentication_htpasswd_admin_user: admin
ocp4_workload_authentication_htpasswd_admin_password: "{{ common_password }}"
ocp4_workload_authentication_htpasswd_user_base: user
ocp4_workload_authentication_htpasswd_user_password: "{{ common_password }}"
ocp4_workload_authentication_htpasswd_user_count: "{{ num_users | default('1') }}"
ocp4_workload_authentication_htpasswd_remove_kubeadmin: true
# ===================================================================
# Workload: ocp4_workload_showroom
# ===================================================================
ocp4_workload_showroom_content_git_repo: https://github.com/rhpds/showroom-repo.git
ocp4_workload_showroom_content_git_repo_ref: main
# -------------------------------------------------------------------
# Metadata
# -------------------------------------------------------------------
__meta__:
asset_uuid: <generated-uuid>
anarchy:
namespace: babylon-anarchy-7
components:
- name: openshift
display_name: OpenShift Cluster
item: agd-v2/ocp-cluster-cnv-pools/prod
parameter_values:
cluster_size: multinode # or sno
host_ocp4_installer_version: "4.20"
ocp4_fips_enable: false
num_users: "{{ num_users }}"
propagate_provision_data:
- name: sandbox_openshift_api_key
var: sandbox_openshift_api_key
- name: sandbox_openshift_api_url
var: sandbox_openshift_api_url
- name: sandbox_openshift_namespace
var: sandbox_openshift_namespace
- name: openshift_cluster_admin_token
var: openshift_cluster_admin_token
- name: openshift_api_url
var: openshift_api_url
- name: bastion_public_hostname
var: bastion_ansible_host
- name: bastion_ssh_user_name
var: bastion_ansible_user
- name: bastion_ssh_password
var: bastion_ansible_ssh_pass
- name: bastion_ssh_port
var: bastion_ansible_port
catalog:
namespace: babylon-catalog-{{ stage | default('?') }}
display_name: "<Display Name>"
category: <Workshops|Demos|Labs|Sandboxes|Brand_Events>
multiuser: true # or false for demos
workshopLabUiRedirect: true # Only for workshops
parameters:
- name: num_users
description: Number of users to provision within the environment
formLabel: User Count
openAPIV3Schema:
type: integer
default: 3
minimum: 3
maximum: 60
keywords:
- <keyword1>
- <keyword2>
labels:
Provider: RHDP
Product: <Product_Name>
Product_Family: <Product_Family>
# Brand_Event: Red_Hat_One_2026 # If Brand_Events
reportingLabels:
primaryBU: Hybrid_Platforms # CRITICAL: For business unit tracking/reporting (Hybrid_Platforms, Application_Services, Ansible, RHEL, etc.)
owners:
maintainer:
- email: <email>
name: <Name>
sme:
- email: <sme-email>
name: <SME Name>
tower:
timeout: 14400 # 4 hours - adjust based on complexity
deployer:
scm_url: https://github.com/agnosticd/agnosticd-v2
scm_ref: main
execution_environment:
image: quay.io/agnosticd/ee-multicloud:chained-2025-12-17
pull: missing
10.2: Generate dev.yaml
---
# -------------------------------------------------------------------
# Purpose - Cost tag. One of development, ilt, production, event
# -------------------------------------------------------------------
purpose: development
__meta__:
deployer:
scm_ref: main
scm_type: git
Note: dev.yaml is minimal - only overrides scm_ref and sets purpose tag for cost tracking.
10.3: Generate description.adoc
Ask for description content:
📄 Description Generation
I can extract description content from your Showroom, or you can provide it manually.
Q: Do you want me to extract from Showroom content? [Y/n]
If YES and Showroom URL provided:
# Clone showroom temporarily
temp_dir=$(mktemp -d)
git clone <showroom-url> "$temp_dir"
# Extract modules
find "$temp_dir/content/modules/ROOT/pages" -name "*.adoc" | sort
# Read module titles
grep "^= " "$temp_dir/content/modules/ROOT/pages"/*.adoc
Generate description.adoc:
= <Display Name>
== Overview
<Product Name> provides... (2-3 sentences starting with product, NOT "This workshop")
NOTE: Add any warnings here (GPU requirements, etc.)
== Guide
link:<github-pages-url>[Open Guide^,role=params-link]
== Featured Products and Technologies
* Product Name Version
* Another Product Version
== Agenda
* Module 1: <title>
* Module 2: <title>
* Module 3: <title>
== Authors
* <Author Name> - mailto:<email>[<email>] - <slack-handle>
For questions or feedback, reach out in Slack: [#forum-demo-developers](https://redhat.enterprise.slack.com/archives/C04MLMA15MX)
10.4: Generate info-message-template.adoc
📧 Info Message Template
This template displays user data after deployment.
Q: Does your catalog use agnosticd_user_info to share data? [Y/n]
If YES:
Q: What data keys does your workload share via agnosticd_user_info.data?
Examples:
- litellm_api_base_url
- litellm_virtual_key
- grafana_admin_password
Data keys (comma-separated):
Generate info-message-template.adoc:
= Environment Provisioned
Your <catalog-name> environment has been provisioned successfully!
== Access Information
* *Console URL*: {openshift_console_url}
* *Username*: {openshift_cluster_admin_username}
* *Password*: {openshift_cluster_admin_password}
== Guide
Access your workshop guide:
* link:{openshift_cluster_console_url}/showroom[Workshop Guide^]
== Additional Information
=== <Service Name>
* *API URL*: {<data_key_1>}
* *API Key*: {<data_key_2>}
NOTE: The data above comes from `agnosticd_user_info.data` in your workload.
== Support
Questions? Reach out in Slack: [#forum-demo-developers](https://redhat.enterprise.slack.com/archives/C04MLMA15MX)
Explain agnosticd_user_info:
ℹ️ How to share data from your workload:
In your workload tasks/workload.yml:
- name: Save user data for info message
agnosticd.core.agnosticd_user_info:
data:
my_api_url: "{{ api_base_url }}"
my_api_key: "{{ virtual_key }}"
Then use in info-message-template.adoc:
* API URL: {my_api_url}
* API Key: {my_api_key}
The template renders when users receive their environment.
If NO user data:
= Environment Provisioned
Your <catalog-name> environment is ready!
== Access Information
* *Console URL*: {openshift_console_url}
* *Username*: {openshift_cluster_admin_username}
* *Password*: {openshift_cluster_admin_password}
== Workshop Guide
link:{openshift_cluster_console_url}/showroom[Open Guide^]
== Support
Questions? [#forum-demo-developers](https://redhat.enterprise.slack.com/archives/C04MLMA15MX)
Step 11: Write Files
💾 Writing Files
Creating catalog directory: agd_v2/<directory-name>/
Writing:
✓ common.yaml
✓ dev.yaml
✓ description.adoc
✓ info-message-template.adoc
Execute:
mkdir -p "$AGV_PATH/agd_v2/$directory_name"
# Write all four files
cat > "$AGV_PATH/agd_v2/$directory_name/common.yaml" <<'EOF'
<generated-content>
EOF
cat > "$AGV_PATH/agd_v2/$directory_name/dev.yaml" <<'EOF'
<generated-content>
EOF
cat > "$AGV_PATH/agd_v2/$directory_name/description.adoc" <<'EOF'
<generated-content>
EOF
cat > "$AGV_PATH/agd_v2/$directory_name/info-message-template.adoc" <<'EOF'
<generated-content>
EOF
Step 12: Git Commit (Optional)
🚀 Ready to Commit
Files created in: agd_v2/<directory-name>/
Q: Commit these changes? [Y/n]
If YES:
cd "$AGV_PATH"
git add "agd_v2/$directory_name/"
git commit -m "Add $directory_name catalog
- Category: $category
- Infrastructure: $cloud_provider ($sandbox_architecture)
- Workloads: $num_workloads selected
- UUID: $asset_uuid"
echo "✓ Committed to branch: $branch_name"
echo ""
echo "Next steps:"
echo " 1. Test locally: agnosticv_cli dev.yaml"
echo " 2. Run validator: /agnosticv-validator"
echo " 3. Create PR: gh pr create --fill"
MODE 2: Description Only
When selected: User chose option 2 (Description Only)
Simplified workflow - just extract from Showroom and generate description.adoc
Step 1: Locate Showroom
📚 Showroom Content
Q: Path to your Showroom repository:
(Press Enter to use current directory)
Path:
Validate:
if [[ -d "$path/content/modules/ROOT/pages" ]]; then
echo "✓ Found Showroom content"
else
echo "✗ No Showroom content found at: $path/content/modules/ROOT/pages"
exit 1
fi
Step 2: Extract Content
Auto-extract:
# Get modules
modules=$(find "$path/content/modules/ROOT/pages" -name "*.adoc" -not -name "index.adoc" | sort)
# Extract titles
while read module; do
title=$(grep "^= " "$module" | head -1 | sed 's/^= //')
echo "* $title"
done <<< "$modules"
# Detect technologies
grep -h "OpenShift\|Ansible\|AAP\|GitOps" "$path/content/modules/ROOT/pages"/*.adoc | head -5
# Get git author
author=$(git config user.name)
# Get GitHub Pages URL from remote
remote=$(git -C "$path" remote get-url origin)
github_pages_url=$(echo "$remote" | sed 's|git@github.com:|https://|' | sed 's|\.git$|/|' | sed 's|github.com/|rhpds.github.io/|')
Step 3: Generate Description
Ask for missing details:
📝 Description Details
Auto-extracted:
✓ Modules: <count> found
✓ Author: <git-name>
✓ Guide URL: <github-pages-url>
Q: Brief overview (2-3 sentences, starting with product name):
Overview:
Q: Featured technologies (comma-separated with versions):
Suggested: <detected-technologies>
Technologies:
Q: Any warnings? (GPU, resources, etc.) [optional]
Warnings:
Generate and write description.adoc (same format as Mode 1, Step 10.3)
Step 4: Locate Output Directory
📂 Output Location
Q: Where should I save description.adoc?
1. Auto-detect AgV catalog path
2. Specify custom path
Choice [1/2]:
If option 1:
# Look for existing catalog in AgV
catalog_dirs=$(find "$AGV_PATH/agd_v2" -type f -name "common.yaml" -exec dirname {} \;)
# Match by name similarity
echo "Found catalogs:"
echo "$catalog_dirs"
echo ""
echo "Q: Which catalog? (or 'none' for custom path)"
Write file and optionally commit (same as Mode 1, Step 12)
MODE 3: Info Message Template Only
When selected: User chose option 3 (Info Message Template)
Step 1: Locate Catalog
📂 Catalog Location
Q: Path to your AgV catalog directory:
Example: ~/work/code/agnosticv/agd_v2/my-catalog
Path:
Step 2: User Data Configuration
📧 Info Message Template
This template uses data from agnosticd_user_info.
Q: Does your workload share data via agnosticd_user_info? [Y/n]
If YES:
Q: List the data keys your workload shares (comma-separated):
Examples:
- litellm_api_base_url, litellm_virtual_key
- grafana_url, grafana_password
- custom_service_url, custom_api_key
Data keys:
Generate template (same as Mode 1, Step 10.4)
Write file and optionally commit
Common Git Workflow (All Modes)
After generating files, always offer to commit:
🚀 Commit Changes
Branch: <branch-name>
Files modified:
- agd_v2/<catalog-name>/...
Q: Commit these changes? [Y/n]
If YES:
cd "$AGV_PATH"
git add <files>
git commit -m "<appropriate-message>"
echo "✓ Committed to branch: $branch_name"
echo ""
echo "Next steps:"
echo " 1. Push: git push origin $branch_name"
echo " 2. Create PR: gh pr create --fill"
echo " 3. Validate: /agnosticv-validator"
Validation & Testing
After file generation, guide users to validate:
✅ Next Steps
Your catalog files are ready!
Recommended actions:
1. Validate configuration:
/agnosticv-validator
2. Test locally (if you have agnosticd-cli):
cd agd_v2/<catalog-name>
agnosticd_cli dev.yaml
3. Create pull request:
git push origin <branch-name>
gh pr create --fill
4. Request review in [#forum-demo-developers](https://redhat.enterprise.slack.com/archives/C04MLMA15MX)
Error Handling
UUID collision:
⚠️ UUID collision detected!
The generated UUID already exists in:
<path-to-existing-catalog>
Regenerating new UUID...
Invalid category:
⚠️ Category must be exactly one of:
- Workshops
- Demos
- Sandboxes
(Case-sensitive, plural form)
Showroom not found:
⚠️ Showroom content not found at: <path>
Expected structure:
content/modules/ROOT/pages/*.adoc
Please check the path and try again.
Branch name with feature/:
⚠️ Branch names should NOT include 'feature/' prefix.
Instead of: feature/add-workshop
Use: add-workshop
Please provide a branch name without 'feature/':
Smart Features
Auto-Detection
- Showroom module structure
- GitHub Pages URL from git remote
- Author name from git config
- Technology keywords in content
- Existing catalog directories
Recommendations
- Workloads based on technology keywords
- Infrastructure based on catalog type
- Multi-user settings based on category
Validation
- UUID uniqueness
- Category exact match
- Directory name conflicts
- Branch naming conventions
- Showroom content structure
Best Practices
- Always pull main before starting - Ensures latest catalog patterns
- Use descriptive branch names - No feature/ prefix, just: add-catalog-name
- Validate before PR - Use /agnosticv-validator
- Test in dev first - Use dev.yaml for testing
- Document user data - Clear info-message-template.adoc
- Start with product name - Description overview must start with product, not "This workshop"
Example Sessions
Example 1: Full Catalog Creation
User: /agnosticv-catalog-builder
Skill: 🏗️ AgnosticV Catalog Builder
What would you like to create or update?
1. Full Catalog (common.yaml, dev.yaml, description.adoc, info-message-template.adoc)
2. Description Only (description.adoc)
3. Info Message Template (info-message-template.adoc)
Your choice [1-3]: 1
Q: AgnosticV repository path: ~/work/code/agnosticv
🔧 Git Workflow Setup
Current branch: main
📥 Pulling latest changes from main...
Already up to date.
Q: Branch name (without feature/): add-ansible-ai-workshop
🌿 Creating branch: add-ansible-ai-workshop
Switched to a new branch 'add-ansible-ai-workshop'
📖 Catalog Discovery
Q: Keywords for search: ansible ai
Found similar catalogs:
1. ansible-aap-workshop (Ansible Automation Platform Self-Service)
2. ansible-automation-mesh (Ansible Automation Mesh on OpenShift)
Choice: A (Create new from scratch)
📂 Category: 1 (Workshops)
🔑 UUID: a1b2c3d4-e5f6-7890-abcd-ef1234567890 (validated)
🏗️ Infrastructure: 1 (CNV Multi-Node)
🔐 Authentication: 1 (htpasswd)
🧩 Workload Selection
Technologies: ansible aap, openshift ai
Recommended workloads:
✓ rhpds.ocp4_workload_authentication.ocp4_workload_authentication
✓ rhpds.showroom.ocp4_workload_showroom
✓ rhpds.aap25.ocp4_workload_aap25
✓ rhpds.openshift_ai.ocp4_workload_openshift_ai
📚 Showroom: https://github.com/rhpds/showroom-ansible-ai
📝 Display name: Ansible Automation with OpenShift AI
📝 Description: Learn to build intelligent automation using Ansible and OpenShift AI
📝 Directory: ansible-ai-workshop
👥 Multi-user: Y (30 users)
📄 Extract description from Showroom: Y
💾 Writing files to: agd_v2/ansible-ai-workshop/
✓ common.yaml
✓ dev.yaml
✓ description.adoc
✓ info-message-template.adoc
🚀 Commit: Y
✓ Committed to branch: add-ansible-ai-workshop
Next steps:
1. Validate: /agnosticv-validator
2. Push: git push origin add-ansible-ai-workshop
3. Create PR: gh pr create --fill
Example 2: Description Only
User: /agnosticv-catalog-builder
What would you like to create or update?
Your choice [1-3]: 2
Q: AgnosticV repository path: ~/work/code/agnosticv
🔧 Git Workflow Setup
Current branch: update-ocp-pipelines
⚠️ You're on: update-ocp-pipelines
Switch to main? Y
📥 Pulling main...
Q: Branch name: update-ocp-pipelines-description
📚 Showroom path: ~/work/code/showroom-ocp-pipelines
✓ Found 5 modules
Auto-extracted:
✓ Modules: Introduction, Deploy App, Create Pipeline, Add Tests, Deploy to Prod
✓ Author: Prakhar Srivastava
✓ Guide: https://rhpds.github.io/showroom-ocp-pipelines
Q: Overview: OpenShift Pipelines enables cloud-native CI/CD using Tekton...
Q: Technologies: OpenShift 4.17, OpenShift Pipelines 1.15
Q: Warnings: [none]
📂 Output location: 1 (Auto-detect)
Found: agd_v2/openshift-pipelines-intro/
💾 Writing description.adoc
🚀 Commit: Y
✓ Updated description.adoc
Example 3: Info Message Template Only
User: /agnosticv-catalog-builder
Your choice [1-3]: 3
Q: AgnosticV repository path: ~/work/code/agnosticv
🔧 Git Workflow Setup
Q: Branch name: add-litellm-info-message
📂 Catalog: ~/work/code/agnosticv/agd_v2/litellm-virtual-keys/
📧 Info Message Template
Q: Uses agnosticd_user_info? Y
Q: Data keys: litellm_api_base_url, litellm_virtual_key, litellm_available_models_list
ℹ️ How to share data from your workload:
In tasks/workload.yml:
- name: Save LiteMaaS credentials
agnosticd.core.agnosticd_user_info:
data:
litellm_api_base_url: "{{ litellm_api_base_url }}"
litellm_virtual_key: "{{ litellm_virtual_key }}"
litellm_available_models_list: "{{ litellm_available_models | join(', ') }}"
Template usage:
* API URL: {litellm_api_base_url}
* API Key: {litellm_virtual_key}
* Models: {litellm_available_models_list}
💾 Writing info-message-template.adoc
🚀 Commit: Y
✓ Created info-message-template.adoc
References
Related Skills
/agnosticv-validator- Validate catalog configuration/create-lab- Create Showroom workshop content/ftl- Create graders/solvers for workshop testing
Documentation
~/.claude/docs/workload-mappings.md- Technology to workload mapping~/.claude/docs/infrastructure-guide.md- Infrastructure selection guide
Key Files Generated
common.yaml - Main catalog configuration
asset_uuid: <uuid>
name: Display Name
description: Brief description
category: Workshops|Demos|Sandboxes
cloud_provider: equinix_metal|ec2
sandbox_architecture: standard|single-node
num_users: <number>
student_guide_url: <github-pages>
workloads:
- namespace.collection.role
dev.yaml - Development overrides
cloud_provider: "{{ cloud_provider }}"
sandbox_architecture: "{{ sandbox_architecture }}"
num_users: 1
description.adoc - UI catalog description
= Display Name
== Overview
Product description starting with product name...
== Guide
link:url[Open Guide]
== Featured Products
* Product Version
== Agenda
* Module titles
== Authors
* Name - contact
info-message-template.adoc - User notification template
= Environment Provisioned
== Access Information
* Console: {openshift_console_url}
* Username: {openshift_cluster_admin_username}
== Additional Data
* Service URL: {custom_data_key}
Variables come from agnosticd_user_info.data
Troubleshooting
Branch Creation Fails
Problem: fatal: A branch named 'X' already exists
Solution:
# List branches
git branch -a
# Delete local branch if needed
git branch -D old-branch-name
# Or use different name
UUID Collision
Problem: Generated UUID already exists
Solution: Skill auto-regenerates. If persistent, check for corrupted catalogs.
Showroom Not Detected
Problem: Cannot find content/modules/ROOT/pages/
Solution:
# Verify structure
ls -la ~/path/to/showroom/content/modules/ROOT/pages/
# Should contain .adoc files
Git Not Clean
Problem: Uncommitted changes prevent branch creation
Solution:
# Stash changes
git stash
# Or commit them first
git add .
git commit -m "WIP"
Workload Not Found
Problem: Selected workload doesn't exist in collections
Solution: Check ~/.claude/docs/workload-mappings.md for correct namespace.collection.role format
Important Reminders
⚠️ Branch Naming
- NO
feature/prefix - YES descriptive names:
add-catalog-name,update-description
⚠️ Description Overview
- NO starting with "This workshop/demo/lab..."
- YES starting with product name: "OpenShift Pipelines enables..."
⚠️ Category Values
- Must be exact match:
Workshops,Demos, orSandboxes - Plural form required
- Case-sensitive
⚠️ Info Message Variables
- List/array variables from Ansible don't render in AsciiDoc
- Convert to strings:
{{ my_list | join(', ') }} - Example:
litellm_available_models_list: "{{ litellm_available_models | join(', ') }}"
⚠️ Git Workflow
- Always pull main first
- Create new branch for each catalog
- Commit with descriptive messages
- Test before creating PR
Success Criteria
After using this skill, you should have:
For Full Catalog:
- ✅ Clean git branch (pulled main, no feature/ prefix)
- ✅ Four files created (common.yaml, dev.yaml, description.adoc, info-message-template.adoc)
- ✅ Valid UUID (lowercase, RFC 4122, unique)
- ✅ Correct category (exact match)
- ✅ Appropriate workloads for technologies
- ✅ Showroom integration configured
- ✅ Ready for validation and PR
For Description Only:
- ✅ Clean git branch
- ✅ description.adoc with extracted content
- ✅ Overview starts with product name
- ✅ Module agenda from Showroom
- ✅ Author and contact info
- ✅ GitHub Pages link
For Info Message Template:
- ✅ Clean git branch
- ✅ info-message-template.adoc with user data placeholders
- ✅ Documented how to use agnosticd_user_info
- ✅ String formatting for lists/arrays
- ✅ Clear variable names
Version History
- 2.0.0 (2026-01-22) - Unified skill combining agv-generator and generate-agv-description
- 1.0.0 (2026-01-15) - Initial separate skills (deprecated)
End of Skill Documentation
Score
Total Score
Based on repository quality metrics
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
3ヶ月以内に更新がある
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
Reviews
Reviews coming soon