
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
スコア
総合スコア
リポジトリの品質指標に基づく評価
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
3ヶ月以内に更新がある
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
レビュー
レビュー機能は近日公開予定です