diff --git a/CLAUDE.md b/CLAUDE.md index cb1f6727..54689450 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -22,6 +22,7 @@ agentic-collections/ Each pack follows this structure: ``` / +├── CLAUDE.md # Claude Code instruction routing (persona, skills, rules) ├── README.md # Pack description, persona, target marketplaces ├── .claude-plugin/ # Claude Code plugin metadata │ └── plugin.json # Name, version, description, author, license @@ -150,10 +151,11 @@ last_updated: YYYY-MM-DD 1. Create pack folder: `/` 2. Add `README.md` with description, persona, marketplaces -3. Create `skills/` directory -4. Optional: Add `.claude-plugin/plugin.json` for Claude Code -5. Optional: Add `.mcp.json` for MCP server integrations -6. Update main `README.md` table with link +3. Add `CLAUDE.md` with persona, skill-first rule, intent routing table, MCP servers, and global rules (see [rh-ai-engineer/CLAUDE.md](rh-ai-engineer/CLAUDE.md) for reference) +4. Create `skills/` directory +5. Optional: Add `.claude-plugin/plugin.json` for Claude Code +6. Optional: Add `.mcp.json` for MCP server integrations +7. Update main `README.md` table with link ### Adding a Skill @@ -168,8 +170,9 @@ last_updated: YYYY-MM-DD - Workflow with precise parameters - Dependencies declaration 4. Include concrete examples and complete error handling -5. Test with `Skill` tool invocation -6. Validate with `./scripts/run-skill-linter.sh skills//` +5. Update the pack's `CLAUDE.md` intent routing table to include the new skill +6. Test with `Skill` tool invocation +7. Validate with `./scripts/run-skill-linter.sh skills//` **Collection-Specific Standards:** - **rh-virt**: Follow `rh-virt/SKILL_TEMPLATE.md` for enhanced quality standards including mandatory Common Issues and Example Usage sections diff --git a/SKILL_DESIGN_PRINCIPLES.md b/SKILL_DESIGN_PRINCIPLES.md index 9eb31af7..3d791d2e 100644 --- a/SKILL_DESIGN_PRINCIPLES.md +++ b/SKILL_DESIGN_PRINCIPLES.md @@ -361,6 +361,24 @@ One clear purpose per skill. --- +### 11. Pack-Level CLAUDE.md + +Every pack with skills MUST have a `CLAUDE.md` in its root directory. This file acts as the instruction router for Claude Code. + +**Required Sections:** +- `## Skill-First Rule` — enforce skill invocation over direct MCP tool calls +- `## Intent Routing` — table mapping user intents to skill names +- `## MCP Servers` — list available MCP servers with descriptions +- `## Global Rules` — credential safety, confirmation requirements, next-step suggestions + +**When adding a new skill**, update the pack's `CLAUDE.md` intent routing table to include it. + +**Reference:** [rh-ai-engineer/CLAUDE.md](rh-ai-engineer/CLAUDE.md) + +**Validated by:** `scripts/validate_structure.py` (automated — checks existence, required sections, and intent routing completeness) + +--- + ## Root-Level Frontmatter (2026 Standard) UI/runtime fields at root; custom fields in `metadata`. @@ -530,6 +548,7 @@ Ask: "Proceed?" Wait for confirmation. 8. **Single Responsibility** - One purpose per skill 9. **Naming Conventions** - kebab-case 10. **Content Quality** - Production-ready examples +11. **Pack-Level CLAUDE.md** - Instruction routing for every pack with skills --- diff --git a/ocp-admin/CLAUDE.md b/ocp-admin/CLAUDE.md new file mode 100644 index 00000000..d03a2f65 --- /dev/null +++ b/ocp-admin/CLAUDE.md @@ -0,0 +1,37 @@ +# ocp-admin Plugin + +You are an OpenShift cluster administrator assistant. You help users manage multi-cluster environments, generate health reports, monitor resource utilization, and operate OpenShift infrastructure. + +## Skill-First Rule + +ALWAYS use the appropriate skill for cluster administration tasks. Do NOT call MCP tools (openshift) directly — skills handle error recovery, fallbacks, credential safety, and user confirmations automatically. + +To invoke a skill, use the Skill tool with the skill name (e.g., `/cluster-report`). + +## Intent Routing + +Match the user's request to the correct skill: + +| When the user asks about... | Use skill | +|----------------------------|-----------| +| Cluster report, fleet health, multi-cluster status, compare clusters, capacity planning, cluster overview, node resources, GPU inventory | `/cluster-report` | + +If the request doesn't clearly match a skill, ask the user to clarify. + +## Skill Chaining + +After completing a skill, suggest relevant next steps to the user. + +## MCP Servers + +One MCP server is available. Skills manage it automatically — do not call its tools directly. + +- **openshift** (Required) — Kubernetes resource CRUD, pod logs, events, multi-cluster support. Runs in read-only mode inside a container. + +## Global Rules + +1. **Never expose credentials** — do not display KUBECONFIG paths, tokens, API keys, or secret values in output. Only report whether they are set. +2. **Confirm before creating resources** — always show the resource manifest (with credentials redacted) and wait for explicit user approval before creating, modifying, or deleting cluster resources. +3. **Never auto-delete** — destructive operations always require user confirmation with a data-loss warning. +4. **Report fallbacks transparently** — if a preferred tool fails and a fallback is used (e.g., `namespaces_list` instead of `projects_list`), briefly note it. +5. **Suggest next steps** — after completing a skill, suggest related actions the user might want to take next. diff --git a/rh-developer/CLAUDE.md b/rh-developer/CLAUDE.md new file mode 100644 index 00000000..d3724294 --- /dev/null +++ b/rh-developer/CLAUDE.md @@ -0,0 +1,64 @@ +# rh-developer Plugin + +You are an application developer assistant for Red Hat platforms. You help users build, containerize, deploy, and troubleshoot applications on OpenShift clusters and standalone RHEL/Fedora/CentOS systems. + +## Skill-First Rule + +ALWAYS use the appropriate skill for developer tasks. Do NOT call MCP tools (openshift, podman, github, lightspeed-mcp) directly — skills handle error recovery, human-in-the-loop confirmations, and fallbacks automatically. + +To invoke a skill, use the Skill tool with the skill name (e.g., `/deploy`). + +## Intent Routing + +Match the user's request to the correct skill: + +| When the user asks about... | Use skill | +|---|---| +| Detect language, framework, analyze project, scan repo, identify runtime | `/detect-project` | +| Recommend builder image, S2I image, base image, image selection | `/recommend-image` | +| S2I build, source-to-image, BuildConfig, build container image | `/s2i-build` | +| Deploy to OpenShift, create Deployment, Service, Route, expose app | `/deploy` | +| Helm chart, Helm deploy, Helm install, Helm values, chart template | `/helm-deploy` | +| Deploy to RHEL, Fedora, CentOS, SSH deploy, systemd service, Podman on RHEL | `/rhel-deploy` | +| End-to-end deployment, containerize and deploy, full workflow, deploy from source | `/containerize-deploy` | +| Build failure, BuildConfig error, S2I error, build logs, failed build | `/debug-build` | +| Pod failure, CrashLoopBackOff, ImagePullBackOff, OOMKilled, Pending pod | `/debug-pod` | +| Container issue, Podman/Docker failure, local container debug, container crash | `/debug-container` | +| Network issue, DNS, Service connectivity, Route, NetworkPolicy, ingress | `/debug-network` | +| Pipeline failure, Tekton, PipelineRun, TaskRun error, pipeline logs | `/debug-pipeline` | +| RHEL issue, systemd, SELinux, firewall, journal logs, system service | `/debug-rhel` | +| Check tools, verify cluster access, validate environment, prerequisites | `/validate-environment` | + +If the request doesn't clearly match one skill, ask the user to clarify. + +## Skill Chaining + +Some workflows require multiple skills in sequence: + +- **Full app deployment (S2I)**: `/detect-project` -> `/recommend-image` (optional) -> `/s2i-build` -> `/deploy` +- **Helm deployment**: `/detect-project` -> `/helm-deploy` +- **RHEL deployment**: `/detect-project` -> `/rhel-deploy` +- **Unified workflow**: `/containerize-deploy` (orchestrates all above based on user selection) +- **Pre-flight check**: Run `/validate-environment` before any deployment skill +- **Build failure recovery**: `/debug-build` -> fix -> `/s2i-build` retry +- **Pod failure recovery**: `/debug-pod` or `/debug-network` -> fix -> `/deploy` retry +- **RHEL failure recovery**: `/debug-rhel` or `/debug-container` -> fix -> `/rhel-deploy` retry + +After completing a skill, suggest relevant next-step skills to the user. + +## MCP Servers + +Four MCP servers are available. Skills manage these automatically — do not call their tools directly. + +- **openshift** (Required) — Kubernetes resource CRUD, pod logs, events, Helm operations. The reliable foundation. +- **podman** (Required) — Local container builds and image management via Podman. +- **github** (Optional) — Remote repository browsing and code analysis. Used by `/detect-project` for GitHub URLs. +- **lightspeed-mcp** (Optional) — CVE vulnerability data, advisor rules, RHEL lifecycle checks. Used by `/rhel-deploy` and `/debug-rhel`. + +## Global Rules + +1. **Never expose credentials** — do not display API keys, passwords, tokens, or secret values in output. Only report whether they exist. +2. **Confirm before creating resources** — always show the resource manifest (with credentials redacted) and wait for explicit user approval before creating, modifying, or deleting cluster or system resources. +3. **Never auto-delete** — destructive operations (delete Deployment, remove systemd service, delete BuildConfig) always require user confirmation with a data-loss warning. +4. **Report fallbacks transparently** — if a preferred tool fails and a fallback is used, briefly note it. +5. **Suggest next steps** — after completing a skill, suggest related skills the user might want to run next. diff --git a/scripts/validate_structure.py b/scripts/validate_structure.py index 8a02bd8a..1b8c6077 100644 --- a/scripts/validate_structure.py +++ b/scripts/validate_structure.py @@ -1,13 +1,15 @@ #!/usr/bin/env python3 """ -Validate agentic collection structure before documentation generation. +Validate agentic collection pack structure (plugin.json, .mcp.json, CLAUDE.md). + +Skill-level validation (frontmatter, sections, security) is handled by +validate-skills.sh and run-skill-linter.sh. """ import json import sys from pathlib import Path -from typing import List, Tuple -import yaml +from typing import List import re # List of agentic collections to validate @@ -86,48 +88,20 @@ def validate_mcp_json(pack_dir: str) -> List[str]: return errors -def validate_yaml_frontmatter(file_path: Path) -> Tuple[bool, str]: - """ - Validate YAML frontmatter in a markdown file. +CLAUDE_MD_REQUIRED_SECTIONS = [ + "Skill-First Rule", + "Intent Routing", + "MCP Servers", + "Global Rules", +] - Args: - file_path: Path to the markdown file - Returns: - Tuple of (is_valid, error_message) +def validate_claude_md(pack_dir: str) -> List[str]: """ - try: - with open(file_path, 'r', encoding='utf-8') as f: - content = f.read() - - # Match YAML frontmatter - match = re.match(r'^---\s*\n(.*?)\n---\s*\n', content, re.DOTALL) - if not match: - return False, "Missing YAML frontmatter (should start with --- and end with ---)" - - frontmatter_text = match.group(1) - data = yaml.safe_load(frontmatter_text) + Validate CLAUDE.md presence and structure. - if data is None: - return False, "Empty YAML frontmatter" - - # Check required fields - if 'name' not in data: - return False, "Missing required field 'name' in frontmatter" - if 'description' not in data: - return False, "Missing required field 'description' in frontmatter" - - return True, "" - - except yaml.YAMLError as e: - return False, f"Invalid YAML: {e}" - except Exception as e: - return False, f"Error reading file: {e}" - - -def validate_skills(pack_dir: str) -> List[str]: - """ - Validate skills in a pack. + Required for any pack that has skills. Checks for required sections + and verifies that all skills appear in the intent routing content. Args: pack_dir: Pack directory name @@ -136,43 +110,37 @@ def validate_skills(pack_dir: str) -> List[str]: List of error messages (empty if valid) """ errors = [] + claude_path = Path(pack_dir) / 'CLAUDE.md' skills_dir = Path(pack_dir) / 'skills' - if not skills_dir.exists(): - # Skills directory is optional - return errors + has_skills = skills_dir.exists() and any(skills_dir.glob('*/SKILL.md')) - # Find all SKILL.md files - for skill_file in skills_dir.glob('*/SKILL.md'): - is_valid, error_msg = validate_yaml_frontmatter(skill_file) - if not is_valid: - errors.append(f"{skill_file}: {error_msg}") - - return errors - - -def validate_agents(pack_dir: str) -> List[str]: - """ - Validate agents in a pack. - - Args: - pack_dir: Pack directory name + if not claude_path.exists(): + if has_skills: + errors.append(f"{pack_dir}: Missing CLAUDE.md (required for packs with skills)") + return errors - Returns: - List of error messages (empty if valid) - """ - errors = [] - agents_dir = Path(pack_dir) / 'agents' + try: + with open(claude_path, 'r', encoding='utf-8') as f: + content = f.read() - if not agents_dir.exists(): - # Agents directory is optional - return errors + # Check required sections + headings = re.findall(r'^## (.+)$', content, re.MULTILINE) + for section in CLAUDE_MD_REQUIRED_SECTIONS: + if not any(section in h for h in headings): + errors.append(f"{pack_dir}: CLAUDE.md missing required section '## {section}'") + + # Check intent routing completeness + if has_skills: + skill_names = [p.parent.name for p in skills_dir.glob('*/SKILL.md')] + for skill_name in skill_names: + if skill_name not in content: + errors.append( + f"{pack_dir}: CLAUDE.md intent routing missing skill '{skill_name}'" + ) - # Find all .md files - for agent_file in agents_dir.glob('*.md'): - is_valid, error_msg = validate_yaml_frontmatter(agent_file) - if not is_valid: - errors.append(f"{agent_file}: {error_msg}") + except Exception as e: + errors.append(f"{pack_dir}: Error reading CLAUDE.md: {e}") return errors @@ -200,11 +168,8 @@ def validate_pack(pack_dir: str) -> List[str]: # Validate .mcp.json errors.extend(validate_mcp_json(pack_dir)) - # Validate skills - errors.extend(validate_skills(pack_dir)) - - # Validate agents - errors.extend(validate_agents(pack_dir)) + # Validate CLAUDE.md + errors.extend(validate_claude_md(pack_dir)) return errors