ftl:rhdp-lab-validator
This skill should be used when the user asks to "write solve and validate playbooks", "add E2E testing to my lab", "generate solve.yml", "generate validate.yml", "add solve and validate buttons", "set up runtime automation", "add ZT grading to my lab", "set up load testing for my lab", "add Demolition grading", or "configure run_e2e_load_test".
Best use case
ftl:rhdp-lab-validator is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
This skill should be used when the user asks to "write solve and validate playbooks", "add E2E testing to my lab", "generate solve.yml", "generate validate.yml", "add solve and validate buttons", "set up runtime automation", "add ZT grading to my lab", "set up load testing for my lab", "add Demolition grading", or "configure run_e2e_load_test".
Teams using ftl:rhdp-lab-validator should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/rhdp-lab-validator/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How ftl:rhdp-lab-validator Compares
| Feature / Agent | ftl:rhdp-lab-validator | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
This skill should be used when the user asks to "write solve and validate playbooks", "add E2E testing to my lab", "generate solve.yml", "generate validate.yml", "add solve and validate buttons", "set up runtime automation", "add ZT grading to my lab", "set up load testing for my lab", "add Demolition grading", or "configure run_e2e_load_test".
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Skill: FTL Lab Validator — Orchestrator
Orchestrates 4 agents to write and test `solve.yml` and `validate.yml` playbooks for RHDP Showroom labs:
| Agent | Job |
|---|---|
| `ftl:content-reader` | Reads .adoc module, extracts tasks and expected outcomes |
| `ftl:solve-writer` | Writes solve.yml from content-reader output |
| `ftl:validate-writer` | Writes validate.yml from content-reader + solve-writer output |
| `ftl:env-connector` | Pushes, restarts, runs full test cycle, reports pass/fail |
Agents talk through this orchestrator — each agent's output is passed as input to the next.
---
## Step 0: Pre-flight Check
Show this message before asking anything else:
```
Before using this skill, make sure two things are ready:
═══ 1. SHOWROOM REPO ════════════════════════════════════════════
Sync from: github.com/rhpds/showroom_template_nookbag (e2e-template branch)
Copy these into your showroom repo:
content/supplemental-ui/js/buttons.js
content/supplemental-ui/css/site-extra.css
content/lib/inject-buttons.js
content/lib/dev-mode.js
runtime-automation/module-XX/solve.yml ← one dir per module
runtime-automation/module-XX/validate.yml
Your site.yml must have these extensions and supplemental_files configured:
ui:
supplemental_files:
- path: ./content/supplemental-ui
- path: ./content/lib
- path: ui.yml
contents: "static_files: [ .nojekyll, css/site-extra.css, js/buttons.js ]"
antora:
extensions:
- require: ./content/lib/dev-mode.js
enabled: false
- require: ./content/lib/inject-buttons.js
Add solve/validate button placeholders to each .adoc module that needs them.
═══ 2. AgV CATALOG (common.yaml) ═══════════════════════════════
• rhpds-ftl collection in requirements_content
• showroom collection v1.6.6 or later (earlier versions silently
ignore runtime_automation vars — runner will not deploy)
• ocp4_workload_runtime_automation_k8s workload (OCP tenant/dedicated)
or vm_workload_runtime_automation (RHEL VM)
• zt-runner image: quay.io/rhpds/zt-runner:v2.4.2
• wetty image: quay.io/rhpds/wetty:v3.0
See examples/ in the e2e-template branch for exact common.yaml config:
github.com/rhpds/showroom_template_nookbag/tree/e2e-template
═════════════════════════════════════════════════════════════════
Ready? Tell me:
1. Lab type: ocp-tenant / ocp-dedicated / vm-rhel
2. Path to your showroom repo (local path or GitHub URL)
3. Access:
OCP labs — provide a cluster admin token, OR log in with
`oc login` and restart Claude so it inherits
your kubeconfig
VM labs — provide SSH host, user, and key path
(or paste your SSH config block)
4. Existing files: Do you already have solve.yml or validate.yml
for any modules? If yes, paste them or share the paths now.
I'll use them as the baseline and only fill in what's missing
instead of generating from scratch.
```
Wait for the user to reply before proceeding.
**If user provides existing files (Step 4 above):**
- Read the existing solve.yml and validate.yml
- Skip `ftl:content-reader` and `ftl:solve-writer`/`ftl:validate-writer` for those modules
- Go directly to `ftl:env-connector` to test the existing files
- Only re-invoke the writer agents if env-connector reports failures
---
## Step 1: Setup
Collect from user reply:
- `lab_type` — `ocp-tenant` | `ocp-dedicated` | `vm-rhel`
- `showroom_path` — local path or GitHub URL (clone to `/tmp/<repo>` if URL)
- Access details
**Verify the showroom repo has the required E2E files:**
```bash
ls <showroom_path>/content/lib/inject-buttons.js \
<showroom_path>/content/lib/dev-mode.js \
<showroom_path>/content/supplemental-ui/js/buttons.js 2>/dev/null
```
If any are missing, tell the user which files to copy from the e2e-template branch before continuing.
**Check dev.yaml silent override:**
```bash
grep "ocp4_workload_showroom_content_git_repo_ref" <showroom_path>/dev.yaml 2>/dev/null
```
If found → warn the user. This overrides common.yaml and the showroom pod clones the wrong branch.
**OCP tenant — guide environment ordering:**
Run `oc whoami` to confirm login. If no live lab exists:
```
**Order the lab now on demo.redhat.com:**
1. Go to https://demo.redhat.com and find your catalog item
2. Order using your Red Hat SSO user (same user as oc login)
3. Note the GUID from the order confirmation
Come back with the GUID once provisioned.
```
If already provisioned, detect GUID:
```bash
GUID=$(oc get namespaces -o name | grep showroom | head -1 | sed 's|namespace/showroom-||')
echo "GUID: $GUID"
```
---
## Step 2: Discover Modules
List all `.adoc` files and identify those with exercises:
```bash
ls <showroom_path>/content/modules/ROOT/pages/*.adoc | sort
```
For each file, do a quick check for numbered exercise steps and button placeholders.
Present summary and ask which modules to process:
```
Found N modules with exercises:
module-01 — <title> (has solve/validate buttons: yes/no)
module-02 — <title> (has solve/validate buttons: yes/no)
Which modules? [all / numbers]
```
**If a module has exercises but no button placeholders**, tell the user:
```
⚠️ module-XX has exercises but no solve/validate button placeholders.
Add these to the module .adoc before or after generating playbooks:
++++
<div class="solve-button-placeholder" data-module="module-XX"></div>
++++
++++
<div class="validate-button-placeholder" data-module="module-XX"></div>
++++
```
Still proceed with playbook generation — buttons can be added separately.
---
## Step 3: Run Agents — One Module at a Time
For each selected module, run all 4 agents in sequence. Pass each agent's output to the next.
---
### 3a — content-reader
Use the **Task tool** with `subagent_type: "ftl:content-reader"`:
```
Task tool:
subagent_type: ftl:content-reader
prompt: |
MODULE_FILE: <showroom_path>/content/modules/ROOT/pages/<module>.adoc
AGV_COMMON: <path to common.yaml if available, else "none">
LAB_TYPE: <lab_type>
```
Wait for the structured task report. Store as `CONTENT_REPORT`.
Show the user a one-line summary:
```
📖 content-reader: found X tasks in <module>
```
---
### 3b — solve-writer
Use the **Task tool** with `subagent_type: "ftl:solve-writer"`:
```
Task tool:
subagent_type: ftl:solve-writer
prompt: |
CONTENT_READER_REPORT: <CONTENT_REPORT>
LAB_TYPE: <lab_type>
REFERENCE_FILE: <absolute path to references/<lab_type>.md>
```
Wait for solve.yml + SOLVE_ACTIONS summary. Store both.
Show the user a preview of solve.yml and ask: `Write solve.yml? [Y/n]`
Write if confirmed:
```bash
mkdir -p <showroom_path>/runtime-automation/<module>
# write solve.yml
```
---
### 3c — validate-writer
Use the **Task tool** with `subagent_type: "ftl:validate-writer"`:
```
Task tool:
subagent_type: ftl:validate-writer
prompt: |
CONTENT_READER_REPORT: <CONTENT_REPORT>
SOLVE_ACTIONS: <SOLVE_ACTIONS from solve-writer>
LAB_TYPE: <lab_type>
```
Wait for validate.yml + VALIDATION_SUMMARY. Store both.
Show the user a preview of validate.yml and ask: `Write validate.yml? [Y/n]`
Write if confirmed:
```bash
# write validate.yml
```
---
### 3d — env-connector
Use the **Task tool** with `subagent_type: "ftl:env-connector"`:
```
Task tool:
subagent_type: ftl:env-connector
prompt: |
LAB_TYPE: <lab_type>
SHOWROOM_PATH: <showroom_path>
MODULE_NAME: <module>
GUID: <guid if known>
ACCESS: <token / kubeconfig / ssh details>
VALIDATION_SUMMARY: <VALIDATION_SUMMARY from validate-writer>
```
env-connector pushes, restarts, and runs the full test cycle:
1. Fresh validate → expect ❌
2. Solve → expect clean
3. Validate after solve → expect ✅
4. Validate again → idempotency check
Wait for TEST_RESULT.
---
## Step 4: Fix Loop
If TEST_RESULT is FAIL:
1. Show the user the exact failing lines from env-connector
2. Determine which agent needs to fix it:
- solve.yml has a `fatal:` error → re-invoke **solve-writer** with the error context
- validate.yml fails after solve → re-invoke **validate-writer** with the error context
- Playwright step failed (output contains `FAILED:` and `INTENT:`) →
**do NOT re-invoke writers yet** — trigger **env-connector self-healing** first:
a. Pull `/tmp/playwright-debug.png` from runner pod
b. Read screenshot + INTENT description with vision
c. Vision generates updated selector for current UI
d. Patch the `.js` file in showroom repo
e. Push and re-run full test cycle
Only re-invoke solve-writer if self-healing fails after 2 attempts
3. Re-invoke the appropriate agent:
```
Re-invoke: ftl:solve-writer | ftl:validate-writer
Pass:
(original inputs)
ERROR_CONTEXT: <raw output from env-connector showing the failure>
INSTRUCTION: Fix the failing task: <task name>
```
4. Preview the fix. Ask: `Apply fix? [Y/n]`
5. Re-invoke **env-connector** for the full test cycle again
6. Repeat until TEST_RESULT is PASS
---
## Step 5: Next Module
When a module passes, move to the next selected module and repeat Step 3.
---
## Step 6: Summary
When all modules pass:
```
✅ All modules pass solve + validate
module-01: fresh ❌ → solve ✅ → validate ✅ → idempotency ✅
module-02: fresh ❌ → solve ✅ → validate ✅ → idempotency ✅
...
Showroom URL: <url>
━━━ Next step ━━━
Order with run_e2e_load_test: true to confirm Demolition-style
automated testing. The load test role calls /stream/solve then
/stream/validate for every module and fails the provision on any ❌.
```Related Skills
health:deployment-validator
Infrastructure Health Checker — use this when you need to validate that a workload or service DEPLOYED SUCCESSFULLY (pods running, routes accessible, dependencies ready). This is NOT for student E2E lab testing. For student exercise validation (solve/validate buttons), use /ftl:rhdp-lab-validator instead. Triggers on: 'create a validation role', 'build health checks', 'add deployment validation', 'create post-deployment checks', 'validate my deployment', 'check if my workload is healthy'.
agnosticv:validator
This skill should be used when the user asks to "validate my catalog", "check my AgnosticV config", "review common.yaml", "validate my RHDP catalog", "check for errors in my catalog", "lint my AgnosticV files", or "verify my catalog before submitting".
showroom:verify-content
This skill should be used when the user asks to "verify my workshop content", "review my lab module", "check my Showroom content", "validate my AsciiDoc module", "quality check my demo", "review my workshop for Red Hat standards", or "run a content review on my lab".
showroom:create-lab
This skill should be used when the user asks to "create a lab module", "write a workshop module", "build a Showroom lab", "convert docs to a lab", "write a hands-on exercise", "create an AsciiDoc module", or "turn this documentation into a lab exercise".
showroom:create-demo
This skill should be used when the user asks to "create a demo module", "write a Know/Show demo", "build a presenter demo", "create a Showroom demo", "write a facilitator guide", "build a demo script", or "create a presenter-led demo for RHDP".
showroom:blog-generate
This skill should be used when the user asks to "turn this lab into a blog post", "write a blog post from this module", "generate a blog from my Showroom content", "convert my workshop to a blog", "write a Red Hat Developer blog post", or "create a blog post from my demo".
agnosticv:catalog-builder
This skill should be used when the user asks to "create a catalog", "build a common.yaml", "add a new RHDP lab", "set up a new catalog item", "create an AgnosticV catalog", "build a dev.yaml", "add a catalog entry", or "create a new lab catalog for RHDP".
sandbox-cli:sandbox-setup
This skill should be used when the user asks to "install sandbox-cli", "setup sandbox", "configure sandbox-cli", "get sandbox-cli working", "download sandbox-cli", or "I don't have sandbox-cli installed".
sandbox-cli:cluster-rotate
This skill should be used when the user asks to "rotate a cluster", "replace a cluster", "swap clusters", "offboard old and onboard new cluster", "cluster rotation", "replace an old cluster with a new one", or "refresh cluster".
sandbox-cli:cluster-onboard
This skill should be used when the user asks to "onboard a cluster", "add a cluster to sandbox", "register a cluster", "onboard OCP cluster", "sandbox onboard", or "add a new shared cluster".
sandbox-cli:cluster-offboard
This skill should be used when the user asks to "offboard a cluster", "remove a cluster from sandbox", "decommission a cluster", "sandbox offboard", "take a cluster offline", or "remove a shared cluster".
sandbox-cli:cluster-list
This skill should be used when the user asks to "list clusters", "show all clusters", "list sandbox clusters", "show registered clusters", "what clusters are available", or "cluster list".