From 378455c2ebe02f91d4a5528358462ea5809f7095 Mon Sep 17 00:00:00 2001 From: r2dedios Date: Fri, 9 Oct 2026 14:16:11 +0200 Subject: [PATCH 1/4] rename: retire "pack" terminology in favor of "agent plugin" (APPENG-6571) --- .../agentic-contribution-skill/SKILL.md | 84 ++++---- .../references/examples.md | 8 +- .claude/skills/collection-compliance/SKILL.md | 14 +- .../compass-manifest-maintenance/SKILL.md | 66 +++--- .../assets/pack-location.yaml | 14 +- .../assets/plugin-catalog-info.yaml | 22 +- .../assets/skill-catalog-info.yaml | 10 +- .../references/mcp-mapping.md | 14 +- .../references/relationship-rules.md | 24 +-- .claude/skills/compliance-checker/SKILL.md | 6 +- .claude/skills/create-collection/SKILL.md | 38 ++-- .github/gemini-review-prompt.md | 6 +- .github/pull_request_template.md | 10 +- .github/workflows/mcp-tool-validation.yml | 36 ++-- .github/workflows/release-skill-zips.yaml | 2 +- .github/workflows/skill-code-review.yml | 12 +- .github/workflows/skill-security-scan.yml | 52 ++--- .pre-commit-config.yaml | 2 +- CLAUDE.md | 86 ++++---- CODEOWNERS | 2 +- COLLECTION_SPEC.md | 30 +-- CONTRIBUTING.md | 22 +- Makefile | 14 +- README.md | 22 +- SKILL_DESIGN_PRINCIPLES.md | 26 +-- catalog-info.yaml | 4 +- catalog/schema.yaml | 4 +- mcps/catalog-info.yaml | 2 +- ocp-admin/.catalog/collection.json | 6 +- ocp-admin/.catalog/collection.yaml | 6 +- ocp-admin/.catalog/deploy_and_use.md | 12 +- ocp-admin/README.md | 10 +- ocp-admin/catalog-info.yaml | 4 +- rh-ai-engineer/.catalog/collection.json | 6 +- rh-ai-engineer/.catalog/collection.yaml | 6 +- rh-ai-engineer/.catalog/deploy_and_use.md | 2 +- rh-ai-engineer/README.md | 4 +- rh-automation/.catalog/collection.json | 6 +- rh-automation/.catalog/collection.yaml | 6 +- rh-automation/.catalog/deploy_and_use.md | 2 +- rh-automation/references/INDEX.md | 4 +- rh-basic/.catalog/collection.json | 8 +- rh-basic/.catalog/collection.yaml | 8 +- rh-basic/.catalog/deploy_and_use.md | 12 +- rh-basic/.catalog/documentation_section.md | 2 +- rh-basic/.catalog/security_model.md | 2 +- rh-basic/README.md | 10 +- rh-basic/catalog-info.yaml | 4 +- rh-basic/skills/red-hat-get-started/SKILL.md | 2 +- rh-developer/.catalog/collection.json | 14 +- rh-developer/.catalog/collection.yaml | 14 +- rh-developer/.catalog/deploy_and_use.md | 4 +- .../.catalog/documentation_section.md | 4 +- rh-developer/README.md | 2 +- rh-sre/.catalog/collection.json | 4 +- rh-sre/.catalog/collection.yaml | 4 +- rh-sre/.catalog/deploy_and_use.md | 12 +- rh-sre/.catalog/documentation_section.md | 4 +- rh-sre/README.md | 18 +- rh-sre/catalog-info.yaml | 4 +- rh-sre/references/INDEX.md | 6 +- rh-sre/skills/execution-summary/SKILL.md | 4 +- .../references/skill-invocation.md | 2 +- rh-virt/.catalog/collection.json | 6 +- rh-virt/.catalog/collection.yaml | 6 +- rh-virt/.catalog/deploy_and_use.md | 12 +- rh-virt/README.md | 12 +- rh-virt/SKILL_TEMPLATE.md | 2 +- rh-virt/catalog-info.yaml | 4 +- scripts/collection_validate_lib.py | 188 +++++++++--------- scripts/install-hooks.sh | 2 +- scripts/package_skills.py | 52 ++--- scripts/test_validate_compass_layout.py | 50 ++--- scripts/test_validate_lifecycle_ceiling.py | 72 +++---- scripts/validate_compass_manifests.py | 116 +++++------ scripts/validate_docs_tree_links.py | 92 ++++----- scripts/validate_lifecycle_ceiling.py | 40 ++-- scripts/validate_mcp_tools.py | 78 ++++---- scripts/validate_skill_doc_links.py | 24 +-- scripts/validate_skills_tier1.py | 26 +-- scripts/validate_skills_tier2.py | 72 +++---- scripts/validate_structure.py | 90 ++++----- system.yaml | 2 +- 83 files changed, 902 insertions(+), 894 deletions(-) diff --git a/.claude/skills/agentic-contribution-skill/SKILL.md b/.claude/skills/agentic-contribution-skill/SKILL.md index b16f938b..73207755 100644 --- a/.claude/skills/agentic-contribution-skill/SKILL.md +++ b/.claude/skills/agentic-contribution-skill/SKILL.md @@ -6,10 +6,10 @@ description: | Use when: - "Create a new skill" - "Import an existing skill" - - "Create a new agentic pack" - - "Add skill to " + - "Create a new agent plugin" + - "Add skill to " - "Build skill for " - - User mentions "skill builder", "contribute", "new skill", "import skill", or "new pack" + - User mentions "skill builder", "contribute", "new skill", "import skill", or "new plugin" Two modes: create from scratch or import existing SKILL.md. Guides through discovery, definition, generation, and validation. Enforces SKILL_DESIGN_PRINCIPLES.md and agentskills.io spec. license: Apache-2.0 @@ -22,14 +22,14 @@ metadata: # /agentic-contribution-skill Skill -Interactive AI assistant for creating production-ready skills and agentic packs for **Red Hat products and platforms** with automated quality validation. +Interactive AI assistant for creating production-ready skills and agent plugins for **Red Hat products and platforms** with automated quality validation. All skills created follow **Red Hat product guidelines, official documentation standards** (docs.redhat.com, access.redhat.com), and **best practices** for Red Hat Enterprise Linux, OpenShift Container Platform, Ansible Automation Platform, Red Hat Lightspeed, and other Red Hat ecosystem products. -**Creates**: Complete skill structure with YAML frontmatter, all mandatory sections, pack integration, and new agentic packs (Lola-compatible) +**Creates**: Complete skill structure with YAML frontmatter, all mandatory sections, plugin integration, and new agent plugins (Lola-compatible) **Validates**: Tier 1 (agentskills.io) + Tier 2 (repository design principles) **Applies**: Red Hat documentation compliance (uses official Red Hat documentation to adapt skill content to manufacturer guidelines - not automated validation) -**Marketplace**: Registers packs in `marketplace/rh-agentic-collection.yml` ([agentic-catalog](https://github.com/RHEcosystemAppEng/agentic-catalog)) for Lola package manager installation +**Marketplace**: Registers plugins in `marketplace/rh-agentic-collection.yml` ([agentic-catalog](https://github.com/RHEcosystemAppEng/agentic-catalog)) for Lola package manager installation ## Prerequisites @@ -59,9 +59,9 @@ If prerequisites fail: ## When to Use This Skill **Use when**: -- Creating new skill for any pack +- Creating new skill for any plugin - Importing an existing SKILL.md into the repository -- Creating new agentic pack collection +- Creating new agent plugin collection - Developing or editing skills for this agentic collection - User explicitly invokes `/agentic-contribution-skill` @@ -83,13 +83,13 @@ Ask: **"Are you creating a new skill from scratch, or importing an existing SKIL Ask concisely, validate before proceeding. Make additional questions if needed to gather complete context. 1. **Purpose & Red Hat Product**: "What does the skill do? (1 sentence) For which Red Hat product(s) is this skill targeted?" -2. **Persona**: "What role uses it?" (detect existing pack or suggest new) -3. **Pack**: "Use ? (yes/no/create-new)" +2. **Persona**: "What role uses it?" (detect existing plugin or suggest new) +3. **Plugin**: "Use ? (yes/no/create-new)" 4. **MCP Tools**: - - Read pack's `mcps.json` to list existing MCP servers + - Read plugin's `mcps.json` to list existing MCP servers - If MCP server mentioned, verify it exists in the file - For tools mentioned, verify they exist in MCP server documentation or configuration - - Ask: "What MCP tools does this skill need? Available MCPs in : . Will you use existing MCPs, need new ones, or both?" + - Ask: "What MCP tools does this skill need? Available MCPs in : . Will you use existing MCPs, need new ones, or both?" - **Never suggest tools based on intuition** - only recommend tools you've verified exist 5. **Operation Type**: "Read-only, additive, or destructive?" (determines color) @@ -106,13 +106,13 @@ Ask concisely, validate before proceeding. Make additional questions if needed t **Validation**: - Purpose: specific, under 100 chars - Red Hat product: identified (OpenShift, RHEL, Ansible, etc.) -- Persona: matches known or justifies new pack +- Persona: matches known or justifies new plugin - MCP tools: **verified to exist** (no assumptions/intuition) - Operation type → Color selected from table above ### Phase 2: Definition (6 questions max) -1. **Name**: Ask "Skill name? (kebab-case, unique)" → Validate if name is representative of purpose and Red Hat product. If NOT representative, propose 2-3 better alternatives and ask user to choose → Check: `test -d /skills//` for uniqueness +1. **Name**: Ask "Skill name? (kebab-case, unique)" → Validate if name is representative of purpose and Red Hat product. If NOT representative, propose 2-3 better alternatives and ask user to choose → Check: `test -d /skills//` for uniqueness 2. **Use Cases**: "3-5 user phrases for 'Use when'" (concrete, not generic) 3. **Anti-Patterns**: "NOT for? (with alternative)" 4. **Workflow**: "Steps with MCP tools?" (e.g., "1. Validate VM - resources_get") @@ -126,9 +126,9 @@ Ask concisely, validate before proceeding. Make additional questions if needed t 1. **Get file**: Ask for the path to the existing SKILL.md 2. **Read & parse**: Read the file with Read tool. Parse YAML frontmatter, extract name, description, workflow steps, MCP tools mentioned -3. **Pack suggestion**: Analyze skill content keywords and suggest the best-fit pack: +3. **Plugin suggestion**: Analyze skill content keywords and suggest the best-fit plugin: - | Keywords in skill content | Suggested pack | + | Keywords in skill content | Suggested plugin | |---|---| | VM, virtual machine, KubeVirt, snapshot, migration, clone | rh-virt | | CVE, vulnerability, remediation, compliance, RHEL, SRE | rh-sre | @@ -138,7 +138,7 @@ Ask concisely, validate before proceeding. Make additional questions if needed t | Ansible, AAP, playbook, governance, job template | rh-automation | | CVE explanation, product lifecycle, support severity, diagnostics, patching, support case, troubleshooting, customer issue, knowledge base, must-gather | rh-basic | - - Present top match with reasoning: "This skill mentions X, Y, Z which aligns with `` (persona: )" + - Present top match with reasoning: "This skill mentions X, Y, Z which aligns with `` (persona: )" - Ask user to confirm or override 4. **Color inference**: If frontmatter has no `color`, analyze the skill's workflow steps and operations to infer the risk level. Present your conclusion to the user: @@ -148,13 +148,13 @@ Ask concisely, validate before proceeding. Make additional questions if needed t ``` Use the color mapping table from Phase 1 (Discovery). -5. **MCP tool verification**: Identify all MCP tools referenced in the skill. Read the target pack's `mcps.json` and verify each tool exists. Flag any tools not found — they may need a new MCP server or the skill may need adaptation. +5. **MCP tool verification**: Identify all MCP tools referenced in the skill. Read the target plugin's `mcps.json` and verify each tool exists. Flag any tools not found — they may need a new MCP server or the skill may need adaptation. 6. **Report analysis**: ``` Analyzed: Name: | Lines: | Frontmatter: - Suggested pack: (keywords: ) + Suggested plugin: (keywords: ) Color: () MCP tools: Missing sections: @@ -170,9 +170,9 @@ Ask concisely, validate before proceeding. Make additional questions if needed t 1. **Fix frontmatter**: Ensure `model: inherit` and `color` set (use value confirmed by user in Phase 1-Import). Add `metadata` block if missing 2. **Add missing sections**: Per DP6/DP7 — Prerequisites, When to Use, Workflow, Common Issues, Dependencies. Keep existing content, add structure around it -3. **Validate naming**: kebab-case, check uniqueness: `test -d /skills//` -4. **Place file**: Copy to `/skills//SKILL.md` -5. **Update routing**: Add entry to `/AGENTS.md` intent routing table +3. **Validate naming**: kebab-case, check uniqueness: `test -d /skills//` +4. **Place file**: Copy to `/skills//SKILL.md` +5. **Update routing**: Add entry to `/AGENTS.md` intent routing table 6. **Show changes**: Present summary of all modifications to user, wait for confirmation After confirmation → proceed to Phase 5 (Validation & Iteration). @@ -199,7 +199,7 @@ Show complete spec: ```markdown ## Review Before Generation -**Pack**: | **Skill**: | **Color**: +**Plugin**: | **Skill**: | **Color**: **Purpose**: **Red Hat Product**: @@ -227,9 +227,9 @@ Proceed with generation? (yes/no) **Create structure**: ```bash -mkdir -p /skills// +mkdir -p /skills// # If external resources provided by user: -mkdir -p /skills//references/ +mkdir -p /skills//references/ ``` **Generate files**: @@ -242,11 +242,11 @@ mkdir -p /skills//references/ - `references/common-issues.md` - Detailed troubleshooting with full KB article content - `references/examples.md` - Comprehensive usage examples - `references/external-resources.md` - Any external references/links/KB articles mentioned by user -3. **Update /AGENTS.md**: Add intent routing entry -4. **Create /mcps.json**: If new MCP server needed (use `${ENV_VAR}` format) -5. **Compass manifests**: Run **compass-manifest-maintenance** (`.claude/skills/compass-manifest-maintenance/`) for registered packs — skill `catalog-info.yaml`, Location targets, bidirectional `dependsOn`/`dependencyOf` on plugin and MCP manifests -6. **Update marketplace/rh-agentic-collection.yml** in [agentic-catalog](https://github.com/RHEcosystemAppEng/agentic-catalog): If new pack (register pack for Lola installation) -7. **Create pack structure**: If new pack (README.md, AGENTS.md, skills/ directory) +3. **Update /AGENTS.md**: Add intent routing entry +4. **Create /mcps.json**: If new MCP server needed (use `${ENV_VAR}` format) +5. **Compass manifests**: Run **compass-manifest-maintenance** (`.claude/skills/compass-manifest-maintenance/`) for registered plugins — skill `catalog-info.yaml`, Location targets, bidirectional `dependsOn`/`dependencyOf` on plugin and MCP manifests +6. **Update marketplace/rh-agentic-collection.yml** in [agentic-catalog](https://github.com/RHEcosystemAppEng/agentic-catalog): If new plugin (register plugin for Lola installation) +7. **Create plugin structure**: If new plugin (README.md, AGENTS.md, skills/ directory) Generate SKILL.md following the mandatory section template in SKILL_DESIGN_PRINCIPLES.md (already consulted in Phase 3). If SKILL.md becomes too long, move detailed content to `references/` with references in main file. @@ -256,12 +256,12 @@ Generate SKILL.md following the mandatory section template in SKILL_DESIGN_PRINC **Tier 1 - agentskills.io**: ```bash -uv run python scripts/validate_skills_tier1.py /skills//SKILL.md +uv run python scripts/validate_skills_tier1.py /skills//SKILL.md ``` **Tier 2 - Design Principles**: ```bash -uv run python scripts/validate_skills_tier2.py /skills//SKILL.md +uv run python scripts/validate_skills_tier2.py /skills//SKILL.md ``` **Report clearly**: @@ -291,7 +291,7 @@ Present a concise summary to the user: - Validation results (Tier 1 + Tier 2, pass/warning counts) - Quality metrics (line count, section count, workflow steps, common issues) - Iteration count if applicable -- Your assessment of readiness and fit within the pack +- Your assessment of readiness and fit within the plugin - Ask: "Ready to commit? (yes/no)" ### Phase 7: Git Workflow (Optional - User Controls) @@ -300,7 +300,7 @@ Present a concise summary to the user: 1. **Branch**: "Create `feat/`? (yes/no)" 2. **Stage**: Show files, ask confirmation -3. **Commit**: Propose message (`feat: add skill to `), wait for approval +3. **Commit**: Propose message (`feat: add skill to `), wait for approval 4. **Push**: "Push changes? (yes/no)" 5. **PR**: Use `gh pr create` if available, or provide manual steps @@ -318,11 +318,11 @@ Report: skill path, quality status, PR URL (if created), and note that CI checks ### Issue 2: "Skill name exists" -**Fix**: Choose more specific name. Check: `ls /skills/` +**Fix**: Choose more specific name. Check: `ls /skills/` ### Issue 3: "MCP server not configured" -**Fix**: Add to `/mcps.json` using `${ENV_VAR}` format. +**Fix**: Add to `/mcps.json` using `${ENV_VAR}` format. ### Issue 4: "Git push authentication failed" @@ -342,16 +342,16 @@ ssh-add ~/.ssh/id_ed25519 curl -LsSf https://astral.sh/uv/install.sh | sh ``` -### Issue 6: "New pack not installable via Lola" +### Issue 6: "New plugin not installable via Lola" -**Cause**: Pack not registered in `marketplace/rh-agentic-collection.yml` ([agentic-catalog](https://github.com/RHEcosystemAppEng/agentic-catalog)) +**Cause**: Plugin not registered in `marketplace/rh-agentic-collection.yml` ([agentic-catalog](https://github.com/RHEcosystemAppEng/agentic-catalog)) -**Fix**: Add pack entry to marketplace file: +**Fix**: Add plugin entry to marketplace file: ```yaml -- name: +- name: version: 0.1.0 - description: - path: + description: + path: ``` ### Issue 7: "Line count exceeds 500" diff --git a/.claude/skills/agentic-contribution-skill/references/examples.md b/.claude/skills/agentic-contribution-skill/references/examples.md index fd0c76b8..38c498c6 100644 --- a/.claude/skills/agentic-contribution-skill/references/examples.md +++ b/.claude/skills/agentic-contribution-skill/references/examples.md @@ -14,7 +14,7 @@ What does it do? For which Red Hat product(s) is this skill targeted? What role uses it? > "Virt admins" -✅ Detected pack: rh-virt. Use it? (yes/no) +✅ Detected plugin: rh-virt. Use it? (yes/no) > yes What MCP tools does this skill need? @@ -72,7 +72,7 @@ Workflow steps with MCP tools: ## Review Before Generation -**Pack**: rh-virt | **Skill**: vm-backup-create | **Color**: green +**Plugin**: rh-virt | **Skill**: vm-backup-create | **Color**: green **Purpose**: Create VM backups using snapshots for OpenShift Virtualization **Red Hat Product**: OpenShift Virtualization @@ -150,7 +150,7 @@ Reading ./my-skills/cluster-backup/SKILL.md... Analyzed: ./my-skills/cluster-backup/SKILL.md Name: cluster-backup | Lines: 180 | Frontmatter: needs-fixes (missing model, color) -Suggested pack: ocp-admin (keywords: cluster, etcd, backup, restore) +Suggested plugin: ocp-admin (keywords: cluster, etcd, backup, restore) No color in frontmatter. Analyzing operations... Inferred color: red — Reason: skill performs etcd backup and restore, which are irreversible operations @@ -163,7 +163,7 @@ MCP tools referenced: resources_get, pods_exec, pods_log Analyzed: ./my-skills/cluster-backup/SKILL.md Name: cluster-backup | Lines: 180 | Frontmatter: needs-fixes (missing model, color) -Suggested pack: ocp-admin (keywords: cluster, etcd, backup, restore) +Suggested plugin: ocp-admin (keywords: cluster, etcd, backup, restore) Color: red (inferred) MCP tools: 3 verified, 0 not found Missing sections: Prerequisites, Dependencies diff --git a/.claude/skills/collection-compliance/SKILL.md b/.claude/skills/collection-compliance/SKILL.md index d1d21e40..5d9d79ab 100644 --- a/.claude/skills/collection-compliance/SKILL.md +++ b/.claude/skills/collection-compliance/SKILL.md @@ -30,21 +30,21 @@ allowed-tools: Read Glob Grep Bash ## Workflow -1. **Re-run** `uv run python scripts/validate_collection_compliance.py` and capture errors (pack path + message). +1. **Re-run** `uv run python scripts/validate_collection_compliance.py` and capture errors (plugin path + message). 2. **Classify** - - **Missing file** — create `.catalog/collection.yaml` via create-collection skill (or `uv run python scripts/bootstrap_catalog.py --pack ` for bootstrap baseline). + - **Missing file** — create `.catalog/collection.yaml` via create-collection skill (or `uv run python scripts/bootstrap_catalog.py --plugin ` for bootstrap baseline). - **Schema** — align YAML with [catalog/schema.yaml](../../catalog/schema.yaml) (includes required **`maturity`**: `GREEN` or `ORANGE`; site listing uses **`GREEN`** only per `pack_registry.get_docs_pack_dirs()`). - **Roster** — every `skills//SKILL.md` must appear once under `contents.skills` or `contents.orchestration_skills` with `name == `. - **Banner** — `collection.yaml` must mention `create-collection` and `Golden sources` in the opening `#` block. - - **`collection.json` drift** — run `uv run python scripts/catalog_yaml_to_json.py --pack ` or `make catalog-mirror-json`. + - **`collection.json` drift** — run `uv run python scripts/catalog_yaml_to_json.py --plugin ` or `make catalog-mirror-json`. - **Fragment refs / length** — `deploy_and_use`, `documentation_section`, `mcp_section`, and `security_model` may be inline or a one-line `#…md` ref naming a sibling file under `.catalog/` (e.g. `#install.md`). Refs must start with `#`. Inline monitored fields over **500** code points must move to a fragment on **that same key** (see COLLECTION_SPEC). - **Fragment provenance (`.catalog/*.md`)** — each referenced fragment must start with a leading HTML **``** block with the **same intent** as the `collection.yaml` banner: **create-collection** workflow and **Golden sources** (SKILL, README, CLAUDE, marketplace). See [COLLECTION_SPEC.md](../../COLLECTION_SPEC.md) **Provenance banners** (CI does not yet assert this text; fix when reviewing fragments). - - **Thin `deploy_and_use` (manual review)** — if the pack has **`mcps.json`** MCP servers, **`deploy_and_use`** (inline or **`#deploy_and_use.md`**) should meet [COLLECTION_SPEC.md](../../COLLECTION_SPEC.md) **install + env + MCP** (prerequisites, **`export`** for each **`${VAR}`** name, Lola **`path:`**, MCP notes, optional Claude/Cursor install). CI may not fail; fix via **create-collection** when reviewing PRs. + - **Thin `deploy_and_use` (manual review)** — if the plugin has **`mcps.json`** MCP servers, **`deploy_and_use`** (inline or **`#deploy_and_use.md`**) should meet [COLLECTION_SPEC.md](../../COLLECTION_SPEC.md) **install + env + MCP** (prerequisites, **`export`** for each **`${VAR}`** name, Lola **`path:`**, MCP notes, optional Claude/Cursor install). CI may not fail; fix via **create-collection** when reviewing PRs. 3. **AI semantic alignment review (required)** - Treat scripts as **structural guards only**; they do not fully verify semantic alignment. - - Compare each pack's catalog metadata and referenced fragments against golden sources: + - Compare each plugin's catalog metadata and referenced fragments against golden sources: - `skills/*/SKILL.md` (names, descriptions, scope, orchestration intent) - `README.md` (installation, prerequisites, env variables, usage caveats) - `AGENTS.md` (persona, routing, global rules, MCP posture) @@ -64,7 +64,7 @@ allowed-tools: Read Glob Grep Bash ## Common Issues -- **`skills_decision_guide` with no skills** — guide must be `[]` if the pack has no `skills/` tree. +- **`skills_decision_guide` with no skills** — guide must be `[]` if the plugin has no `skills/` tree. - **Orchestration miscount** — move skills that delegate end-to-end flows to `orchestration_skills` per COLLECTION_SPEC judgment rules. - **Install drift** — `README.md` and `.catalog/deploy_and_use(.md)` disagree on Lola commands/module IDs. - **Env drift** — `${VAR}` names in `mcps.json` are not fully represented in `deploy_and_use`. @@ -73,6 +73,6 @@ allowed-tools: Read Glob Grep Bash ```bash make validate-collection-compliance -uv run python scripts/catalog_yaml_to_json.py --pack rh-developer +uv run python scripts/catalog_yaml_to_json.py --plugin rh-developer make validate-collection-compliance ``` diff --git a/.claude/skills/compass-manifest-maintenance/SKILL.md b/.claude/skills/compass-manifest-maintenance/SKILL.md index a8d69845..3fae000f 100644 --- a/.claude/skills/compass-manifest-maintenance/SKILL.md +++ b/.claude/skills/compass-manifest-maintenance/SKILL.md @@ -1,9 +1,9 @@ --- name: compass-manifest-maintenance description: | - Author and maintain Compass catalog-info.yaml manifests for agentic packs (skills, plugins, Locations, MCP inverse relations). Use when: + Author and maintain Compass catalog-info.yaml manifests for agent plugins (skills, plugins, Locations, MCP inverse relations). Use when: - Adding or updating a skill and its Compass manifest - - Registering an existing pack in Compass (manifests only; not creating a new agentic pack) + - Registering an existing plugin in Compass (manifests only; not creating a new agent plugin) - MCP usage or orchestration changed in SKILL.md - Auditing bidirectional dependsOn/dependencyOf drift against repo Compass conventions @@ -45,7 +45,7 @@ test -f CLAUDE.md && echo "✓ repo root" || echo "✗ wrong directory" **Use when:** - New skill needs `skills//catalog-info.yaml` and Location / inverse updates. - Skill `allowed-tools` or orchestration changed → MCP or skill `dependsOn` must change. -- Register an existing pack in Compass (plugin, Location, root index, `system.yaml` manifests). +- Register an existing plugin in Compass (plugin, Location, root index, `system.yaml` manifests). - Drift audit: skill on disk without manifest, stale `dependencyOf`, or dangling entity refs. - After `agentic-contribution-skill` creates a skill (run before opening PR). @@ -55,50 +55,50 @@ test -f CLAUDE.md && echo "✓ repo root" || echo "✗ wrong directory" **MCP Tool:** None — file-based; uses Read, Glob, Grep, Bash only (see `allowed-tools` in frontmatter). -**Parameters:** N/A — no MCP tools; inputs are ``, ``, and on-disk manifest paths. +**Parameters:** N/A — no MCP tools; inputs are ``, ``, and on-disk manifest paths. ### 1. Add or update a skill manifest -1. **Resolve** `` and `` — confirm `/skills//SKILL.md` exists. +1. **Resolve** `` and `` — confirm `/skills//SKILL.md` exists. 2. **Read golden sources** (precedence): - - `/-plugin.yaml` — `spec.lifecycle` (default for new skill manifest; see [relationship-rules.md](references/relationship-rules.md) Lifecycle) + - `/-plugin.yaml` — `spec.lifecycle` (default for new skill manifest; see [relationship-rules.md](references/relationship-rules.md) Lifecycle) - `SKILL.md` frontmatter: `name`, `description`, `allowed-tools` - `SKILL.md` body: `Required MCP Servers`, `/skill-name` invocations, Dependencies, validator prerequisites - - `/mcps.json` — server keys (map via [mcp-mapping.md](references/mcp-mapping.md)) - - `/AGENTS.md` — tags/disciplines hints only (not orchestration inference) + - `/mcps.json` — server keys (map via [mcp-mapping.md](references/mcp-mapping.md)) + - `/AGENTS.md` — tags/disciplines hints only (not orchestration inference) 3. **Derive `dependsOn`** for the skill manifest: - - Always: `airesource:ai5-marketplace/` + - Always: `airesource:ai5-marketplace/` - MCP: only servers the skill **actually uses** (tool prefixes + body); see [mcp-mapping.md](references/mcp-mapping.md) - Other skills: orchestration or documented `/other-skill` invocations in `SKILL.md` - Script-only skills: no `mcpserver:` entries 4. **Set `spec.lifecycle`** (do not hardcode `beta`): - - Read `spec.lifecycle` from `/-plugin.yaml` — use as the **default** for the skill. + - Read `spec.lifecycle` from `/-plugin.yaml` — use as the **default** for the skill. - **Human in the loop:** ask whether to change it. The skill may match the plugin or use a **less mature** value only (e.g. plugin `beta` → skill `development` is OK; plugin `development` → skill `beta` is **not** allowed). - See [relationship-rules.md](references/relationship-rules.md) Lifecycle. -5. **Write** `/skills//catalog-info.yaml` from [assets/skill-catalog-info.yaml](assets/skill-catalog-info.yaml): +5. **Write** `/skills//catalog-info.yaml` from [assets/skill-catalog-info.yaml](assets/skill-catalog-info.yaml): - `namespace: ai5-marketplace` - `labels.distribution: external` - `agents: []` - `lifecycle:` value from step 4 (typically matches the plugin) - `owner: group:redhat/ai5-marketplace` - `backstage.io/source-location` → GitHub `main` branch SKILL.md URL - - `dependencyOf`: list orchestrators that `dependsOn` this skill (scan pack or update when editing orchestrator) + - `dependencyOf`: list orchestrators that `dependsOn` this skill (scan plugin or update when editing orchestrator) 6. **Update inverse manifests** ([relationship-rules.md](references/relationship-rules.md)): - - `/catalog-info.yaml` — `./skills//catalog-info.yaml` in `spec.targets` - - `/-plugin.yaml` — `dependencyOf: airesource:ai5-marketplace/` + - `/catalog-info.yaml` — `./skills//catalog-info.yaml` in `spec.targets` + - `/-plugin.yaml` — `dependencyOf: airesource:ai5-marketplace/` - Each `mcpserver:` in skill `dependsOn` → matching `mcps/*.yaml` `dependencyOf` - Each skill in skill `dependsOn` → that skill's `dependencyOf` includes orchestrator -7. **Reconcile plugin MCP deps** — plugin `dependsOn` = union of all `mcpserver:` refs across pack skill manifests. +7. **Reconcile plugin MCP deps** — plugin `dependsOn` = union of all `mcpserver:` refs across plugin skill manifests. 8. **Verify skill documentation layout** ([agent-plugins.org](https://agent-plugins.org/specification) / agentskills.io): - Skill-local documentation belongs in `skills//references/`, not `docs/`. - - **Allowed locations only:** pack-level `/references/` or skill-level `skills//references/`. **No** `references/references/` nesting inside a skill. + - **Allowed locations only:** plugin-level `/references/` or skill-level `skills//references/`. **No** `references/references/` nesting inside a skill. - **Scan** every `skills//` for a `docs/` directory. - **If `docs/` exists:** 1. Rename or merge into `references/` (merge file-by-file when both exist). @@ -109,13 +109,13 @@ test -f CLAUDE.md && echo "✓ repo root" || echo "✗ wrong directory" - Shared reference pools (e.g. `common-issues.md`, `live-doc-lookup.md`) symlinked into multiple skills must use link targets that resolve when opened through the symlink (same-directory or `references/...` paths from the symlink location). - Run `uv run python scripts/validate_compass_manifests.py` to confirm (includes manifest roster, bidirectional refs, and references layout). -### 2. Register a new pack in Compass +### 2. Register a new plugin in Compass -1. Create `/-plugin.yaml` from [assets/plugin-catalog-info.yaml](assets/plugin-catalog-info.yaml) with **`spec.lifecycle: development`** (default for new packs; confirm with user before raising maturity). -2. Create `/catalog-info.yaml` from [assets/pack-location.yaml](assets/pack-location.yaml). -3. Add `.//catalog-info.yaml` to root `catalog-info.yaml`. -4. Add `airesource:ai5-marketplace/` to `system.yaml` `spec.dependencyOf`. -5. Run **create-collection** for `/.catalog/` separately. +1. Create `/-plugin.yaml` from [assets/plugin-catalog-info.yaml](assets/plugin-catalog-info.yaml) with **`spec.lifecycle: development`** (default for new plugins; confirm with user before raising maturity). +2. Create `/catalog-info.yaml` from [assets/plugin-location.yaml](assets/plugin-location.yaml). +3. Add `.//catalog-info.yaml` to root `catalog-info.yaml`. +4. Add `airesource:ai5-marketplace/` to `system.yaml` `spec.dependencyOf`. +5. Run **create-collection** for `/.catalog/` separately. ### 3. Drift / compliance audit @@ -123,7 +123,7 @@ Run `uv run python scripts/validate_compass_manifests.py` (or `make validate-com | Check | Rule | |-------|------| -| Roster parity | Every `skills/*/SKILL.md` has `catalog-info.yaml` and pack Location target | +| Roster parity | Every `skills/*/SKILL.md` has `catalog-info.yaml` and plugin Location target | | Inverse parity | Plugin `dependencyOf` = full skill set; each skill `dependsOn` includes plugin | | MCP inverse | Each skill `mcpserver:` in `dependsOn` → MCP `dependencyOf` includes skill | | Skill inverse | Each skill→skill `dependsOn` → target `dependencyOf` includes source | @@ -136,7 +136,7 @@ Report violations with file path and fix per workflow §1. Do not weaken checks. ### 4. Validate (file-based) -1. Compare YAML against [assets/](assets/) and a known-good manifest in the same pack. +1. Compare YAML against [assets/](assets/) and a known-good manifest in the same plugin. 2. Run `uv run python scripts/validate_compass_manifests.py` (included in `make validate` and `make validate-structure`). 3. Tier 1 on this skill if edited: `uv run python scripts/validate_skills_tier1.py .claude/skills/compass-manifest-maintenance/SKILL.md`. 4. Post-merge: maintainer may register in Compass UI manually (out of scope for this skill). @@ -144,7 +144,7 @@ Report violations with file path and fix per workflow §1. Do not weaken checks. **Error Handling:** - If skill on disk has no manifest → create from `assets/skill-catalog-info.yaml` and add Location target. - If inverse `dependencyOf` missing on plugin or MCP → update per [relationship-rules.md](references/relationship-rules.md). -- If MCP ref cannot be resolved → grep pack manifests; do not invent new `mcpserver:` refs. +- If MCP ref cannot be resolved → grep plugin manifests; do not invent new `mcpserver:` refs. - If `skills//docs/` exists or markdown links use `docs/...` → rename/merge to `references/`, flatten any `references/references/`, update link paths, **delete** `docs/`, fix symlinks; re-run `validate_compass_manifests.py`. ## Self-review checklist @@ -153,8 +153,8 @@ Report violations with file path and fix per workflow §1. Do not weaken checks. - [ ] Manifest conventions: `agents: []`, `labels.distribution: external`, `namespace: ai5-marketplace`, `owner: group:redhat/ai5-marketplace`. - [ ] MCP deps derived from `SKILL.md` usage, not copied from sibling skills. - [ ] Every new `dependsOn` has matching `dependencyOf` on the target entity. -- [ ] Pack Location lists every skill manifest path. -- [ ] Plugin `dependencyOf` lists every skill in the pack. +- [ ] Plugin Location lists every skill manifest path. +- [ ] Plugin `dependencyOf` lists every skill in the plugin. - [ ] No `partOf`/`hasPart` on custom kinds. - [ ] Skill documentation uses `references/` only — no leftover `docs/` directory, no `references/references/` nesting; links use `references/...` or `./references/...`. @@ -185,7 +185,7 @@ None — uses Read, Glob, Grep, Bash. - **Blanket MCP deps** — declaring every MCP in `mcps.json` instead of per-skill `allowed-tools` usage. - **Orchestration gaps** — `remediation`-style skills missing skill→skill edges or inverse `dependencyOf` on depended skills. - **Canonical vs owned** — Lightspeed and Security use `mcpserver:redhat/...`; do not register duplicates in `mcps/`. -- **Unregistered packs** — `rh-developer`, `rh-ai-engineer`, `rh-automation` exist on disk but are not in root Location until explicitly added. +- **Unregistered plugins** — `rh-developer`, `rh-ai-engineer`, `rh-automation` exist on disk but are not in root Location until explicitly added. - **`docs/` vs `references/`** — agent-plugins.org expects `references/` for skill-local docs; rename/merge, flatten `references/references/`, update links, **delete** `docs/`, then run `make validate-compass-manifests`. ## Example usage @@ -207,13 +207,13 @@ uv run python scripts/validate_skills_tier1.py .claude/skills/compass-manifest-m make validate ``` -Audit all four registered packs: +Audit all four registered plugins: ```bash -for pack in ocp-admin rh-sre rh-virt rh-basic; do - echo "=== $pack ===" +for plugin in ocp-admin rh-sre rh-virt rh-basic; do + echo "=== $plugin ===" comm -23 \ - <(find "$pack/skills" -name SKILL.md 2>/dev/null | sed 's|.*/skills/||;s|/SKILL.md||' | sort) \ - <(grep -oP 'skills/\K[^/]+(?=/catalog-info)' "$pack/catalog-info.yaml" 2>/dev/null | sort) + <(find "$plugin/skills" -name SKILL.md 2>/dev/null | sed 's|.*/skills/||;s|/SKILL.md||' | sort) \ + <(grep -oP 'skills/\K[^/]+(?=/catalog-info)' "$plugin/catalog-info.yaml" 2>/dev/null | sort) done ``` diff --git a/.claude/skills/compass-manifest-maintenance/assets/pack-location.yaml b/.claude/skills/compass-manifest-maintenance/assets/pack-location.yaml index 62891971..40284794 100644 --- a/.claude/skills/compass-manifest-maintenance/assets/pack-location.yaml +++ b/.claude/skills/compass-manifest-maintenance/assets/pack-location.yaml @@ -1,20 +1,20 @@ -# Template: /catalog-info.yaml (Location) +# Template: /catalog-info.yaml (Location) apiVersion: backstage.io/v1alpha1 kind: Location metadata: - name: - title: Agentic Pack + name: + title: Agent Plugin description: > - Points to all AI skill catalog entities in the agentic pack. + Points to all AI skill catalog entities in the agent plugin. annotations: agentic-plugins.redhat.com/version: "1.0" agentic-plugins.redhat.com/repo: "agentic-plugins" agentic.redhat.com/lola-module: "true" - agentic.redhat.com/lola-module-name: + agentic.redhat.com/lola-module-name: agentic.redhat.com/repository: https://github.com/RHEcosystemAppEng/agentic-plugins - agentic.redhat.com/path: + agentic.redhat.com/path: spec: targets: - - ./-plugin.yaml + - ./-plugin.yaml - ./skills//catalog-info.yaml # List every skill manifest under skills/ diff --git a/.claude/skills/compass-manifest-maintenance/assets/plugin-catalog-info.yaml b/.claude/skills/compass-manifest-maintenance/assets/plugin-catalog-info.yaml index 8d319976..10c22371 100644 --- a/.claude/skills/compass-manifest-maintenance/assets/plugin-catalog-info.yaml +++ b/.claude/skills/compass-manifest-maintenance/assets/plugin-catalog-info.yaml @@ -1,24 +1,24 @@ -# Template: /-plugin.yaml -# Replace , title, description, tags, disciplines, categories, dependencyOf, dependsOn (MCP union). -# New packs: spec.lifecycle defaults to development (confirm with user before raising maturity). +# Template: /-plugin.yaml +# Replace , title, description, tags, disciplines, categories, dependencyOf, dependsOn (MCP union). +# New plugins: spec.lifecycle defaults to development (confirm with user before raising maturity). apiVersion: backstage.io/v1alpha1 kind: AiResource metadata: - name: + name: namespace: ai5-marketplace - title: + title: description: > - + tags: - ai-skill - - + - annotations: agentic-plugins.redhat.com/version: "1.0" agentic-plugins.redhat.com/repo: "agentic-plugins" agentic.redhat.com/lola-module: "true" - agentic.redhat.com/lola-module-name: + agentic.redhat.com/lola-module-name: agentic.redhat.com/repository: https://github.com/RHEcosystemAppEng/agentic-plugins - agentic.redhat.com/path: + agentic.redhat.com/path: github.com/project-slug: RHEcosystemAppEng/agentic-plugins links: - url: https://github.com/RHEcosystemAppEng/agentic-plugins @@ -35,9 +35,9 @@ spec: - agents: [] dependsOn: - # Union of mcpserver refs used by any skill in this pack (omit if none) + # Union of mcpserver refs used by any skill in this plugin (omit if none) # - mcpserver:ai5-marketplace/ # - mcpserver:redhat/ dependencyOf: - airesource:ai5-marketplace/ - # Every skill in the pack — bidirectional with skill dependsOn plugin + # Every skill in the plugin — bidirectional with skill dependsOn plugin diff --git a/.claude/skills/compass-manifest-maintenance/assets/skill-catalog-info.yaml b/.claude/skills/compass-manifest-maintenance/assets/skill-catalog-info.yaml index 596feb3f..cf518386 100644 --- a/.claude/skills/compass-manifest-maintenance/assets/skill-catalog-info.yaml +++ b/.claude/skills/compass-manifest-maintenance/assets/skill-catalog-info.yaml @@ -1,6 +1,6 @@ # Template: skills//catalog-info.yaml -# Replace , , title, description, tags, disciplines, categories, dependsOn. -# lifecycle: copy from /-plugin.yaml spec.lifecycle (default); may downgrade only — see relationship-rules.md +# Replace , , title, description, tags, disciplines, categories, dependsOn. +# lifecycle: copy from /-plugin.yaml spec.lifecycle (default); may downgrade only — see relationship-rules.md apiVersion: backstage.io/v1alpha1 kind: AiResource metadata: @@ -13,7 +13,7 @@ metadata: distribution: external annotations: backstage.io/source-location: >- - url:https://github.com/RHEcosystemAppEng/agentic-plugins/blob/main//skills//SKILL.md + url:https://github.com/RHEcosystemAppEng/agentic-plugins/blob/main//skills//SKILL.md tags: - ai-skill - @@ -23,7 +23,7 @@ metadata: icon: github spec: type: skill - lifecycle: # from /-plugin.yaml; same or less mature than plugin + lifecycle: # from /-plugin.yaml; same or less mature than plugin owner: group:redhat/ai5-marketplace disciplines: - @@ -31,7 +31,7 @@ spec: - agents: [] dependsOn: - - airesource:ai5-marketplace/ + - airesource:ai5-marketplace/ # Add mcpserver: and airesource: (other skills) only when SKILL.md uses them dependencyOf: [] # dependencyOf: list orchestration skills that dependsOn this skill (COMPASS-1288) diff --git a/.claude/skills/compass-manifest-maintenance/references/mcp-mapping.md b/.claude/skills/compass-manifest-maintenance/references/mcp-mapping.md index 1f398ec7..9b7f87cd 100644 --- a/.claude/skills/compass-manifest-maintenance/references/mcp-mapping.md +++ b/.claude/skills/compass-manifest-maintenance/references/mcp-mapping.md @@ -1,10 +1,10 @@ # Deriving MCP `dependsOn` for skill manifests -Map **only** MCP servers the skill **actually uses**. Never copy a sibling manifest and never declare every key in `/mcps.json`. +Map **only** MCP servers the skill **actually uses**. Never copy a sibling manifest and never declare every key in `/mcps.json`. ## Step 1 — Detect MCP usage in the skill -From `/skills//SKILL.md`: +From `/skills//SKILL.md`: - `allowed-tools` in frontmatter (tool names / prefixes) - `Required MCP Servers` / `Required MCP Tools` in the body @@ -14,7 +14,7 @@ If none of the above reference MCP tools → **no** `mcpserver:` in `dependsOn` ## Step 2 — Match usage to `mcps.json` keys -Read `/mcps.json`. Note which **server keys** the skill documents (e.g. `openshift-administration`, `lightspeed-mcp`, `aap-mcp-job-management`). +Read `/mcps.json`. Note which **server keys** the skill documents (e.g. `openshift-administration`, `lightspeed-mcp`, `aap-mcp-job-management`). When `allowed-tools` lists tools but SKILL.md does not name a key, infer the server from context in the skill body (which MCP block documents those tools). @@ -32,13 +32,13 @@ For each MCP the skill uses: ### B. Canonical MCP (registered upstream, not in `mcps/`) -If the pack references an MCP that **no** file under `mcps/` covers: +If the plugin references an MCP that **no** file under `mcps/` covers: -1. Search existing skill manifests in the same pack (or repo) for the same `mcps.json` key or the same upstream product. +1. Search existing skill manifests in the same plugin (or repo) for the same `mcps.json` key or the same upstream product. 2. Reuse the `mcpserver:` ref already used there (often `mcpserver:redhat/`). 3. Do **not** add a duplicate MCPServer manifest in `mcps/`. -When unsure, grep the repo for the `mcps.json` key or tool prefix in other `catalog-info.yaml` files under the same pack. +When unsure, grep the repo for the `mcps.json` key or tool prefix in other `catalog-info.yaml` files under the same plugin. ## Step 4 — Update inverse relations @@ -48,7 +48,7 @@ For each `mcpserver:` added to the skill’s `dependsOn`: ## Step 5 — Plugin MCP union -The pack plugin’s `dependsOn` MCP list = **union** of all `mcpserver:` refs across skill manifests in that pack — not the full set of keys in `mcps.json`. +The plugin plugin’s `dependsOn` MCP list = **union** of all `mcpserver:` refs across skill manifests in that plugin — not the full set of keys in `mcps.json`. ## Sanity checks diff --git a/.claude/skills/compass-manifest-maintenance/references/relationship-rules.md b/.claude/skills/compass-manifest-maintenance/references/relationship-rules.md index 5cd75908..82ca5cef 100644 --- a/.claude/skills/compass-manifest-maintenance/references/relationship-rules.md +++ b/.claude/skills/compass-manifest-maintenance/references/relationship-rules.md @@ -24,7 +24,7 @@ Compass does **not** auto-generate inverse relations for custom kinds (`AiResour | Entity | Ref format | |--------|------------| | Skill | `airesource:ai5-marketplace/` | -| Pack plugin | `airesource:ai5-marketplace/` | +| Plugin plugin | `airesource:ai5-marketplace/` | | Owned MCP | `mcpserver:ai5-marketplace/` | | Canonical MCP | `mcpserver:redhat/` | | System | `default/agentic-plugins` (in `spec.system` only) | @@ -33,23 +33,23 @@ All skills, plugins, and owned MCPs use `metadata.namespace: ai5-marketplace`. ## Lifecycle (`spec.lifecycle`) -- **New skill:** copy `spec.lifecycle` from `/-plugin.yaml` (ask before changing). Skill must not exceed plugin maturity (`development` < `beta` < `production`). -- **New pack:** default plugin to `development`. +- **New skill:** copy `spec.lifecycle` from `/-plugin.yaml` (ask before changing). Skill must not exceed plugin maturity (`development` < `beta` < `production`). +- **New plugin:** default plugin to `development`. ## Files to touch when adding a skill 1. `skills//catalog-info.yaml` — new or updated entity -2. `/catalog-info.yaml` — Location `targets` entry -3. `/-plugin.yaml` — `dependencyOf` skill +2. `/catalog-info.yaml` — Location `targets` entry +3. `/-plugin.yaml` — `dependencyOf` skill 4. Each `mcps/*.yaml` referenced — `dependencyOf` skill (and plugin if plugin depends on MCP) 5. Each depended-on skill manifest — `dependencyOf` orchestrator (skill→skill) -6. Reconcile plugin `dependsOn` MCP union if MCP usage changed pack-wide +6. Reconcile plugin `dependsOn` MCP union if MCP usage changed plugin-wide -## Files to touch when adding a pack +## Files to touch when adding a plugin -1. `/-plugin.yaml` -2. `/catalog-info.yaml` -3. Root `catalog-info.yaml` — add pack Location target +1. `/-plugin.yaml` +2. `/catalog-info.yaml` +3. Root `catalog-info.yaml` — add plugin Location target 4. `system.yaml` — `dependencyOf` plugin entry 5. Register owned MCPs in `mcps/` if new (and `mcps/catalog-info.yaml`, `system.yaml` for MCP) @@ -63,6 +63,6 @@ Add skill→skill `dependsOn` when `SKILL.md` documents: Do **not** infer orchestration from `AGENTS.md` routing alone. -## Registered packs (Compass Location in root) +## Registered plugins (Compass Location in root) -Currently indexed: `ocp-admin`, `rh-sre`, `rh-virt`, `rh-basic`. Packs on disk without root Location targets (`rh-developer`, `rh-ai-engineer`, `rh-automation`) are out of scope until added to root `catalog-info.yaml`. +Currently indexed: `ocp-admin`, `rh-sre`, `rh-virt`, `rh-basic`. Plugins on disk without root Location targets (`rh-developer`, `rh-ai-engineer`, `rh-automation`) are out of scope until added to root `catalog-info.yaml`. diff --git a/.claude/skills/compliance-checker/SKILL.md b/.claude/skills/compliance-checker/SKILL.md index 0e542163..a34cae83 100644 --- a/.claude/skills/compliance-checker/SKILL.md +++ b/.claude/skills/compliance-checker/SKILL.md @@ -30,11 +30,11 @@ Invoke this skill when the user wants to: ``` This validates only staged and unstaged skill changes. -3. **Alternative: validate all skills or a specific pack**: +3. **Alternative: validate all skills or a specific plugin**: ```bash make validate-skill-design - # Or validate a specific pack: - make validate-skill-design PACK=rh-sre + # Or validate a specific plugin: + make validate-skill-design PLUGIN=rh-sre ``` 4. **Report results** to the user: diff --git a/.claude/skills/create-collection/SKILL.md b/.claude/skills/create-collection/SKILL.md index 473257e2..c3b5ec32 100644 --- a/.claude/skills/create-collection/SKILL.md +++ b/.claude/skills/create-collection/SKILL.md @@ -1,12 +1,12 @@ --- name: create-collection description: | - Author or refresh `/.catalog/collection.yaml` and related `.catalog/` artifacts from golden sources (SKILL.md, README, AGENTS.md, Lola marketplace). Use when: - - Adding a new pack or refreshing the collection catalog for GitHub Pages / tooling + Author or refresh `/.catalog/collection.yaml` and related `.catalog/` artifacts from golden sources (SKILL.md, README, AGENTS.md, Lola marketplace). Use when: + - Adding a new plugin or refreshing the collection catalog for GitHub Pages / tooling - Aligning catalog narrative, sample workflows, and decision guide with skills on disk - Preparing a PR after changing skills or marketplace metadata - Outputs only under `/.catalog/` (never overwrite README, SKILL, CLAUDE, or marketplace YAML). + Outputs only under `/.catalog/` (never overwrite README, SKILL, CLAUDE, or marketplace YAML). model: inherit color: blue allowed-tools: Read Glob Grep Bash @@ -14,7 +14,7 @@ allowed-tools: Read Glob Grep Bash # Create collection catalog -**Audience:** Maintainers and assistants updating per-pack `.catalog/` data. +**Audience:** Maintainers and assistants updating per-plugin `.catalog/` data. **Goal:** Produce a coherent `collection.yaml` that passes `make validate-collection-compliance`, using human judgment for synthesis—not a blind dump of frontmatter. @@ -22,43 +22,43 @@ allowed-tools: Read Glob Grep Bash - Repository root as cwd. - Read [COLLECTION_SPEC.md](../../COLLECTION_SPEC.md) and [catalog/schema.yaml](../../catalog/schema.yaml). -- Optional: run `uv run python scripts/scaffold_catalog.py ` for a stdout draft roster. +- Optional: run `uv run python scripts/scaffold_catalog.py ` for a stdout draft roster. ## When to Use -- New marketplace module or new pack directory needs `.catalog/`. +- New marketplace module or new plugin directory needs `.catalog/`. - Skills were added/removed/renamed and roster parity must match disk. - Marketplace `description` / `version` changed and catalog should reflect it (still edit marketplace in git separately). ## Workflow -1. **Resolve pack** — directory name must appear in `union(marketplace/modules[].path, docs/plugins.json keys)` and exist on disk. +1. **Resolve plugin** — directory name must appear in `union(marketplace/modules[].path, docs/plugins.json keys)` and exist on disk. 2. **Read sources in order** (precedence): - `skills/*/SKILL.md` (frontmatter + body for summaries and orchestration hints) - - `/README.md` - - `/AGENTS.md` (intent routing → `skills_decision_guide` ideas) - - Matching row in `marketplace/rh-agentic-collection.yml` in [agentic-catalog](https://github.com/RHEcosystemAppEng/agentic-catalog) (`path` == pack) + - `/README.md` + - `/AGENTS.md` (intent routing → `skills_decision_guide` ideas) + - Matching row in `marketplace/rh-agentic-collection.yml` in [agentic-catalog](https://github.com/RHEcosystemAppEng/agentic-catalog) (`path` == plugin) 3. **Classify skills** — place each skill in `contents.skills` or `contents.orchestration_skills` using maintainer judgment. Optional hint: `metadata.collection.role: orchestration` in `SKILL.md` frontmatter. Names in YAML **must** match the `skills//` directory name. -4. **Write `/.catalog/collection.yaml`** — start with the standard **# banner** (see COLLECTION_SPEC). Include every field required by [catalog/schema.yaml](../../catalog/schema.yaml). Keep inline strings under **500 Unicode code points** for monitored fields (`summary`, `documentation_section`, `mcp_section`, `security_model`, and inline **`deploy_and_use`**); otherwise move prose to a sibling **`.md`** and set **the same field** to a one-line ref, e.g. **`documentation_section: '#documentation_section.md'`** or **`deploy_and_use: '#deploy_and_use.md'`** (see COLLECTION_SPEC). Do **not** use parallel `documentation_section_file` / `mcp_section_file` / `security_model_file` keys. +4. **Write `/.catalog/collection.yaml`** — start with the standard **# banner** (see COLLECTION_SPEC). Include every field required by [catalog/schema.yaml](../../catalog/schema.yaml). Keep inline strings under **500 Unicode code points** for monitored fields (`summary`, `documentation_section`, `mcp_section`, `security_model`, and inline **`deploy_and_use`**); otherwise move prose to a sibling **`.md`** and set **the same field** to a one-line ref, e.g. **`documentation_section: '#documentation_section.md'`** or **`deploy_and_use: '#deploy_and_use.md'`** (see COLLECTION_SPEC). Do **not** use parallel `documentation_section_file` / `mcp_section_file` / `security_model_file` keys. **`deploy_and_use` / install prose:** Follow [COLLECTION_SPEC.md](../../COLLECTION_SPEC.md) **`deploy_and_use` content (install + env + MCP)**. If **`mcps.json`** defines MCP servers, document prerequisites, **`export`** lines for **every `${VAR}`** name used there, Lola + marketplace **`path:`**, optional Claude/Cursor install when those marketplaces are listed, and an MCP configuration subsection. Prefer **`deploy_and_use: '#deploy_and_use.md'`** plus **`deploy_and_use.md`** structured like **`rh-sre/.catalog/deploy_and_use.md`** (see **`rh-virt/.catalog/deploy_and_use.md`** for a kubeconfig-focused variant). **YAML multiline style (`|` literal blocks):** For `contents.description`, every **`summary_markdown`** (regular and orchestration skills), and every **`sample_workflows[].workflow`**, use a **literal block scalar** (`field: |`) instead of a single-quoted string that continues across many YAML lines with spacer blanks. Indent each body line one level deeper than the key line. Inside the block, keep **consecutive lines without empty lines** between the intro, `**Use when:**`, list items, and `**What it does:**` (and similar headings) unless you intentionally want extra paragraph breaks in rendered markdown—reference **`rh-sre`** and **`rh-developer`** `.catalog/collection.yaml` for the house style. Prose with apostrophes (e.g. *What's*) stays readable in `|` without `''` escaping. -5. **Mirror JSON** — from repo root: `uv run python scripts/catalog_yaml_to_json.py --pack ` (or `make catalog-mirror-json`). +5. **Mirror JSON** — from repo root: `uv run python scripts/catalog_yaml_to_json.py --plugin ` (or `make catalog-mirror-json`). 6. **Self-review checklist** - Every on-disk `skills//SKILL.md` appears exactly once in `skills` ∪ `orchestration_skills` (orchestration-only skills such as `/remediation` still live under `skills//`; list them **only** under `contents.orchestration_skills` when they orchestrate others). - No `TODO:` / `TBD` in `sample_workflows.workflow`; each workflow includes `User:` and `-` bullets. - - `skills_decision_guide` empty if the pack has **no** skills; otherwise each `skill_to_use` matches a skill dir. - - `resources[].url` set; `embedded_doc` only if that path exists under the pack. + - `skills_decision_guide` empty if the plugin has **no** skills; otherwise each `skill_to_use` matches a skill dir. + - `resources[].url` set; `embedded_doc` only if that path exists under the plugin. - **Install / deploy (`deploy_and_use`):** **inline** (≤ **500** code points) *or* one-line **`#deploy_and_use.md`** ref (see [COLLECTION_SPEC.md](../../COLLECTION_SPEC.md) **install + env + MCP**). If **`mcps.json`** has MCP servers: fragment (or inline) must include prerequisites, **`export`** examples for each **`${VAR}`** name from **`mcps.json`**, Lola/marketplace **`path:`**, and MCP configuration notes; add Claude Code / Cursor install when **`marketplaces`** lists them. Fragments use the HTML provenance banner. Use **`mcps.json`**, not `.mcp.json`. - **Other long blocks:** **`documentation_section`**, **`mcp_section`**, and **`security_model`** follow **`deploy_and_use`**: inline markdown (≤ **500** code points) **or** one-line **`#fragment.md`** on that same key (sibling under `.catalog/`; no `.catalog/` prefix in the YAML string). - **Publication-style metadata:** **`maturity`** (**required**) — `GREEN` (listed on GitHub Pages catalog) or `ORANGE` (in-repo only until promoted). Also when useful: `support_level`, `author`, `homepage`, `keywords`, `legal_resources` (URLs only). - - **`version` / listing fields:** Align `version` and core listing copy with the matching **`marketplace/rh-agentic-collection.yml`** row in [agentic-catalog](https://github.com/RHEcosystemAppEng/agentic-catalog) (`path` == pack); do not bump marketplace YAML from the catalog workflow. + - **`version` / listing fields:** Align `version` and core listing copy with the matching **`marketplace/rh-agentic-collection.yml`** row in [agentic-catalog](https://github.com/RHEcosystemAppEng/agentic-catalog) (`path` == plugin); do not bump marketplace YAML from the catalog workflow. - **Multiline fields:** `contents.description`, all **`summary_markdown`**, and all **`sample_workflows[].workflow`** use **`|`** block scalars (not long single-quoted multiline); content lines are compact unless extra blank lines are deliberate for markdown. 7. **Validate** — `make validate-collection-compliance` before commit. @@ -66,20 +66,20 @@ allowed-tools: Read Glob Grep Bash ## Dependencies - `make validate-collection-compliance` -- `uv run python scripts/scaffold_catalog.py ` (optional) +- `uv run python scripts/scaffold_catalog.py ` (optional) ## Common Issues - **CI: `collection.json` drift** — regenerate with `make catalog-mirror-json`. - **Roster errors** — YAML `name` must equal the skill folder name, not a display alias. -- **Empty support pack** — if there are no `skills/`, use empty `skills`, `orchestration_skills`, and `skills_decision_guide: []`. +- **Empty support plugin** — if there are no `skills/`, use empty `skills`, `orchestration_skills`, and `skills_decision_guide: []`. - **Unreadable multiline YAML** — replace spanning `'`…`'` blocks with **`field: |`** and indented lines; see step 4 **YAML multiline style**. -- **Thin `deploy_and_use`** — pack has **`mcps.json`** but catalog only says “see README”; add **Environment setup** (`export` for each **`${VAR}`**) and **MCP configuration** per COLLECTION_SPEC (use **`#deploy_and_use.md`** like **rh-sre** / **rh-virt**). +- **Thin `deploy_and_use`** — plugin has **`mcps.json`** but catalog only says “see README”; add **Environment setup** (`export` for each **`${VAR}`**) and **MCP configuration** per COLLECTION_SPEC (use **`#deploy_and_use.md`** like **rh-sre** / **rh-virt**). ## Example usage ```bash uv run python scripts/scaffold_catalog.py rh-sre -uv run python scripts/catalog_yaml_to_json.py --pack rh-sre +uv run python scripts/catalog_yaml_to_json.py --plugin rh-sre make validate-collection-compliance ``` diff --git a/.github/gemini-review-prompt.md b/.github/gemini-review-prompt.md index e7a9e8fb..52c7a76c 100644 --- a/.github/gemini-review-prompt.md +++ b/.github/gemini-review-prompt.md @@ -1,4 +1,4 @@ -You are a senior code reviewer for the agentic-plugins repository — a collection of AI agent skills and plugins for Red Hat platforms. Each pack ships skills, agents, and MCP server configurations for AI marketplaces (Claude Code, Cursor, ChatGPT). +You are a senior code reviewer for the agentic-plugins repository — a collection of AI agent skills and plugins for Red Hat platforms. Each plugin ships skills, agents, and MCP server configurations for AI marketplaces (Claude Code, Cursor, ChatGPT). Review the PR diff against BOTH general code quality AND the project-specific rules provided below. Format your response in GitHub-flavored Markdown. @@ -17,8 +17,8 @@ Check the diff against the project rules injected in PROJECT RULES REFERENCE (fr - **Security**: no hardcoded credentials, no exposed secret values, `${ENV_VAR}` references only - **Skill invocation**: use `/skill-name` slash format, never call MCP tools directly - **Human-in-the-Loop**: required for create/delete/modify/restore/execute ops, not for read-only -- **Pack-persona alignment**: when reviewing new skills, verify that the skill's purpose aligns with the pack's persona (defined in the opening paragraph of the pack's AGENTS.md). Flag any skill that appears to belong in a different pack -- **New packs**: must add pack name to `PACK_DIRS` in `scripts/validate_structure.py`; `docs/data.json` must NOT be committed +- **Plugin-persona alignment**: when reviewing new skills, verify that the skill's purpose aligns with the plugin's persona (defined in the opening paragraph of the plugin's AGENTS.md). Flag any skill that appears to belong in a different plugin +- **New plugins**: `PLUGIN_DIRS` in `scripts/validate_structure.py` is auto-discovered — do NOT flag a PR for not registering a new plugin there; `docs/data.json` must NOT be committed - **Build reminder**: if skills, agents, or `mcps.json` changed, remind author to run `make validate` ### 3. Code Quality Issues diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index e007512e..269082ef 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,6 +1,6 @@ @@ -8,7 +8,7 @@ -## Pack(s) affected +## Plugin(s) affected - [ ] `ocp-admin` - [ ] `rh-ai-engineer` @@ -23,7 +23,7 @@ - [ ] New skill - [ ] New agent -- [ ] New pack +- [ ] New plugin - [ ] Update existing skill / agent - [ ] MCP server config (`mcps.json`) - [ ] Docs / README @@ -34,9 +34,9 @@ - [ ] Created/imported with `/agentic-contribution-skill` - [ ] Manual contribution (validated with `make validate` + `make validate-skill-design-changed`) -## Pack-persona alignment (new skills only) +## Plugin-persona alignment (new skills only) - + ## AGENTS.md compliance diff --git a/.github/workflows/mcp-tool-validation.yml b/.github/workflows/mcp-tool-validation.yml index 152309d8..d1886223 100644 --- a/.github/workflows/mcp-tool-validation.yml +++ b/.github/workflows/mcp-tool-validation.yml @@ -13,8 +13,8 @@ on: - '**/skills/*/SKILL.md' workflow_dispatch: inputs: - pack: - description: 'Pack name to validate (empty = all packs)' + plugin: + description: 'Plugin name to validate (empty = all plugins)' required: false type: string @@ -35,7 +35,7 @@ jobs: - name: Checkout repository uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: - fetch-depth: 0 # full history required for git diff in pack detection + fetch-depth: 0 # full history required for git diff in plugin detection - name: Set up Python uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 @@ -80,7 +80,7 @@ jobs: KUBECONFIG echo "KUBECONFIG=$HOME/.kube/config" >> "$GITHUB_ENV" - - name: Detect changed packs + - name: Detect changed plugins if: github.event_name == 'pull_request' id: detect env: @@ -94,28 +94,28 @@ jobs: echo "changed=false" >> "$GITHUB_OUTPUT" else echo "changed=true" >> "$GITHUB_OUTPUT" - echo "packs=$CHANGED" >> "$GITHUB_OUTPUT" - echo "Changed packs: $CHANGED" + echo "plugins=$CHANGED" >> "$GITHUB_OUTPUT" + echo "Changed plugins: $CHANGED" fi - name: Validate MCP tools env: KUBECONFIG: ${{ env.KUBECONFIG }} EVENT_NAME: ${{ github.event_name }} - INPUT_PACK: ${{ inputs.pack }} - CHANGED_PACKS: ${{ steps.detect.outputs.packs }} - PACKS_CHANGED: ${{ steps.detect.outputs.changed }} + INPUT_PLUGIN: ${{ inputs.plugin }} + CHANGED_PLUGINS: ${{ steps.detect.outputs.plugins }} + PLUGINS_CHANGED: ${{ steps.detect.outputs.changed }} run: | - # Dispatch: manual with pack > PR changed packs > all packs - if [ "$EVENT_NAME" = "workflow_dispatch" ] && [ -n "$INPUT_PACK" ]; then - echo "Manual dispatch: validating pack '$INPUT_PACK'" - python scripts/validate_mcp_tools.py "$INPUT_PACK" - elif [ "$EVENT_NAME" = "pull_request" ] && [ "$PACKS_CHANGED" != "true" ]; then - echo "No packs changed in this PR, skipping" + # Dispatch: manual with plugin > PR changed plugins > all plugins + if [ "$EVENT_NAME" = "workflow_dispatch" ] && [ -n "$INPUT_PLUGIN" ]; then + echo "Manual dispatch: validating plugin '$INPUT_PLUGIN'" + python scripts/validate_mcp_tools.py "$INPUT_PLUGIN" + elif [ "$EVENT_NAME" = "pull_request" ] && [ "$PLUGINS_CHANGED" != "true" ]; then + echo "No plugins changed in this PR, skipping" elif [ "$EVENT_NAME" = "pull_request" ]; then - echo "Validating changed packs: $CHANGED_PACKS" - python scripts/validate_mcp_tools.py $CHANGED_PACKS + echo "Validating changed plugins: $CHANGED_PLUGINS" + python scripts/validate_mcp_tools.py $CHANGED_PLUGINS else - echo "Validating all packs..." + echo "Validating all plugins..." python scripts/validate_mcp_tools.py fi diff --git a/.github/workflows/release-skill-zips.yaml b/.github/workflows/release-skill-zips.yaml index 2bcdecc1..5715c57f 100644 --- a/.github/workflows/release-skill-zips.yaml +++ b/.github/workflows/release-skill-zips.yaml @@ -48,7 +48,7 @@ jobs: gh release delete latest --yes 2>/dev/null || true git tag -f latest git push origin latest --force - gh release create latest dist/*.zip --title "Latest Skill Packs" --notes "Auto-updated on every merge to main. Download the ZIP for your pack." --latest + gh release create latest dist/*.zip --title "Latest Agent Plugins" --notes "Auto-updated on every merge to main. Download the ZIP for your plugin." --latest - name: Upload release assets if: github.event_name == 'release' && github.event.release.tag_name != 'latest' diff --git a/.github/workflows/skill-code-review.yml b/.github/workflows/skill-code-review.yml index d6140489..2ba739ba 100644 --- a/.github/workflows/skill-code-review.yml +++ b/.github/workflows/skill-code-review.yml @@ -1,7 +1,7 @@ # Skill Code Review Workflow # # Automated code review using Google Gemini, validating PRs against project -# rules (CLAUDE.md, SKILL_DESIGN_PRINCIPLES.md, pack-level AGENTS.md). +# rules (CLAUDE.md, SKILL_DESIGN_PRINCIPLES.md, plugin-level AGENTS.md). # # Trigger methods: # 1. PR comment: Maintainer comments "/skill-code-review" @@ -178,13 +178,13 @@ jobs: cat SKILL_DESIGN_PRINCIPLES.md 2>/dev/null || echo "(not found)" } > /tmp/project_rules.txt - CHANGED_PACKS=$(grep -oP '^diff --git a/([^/]+)/' /tmp/pr.diff | sort -u | sed 's|diff --git a/||;s|/||') - for pack in $CHANGED_PACKS; do - if [ -f "$pack/AGENTS.md" ]; then + CHANGED_PLUGINS=$(grep -oP '^diff --git a/([^/]+)/' /tmp/pr.diff | sort -u | sed 's|diff --git a/||;s|/||') + for plugin in $CHANGED_PLUGINS; do + if [ -f "$plugin/AGENTS.md" ]; then { echo "" - echo "=== PACK RULES: $pack/AGENTS.md ===" - cat "$pack/AGENTS.md" + echo "=== PLUGIN RULES: $plugin/AGENTS.md ===" + cat "$plugin/AGENTS.md" } >> /tmp/project_rules.txt fi done diff --git a/.github/workflows/skill-security-scan.yml b/.github/workflows/skill-security-scan.yml index 64d2c265..3e681814 100644 --- a/.github/workflows/skill-security-scan.yml +++ b/.github/workflows/skill-security-scan.yml @@ -116,7 +116,7 @@ jobs: echo "PR #$PR_NUMBER — HEAD: $HEAD_SHA" # --------------------------------------------------------------------------- - # Scan job: runs the security scanner against changed skill packs. + # Scan job: runs the security scanner against changed agent plugins. # --------------------------------------------------------------------------- scan: needs: gate @@ -157,8 +157,8 @@ jobs: - name: Install skill-scanner run: uv pip install --system 'cisco-ai-skill-scanner[google]' - # Detect packs with changed files via GitHub API (safe — no PR code execution) - - name: Detect packs to scan + # Detect plugins with changed files via GitHub API (safe — no PR code execution) + - name: Detect plugins to scan id: detect env: GH_TOKEN: ${{ github.token }} @@ -167,7 +167,7 @@ jobs: gh api "/repos/${{ github.repository }}/pulls/$PR_NUMBER/files" \ --paginate --jq '.[].filename' > /tmp/changed_files.txt - PACKS=$(grep -v '^\.' /tmp/changed_files.txt \ + PLUGINS=$(grep -v '^\.' /tmp/changed_files.txt \ | cut -d'/' -f1 \ | sort -u \ | while read -r dir; do @@ -176,21 +176,21 @@ jobs: fi done) - if [ -z "$PACKS" ]; then - echo "packs=" >> "$GITHUB_OUTPUT" - echo "pack_count=0" >> "$GITHUB_OUTPUT" - echo "No packs to scan" + if [ -z "$PLUGINS" ]; then + echo "plugins=" >> "$GITHUB_OUTPUT" + echo "plugin_count=0" >> "$GITHUB_OUTPUT" + echo "No plugins to scan" else - PACK_COUNT=$(echo "$PACKS" | grep -c . || true) - echo "packs<> "$GITHUB_OUTPUT" - echo "$PACKS" >> "$GITHUB_OUTPUT" + PLUGIN_COUNT=$(echo "$PLUGINS" | grep -c . || true) + echo "plugins<> "$GITHUB_OUTPUT" + echo "$PLUGINS" >> "$GITHUB_OUTPUT" echo "EOF" >> "$GITHUB_OUTPUT" - echo "pack_count=$PACK_COUNT" >> "$GITHUB_OUTPUT" - echo "Packs to scan ($PACK_COUNT): $PACKS" + echo "plugin_count=$PLUGIN_COUNT" >> "$GITHUB_OUTPUT" + echo "Plugins to scan ($PLUGIN_COUNT): $PLUGINS" fi - name: Check scanner credentials - if: steps.detect.outputs.pack_count != '0' + if: steps.detect.outputs.plugin_count != '0' id: creds env: SKILL_SCANNER_LLM_API_KEY: ${{ secrets.SKILL_SCANNER_LLM_API_KEY }} @@ -203,7 +203,7 @@ jobs: fi - name: Run security scan - if: steps.detect.outputs.pack_count != '0' && steps.creds.outputs.available == 'true' + if: steps.detect.outputs.plugin_count != '0' && steps.creds.outputs.available == 'true' id: scan env: SKILL_SCANNER_LLM_API_KEY: ${{ secrets.SKILL_SCANNER_LLM_API_KEY }} @@ -212,11 +212,11 @@ jobs: mkdir -p security-reports SCAN_FAILED=false - while IFS= read -r pack; do - [ -z "$pack" ] && continue - echo "=== Scanning: $pack ===" + while IFS= read -r plugin; do + [ -z "$plugin" ] && continue + echo "=== Scanning: $plugin ===" - skill-scanner scan-all "$pack/skills" \ + skill-scanner scan-all "$plugin/skills" \ --recursive \ --use-behavioral \ --use-llm \ @@ -226,10 +226,10 @@ jobs: --fail-on-severity medium \ --format markdown \ --detailed \ - --output "security-reports/security-report-${pack}.md" || SCAN_FAILED=true + --output "security-reports/security-report-${plugin}.md" || SCAN_FAILED=true echo "" - done <<< "${{ steps.detect.outputs.packs }}" + done <<< "${{ steps.detect.outputs.plugins }}" if [ "$SCAN_FAILED" = "true" ]; then echo "scan_result=failed" >> "$GITHUB_OUTPUT" @@ -239,7 +239,7 @@ jobs: - name: Upload security reports id: upload - if: steps.detect.outputs.pack_count != '0' && steps.creds.outputs.available == 'true' && always() + if: steps.detect.outputs.plugin_count != '0' && steps.creds.outputs.available == 'true' && always() uses: actions/upload-artifact@v4 with: name: security-reports @@ -249,7 +249,7 @@ jobs: - name: Post scan summary if: > - steps.detect.outputs.pack_count != '0' && + steps.detect.outputs.plugin_count != '0' && steps.creds.outputs.available == 'true' && always() env: @@ -294,9 +294,9 @@ jobs: if [ -d "security-reports" ]; then for report in security-reports/security-report-*.md; do [ -f "$report" ] || continue - pack=$(basename "$report" .md | sed 's/^security-report-//') + plugin=$(basename "$report" .md | sed 's/^security-report-//') echo "
" - echo "📋 $pack" + echo "📋 $plugin" echo "" cat "$report" echo "" @@ -334,7 +334,7 @@ jobs: fi - name: Check scan results - if: steps.detect.outputs.pack_count != '0' && steps.creds.outputs.available == 'true' + if: steps.detect.outputs.plugin_count != '0' && steps.creds.outputs.available == 'true' run: | if [ "${{ steps.scan.outputs.scan_result }}" = "failed" ]; then echo "❌ Security scan found MEDIUM or higher severity issues — blocking merge" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5d1d7c02..040b43eb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,7 +25,7 @@ repos: (?x)^( catalog/.*| marketplace/.*| - scripts/(validate_structure|validate_collection_compliance|validate_collection_schema|validate_compass_manifests|collection_validate_lib|pack_registry|catalog_yaml_to_json)\.py| + scripts/(validate_structure|validate_collection_compliance|validate_collection_schema|validate_compass_manifests|collection_validate_lib|catalog_yaml_to_json)\.py| (rh-[-a-z0-9]+|ocp-admin)/\.catalog/.*| (rh-[-a-z0-9]+|ocp-admin)/skills/[^/]+/SKILL\.md| (rh-[-a-z0-9]+|ocp-admin)/skills/[^/]+/catalog-info\.yaml| diff --git a/CLAUDE.md b/CLAUDE.md index 7987b134..c16fc75a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## What This Repository Is -This is a **skills source repository** — one of potentially many that feed into the [agentic-catalog](https://github.com/RHEcosystemAppEng/agentic-catalog). It contains agentic packs with skills, MCP server configurations, AI-optimized documentation, and catalog metadata for Red Hat platforms. +This is a **skills source repository** — one of potentially many that feed into the [agentic-catalog](https://github.com/RHEcosystemAppEng/agentic-catalog). It contains agent plugins with skills, MCP server configurations, AI-optimized documentation, and catalog metadata for Red Hat platforms. Contributors work here to create, improve, and validate skills. An internal process periodically fetches content from this repository (and others like it) to build the unified catalog and marketplace. **This repo does not serve the marketplace directly** — it is a source of skills that the catalog aggregates. @@ -14,13 +14,13 @@ Contributors work here to create, improve, and validate skills. An internal proc agentic-plugins/ ├── catalog-info.yaml # Root Location — entry point for Compass ingestion ├── system.yaml # System entity (agentic-plugins) — models the whole repo -├── rh-sre/ # Site Reliability Engineering pack (reference implementation) -├── rh-developer/ # Developer tools pack -├── ocp-admin/ # OpenShift administration pack -├── rh-virt/ # Virtualization management pack -├── rh-basic/ # Getting started pack -├── rh-ai-engineer/ # AI/ML engineering pack -├── rh-automation/ # IT automation pack +├── rh-sre/ # Site Reliability Engineering plugin (reference implementation) +├── rh-developer/ # Developer tools plugin +├── ocp-admin/ # OpenShift administration plugin +├── rh-virt/ # Virtualization management plugin +├── rh-basic/ # Getting started plugin +├── rh-ai-engineer/ # AI/ML engineering plugin +├── rh-automation/ # IT automation plugin ├── mcps/ # MCP server Compass manifests (3 MCPServer entities) ├── eval/ # Skill evaluation reports (report.json + report.md per skill) ├── scripts/ # Validation and CI helper scripts @@ -31,21 +31,21 @@ agentic-plugins/ ### `catalog/schema.yaml` -This file defines the JSON Schema used by `validate_collection_schema.py` and `validate_collection_compliance.py` to validate each pack's `.catalog/collection.yaml`. It is not related to the catalog marketplace repository — it is a validation artifact that ensures catalog metadata is well-formed before the catalog build process consumes it. +This file defines the JSON Schema used by `validate_collection_schema.py` and `validate_collection_compliance.py` to validate each plugin's `.catalog/collection.yaml`. It is not related to the catalog marketplace repository — it is a validation artifact that ensures catalog metadata is well-formed before the catalog build process consumes it. -### Agentic Pack Architecture +### Agent Plugin Architecture -Each pack is persona-specific and follows this structure: +Each plugin is persona-specific and follows this structure: ``` -/ -├── catalog-info.yaml # Location entity — indexes this pack's Compass manifests -├── -plugin.yaml # AiResource (type: plugin) — defines the pack itself +/ +├── catalog-info.yaml # Location entity — indexes this plugin's Compass manifests +├── -plugin.yaml # AiResource (type: plugin) — defines the plugin itself ├── AGENTS.md # AI Context Module instruction routing (persona, skills, rules) -├── README.md # Pack description, persona, target marketplaces +├── README.md # Plugin description, persona, target marketplaces ├── mcps.json # MCP server configurations (uses env vars for credentials) ├── .catalog/ # Collection metadata consumed by the catalog build process -│ ├── collection.yaml # Pack catalog definition (golden source for catalog) +│ ├── collection.yaml # Plugin catalog definition (golden source for catalog) │ └── collection.json # Deterministic JSON mirror of collection.yaml ├── skills/ # Specialized task executors (including orchestration skills) │ └── / @@ -56,7 +56,7 @@ Each pack is persona-specific and follows this structure: ### Relationship with the Catalog -Each pack's `.catalog/` directory contains metadata that describes the pack for the marketplace. This metadata stays here, alongside the skills it describes. The catalog build process reads it from this repo to assemble the unified marketplace. The golden sources are always `SKILL.md`, `AGENTS.md`, `README.md`, and `mcps.json` — `.catalog/` is derived from them, never the other way around. +Each plugin's `.catalog/` directory contains metadata that describes the plugin for the marketplace. This metadata stays here, alongside the skills it describes. The catalog build process reads it from this repo to assemble the unified marketplace. The golden sources are always `SKILL.md`, `AGENTS.md`, `README.md`, and `mcps.json` — `.catalog/` is derived from them, never the other way around. ### Compass / Backstage Manifests @@ -66,9 +66,9 @@ The repository is registered in [Red Hat Compass](https://compass.redhat.com) (i | Kind | Purpose | spec.type | Count | |------|---------|-----------|-------| -| **Location** | Index that references other manifest files | — | 6 (1 root + 4 packs + 1 mcps) | +| **Location** | Index that references other manifest files | — | 6 (1 root + 4 plugins + 1 mcps) | | **System** | Top-level grouping for the repository | — | 1 (`agentic-plugins`) | -| **AiResource** | Skills and pack definitions | `plugin` (packs) / `skill` (skills) | 4 packs + 37 skills | +| **AiResource** | Skills and plugin definitions | `plugin` (plugins) / `skill` (skills) | 4 plugins + 37 skills | | **MCPServer** | MCP server configurations | `local` / `remote` | 3 | #### Location Hierarchy @@ -98,12 +98,12 @@ All entities (skills, plugins, and MCP servers) share a single namespace: `ai5-m #### Entity Reference Formats - Skills: `airesource:ai5-marketplace/` -- Pack plugins: `airesource:ai5-marketplace/` +- Plugins: `airesource:ai5-marketplace/` - MCP servers: `mcpserver:ai5-marketplace/` #### Adding Compass Manifests for a New Skill -When adding a skill, create `skills//catalog-info.yaml`. Set `spec.lifecycle` from the pack plugin (`/-plugin.yaml`); default to the plugin value and ask the user before changing it — a skill may match the plugin or use a **less mature** lifecycle only (never above the plugin). New packs default the plugin to `development`. +When adding a skill, create `skills//catalog-info.yaml`. Set `spec.lifecycle` from the plugin manifest (`/-plugin.yaml`); default to the plugin value and ask the user before changing it — a skill may match the plugin or use a **less mature** lifecycle only (never above the plugin). New plugins default the plugin to `development`. ```yaml apiVersion: backstage.io/v1alpha1 @@ -118,7 +118,7 @@ metadata: distribution: external annotations: backstage.io/source-location: >- - url:https://github.com/RHEcosystemAppEng/agentic-plugins/blob/main//skills//SKILL.md + url:https://github.com/RHEcosystemAppEng/agentic-plugins/blob/main//skills//SKILL.md tags: - ai-skill links: @@ -127,7 +127,7 @@ metadata: icon: github spec: type: skill - lifecycle: # from -plugin.yaml; same or less mature than plugin + lifecycle: # from -plugin.yaml; same or less mature than plugin owner: group:redhat/ai5-marketplace disciplines: - @@ -135,20 +135,20 @@ spec: - agents: [] dependsOn: - - airesource:ai5-marketplace/ + - airesource:ai5-marketplace/ # Add mcpserver and airesource (skill) dependencies as needed - mcpserver:ai5-marketplace/ ``` Then update **both sides** of every relationship: -1. Add the file as a target in the pack's `catalog-info.yaml` Location -2. Add the skill to the plugin's `dependencyOf` list in `-plugin.yaml` +1. Add the file as a target in the plugin's `catalog-info.yaml` Location +2. Add the skill to the plugin's `dependencyOf` list in `-plugin.yaml` 3. Add the skill to each referenced MCP server's `dependencyOf` list in `mcps/.yaml` 4. If the skill depends on other skills, add `dependencyOf` entries in those skills' manifests ## Contributing -Skills are added directly to this repository, inside an existing pack. The contributor opens a PR, skills are reviewed and merged, and maintainers own them from that point. Use `/agentic-contribution-skill` in Claude Code or follow [CONTRIBUTING.md](CONTRIBUTING.md). +Skills are added directly to this repository, inside an existing plugin. The contributor opens a PR, skills are reviewed and merged, and maintainers own them from that point. Use `/agentic-contribution-skill` in Claude Code or follow [CONTRIBUTING.md](CONTRIBUTING.md). ## Working with Skills @@ -172,7 +172,7 @@ The catalog's internal process applies its own evaluation and assigns a scorecar 1. **Run automated validation (Tier 1):** ```bash - uv run python scripts/validate_skills_tier1.py /skills//SKILL.md + uv run python scripts/validate_skills_tier1.py /skills//SKILL.md ``` 2. **Manual review (Tier 2):** @@ -189,7 +189,7 @@ The catalog's internal process applies its own evaluation and assigns a scorecar ### MCP Server Integration -MCP servers are configured in `/mcps.json`: +MCP servers are configured in `/mcps.json`: ```json { "mcpServers": { @@ -213,7 +213,7 @@ MCP servers are configured in `/mcps.json`: ## AI-Optimized Documentation (rh-sre Reference) -The `rh-sre` pack demonstrates advanced documentation patterns for token optimization: +The `rh-sre` plugin demonstrates advanced documentation patterns for token optimization: ### Semantic Indexing System @@ -258,22 +258,22 @@ last_updated: YYYY-MM-DD ### Files - Skills: `skills//SKILL.md` (uppercase SKILL.md) -- Compass manifests: `catalog-info.yaml` (Locations), `-plugin.yaml` (pack AiResource), `system.yaml` (System entities) +- Compass manifests: `catalog-info.yaml` (Locations), `-plugin.yaml` (plugin AiResource), `system.yaml` (System entities) - Docs: Lowercase with dashes, categorized by directory ## Development Workflow -### Creating a New Agentic Pack +### Creating a New Agent Plugin -1. Create pack folder: `/` +1. Create plugin folder: `/` 2. Add `README.md` with description, persona, marketplaces 3. Add `AGENTS.md` with persona, skill-first rule, intent routing table, MCP servers, and global rules (see [rh-ai-engineer/AGENTS.md](rh-ai-engineer/AGENTS.md) for reference) 4. Create `skills/` directory -5. Add `mcps.json` when the pack integrates MCP servers (use `${VAR}` for secrets) +5. Add `mcps.json` when the plugin integrates MCP servers (use `${VAR}` for secrets) 6. Create Compass manifests: - - `-plugin.yaml` — AiResource with `type: plugin`, `system: agentic-plugins` + - `-plugin.yaml` — AiResource with `type: plugin`, `system: agentic-plugins` - `catalog-info.yaml` — Location targeting the plugin file and all skill catalog-info.yaml files -7. Add the pack's `catalog-info.yaml` as a target in the root `catalog-info.yaml` +7. Add the plugin's `catalog-info.yaml` as a target in the root `catalog-info.yaml` 8. Update main `README.md` table with link ### Adding a Skill @@ -289,11 +289,11 @@ last_updated: YYYY-MM-DD - Workflow with precise parameters - Dependencies declaration 4. Include concrete examples and complete error handling -5. Update the pack's `AGENTS.md` intent routing table to include the new skill -6. Run **compass-manifest-maintenance** (`.claude/skills/compass-manifest-maintenance/`) to create or update Compass manifests — skill `catalog-info.yaml`, pack Location targets, plugin/MCP inverse `dependencyOf` (see "Adding Compass Manifests for a New Skill") +5. Update the plugin's `AGENTS.md` intent routing table to include the new skill +6. Run **compass-manifest-maintenance** (`.claude/skills/compass-manifest-maintenance/`) to create or update Compass manifests — skill `catalog-info.yaml`, plugin Location targets, plugin/MCP inverse `dependencyOf` (see "Adding Compass Manifests for a New Skill") 7. Run `make validate-compass-manifests` (or full `make validate`) 8. Test with `Skill` tool invocation -9. Validate with `uv run python scripts/validate_skills_tier1.py /skills//SKILL.md` +9. Validate with `uv run python scripts/validate_skills_tier1.py /skills//SKILL.md` **Collection-Specific Standards:** - **rh-virt**: Follow `rh-virt/SKILL_TEMPLATE.md` for enhanced quality standards including mandatory Common Issues and Example Usage sections @@ -324,14 +324,14 @@ last_updated: YYYY-MM-DD ### rh-sre (Full-Featured Reference) -The most complete pack, demonstrating: +The most complete plugin, demonstrating: - Full skill orchestration (13 skills) - Orchestration skills (remediation skill orchestrates 6 skills) - AI-optimized documentation system - MCP server integration - Red Hat Lightspeed platform integration -When creating new packs, use `rh-sre` as the architectural reference. +When creating new plugins, use `rh-sre` as the architectural reference. ### rh-virt (Quality-Controlled Pattern) @@ -341,7 +341,7 @@ Demonstrates skill quality standardization: - Mandatory Common Issues and Example Usage sections - Consistent section ordering and formatting -Use `rh-virt` as reference for packs requiring high consistency and maintainability. +Use `rh-virt` as reference for plugins requiring high consistency and maintainability. ## Key Principles @@ -359,7 +359,7 @@ Use `rh-virt` as reference for packs requiring high consistency and maintainabil ### Documentation & Quality 8. **Official sources only** - Document all sources in SOURCES.md 9. **Production-ready examples** - No toy code, include error handling -10. **Persona-focused design** - Each pack serves specific user roles +10. **Persona-focused design** - Each plugin serves specific user roles **Validation:** - Design principles and requirements: [SKILL_DESIGN_PRINCIPLES.md](./SKILL_DESIGN_PRINCIPLES.md) diff --git a/CODEOWNERS b/CODEOWNERS index 6eab6433..c69ded03 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -7,7 +7,7 @@ # Default: all maintainers review anything not matched below * @r2dedios @dmartinol @ikrispin @nemerna -# Pack owners +# Plugin owners rh-sre/ @TomerFi @r2dedios @dmartinol rh-developer/ @TomerFi @ikrispin @r2dedios @dmartinol rh-virt/ @TomerFi @r2dedios @dmartinol diff --git a/COLLECTION_SPEC.md b/COLLECTION_SPEC.md index 9e68c565..6541bed0 100644 --- a/COLLECTION_SPEC.md +++ b/COLLECTION_SPEC.md @@ -1,6 +1,6 @@ # Collection catalog specification -This repository uses a **pack-local collection catalog**: curated metadata and summaries live under **`/.catalog/`** (YAML as the source of record, JSON as a deterministic mirror for consumers that prefer it). **Golden sources** are pack `SKILL.md` files, `README.md`, and `AGENTS.md`. Catalog files **describe** the collection for tooling and documentation; they are **authored** primarily via the [**create-collection**](.claude/skills/create-collection/SKILL.md) skill (assistant + maintainer + PR review) and must not overwrite READMEs. +This repository uses a **plugin-local collection catalog**: curated metadata and summaries live under **`/.catalog/`** (YAML as the source of record, JSON as a deterministic mirror for consumers that prefer it). **Golden sources** are plugin `SKILL.md` files, `README.md`, and `AGENTS.md`. Catalog files **describe** the collection for tooling and documentation; they are **authored** primarily via the [**create-collection**](.claude/skills/create-collection/SKILL.md) skill (assistant + maintainer + PR review) and must not overwrite READMEs. **Machine validation:** [`catalog/schema.yaml`](catalog/schema.yaml) (JSON Schema expressed in YAML) and [`scripts/validate_collection_compliance.py`](scripts/validate_collection_compliance.py). These checks are primarily structural and cannot fully evaluate semantic parity with golden-source docs. **Required review gate:** run an AI semantic alignment review (via [`.claude/skills/collection-compliance/SKILL.md`](.claude/skills/collection-compliance/SKILL.md)) to confirm catalog metadata/fragments remain aligned with `SKILL.md`, `README.md`, and `AGENTS.md`. @@ -8,7 +8,7 @@ This repository uses a **pack-local collection catalog**: curated metadata and s | Value | Meaning | |-------|---------| -| **`GREEN`** | Pack is ready for promotion to the public catalog. | +| **`GREEN`** | Plugin is ready for promotion to the public catalog. | | **`ORANGE`** | Collection metadata is maintained under `.catalog/` for validation and future promotion; excluded from the public catalog surface until explicitly moved to **`GREEN`**. | Set in **`collection.yaml`** as a plain string (`maturity: GREEN` or `maturity: ORANGE`). @@ -17,44 +17,44 @@ Set in **`collection.yaml`** as a plain string (`maturity: GREEN` or `maturity: | Path | Purpose | |------|---------| -| `/.catalog/collection.yaml` | Canonical catalog document (YAML) | -| `/.catalog/collection.json` | Deterministic JSON mirror of YAML (CI fails on drift) | -| `/.catalog/*.md` | Optional prose fragments, **siblings of** `collection.yaml`. Reference them with **`#.md`** (quoted in YAML) **on the same field** as inline text would use—for example `documentation_section: '#docs.md'` or `deploy_and_use: '#install.md'`. If inline text in `collection.yaml` for a monitored field exceeds **`CATALOG_INLINE_CHAR_LIMIT`** (500 Unicode code points; see `scripts/collection_validate_lib.py`), move prose here and set **that same field** to the ref. | +| `/.catalog/collection.yaml` | Canonical catalog document (YAML) | +| `/.catalog/collection.json` | Deterministic JSON mirror of YAML (CI fails on drift) | +| `/.catalog/*.md` | Optional prose fragments, **siblings of** `collection.yaml`. Reference them with **`#.md`** (quoted in YAML) **on the same field** as inline text would use—for example `documentation_section: '#docs.md'` or `deploy_and_use: '#install.md'`. If inline text in `collection.yaml` for a monitored field exceeds **`CATALOG_INLINE_CHAR_LIMIT`** (500 Unicode code points; see `scripts/collection_validate_lib.py`), move prose here and set **that same field** to the ref. | **Multiline YAML in `collection.yaml`:** For `contents.description`, each **`summary_markdown`**, and each **`sample_workflows[].workflow`**, authors should use YAML **literal block scalars** (`field: |`) with indented lines—see step 4 of the [**create-collection**](.claude/skills/create-collection/SKILL.md) skill (reference **`rh-sre`** / **`rh-developer`** `.catalog/collection.yaml`). CI does not assert this style; it is a maintainability convention. ### External references (`#…md` on the same field) -- **Path rule:** refs are **siblings of** `collection.yaml` inside **`/.catalog/`**. Write **`#install.md`**, not `#.catalog/install.md` (omit the `.catalog/` segment in the string). +- **Path rule:** refs are **siblings of** `collection.yaml` inside **`/.catalog/`**. Write **`#install.md`**, not `#.catalog/install.md` (omit the `.catalog/` segment in the string). - **One field, two shapes:** for **`deploy_and_use`**, **`documentation_section`**, **`mcp_section`**, and **`security_model`**, the value is either **inline** markdown or a **one-line** fragment ref **`#.md`**. Do **not** use separate `documentation_section_file` / `mcp_section_file` / `security_model_file` keys. - **Monitored inline length:** for **`summary`**, **`documentation_section`**, **`mcp_section`**, and **`security_model`**, if the value is **inline** (not a `#…md` ref) and longer than **500 Unicode code points**, move the prose to a fragment file and set **that same key** to **`#.md`** (one line only). For **`deploy_and_use`**, the same limit applies when it is **inline** markdown (not a one-line ref). -- **`deploy_and_use` (two flavors):** (1) **Inline** — markdown in YAML, ≤ **500** code points unless you externalize. (2) **File ref** — one line only: **`#.md`** next to `collection.yaml`. CI resolves the file under **`/.catalog/`**. +- **`deploy_and_use` (two flavors):** (1) **Inline** — markdown in YAML, ≤ **500** code points unless you externalize. (2) **File ref** — one line only: **`#.md`** next to `collection.yaml`. CI resolves the file under **`/.catalog/`**. - **Fragment ref values:** must start with **`#`** (e.g. `#documentation_section.md`). Legacy `#.catalog/…` is accepted and normalized to a sibling path. ### `deploy_and_use` content (install + env + MCP) Consumers read **`deploy_and_use`** (resolved from inline YAML or from **`#deploy_and_use.md`**) for marketplace install steps and operator setup. **CI does not yet cross-check `mcps.json` or README install parity;** reviewers enforce this section with the [**create-collection**](.claude/skills/create-collection/SKILL.md) and [**collection-compliance**](.claude/skills/collection-compliance/SKILL.md) workflows. -**When `/mcps.json` defines one or more MCP servers**, the prose behind **`deploy_and_use`** (inline or fragment) **must** cover, in substance: +**When `/mcps.json` defines one or more MCP servers**, the prose behind **`deploy_and_use`** (inline or fragment) **must** cover, in substance: 1. **Prerequisites** — Cluster/product access, CLIs, operators, or accounts needed before install, aligned with **`README.md`** / **`AGENTS.md`**. 2. **Environment setup** — Example **`export VAR=...`** (or host env equivalent) for **every** environment variable **name** referenced in **`mcps.json`** via **`${VAR}`** in `command`, `args`, or `env`. Variable **names** must match **`mcps.json`** exactly. State that secrets are never committed and must not be echoed in assistant output. -3. **MCP configuration** — Server definitions live in **`mcps.json`** at the pack root; use **`${...}`** placeholders only; briefly note isolation/network/credentials posture if it affects the user (see existing pack fragments). -4. **Installation** — At minimum **Lola** (`lola install -f `). If the catalog includes **Claude Code** or **Cursor**, include install notes for those hosts (copy the pattern from **`rh-sre/.catalog/deploy_and_use.md`**). +3. **MCP configuration** — Server definitions live in **`mcps.json`** at the plugin root; use **`${...}`** placeholders only; briefly note isolation/network/credentials posture if it affects the user (see existing plugin fragments). +4. **Installation** — At minimum **Lola** (`lola install -f `). If the catalog includes **Claude Code** or **Cursor**, include install notes for those hosts (copy the pattern from **`rh-sre/.catalog/deploy_and_use.md`**). **Layout recommendation:** Prefer **`deploy_and_use: '#deploy_and_use.md'`** and a sibling **`deploy_and_use.md`** so `collection.yaml` stays short. Use the **same section order** as **`rh-sre/.catalog/deploy_and_use.md`**: Prerequisites → Environment setup → Installation (Lola, then Claude Code / Cursor as applicable) → MCP configuration. For a kubeconfig-only MCP story, see **`rh-virt/.catalog/deploy_and_use.md`**. -**Packs with no MCP servers** (or a trivial single-token env story): a compact **`deploy_and_use: |`** under **500** Unicode code points is acceptable if it still states Lola/repo install and defers detail to **`README.md`** where needed. +**Plugins with no MCP servers** (or a trivial single-token env story): a compact **`deploy_and_use: |`** under **500** Unicode code points is acceptable if it still states Lola/repo install and defers detail to **`README.md`** where needed. -**Plugin / install IDs:** default `id` equals the pack directory name. Overrides: **`rh-virt`** → `openshift-virtualization`; **`ocp-admin`** → `openshift-administration`. +**Plugin / install IDs:** default `id` equals the plugin directory name. Overrides: **`rh-virt`** → `openshift-virtualization`; **`ocp-admin`** → `openshift-administration`. -## Source precedence (pack-local) +## Source precedence (plugin-local) When multiple sources could supply the same logical field: 1. **`skills/*/SKILL.md`** (per-skill `name`, `description`, body for `summary_markdown` hints) -2. **`/README.md`** -3. **`/AGENTS.md`** (intent routing for decision-guide hints, personas) +2. **`/README.md`** +3. **`/AGENTS.md`** (intent routing for decision-guide hints, personas) ## Provenance banners diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 67acc557..a455c70c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,13 +28,13 @@ The fastest way to contribute is using `/agentic-contribution-skill` in Claude C 2. Open the project in Claude Code 3. Run `/agentic-contribution-skill` and follow the prompts -The skill handles pack selection, AGENTS.md routing, validation (Tier 1 + Tier 2), and git workflow automatically. +The skill handles plugin selection, AGENTS.md routing, validation (Tier 1 + Tier 2), and git workflow automatically. -## Pack Selection +## Plugin Selection -Each pack targets a specific persona. Choose the one that matches your skill: +Each plugin targets a specific persona. Choose the one that matches your skill: -| Pack | Persona | Use when | +| Plugin | Persona | Use when | |------|---------|----------| | `rh-sre` | Site Reliability Engineers | CVE remediation, system compliance, RHEL automation | | `rh-developer` | Application Developers | App deployment, S2I builds, Helm charts | @@ -44,16 +44,16 @@ Each pack targets a specific persona. Choose the one that matches your skill: | `rh-automation` | Automation Leads | Ansible AAP governance, safety checks | | `rh-basic` | General Red Hat Users | CVE diagnostics, lifecycle, patching, support cases, troubleshooting | -Not sure which pack? The skill will suggest one based on your skill's content. +Not sure which plugin? The skill will suggest one based on your skill's content. ## Manual Contribution If you prefer to create skills manually: 1. Read the standards: [SKILL_DESIGN_PRINCIPLES.md](SKILL_DESIGN_PRINCIPLES.md) -2. Create `/skills//SKILL.md` following the template -3. Update `/AGENTS.md` intent routing table -4. Validate Tier 1: `uv run python scripts/validate_skills_tier1.py /skills//SKILL.md` +2. Create `/skills//SKILL.md` following the template +3. Update `/AGENTS.md` intent routing table +4. Validate Tier 1: `uv run python scripts/validate_skills_tier1.py /skills//SKILL.md` 5. Validate Tier 2: `make validate-skill-design-changed` Both tiers must pass before submitting a PR. @@ -63,9 +63,9 @@ Both tiers must pass before submitting a PR. - [ ] Tier 1 validation passed (agentskills.io spec) - [ ] Tier 2 validation passed (design principles) - [ ] Compass manifests and references layout validated: `make validate-compass-manifests` -- [ ] Skill doc links validated: `uv run python scripts/validate_skill_doc_links.py /skills//SKILL.md` -- [ ] Skill doc tree links validated: `uv run python scripts/validate_docs_tree_links.py /skills//SKILL.md` -- [ ] Pack AGENTS.md intent routing updated +- [ ] Skill doc links validated: `uv run python scripts/validate_skill_doc_links.py /skills//SKILL.md` +- [ ] Skill doc tree links validated: `uv run python scripts/validate_docs_tree_links.py /skills//SKILL.md` +- [ ] Plugin AGENTS.md intent routing updated - [ ] Tested skill locally by invoking it in Claude Code - [ ] No credentials hardcoded (use `${ENV_VAR}` format) - [ ] Human-in-the-loop confirmation for destructive operations diff --git a/Makefile b/Makefile index df395bcb..5fc4db9e 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ help: @echo " validate-collection-compliance - Full .catalog compliance (includes collection.json drift)" @echo " validate-compass-manifests - Compass manifests, roster, refs, and skill references/ layout" @echo " validate-lifecycle-ceiling - Compass lifecycle ceiling (skill <= plugin lifecycle) + unit tests" - @echo " validate-skill-design - Validate all skills (use PACK=rh-sre for a specific pack)" + @echo " validate-skill-design - Validate all skills (use PLUGIN=rh-sre for a specific plugin)" @echo " validate-skill-design-changed - Validate only changed skills (staged + unstaged, for local dev)" @echo " validate-mcp-tools - Validate allowed-tools against live MCP servers (requires podman)" @echo " validate-spelling - Run codespell spell check on all files" @@ -116,14 +116,22 @@ validate-lifecycle-ceiling: check-uv @uv run python scripts/test_validate_lifecycle_ceiling.py validate-skill-design: check-uv - @uv run python scripts/validate_skills_tier2.py $(if $(PACK),$(PACK)) + @if [ -n "$(PACK)" ]; then \ + echo "Error: PACK= was renamed to PLUGIN= (e.g. make validate-skill-design PLUGIN=rh-sre)"; \ + exit 1; \ + fi + @uv run python scripts/validate_skills_tier2.py $(if $(PLUGIN),$(PLUGIN)) validate-skill-design-changed: check-uv @VALIDATE_INCLUDE_UNCOMMITTED=1 ./scripts/ci-validate-changed-skills.sh validate-mcp-tools: check-uv + @if [ -n "$(PACK)" ]; then \ + echo "Error: PACK= was renamed to PLUGIN= (e.g. make validate-mcp-tools PLUGIN=rh-sre)"; \ + exit 1; \ + fi @echo "Validating MCP tool references against live servers..." - @uv run python scripts/validate_mcp_tools.py $(if $(PACK),$(PACK)) + @uv run python scripts/validate_mcp_tools.py $(if $(PLUGIN),$(PLUGIN)) @echo "MCP tool validation complete!" validate-spelling: check-uv diff --git a/README.md b/README.md index 1c2dcfcb..28887e51 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,9 @@ --- -## Available Packs +## Available Plugins -| Pack | Skills | Description | Persona | +| Plugin | Skills | Description | Persona | |------|--------|-------------|---------| | **[rh-sre](rh-sre/README.md)** | 13 | CVE remediation, system compliance, RHEL automation | Site Reliability Engineers | | **[rh-developer](rh-developer/README.md)** | 14 | Application deployment, S2I builds, Helm charts | Application Developers | @@ -26,17 +26,17 @@ | **[rh-automation](rh-automation/README.md)** | 11 | Ansible Automation Platform governance, safety checks | Automation Leads | | **[rh-basic](rh-basic/README.md)** | 6 | CVE diagnostics, lifecycle, patching, support cases | General Red Hat Users | -See each pack's README for available skills and usage examples. +See each plugin's README for available skills and usage examples. The `eval/` directory contains skill evaluation reports (`report.json` + `report.md` per skill) generated by an external evaluation pipeline. -### Download Skill Packs +### Download Skill Plugins -Pre-packaged ZIP files are available on the [Releases page](https://github.com/RHEcosystemAppEng/agentic-plugins/releases). The `latest` release is auto-updated on every merge to main. Each ZIP contains all skills for a pack with documentation included. +Pre-packaged ZIP files are available on the [Releases page](https://github.com/RHEcosystemAppEng/agentic-plugins/releases). The `latest` release is auto-updated on every merge to main. Each ZIP contains all skills for a plugin with documentation included. To use them: 1. Go to the [latest release](https://github.com/RHEcosystemAppEng/agentic-plugins/releases/tag/latest) -2. Download the ZIP for your pack (e.g., `ocp-admin.zip`) +2. Download the ZIP for your plugin (e.g., `ocp-admin.zip`) 3. Upload to your AI agent of choice (e.g., ChatGPT Custom GPT, Claude) --- @@ -45,8 +45,8 @@ To use them: 1. **Claude Code** (latest version recommended) or **Cursor** 2. **Container Runtime** (Podman or Docker) for MCP servers -3. **Network Access** to Red Hat platforms (depending on packs used) -4. **Credentials**: Red Hat API keys, cluster kubeconfigs, service tokens (per pack) +3. **Network Access** to Red Hat platforms (depending on plugins used) +4. **Credentials**: Red Hat API keys, cluster kubeconfigs, service tokens (per plugin) --- @@ -64,15 +64,15 @@ To use them: # Install dependencies (first time) make install -# Validate pack structure + compliance +# Validate plugin structure + compliance make validate # Validate only changed skills (recommended for local dev) make validate-skill-design-changed -# Validate all skills or a specific pack +# Validate all skills or a specific plugin make validate-skill-design -make validate-skill-design PACK=rh-sre +make validate-skill-design PLUGIN=rh-sre # Validate MCP tool references against live servers make validate-mcp-tools diff --git a/SKILL_DESIGN_PRINCIPLES.md b/SKILL_DESIGN_PRINCIPLES.md index 8c4d5a46..b31d8da8 100644 --- a/SKILL_DESIGN_PRINCIPLES.md +++ b/SKILL_DESIGN_PRINCIPLES.md @@ -4,11 +4,11 @@ Repository-specific design principles for creating skills and agents in agentic **Scope**: Tier 2 requirements - repository enhancements beyond base agentskills.io specification (Tier 1 validated by linter). -**Distribution (Lola):** Packs are installed with the [Lola](https://github.com/LobsterTrap/lola) package manager from the registry in [`marketplace/rh-agentic-collection.yml`](https://github.com/RHEcosystemAppEng/agentic-catalog/blob/main/marketplace/rh-agentic-collection.yml) (hosted in [agentic-catalog](https://github.com/RHEcosystemAppEng/agentic-catalog)). Layout and install flow are documented in [CLAUDE.md](CLAUDE.md) and the root [README.md](README.md). +**Distribution (Lola):** Plugins are installed with the [Lola](https://github.com/LobsterTrap/lola) package manager from the registry in [`marketplace/rh-agentic-collection.yml`](https://github.com/RHEcosystemAppEng/agentic-catalog/blob/main/marketplace/rh-agentic-collection.yml) (hosted in [agentic-catalog](https://github.com/RHEcosystemAppEng/agentic-catalog)). Layout and install flow are documented in [CLAUDE.md](CLAUDE.md) and the root [README.md](README.md). -**Collection catalog (pack-local):** Each pack may include **`/.catalog/collection.yaml`** and a **`collection.json`** mirror so tooling and docs can show a structured view of the collection. Authors follow [COLLECTION_SPEC.md](COLLECTION_SPEC.md) and the **create-collection** skill; field constraints are defined in **[`catalog/schema.yaml`](catalog/schema.yaml)** (JSON Schema in YAML). Pack **`SKILL.md`**, **`README.md`**, **`AGENTS.md`**, and **`marketplace/rh-agentic-collection.yml`** (in [agentic-catalog](https://github.com/RHEcosystemAppEng/agentic-catalog)) stay the **sources of truth**; the catalog aggregates and summarizes them and does **not** replace or regenerate README or marketplace content. +**Collection catalog (plugin-local):** Each plugin may include **`/.catalog/collection.yaml`** and a **`collection.json`** mirror so tooling and docs can show a structured view of the collection. Authors follow [COLLECTION_SPEC.md](COLLECTION_SPEC.md) and the **create-collection** skill; field constraints are defined in **[`catalog/schema.yaml`](catalog/schema.yaml)** (JSON Schema in YAML). Plugin **`SKILL.md`**, **`README.md`**, **`AGENTS.md`**, and **`marketplace/rh-agentic-collection.yml`** (in [agentic-catalog](https://github.com/RHEcosystemAppEng/agentic-catalog)) stay the **sources of truth**; the catalog aggregates and summarizes them and does **not** replace or regenerate README or marketplace content. -**MCP configuration:** Use `/mcps.json` for MCP server definitions (never hardcode secrets; use `${VAR}` references). The deprecated filename `.mcp.json` is not used in this repository. +**MCP configuration:** Use `/mcps.json` for MCP server definitions (never hardcode secrets; use `${VAR}` references). The deprecated filename `.mcp.json` is not used in this repository. **Optional Claude Code manifest:** `.claude-plugin/plugin.json` is optional—only needed for Claude Code–specific plugin publishing. It is not required for Lola installation or for Tier 2 skill content compliance. @@ -183,17 +183,17 @@ Every skill MUST include a **Dependencies** section listing: **Skill-local docs rule (required):** - Internal docs consumed by a skill must resolve under that skill directory using `references/...` or `./references/...` links in `SKILL.md`. -- Do **not** use upward traversal links to pack-level docs such as `../references/...`, `../../references/...`, or `../../../references/...`. +- Do **not** use upward traversal links to plugin-level docs such as `../references/...`, `../../references/...`, or `../../../references/...`. - Shared docs may be reused via symlinks under `skills//references/...`. Link targets inside shared pool files must resolve when the file is opened through a skill symlink (use same-directory or `references/...` paths from the symlink location). - After migrating `docs/` → `references/`, **delete** the `skills//docs/` directory — do not leave empty or stale folders. - Do **not** nest `references/references/` inside a skill. If `docs/references/` existed, flatten files into `skills//references/`. -- Pack-level `/references/` or skill-level `skills//references/` are the only allowed reference locations. -- Pack-level `references/INDEX.md` and `references/SOURCES.md` may exist for repository navigation/source attribution, but skills must not depend on them at execution time. +- Plugin-level `/references/` or skill-level `skills//references/` are the only allowed reference locations. +- Plugin-level `references/INDEX.md` and `references/SOURCES.md` may exist for repository navigation/source attribution, but skills must not depend on them at execution time. **Skill-local scripts rule (required):** -- Scripts the agent runs must live under `skills//scripts/` (often as symlinks into `/scripts//`). +- Scripts the agent runs must live under `skills//scripts/` (often as symlinks into `/scripts//`). - If a skill symlinks any file from `scripts//`, symlink **every** non-test file in that group (YAML, JSON, and config files included — not only `.py`). -- In skill markdown, document commands with skill-local paths (`python3 scripts/foo.py`, `oc apply -f scripts/manifest.yaml`). Do not use `/scripts/...` paths meant for the authoring repo. +- In skill markdown, document commands with skill-local paths (`python3 scripts/foo.py`, `oc apply -f scripts/manifest.yaml`). Do not use `/scripts/...` paths meant for the authoring repo. **Rationale**: Makes dependencies explicit for debugging and troubleshooting. @@ -386,9 +386,9 @@ One clear purpose per skill. --- -### 11. Pack-Level AGENTS.md +### 11. Plugin-Level AGENTS.md -Every pack with skills MUST have an `AGENTS.md` in its root directory. This file is the [Lola AI Context Module](https://lobstertrap.org/lola/guides/creating-modules/#add-an-agentsmd) instruction router for the pack persona, intent routing, and global rules. Do **not** use pack-level `CLAUDE.md` — Lola manages `AGENTS.md`, not `CLAUDE.md`. +Every plugin with skills MUST have an `AGENTS.md` in its root directory. This file is the [Lola AI Context Module](https://lobstertrap.org/lola/guides/creating-modules/#add-an-agentsmd) instruction router for the plugin persona, intent routing, and global rules. Do **not** use plugin-level `CLAUDE.md` — Lola manages `AGENTS.md`, not `CLAUDE.md`. **Required Sections:** - `## Skill-First Rule` — enforce skill invocation over direct MCP tool calls @@ -396,11 +396,11 @@ Every pack with skills MUST have an `AGENTS.md` in its root directory. This file - `## 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 `AGENTS.md` intent routing table to include it. +**When adding a new skill**, update the plugin's `AGENTS.md` intent routing table to include it. **Reference:** [rh-ai-engineer/AGENTS.md](rh-ai-engineer/AGENTS.md) -**Validated by:** `scripts/validate_structure.py` (automated — checks existence, required sections, intent routing completeness, and rejects deprecated pack-level `CLAUDE.md`) +**Validated by:** `scripts/validate_structure.py` (automated — checks existence, required sections, intent routing completeness, and rejects deprecated plugin-level `CLAUDE.md`) --- @@ -573,7 +573,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 AGENTS.md** - Instruction routing for every pack with skills (Lola convention) +11. **Plugin-Level AGENTS.md** - Instruction routing for every plugin with skills (Lola convention) --- diff --git a/catalog-info.yaml b/catalog-info.yaml index 8159dbda..ed51d310 100644 --- a/catalog-info.yaml +++ b/catalog-info.yaml @@ -5,7 +5,7 @@ metadata: title: Agentic Plugins description: > Root catalog entry point for the agentic-plugins repository. - Points to all agentic pack locations and MCP server manifests + Points to all agent plugin locations and MCP server manifests for Compass ingestion. annotations: agentic-plugins.redhat.com/version: "1.0" @@ -14,7 +14,7 @@ spec: targets: # Repository-level system - ./system.yaml - # Agentic Pack Locations + # Agent Plugin Locations - ./ocp-admin/catalog-info.yaml - ./rh-sre/catalog-info.yaml - ./rh-virt/catalog-info.yaml diff --git a/catalog/schema.yaml b/catalog/schema.yaml index 2f337ffc..01bbbecc 100644 --- a/catalog/schema.yaml +++ b/catalog/schema.yaml @@ -1,5 +1,5 @@ -# Pack-local collection catalog — JSON Schema (Draft 2020-12), YAML encoding. -# Field semantics and authoring: COLLECTION_SPEC.md. Instance files: /.catalog/collection.yaml +# Plugin-local collection catalog — JSON Schema (Draft 2020-12), YAML encoding. +# Field semantics and authoring: COLLECTION_SPEC.md. Instance files: /.catalog/collection.yaml # Fragments: sibling *.md of collection.yaml; reference as #name.md (quote in YAML). Inline monitored fields # >500 code points must use a fragment; see COLLECTION_SPEC.md. Resolved by scripts/collection_validate_lib.py. diff --git a/mcps/catalog-info.yaml b/mcps/catalog-info.yaml index 7c52e39c..e12dd596 100644 --- a/mcps/catalog-info.yaml +++ b/mcps/catalog-info.yaml @@ -5,7 +5,7 @@ metadata: title: Agentic Plugins MCP Servers description: > Points to the MCP system and all MCP server manifests - used across agentic packs. + used across agent plugins. annotations: agentic-plugins.redhat.com/version: "1.0" agentic-plugins.redhat.com/repo: "agentic-plugins" diff --git a/ocp-admin/.catalog/collection.json b/ocp-admin/.catalog/collection.json index e95f5f8f..da9d030d 100644 --- a/ocp-admin/.catalog/collection.json +++ b/ocp-admin/.catalog/collection.json @@ -13,7 +13,7 @@ "Vulnerability Management" ], "contents": { - "description": "The pack provides eight skills for cluster lifecycle, fleet visibility, security validation, and network\nsecurity on OpenShift, using Assisted Installer and OCM APIs for cluster management, read-only cluster APIs\nfor consolidated reports, Python helper scripts for CVE/SBOM/VEX-based security validation, and MCP-based\nNetworkPolicy design with live cluster verification.\n", + "description": "The plugin provides eight skills for cluster lifecycle, fleet visibility, security validation, and network\nsecurity on OpenShift, using Assisted Installer and OCM APIs for cluster management, read-only cluster APIs\nfor consolidated reports, Python helper scripts for CVE/SBOM/VEX-based security validation, and MCP-based\nNetworkPolicy design with live cluster verification.\n", "orchestration_skills": [], "skills": [ { @@ -131,7 +131,7 @@ ], "maturity": "GREEN", "mcp_section": "#mcp_section.md", - "name": "Agentic skill pack for Red Hat OpenShift", + "name": "Agent plugin for Red Hat OpenShift", "personas": [ "OpenShift Administrator", "Security Engineer", @@ -146,7 +146,7 @@ "url": "https://docs.redhat.com/en/documentation/openshift_container_platform/" }, { - "description": "Source repository for these packs, skills, and catalog metadata.", + "description": "Source repository for these plugins, skills, and catalog metadata.", "title": "agentic-plugins repository", "url": "https://github.com/RHEcosystemAppEng/agentic-plugins" }, diff --git a/ocp-admin/.catalog/collection.yaml b/ocp-admin/.catalog/collection.yaml index 5b8d1090..567ce928 100644 --- a/ocp-admin/.catalog/collection.yaml +++ b/ocp-admin/.catalog/collection.yaml @@ -3,7 +3,7 @@ # Do not edit ad hoc — follow COLLECTION_SPEC.md and the create-collection skill. id: openshift-administration -name: Agentic skill pack for Red Hat OpenShift +name: Agent plugin for Red Hat OpenShift provider: Red Hat version: 0.1.0 categories: @@ -31,7 +31,7 @@ summary: | official SBOMs and VEX data. Use AGENTS.md intent routing to pick the right skill. contents: description: | - The pack provides eight skills for cluster lifecycle, fleet visibility, security validation, and network + The plugin provides eight skills for cluster lifecycle, fleet visibility, security validation, and network security on OpenShift, using Assisted Installer and OCM APIs for cluster management, read-only cluster APIs for consolidated reports, Python helper scripts for CVE/SBOM/VEX-based security validation, and MCP-based NetworkPolicy design with live cluster verification. @@ -179,7 +179,7 @@ resources: description: Platform guides for administrators installing and operating OpenShift. - title: agentic-plugins repository url: https://github.com/RHEcosystemAppEng/agentic-plugins - description: Source repository for these packs, skills, and catalog metadata. + description: Source repository for these plugins, skills, and catalog metadata. - title: Red Hat Security Data url: https://security.access.redhat.com/ description: Official Red Hat VEX/CSAF data, security advisories, and CVE information. diff --git a/ocp-admin/.catalog/deploy_and_use.md b/ocp-admin/.catalog/deploy_and_use.md index 923c8413..08014aa1 100644 --- a/ocp-admin/.catalog/deploy_and_use.md +++ b/ocp-admin/.catalog/deploy_and_use.md @@ -4,7 +4,7 @@ --> ## Deploy and use -**Note:** This skill pack is released as Developer Preview. Developer Preview features provide early access to functionality in advance of possible inclusion in a Red Hat product offering. For more information about the support scope of Red Hat Developer Preview features, see [Developer Preview Support Scope](https://access.redhat.com/support/offerings/devpreview). +**Note:** This agent plugin is released as Developer Preview. Developer Preview features provide early access to functionality in advance of possible inclusion in a Red Hat product offering. For more information about the support scope of Red Hat Developer Preview features, see [Developer Preview Support Scope](https://access.redhat.com/support/offerings/devpreview). ### Prerequisites @@ -22,13 +22,13 @@ - [cosign](https://github.com/sigstore/cosign) - [syft](https://github.com/anchore/syft) (optional, fallback SBOM generation) -### Step 1: Install the skill pack +### Step 1: Install the agent plugin ```bash # Add the Red Hat Agentic marketplace (one-time setup) lola market add rh-agentic-plugins https://raw.githubusercontent.com/RHEcosystemAppEng/agentic-catalog/main/marketplace/rh-agentic-collection.yml -# Install the ocp-admin pack (replace claude-code with your AI assistant) +# Install the ocp-admin plugin (replace claude-code with your AI assistant) # Valid targets: claude-code, copilot-cli, copilot-vscode, cursor, opencode lola install ocp-admin -a claude-code ``` @@ -43,7 +43,7 @@ lola list ### Step 2: Configure environment variables -The pack uses three MCP servers, each requiring specific credentials passed as environment variables. **Never hardcode tokens or paths — always use environment variables.** +The plugin uses three MCP servers, each requiring specific credentials passed as environment variables. **Never hardcode tokens or paths — always use environment variables.** **For cluster creation and inventory** (`openshift-self-managed`, `openshift-ocm-managed`): @@ -63,11 +63,11 @@ export KUBECONFIG="/path/to/your/kubeconfig" ### Step 3: Use the skills -The pack provides 8 skills. See the [ocp-admin README](../README.md) for the full list with descriptions and usage examples. +The plugin provides 8 skills. See the [ocp-admin README](../README.md) for the full list with descriptions and usage examples. ### Uninstall -Remove the skill pack from your project: +Remove the agent plugin from your project: ```bash lola uninstall ocp-admin diff --git a/ocp-admin/README.md b/ocp-admin/README.md index 54354c97..f4cf69c5 100644 --- a/ocp-admin/README.md +++ b/ocp-admin/README.md @@ -1,4 +1,4 @@ -# Agentic skill pack for Red Hat OpenShift administration +# Agent plugin for Red Hat OpenShift administration Administration and management tools for OpenShift Container Platform including cluster lifecycle management, multi-cluster operations, workload orchestration, and security policies @@ -42,7 +42,7 @@ The ocp-admin collection provides specialized tools for managing OpenShift clust ### Installation (Lola) -Install the pack with [Lola](https://github.com/LobsterTrap/lola): +Install the plugin with [Lola](https://github.com/LobsterTrap/lola): ```bash lola market add rh-agentic-plugins https://raw.githubusercontent.com/RHEcosystemAppEng/agentic-catalog/main/marketplace/rh-agentic-collection.yml @@ -472,7 +472,7 @@ See [skills/cluster-report/references/multi-cluster-auth.md](skills/cluster-repo ## MCP Server Integration -The pack integrates with two MCP servers for comprehensive cluster management: +The plugin integrates with two MCP servers for comprehensive cluster management: ### **openshift-installer** - Assisted Service MCP Server @@ -677,7 +677,7 @@ Result: Real-time installation status without leaving Claude ## Documentation -The pack includes 17 comprehensive reference documents covering all aspects of OpenShift administration: +The plugin includes 17 comprehensive reference documents covering all aspects of OpenShift administration: ### Installation & Planning - [Input Validation Guide](skills/cluster-creator/references/input-validation-guide.md) - Parameter validation rules @@ -879,7 +879,7 @@ See main repository [README.md](../README.md) for: ## References -- [Agentic skill pack for Red Hat OpenShift administration repository](https://github.com/RHEcosystemAppEng/agentic-plugins/tree/main/ocp-admin) - Documentation and details for this skill pack +- [Agent plugin for Red Hat OpenShift administration repository](https://github.com/RHEcosystemAppEng/agentic-plugins/tree/main/ocp-admin) - Documentation and details for this agent plugin - [OpenShift Container Platform documentation](https://docs.redhat.com/en/documentation/openshift_container_platform/4.18) - Documentation for Red Hat OpenShift Container Platform - [Assisted Installer documentation](https://docs.redhat.com/en/documentation/assisted_installer_for_openshift_container_platform) - Documentation for Red Hat OpenShift Container Platform Assisted Installer - [Assisted Service MCP Server](https://github.com/openshift-assisted/assisted-service-mcp) - Documentation for Assisted Service MCP Server diff --git a/ocp-admin/catalog-info.yaml b/ocp-admin/catalog-info.yaml index a59f882f..2670c16e 100644 --- a/ocp-admin/catalog-info.yaml +++ b/ocp-admin/catalog-info.yaml @@ -2,9 +2,9 @@ apiVersion: backstage.io/v1alpha1 kind: Location metadata: name: ocp-admin - title: OpenShift Administration Agentic Pack + title: OpenShift Administration Agent Plugin description: > - Points to all AI skill catalog entities in the ocp-admin agentic pack + Points to all AI skill catalog entities in the ocp-admin agent plugin for Red Hat OpenShift administration. annotations: agentic-plugins.redhat.com/version: "1.0" diff --git a/rh-ai-engineer/.catalog/collection.json b/rh-ai-engineer/.catalog/collection.json index d964888d..50154cc9 100644 --- a/rh-ai-engineer/.catalog/collection.json +++ b/rh-ai-engineer/.catalog/collection.json @@ -15,7 +15,7 @@ "GPU" ], "contents": { - "description": "The pack provides 10 skills and 1 orchestration skill for OpenShift AI workflows on Red Hat platforms; see AGENTS.md\nfor intent routing.\n", + "description": "The plugin provides 10 skills and 1 orchestration skill for OpenShift AI workflows on Red Hat platforms; see AGENTS.md\nfor intent routing.\n", "orchestration_skills": [ { "description": "Configure TrustyAI Guardrails Orchestrator for LLM input/output content safety on OpenShift AI.", @@ -131,7 +131,7 @@ ], "maturity": "ORANGE", "mcp_section": "#mcp_section.md", - "name": "Agentic skill pack for OpenShift AI Engineers", + "name": "Agent plugin for OpenShift AI Engineers", "personas": [ "Red Hat platform engineer" ], @@ -149,7 +149,7 @@ "url": "https://kserve.github.io/website/latest/" }, { - "description": "Source for this pack and catalog metadata.", + "description": "Source for this plugin and catalog metadata.", "title": "agentic-plugins repository", "url": "https://github.com/RHEcosystemAppEng/agentic-plugins" } diff --git a/rh-ai-engineer/.catalog/collection.yaml b/rh-ai-engineer/.catalog/collection.yaml index 7e260a90..0b803e51 100644 --- a/rh-ai-engineer/.catalog/collection.yaml +++ b/rh-ai-engineer/.catalog/collection.yaml @@ -3,7 +3,7 @@ # Do not edit ad hoc — follow COLLECTION_SPEC.md and the create-collection skill. id: rh-ai-engineer -name: Agentic skill pack for OpenShift AI Engineers +name: Agent plugin for OpenShift AI Engineers provider: Red Hat version: 0.1.0 categories: @@ -30,7 +30,7 @@ summary: | guardrails, and inference troubleshooting across 11 skills. contents: description: | - The pack provides 10 skills and 1 orchestration skill for OpenShift AI workflows on Red Hat platforms; see AGENTS.md + The plugin provides 10 skills and 1 orchestration skill for OpenShift AI workflows on Red Hat platforms; see AGENTS.md for intent routing. skills: - name: ai-observability @@ -215,7 +215,7 @@ resources: description: Model serving patterns used with OpenShift AI. - title: agentic-plugins repository url: https://github.com/RHEcosystemAppEng/agentic-plugins - description: Source for this pack and catalog metadata. + description: Source for this plugin and catalog metadata. legal_resources: license_agreement_url: https://github.com/RHEcosystemAppEng/agentic-plugins/blob/main/LICENSE privacy_policy_url: https://www.redhat.com/en/about/privacy-policy diff --git a/rh-ai-engineer/.catalog/deploy_and_use.md b/rh-ai-engineer/.catalog/deploy_and_use.md index 52603232..718e5859 100644 --- a/rh-ai-engineer/.catalog/deploy_and_use.md +++ b/rh-ai-engineer/.catalog/deploy_and_use.md @@ -23,7 +23,7 @@ export KUBECONFIG="/path/to/your/kubeconfig" The **`rhoai`** server maps **`RHOAI_MCP_KUBECONFIG_PATH`** to **`${KUBECONFIG}`** in **`mcps.json`**—set **`KUBECONFIG`** once for both. -**`RHOAI_MCP_TRANSPORT`** is set to **`stdio`** in **`mcps.json`** (fixed for this pack). You do not need to export or override it unless you maintain a forked **`mcps.json`**. +**`RHOAI_MCP_TRANSPORT`** is set to **`stdio`** in **`mcps.json`** (fixed for this plugin). You do not need to export or override it unless you maintain a forked **`mcps.json`**. **AI Observability MCP (optional HTTP MCP):** diff --git a/rh-ai-engineer/README.md b/rh-ai-engineer/README.md index 461709a9..2f9a7f53 100644 --- a/rh-ai-engineer/README.md +++ b/rh-ai-engineer/README.md @@ -1,4 +1,4 @@ -# Red Hat AI Engineer Agentic Pack +# Red Hat AI Engineer Agent Plugin Automation tools for AI/ML engineers working with Red Hat OpenShift AI (RHOAI). Deploy and manage models, pipelines, registries, workbenches, and serving runtimes on OpenShift AI. @@ -49,7 +49,7 @@ Automation tools for AI/ML engineers working with Red Hat OpenShift AI (RHOAI). The `openshift` MCP server is the foundation for all skills. It provides reliable Kubernetes resource CRUD operations that serve as automatic fallbacks when RHOAI MCP tools are unavailable or return errors. -The `rhoai` MCP server provides high-level, RHOAI-domain-specific tools that simplify model deployment (no YAML construction needed), runtime management (including platform template discovery), and project validation. When these tools fail (auth errors, API inconsistencies), skills transparently fall back to equivalent OpenShift operations. See [rhoai-mcp](https://github.com/opendatahub-io/rhoai-mcp) for details. Note: the upstream project does not publish a public container image or version tags, so this pack runs the server via `uvx` pinned to a specific commit hash for reproducibility. +The `rhoai` MCP server provides high-level, RHOAI-domain-specific tools that simplify model deployment (no YAML construction needed), runtime management (including platform template discovery), and project validation. When these tools fail (auth errors, API inconsistencies), skills transparently fall back to equivalent OpenShift operations. See [rhoai-mcp](https://github.com/opendatahub-io/rhoai-mcp) for details. Note: the upstream project does not publish a public container image or version tags, so this plugin runs the server via `uvx` pinned to a specific commit hash for reproducibility. The `ai-observability` MCP server is optional. When available, it enables GPU pre-flight checks before deployment and post-deployment performance validation. diff --git a/rh-automation/.catalog/collection.json b/rh-automation/.catalog/collection.json index d03e20af..ce2c7cb3 100644 --- a/rh-automation/.catalog/collection.json +++ b/rh-automation/.catalog/collection.json @@ -13,7 +13,7 @@ "Execution" ], "contents": { - "description": "The pack provides 8 skills and 3 orchestration skills for rh automation workflows on Red Hat platforms; see AGENTS.md for intent routing.\n", + "description": "The plugin provides 8 skills and 3 orchestration skills for rh automation workflows on Red Hat platforms; see AGENTS.md for intent routing.\n", "orchestration_skills": [ { "description": "Orchestrates forensic analysis of failed jobs with event extraction, host correlation, and resolution advisory.", @@ -123,7 +123,7 @@ ], "maturity": "ORANGE", "mcp_section": "#mcp_section.md", - "name": "Agentic skill pack for Automation Engineers", + "name": "Agent plugin for Automation Engineers", "personas": [ "Red Hat platform engineer" ], @@ -136,7 +136,7 @@ "url": "https://docs.redhat.com/en/documentation/red_hat_ansible_automation_platform/" }, { - "description": "Source for this pack and catalog metadata.", + "description": "Source for this plugin and catalog metadata.", "title": "agentic-plugins repository", "url": "https://github.com/RHEcosystemAppEng/agentic-plugins" } diff --git a/rh-automation/.catalog/collection.yaml b/rh-automation/.catalog/collection.yaml index 74ba40ca..a9235a28 100644 --- a/rh-automation/.catalog/collection.yaml +++ b/rh-automation/.catalog/collection.yaml @@ -3,7 +3,7 @@ # Do not edit ad hoc — follow COLLECTION_SPEC.md and the create-collection skill. id: rh-automation -name: Agentic skill pack for Automation Engineers +name: Agent plugin for Automation Engineers provider: Red Hat version: 0.1.0 categories: @@ -26,7 +26,7 @@ summary: | The rh-automation collection ships 11 catalogued skills for Red Hat automation workflows described in README and AGENTS.md; orchestration entries coordinate sub-skills with explicit approvals. contents: description: | - The pack provides 8 skills and 3 orchestration skills for rh automation workflows on Red Hat platforms; see AGENTS.md for intent routing. + The plugin provides 8 skills and 3 orchestration skills for rh automation workflows on Red Hat platforms; see AGENTS.md for intent routing. skills: - name: aap-mcp-validator description: "Validate that required AAP MCP servers are accessible before executing automation skills." @@ -192,7 +192,7 @@ resources: description: "Official AAP documentation for controllers and execution." - title: "agentic-plugins repository" url: https://github.com/RHEcosystemAppEng/agentic-plugins - description: "Source for this pack and catalog metadata." + description: "Source for this plugin and catalog metadata." legal_resources: license_agreement_url: https://github.com/RHEcosystemAppEng/agentic-plugins/blob/main/LICENSE privacy_policy_url: https://www.redhat.com/en/about/privacy-policy diff --git a/rh-automation/.catalog/deploy_and_use.md b/rh-automation/.catalog/deploy_and_use.md index 75af038b..c5928bd1 100644 --- a/rh-automation/.catalog/deploy_and_use.md +++ b/rh-automation/.catalog/deploy_and_use.md @@ -7,7 +7,7 @@ - Claude Code CLI or IDE extension (if using Claude Code) - Ansible Automation Platform **controller** reachable over HTTPS from the workstation running the assistant -- API token with permissions appropriate for job, inventory, configuration, security, monitoring, and user APIs used by the pack +- API token with permissions appropriate for job, inventory, configuration, security, monitoring, and user APIs used by the plugin ### Environment setup diff --git a/rh-automation/references/INDEX.md b/rh-automation/references/INDEX.md index d973f744..b6186b91 100644 --- a/rh-automation/references/INDEX.md +++ b/rh-automation/references/INDEX.md @@ -1,6 +1,6 @@ # Documentation Index -Navigation guide for the rh-automation knowledge base. Runtime copies live under each skill's `references/` directory (canonical files plus shared-pool symlinks). This pack index maps those files for repository navigation. +Navigation guide for the rh-automation knowledge base. Runtime copies live under each skill's `references/` directory (canonical files plus shared-pool symlinks). This plugin index maps those files for repository navigation. ## How Documents Are Used @@ -8,7 +8,7 @@ Navigation guide for the rh-automation knowledge base. Runtime copies live under User Request → Agent → Skill reads document → Skill queries MCP tools → Skill interprets with document knowledge → Output with Red Hat citations ``` -Paths in `.ai-index/` are pack-relative (from `rh-automation/`). +Paths in `.ai-index/` are plugin-relative (from `rh-automation/`). ## Document Map diff --git a/rh-basic/.catalog/collection.json b/rh-basic/.catalog/collection.json index 9cc8c496..96aa73e0 100644 --- a/rh-basic/.catalog/collection.json +++ b/rh-basic/.catalog/collection.json @@ -9,7 +9,7 @@ "Support" ], "contents": { - "description": "The pack provides 6 skills covering the most common Red Hat support and operations workflows.\nAll skills are self-contained, and those using the Red Hat Security MCP server fall back to WebFetch when it is unavailable.\n", + "description": "The plugin provides 6 skills covering the most common Red Hat support and operations workflows.\nAll skills are self-contained, and those using the Red Hat Security MCP server fall back to WebFetch when it is unavailable.\n", "orchestration_skills": [], "skills": [ { @@ -25,7 +25,7 @@ { "description": "Bootstrap Installer (self-removes after use)", "name": "red-hat-get-started", - "summary_markdown": "Fetch and install all skills from Agentic skill pack for Red Hat customers into the current project. Removes itself after running.\n**Use when:**\n- Setting up Red Hat skills for the first time in a project\n**What it does:**\n- Downloads each skill from the canonical source URL\n- Creates skill directories under .claude/skills/\n- Reports any download failures for manual recovery\n- Deletes itself on completion\n" + "summary_markdown": "Fetch and install all skills from Agent plugin for Red Hat customers into the current project. Removes itself after running.\n**Use when:**\n- Setting up Red Hat skills for the first time in a project\n**What it does:**\n- Downloads each skill from the canonical source URL\n- Creates skill directories under .claude/skills/\n- Reports any download failures for manual recovery\n- Deletes itself on completion\n" }, { "description": "Product Lifecycle Status and Support Phase Lookup", @@ -65,7 +65,7 @@ "user_request": "\"What severity should I file this support case?\" or \"What SLA do I get?\"" }, { - "reason": "Bootstrap installer that downloads and installs all skills in the pack.", + "reason": "Bootstrap installer that downloads and installs all skills in the plugin.", "skill_to_use": "red-hat-get-started", "user_request": "\"Install Red Hat skills\" or \"Set up Red Hat agent skills\"" }, @@ -101,7 +101,7 @@ ], "maturity": "GREEN", "mcp_section": "#mcp_section.md", - "name": "Agentic skill pack for Red Hat customers", + "name": "Agent plugin for Red Hat customers", "personas": [ "IT Professional", "Red Hat Customer" diff --git a/rh-basic/.catalog/collection.yaml b/rh-basic/.catalog/collection.yaml index f1aaf830..84e7186c 100644 --- a/rh-basic/.catalog/collection.yaml +++ b/rh-basic/.catalog/collection.yaml @@ -3,7 +3,7 @@ # Do not edit ad hoc — follow COLLECTION_SPEC.md and the create-collection skill. id: rh-basic -name: Agentic skill pack for Red Hat customers +name: Agent plugin for Red Hat customers provider: Red Hat version: 0.1.0 categories: @@ -22,7 +22,7 @@ description: "Essential Red Hat skills for IT professionals: CVE explanation, di summary: Lightweight, self-contained skills for everyday Red Hat operations and support tasks. Skills fall back to public Red Hat documentation when MCP tools are unavailable. contents: description: | - The pack provides 6 skills covering the most common Red Hat support and operations workflows. + The plugin provides 6 skills covering the most common Red Hat support and operations workflows. All skills are self-contained, and those using the Red Hat Security MCP server fall back to WebFetch when it is unavailable. skills: - name: red-hat-cve-explainer @@ -53,7 +53,7 @@ contents: - name: red-hat-get-started description: Bootstrap Installer (self-removes after use) summary_markdown: | - Fetch and install all skills from Agentic skill pack for Red Hat customers into the current project. Removes itself after running. + Fetch and install all skills from Agent plugin for Red Hat customers into the current project. Removes itself after running. **Use when:** - Setting up Red Hat skills for the first time in a project **What it does:** @@ -116,7 +116,7 @@ contents: reason: Maps situation to Sev 1-4 and shows SLA for Premium and Standard support. - user_request: '"Install Red Hat skills" or "Set up Red Hat agent skills"' skill_to_use: red-hat-get-started - reason: Bootstrap installer that downloads and installs all skills in the pack. + reason: Bootstrap installer that downloads and installs all skills in the plugin. - user_request: '"Set up the Red Hat Security MCP server" or "Add red-hat-security to my MCP config"' skill_to_use: red-hat-security-mcp-setup reason: Configures the HTTP-transport Red Hat Security MCP endpoint and explains browser SSO login. diff --git a/rh-basic/.catalog/deploy_and_use.md b/rh-basic/.catalog/deploy_and_use.md index 3b150c39..39ed512f 100644 --- a/rh-basic/.catalog/deploy_and_use.md +++ b/rh-basic/.catalog/deploy_and_use.md @@ -4,7 +4,7 @@ --> ## Deploy and use -**Note:** This skill pack is released as Developer Preview. Developer Preview features provide early access to functionality in advance of possible inclusion in a Red Hat product offering. For more information about the support scope of Red Hat Developer Preview features, see [Developer Preview Support Scope](https://access.redhat.com/support/offerings/devpreview). +**Note:** This agent plugin is released as Developer Preview. Developer Preview features provide early access to functionality in advance of possible inclusion in a Red Hat product offering. For more information about the support scope of Red Hat Developer Preview features, see [Developer Preview Support Scope](https://access.redhat.com/support/offerings/devpreview). ### Prerequisites @@ -15,13 +15,13 @@ - [OpenCode](https://opencode.ai/) - [Lola](https://github.com/LobsterTrap/lola) CLI installed -### Step 1: Install the skill pack +### Step 1: Install the agent plugin ```bash # Add the Red Hat Agentic marketplace (one-time setup) lola market add rh-agentic-plugins https://raw.githubusercontent.com/RHEcosystemAppEng/agentic-catalog/main/marketplace/rh-agentic-collection.yml -# Install the rh-basic pack (replace claude-code with your AI assistant) +# Install the rh-basic plugin (replace claude-code with your AI assistant) # Valid targets: claude-code, copilot-cli, copilot-vscode, cursor, opencode lola install rh-basic -a claude-code ``` @@ -36,7 +36,7 @@ lola list ### Step 2: Set up the MCP server -This pack uses the Red Hat Security MCP server, which authenticates via browser SSO — no environment variables are required. +This plugin uses the Red Hat Security MCP server, which authenticates via browser SSO — no environment variables are required. After installation, run the setup skill to configure the server: @@ -48,11 +48,11 @@ This adds the Red Hat Security MCP server to your project's `.mcp.json` and guid ### Step 3: Use the skills -The pack provides 6 skills. See the [rh-basic README](../README.md) for the full list with descriptions and usage examples. +The plugin provides 6 skills. See the [rh-basic README](../README.md) for the full list with descriptions and usage examples. ### Uninstall -Remove the skill pack from your project: +Remove the agent plugin from your project: ```bash lola uninstall rh-basic diff --git a/rh-basic/.catalog/documentation_section.md b/rh-basic/.catalog/documentation_section.md index 6859f353..d2527a7a 100644 --- a/rh-basic/.catalog/documentation_section.md +++ b/rh-basic/.catalog/documentation_section.md @@ -3,7 +3,7 @@ Golden sources: skills/*/SKILL.md, README.md, AGENTS.md --> -Skills source authoritative content from official Red Hat documentation/APIs at runtime using `WebFetch` or the documented APIs. No offline doc corpus is bundled; the pack stays lean and always reflects current Red Hat guidance. +Skills source authoritative content from official Red Hat documentation/APIs at runtime using `WebFetch` or the documented APIs. No offline doc corpus is bundled; the plugin stays lean and always reflects current Red Hat guidance. Key reference sources used by skills: diff --git a/rh-basic/.catalog/security_model.md b/rh-basic/.catalog/security_model.md index cbcebfd9..121666d8 100644 --- a/rh-basic/.catalog/security_model.md +++ b/rh-basic/.catalog/security_model.md @@ -5,5 +5,5 @@ - **Credentials:** Browser SSO only for `red-hat-security`; no API keys or client secrets are required for `mcps.json`. - **Transport security:** MCP access uses HTTPS to `https://security-mcp.api.redhat.com/mcp` and relies on Red Hat Customer Portal authentication. -- **No write operations:** All skills are read-only with respect to Red Hat platform data. No remediation playbooks are generated or executed by this pack. +- **No write operations:** All skills are read-only with respect to Red Hat platform data. No remediation playbooks are generated or executed by this plugin. - **Self-removing setup skill:** `red-hat-get-started` deletes itself from the project after completing its one-time task. diff --git a/rh-basic/README.md b/rh-basic/README.md index cd125447..c434bb27 100644 --- a/rh-basic/README.md +++ b/rh-basic/README.md @@ -1,13 +1,13 @@ -# Agentic skill pack for Red Hat customers +# Agent plugin for Red Hat customers -Essential Red Hat skills for IT professionals working with Red Hat products. This pack covers everyday tasks: understanding CVEs, gathering diagnostics, checking product lifecycle status, and filing support cases at the right severity. +Essential Red Hat skills for IT professionals working with Red Hat products. This plugin covers everyday tasks: understanding CVEs, gathering diagnostics, checking product lifecycle status, and filing support cases at the right severity. **Persona**: IT Professional / Red Hat Customer **Marketplaces**: Claude Code, Cursor ## Overview -Agentic skill pack for Red Hat customers provides lightweight, self-contained skills that work with or without a configured MCP server. Each skill falls back to web sources when MCP tools are unavailable. +Agent plugin for Red Hat customers provides lightweight, self-contained skills that work with or without a configured MCP server. Each skill falls back to web sources when MCP tools are unavailable. - **6 skills** covering the most common Red Hat support and operations workflows - **1 MCP server integration** (Red Hat Security MCP) for live CVE and advisory data @@ -94,7 +94,7 @@ Determines the correct severity for a Red Hat support ticket and explains the SL ### 5. **red-hat-get-started** - Bootstrap Installer -Fetches and installs all skills from Agentic skill pack for Red Hat customers into the current project. Removes itself after running. +Fetches and installs all skills from Agent plugin for Red Hat customers into the current project. Removes itself after running. **Use when:** - Setting up Red Hat skills for the first time in a project @@ -135,7 +135,7 @@ Provides CVE, advisory, and errata data from the Red Hat Security API. - **Transport:** HTTP (`https://security-mcp.api.redhat.com/mcp`) - **Authentication:** Red Hat Customer Portal SSO (browser login, no env vars required) -**Skills fall back to `WebFetch` on Red Hat documentation if MCP is unavailable** — you do not need MCP configured to use this pack. +**Skills fall back to `WebFetch` on Red Hat documentation if MCP is unavailable** — you do not need MCP configured to use this plugin. ## Security Model diff --git a/rh-basic/catalog-info.yaml b/rh-basic/catalog-info.yaml index dd0a69d0..d771bba6 100644 --- a/rh-basic/catalog-info.yaml +++ b/rh-basic/catalog-info.yaml @@ -2,9 +2,9 @@ apiVersion: backstage.io/v1alpha1 kind: Location metadata: name: rh-basic - title: Getting Started Agentic Pack + title: Getting Started Agent Plugin description: > - Points to all AI skill catalog entities in the rh-basic agentic pack + Points to all AI skill catalog entities in the rh-basic agent plugin for Red Hat product exploration and getting started workflows. annotations: agentic-plugins.redhat.com/version: "1.0" diff --git a/rh-basic/skills/red-hat-get-started/SKILL.md b/rh-basic/skills/red-hat-get-started/SKILL.md index ba293c04..d05a806d 100644 --- a/rh-basic/skills/red-hat-get-started/SKILL.md +++ b/rh-basic/skills/red-hat-get-started/SKILL.md @@ -22,7 +22,7 @@ Network access to GitHub to download skill files. ## When to Use This Skill -When setting up Agentic skill pack for Red Hat customers for the first time in a project. +When setting up Agent plugin for Red Hat customers for the first time in a project. ## Workflow diff --git a/rh-developer/.catalog/collection.json b/rh-developer/.catalog/collection.json index 5c27d71c..e7e697c1 100644 --- a/rh-developer/.catalog/collection.json +++ b/rh-developer/.catalog/collection.json @@ -10,7 +10,7 @@ "Automation" ], "contents": { - "description": "The pack provides 17 skills for developer workflows on OpenShift and RHEL, including two orchestration skills\nfor end-to-end containerize-and-deploy and structured incident investigation.\n", + "description": "The plugin provides 17 skills for developer workflows on OpenShift and RHEL, including two orchestration skills\nfor end-to-end containerize-and-deploy and structured incident investigation.\n", "orchestration_skills": [ { "description": "End-to-end containerize and deploy", @@ -52,7 +52,7 @@ { "description": "RHEL / SSH deployment", "name": "rhel-deploy", - "summary_markdown": "Deploy to standalone RHEL/Fedora hosts via SSH and systemd/Podman patterns.\n**Use when:**\n- \"Deploy on RHEL over SSH\"\n- \"systemd unit for my container\"\n**What it does:**\n- Uses SSH and host workflows from pack docs.\n- Optional Lightspeed context when configured.\n" + "summary_markdown": "Deploy to standalone RHEL/Fedora hosts via SSH and systemd/Podman patterns.\n**Use when:**\n- \"Deploy on RHEL over SSH\"\n- \"systemd unit for my container\"\n**What it does:**\n- Uses SSH and host workflows from plugin docs.\n- Optional Lightspeed context when configured.\n" }, { "description": "Environment validation", @@ -179,7 +179,7 @@ ], "maturity": "ORANGE", "mcp_section": "#mcp_section.md", - "name": "Agentic skill pack for Software Developers", + "name": "Agent plugin for Software Developers", "personas": [ "Application developer" ], @@ -211,21 +211,21 @@ "url": "https://developers.redhat.com/products/rhel/ubi" }, { - "description": "Local container workflows used by the pack.", + "description": "Local container workflows used by the plugin.", "embedded_doc": "skills/debug-build/references/debugging-patterns.md", "title": "Podman", "url": "https://docs.podman.io/" }, { - "description": "Pack policy for confirmations and destructive actions.", + "description": "Plugin policy for confirmations and destructive actions.", "embedded_doc": "skills/validate-environment/references/human-in-the-loop.md", - "title": "Human-in-the-loop (pack)", + "title": "Human-in-the-loop (plugin)", "url": "https://github.com/RHEcosystemAppEng/agentic-plugins" }, { "description": "SSH/systemd patterns for `/rhel-deploy`.", "embedded_doc": "skills/rhel-deploy/references/rhel-deployment.md", - "title": "RHEL deployment notes (pack)", + "title": "RHEL deployment notes (plugin)", "url": "https://github.com/RHEcosystemAppEng/agentic-plugins" } ], diff --git a/rh-developer/.catalog/collection.yaml b/rh-developer/.catalog/collection.yaml index 2bd9823a..3a838d9c 100644 --- a/rh-developer/.catalog/collection.yaml +++ b/rh-developer/.catalog/collection.yaml @@ -3,7 +3,7 @@ # Do not edit ad hoc — follow COLLECTION_SPEC.md and the create-collection skill. id: rh-developer -name: Agentic skill pack for Software Developers +name: Agent plugin for Software Developers provider: Red Hat version: 0.1.0 categories: @@ -23,7 +23,7 @@ summary: The rh-developer collection provides skills to detect projects, build i validate environments, and debug builds, pods, pipelines, networks, and hosts. contents: description: | - The pack provides 17 skills for developer workflows on OpenShift and RHEL, including two orchestration skills + The plugin provides 17 skills for developer workflows on OpenShift and RHEL, including two orchestration skills for end-to-end containerize-and-deploy and structured incident investigation. skills: - name: detect-project @@ -86,7 +86,7 @@ contents: - "Deploy on RHEL over SSH" - "systemd unit for my container" **What it does:** - - Uses SSH and host workflows from pack docs. + - Uses SSH and host workflows from plugin docs. - Optional Lightspeed context when configured. - name: validate-environment description: Environment validation @@ -291,13 +291,13 @@ resources: embedded_doc: skills/recommend-image/references/image-selection-criteria.md - title: Podman url: https://docs.podman.io/ - description: Local container workflows used by the pack. + description: Local container workflows used by the plugin. embedded_doc: skills/debug-build/references/debugging-patterns.md -- title: Human-in-the-loop (pack) +- title: Human-in-the-loop (plugin) url: https://github.com/RHEcosystemAppEng/agentic-plugins - description: Pack policy for confirmations and destructive actions. + description: Plugin policy for confirmations and destructive actions. embedded_doc: skills/validate-environment/references/human-in-the-loop.md -- title: RHEL deployment notes (pack) +- title: RHEL deployment notes (plugin) url: https://github.com/RHEcosystemAppEng/agentic-plugins description: SSH/systemd patterns for `/rhel-deploy`. embedded_doc: skills/rhel-deploy/references/rhel-deployment.md diff --git a/rh-developer/.catalog/deploy_and_use.md b/rh-developer/.catalog/deploy_and_use.md index 19586158..6b4447f3 100644 --- a/rh-developer/.catalog/deploy_and_use.md +++ b/rh-developer/.catalog/deploy_and_use.md @@ -55,6 +55,6 @@ lola install -f rh-developer -a cursor ### MCP configuration -Servers are defined in **`mcps.json`** at the pack root. Use **`${VAR}`** placeholders only. +Servers are defined in **`mcps.json`** at the plugin root. Use **`${VAR}`** placeholders only. -**Note (Linux vs macOS):** the OpenShift MCP `Podman` invocation may include user-namespace flags for `KUBECONFIG` readability; on macOS Podman-in-VM may require adjusting `mcps.json` per the pack README. +**Note (Linux vs macOS):** the OpenShift MCP `Podman` invocation may include user-namespace flags for `KUBECONFIG` readability; on macOS Podman-in-VM may require adjusting `mcps.json` per the plugin README. diff --git a/rh-developer/.catalog/documentation_section.md b/rh-developer/.catalog/documentation_section.md index 711bce15..1ff7d556 100644 --- a/rh-developer/.catalog/documentation_section.md +++ b/rh-developer/.catalog/documentation_section.md @@ -7,9 +7,9 @@ - **Safety** — skills enforce confirmation before creates/updates/deletes and redact secrets. - **Recovery** — standardized debug skills (`/debug-pod`, `/debug-build`, …) chain to remediation steps. -- **Consistency** — workflows follow pack docs (human-in-the-loop, image selection, RHEL patterns). +- **Consistency** — workflows follow plugin docs (human-in-the-loop, image selection, RHEL patterns). -### Pack documentation +### Plugin documentation Skill-local reference docs live under **`skills/*/references/`** (for example `skills/validate-environment/references/prerequisites.md`, `skills/recommend-image/references/image-selection-criteria.md`, `skills/debug-pod/references/debugging-patterns.md`). diff --git a/rh-developer/README.md b/rh-developer/README.md index 6fa6622d..9c6da808 100644 --- a/rh-developer/README.md +++ b/rh-developer/README.md @@ -1,4 +1,4 @@ -# Red Hat Developer Agentic Pack +# Red Hat Developer Agent Plugin A Claude Code plugin for building and deploying applications on Red Hat platforms. diff --git a/rh-sre/.catalog/collection.json b/rh-sre/.catalog/collection.json index 304565c4..925a94de 100644 --- a/rh-sre/.catalog/collection.json +++ b/rh-sre/.catalog/collection.json @@ -8,7 +8,7 @@ "Security" ], "contents": { - "description": "The pack provides 13 skills for common SRE operations, including one orchestration skill for end-to-end remediation.\n", + "description": "The plugin provides 13 skills for common SRE operations, including one orchestration skill for end-to-end remediation.\n", "orchestration_skills": [ { "description": "End-to-End CVE Remediation", @@ -129,7 +129,7 @@ ], "maturity": "GREEN", "mcp_section": "#mcp_section.md", - "name": "Agentic skill pack for Security Reliability Engineers", + "name": "Agent plugin for Site Reliability Engineers", "personas": [ "Site Reliability Engineer" ], diff --git a/rh-sre/.catalog/collection.yaml b/rh-sre/.catalog/collection.yaml index ea5178ae..4d311466 100644 --- a/rh-sre/.catalog/collection.yaml +++ b/rh-sre/.catalog/collection.yaml @@ -3,7 +3,7 @@ # Do not edit ad hoc — follow COLLECTION_SPEC.md and the create-collection skill. id: rh-sre -name: Agentic skill pack for Security Reliability Engineers +name: Agent plugin for Site Reliability Engineers provider: Red Hat version: 0.1.0 categories: @@ -20,7 +20,7 @@ description: Site reliability engineering tools and automation for managing Red summary: The rh-sre collection provides skills for site reliability tasks. contents: description: | - The pack provides 13 skills for common SRE operations, including one orchestration skill for end-to-end remediation. + The plugin provides 13 skills for common SRE operations, including one orchestration skill for end-to-end remediation. skills: - name: fleet-inventory description: System Discovery and Fleet Management diff --git a/rh-sre/.catalog/deploy_and_use.md b/rh-sre/.catalog/deploy_and_use.md index a76f5f25..5186891a 100644 --- a/rh-sre/.catalog/deploy_and_use.md +++ b/rh-sre/.catalog/deploy_and_use.md @@ -4,7 +4,7 @@ --> ## Deploy and use -**Note:** This skill pack is released as Developer Preview. Developer Preview features provide early access to functionality in advance of possible inclusion in a Red Hat product offering. For more information about the support scope of Red Hat Developer Preview features, see [Developer Preview Support Scope](https://access.redhat.com/support/offerings/devpreview). +**Note:** This agent plugin is released as Developer Preview. Developer Preview features provide early access to functionality in advance of possible inclusion in a Red Hat product offering. For more information about the support scope of Red Hat Developer Preview features, see [Developer Preview Support Scope](https://access.redhat.com/support/offerings/devpreview). ### Prerequisites @@ -16,13 +16,13 @@ - [Lola](https://github.com/LobsterTrap/lola) CLI installed - [Podman](https://podman.io/) (or Docker) — the MCP servers run as containers -### Step 1: Install the skill pack +### Step 1: Install the agent plugin ```bash # Add the Red Hat Agentic marketplace (one-time setup) lola market add rh-agentic-plugins https://raw.githubusercontent.com/RHEcosystemAppEng/agentic-catalog/main/marketplace/rh-agentic-collection.yml -# Install the rh-sre pack (replace claude-code with your AI assistant) +# Install the rh-sre plugin (replace claude-code with your AI assistant) # Valid targets: claude-code, copilot-cli, copilot-vscode, cursor, opencode lola install rh-sre -a claude-code ``` @@ -37,7 +37,7 @@ lola list ### Step 2: Configure environment variables -The pack uses three MCP servers that require credentials passed as environment variables. **Never hardcode tokens — always use environment variables.** +The plugin uses three MCP servers that require credentials passed as environment variables. **Never hardcode tokens — always use environment variables.** **For CVE discovery and remediation** (`lightspeed-mcp`): @@ -60,11 +60,11 @@ export AAP_API_TOKEN="" ### Step 3: Use the skills -The pack provides 13 skills. See the [rh-sre README](../README.md) for the full list with descriptions and usage examples. +The plugin provides 13 skills. See the [rh-sre README](../README.md) for the full list with descriptions and usage examples. ### Uninstall -Remove the skill pack from your project: +Remove the agent plugin from your project: ```bash lola uninstall rh-sre diff --git a/rh-sre/.catalog/documentation_section.md b/rh-sre/.catalog/documentation_section.md index 837bbb0e..e62ba7d6 100644 --- a/rh-sre/.catalog/documentation_section.md +++ b/rh-sre/.catalog/documentation_section.md @@ -12,9 +12,9 @@ ### In-repository documentation -This pack ships an AI-oriented knowledge base under **`references/`** (index and source attribution) and **`skills/*/references/`** (runtime skill docs). Start at **[references/INDEX.md](references/INDEX.md)** and use **`references/.ai-index/`** (semantic index, task mapping) for token-efficient discovery. +This plugin ships an AI-oriented knowledge base under **`references/`** (index and source attribution) and **`skills/*/references/`** (runtime skill docs). Start at **[references/INDEX.md](references/INDEX.md)** and use **`references/.ai-index/`** (semantic index, task mapping) for token-efficient discovery. ### Configuration and architecture - Environment variables for Lightspeed and AAP are declared only as `${VAR}` placeholders in **`mcps.json`**. -- Orchestration (**`/remediation`**) chains impact, validation, context, playbook generation, execution, and verification; see pack **AGENTS.md** for routing when you need a single step only. +- Orchestration (**`/remediation`**) chains impact, validation, context, playbook generation, execution, and verification; see plugin **AGENTS.md** for routing when you need a single step only. diff --git a/rh-sre/README.md b/rh-sre/README.md index 2699bf16..3a809a0a 100644 --- a/rh-sre/README.md +++ b/rh-sre/README.md @@ -1,6 +1,6 @@ -# Agentic skill pack for Site Reliability Engineers +# Agent plugin for Site Reliability Engineers -Agentic tools and automation for managing Red Hat platforms and infrastructure. This pack provides comprehensive capabilities for SRE tasks including vulnerability management, fleet inventory, system monitoring, and operational excellence +Agentic tools and automation for managing Red Hat platforms and infrastructure. This plugin provides comprehensive capabilities for SRE tasks including vulnerability management, fleet inventory, system monitoring, and operational excellence **Persona**: Site Reliability Engineer **Marketplaces**: Claude Code, Cursor @@ -138,7 +138,7 @@ export LIGHTSPEED_CLIENT_SECRET="your-service-account-client-secret" ### Installation (Lola) -Install the pack with [Lola](https://github.com/LobsterTrap/lola): +Install the plugin with [Lola](https://github.com/LobsterTrap/lola): ```bash lola market add rh-agentic-plugins https://raw.githubusercontent.com/RHEcosystemAppEng/agentic-catalog/main/marketplace/rh-agentic-collection.yml @@ -153,7 +153,7 @@ lola list ## Skills -The pack provides 13 skills for common SRE operations, including one orchestration skill for end-to-end remediation: +The plugin provides 13 skills for common SRE operations, including one orchestration skill for end-to-end remediation: ### 1. **remediation** - End-to-End CVE Remediation (Orchestration) Orchestrates 6 specialized skills for complete CVE remediation workflows. @@ -384,7 +384,7 @@ The remediation skill orchestrates 6 specialized skills to provide complete CVE ## Documentation -The rh-sre pack includes AI-optimized documentation under `references/` (pack index) and `skills/*/references/` (runtime skill docs): +The rh-sre plugin includes AI-optimized documentation under `references/` (plugin index) and `skills/*/references/` (runtime skill docs): ### Semantic Indexing System @@ -404,7 +404,7 @@ See [references/INDEX.md](references/INDEX.md) for the complete documentation ma ## MCP Server Integrations -The pack integrates with three MCP servers (configured in `mcps.json`): +The plugin integrates with three MCP servers (configured in `mcps.json`): ### 1. **lightspeed-mcp** - Red Hat Lightspeed Platform - CVE data and vulnerability management @@ -585,7 +585,7 @@ MCP servers are configured in `mcps.json`: ## Architecture Reference -This pack demonstrates the complete agentic pack architecture: +This plugin demonstrates the complete agent plugin architecture: ### Directory Structure ``` @@ -606,7 +606,7 @@ rh-sre/ │ ├── job-template-creator/SKILL.md │ ├── job-template-remediation-validator/SKILL.md │ └── execution-summary/SKILL.md -└── references/ # Pack documentation map and attributions +└── references/ # Plugin documentation map and attributions ├── INDEX.md ├── SOURCES.md └── .ai-index/ # Semantic indexing @@ -634,7 +634,7 @@ See main repository [CLAUDE.md](../CLAUDE.md) for: ## References -- [Agentic skill pack for Site Reliability Engineers repository](https://github.com/RHEcosystemAppEng/agentic-plugins/tree/main/rh-sre) - Documentation and details for this skill pack +- [Agent plugin for Site Reliability Engineers repository](https://github.com/RHEcosystemAppEng/agentic-plugins/tree/main/rh-sre) - Documentation and details for this agent plugin - [Red Hat Lightspeed](https://www.redhat.com/en/lightspeed) - [Red Hat Hybrid Cloud Console](https://console.redhat.com) - [Red Hat Lightspeed MCP](https://github.com/RedHatInsights/insights-mcp) diff --git a/rh-sre/catalog-info.yaml b/rh-sre/catalog-info.yaml index 4c901f2e..d874bcec 100644 --- a/rh-sre/catalog-info.yaml +++ b/rh-sre/catalog-info.yaml @@ -2,9 +2,9 @@ apiVersion: backstage.io/v1alpha1 kind: Location metadata: name: rh-sre - title: Site Reliability Engineering Agentic Pack + title: Site Reliability Engineering Agent Plugin description: > - Points to all AI skill catalog entities in the rh-sre agentic pack + Points to all AI skill catalog entities in the rh-sre agent plugin for Red Hat Site Reliability Engineering workflows. annotations: agentic-plugins.redhat.com/version: "1.0" diff --git a/rh-sre/references/INDEX.md b/rh-sre/references/INDEX.md index c9dd086c..cd50794a 100644 --- a/rh-sre/references/INDEX.md +++ b/rh-sre/references/INDEX.md @@ -11,7 +11,7 @@ last_updated: 2026-02-24 # Red Hat Remediation Agent - Documentation Index -This knowledge base provides comprehensive Red Hat-specific patterns for CVE remediation on Kubernetes-managed RHEL systems. Canonical runtime documents live under `skills//references/`; this pack-level index is for navigation and source attribution. +This knowledge base provides comprehensive Red Hat-specific patterns for CVE remediation on Kubernetes-managed RHEL systems. Canonical runtime documents live under `skills//references/`; this plugin-level index is for navigation and source attribution. ## Quick Navigation @@ -103,7 +103,7 @@ This knowledge base provides comprehensive Red Hat-specific patterns for CVE rem ``` rh-sre/ -├── references/ # Pack navigation and source attribution (this tree) +├── references/ # Plugin navigation and source attribution (this tree) │ ├── INDEX.md (this file) ✅ │ ├── SOURCES.md ✅ │ └── .ai-index/ # AI inference optimization @@ -141,7 +141,7 @@ Shared copies in other skills are symlinks to these canonical files. Do **not** ``` Read: references/.ai-index/semantic-index.json (~200 tokens) -Index `path` values are pack-relative (from `rh-sre/`). +Index `path` values are plugin-relative (from `rh-sre/`). ``` The semantic index enables: diff --git a/rh-sre/skills/execution-summary/SKILL.md b/rh-sre/skills/execution-summary/SKILL.md index ec4444a0..9ef8df16 100644 --- a/rh-sre/skills/execution-summary/SKILL.md +++ b/rh-sre/skills/execution-summary/SKILL.md @@ -121,7 +121,7 @@ Docs: ,,... - Example: `aap-mcp-job-management:job_templates_list` - Separate with commas: `lightspeed-mcp:get_cve,lightspeed-mcp:get_host_details` -4. **Doc names**: Pack-relative path from `skills/` or pack `references/` +4. **Doc names**: Plugin-relative path from `skills/` or plugin `references/` - Format: `skills/skill-name/references/category/filename.md` or `skills/skill-name/SKILL.md` - Example: `skills/playbook-generator/references/ansible/cve-remediation-templates.md` - Example: `skills/fleet-inventory/SKILL.md` @@ -308,7 +308,7 @@ Note: "unknown-plugin:custom-skill" origin unclear - verify plugin source. 5. **Compact format** - No spaces after commas 6. **Include all categories** - Even if "None" 7. **Extract docs from "I consulted" statements** - These indicate documentation usage -8. **Pack-relative paths** - Use `skills/.../references/...` or `skills/.../SKILL.md`, not full filesystem paths +8. **Plugin-relative paths** - Use `skills/.../references/...` or `skills/.../SKILL.md`, not full filesystem paths 9. **Brief explanation** - Help user understand the summary 10. **Handle edge cases gracefully** - Empty workflows, incomplete history diff --git a/rh-sre/skills/remediation/references/skill-invocation.md b/rh-sre/skills/remediation/references/skill-invocation.md index 132854c8..26a454a3 100644 --- a/rh-sre/skills/remediation/references/skill-invocation.md +++ b/rh-sre/skills/remediation/references/skill-invocation.md @@ -7,7 +7,7 @@ last_updated: 2026-03-02 # Skill Invocation Reference -Guidance for correctly invoking skills in the rh-sre pack across different AI hosts (Cursor, Claude Code, etc.). +Guidance for correctly invoking skills in the rh-sre plugin across different AI hosts (Cursor, Claude Code, etc.). ## Invoking Skills (All Sub-Skills) diff --git a/rh-virt/.catalog/collection.json b/rh-virt/.catalog/collection.json index d22b04da..1f1f190b 100644 --- a/rh-virt/.catalog/collection.json +++ b/rh-virt/.catalog/collection.json @@ -11,7 +11,7 @@ "Virt" ], "contents": { - "description": "The pack provides 10 skills for rh virt workflows on Red Hat platforms; see AGENTS.md for intent routing.\n", + "description": "The plugin provides 10 skills for rh virt workflows on Red Hat platforms; see AGENTS.md for intent routing.\n", "orchestration_skills": [], "skills": [ { @@ -115,7 +115,7 @@ ], "maturity": "GREEN", "mcp_section": "#mcp_section.md", - "name": "Agentic skill pack for Red Hat OpenShift Virtualization", + "name": "Agent plugin for Red Hat OpenShift Virtualization", "personas": [ "Red Hat platform engineer" ], @@ -133,7 +133,7 @@ "url": "https://kubevirt.io/user-guide/" }, { - "description": "Source for this pack and catalog metadata.", + "description": "Source for this plugin and catalog metadata.", "title": "agentic-plugins repository", "url": "https://github.com/RHEcosystemAppEng/agentic-plugins" } diff --git a/rh-virt/.catalog/collection.yaml b/rh-virt/.catalog/collection.yaml index a76c567f..2251ebd5 100644 --- a/rh-virt/.catalog/collection.yaml +++ b/rh-virt/.catalog/collection.yaml @@ -3,7 +3,7 @@ # Do not edit ad hoc — follow COLLECTION_SPEC.md and the create-collection skill. id: openshift-virtualization -name: Agentic skill pack for Red Hat OpenShift Virtualization +name: Agent plugin for Red Hat OpenShift Virtualization provider: Red Hat version: 0.1.0 categories: @@ -24,7 +24,7 @@ summary: | The rh-virt collection ships 10 skills for OpenShift Virtualization operations with confirmations on destructive steps. contents: description: | - The pack provides 10 skills for rh virt workflows on Red Hat platforms; see AGENTS.md for intent routing. + The plugin provides 10 skills for rh virt workflows on Red Hat platforms; see AGENTS.md for intent routing. skills: - name: vm-clone description: "Clone existing virtual machines for testing, scaling, or creating templates." @@ -186,7 +186,7 @@ resources: description: "KubeVirt concepts underlying OpenShift Virtualization." - title: "agentic-plugins repository" url: https://github.com/RHEcosystemAppEng/agentic-plugins - description: "Source for this pack and catalog metadata." + description: "Source for this plugin and catalog metadata." legal_resources: license_agreement_url: https://github.com/RHEcosystemAppEng/agentic-plugins/blob/main/LICENSE privacy_policy_url: https://www.redhat.com/en/about/privacy-policy diff --git a/rh-virt/.catalog/deploy_and_use.md b/rh-virt/.catalog/deploy_and_use.md index cb905749..00ab17a7 100644 --- a/rh-virt/.catalog/deploy_and_use.md +++ b/rh-virt/.catalog/deploy_and_use.md @@ -4,7 +4,7 @@ --> ## Deploy and use -**Note:** This skill pack is released as Developer Preview. Developer Preview features provide early access to functionality in advance of possible inclusion in a Red Hat product offering. For more information about the support scope of Red Hat Developer Preview features, see [Developer Preview Support Scope](https://access.redhat.com/support/offerings/devpreview). +**Note:** This agent plugin is released as Developer Preview. Developer Preview features provide early access to functionality in advance of possible inclusion in a Red Hat product offering. For more information about the support scope of Red Hat Developer Preview features, see [Developer Preview Support Scope](https://access.redhat.com/support/offerings/devpreview). ### Prerequisites @@ -18,13 +18,13 @@ - OpenShift cluster (**>= 4.19**) with the **OpenShift Virtualization** operator installed - A kubeconfig with RBAC sufficient for VirtualMachine and related KubeVirt resources in target namespaces -### Step 1: Install the skill pack +### Step 1: Install the agent plugin ```bash # Add the Red Hat Agentic marketplace (one-time setup) lola market add rh-agentic-plugins https://raw.githubusercontent.com/RHEcosystemAppEng/agentic-catalog/main/marketplace/rh-agentic-collection.yml -# Install the rh-virt pack (replace claude-code with your AI assistant) +# Install the rh-virt plugin (replace claude-code with your AI assistant) # Valid targets: claude-code, copilot-cli, copilot-vscode, cursor, opencode lola install rh-virt -a claude-code ``` @@ -39,7 +39,7 @@ lola list ### Step 2: Configure environment variables -The pack uses an MCP server that requires a kubeconfig passed as an environment variable. **Never hardcode kubeconfig contents — always use environment variables.** +The plugin uses an MCP server that requires a kubeconfig passed as an environment variable. **Never hardcode kubeconfig contents — always use environment variables.** **For cluster operations** (`openshift-virtualization`): @@ -55,11 +55,11 @@ oc get virtualmachines -A ### Step 3: Use the skills -The pack provides 10 skills. See the [rh-virt README](../README.md) for the full list with descriptions and usage examples. +The plugin provides 10 skills. See the [rh-virt README](../README.md) for the full list with descriptions and usage examples. ### Uninstall -Remove the skill pack from your project: +Remove the agent plugin from your project: ```bash lola uninstall rh-virt diff --git a/rh-virt/README.md b/rh-virt/README.md index b2181b11..0ce0a258 100644 --- a/rh-virt/README.md +++ b/rh-virt/README.md @@ -1,4 +1,4 @@ -# Agentic skill pack for Red Hat OpenShift Virtualization (Kubevirt) +# Agent plugin for Red Hat OpenShift Virtualization (Kubevirt) Provides automation capabilities for VM lifecycle management, provisioning, and inventory operations on OpenShift clusters using KubeVirt. @@ -40,7 +40,7 @@ kubectl get vms -A ### MCP Server Container Image -This pack uses the [OpenShift MCP Server](https://github.com/openshift/openshift-mcp-server) container image from `quay.io/redhat-user-workloads/crt-nshift-lightspeed-tenant/openshift-mcp-server`, pinned by SHA256 digest for supply chain security. No local build is required — the image is pulled automatically on first use. +This plugin uses the [OpenShift MCP Server](https://github.com/openshift/openshift-mcp-server) container image from `quay.io/redhat-user-workloads/crt-nshift-lightspeed-tenant/openshift-mcp-server`, pinned by SHA256 digest for supply chain security. No local build is required — the image is pulled automatically on first use. To verify the image integrity: ```bash @@ -49,7 +49,7 @@ podman inspect --format='{{.Digest}}' quay.io/redhat-user-workloads/crt-nshift-l ### Installation (Lola) -Install the pack with [Lola](https://github.com/LobsterTrap/lola): +Install the plugin with [Lola](https://github.com/LobsterTrap/lola): ```bash lola market add rh-agentic-plugins https://raw.githubusercontent.com/RHEcosystemAppEng/agentic-catalog/main/marketplace/rh-agentic-collection.yml @@ -58,7 +58,7 @@ lola install -f rh-virt ## Skills -The pack provides 5 specialized skills for complete VM lifecycle management: +The plugin provides 5 specialized skills for complete VM lifecycle management: ### 1. **vm-create** - Virtual Machine Provisioning @@ -176,7 +176,7 @@ Clone existing virtual machines for testing, scaling, or creating VM templates. ## MCP Server Integration -The pack integrates with the OpenShift MCP server (configured in `mcps.json`), which provides two toolsets for comprehensive cluster and virtualization management: +The plugin integrates with the OpenShift MCP server (configured in `mcps.json`), which provides two toolsets for comprehensive cluster and virtualization management: ### **openshift-virtualization** - OpenShift MCP Server @@ -495,7 +495,7 @@ See main repository [README.md](../README.md) for: ## References -- [Agentic skill pack for Red Hat OpenShift administration repository](https://github.com/RHEcosystemAppEng/agentic-plugins/tree/main/ocp-admin) - Documentation and details for this skill pack +- [Agent plugin for Red Hat OpenShift administration repository](https://github.com/RHEcosystemAppEng/agentic-plugins/tree/main/ocp-admin) - Documentation and details for this agent plugin - [OpenShift Virtualization Documentation](https://docs.openshift.com/container-platform/latest/virt/about_virt/about-virt.html) - [KubeVirt User Guide](https://docs.openshift.com/container-platform/latest/virt/about_virt/about-virt.html) - [OpenShift MCP Server](https://github.com/openshift/openshift-mcp-server) - Documentation and details for the OpenShift MCP Server diff --git a/rh-virt/SKILL_TEMPLATE.md b/rh-virt/SKILL_TEMPLATE.md index d7cbc0e7..a1577672 100644 --- a/rh-virt/SKILL_TEMPLATE.md +++ b/rh-virt/SKILL_TEMPLATE.md @@ -873,7 +873,7 @@ For complete details, see [SKILL_DESIGN_PRINCIPLES.md](/SKILL_DESIGN_PRINCIPLES. **Documentation**: skills/*/references/troubleshooting/ contains error resolution guides (6 documents) **Related Collections**: -- rh-sre: Reference implementation with pack references/ index and semantic indexing +- rh-sre: Reference implementation with plugin references/ index and semantic indexing - Use rh-sre as architectural reference for advanced patterns --- diff --git a/rh-virt/catalog-info.yaml b/rh-virt/catalog-info.yaml index b68feecb..457fc28f 100644 --- a/rh-virt/catalog-info.yaml +++ b/rh-virt/catalog-info.yaml @@ -2,9 +2,9 @@ apiVersion: backstage.io/v1alpha1 kind: Location metadata: name: rh-virt - title: Virtualization Management Agentic Pack + title: Virtualization Management Agent Plugin description: > - Points to all AI skill catalog entities in the rh-virt agentic pack + Points to all AI skill catalog entities in the rh-virt agent plugin for Red Hat OpenShift Virtualization management. annotations: agentic-plugins.redhat.com/version: "1.0" diff --git a/scripts/collection_validate_lib.py b/scripts/collection_validate_lib.py index 67e2bba6..1754af35 100644 --- a/scripts/collection_validate_lib.py +++ b/scripts/collection_validate_lib.py @@ -1,5 +1,5 @@ """ -Shared validation for /.catalog/collection.yaml (JSON Schema in catalog/schema.yaml, roster, banners, +Shared validation for /.catalog/collection.yaml (JSON Schema in catalog/schema.yaml, roster, banners, #fragment refs on top-level prose fields, JSON mirror). Used by validate_collection_schema.py and validate_collection_compliance.py. """ @@ -16,13 +16,13 @@ REPO_ROOT = Path(__file__).resolve().parent.parent -_PACK_EXCLUDE = {"scripts", "catalog", ".claude", ".github", ".lola", "docs", "eval"} +_PLUGIN_EXCLUDE = {"scripts", "catalog", ".claude", ".github", ".lola", "docs", "eval"} -def _discover_packs(root: Path) -> List[str]: +def _discover_plugins(root: Path) -> List[str]: return sorted( d.name for d in root.iterdir() - if d.is_dir() and d.name not in _PACK_EXCLUDE and not d.name.startswith(".") + if d.is_dir() and d.name not in _PLUGIN_EXCLUDE and not d.name.startswith(".") and ((d / "AGENTS.md").exists() or (d / "skills").is_dir()) ) SCHEMA_YAML_PATH = REPO_ROOT / "catalog" / "schema.yaml" @@ -58,7 +58,7 @@ def _discover_packs(root: Path) -> List[str]: def normalize_external_file_ref(ref: str) -> str: - """Strip leading ``#`` and optional ``.catalog/`` prefix; remainder is a path under ``/.catalog/``.""" + """Strip leading ``#`` and optional ``.catalog/`` prefix; remainder is a path under ``/.catalog/``.""" s = ref.strip() if s.startswith("#"): s = s[1:].lstrip() @@ -111,25 +111,25 @@ def collection_json_dumps(data: Any) -> str: return json.dumps(data, ensure_ascii=False, sort_keys=True, indent=2) + "\n" -def read_yaml_catalog(pack_dir: str, root: Optional[Path] = None) -> Tuple[Optional[Dict[str, Any]], List[str]]: +def read_yaml_catalog(plugin_dir: str, root: Optional[Path] = None) -> Tuple[Optional[Dict[str, Any]], List[str]]: root = root or REPO_ROOT - p = root / pack_dir / ".catalog" / "collection.yaml" + p = root / plugin_dir / ".catalog" / "collection.yaml" if not p.exists(): - return None, [f"{pack_dir}: missing {p.relative_to(root)}"] + return None, [f"{plugin_dir}: missing {p.relative_to(root)}"] try: with open(p, "r", encoding="utf-8") as f: raw = f.read() data = yaml.safe_load(raw) if not isinstance(data, dict): - return None, [f"{pack_dir}: collection.yaml must parse to a mapping"] + return None, [f"{plugin_dir}: collection.yaml must parse to a mapping"] return data, [] except Exception as e: - return None, [f"{pack_dir}: failed to parse collection.yaml: {e}"] + return None, [f"{plugin_dir}: failed to parse collection.yaml: {e}"] -def catalog_yaml_path(pack_dir: str, root: Optional[Path] = None) -> Path: +def catalog_yaml_path(plugin_dir: str, root: Optional[Path] = None) -> Path: root = root or REPO_ROOT - return root / pack_dir / ".catalog" / "collection.yaml" + return root / plugin_dir / ".catalog" / "collection.yaml" def _parse_yaml_scalar(value: str) -> str: @@ -184,22 +184,22 @@ def catalog_decision_guide_skill_line_map(yaml_path: Path) -> Dict[str, int]: return result -def _yaml_loc(pack_dir: str, yaml_path: Path, line: Optional[int], root: Path) -> str: +def _yaml_loc(plugin_dir: str, yaml_path: Path, line: Optional[int], root: Path) -> str: rel = yaml_path.relative_to(root) return f"{rel}:{line}" if line else str(rel) def describe_json_mirror_drift( - pack_dir: str, yaml_data: Dict[str, Any], root: Optional[Path] = None, + plugin_dir: str, yaml_data: Dict[str, Any], root: Optional[Path] = None, ) -> List[str]: """Explain how collection.json differs from collection.yaml with field paths and line numbers.""" root = root or REPO_ROOT - yaml_path = catalog_yaml_path(pack_dir, root) - json_path = root / pack_dir / ".catalog" / "collection.json" + yaml_path = catalog_yaml_path(plugin_dir, root) + json_path = root / plugin_dir / ".catalog" / "collection.json" try: json_data = json.loads(json_path.read_text(encoding="utf-8")) except json.JSONDecodeError as exc: - return [f"{pack_dir}: .catalog/collection.json is invalid JSON: {exc}"] + return [f"{plugin_dir}: .catalog/collection.json is invalid JSON: {exc}"] errs: List[str] = [] skill_lines = catalog_skill_name_line_map(yaml_path) @@ -219,9 +219,9 @@ def describe_json_mirror_drift( if yn == jn: continue line = skill_lines.get(str(yn or "")) or skill_lines.get(str(jn or "")) - loc = _yaml_loc(pack_dir, yaml_path, line, root) + loc = _yaml_loc(plugin_dir, yaml_path, line, root) errs.append( - f"{pack_dir}: {loc} {group}[{i}].name out of sync: " + f"{plugin_dir}: {loc} {group}[{i}].name out of sync: " f"collection.yaml={yn!r}, collection.json={jn!r}" ) @@ -230,51 +230,51 @@ def describe_json_mirror_drift( jv = json_data.get(key) if yv != jv: line = _find_top_level_key_line(yaml_path, key) - loc = _yaml_loc(pack_dir, yaml_path, line, root) + loc = _yaml_loc(plugin_dir, yaml_path, line, root) errs.append( - f"{pack_dir}: {loc} {key} out of sync: " + f"{plugin_dir}: {loc} {key} out of sync: " f"collection.yaml={yv!r}, collection.json={jv!r}" ) if not errs: errs.append( - f"{pack_dir}: .catalog/collection.json content differs from collection.yaml " + f"{plugin_dir}: .catalog/collection.json content differs from collection.yaml " "(run diff or regenerate JSON to inspect)" ) errs.append( - f"{pack_dir}: regenerate mirror with: " - f"uv run python scripts/catalog_yaml_to_json.py --pack {pack_dir}" + f"{plugin_dir}: regenerate mirror with: " + f"uv run python scripts/catalog_yaml_to_json.py --plugin {plugin_dir}" ) return errs -def validate_yaml_banner(pack_dir: str, root: Optional[Path] = None) -> List[str]: +def validate_yaml_banner(plugin_dir: str, root: Optional[Path] = None) -> List[str]: root = root or REPO_ROOT - p = root / pack_dir / ".catalog" / "collection.yaml" + p = root / plugin_dir / ".catalog" / "collection.yaml" if not p.exists(): return [] try: text = p.read_text(encoding="utf-8") except OSError as e: - return [f"{pack_dir}: cannot read collection.yaml: {e}"] + return [f"{plugin_dir}: cannot read collection.yaml: {e}"] head = "\n".join(text.splitlines()[:40]) missing = [m for m in YAML_BANNER_MARKERS if m not in head] if missing: return [ - f"{pack_dir}: collection.yaml must start with a # comment banner mentioning: " + f"{plugin_dir}: collection.yaml must start with a # comment banner mentioning: " + ", ".join(YAML_BANNER_MARKERS) ] return [] -def validate_deprecated_catalog_file_keys(pack_dir: str, data: Dict[str, Any]) -> List[str]: +def validate_deprecated_catalog_file_keys(plugin_dir: str, data: Dict[str, Any]) -> List[str]: """Reject legacy ``*_file`` split keys; prose fields use the same key for inline or ``#fragment.md``.""" errs: List[str] = [] for k in DEPRECATED_CATALOG_FILE_KEYS: if k in data and data[k] is not None and str(data[k]).strip() != "": base = k[: -len("_file")] errs.append( - f"{pack_dir}: deprecated key {k!r}; use {base!r} with inline markdown or " + f"{plugin_dir}: deprecated key {k!r}; use {base!r} with inline markdown or " f"a one-line fragment ref like '#{base}.md' (same pattern as deploy_and_use; see COLLECTION_SPEC.md)." ) return errs @@ -290,40 +290,40 @@ def _collect_top_level_catalog_fragment_refs(data: Dict[str, Any]) -> List[str]: return refs -def validate_file_refs(pack_dir: str, data: Dict[str, Any], root: Optional[Path] = None) -> List[str]: +def validate_file_refs(plugin_dir: str, data: Dict[str, Any], root: Optional[Path] = None) -> List[str]: root = root or REPO_ROOT refs = _collect_top_level_catalog_fragment_refs(data) errs: List[str] = [] - pack_root = root / pack_dir - catalog_dir = (pack_root / ".catalog").resolve() + plugin_root = root / plugin_dir + catalog_dir = (plugin_root / ".catalog").resolve() for ref in refs: if not ref.strip().startswith("#"): errs.append( - f"{pack_dir}: fragment ref must start with '#' (e.g. #install.md), got {ref!r}" + f"{plugin_dir}: fragment ref must start with '#' (e.g. #install.md), got {ref!r}" ) continue path_part = normalize_external_file_ref(ref) if not path_part: - errs.append(f"{pack_dir}: empty fragment path after normalizing {ref!r}") + errs.append(f"{plugin_dir}: empty fragment path after normalizing {ref!r}") continue if ".." in path_part or path_part.startswith("/"): - errs.append(f"{pack_dir}: invalid fragment path {ref!r}") + errs.append(f"{plugin_dir}: invalid fragment path {ref!r}") continue target = (catalog_dir / path_part).resolve() try: target.relative_to(catalog_dir) except ValueError: - errs.append(f"{pack_dir}: fragment {ref!r} escapes .catalog/ directory") + errs.append(f"{plugin_dir}: fragment {ref!r} escapes .catalog/ directory") continue if not target.is_file(): - errs.append(f"{pack_dir}: missing fragment file {path_part} (from {ref!r})") + errs.append(f"{plugin_dir}: missing fragment file {path_part} (from {ref!r})") return errs -def validate_embedded_docs(pack_dir: str, data: Dict[str, Any], root: Optional[Path] = None) -> List[str]: +def validate_embedded_docs(plugin_dir: str, data: Dict[str, Any], root: Optional[Path] = None) -> List[str]: root = root or REPO_ROOT errs: List[str] = [] - pack_root = root / pack_dir + plugin_root = root / plugin_dir for i, r in enumerate(data.get("resources") or []): if not isinstance(r, dict): continue @@ -331,15 +331,15 @@ def validate_embedded_docs(pack_dir: str, data: Dict[str, Any], root: Optional[P if not ed or not str(ed).strip(): continue rel = str(ed).strip() - target = (pack_root / rel).resolve() + target = (plugin_root / rel).resolve() if not target.is_file(): - errs.append(f"{pack_dir}: resources[{i}].embedded_doc missing file {rel}") + errs.append(f"{plugin_dir}: resources[{i}].embedded_doc missing file {rel}") return errs -def list_disk_skill_names(pack_dir: str, root: Optional[Path] = None) -> List[str]: +def list_disk_skill_names(plugin_dir: str, root: Optional[Path] = None) -> List[str]: root = root or REPO_ROOT - skills_dir = root / pack_dir / "skills" + skills_dir = root / plugin_dir / "skills" if not skills_dir.is_dir(): return [] names = sorted(p.name for p in skills_dir.iterdir() if p.is_dir() and (p / "SKILL.md").is_file()) @@ -361,78 +361,78 @@ def catalog_skill_names(data: Dict[str, Any]) -> Tuple[List[str], List[str]]: return reg, orch -def validate_skill_roster(pack_dir: str, data: Dict[str, Any], root: Optional[Path] = None) -> List[str]: - disk = set(list_disk_skill_names(pack_dir, root)) +def validate_skill_roster(plugin_dir: str, data: Dict[str, Any], root: Optional[Path] = None) -> List[str]: + disk = set(list_disk_skill_names(plugin_dir, root)) reg, orch = catalog_skill_names(data) yaml_names = reg + orch errs: List[str] = [] if len(yaml_names) != len(set(yaml_names)): - errs.append(f"{pack_dir}: duplicate skill name in contents.skills / orchestration_skills") + errs.append(f"{plugin_dir}: duplicate skill name in contents.skills / orchestration_skills") seen = set(reg) | set(orch) for n in reg + orch: if n not in disk: - errs.append(f"{pack_dir}: YAML lists skill {n!r} with no skills/{n}/SKILL.md on disk") + errs.append(f"{plugin_dir}: YAML lists skill {n!r} with no skills/{n}/SKILL.md on disk") for d in disk: if d not in seen: - errs.append(f"{pack_dir}: on-disk skill {d!r} missing from collection.yaml contents") + errs.append(f"{plugin_dir}: on-disk skill {d!r} missing from collection.yaml contents") return errs -def validate_json_mirror(pack_dir: str, data: Dict[str, Any], root: Optional[Path] = None) -> List[str]: +def validate_json_mirror(plugin_dir: str, data: Dict[str, Any], root: Optional[Path] = None) -> List[str]: root = root or REPO_ROOT - json_path = root / pack_dir / ".catalog" / "collection.json" + json_path = root / plugin_dir / ".catalog" / "collection.json" if not json_path.exists(): - return [f"{pack_dir}: missing .catalog/collection.json (run make catalog-mirror-json)"] + return [f"{plugin_dir}: missing .catalog/collection.json (run make catalog-mirror-json)"] expected = collection_json_dumps(data) actual = json_path.read_text(encoding="utf-8") if actual != expected: - return describe_json_mirror_drift(pack_dir, data, root) + return describe_json_mirror_drift(plugin_dir, data, root) return [] -def validate_schema_instance(pack_dir: str, data: Dict[str, Any]) -> List[str]: +def validate_schema_instance(plugin_dir: str, data: Dict[str, Any]) -> List[str]: v = get_validator() - errs = [f"{pack_dir}: schema: {'/'.join(str(x) for x in e.path)}: {e.message}" for e in v.iter_errors(data)] + errs = [f"{plugin_dir}: schema: {'/'.join(str(x) for x in e.path)}: {e.message}" for e in v.iter_errors(data)] return errs -def validate_pack_iteration3( - pack_dir: str, root: Optional[Path] = None, check_banner: bool = True, +def validate_plugin_iteration3( + plugin_dir: str, root: Optional[Path] = None, check_banner: bool = True, ) -> List[str]: """Iteration 3: schema + fragment refs + roster + optional YAML banner (no collection.json mirror).""" root = root or REPO_ROOT - data, errs = read_yaml_catalog(pack_dir, root) + data, errs = read_yaml_catalog(plugin_dir, root) if errs or data is None: return errs out: List[str] = [] - out.extend(validate_deprecated_catalog_file_keys(pack_dir, data)) - out.extend(validate_schema_instance(pack_dir, data)) - out.extend(validate_file_refs(pack_dir, data, root)) - out.extend(validate_skill_roster(pack_dir, data, root)) + out.extend(validate_deprecated_catalog_file_keys(plugin_dir, data)) + out.extend(validate_schema_instance(plugin_dir, data)) + out.extend(validate_file_refs(plugin_dir, data, root)) + out.extend(validate_skill_roster(plugin_dir, data, root)) if check_banner: - out.extend(validate_yaml_banner(pack_dir, root)) + out.extend(validate_yaml_banner(plugin_dir, root)) return out -def validate_pack_iteration5( - pack_dir: str, root: Optional[Path] = None, +def validate_plugin_iteration5( + plugin_dir: str, root: Optional[Path] = None, ) -> List[str]: """Full collection compliance: Iteration 3 + semantic rules + JSON mirror drift.""" root = root or REPO_ROOT - errs = validate_pack_iteration3(pack_dir, root, check_banner=True) - data, e = read_yaml_catalog(pack_dir, root) + errs = validate_plugin_iteration3(plugin_dir, root, check_banner=True) + data, e = read_yaml_catalog(plugin_dir, root) errs.extend(e) if data: - errs.extend(validate_pack_catalog_compliance_extra(pack_dir, data, root)) - errs.extend(validate_json_mirror(pack_dir, data, root)) + errs.extend(validate_plugin_catalog_compliance_extra(plugin_dir, data, root)) + errs.extend(validate_json_mirror(plugin_dir, data, root)) return errs -def validate_pack_catalog_compliance_extra( - pack_dir: str, data: Dict[str, Any], root: Optional[Path] = None, +def validate_plugin_catalog_compliance_extra( + plugin_dir: str, data: Dict[str, Any], root: Optional[Path] = None, ) -> List[str]: """Iteration 5 semantic checks.""" root = root or REPO_ROOT @@ -450,26 +450,26 @@ def validate_pack_catalog_compliance_extra( desc = (s.get("description") or "").strip() sm = (s.get("summary_markdown") or "").strip() if not name or not desc: - errs.append(f"{pack_dir}: {label}[{i}] requires name and description") + errs.append(f"{plugin_dir}: {label}[{i}] requires name and description") if len(sm) < 20: - errs.append(f"{pack_dir}: {label}[{i}] summary_markdown too short (<20 chars)") - skill_md = (root / pack_dir / "skills" / str(name) / "SKILL.md") + errs.append(f"{plugin_dir}: {label}[{i}] summary_markdown too short (<20 chars)") + skill_md = (root / plugin_dir / "skills" / str(name) / "SKILL.md") if not skill_md.is_file(): errs.append( - f"{pack_dir}: {label}[{i}] name {name!r} must match skills// directory " + f"{plugin_dir}: {label}[{i}] name {name!r} must match skills// directory " f"(missing {skill_md.relative_to(root)})" ) - disk_skill_names = set(list_disk_skill_names(pack_dir, root)) + disk_skill_names = set(list_disk_skill_names(plugin_dir, root)) guide = (contents or {}).get("skills_decision_guide") or [] if not disk_skill_names and guide: - errs.append(f"{pack_dir}: skills_decision_guide must be empty when the pack has no skills/") + errs.append(f"{plugin_dir}: skills_decision_guide must be empty when the plugin has no skills/") for i, row in enumerate(guide): if not isinstance(row, dict): continue st = row.get("skill_to_use") if disk_skill_names and st and st not in disk_skill_names: - errs.append(f"{pack_dir}: skills_decision_guide[{i}] skill_to_use {st!r} not a known skill dir") + errs.append(f"{plugin_dir}: skills_decision_guide[{i}] skill_to_use {st!r} not a known skill dir") for i, wf in enumerate(data.get("sample_workflows") or []): if not isinstance(wf, dict): @@ -477,18 +477,18 @@ def validate_pack_catalog_compliance_extra( w = (wf.get("workflow") or "") for tok in FORBIDDEN_WORKFLOW_TOKENS: if tok in w: - errs.append(f"{pack_dir}: sample_workflows[{i}] contains forbidden token {tok!r}") + errs.append(f"{plugin_dir}: sample_workflows[{i}] contains forbidden token {tok!r}") if "User:" not in w and 'User: "' not in w: - errs.append(f"{pack_dir}: sample_workflows[{i}] workflow must include User: line") + errs.append(f"{plugin_dir}: sample_workflows[{i}] workflow must include User: line") if "-" not in w: - errs.append(f"{pack_dir}: sample_workflows[{i}] workflow must use bullet lines (-)") + errs.append(f"{plugin_dir}: sample_workflows[{i}] workflow must use bullet lines (-)") - errs.extend(validate_embedded_docs(pack_dir, data, root)) - errs.extend(validate_catalog_inline_length(pack_dir, data)) + errs.extend(validate_embedded_docs(plugin_dir, data, root)) + errs.extend(validate_catalog_inline_length(plugin_dir, data)) return errs -def validate_catalog_inline_length(pack_dir: str, data: Dict[str, Any]) -> List[str]: +def validate_catalog_inline_length(plugin_dir: str, data: Dict[str, Any]) -> List[str]: """Require long prose to use a #fragment .md ref (sibling of collection.yaml), not huge inline strings.""" errs: List[str] = [] for key in CATALOG_INLINE_LENGTH_KEYS: @@ -499,7 +499,7 @@ def validate_catalog_inline_length(pack_dir: str, data: Dict[str, Any]) -> List[ continue if len(val) > CATALOG_INLINE_CHAR_LIMIT: errs.append( - f"{pack_dir}: {key} is {len(val)} chars (limit {CATALOG_INLINE_CHAR_LIMIT}); " + f"{plugin_dir}: {key} is {len(val)} chars (limit {CATALOG_INLINE_CHAR_LIMIT}); " f"move prose to a sibling .md under .catalog/ and set {key}: '#.md' " f"(same pattern as deploy_and_use)." ) @@ -507,7 +507,7 @@ def validate_catalog_inline_length(pack_dir: str, data: Dict[str, Any]) -> List[ if isinstance(dau, str) and not deploy_and_use_external_rel_path(dau): if len(dau) > CATALOG_INLINE_CHAR_LIMIT: errs.append( - f"{pack_dir}: deploy_and_use is {len(dau)} chars inline (limit {CATALOG_INLINE_CHAR_LIMIT}); " + f"{plugin_dir}: deploy_and_use is {len(dau)} chars inline (limit {CATALOG_INLINE_CHAR_LIMIT}); " "use markdown in a sibling .md and deploy_and_use: #.md" ) return errs @@ -516,22 +516,22 @@ def validate_catalog_inline_length(pack_dir: str, data: Dict[str, Any]) -> List[ def validate_all_iteration3(root: Optional[Path] = None, check_banner: bool = True) -> List[str]: root = root or REPO_ROOT all_errs: List[str] = [] - for pack in _discover_packs(root): - cat = root / pack / ".catalog" / "collection.yaml" + for plugin in _discover_plugins(root): + cat = root / plugin / ".catalog" / "collection.yaml" if not cat.exists(): - all_errs.append(f"{pack}: missing .catalog/collection.yaml") + all_errs.append(f"{plugin}: missing .catalog/collection.yaml") continue - all_errs.extend(validate_pack_iteration3(pack, root, check_banner=check_banner)) + all_errs.extend(validate_plugin_iteration3(plugin, root, check_banner=check_banner)) return all_errs def validate_all_iteration5(root: Optional[Path] = None) -> List[str]: root = root or REPO_ROOT all_errs: List[str] = [] - for pack in _discover_packs(root): - cat = root / pack / ".catalog" / "collection.yaml" + for plugin in _discover_plugins(root): + cat = root / plugin / ".catalog" / "collection.yaml" if not cat.exists(): - all_errs.append(f"{pack}: missing .catalog/collection.yaml") + all_errs.append(f"{plugin}: missing .catalog/collection.yaml") continue - all_errs.extend(validate_pack_iteration5(pack, root)) + all_errs.extend(validate_plugin_iteration5(plugin, root)) return all_errs diff --git a/scripts/install-hooks.sh b/scripts/install-hooks.sh index 6eab5000..a5220c64 100755 --- a/scripts/install-hooks.sh +++ b/scripts/install-hooks.sh @@ -83,7 +83,7 @@ echo "=========================================" echo "On commit, pre-commit runs (see .pre-commit-config.yaml):" echo " - gitleaks (secrets)" echo " - make validate (when roster/catalog-related paths change)" -echo " - make validate-skill-design-changed (when pack SKILL.md files change)" +echo " - make validate-skill-design-changed (when plugin SKILL.md files change)" echo "" echo "CI source of truth for collection checks: .github/workflows/compliance-check.yml (make validate)." echo "Manual: pre-commit run --all-files" diff --git a/scripts/package_skills.py b/scripts/package_skills.py index 61175475..4e450ca5 100644 --- a/scripts/package_skills.py +++ b/scripts/package_skills.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Package skill packs into self-contained ZIPs.""" +"""Package agent plugins into self-contained ZIPs.""" import argparse import logging @@ -12,28 +12,28 @@ logger = logging.getLogger(__name__) _REPO_ROOT = Path(__file__).resolve().parent.parent -_PACK_EXCLUDE = {"scripts", "catalog", ".claude", ".github", ".lola", "docs", "eval"} +_PLUGIN_EXCLUDE = {"scripts", "catalog", ".claude", ".github", ".lola", "docs", "eval"} @dataclass class PackageReport: - total_packs: int = 0 + total_plugins: int = 0 total_skills: int = 0 total_size_bytes: int = 0 broken_symlinks: list[str] = field(default_factory=list) errors: list[str] = field(default_factory=list) -def discover_packs(root: Path) -> list[str]: +def discover_plugins(root: Path) -> list[str]: return sorted( d.name for d in root.iterdir() - if d.is_dir() and d.name not in _PACK_EXCLUDE and not d.name.startswith(".") + if d.is_dir() and d.name not in _PLUGIN_EXCLUDE and not d.name.startswith(".") and ((d / "AGENTS.md").exists() or (d / "skills").is_dir()) ) -def discover_skills(pack_dir: Path) -> list[Path]: - skills_dir = pack_dir / "skills" +def discover_skills(plugin_dir: Path) -> list[Path]: + skills_dir = plugin_dir / "skills" if not skills_dir.is_dir(): return [] return sorted( @@ -42,9 +42,9 @@ def discover_skills(pack_dir: Path) -> list[Path]: ) -def create_pack_zip(pack_dir: Path, output_path: Path) -> tuple[int, int, list[str]]: - """Create a single ZIP containing all skills for a pack. Returns (skill_count, file_count, broken_symlinks).""" - skills = discover_skills(pack_dir) +def create_plugin_zip(plugin_dir: Path, output_path: Path) -> tuple[int, int, list[str]]: + """Create a single ZIP containing all skills for a plugin. Returns (skill_count, file_count, broken_symlinks).""" + skills = discover_skills(plugin_dir) if not skills: return 0, 0, [] @@ -80,39 +80,39 @@ def create_pack_zip(pack_dir: Path, output_path: Path) -> tuple[int, int, list[s def package_all( root: Path, output_dir: Path, - packs: list[str] | None = None, + plugins: list[str] | None = None, ) -> PackageReport: report = PackageReport() - all_packs = discover_packs(root) - target_packs = [p for p in all_packs if p in packs] if packs else all_packs - report.total_packs = len(target_packs) + all_plugins = discover_plugins(root) + target_plugins = [p for p in all_plugins if p in plugins] if plugins else all_plugins + report.total_plugins = len(target_plugins) - for pack_name in target_packs: - pack_dir = root / pack_name - zip_path = output_dir / f"{pack_name}.zip" + for plugin_name in target_plugins: + plugin_dir = root / plugin_name + zip_path = output_dir / f"{plugin_name}.zip" try: - skill_count, file_count, broken = create_pack_zip(pack_dir, zip_path) + skill_count, file_count, broken = create_plugin_zip(plugin_dir, zip_path) if skill_count == 0: - logger.info("Pack %s has no skills, skipping", pack_name) + logger.info("Plugin %s has no skills, skipping", plugin_name) continue report.broken_symlinks.extend(broken) report.total_skills += skill_count zip_size = zip_path.stat().st_size report.total_size_bytes += zip_size - logger.info("Packaged %s (%d skills, %d files, %d KB)", pack_name, skill_count, file_count, zip_size // 1024) + logger.info("Packaged %s (%d skills, %d files, %d KB)", plugin_name, skill_count, file_count, zip_size // 1024) except Exception as e: - report.errors.append(f"{pack_name}: {e}") - logger.error("Failed to package %s: %s", pack_name, e) + report.errors.append(f"{plugin_name}: {e}") + logger.error("Failed to package %s: %s", plugin_name, e) return report def main() -> int: - parser = argparse.ArgumentParser(description="Package skill packs into self-contained ZIPs") + parser = argparse.ArgumentParser(description="Package agent plugins into self-contained ZIPs") parser.add_argument("--output-dir", default="dist", help="Output directory (default: dist)") - parser.add_argument("--packs", nargs="+", help="Only package these packs (default: all)") + parser.add_argument("--plugins", nargs="+", help="Only package these plugins (default: all)") parser.add_argument("--root", default=str(_REPO_ROOT), help="Repository root (default: auto-detect)") args = parser.parse_args() @@ -123,9 +123,9 @@ def main() -> int: if not output_dir.is_absolute(): output_dir = root / output_dir - report = package_all(root=root, output_dir=output_dir, packs=args.packs) + report = package_all(root=root, output_dir=output_dir, plugins=args.plugins) - print(f"\nPackaging complete: {report.total_packs} packs, {report.total_skills} skills, {report.total_size_bytes // 1024} KB") + print(f"\nPackaging complete: {report.total_plugins} plugins, {report.total_skills} skills, {report.total_size_bytes // 1024} KB") if report.broken_symlinks: print(f" Warnings: {len(report.broken_symlinks)} broken symlinks skipped") if report.errors: diff --git a/scripts/test_validate_compass_layout.py b/scripts/test_validate_compass_layout.py index cecd47c2..6e67ae64 100644 --- a/scripts/test_validate_compass_layout.py +++ b/scripts/test_validate_compass_layout.py @@ -47,7 +47,7 @@ def _minimal_skill_md(name: str) -> str: class _RepoFixtureTestCase(unittest.TestCase): - """Create pack fixtures under the repo so compass checks can build rel paths.""" + """Create plugin fixtures under the repo so compass checks can build rel paths.""" fixture_root: Path @@ -97,29 +97,29 @@ def test_nested_references_references_flagged(self) -> None: self.assertIn("references/references/", errors[0]) def test_missing_shared_script_symlink_flagged(self) -> None: - pack_dir = self.fixture_root - group_dir = pack_dir / "scripts" / "demo-group" + plugin_dir = self.fixture_root + group_dir = plugin_dir / "scripts" / "demo-group" group_dir.mkdir(parents=True) (group_dir / "run.py").write_text("# run\n", encoding="utf-8") (group_dir / "config.yaml").write_text("key: value\n", encoding="utf-8") - scripts_dir = pack_dir / "skills" / "demo-skill" / "scripts" + scripts_dir = plugin_dir / "skills" / "demo-skill" / "scripts" scripts_dir.mkdir(parents=True) os.symlink("../../../scripts/demo-group/run.py", scripts_dir / "run.py") errors: list[str] = [] compass._check_skill_scripts_layout( - pack_dir.name, pack_dir / "skills" / "demo-skill", errors + plugin_dir.name, plugin_dir / "skills" / "demo-skill", errors ) self.assertTrue(errors) self.assertIn("config.yaml", errors[0]) - def test_forbidden_pack_scripts_path_in_skill_markdown_flagged(self) -> None: - pack_dir = self.fixture_root - pack = pack_dir.name - skill_dir = pack_dir / "skills" / "demo-skill" - group_dir = pack_dir / "scripts" / "demo-group" + def test_forbidden_plugin_scripts_path_in_skill_markdown_flagged(self) -> None: + plugin_dir = self.fixture_root + plugin = plugin_dir.name + skill_dir = plugin_dir / "skills" / "demo-skill" + group_dir = plugin_dir / "scripts" / "demo-group" group_dir.mkdir(parents=True) (group_dir / "run.py").write_text("# run\n", encoding="utf-8") @@ -130,24 +130,24 @@ def test_forbidden_pack_scripts_path_in_skill_markdown_flagged(self) -> None: refs = skill_dir / "references" refs.mkdir(parents=True) (refs / "guide.md").write_text( - f"Run python3 {pack}/scripts/demo-group/run.py\n", + f"Run python3 {plugin}/scripts/demo-group/run.py\n", encoding="utf-8", ) errors: list[str] = [] - compass._check_skill_scripts_layout(pack, skill_dir, errors) + compass._check_skill_scripts_layout(plugin, skill_dir, errors) self.assertTrue(errors) self.assertTrue( - any(f"{pack}/scripts/" in err and "authoring-repo" in err for err in errors), - msg=f"expected pack scripts path error, got: {errors}", + any(f"{plugin}/scripts/" in err and "authoring-repo" in err for err in errors), + msg=f"expected plugin scripts path error, got: {errors}", ) def test_shared_script_symlinks_complete_passes(self) -> None: - pack_dir = self.fixture_root - pack = pack_dir.name - skill_dir = pack_dir / "skills" / "demo-skill" - group_dir = pack_dir / "scripts" / "demo-group" + plugin_dir = self.fixture_root + plugin = plugin_dir.name + skill_dir = plugin_dir / "skills" / "demo-skill" + group_dir = plugin_dir / "scripts" / "demo-group" group_dir.mkdir(parents=True) (group_dir / "run.py").write_text("# run\n", encoding="utf-8") (group_dir / "config.yaml").write_text("key: value\n", encoding="utf-8") @@ -168,7 +168,7 @@ def test_shared_script_symlinks_complete_passes(self) -> None: ) errors: list[str] = [] - compass._check_skill_scripts_layout(pack, skill_dir, errors) + compass._check_skill_scripts_layout(plugin, skill_dir, errors) self.assertEqual(errors, []) @@ -201,14 +201,14 @@ def test_tier1_rejects_docs_subdirectory(self) -> None: class TestDocsTreeLinks(unittest.TestCase): def test_readme_docs_link_flagged(self) -> None: with tempfile.TemporaryDirectory() as tmp: - pack = Path(tmp) / "demo-pack" - (pack / "skills" / "demo-skill").mkdir(parents=True) - readme = pack / "README.md" + plugin = Path(tmp) / "demo-plugin" + (plugin / "skills" / "demo-skill").mkdir(parents=True) + readme = plugin / "README.md" readme.write_text( "See [docs index](docs/INDEX.md) for navigation.\n", encoding="utf-8" ) - errors = docs_tree.validate_file(readme, pack) + errors = docs_tree.validate_file(readme, plugin) self.assertTrue(errors) self.assertIn("docs/INDEX.md", errors[0]) @@ -216,8 +216,8 @@ def test_readme_docs_link_flagged(self) -> None: class TestSkillDocLinks(unittest.TestCase): def test_symlink_chain_detected_without_premature_resolve(self) -> None: with tempfile.TemporaryDirectory() as tmp: - pack = Path(tmp) / "demo-pack" - skill_dir = pack / "skills" / "demo-skill" + plugin = Path(tmp) / "demo-plugin" + skill_dir = plugin / "skills" / "demo-skill" refs = skill_dir / "references" refs.mkdir(parents=True) (refs / "leaf.md").write_text("# leaf\n", encoding="utf-8") diff --git a/scripts/test_validate_lifecycle_ceiling.py b/scripts/test_validate_lifecycle_ceiling.py index 56b40aa6..18ae9751 100644 --- a/scripts/test_validate_lifecycle_ceiling.py +++ b/scripts/test_validate_lifecycle_ceiling.py @@ -41,12 +41,12 @@ def _write_manifest(path: Path, *, name: str, kind: str = "AiResource", lifecycl path.write_text(yaml.safe_dump(data, sort_keys=False), encoding="utf-8") -def _write_root_catalog(root: Path, packs: list[str]) -> None: +def _write_root_catalog(root: Path, plugins: list[str]) -> None: data = { "apiVersion": "backstage.io/v1alpha1", "kind": "Location", "metadata": {"name": "agentic-plugins"}, - "spec": {"targets": [f"./{pack}/catalog-info.yaml" for pack in packs] + ["./mcps/catalog-info.yaml"]}, + "spec": {"targets": [f"./{plugin}/catalog-info.yaml" for plugin in plugins] + ["./mcps/catalog-info.yaml"]}, } (root / "catalog-info.yaml").write_text(yaml.safe_dump(data, sort_keys=False), encoding="utf-8") (root / "mcps").mkdir(parents=True, exist_ok=True) @@ -56,23 +56,23 @@ def _write_root_catalog(root: Path, packs: list[str]) -> None: ) -def _write_pack( +def _write_plugin( root: Path, - pack: str, + plugin: str, *, plugin_lifecycle: str | None = "__unset__", skills: dict[str, str | None] | None = None, ) -> None: - """Create /-plugin.yaml and /skills//catalog-info.yaml files.""" - pack_dir = root / pack - _write_manifest(pack_dir / f"{pack}-plugin.yaml", name=pack, lifecycle=plugin_lifecycle) + """Create /-plugin.yaml and /skills//catalog-info.yaml files.""" + plugin_dir = root / plugin + _write_manifest(plugin_dir / f"{plugin}-plugin.yaml", name=plugin, lifecycle=plugin_lifecycle) for skill_name, skill_lifecycle in (skills or {}).items(): _write_manifest( - pack_dir / "skills" / skill_name / "catalog-info.yaml", + plugin_dir / "skills" / skill_name / "catalog-info.yaml", name=skill_name, lifecycle=skill_lifecycle, ) - (root / pack / "catalog-info.yaml").write_text( + (root / plugin / "catalog-info.yaml").write_text( yaml.safe_dump({"apiVersion": "backstage.io/v1alpha1", "kind": "Location", "spec": {"targets": []}}), encoding="utf-8", ) @@ -113,25 +113,25 @@ def test_is_deprecated(self) -> None: class TestPassingCases(_TempRepoTestCase): def test_skill_equal_to_plugin_passes(self) -> None: - _write_pack(self.repo_root, "rh-demo", plugin_lifecycle="beta", skills={"demo-skill": "beta"}) + _write_plugin(self.repo_root, "rh-demo", plugin_lifecycle="beta", skills={"demo-skill": "beta"}) errors: list[str] = [] - lifecycle_ceiling.check_pack(self.repo_root, "rh-demo", errors) + lifecycle_ceiling.check_plugin(self.repo_root, "rh-demo", errors) self.assertEqual(errors, []) def test_skill_less_mature_than_plugin_passes(self) -> None: - _write_pack( + _write_plugin( self.repo_root, "rh-demo", plugin_lifecycle="production", skills={"demo-skill": "development"} ) errors: list[str] = [] - lifecycle_ceiling.check_pack(self.repo_root, "rh-demo", errors) + lifecycle_ceiling.check_plugin(self.repo_root, "rh-demo", errors) self.assertEqual(errors, []) def test_missing_lifecycles_default_to_development_and_pass(self) -> None: - _write_pack( + _write_plugin( self.repo_root, "rh-demo", plugin_lifecycle="__unset__", @@ -139,12 +139,12 @@ def test_missing_lifecycles_default_to_development_and_pass(self) -> None: ) errors: list[str] = [] - lifecycle_ceiling.check_pack(self.repo_root, "rh-demo", errors) + lifecycle_ceiling.check_plugin(self.repo_root, "rh-demo", errors) self.assertEqual(errors, []) def test_multiple_skills_all_within_ceiling(self) -> None: - _write_pack( + _write_plugin( self.repo_root, "rh-demo", plugin_lifecycle="beta", @@ -152,17 +152,17 @@ def test_multiple_skills_all_within_ceiling(self) -> None: ) errors: list[str] = [] - lifecycle_ceiling.check_pack(self.repo_root, "rh-demo", errors) + lifecycle_ceiling.check_plugin(self.repo_root, "rh-demo", errors) self.assertEqual(errors, []) class TestFailCase(_TempRepoTestCase): def test_skill_more_mature_than_plugin_fails(self) -> None: - _write_pack(self.repo_root, "rh-demo", plugin_lifecycle="development", skills={"demo-skill": "beta"}) + _write_plugin(self.repo_root, "rh-demo", plugin_lifecycle="development", skills={"demo-skill": "beta"}) errors: list[str] = [] - lifecycle_ceiling.check_pack(self.repo_root, "rh-demo", errors) + lifecycle_ceiling.check_plugin(self.repo_root, "rh-demo", errors) self.assertEqual(len(errors), 1) self.assertIn("demo-skill", errors[0]) @@ -170,15 +170,15 @@ def test_skill_more_mature_than_plugin_fails(self) -> None: self.assertIn("'development'", errors[0]) def test_production_skill_under_beta_plugin_fails(self) -> None: - _write_pack(self.repo_root, "rh-demo", plugin_lifecycle="beta", skills={"demo-skill": "production"}) + _write_plugin(self.repo_root, "rh-demo", plugin_lifecycle="beta", skills={"demo-skill": "production"}) errors: list[str] = [] - lifecycle_ceiling.check_pack(self.repo_root, "rh-demo", errors) + lifecycle_ceiling.check_plugin(self.repo_root, "rh-demo", errors) self.assertEqual(len(errors), 1) def test_only_offending_skill_is_reported(self) -> None: - _write_pack( + _write_plugin( self.repo_root, "rh-demo", plugin_lifecycle="development", @@ -186,7 +186,7 @@ def test_only_offending_skill_is_reported(self) -> None: ) errors: list[str] = [] - lifecycle_ceiling.check_pack(self.repo_root, "rh-demo", errors) + lifecycle_ceiling.check_plugin(self.repo_root, "rh-demo", errors) self.assertEqual(len(errors), 1) self.assertIn("bad-skill", errors[0]) @@ -195,15 +195,15 @@ def test_only_offending_skill_is_reported(self) -> None: class TestDeprecatedSkipLogic(_TempRepoTestCase): def test_deprecated_skill_is_skipped_even_if_more_mature(self) -> None: - _write_pack(self.repo_root, "rh-demo", plugin_lifecycle="development", skills={"demo-skill": "deprecated"}) + _write_plugin(self.repo_root, "rh-demo", plugin_lifecycle="development", skills={"demo-skill": "deprecated"}) errors: list[str] = [] - lifecycle_ceiling.check_pack(self.repo_root, "rh-demo", errors) + lifecycle_ceiling.check_plugin(self.repo_root, "rh-demo", errors) self.assertEqual(errors, []) def test_deprecated_plugin_skips_all_skills(self) -> None: - _write_pack( + _write_plugin( self.repo_root, "rh-demo", plugin_lifecycle="deprecated", @@ -211,12 +211,12 @@ def test_deprecated_plugin_skips_all_skills(self) -> None: ) errors: list[str] = [] - lifecycle_ceiling.check_pack(self.repo_root, "rh-demo", errors) + lifecycle_ceiling.check_plugin(self.repo_root, "rh-demo", errors) self.assertEqual(errors, []) def test_deprecated_skill_among_others_only_skips_itself(self) -> None: - _write_pack( + _write_plugin( self.repo_root, "rh-demo", plugin_lifecycle="development", @@ -224,7 +224,7 @@ def test_deprecated_skill_among_others_only_skips_itself(self) -> None: ) errors: list[str] = [] - lifecycle_ceiling.check_pack(self.repo_root, "rh-demo", errors) + lifecycle_ceiling.check_plugin(self.repo_root, "rh-demo", errors) self.assertEqual(len(errors), 1) self.assertIn("bad-skill", errors[0]) @@ -232,20 +232,20 @@ def test_deprecated_skill_among_others_only_skips_itself(self) -> None: class TestValidateAll(_TempRepoTestCase): - def test_validate_all_discovers_registered_packs_from_root_catalog(self) -> None: + def test_validate_all_discovers_registered_plugins_from_root_catalog(self) -> None: _write_root_catalog(self.repo_root, ["rh-good", "rh-bad"]) - _write_pack(self.repo_root, "rh-good", plugin_lifecycle="beta", skills={"good-skill": "beta"}) - _write_pack(self.repo_root, "rh-bad", plugin_lifecycle="development", skills={"bad-skill": "production"}) + _write_plugin(self.repo_root, "rh-good", plugin_lifecycle="beta", skills={"good-skill": "beta"}) + _write_plugin(self.repo_root, "rh-bad", plugin_lifecycle="development", skills={"bad-skill": "production"}) errors = lifecycle_ceiling.validate_all(self.repo_root) self.assertEqual(len(errors), 1) self.assertIn("bad-skill", errors[0]) - def test_validate_all_ignores_unregistered_packs(self) -> None: + def test_validate_all_ignores_unregistered_plugins(self) -> None: _write_root_catalog(self.repo_root, ["rh-good"]) - _write_pack(self.repo_root, "rh-good", plugin_lifecycle="beta", skills={"good-skill": "beta"}) - _write_pack(self.repo_root, "rh-bad", plugin_lifecycle="development", skills={"bad-skill": "production"}) + _write_plugin(self.repo_root, "rh-good", plugin_lifecycle="beta", skills={"good-skill": "beta"}) + _write_plugin(self.repo_root, "rh-bad", plugin_lifecycle="development", skills={"bad-skill": "production"}) errors = lifecycle_ceiling.validate_all(self.repo_root) @@ -257,7 +257,7 @@ def test_validate_all_missing_root_catalog_reports_error(self) -> None: self.assertEqual(len(errors), 1) self.assertIn("catalog-info.yaml", errors[0]) - def test_pack_missing_plugin_manifest_reports_error(self) -> None: + def test_plugin_missing_plugin_manifest_reports_error(self) -> None: _write_root_catalog(self.repo_root, ["rh-orphan"]) (self.repo_root / "rh-orphan").mkdir(parents=True) diff --git a/scripts/validate_compass_manifests.py b/scripts/validate_compass_manifests.py index b5316570..1c42a769 100644 --- a/scripts/validate_compass_manifests.py +++ b/scripts/validate_compass_manifests.py @@ -3,18 +3,18 @@ Validate Compass catalog-info.yaml manifests and skill references layout. Structural checks (no SKILL.md semantic inference): - - Roster parity: skills on disk vs pack Location targets vs manifest files + - Roster parity: skills on disk vs plugin Location targets vs manifest files - Plugin inverse roster and skill dependsOn plugin - Bidirectional dependsOn/dependencyOf for skill→skill and skill→owned-MCP - Plugin→owned-MCP inverse; plugin MCP dependsOn union vs skills - Forbidden partOf/hasPart on skill manifests; redundant plugin dependsOn system - Dangling airesource refs; canonical mcpserver:redhat/* allowed without local file - Basic field conventions on skill manifests (namespace, owner, agents, distribution) - - Skill documentation layout (all packs with skills/): + - Skill documentation layout (all plugins with skills/): no skills//docs/; no references/references/ nesting; no internal docs/ links; symlinks under references/ must not target docs/ - - Skill scripts layout: symlinks into pack scripts// must fan out all - non-test files in that group; skill docs must not use /scripts/ paths + - Skill scripts layout: symlinks into plugin scripts// must fan out all + non-test files in that group; skill docs must not use /scripts/ paths """ from __future__ import annotations @@ -29,7 +29,7 @@ _REPO_ROOT = Path(__file__).resolve().parent.parent _ROOT_CATALOG = _REPO_ROOT / "catalog-info.yaml" _SKILL_TARGET_RE = re.compile(r"^\./skills/([^/]+)/catalog-info\.yaml$") -_PLUGIN_REF = "airesource:ai5-marketplace/{pack}" +_PLUGIN_REF = "airesource:ai5-marketplace/{plugin}" _FORBIDDEN_RELATION_RE = re.compile(r"^\s+(partOf|hasPart)\s*:", re.MULTILINE) _CANONICAL_MCP_PREFIXES = ("mcpserver:redhat/", "mcpserver:default/") _EXPECTED_OWNER = "group:redhat/ai5-marketplace" @@ -56,19 +56,19 @@ def _refs(spec: dict, key: str) -> list[str]: return [str(item) for item in value] -def all_packs_with_skills() -> list[str]: - packs: list[str] = [] +def all_plugins_with_skills() -> list[str]: + plugins: list[str] = [] for entry in sorted(_REPO_ROOT.iterdir()): if not entry.is_dir() or entry.name.startswith("."): continue if (entry / "skills").is_dir(): - packs.append(entry.name) - return packs + plugins.append(entry.name) + return plugins -def registered_packs() -> list[str]: +def registered_plugins() -> list[str]: data = _load_yaml(_ROOT_CATALOG) - packs: list[str] = [] + plugins: list[str] = [] for target in data.get("spec", {}).get("targets", []): if not isinstance(target, str): continue @@ -79,12 +79,12 @@ def registered_packs() -> list[str]: parts = Path(target).parts if len(parts) != 2: continue - packs.append(parts[0]) - return sorted(set(packs)) + plugins.append(parts[0]) + return sorted(set(plugins)) -def skills_on_disk(pack_dir: Path) -> set[str]: - skills_dir = pack_dir / "skills" +def skills_on_disk(plugin_dir: Path) -> set[str]: + skills_dir = plugin_dir / "skills" if not skills_dir.is_dir(): return set() return { @@ -207,12 +207,12 @@ def _parse_shared_script_symlink_target(raw: str) -> tuple[str, str] | None: return match.group(1), match.group(2) -def _check_skill_scripts_layout(pack: str, skill_dir: Path, errors: list[str]) -> None: +def _check_skill_scripts_layout(plugin: str, skill_dir: Path, errors: list[str]) -> None: scripts_dir = skill_dir / "scripts" if not scripts_dir.is_dir(): return - pack_dir = skill_dir.parent.parent + plugin_dir = skill_dir.parent.parent skill_rel = skill_dir.relative_to(_REPO_ROOT) linked_by_group: dict[str, set[str]] = {} @@ -229,11 +229,11 @@ def _check_skill_scripts_layout(pack: str, skill_dir: Path, errors: list[str]) - return for group, linked_files in sorted(linked_by_group.items()): - group_dir = pack_dir / "scripts" / group + group_dir = plugin_dir / "scripts" / group if not group_dir.is_dir(): errors.append( f"{skill_rel}/scripts: symlinks reference scripts/{group}/ but " - f"{pack}/scripts/{group}/ is missing" + f"{plugin}/scripts/{group}/ is missing" ) continue for path in sorted(group_dir.iterdir()): @@ -244,11 +244,11 @@ def _check_skill_scripts_layout(pack: str, skill_dir: Path, errors: list[str]) - if path.name not in linked_files: errors.append( f"{skill_rel}/scripts: missing symlink for " - f"{pack}/scripts/{group}/{path.name} — fan out all non-test " + f"{plugin}/scripts/{group}/{path.name} — fan out all non-test " f"files when linking from scripts/{group}/" ) - forbidden = f"{pack}/scripts/" + forbidden = f"{plugin}/scripts/" for md_file in sorted(skill_dir.rglob("*.md")): if md_file.is_symlink() and not md_file.exists(): continue @@ -283,42 +283,42 @@ def _check_skill_conventions(path: Path, data: dict, errors: list[str]) -> None: errors.append(f"{rel}: spec.type must be skill") -def validate_pack_layout(pack: str, errors: list[str]) -> None: - pack_dir = _REPO_ROOT / pack - for skill in sorted(skills_on_disk(pack_dir)): - skill_dir = pack_dir / "skills" / skill +def validate_plugin_layout(plugin: str, errors: list[str]) -> None: + plugin_dir = _REPO_ROOT / plugin + for skill in sorted(skills_on_disk(plugin_dir)): + skill_dir = plugin_dir / "skills" / skill _check_skill_docs_layout(skill_dir, errors) - _check_skill_scripts_layout(pack, skill_dir, errors) + _check_skill_scripts_layout(plugin, skill_dir, errors) -def validate_pack(pack: str, owned_mcps: dict[str, Path], errors: list[str]) -> None: - pack_dir = _REPO_ROOT / pack - loc_path = pack_dir / "catalog-info.yaml" - plugin_path = pack_dir / f"{pack}-plugin.yaml" - plugin_ref = _PLUGIN_REF.format(pack=pack) +def validate_plugin(plugin: str, owned_mcps: dict[str, Path], errors: list[str]) -> None: + plugin_dir = _REPO_ROOT / plugin + loc_path = plugin_dir / "catalog-info.yaml" + plugin_path = plugin_dir / f"{plugin}-plugin.yaml" + plugin_ref = _PLUGIN_REF.format(plugin=plugin) if not loc_path.is_file(): - errors.append(f"{pack}: missing {loc_path.relative_to(_REPO_ROOT)}") + errors.append(f"{plugin}: missing {loc_path.relative_to(_REPO_ROOT)}") return if not plugin_path.is_file(): - errors.append(f"{pack}: missing {plugin_path.relative_to(_REPO_ROOT)}") + errors.append(f"{plugin}: missing {plugin_path.relative_to(_REPO_ROOT)}") return loc_data = _load_yaml(loc_path) plugin_data = _load_yaml(plugin_path) plugin_spec = plugin_data.get("spec", {}) - disk = skills_on_disk(pack_dir) + disk = skills_on_disk(plugin_dir) loc_targets = location_skill_targets(loc_data) for skill in sorted(disk - loc_targets): errors.append( - f"{pack}: skill '{skill}' on disk but missing from " + f"{plugin}: skill '{skill}' on disk but missing from " f"{loc_path.relative_to(_REPO_ROOT)} targets" ) for skill in sorted(loc_targets - disk): errors.append( - f"{pack}: {loc_path.relative_to(_REPO_ROOT)} targets skill '{skill}' " + f"{plugin}: {loc_path.relative_to(_REPO_ROOT)} targets skill '{skill}' " "but skills//SKILL.md not found" ) @@ -329,12 +329,12 @@ def validate_pack(pack: str, owned_mcps: dict[str, Path], errors: list[str]) -> } for skill in sorted(disk - plugin_depof_skills): errors.append( - f"{pack}: {plugin_path.relative_to(_REPO_ROOT)} missing " + f"{plugin}: {plugin_path.relative_to(_REPO_ROOT)} missing " f"dependencyOf airesource:ai5-marketplace/{skill}" ) for skill in sorted(plugin_depof_skills - disk): errors.append( - f"{pack}: {plugin_path.relative_to(_REPO_ROOT)} dependencyOf unknown skill '{skill}'" + f"{plugin}: {plugin_path.relative_to(_REPO_ROOT)} dependencyOf unknown skill '{skill}'" ) if "system:default/agentic-plugins" in _refs(plugin_spec, "dependsOn"): @@ -345,16 +345,16 @@ def validate_pack(pack: str, owned_mcps: dict[str, Path], errors: list[str]) -> skill_depends: dict[str, list[str]] = {} skill_depof: dict[str, set[str]] = {} - pack_skill_mcp_union: set[str] = set() + plugin_skill_mcp_union: set[str] = set() for skill in sorted(disk): - skill_dir = pack_dir / "skills" / skill + skill_dir = plugin_dir / "skills" / skill _check_skill_docs_layout(skill_dir, errors) - _check_skill_scripts_layout(pack, skill_dir, errors) + _check_skill_scripts_layout(plugin, skill_dir, errors) manifest = skill_dir / "catalog-info.yaml" if not manifest.is_file(): - errors.append(f"{pack}: missing {manifest.relative_to(_REPO_ROOT)}") + errors.append(f"{plugin}: missing {manifest.relative_to(_REPO_ROOT)}") continue raw = manifest.read_text(encoding="utf-8") @@ -377,22 +377,22 @@ def validate_pack(pack: str, owned_mcps: dict[str, Path], errors: list[str]) -> for dep in deps: if dep.startswith("mcpserver:"): - pack_skill_mcp_union.add(dep) + plugin_skill_mcp_union.add(dep) plugin_mcp_deps = { d for d in _refs(plugin_spec, "dependsOn") if d.startswith("mcpserver:") } - if plugin_mcp_deps != pack_skill_mcp_union: - missing_on_plugin = pack_skill_mcp_union - plugin_mcp_deps - extra_on_plugin = plugin_mcp_deps - pack_skill_mcp_union + if plugin_mcp_deps != plugin_skill_mcp_union: + missing_on_plugin = plugin_skill_mcp_union - plugin_mcp_deps + extra_on_plugin = plugin_mcp_deps - plugin_skill_mcp_union if missing_on_plugin: errors.append( - f"{pack}: {plugin_path.relative_to(_REPO_ROOT)} missing plugin dependsOn " + f"{plugin}: {plugin_path.relative_to(_REPO_ROOT)} missing plugin dependsOn " f"MCP union entries: {sorted(missing_on_plugin)}" ) if extra_on_plugin: errors.append( - f"{pack}: {plugin_path.relative_to(_REPO_ROOT)} extra plugin dependsOn " + f"{plugin}: {plugin_path.relative_to(_REPO_ROOT)} extra plugin dependsOn " f"MCP refs not used by any skill: {sorted(extra_on_plugin)}" ) @@ -405,13 +405,13 @@ def validate_pack(pack: str, owned_mcps: dict[str, Path], errors: list[str]) -> target = dep.split("/", 1)[1] if target not in disk: errors.append( - f"{pack}/skills/{skill}/catalog-info.yaml: dependsOn {dep} " - "but skill not in pack" + f"{plugin}/skills/{skill}/catalog-info.yaml: dependsOn {dep} " + "but skill not in plugin" ) continue if orchestrator_ref not in skill_depof.get(target, set()): errors.append( - f"{pack}/skills/{target}/catalog-info.yaml: missing dependencyOf " + f"{plugin}/skills/{target}/catalog-info.yaml: missing dependencyOf " f"{orchestrator_ref} (inverse of {skill} dependsOn)" ) elif dep.startswith("mcpserver:"): @@ -425,7 +425,7 @@ def validate_pack(pack: str, owned_mcps: dict[str, Path], errors: list[str]) -> ) elif not _is_allowed_dangling_mcp(dep): errors.append( - f"{pack}/skills/{skill}/catalog-info.yaml: unknown mcpserver ref {dep}" + f"{plugin}/skills/{skill}/catalog-info.yaml: unknown mcpserver ref {dep}" ) for dep in _refs(plugin_spec, "dependsOn"): @@ -449,14 +449,14 @@ def main() -> int: f"missing root catalog Location: {_ROOT_CATALOG.relative_to(_REPO_ROOT)}" ) else: - registered = registered_packs() - for pack in registered: - validate_pack(pack, owned_mcps, errors) + registered = registered_plugins() + for plugin in registered: + validate_plugin(plugin, owned_mcps, errors) registered_set = set(registered) - for pack in all_packs_with_skills(): - if pack not in registered_set: - validate_pack_layout(pack, errors) + for plugin in all_plugins_with_skills(): + if plugin not in registered_set: + validate_plugin_layout(plugin, errors) if errors: print("Compass manifest validation failed:", file=sys.stderr) diff --git a/scripts/validate_docs_tree_links.py b/scripts/validate_docs_tree_links.py index a3b0303f..70d2602f 100644 --- a/scripts/validate_docs_tree_links.py +++ b/scripts/validate_docs_tree_links.py @@ -5,18 +5,18 @@ Scope: - skills/*/references/**/*.md - skills/*/*.md (skill-root markdown such as SKILL.md and REBALANCE_*.md) -- /references/**/*.md -- leftover /docs/**/*.md (if present after incomplete migration) -- /README.md -- /.catalog/*.md +- /references/**/*.md +- leftover /docs/**/*.md (if present after incomplete migration) +- /README.md +- /.catalog/*.md Checks: - local markdown link targets exist - symlink targets resolve - no symlink loops -- resolved targets do not escape pack root +- resolved targets do not escape plugin root -Pack README / catalog fragments: validate pack-local docs links +Plugin README / catalog fragments: validate plugin-local docs links (`references/`, `skills/`, and leftover `docs/`) so stale `docs/INDEX.md` pointers fail CI after a `docs/` → `references/` migration. """ @@ -31,7 +31,7 @@ from pathlib import Path from typing import Iterable -DEFAULT_PACKS = [ +DEFAULT_PLUGINS = [ "rh-sre", "rh-developer", "ocp-admin", @@ -53,28 +53,28 @@ def is_external(target: str) -> bool: ) -def resolve_packs(paths: Iterable[str]) -> set[Path]: - packs: set[Path] = set() +def resolve_plugins(paths: Iterable[str]) -> set[Path]: + plugins: set[Path] = set() for p in paths: path = Path(p) if path.is_file(): if path.name == "SKILL.md" and path.parent.parent.name == "skills": - packs.add(path.parent.parent.parent.resolve()) + plugins.add(path.parent.parent.parent.resolve()) elif path.name.endswith(".md"): - # If file belongs to a pack directory, infer it. + # If file belongs to a plugin directory, infer it. parts = path.resolve().parts if "skills" in parts: idx = parts.index("skills") - packs.add(Path(*parts[:idx]).resolve()) + plugins.add(Path(*parts[:idx]).resolve()) continue if path.is_dir(): if (path / "skills").exists(): - packs.add(path.resolve()) + plugins.add(path.resolve()) continue - # Maybe path is pack name that exists in cwd + # Maybe path is plugin name that exists in cwd if (Path.cwd() / path / "skills").exists(): - packs.add((Path.cwd() / path).resolve()) - return packs + plugins.add((Path.cwd() / path).resolve()) + return plugins def _dedupe(paths: Iterable[Path]) -> list[Path]: @@ -91,8 +91,8 @@ def _dedupe(paths: Iterable[Path]) -> list[Path]: return out -def _is_pack_local_doc_link(base: str) -> bool: - """README/catalog links that must resolve from the pack root.""" +def _is_plugin_local_doc_link(base: str) -> bool: + """README/catalog links that must resolve from the plugin root.""" normalized = base.replace("\\", "/") if normalized.startswith("./"): normalized = normalized[2:] @@ -103,34 +103,34 @@ def _is_pack_local_doc_link(base: str) -> bool: ) -def scan_targets(pack_root: Path) -> list[Path]: +def scan_targets(plugin_root: Path) -> list[Path]: targets: list[Path] = [] - skills_dir = pack_root / "skills" + skills_dir = plugin_root / "skills" if skills_dir.exists(): for skill_dir in sorted(skills_dir.glob("*")): if not skill_dir.is_dir() or not (skill_dir / "SKILL.md").exists(): continue targets.extend(sorted(skill_dir.glob("references/**/*.md"))) targets.extend(sorted(skill_dir.glob("*.md"))) - pack_refs = pack_root / "references" - if pack_refs.exists(): - targets.extend(sorted(pack_refs.glob("**/*.md"))) - pack_docs = pack_root / "docs" - if pack_docs.exists(): - targets.extend(sorted(pack_docs.glob("**/*.md"))) - readme = pack_root / "README.md" + plugin_refs = plugin_root / "references" + if plugin_refs.exists(): + targets.extend(sorted(plugin_refs.glob("**/*.md"))) + plugin_docs = plugin_root / "docs" + if plugin_docs.exists(): + targets.extend(sorted(plugin_docs.glob("**/*.md"))) + readme = plugin_root / "README.md" if readme.exists(): targets.append(readme) - catalog = pack_root / ".catalog" + catalog = plugin_root / ".catalog" if catalog.exists(): targets.extend(sorted(catalog.glob("*.md"))) return _dedupe(targets) -def validate_file(path: Path, pack_root: Path) -> list[str]: +def validate_file(path: Path, plugin_root: Path) -> list[str]: errs: list[str] = [] text = path.read_text(encoding="utf-8", errors="ignore") - is_pack_meta = (path == (pack_root / "README.md")) or (path.parent == (pack_root / ".catalog")) + is_plugin_meta = (path == (plugin_root / "README.md")) or (path.parent == (plugin_root / ".catalog")) for line_no, line in enumerate(text.splitlines(), start=1): for m in MD_LINK_RE.finditer(line): raw = m.group(1).strip() @@ -140,15 +140,15 @@ def validate_file(path: Path, pack_root: Path) -> list[str]: if not base.endswith(".md"): continue - # For pack README / catalog fragments, validate pack-local docs references + # For plugin README / catalog fragments, validate plugin-local docs references # including leftover docs/ links from incomplete migrations. - if is_pack_meta: - if not _is_pack_local_doc_link(base): + if is_plugin_meta: + if not _is_plugin_local_doc_link(base): continue link_base = base.replace("\\", "/") if link_base.startswith("./"): link_base = link_base[2:] - link_path = pack_root / link_base + link_path = plugin_root / link_base else: link_path = path.parent / base try: @@ -161,10 +161,10 @@ def validate_file(path: Path, pack_root: Path) -> list[str]: continue try: - resolved.relative_to(pack_root) + resolved.relative_to(plugin_root) except ValueError: errs.append( - f"{path}:{line_no}: link escapes pack root '{raw}' -> '{resolved}'" + f"{path}:{line_no}: link escapes plugin root '{raw}' -> '{resolved}'" ) if link_path.is_symlink(): @@ -183,30 +183,30 @@ def validate_file(path: Path, pack_root: Path) -> list[str]: def main() -> int: parser = argparse.ArgumentParser( - description="Validate markdown links in skill docs, pack references, README, and catalog fragments" + description="Validate markdown links in skill docs, plugin references, README, and catalog fragments" ) parser.add_argument( "paths", nargs="*", - default=DEFAULT_PACKS, - help="Pack directories or SKILL.md paths", + default=DEFAULT_PLUGINS, + help="Plugin directories or SKILL.md paths", ) parser.add_argument("--json-out", help="Optional JSON summary output path") args = parser.parse_args() - packs = resolve_packs(args.paths) - if not packs: - packs = {Path(p).resolve() for p in DEFAULT_PACKS if (Path(p) / "skills").exists()} + plugins = resolve_plugins(args.paths) + if not plugins: + plugins = {Path(p).resolve() for p in DEFAULT_PLUGINS if (Path(p) / "skills").exists()} all_errors: list[str] = [] scanned_files = 0 - for pack in sorted(packs): - for f in scan_targets(pack): + for plugin in sorted(plugins): + for f in scan_targets(plugin): scanned_files += 1 - all_errors.extend(validate_file(f, pack)) + all_errors.extend(validate_file(f, plugin)) summary = { - "packs_scanned": len(packs), + "plugins_scanned": len(plugins), "files_scanned": scanned_files, "error_count": len(all_errors), } diff --git a/scripts/validate_lifecycle_ceiling.py b/scripts/validate_lifecycle_ceiling.py index 0ee3210f..e8899adf 100644 --- a/scripts/validate_lifecycle_ceiling.py +++ b/scripts/validate_lifecycle_ceiling.py @@ -3,13 +3,13 @@ Validate the Compass "lifecycle ceiling" rule. By design, a child skill cannot have a more mature ``spec.lifecycle`` than -its parent plugin (pack). This script enforces that rule in CI: +its parent plugin. This script enforces that rule in CI: - The allowed lifecycle order is: development (0) < beta (1) < production (2). - Missing lifecycles default to "development". - Entities with lifecycle "deprecated" (skills or plugins) are skipped — they are not compared against the ceiling. - - Packs are discovered from the root ``catalog-info.yaml`` ``spec.targets`` + - Plugins are discovered from the root ``catalog-info.yaml`` ``spec.targets`` (the same set Compass ingests), mirroring ``validate_compass_manifests.py``. """ @@ -59,11 +59,11 @@ def lifecycle_rank(lifecycle: str | None) -> int: return LIFECYCLE_RANK[value] -def registered_packs(root: Path) -> list[str]: - """Return pack directory names referenced from the root catalog-info.yaml.""" +def registered_plugins(root: Path) -> list[str]: + """Return plugin directory names referenced from the root catalog-info.yaml.""" root_catalog = root / "catalog-info.yaml" data = _load_yaml(root_catalog) - packs: list[str] = [] + plugins: list[str] = [] for target in data.get("spec", {}).get("targets", []): if not isinstance(target, str): continue @@ -74,23 +74,23 @@ def registered_packs(root: Path) -> list[str]: parts = Path(target).parts if len(parts) != 2: continue - packs.append(parts[0]) - return sorted(set(packs)) + plugins.append(parts[0]) + return sorted(set(plugins)) -def _skill_manifests(pack_dir: Path) -> list[Path]: - skills_dir = pack_dir / "skills" +def _skill_manifests(plugin_dir: Path) -> list[Path]: + skills_dir = plugin_dir / "skills" if not skills_dir.is_dir(): return [] return sorted(skills_dir.glob("*/catalog-info.yaml")) -def check_pack(root: Path, pack: str, errors: list[str]) -> None: - """Validate the lifecycle ceiling for a single pack (skills vs. their plugin).""" - pack_dir = root / pack - plugin_path = pack_dir / f"{pack}-plugin.yaml" +def check_plugin(root: Path, plugin: str, errors: list[str]) -> None: + """Validate the lifecycle ceiling for a single plugin (skills vs. their plugin).""" + plugin_dir = root / plugin + plugin_path = plugin_dir / f"{plugin}-plugin.yaml" if not plugin_path.is_file(): - errors.append(f"{pack}: missing plugin manifest {plugin_path.relative_to(root)}") + errors.append(f"{plugin}: missing plugin manifest {plugin_path.relative_to(root)}") return try: @@ -110,7 +110,7 @@ def check_pack(root: Path, pack: str, errors: list[str]) -> None: errors.append(f"{plugin_path.relative_to(root)}: {exc}") return - for manifest in _skill_manifests(pack_dir): + for manifest in _skill_manifests(plugin_dir): try: skill_data = _load_yaml(manifest) except (OSError, ValueError, yaml.YAMLError) as exc: @@ -131,22 +131,22 @@ def check_pack(root: Path, pack: str, errors: list[str]) -> None: if skill_rank > plugin_rank: errors.append( - f"{pack}/{skill_name}: lifecycle '{skill_lifecycle}' exceeds parent " - f"plugin '{pack}' lifecycle '{plugin_lifecycle}' " + f"{plugin}/{skill_name}: lifecycle '{skill_lifecycle}' exceeds parent " + f"plugin '{plugin}' lifecycle '{plugin_lifecycle}' " f"({manifest.relative_to(root)})" ) def validate_all(root: Path) -> list[str]: - """Run the lifecycle ceiling check for every pack registered in catalog-info.yaml.""" + """Run the lifecycle ceiling check for every plugin registered in catalog-info.yaml.""" errors: list[str] = [] root_catalog = root / "catalog-info.yaml" if not root_catalog.is_file(): errors.append(f"missing root catalog Location: {root_catalog}") return errors - for pack in registered_packs(root): - check_pack(root, pack, errors) + for plugin in registered_plugins(root): + check_plugin(root, plugin, errors) return errors diff --git a/scripts/validate_mcp_tools.py b/scripts/validate_mcp_tools.py index ab014596..9384f8cf 100644 --- a/scripts/validate_mcp_tools.py +++ b/scripts/validate_mcp_tools.py @@ -9,9 +9,9 @@ Platform: Linux and macOS only (uses select.select for non-blocking I/O). Usage: - python scripts/validate_mcp_tools.py [pack1] [pack2] ... + python scripts/validate_mcp_tools.py [plugin1] [plugin2] ... python scripts/validate_mcp_tools.py --summary-only --log-file .validate/mcp-tools.log - No args: validates all packs that have mcps.json + No args: validates all plugins that have mcps.json """ from __future__ import annotations @@ -53,7 +53,7 @@ @dataclass class Finding: skill: str - pack: str + plugin: str tool: str file_path: str line_number: int | None @@ -184,14 +184,14 @@ def print_validation_summary(combined: ValidationResult, reporter: Reporter) -> reporter.summary() if combined.warnings: - skills_affected = len({(w.pack, w.skill) for w in combined.warnings}) - by_pack = Counter(w.pack for w in combined.warnings) - pack_bits = ", ".join(f"{pack} ({count})" for pack, count in by_pack.most_common()) + skills_affected = len({(w.plugin, w.skill) for w in combined.warnings}) + by_plugin = Counter(w.plugin for w in combined.warnings) + plugin_bits = ", ".join(f"{plugin} ({count})" for plugin, count in by_plugin.most_common()) reporter.summary( f" Unverifiable tools: {len(combined.warnings)} tool reference(s) " f"in {skills_affected} skill(s)" ) - reporter.summary(f" By pack: {pack_bits}") + reporter.summary(f" By plugin: {plugin_bits}") if reporter.log_path is not None: reporter.summary(f" Details: see {reporter.log_path}") reporter.summary() @@ -443,33 +443,33 @@ def parse_frontmatter(skill_path: Path) -> tuple[str, int | None]: return "", None -def find_packs(repo_root: Path) -> list[str]: - """Find all packs that have both mcps.json and a skills directory.""" - packs = [] +def find_plugins(repo_root: Path) -> list[str]: + """Find all plugins that have both mcps.json and a skills directory.""" + plugins = [] for mcps_file in sorted(repo_root.glob("*/mcps.json")): - pack_dir = mcps_file.parent - if (pack_dir / "skills").is_dir(): - packs.append(pack_dir.name) - return packs + plugin_dir = mcps_file.parent + if (plugin_dir / "skills").is_dir(): + plugins.append(plugin_dir.name) + return plugins -def validate_pack( - pack: str, repo_root: Path, kubeconfig: str, reporter: Reporter, +def validate_plugin( + plugin: str, repo_root: Path, kubeconfig: str, reporter: Reporter, ) -> ValidationResult: - """Validate all skills in a single pack against its MCP servers.""" + """Validate all skills in a single plugin against its MCP servers.""" result = ValidationResult() - pack_dir = repo_root / pack - mcps_file = pack_dir / "mcps.json" + plugin_dir = repo_root / plugin + mcps_file = plugin_dir / "mcps.json" if not mcps_file.exists(): - reporter.detail(f" WARNING: {pack}/mcps.json not found, skipping pack") + reporter.detail(f" WARNING: {plugin}/mcps.json not found, skipping plugin") return result try: with open(mcps_file) as f: config = json.load(f) except (json.JSONDecodeError, OSError) as e: - reporter.detail(f" ERROR: failed to parse {pack}/mcps.json: {e}") + reporter.detail(f" ERROR: failed to parse {plugin}/mcps.json: {e}") result.failed += 1 return result @@ -510,7 +510,7 @@ def validate_pack( if all_available_tools: reporter.detail(f" Combined tool pool: {len(all_available_tools)} unique tools") - skills_dir = pack_dir / "skills" + skills_dir = plugin_dir / "skills" if not skills_dir.exists(): return result @@ -526,7 +526,7 @@ def validate_pack( if not allowed_tools_str: result.skipped += 1 - reporter.detail(f" SKIP {pack}/{skill_name}: no allowed-tools declared") + reporter.detail(f" SKIP {plugin}/{skill_name}: no allowed-tools declared") continue declared_tools = allowed_tools_str.split() @@ -535,7 +535,7 @@ def validate_pack( if not missing: result.passed += 1 reporter.detail( - f" PASS {pack}/{skill_name}: all {len(declared_tools)} tools validated" + f" PASS {plugin}/{skill_name}: all {len(declared_tools)} tools validated" ) elif result.has_skipped_servers: verified = [t for t in declared_tools if t in all_available_tools] @@ -545,7 +545,7 @@ def validate_pack( suggestion = suggest_tool(tool, all_available_tools) finding = Finding( skill=skill_name, - pack=pack, + plugin=plugin, tool=tool, file_path=rel_path, line_number=line_number, @@ -553,7 +553,7 @@ def validate_pack( ) result.warnings.append(finding) reporter.detail( - f" WARN {pack}/{skill_name}: {len(verified)}/{len(declared_tools)} tools verified, " + f" WARN {plugin}/{skill_name}: {len(verified)}/{len(declared_tools)} tools verified, " f"{len(missing)} unverifiable (MCP server not started)" ) else: @@ -563,14 +563,14 @@ def validate_pack( suggestion = suggest_tool(tool, all_available_tools) finding = Finding( skill=skill_name, - pack=pack, + plugin=plugin, tool=tool, file_path=rel_path, line_number=line_number, suggestion=suggestion, ) result.findings.append(finding) - reporter.detail(f" FAIL {pack}/{skill_name}: {finding}") + reporter.detail(f" FAIL {plugin}/{skill_name}: {finding}") return result @@ -599,9 +599,9 @@ def parse_args(argv: list[str]) -> argparse.Namespace: description="Validate allowed-tools in SKILL.md against live MCP servers", ) parser.add_argument( - "packs", + "plugins", nargs="*", - help="Pack names to validate (default: all packs with mcps.json)", + help="Plugin names to validate (default: all plugins with mcps.json)", ) parser.add_argument( "--log-file", @@ -620,7 +620,7 @@ def parse_args(argv: list[str]) -> argparse.Namespace: def main(argv: list[str] | None = None) -> int: args = parse_args(argv if argv is not None else sys.argv[1:]) repo_root = Path(__file__).resolve().parent.parent - packs = args.packs or None + plugins = args.plugins or None skip_reason = check_prerequisites() if skip_reason: @@ -633,11 +633,11 @@ def main(argv: list[str] | None = None) -> int: if default.exists(): kubeconfig = str(default) - if not packs: - packs = find_packs(repo_root) + if not plugins: + plugins = find_plugins(repo_root) - if not packs: - print("No packs with mcps.json found") + if not plugins: + print("No plugins with mcps.json found") return 0 log_path = args.log_file @@ -652,15 +652,15 @@ def main(argv: list[str] | None = None) -> int: reporter.detail(" Verifying allowed-tools against live MCP servers") reporter.detail("=" * 66) reporter.detail() - reporter.detail(f"Packs to validate: {', '.join(packs)}") + reporter.detail(f"Plugins to validate: {', '.join(plugins)}") reporter.detail(f"KUBECONFIG: {kubeconfig}") reporter.detail() combined = ValidationResult() - for pack in packs: - reporter.detail(f"-- {pack} --") - result = validate_pack(pack, repo_root, kubeconfig, reporter) + for plugin in plugins: + reporter.detail(f"-- {plugin} --") + result = validate_plugin(plugin, repo_root, kubeconfig, reporter) combined.total_skills += result.total_skills combined.passed += result.passed combined.skipped += result.skipped diff --git a/scripts/validate_skill_doc_links.py b/scripts/validate_skill_doc_links.py index a0a7d17d..8399bdc1 100644 --- a/scripts/validate_skill_doc_links.py +++ b/scripts/validate_skill_doc_links.py @@ -3,13 +3,13 @@ Validate skill markdown links to enforce skill-local references convention. Rules: -- Forbid upward traversal into pack docs (../references, ../../references, etc). +- Forbid upward traversal into plugin docs (../references, ../../references, etc). - Internal docs links must use references/... path from skill directory. - Linked reference files must exist (symlinks allowed, dangling symlinks rejected). -- Resolved targets must stay within the pack root. +- Resolved targets must stay within the plugin root. Scans SKILL.md and other skill-root markdown (for example REBALANCE_*.md). -Pack-level references/**/*.md is covered by validate_docs_tree_links.py. +Plugin-level references/**/*.md is covered by validate_docs_tree_links.py. """ from __future__ import annotations @@ -23,7 +23,7 @@ from pathlib import Path from typing import Iterable -DEFAULT_PACKS = [ +DEFAULT_PLUGINS = [ "rh-sre", "rh-developer", "ocp-admin", @@ -65,9 +65,9 @@ def iter_skill_files(paths: Iterable[str]) -> list[Path]: if skills_dir.exists(): files.extend(_skill_root_markdown(skills_dir)) continue - pack_path = Path(p) - if (pack_path / "skills").exists(): - files.extend(_skill_root_markdown(pack_path / "skills")) + plugin_path = Path(p) + if (plugin_path / "skills").exists(): + files.extend(_skill_root_markdown(plugin_path / "skills")) dedup = sorted(set(files)) return dedup @@ -89,7 +89,7 @@ def _is_skill_local_references_link(target: str) -> bool: def validate_skill_file(skill_file: Path, result: ValidationResult) -> None: skill_dir = skill_file.parent - pack_root = skill_file.parent.parent.parent.resolve() + plugin_root = skill_file.parent.parent.parent.resolve() text = skill_file.read_text(encoding="utf-8") for line_no, line in enumerate(text.splitlines(), start=1): @@ -153,10 +153,10 @@ def validate_skill_file(skill_file: Path, result: ValidationResult) -> None: continue try: - resolved.relative_to(pack_root) + resolved.relative_to(plugin_root) except ValueError: result.errors.append( - f"{skill_file}:{line_no}: linked doc escapes pack root '{raw_target}' -> '{resolved}'" + f"{skill_file}:{line_no}: linked doc escapes plugin root '{raw_target}' -> '{resolved}'" ) @@ -167,8 +167,8 @@ def main() -> int: parser.add_argument( "paths", nargs="*", - default=DEFAULT_PACKS, - help="Pack directories or SKILL.md paths to validate", + default=DEFAULT_PLUGINS, + help="Plugin directories or SKILL.md paths to validate", ) parser.add_argument( "--json-out", diff --git a/scripts/validate_skills_tier1.py b/scripts/validate_skills_tier1.py index 5de3fea4..89fe615e 100644 --- a/scripts/validate_skills_tier1.py +++ b/scripts/validate_skills_tier1.py @@ -55,7 +55,7 @@ re.IGNORECASE, ) -DEFAULT_PACKS = [ +DEFAULT_PLUGINS = [ "rh-sre", "rh-developer", "ocp-admin", "rh-virt", "rh-ai-engineer", "rh-automation", "rh-basic", ] @@ -129,8 +129,8 @@ def _rel(path: Path) -> str: return str(path) -def _pack_name(skill_path: Path) -> str: - """Extract pack name from a skill path like rh-sre/skills/cve-impact/SKILL.md.""" +def _plugin_name(skill_path: Path) -> str: + """Extract plugin name from a skill path like rh-sre/skills/cve-impact/SKILL.md.""" if skill_path.parent.parent.name == "skills": return str(skill_path.parent.parent.parent) return str(skill_path.parent) @@ -316,8 +316,8 @@ def main() -> int: parser.add_argument( "paths", nargs="*", - default=DEFAULT_PACKS, - help="Pack directories or specific SKILL.md paths to validate", + default=DEFAULT_PLUGINS, + help="Plugin directories or specific SKILL.md paths to validate", ) parser.add_argument( "--warnings-as-errors", @@ -349,12 +349,12 @@ def main() -> int: all_errors: list[tuple[Path, str]] = [] all_warnings: list[tuple[Path, str]] = [] - # Validate and group results by pack - results_by_pack: dict[str, list[tuple[Path, ValidationResult]]] = {} + # Validate and group results by plugin + results_by_plugin: dict[str, list[tuple[Path, ValidationResult]]] = {} for skill_path in sorted(skill_files): r = validate_skill(skill_path) - pack = _pack_name(skill_path) - results_by_pack.setdefault(pack, []).append((skill_path, r)) + plugin = _plugin_name(skill_path) + results_by_plugin.setdefault(plugin, []).append((skill_path, r)) for err in r.errors: all_errors.append((skill_path, err)) @@ -363,18 +363,18 @@ def main() -> int: if args.warnings_as_errors: all_errors.append((skill_path, f"[WARN] {warn}")) - # Print results grouped by pack + # Print results grouped by plugin total_skills = 0 passed_skills = 0 warned_skills = 0 failed_skills = 0 - for pack, pack_results in sorted(results_by_pack.items()): + for plugin, plugin_results in sorted(results_by_plugin.items()): print(SEPARATOR) - print(f"{BOLD} Pack: {pack}{NC}") + print(f"{BOLD} Plugin: {plugin}{NC}") print(SEPARATOR) - for skill_path, r in pack_results: + for skill_path, r in plugin_results: skill_name = skill_path.parent.name total_skills += 1 diff --git a/scripts/validate_skills_tier2.py b/scripts/validate_skills_tier2.py index b02eae0e..a991f77b 100644 --- a/scripts/validate_skills_tier2.py +++ b/scripts/validate_skills_tier2.py @@ -11,7 +11,7 @@ Frontmatter: description should include 'NOT for' anti-pattern (WARNING) Heading: first heading should follow '# / Skill' format Heading: overview paragraph after heading (WARNING) - DP0: Pack layout (Lola format) - mcps.json only, error if .mcp.json exists + DP0: Plugin layout (Lola format) - mcps.json only, error if .mcp.json exists DP1: Document Consultation - correct format (Action: Read, Output to user) DP2: Parameter order - Document Consultation before MCP Tool/Parameters DP3: Conciseness - description length, "Use when" examples @@ -124,19 +124,19 @@ re.IGNORECASE, ) -# Pack layout (Lola format) +# Plugin layout (Lola format) MCP_FILENAME = "mcps.json" MCP_DEPRECATED = ".mcp.json" -def validate_pack_layout(pack_dir: Path) -> list[str]: +def validate_plugin_layout(plugin_dir: Path) -> list[str]: """ - DP0: Pack layout (Lola format). + DP0: Plugin layout (Lola format). Error if .mcp.json exists; validate mcps.json structure if present. """ errors = [] - deprecated = pack_dir / MCP_DEPRECATED - mcp_file = pack_dir / MCP_FILENAME + deprecated = plugin_dir / MCP_DEPRECATED + mcp_file = plugin_dir / MCP_FILENAME if deprecated.exists(): errors.append( @@ -172,10 +172,10 @@ def is_valid(self) -> bool: return len(self.errors) == 0 -def find_skill_files(pack_dirs: list[str]) -> Iterator[Path]: - """Yield paths to all SKILL.md files in pack directories.""" - for pack_dir in pack_dirs: - skills_dir = Path(pack_dir) / "skills" +def find_skill_files(plugin_dirs: list[str]) -> Iterator[Path]: + """Yield paths to all SKILL.md files in plugin directories.""" + for plugin_dir in plugin_dirs: + skills_dir = Path(plugin_dir) / "skills" if skills_dir.exists(): yield from skills_dir.glob("*/SKILL.md") @@ -726,8 +726,8 @@ def _rel(path: Path) -> Path: return path.relative_to(cwd) if path.is_relative_to(cwd) else path -def _pack_name(skill_path: Path) -> str: - """Extract pack name from a skill path like rh-sre/skills/cve-impact/SKILL.md.""" +def _plugin_name(skill_path: Path) -> str: + """Extract plugin name from a skill path like rh-sre/skills/cve-impact/SKILL.md.""" if skill_path.parent.parent.name == "skills": return str(skill_path.parent.parent.parent) return str(skill_path.parent) @@ -742,7 +742,7 @@ def main() -> int: "paths", nargs="*", default=["rh-sre", "rh-developer", "ocp-admin", "rh-virt", "rh-ai-engineer", "rh-automation", "rh-basic"], - help="Pack directories or specific SKILL.md paths to validate", + help="Plugin directories or specific SKILL.md paths to validate", ) parser.add_argument( "--warnings-as-errors", @@ -762,33 +762,33 @@ def main() -> int: if skills_dir.exists(): skill_files.extend(skills_dir.glob("*/SKILL.md")) else: - pack_path = Path(p) - if (pack_path / "skills").exists(): - skill_files.extend((pack_path / "skills").glob("*/SKILL.md")) + plugin_path = Path(p) + if (plugin_path / "skills").exists(): + skill_files.extend((plugin_path / "skills").glob("*/SKILL.md")) all_errors: list[tuple[Path, str]] = [] all_warnings: list[tuple[Path, str]] = [] - # Collect pack dirs for layout validation - pack_dirs: set[Path] = set() + # Collect plugin dirs for layout validation + plugin_dirs: set[Path] = set() for p in args.paths: path = Path(p) if path.is_dir() and path.exists(): - pack_dirs.add(path) + plugin_dirs.add(path) for sf in skill_files: if sf.parent.parent.name == "skills": - pack_dirs.add(sf.parent.parent.parent) + plugin_dirs.add(sf.parent.parent.parent) - # DP0: Pack layout (Lola format) - for pack_dir in sorted(pack_dirs): - if pack_dir.exists(): - layout_errors = validate_pack_layout(pack_dir) + # DP0: Plugin layout (Lola format) + for plugin_dir in sorted(plugin_dirs): + if plugin_dir.exists(): + layout_errors = validate_plugin_layout(plugin_dir) for err in layout_errors: - all_errors.append((pack_dir, err)) + all_errors.append((plugin_dir, err)) if not skill_files: if all_errors: - print(f"{RED}❌ Pack layout validation failed:{NC}") + print(f"{RED}❌ Plugin layout validation failed:{NC}") for path, err in all_errors: print(f" • {path}: {err}") return 1 @@ -800,12 +800,12 @@ def main() -> int: print(SEPARATOR) print() - # Validate and group results by pack - results_by_pack: dict[str, list[tuple[Path, ValidationResult]]] = {} + # Validate and group results by plugin + results_by_plugin: dict[str, list[tuple[Path, ValidationResult]]] = {} for skill_path in sorted(skill_files): result = validate_skill(skill_path) - pack = _pack_name(skill_path) - results_by_pack.setdefault(pack, []).append((skill_path, result)) + plugin = _plugin_name(skill_path) + results_by_plugin.setdefault(plugin, []).append((skill_path, result)) if result.errors: for err in result.errors: @@ -816,18 +816,18 @@ def main() -> int: if args.warnings_as_errors: all_errors.append((skill_path, f"[WARN] {warn}")) - # Print results grouped by pack + # Print results grouped by plugin total_skills = 0 passed_skills = 0 warned_skills = 0 failed_skills = 0 - for pack, pack_results in sorted(results_by_pack.items()): + for plugin, plugin_results in sorted(results_by_plugin.items()): print(SEPARATOR) - print(f"{BOLD} Pack: {pack}{NC}") + print(f"{BOLD} Plugin: {plugin}{NC}") print(SEPARATOR) - for skill_path, result in pack_results: + for skill_path, result in plugin_results: skill_name = skill_path.parent.name total_skills += 1 @@ -849,11 +849,11 @@ def main() -> int: print() - # DP0 pack layout errors + # DP0 plugin layout errors if all_errors and any(e.startswith("DP0:") for _, e in all_errors): layout_errs = [(p, e) for p, e in all_errors if e.startswith("DP0:")] print(SEPARATOR) - print(f"{BOLD} Pack Layout (DP0){NC}") + print(f"{BOLD} Plugin Layout (DP0){NC}") print(SEPARATOR) for path, err in layout_errs: print(f" {RED}❌{NC} {_rel(path)}: {err}") diff --git a/scripts/validate_structure.py b/scripts/validate_structure.py index 92e661fe..26b8f7ef 100644 --- a/scripts/validate_structure.py +++ b/scripts/validate_structure.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 """ -Validate agentic collection pack structure (mcps.json, AGENTS.md; plugin.json optional). +Validate agentic collection plugin structure (mcps.json, AGENTS.md; plugin.json optional). Skill-level validation (frontmatter, sections, security) is handled by validate_skills_tier1.py and validate_skills_tier2.py. @@ -15,7 +15,7 @@ _REPO_ROOT = Path(__file__).resolve().parent.parent _EXCLUDE = {"scripts", "catalog", ".claude", ".github", ".lola", "docs", "eval"} -PACK_DIRS = sorted( +PLUGIN_DIRS = sorted( d.name for d in _REPO_ROOT.iterdir() if d.is_dir() and d.name not in _EXCLUDE and not d.name.startswith(".") and ((d / "AGENTS.md").exists() or (d / "skills").is_dir()) @@ -25,18 +25,18 @@ AGENTS_MD_DEPRECATED = "CLAUDE.md" -def validate_plugin_json(pack_dir: str) -> List[str]: +def validate_plugin_json(plugin_dir: str) -> List[str]: """ Validate plugin.json structure when `.claude-plugin/plugin.json` exists. Args: - pack_dir: Collection directory name + plugin_dir: Collection directory name Returns: List of error messages (empty if valid or file absent) """ errors = [] - plugin_path = Path(pack_dir) / '.claude-plugin' / 'plugin.json' + plugin_path = Path(plugin_dir) / '.claude-plugin' / 'plugin.json' if not plugin_path.exists(): # plugin.json is optional @@ -48,16 +48,16 @@ def validate_plugin_json(pack_dir: str) -> List[str]: # Check required fields if 'name' not in data: - errors.append(f"{pack_dir}: plugin.json missing required field 'name'") + errors.append(f"{plugin_dir}: plugin.json missing required field 'name'") if 'version' not in data: - errors.append(f"{pack_dir}: plugin.json missing required field 'version'") + errors.append(f"{plugin_dir}: plugin.json missing required field 'version'") if 'description' not in data: - errors.append(f"{pack_dir}: plugin.json missing required field 'description'") + errors.append(f"{plugin_dir}: plugin.json missing required field 'description'") except json.JSONDecodeError as e: - errors.append(f"{pack_dir}: Invalid JSON in plugin.json: {e}") + errors.append(f"{plugin_dir}: Invalid JSON in plugin.json: {e}") except Exception as e: - errors.append(f"{pack_dir}: Error reading plugin.json: {e}") + errors.append(f"{plugin_dir}: Error reading plugin.json: {e}") return errors @@ -66,25 +66,25 @@ def validate_plugin_json(pack_dir: str) -> List[str]: MCP_DEPRECATED = ".mcp.json" -def validate_mcp_json(pack_dir: str) -> List[str]: +def validate_mcp_json(plugin_dir: str) -> List[str]: """ Validate mcps.json structure. Errors if deprecated .mcp.json exists (must be renamed to mcps.json). Args: - pack_dir: Pack directory name + plugin_dir: Plugin directory name Returns: List of error messages (empty if valid) """ errors = [] - pack_path = Path(pack_dir) - deprecated_path = pack_path / MCP_DEPRECATED - mcp_path = pack_path / MCP_FILENAME + plugin_path = Path(plugin_dir) + deprecated_path = plugin_path / MCP_DEPRECATED + mcp_path = plugin_path / MCP_FILENAME if deprecated_path.exists(): errors.append( - f"{pack_dir}: deprecated {MCP_DEPRECATED} found; rename to {MCP_FILENAME}" + f"{plugin_dir}: deprecated {MCP_DEPRECATED} found; rename to {MCP_FILENAME}" ) return errors @@ -98,14 +98,14 @@ def validate_mcp_json(pack_dir: str) -> List[str]: # Check for mcpServers key if 'mcpServers' not in data: - errors.append(f"{pack_dir}: {MCP_FILENAME} missing 'mcpServers' key") + errors.append(f"{plugin_dir}: {MCP_FILENAME} missing 'mcpServers' key") elif not isinstance(data['mcpServers'], dict): - errors.append(f"{pack_dir}: {MCP_FILENAME} 'mcpServers' must be an object") + errors.append(f"{plugin_dir}: {MCP_FILENAME} 'mcpServers' must be an object") except json.JSONDecodeError as e: - errors.append(f"{pack_dir}: Invalid JSON in {MCP_FILENAME}: {e}") + errors.append(f"{plugin_dir}: Invalid JSON in {MCP_FILENAME}: {e}") except Exception as e: - errors.append(f"{pack_dir}: Error reading {MCP_FILENAME}: {e}") + errors.append(f"{plugin_dir}: Error reading {MCP_FILENAME}: {e}") return errors @@ -118,31 +118,31 @@ def validate_mcp_json(pack_dir: str) -> List[str]: ] -def validate_agents_md(pack_dir: str) -> List[str]: +def validate_agents_md(plugin_dir: str) -> List[str]: """ Validate AGENTS.md presence and structure. - Required for any pack that has skills. Checks for required sections + Required for any plugin that has skills. Checks for required sections and verifies that all skills appear in the intent routing content. - Errors if deprecated pack-level CLAUDE.md exists (Lola manages AGENTS.md). + Errors if deprecated plugin-level CLAUDE.md exists (Lola manages AGENTS.md). Args: - pack_dir: Pack directory name + plugin_dir: Plugin directory name Returns: List of error messages (empty if valid) """ errors = [] - pack_path = Path(pack_dir) - deprecated_path = pack_path / AGENTS_MD_DEPRECATED - agents_path = pack_path / AGENTS_MD_FILENAME - skills_dir = pack_path / 'skills' + plugin_path = Path(plugin_dir) + deprecated_path = plugin_path / AGENTS_MD_DEPRECATED + agents_path = plugin_path / AGENTS_MD_FILENAME + skills_dir = plugin_path / 'skills' has_skills = skills_dir.exists() and any(skills_dir.glob('*/SKILL.md')) if deprecated_path.exists(): errors.append( - f"{pack_dir}: deprecated pack-level {AGENTS_MD_DEPRECATED} found; " + f"{plugin_dir}: deprecated plugin-level {AGENTS_MD_DEPRECATED} found; " f"rename to {AGENTS_MD_FILENAME} (Lola AI Context Module convention)" ) return errors @@ -150,7 +150,7 @@ def validate_agents_md(pack_dir: str) -> List[str]: if not agents_path.exists(): if has_skills: errors.append( - f"{pack_dir}: Missing {AGENTS_MD_FILENAME} (required for packs with skills)" + f"{plugin_dir}: Missing {AGENTS_MD_FILENAME} (required for plugins with skills)" ) return errors @@ -163,7 +163,7 @@ def validate_agents_md(pack_dir: str) -> List[str]: for section in AGENTS_MD_REQUIRED_SECTIONS: if not any(section in h for h in headings): errors.append( - f"{pack_dir}: {AGENTS_MD_FILENAME} missing required section '## {section}'" + f"{plugin_dir}: {AGENTS_MD_FILENAME} missing required section '## {section}'" ) # Check intent routing completeness @@ -172,40 +172,40 @@ def validate_agents_md(pack_dir: str) -> List[str]: for skill_name in skill_names: if skill_name not in content: errors.append( - f"{pack_dir}: {AGENTS_MD_FILENAME} intent routing missing skill '{skill_name}'" + f"{plugin_dir}: {AGENTS_MD_FILENAME} intent routing missing skill '{skill_name}'" ) except Exception as e: - errors.append(f"{pack_dir}: Error reading {AGENTS_MD_FILENAME}: {e}") + errors.append(f"{plugin_dir}: Error reading {AGENTS_MD_FILENAME}: {e}") return errors -def validate_pack(pack_dir: str) -> List[str]: +def validate_plugin(plugin_dir: str) -> List[str]: """ - Validate a single pack. + Validate a single plugin. Args: - pack_dir: Pack directory name + plugin_dir: Plugin directory name Returns: List of error messages (empty if valid) """ errors = [] - # Check if pack directory exists - if not Path(pack_dir).exists(): - errors.append(f"{pack_dir}: Pack directory does not exist") + # Check if plugin directory exists + if not Path(plugin_dir).exists(): + errors.append(f"{plugin_dir}: Plugin directory does not exist") return errors # Validate plugin.json - errors.extend(validate_plugin_json(pack_dir)) + errors.extend(validate_plugin_json(plugin_dir)) # Validate mcps.json - errors.extend(validate_mcp_json(pack_dir)) + errors.extend(validate_mcp_json(plugin_dir)) # Validate AGENTS.md - errors.extend(validate_agents_md(pack_dir)) + errors.extend(validate_agents_md(plugin_dir)) return errors @@ -219,9 +219,9 @@ def main(): all_errors = [] - for pack_dir in PACK_DIRS: - print(f"Validating {pack_dir}...", end=' ') - errors = validate_pack(pack_dir) + for plugin_dir in PLUGIN_DIRS: + print(f"Validating {plugin_dir}...", end=' ') + errors = validate_plugin(plugin_dir) if errors: print("❌") diff --git a/system.yaml b/system.yaml index bc153cb7..3e3b81da 100644 --- a/system.yaml +++ b/system.yaml @@ -4,7 +4,7 @@ metadata: name: agentic-plugins title: Agentic Plugins description: > - Agentic skill packs and MCP server configurations for Red Hat platforms. + Agent plugins and MCP server configurations for Red Hat platforms. Provides AI-powered automation across OpenShift, Ansible, Virtualization, AI/ML, and SRE workflows through persona-specific skill modules. tags: From 9f8df2d5fb9980427a3a7c47cef94090f26117ac Mon Sep 17 00:00:00 2001 From: r2dedios Date: Fri, 9 Oct 2026 14:24:02 +0200 Subject: [PATCH 2/4] fix: deduplicate 'plugin plugin' artifact left by the pack-rename find/replace --- .../compass-manifest-maintenance/references/mcp-mapping.md | 2 +- .../references/relationship-rules.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.claude/skills/compass-manifest-maintenance/references/mcp-mapping.md b/.claude/skills/compass-manifest-maintenance/references/mcp-mapping.md index 9b7f87cd..e73bbe7c 100644 --- a/.claude/skills/compass-manifest-maintenance/references/mcp-mapping.md +++ b/.claude/skills/compass-manifest-maintenance/references/mcp-mapping.md @@ -48,7 +48,7 @@ For each `mcpserver:` added to the skill’s `dependsOn`: ## Step 5 — Plugin MCP union -The plugin plugin’s `dependsOn` MCP list = **union** of all `mcpserver:` refs across skill manifests in that plugin — not the full set of keys in `mcps.json`. +The plugin’s `dependsOn` MCP list = **union** of all `mcpserver:` refs across skill manifests in that plugin — not the full set of keys in `mcps.json`. ## Sanity checks diff --git a/.claude/skills/compass-manifest-maintenance/references/relationship-rules.md b/.claude/skills/compass-manifest-maintenance/references/relationship-rules.md index 82ca5cef..87cdcf94 100644 --- a/.claude/skills/compass-manifest-maintenance/references/relationship-rules.md +++ b/.claude/skills/compass-manifest-maintenance/references/relationship-rules.md @@ -24,7 +24,7 @@ Compass does **not** auto-generate inverse relations for custom kinds (`AiResour | Entity | Ref format | |--------|------------| | Skill | `airesource:ai5-marketplace/` | -| Plugin plugin | `airesource:ai5-marketplace/` | +| Plugin | `airesource:ai5-marketplace/` | | Owned MCP | `mcpserver:ai5-marketplace/` | | Canonical MCP | `mcpserver:redhat/` | | System | `default/agentic-plugins` (in `spec.system` only) | From 71c11e3c006a40a80f1974c2f0da49b43260ad39 Mon Sep 17 00:00:00 2001 From: r2dedios Date: Fri, 9 Oct 2026 16:25:24 +0200 Subject: [PATCH 3/4] fix: "Download Agent Plugins" heading, not "Skill Plugins" (consistency with gitlab rename) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 28887e51..8a0aaa65 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ See each plugin's README for available skills and usage examples. The `eval/` directory contains skill evaluation reports (`report.json` + `report.md` per skill) generated by an external evaluation pipeline. -### Download Skill Plugins +### Download Agent Plugins Pre-packaged ZIP files are available on the [Releases page](https://github.com/RHEcosystemAppEng/agentic-plugins/releases). The `latest` release is auto-updated on every merge to main. Each ZIP contains all skills for a plugin with documentation included. From fb34c27afa7f3188d3cfb6967c404b6de965a3f3 Mon Sep 17 00:00:00 2001 From: r2dedios Date: Fri, 9 Oct 2026 16:33:24 +0200 Subject: [PATCH 4/4] fix: rename pack-location.yaml -> plugin-location.yaml (link was renamed but file wasn't) --- .../assets/{pack-location.yaml => plugin-location.yaml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .claude/skills/compass-manifest-maintenance/assets/{pack-location.yaml => plugin-location.yaml} (100%) diff --git a/.claude/skills/compass-manifest-maintenance/assets/pack-location.yaml b/.claude/skills/compass-manifest-maintenance/assets/plugin-location.yaml similarity index 100% rename from .claude/skills/compass-manifest-maintenance/assets/pack-location.yaml rename to .claude/skills/compass-manifest-maintenance/assets/plugin-location.yaml