From c625f31177da917b377d98955e84c01a39a2cbfe Mon Sep 17 00:00:00 2001 From: rhartuv Date: Thu, 20 Aug 2026 10:29:46 +0300 Subject: [PATCH 01/10] feat: add skill to author and maintain Compass manifests for agentic packs --- .../agentic-contribution-skill/SKILL.md | 5 +- .../compass-manifest-maintenance/SKILL.md | 156 ++++++++++++++++++ .../assets/pack-location.yaml | 20 +++ .../assets/plugin-catalog-info.yaml | 42 +++++ .../assets/skill-catalog-info.yaml | 36 ++++ .../references/mcp-mapping.md | 50 ++++++ .../references/relationship-rules.md | 63 +++++++ CLAUDE.md | 7 +- 8 files changed, 373 insertions(+), 6 deletions(-) create mode 100644 .claude/skills/compass-manifest-maintenance/SKILL.md create mode 100644 .claude/skills/compass-manifest-maintenance/assets/pack-location.yaml create mode 100644 .claude/skills/compass-manifest-maintenance/assets/plugin-catalog-info.yaml create mode 100644 .claude/skills/compass-manifest-maintenance/assets/skill-catalog-info.yaml create mode 100644 .claude/skills/compass-manifest-maintenance/references/mcp-mapping.md create mode 100644 .claude/skills/compass-manifest-maintenance/references/relationship-rules.md diff --git a/.claude/skills/agentic-contribution-skill/SKILL.md b/.claude/skills/agentic-contribution-skill/SKILL.md index 1121a379..2de61c38 100644 --- a/.claude/skills/agentic-contribution-skill/SKILL.md +++ b/.claude/skills/agentic-contribution-skill/SKILL.md @@ -244,8 +244,9 @@ mkdir -p /skills//docs/ - `docs/external-resources.md` - Any external docs/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. **Update marketplace/rh-agentic-collection.yml** in [agentic-catalog](https://github.com/RHEcosystemAppEng/agentic-catalog): If new pack (register pack for Lola installation) -6. **Create pack structure**: If new pack (README.md, AGENTS.md, skills/ directory) +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) 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 `docs/` with references in main file. diff --git a/.claude/skills/compass-manifest-maintenance/SKILL.md b/.claude/skills/compass-manifest-maintenance/SKILL.md new file mode 100644 index 00000000..9e0777b9 --- /dev/null +++ b/.claude/skills/compass-manifest-maintenance/SKILL.md @@ -0,0 +1,156 @@ +--- +name: compass-manifest-maintenance +description: | + Author and maintain Compass catalog-info.yaml manifests for agentic packs (skills, plugins, Locations, MCP inverse relations). Use when: + - Adding or updating a skill and its Compass manifest + - Adding a new pack to Compass registration + - MCP usage or orchestration changed in SKILL.md + - Auditing bidirectional dependsOn/dependencyOf drift after PR #133 model + + File-based only: Read/Glob/Grep/Bash. For `.catalog/` marketplace metadata use create-collection. +model: inherit +color: magenta +license: Apache-2.0 +allowed-tools: Read Glob Grep Bash +--- + +# Compass manifest maintenance + +**Audience:** Maintainers updating `catalog-info.yaml` manifests for Red Hat Compass (Backstage) registration. + +**Goal:** Keep Compass manifests aligned with golden sources (`SKILL.md`, `mcps.json`, `AGENTS.md`) + +## Prerequisites + +- Repository root as cwd. +- Read [CLAUDE.md](../../CLAUDE.md) Compass / Backstage Manifests section. +- Read [references/relationship-rules.md](references/relationship-rules.md) and [references/mcp-mapping.md](references/mcp-mapping.md). +- Templates: [assets/](assets/). + +**Do not use** Compass MCP tools (`validate-entity`, `register-entity`, `get-catalog-entity`, `query-entity-graph`). Validation is structural (roster + inverse ref checks) and optional human Compass UI review after merge. + +## When to Use + +- New skill needs `skills//catalog-info.yaml` and Location / inverse updates. +- Skill `allowed-tools` or orchestration changed → MCP or skill `dependsOn` must change. +- New pack registered in Compass (plugin, Location, root index, `system.yaml`). +- Drift audit: skill on disk without manifest, stale `dependencyOf`, or dangling entity refs. +- After `agentic-contribution-skill` creates a skill (run before opening PR). + +**Do not use for:** `.catalog/collection.yaml` (use **create-collection**), generic Compass platform tasks, or automated Compass registration. + +## Workflow + +### 1. Add or update a skill manifest + +1. **Resolve** `` and `` — confirm `/skills//SKILL.md` exists. + +2. **Read golden sources** (precedence): + - `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) + +3. **Derive `dependsOn`** for the skill manifest: + - 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. **Write** `/skills//catalog-info.yaml` from [assets/skill-catalog-info.yaml](assets/skill-catalog-info.yaml): + - `namespace: ai5-marketplace` + - `labels.distribution: external` + - `agents: []` + - `lifecycle: beta` + - `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) + +5. **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/` + - Each `mcpserver:` in skill `dependsOn` → matching `mcps/*.yaml` `dependencyOf` + - Each skill in skill `dependsOn` → that skill's `dependencyOf` includes orchestrator + +6. **Reconcile plugin MCP deps** — plugin `dependsOn` = union of all `mcpserver:` refs across pack skill manifests. + +### 2. Add a new pack (Compass registration) + +1. Create `/-plugin.yaml` from [assets/plugin-catalog-info.yaml](assets/plugin-catalog-info.yaml). +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. + +### 3. Drift / compliance audit + +Run checks with `Glob`/`Grep`/`Bash`: + +| Check | Rule | +|-------|------| +| Roster parity | Every `skills/*/SKILL.md` has `catalog-info.yaml` and pack 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 | +| Dangling refs | Every ref resolves to on-disk manifest or documented canonical MCP | +| Forbidden | No `partOf`/`hasPart` on AiResource/MCPServer; no redundant `dependsOn: system:default/agentic-plugins` on plugins | +| Namespace | Refs use `ai5-marketplace` except `mcpserver:redhat/*` and `default/agentic-plugins` | + +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. +2. Re-run drift audit (§3). +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). + +## Self-review checklist + +- [ ] Skill manifest matches PR #133 field conventions (`agents: []`, `distribution: external`, `namespace: 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. +- [ ] No `partOf`/`hasPart` on custom kinds. + +## Dependencies + +- [CLAUDE.md](../../CLAUDE.md) — entity kinds, namespaces, reference formats +- **create-collection** — `.catalog/` marketplace metadata (sibling under `.claude/skills/`) +- [references/relationship-rules.md](references/relationship-rules.md) +- [references/mcp-mapping.md](references/mcp-mapping.md) + +## Common Issues + +- **COMPASS-1288 drift** — updated skill `dependsOn` but forgot plugin or MCP `dependencyOf`. +- **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. + +## Example usage + +```bash +# Roster: skills on disk missing from Location (example: rh-sre) +comm -23 \ + <(find rh-sre/skills -name SKILL.md | sed 's|.*/skills/||;s|/SKILL.md||' | sort) \ + <(grep -oP 'skills/\K[^/]+(?=/catalog-info)' rh-sre/catalog-info.yaml | sort) + +# Tier 1 lint for this maintenance skill +uv run python scripts/validate_skills_tier1.py .claude/skills/compass-manifest-maintenance/SKILL.md + +# Full repo validation (no Compass CI yet) +make validate +``` + +Audit all four registered packs: + +```bash +for pack in ocp-admin rh-sre rh-virt rh-basic; do + echo "=== $pack ===" + 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) +done +``` diff --git a/.claude/skills/compass-manifest-maintenance/assets/pack-location.yaml b/.claude/skills/compass-manifest-maintenance/assets/pack-location.yaml new file mode 100644 index 00000000..62891971 --- /dev/null +++ b/.claude/skills/compass-manifest-maintenance/assets/pack-location.yaml @@ -0,0 +1,20 @@ +# Template: /catalog-info.yaml (Location) +apiVersion: backstage.io/v1alpha1 +kind: Location +metadata: + name: + title: Agentic Pack + description: > + Points to all AI skill catalog entities in the agentic pack. + 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/repository: https://github.com/RHEcosystemAppEng/agentic-plugins + agentic.redhat.com/path: +spec: + targets: + - ./-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 new file mode 100644 index 00000000..6ad07267 --- /dev/null +++ b/.claude/skills/compass-manifest-maintenance/assets/plugin-catalog-info.yaml @@ -0,0 +1,42 @@ +# Template: /-plugin.yaml +# Replace , title, description, tags, disciplines, categories, dependencyOf, dependsOn (MCP union). +apiVersion: backstage.io/v1alpha1 +kind: AiResource +metadata: + name: + namespace: ai5-marketplace + 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/repository: https://github.com/RHEcosystemAppEng/agentic-plugins + agentic.redhat.com/path: + github.com/project-slug: RHEcosystemAppEng/agentic-plugins + links: + - url: https://github.com/RHEcosystemAppEng/agentic-plugins + title: Source Repository + icon: github +spec: + type: plugin + lifecycle: development + owner: group:redhat/ai5-marketplace + system: default/agentic-plugins + disciplines: + - + categories: + - + agents: [] + dependsOn: + # Union of mcpserver refs used by any skill in this pack (omit if none) + # - mcpserver:ai5-marketplace/ + # - mcpserver:redhat/ + dependencyOf: + - airesource:ai5-marketplace/ + # Every skill in the pack — 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 new file mode 100644 index 00000000..29852449 --- /dev/null +++ b/.claude/skills/compass-manifest-maintenance/assets/skill-catalog-info.yaml @@ -0,0 +1,36 @@ +# Template: skills//catalog-info.yaml +# Replace , , title, description, tags, disciplines, categories, dependsOn. +apiVersion: backstage.io/v1alpha1 +kind: AiResource +metadata: + name: + namespace: ai5-marketplace + title: + description: > + + labels: + distribution: external + annotations: + backstage.io/source-location: >- + url:https://github.com/RHEcosystemAppEng/agentic-plugins/blob/main//skills//SKILL.md + tags: + - ai-skill + - + links: + - url: https://github.com/RHEcosystemAppEng/agentic-plugins + title: Source Repository + icon: github +spec: + type: skill + lifecycle: beta + owner: group:redhat/ai5-marketplace + disciplines: + - + categories: + - + agents: [] + dependsOn: + - 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 new file mode 100644 index 00000000..9265ebc3 --- /dev/null +++ b/.claude/skills/compass-manifest-maintenance/references/mcp-mapping.md @@ -0,0 +1,50 @@ +# MCP mapping: mcps.json → Compass entity refs + +Map **only** MCP servers a skill actually uses. Derive usage from `SKILL.md` `allowed-tools`, `Required MCP Servers`, and workflow MCP tool names — not from copying another skill's manifest. + +## Owned MCP servers (registered in `mcps/`) + +| `mcps.json` key | Tool / signal hints | Compass entity ref | +|-----------------|---------------------|-------------------| +| `openshift-self-managed` | Assisted Installer self-managed API | `mcpserver:ai5-marketplace/assisted-installer` | +| `openshift-ocm-managed` | OCM / ROSA / managed clusters | `mcpserver:ai5-marketplace/assisted-installer` | +| `openshift-administration` | Kubernetes/OpenShift cluster ops (`configuration_*`, `nodes_*`, etc.) | `mcpserver:ai5-marketplace/openshift-mcp-server` | +| `openshift-virtualization` | KubeVirt VM tools | `mcpserver:ai5-marketplace/openshift-mcp-server` | +| `openshift` | Generic OpenShift MCP (other packs) | `mcpserver:ai5-marketplace/openshift-mcp-server` | +| `aap-mcp-job-management` | `controller.*`, `eda.*`, job/workflow tools | `mcpserver:ai5-marketplace/ansible-automation-platform` | +| `aap-mcp-inventory-management` | `controller.inventories_*`, `controller.hosts_*`, `controller.groups_*` | `mcpserver:ai5-marketplace/ansible-automation-platform` | + +## Canonical MCP servers (not duplicated in `mcps/`) + +| `mcps.json` key | Tool / signal hints | Compass entity ref | +|-----------------|---------------------|-------------------| +| `lightspeed-mcp` | `vulnerability__*`, `inventory__*`, `get_mcp_version` (Lightspeed) | `mcpserver:redhat/red-hat-lightspeed-mcp-server` | +| `red-hat-security` | Red Hat Security MCP / CVE advisory tools | `mcpserver:redhat/security-mcp-server` | + +## AAP tool prefix quick reference + +If `allowed-tools` includes any of these prefixes, the skill uses **ansible-automation-platform**: + +- `controller.` +- `gateway.` +- `eda.` +- `galaxy.` +- `lightspeed.aap_rag_search` + +## No MCP manifest entry + +Skills that use only scripts, `WebFetch`, or public APIs (no MCP tools in `allowed-tools` and no `Required MCP Servers`) should have **no** `mcpserver:` in `dependsOn`. Examples: ocp-admin security-validation skills (`container-cve-validator`, `coreos-cve-validator`, `cve-recon`, `image-inspect`). + +## Plugin `dependsOn` MCP list + +The pack plugin's `dependsOn` MCP entries = **union** of all `mcpserver:` refs across every skill manifest in that pack (not every key in `mcps.json`). + +## Owned MCP manifest files + +| Compass name | File | +|--------------|------| +| `openshift-mcp-server` | `mcps/openshift-mcp-server.yaml` | +| `assisted-installer` | `mcps/assisted-installer.yaml` | +| `ansible-automation-platform` | `mcps/ansible-automation-platform.yaml` | + +When a skill adds or removes an MCP `dependsOn`, update the corresponding MCP file's `dependencyOf` list. diff --git a/.claude/skills/compass-manifest-maintenance/references/relationship-rules.md b/.claude/skills/compass-manifest-maintenance/references/relationship-rules.md new file mode 100644 index 00000000..573fa288 --- /dev/null +++ b/.claude/skills/compass-manifest-maintenance/references/relationship-rules.md @@ -0,0 +1,63 @@ +# Compass relationship rules (agentic-plugins) + +## COMPASS-1288 bidirectional policy + +Compass does **not** auto-generate inverse relations for custom kinds (`AiResource`, `MCPServer`). Every relationship must be declared on **both sides**: + +| Origin | Field | Target | Inverse on target | +|--------|-------|--------|-------------------| +| Skill | `dependsOn` | Plugin | Plugin `dependencyOf` skill | +| Skill | `dependsOn` | MCP | MCP `dependencyOf` skill | +| Skill | `dependsOn` | Other skill | Other skill `dependencyOf` orchestrator | +| Plugin | `dependsOn` | MCP | MCP `dependencyOf` plugin | +| MCP | `dependsOn` | System | System `dependencyOf` MCP | + +**Exception:** Plugin and owned MCP → System use `spec.system: default/agentic-plugins`. Compass generates `partOf` automatically. Do **not** add `dependsOn: system:default/agentic-plugins` on plugins (redundant). + +## What does NOT work for custom kinds + +- `partOf` / `hasPart` on `AiResource` or `MCPServer` — stored in spec but **not** in the relation graph (validated Aug 2026). +- Use `dependsOn` / `dependencyOf` for all membership and technical dependencies. + +## Entity reference formats + +| Entity | Ref format | +|--------|------------| +| Skill | `airesource:ai5-marketplace/` | +| Pack plugin | `airesource:ai5-marketplace/` | +| Owned MCP | `mcpserver:ai5-marketplace/` | +| Canonical MCP | `mcpserver:redhat/` | +| System | `default/agentic-plugins` (in `spec.system` only) | + +All skills, plugins, and owned MCPs use `metadata.namespace: ai5-marketplace`. + +## 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 +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 + +## Files to touch when adding a pack + +1. `/-plugin.yaml` +2. `/catalog-info.yaml` +3. Root `catalog-info.yaml` — add pack 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) + +## Orchestration skill detection + +Add skill→skill `dependsOn` when `SKILL.md` documents: + +- `Execute the `/other-skill` skill` +- Skill tool invocation of another skill in workflow +- Explicit prerequisite validator skills (`/mcp-lightspeed-validator`, etc.) + +Do **not** infer orchestration from `AGENTS.md` routing alone. + +## Registered packs (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`. diff --git a/CLAUDE.md b/CLAUDE.md index 6790a9a9..79f3f679 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -304,10 +304,9 @@ last_updated: YYYY-MM-DD - 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. Create `skills//catalog-info.yaml` Compass manifest (see "Adding Compass Manifests for a New Skill") -7. Add the skill's `catalog-info.yaml` as a target in the pack's `catalog-info.yaml` Location -8. Test with `Skill` tool invocation -9. Validate with `uv run python scripts/validate_skills_tier1.py /skills//SKILL.md` +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") +7. Test with `Skill` tool invocation +8. 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 From 89794ec6348c0b0a3f54abed6bd543377be79482 Mon Sep 17 00:00:00 2001 From: rhartuv Date: Thu, 20 Aug 2026 14:37:00 +0300 Subject: [PATCH 02/10] fix: removed the static mcp mapping tables --- .../references/mcp-mapping.md | 77 ++++++++++--------- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/.claude/skills/compass-manifest-maintenance/references/mcp-mapping.md b/.claude/skills/compass-manifest-maintenance/references/mcp-mapping.md index 9265ebc3..1f398ec7 100644 --- a/.claude/skills/compass-manifest-maintenance/references/mcp-mapping.md +++ b/.claude/skills/compass-manifest-maintenance/references/mcp-mapping.md @@ -1,50 +1,57 @@ -# MCP mapping: mcps.json → Compass entity refs +# Deriving MCP `dependsOn` for skill manifests -Map **only** MCP servers a skill actually uses. Derive usage from `SKILL.md` `allowed-tools`, `Required MCP Servers`, and workflow MCP tool names — not from copying another skill's manifest. +Map **only** MCP servers the skill **actually uses**. Never copy a sibling manifest and never declare every key in `/mcps.json`. -## Owned MCP servers (registered in `mcps/`) +## Step 1 — Detect MCP usage in the skill -| `mcps.json` key | Tool / signal hints | Compass entity ref | -|-----------------|---------------------|-------------------| -| `openshift-self-managed` | Assisted Installer self-managed API | `mcpserver:ai5-marketplace/assisted-installer` | -| `openshift-ocm-managed` | OCM / ROSA / managed clusters | `mcpserver:ai5-marketplace/assisted-installer` | -| `openshift-administration` | Kubernetes/OpenShift cluster ops (`configuration_*`, `nodes_*`, etc.) | `mcpserver:ai5-marketplace/openshift-mcp-server` | -| `openshift-virtualization` | KubeVirt VM tools | `mcpserver:ai5-marketplace/openshift-mcp-server` | -| `openshift` | Generic OpenShift MCP (other packs) | `mcpserver:ai5-marketplace/openshift-mcp-server` | -| `aap-mcp-job-management` | `controller.*`, `eda.*`, job/workflow tools | `mcpserver:ai5-marketplace/ansible-automation-platform` | -| `aap-mcp-inventory-management` | `controller.inventories_*`, `controller.hosts_*`, `controller.groups_*` | `mcpserver:ai5-marketplace/ansible-automation-platform` | +From `/skills//SKILL.md`: -## Canonical MCP servers (not duplicated in `mcps/`) +- `allowed-tools` in frontmatter (tool names / prefixes) +- `Required MCP Servers` / `Required MCP Tools` in the body +- Workflow steps that name an MCP server key or tool -| `mcps.json` key | Tool / signal hints | Compass entity ref | -|-----------------|---------------------|-------------------| -| `lightspeed-mcp` | `vulnerability__*`, `inventory__*`, `get_mcp_version` (Lightspeed) | `mcpserver:redhat/red-hat-lightspeed-mcp-server` | -| `red-hat-security` | Red Hat Security MCP / CVE advisory tools | `mcpserver:redhat/security-mcp-server` | +If none of the above reference MCP tools → **no** `mcpserver:` in `dependsOn` (script-only, `WebFetch`, or public API skills). -## AAP tool prefix quick reference +## Step 2 — Match usage to `mcps.json` keys -If `allowed-tools` includes any of these prefixes, the skill uses **ansible-automation-platform**: +Read `/mcps.json`. Note which **server keys** the skill documents (e.g. `openshift-administration`, `lightspeed-mcp`, `aap-mcp-job-management`). -- `controller.` -- `gateway.` -- `eda.` -- `galaxy.` -- `lightspeed.aap_rag_search` +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). -## No MCP manifest entry +## Step 3 — Resolve each key to a Compass entity ref -Skills that use only scripts, `WebFetch`, or public APIs (no MCP tools in `allowed-tools` and no `Required MCP Servers`) should have **no** `mcpserver:` in `dependsOn`. Examples: ocp-admin security-validation skills (`container-cve-validator`, `coreos-cve-validator`, `cve-recon`, `image-inspect`). +For each MCP the skill uses: -## Plugin `dependsOn` MCP list +### A. Owned MCP (manifest in this repo) -The pack plugin's `dependsOn` MCP entries = **union** of all `mcpserver:` refs across every skill manifest in that pack (not every key in `mcps.json`). +1. List `mcps/*.yaml` (exclude `catalog-info.yaml`). +2. Open manifests and read `metadata.name` and `metadata.namespace` (typically `ai5-marketplace`). +3. Entity ref: `mcpserver:/`. +4. **Deduplication:** Several `mcps.json` keys may share one Compass entity (same image/technology). Compare `mcps.json` entries (image URL, upstream repo in manifest `links`) to pick the correct owned manifest — do not create one ref per key if they map to the same `mcps/*.yaml`. +5. Confirm the skill’s tools appear in that manifest’s `spec.primitives` (or match the server described in SKILL.md) when ambiguous. -## Owned MCP manifest files +### B. Canonical MCP (registered upstream, not in `mcps/`) -| Compass name | File | -|--------------|------| -| `openshift-mcp-server` | `mcps/openshift-mcp-server.yaml` | -| `assisted-installer` | `mcps/assisted-installer.yaml` | -| `ansible-automation-platform` | `mcps/ansible-automation-platform.yaml` | +If the pack references an MCP that **no** file under `mcps/` covers: -When a skill adds or removes an MCP `dependsOn`, update the corresponding MCP file's `dependencyOf` list. +1. Search existing skill manifests in the same pack (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. + +## Step 4 — Update inverse relations + +For each `mcpserver:` added to the skill’s `dependsOn`: + +- Add `airesource:ai5-marketplace/` to that MCP manifest’s `spec.dependencyOf` (owned MCPs only — canonical MCPs are maintained by their owners). + +## 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`. + +## Sanity checks + +- Fewer MCP refs than keys in `mcps.json` is normal (per-skill usage). +- More MCP refs than the skill uses is wrong (blanket template deps). +- Canonical refs (`mcpserver:redhat/...`) do not get new files under `mcps/`. From 9a809a788e2451a3c70bdc6a4a187eb90216989d Mon Sep 17 00:00:00 2001 From: rhartuv Date: Thu, 20 Aug 2026 14:51:43 +0300 Subject: [PATCH 03/10] fix: remove pr references --- .claude/skills/compass-manifest-maintenance/SKILL.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.claude/skills/compass-manifest-maintenance/SKILL.md b/.claude/skills/compass-manifest-maintenance/SKILL.md index 9e0777b9..7c0a71ad 100644 --- a/.claude/skills/compass-manifest-maintenance/SKILL.md +++ b/.claude/skills/compass-manifest-maintenance/SKILL.md @@ -5,7 +5,7 @@ description: | - Adding or updating a skill and its Compass manifest - Adding a new pack to Compass registration - MCP usage or orchestration changed in SKILL.md - - Auditing bidirectional dependsOn/dependencyOf drift after PR #133 model + - Auditing bidirectional dependsOn/dependencyOf drift against repo Compass conventions File-based only: Read/Glob/Grep/Bash. For `.catalog/` marketplace metadata use create-collection. model: inherit @@ -107,7 +107,7 @@ Report violations with file path and fix per workflow §1. Do not weaken checks. ## Self-review checklist -- [ ] Skill manifest matches PR #133 field conventions (`agents: []`, `distribution: external`, `namespace: ai5-marketplace`). +- [ ] Skill manifest matches repo Compass 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. From a3fe4b110cba1b22f601d5131e3c593db70a238b Mon Sep 17 00:00:00 2001 From: rhartuv Date: Thu, 20 Aug 2026 15:13:38 +0300 Subject: [PATCH 04/10] fix: add missing Compass manifest for ocp-admin/network-policy-architect skill --- mcps/openshift-mcp-server.yaml | 1 + ocp-admin/catalog-info.yaml | 1 + ocp-admin/ocp-admin-plugin.yaml | 1 + .../catalog-info.yaml | 39 +++++++++++++++++++ 4 files changed, 42 insertions(+) create mode 100644 ocp-admin/skills/network-policy-architect/catalog-info.yaml diff --git a/mcps/openshift-mcp-server.yaml b/mcps/openshift-mcp-server.yaml index efd680da..a0b57ed8 100644 --- a/mcps/openshift-mcp-server.yaml +++ b/mcps/openshift-mcp-server.yaml @@ -102,6 +102,7 @@ spec: - system:default/agentic-plugins dependencyOf: - airesource:ai5-marketplace/cluster-report + - airesource:ai5-marketplace/network-policy-architect - airesource:ai5-marketplace/ocp-admin - airesource:ai5-marketplace/rh-virt - airesource:ai5-marketplace/vm-clone diff --git a/ocp-admin/catalog-info.yaml b/ocp-admin/catalog-info.yaml index adad806c..a59f882f 100644 --- a/ocp-admin/catalog-info.yaml +++ b/ocp-admin/catalog-info.yaml @@ -23,3 +23,4 @@ spec: - ./skills/coreos-cve-validator/catalog-info.yaml - ./skills/cve-recon/catalog-info.yaml - ./skills/image-inspect/catalog-info.yaml + - ./skills/network-policy-architect/catalog-info.yaml diff --git a/ocp-admin/ocp-admin-plugin.yaml b/ocp-admin/ocp-admin-plugin.yaml index ec128434..7d824969 100644 --- a/ocp-admin/ocp-admin-plugin.yaml +++ b/ocp-admin/ocp-admin-plugin.yaml @@ -47,3 +47,4 @@ spec: - airesource:ai5-marketplace/coreos-cve-validator - airesource:ai5-marketplace/cve-recon - airesource:ai5-marketplace/image-inspect + - airesource:ai5-marketplace/network-policy-architect diff --git a/ocp-admin/skills/network-policy-architect/catalog-info.yaml b/ocp-admin/skills/network-policy-architect/catalog-info.yaml new file mode 100644 index 00000000..d03aae3d --- /dev/null +++ b/ocp-admin/skills/network-policy-architect/catalog-info.yaml @@ -0,0 +1,39 @@ +apiVersion: backstage.io/v1alpha1 +kind: AiResource +metadata: + name: network-policy-architect + namespace: ai5-marketplace + title: Network Policy Architect + description: > + Design and validate Kubernetes NetworkPolicies following Zero Trust principles + (NIST SP 800-207). Two-tier analysis — architecture review then live cluster + verification — produces a verified implementation plan with apply-and-verify results. + labels: + distribution: external + annotations: + backstage.io/source-location: >- + url:https://github.com/RHEcosystemAppEng/agentic-plugins/blob/main/ocp-admin/skills/network-policy-architect/SKILL.md + tags: + - ai-skill + - openshift + - security + - network-policy + - zero-trust + links: + - url: https://github.com/RHEcosystemAppEng/agentic-plugins + title: Source Repository + icon: github +spec: + type: skill + lifecycle: beta + owner: group:redhat/ai5-marketplace + disciplines: + - security + - platform-engineering + categories: + - security + - network-segmentation + agents: [] + dependsOn: + - airesource:ai5-marketplace/ocp-admin + - mcpserver:ai5-marketplace/openshift-mcp-server From 445a70e886dfbad7b4250670d8d9d982179ae518 Mon Sep 17 00:00:00 2001 From: rhartuv Date: Sun, 23 Aug 2026 12:10:11 +0300 Subject: [PATCH 05/10] fix: fix validate skills tier2 --- .../compass-manifest-maintenance/SKILL.md | 45 ++++++++++++++++--- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/.claude/skills/compass-manifest-maintenance/SKILL.md b/.claude/skills/compass-manifest-maintenance/SKILL.md index 7c0a71ad..adeb3334 100644 --- a/.claude/skills/compass-manifest-maintenance/SKILL.md +++ b/.claude/skills/compass-manifest-maintenance/SKILL.md @@ -8,13 +8,15 @@ description: | - Auditing bidirectional dependsOn/dependencyOf drift against repo Compass conventions File-based only: Read/Glob/Grep/Bash. For `.catalog/` marketplace metadata use create-collection. + + NOT for: `.catalog/` metadata (use create-collection) or automated Compass registration. model: inherit color: magenta license: Apache-2.0 allowed-tools: Read Glob Grep Bash --- -# Compass manifest maintenance +# /compass-manifest-maintenance Skill **Audience:** Maintainers updating `catalog-info.yaml` manifests for Red Hat Compass (Backstage) registration. @@ -22,25 +24,39 @@ allowed-tools: Read Glob Grep Bash ## Prerequisites +**Required MCP Servers:** None — file-based skill. Do not use Compass MCP tools (`validate-entity`, `register-entity`, `get-catalog-entity`, `query-entity-graph`). + - Repository root as cwd. - Read [CLAUDE.md](../../CLAUDE.md) Compass / Backstage Manifests section. - Read [references/relationship-rules.md](references/relationship-rules.md) and [references/mcp-mapping.md](references/mcp-mapping.md). - Templates: [assets/](assets/). -**Do not use** Compass MCP tools (`validate-entity`, `register-entity`, `get-catalog-entity`, `query-entity-graph`). Validation is structural (roster + inverse ref checks) and optional human Compass UI review after merge. +**Verification:** +```bash +test -f CLAUDE.md && echo "✓ repo root" || echo "✗ wrong directory" +``` + +**Human Notification Protocol:** If drift audit finds violations, report file path and fix per workflow §1. + +**Security:** Never display or expose credentials or token values. -## When to Use +## When to Use This Skill +**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. - New pack registered in Compass (plugin, Location, root index, `system.yaml`). - Drift audit: skill on disk without manifest, stale `dependencyOf`, or dangling entity refs. - After `agentic-contribution-skill` creates a skill (run before opening PR). -**Do not use for:** `.catalog/collection.yaml` (use **create-collection**), generic Compass platform tasks, or automated Compass registration. +**Do not use when:** `.catalog/collection.yaml` (use **create-collection** instead), generic Compass platform tasks, or automated Compass registration. ## Workflow +**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. + ### 1. Add or update a skill manifest 1. **Resolve** `` and `` — confirm `/skills//SKILL.md` exists. @@ -105,6 +121,11 @@ Report violations with file path and fix per workflow §1. Do not weaken checks. 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). +**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. + ## Self-review checklist - [ ] Skill manifest matches repo Compass conventions (`agents: []`, `labels.distribution: external`, `namespace: ai5-marketplace`, `owner: group:redhat/ai5-marketplace`). @@ -116,8 +137,22 @@ Report violations with file path and fix per workflow §1. Do not weaken checks. ## Dependencies +### Required MCP Servers + +None — file-based manifest maintenance only. + +### Required MCP Tools + +None — uses Read, Glob, Grep, Bash. + +### Related Skills + +- **create-collection** — for `.catalog/` marketplace metadata (not Compass manifests) +- **agentic-contribution-skill** — run before this skill when creating a new skill + +### Reference Documentation + - [CLAUDE.md](../../CLAUDE.md) — entity kinds, namespaces, reference formats -- **create-collection** — `.catalog/` marketplace metadata (sibling under `.claude/skills/`) - [references/relationship-rules.md](references/relationship-rules.md) - [references/mcp-mapping.md](references/mcp-mapping.md) From fabfd5bb4a88ecbf94eeefd4fdb5563d89e6b388 Mon Sep 17 00:00:00 2001 From: rhartuv Date: Tue, 1 Sep 2026 14:39:32 +0300 Subject: [PATCH 06/10] fix: amount of skills --- CLAUDE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 79f3f679..d0355afa 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -68,7 +68,7 @@ The repository is registered in [Red Hat Compass](https://compass.redhat.com) (i |------|---------|-----------|-------| | **Location** | Index that references other manifest files | — | 6 (1 root + 4 packs + 1 mcps) | | **System** | Top-level grouping for the repository | — | 1 (`agentic-plugins`) | -| **AiResource** | Skills and pack definitions | `plugin` (packs) / `skill` (skills) | 4 packs + 36 skills | +| **AiResource** | Skills and pack definitions | `plugin` (packs) / `skill` (skills) | 4 packs + 37 skills | | **MCPServer** | MCP server configurations | `local` / `remote` | 3 | #### Location Hierarchy @@ -78,7 +78,7 @@ Compass ingests a single root Location. Everything else is discovered through de ``` catalog-info.yaml (root Location) ├── system.yaml → System: agentic-plugins -├── ocp-admin/catalog-info.yaml → Location → ocp-admin-plugin.yaml + 7 skills +├── ocp-admin/catalog-info.yaml → Location → ocp-admin-plugin.yaml + 8 skills ├── rh-sre/catalog-info.yaml → Location → rh-sre-plugin.yaml + 13 skills ├── rh-virt/catalog-info.yaml → Location → rh-virt-plugin.yaml + 10 skills ├── rh-basic/catalog-info.yaml → Location → rh-basic-plugin.yaml + 6 skills From 62a2f6c900bd126f2f3f841e1a4188a89353f9e1 Mon Sep 17 00:00:00 2001 From: rhartuv Date: Wed, 2 Sep 2026 14:38:29 +0300 Subject: [PATCH 07/10] fix: review fixes --- .../skills/compass-manifest-maintenance/SKILL.md | 6 +++--- CLAUDE.md | 16 ++-------------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/.claude/skills/compass-manifest-maintenance/SKILL.md b/.claude/skills/compass-manifest-maintenance/SKILL.md index adeb3334..6273f139 100644 --- a/.claude/skills/compass-manifest-maintenance/SKILL.md +++ b/.claude/skills/compass-manifest-maintenance/SKILL.md @@ -3,7 +3,7 @@ name: compass-manifest-maintenance description: | Author and maintain Compass catalog-info.yaml manifests for agentic packs (skills, plugins, Locations, MCP inverse relations). Use when: - Adding or updating a skill and its Compass manifest - - Adding a new pack to Compass registration + - Registering an existing pack in Compass (manifests only; not creating a new agentic pack) - 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. -- New pack registered in Compass (plugin, Location, root index, `system.yaml`). +- Register an existing pack 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). @@ -90,7 +90,7 @@ test -f CLAUDE.md && echo "✓ repo root" || echo "✗ wrong directory" 6. **Reconcile plugin MCP deps** — plugin `dependsOn` = union of all `mcpserver:` refs across pack skill manifests. -### 2. Add a new pack (Compass registration) +### 2. Register a new pack in Compass 1. Create `/-plugin.yaml` from [assets/plugin-catalog-info.yaml](assets/plugin-catalog-info.yaml). 2. Create `/catalog-info.yaml` from [assets/pack-location.yaml](assets/pack-location.yaml). diff --git a/CLAUDE.md b/CLAUDE.md index d0355afa..62ba1fd6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -87,21 +87,9 @@ catalog-info.yaml (root Location) #### Entity Relationships -All relationships use `dependsOn` / `dependencyOf`: +Use `dependsOn` / `dependencyOf` for custom kinds (`AiResource`, `MCPServer`); do not use `partOf` / `hasPart` on those kinds. Compass does not auto-generate inverse relations (COMPASS-1288) — declare both sides on every edge. -> **Why not `partOf`/`hasPart`?** Compass only processes `partOf`/`hasPart` for standard Backstage kinds (Component, API, Resource). Custom kinds like `AiResource` and `MCPServer` can store these fields in `spec`, but they are not processed into the relation graph. Only `dependsOn`/`dependencyOf` and `ownedBy`/`ownerOf` generate actual relations for custom kinds. - -Concrete relationships in this repo: - -- **Skill → Plugin**: `dependsOn` / `dependencyOf` (a skill belongs to its plugin) -- **Plugin → System**: `spec.system` (generates `partOf` relation automatically; no explicit `dependsOn` to the system needed) -- **MCPServer → System**: `dependsOn` / `dependencyOf` (an MCP server belongs to the system) -- **Skill → MCPServer**: `dependsOn` / `dependencyOf` (a skill uses an MCP server) -- **Plugin → MCPServer**: `dependsOn` / `dependencyOf` (a plugin uses an MCP server) -- **Skill → Skill**: `dependsOn` / `dependencyOf` (orchestration skills invoke other skills) -- **All entities → Group**: `spec.owner: group:redhat/ai5-marketplace` - -> **Bidirectional declaration policy:** Compass does not auto-generate inverse relations for custom entity kinds such as `AiResource` and `MCPServer` (tracked as COMPASS-1288). Until this is resolved upstream, we explicitly declare **both directions** of every relationship in our manifests. For example, if a skill declares `dependsOn: [airesource:rh-sre/rh-sre]`, the plugin must also declare `dependencyOf: [airesource:rh-sre/]`. When adding or modifying a relationship, always update both the source and target manifests. +Full relationship matrix, bidirectional policy, entity ref formats, and file touch lists: [`.claude/skills/compass-manifest-maintenance/references/relationship-rules.md`](.claude/skills/compass-manifest-maintenance/references/relationship-rules.md). Use the **compass-manifest-maintenance** skill when adding or updating manifests. #### Namespaces From 00389a4c9d369a38d820995f9ba8b8b50850639c Mon Sep 17 00:00:00 2001 From: rhartuv Date: Wed, 2 Sep 2026 17:43:02 +0300 Subject: [PATCH 08/10] feat: add a script to evaluate the Compass Manifests --- .../compass-manifest-maintenance/SKILL.md | 11 +- .pre-commit-config.yaml | 8 +- CLAUDE.md | 7 +- Makefile | 10 +- scripts/validate_compass_manifests.py | 289 ++++++++++++++++++ 5 files changed, 317 insertions(+), 8 deletions(-) create mode 100644 scripts/validate_compass_manifests.py diff --git a/.claude/skills/compass-manifest-maintenance/SKILL.md b/.claude/skills/compass-manifest-maintenance/SKILL.md index 6273f139..99238abc 100644 --- a/.claude/skills/compass-manifest-maintenance/SKILL.md +++ b/.claude/skills/compass-manifest-maintenance/SKILL.md @@ -100,7 +100,7 @@ test -f CLAUDE.md && echo "✓ repo root" || echo "✗ wrong directory" ### 3. Drift / compliance audit -Run checks with `Glob`/`Grep`/`Bash`: +Run `uv run python scripts/validate_compass_manifests.py` (or `make validate-compass-manifests`). It enforces the same structural rules as this table: | Check | Rule | |-------|------| @@ -117,7 +117,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. -2. Re-run drift audit (§3). +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). @@ -153,6 +153,7 @@ None — uses Read, Glob, Grep, Bash. ### Reference Documentation - [CLAUDE.md](../../CLAUDE.md) — entity kinds, namespaces, reference formats +- `scripts/validate_compass_manifests.py` — CI roster and bidirectional ref checks - [references/relationship-rules.md](references/relationship-rules.md) - [references/mcp-mapping.md](references/mcp-mapping.md) @@ -167,6 +168,10 @@ None — uses Read, Glob, Grep, Bash. ## Example usage ```bash +# CI structural validation (roster + bidirectional refs) +uv run python scripts/validate_compass_manifests.py +# or: make validate-compass-manifests + # Roster: skills on disk missing from Location (example: rh-sre) comm -23 \ <(find rh-sre/skills -name SKILL.md | sed 's|.*/skills/||;s|/SKILL.md||' | sort) \ @@ -175,7 +180,7 @@ comm -23 \ # Tier 1 lint for this maintenance skill uv run python scripts/validate_skills_tier1.py .claude/skills/compass-manifest-maintenance/SKILL.md -# Full repo validation (no Compass CI yet) +# Full repo validation make validate ``` diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c5507653..5d1d7c02 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -25,9 +25,15 @@ repos: (?x)^( catalog/.*| marketplace/.*| - scripts/(validate_structure|validate_collection_compliance|validate_collection_schema|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|pack_registry|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| + (rh-[-a-z0-9]+|ocp-admin)/catalog-info\.yaml| + (rh-[-a-z0-9]+|ocp-admin)/[^/]+-plugin\.yaml| + mcps/[^/]+\.yaml| + ^catalog-info\.yaml$| + ^system\.yaml$| (rh-[-a-z0-9]+|ocp-admin)/mcps\.json| (rh-[-a-z0-9]+|ocp-admin)/CLAUDE\.md ) diff --git a/CLAUDE.md b/CLAUDE.md index 62ba1fd6..d127d2aa 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -89,7 +89,7 @@ catalog-info.yaml (root Location) Use `dependsOn` / `dependencyOf` for custom kinds (`AiResource`, `MCPServer`); do not use `partOf` / `hasPart` on those kinds. Compass does not auto-generate inverse relations (COMPASS-1288) — declare both sides on every edge. -Full relationship matrix, bidirectional policy, entity ref formats, and file touch lists: [`.claude/skills/compass-manifest-maintenance/references/relationship-rules.md`](.claude/skills/compass-manifest-maintenance/references/relationship-rules.md). Use the **compass-manifest-maintenance** skill when adding or updating manifests. +Full relationship matrix, bidirectional policy, entity ref formats, and file touch lists: [`.claude/skills/compass-manifest-maintenance/references/relationship-rules.md`](.claude/skills/compass-manifest-maintenance/references/relationship-rules.md). Use the **compass-manifest-maintenance** skill when adding or updating manifests. CI enforces structural rules via `scripts/validate_compass_manifests.py` (`make validate-compass-manifests`). #### Namespaces @@ -293,8 +293,9 @@ last_updated: YYYY-MM-DD 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") -7. Test with `Skill` tool invocation -8. Validate with `uv run python scripts/validate_skills_tier1.py /skills//SKILL.md` +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` **Collection-Specific Standards:** - **rh-virt**: Follow `rh-virt/SKILL_TEMPLATE.md` for enhanced quality standards including mandatory Common Issues and Example Usage sections diff --git a/Makefile b/Makefile index 0a86d3f8..8927a78b 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: help install validate validate-structure validate-collection-schema validate-collection-compliance validate-skill-design validate-skill-design-changed validate-mcp-tools validate-spelling package clean check-uv +.PHONY: help install validate validate-structure validate-collection-schema validate-collection-compliance validate-compass-manifests validate-skill-design validate-skill-design-changed validate-mcp-tools validate-spelling package clean check-uv help: @echo "agentic-plugins" @@ -9,6 +9,7 @@ help: @echo " validate-structure - Structure, links, compliance, MCP tools (no per-skill tier checks)" @echo " validate-collection-schema - Schema + roster + banners (subset of compliance)" @echo " validate-collection-compliance - Full .catalog compliance (includes collection.json drift)" + @echo " validate-compass-manifests - Compass catalog-info.yaml roster and bidirectional refs" @echo " validate-skill-design - Validate all skills (use PACK=rh-sre for a specific pack)" @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)" @@ -57,6 +58,8 @@ validate: check-uv uv run python scripts/validate_docs_tree_links.py || EXIT=1; \ echo "=== Validating collection compliance (.catalog/)..."; \ uv run python scripts/validate_collection_compliance.py || EXIT=1; \ + echo "=== Validating Compass manifests..."; \ + uv run python scripts/validate_compass_manifests.py || EXIT=1; \ echo "=== Validating MCP tool references (skips gracefully without podman)..."; \ uv run python scripts/validate_mcp_tools.py --summary-only --log-file .validate/mcp-tools.log || EXIT=1; \ echo "=== Validating skill design principles..."; \ @@ -79,6 +82,8 @@ validate-structure: check-uv uv run python scripts/validate_docs_tree_links.py || EXIT=1; \ echo "=== Validating collection compliance (.catalog/)..."; \ uv run python scripts/validate_collection_compliance.py || EXIT=1; \ + echo "=== Validating Compass manifests..."; \ + uv run python scripts/validate_compass_manifests.py || EXIT=1; \ echo "=== Validating MCP tool references (skips gracefully without podman)..."; \ uv run python scripts/validate_mcp_tools.py --summary-only --log-file .validate/mcp-tools.log || EXIT=1; \ echo "=== Validation complete!"; \ @@ -90,6 +95,9 @@ validate-collection-schema: check-uv validate-collection-compliance: check-uv @uv run python scripts/validate_collection_compliance.py +validate-compass-manifests: check-uv + @uv run python scripts/validate_compass_manifests.py + validate-skill-design: check-uv @uv run python scripts/validate_skills_tier2.py $(if $(PACK),$(PACK)) diff --git a/scripts/validate_compass_manifests.py b/scripts/validate_compass_manifests.py new file mode 100644 index 00000000..489b96e2 --- /dev/null +++ b/scripts/validate_compass_manifests.py @@ -0,0 +1,289 @@ +#!/usr/bin/env python3 +""" +Validate Compass catalog-info.yaml manifests for agentic packs in the root Location. + +Structural checks (no SKILL.md semantic inference): + - Roster parity: skills on disk vs pack 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) +""" + +from __future__ import annotations + +import re +import sys +from pathlib import Path + +import yaml + +_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}" +_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" +_EXPECTED_NAMESPACE = "ai5-marketplace" + + +def _load_yaml(path: Path) -> dict: + data = yaml.safe_load(path.read_text(encoding="utf-8")) + if not isinstance(data, dict): + raise ValueError(f"{path}: expected mapping at top level") + return data + + +def _refs(spec: dict, key: str) -> list[str]: + value = spec.get(key) or [] + if not isinstance(value, list): + return [] + return [str(item) for item in value] + + +def registered_packs() -> list[str]: + data = _load_yaml(_ROOT_CATALOG) + packs: list[str] = [] + for target in data.get("spec", {}).get("targets", []): + if not isinstance(target, str): + continue + if target.startswith("./mcps/"): + continue + if not target.endswith("/catalog-info.yaml"): + continue + parts = Path(target).parts + if len(parts) != 2: + continue + packs.append(parts[0]) + return sorted(set(packs)) + + +def skills_on_disk(pack_dir: Path) -> set[str]: + skills_dir = pack_dir / "skills" + if not skills_dir.is_dir(): + return set() + return { + entry.name + for entry in skills_dir.iterdir() + if entry.is_dir() and (entry / "SKILL.md").is_file() + } + + +def location_skill_targets(loc_data: dict) -> set[str]: + targets: set[str] = set() + for target in loc_data.get("spec", {}).get("targets", []): + if not isinstance(target, str): + continue + match = _SKILL_TARGET_RE.match(target) + if match: + targets.add(match.group(1)) + return targets + + +def load_owned_mcps() -> dict[str, Path]: + owned: dict[str, Path] = {} + for path in sorted((_REPO_ROOT / "mcps").glob("*.yaml")): + if path.name == "catalog-info.yaml": + continue + data = _load_yaml(path) + meta = data.get("metadata", {}) + name = meta.get("name") + namespace = meta.get("namespace", _EXPECTED_NAMESPACE) + if name: + owned[f"mcpserver:{namespace}/{name}"] = path + return owned + + +def _is_allowed_dangling_mcp(ref: str) -> bool: + return ref.startswith(_CANONICAL_MCP_PREFIXES) + + +def _check_skill_conventions(path: Path, data: dict, errors: list[str]) -> None: + meta = data.get("metadata", {}) + spec = data.get("spec", {}) + rel = path.relative_to(_REPO_ROOT) + + if meta.get("namespace") != _EXPECTED_NAMESPACE: + errors.append(f"{rel}: metadata.namespace must be {_EXPECTED_NAMESPACE}") + labels = meta.get("labels") or {} + if labels.get("distribution") != "external": + errors.append(f"{rel}: labels.distribution must be external") + if spec.get("owner") != _EXPECTED_OWNER: + errors.append(f"{rel}: spec.owner must be {_EXPECTED_OWNER}") + if spec.get("agents") != []: + errors.append(f"{rel}: spec.agents must be []") + if spec.get("type") != "skill": + errors.append(f"{rel}: spec.type must be skill") + + +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) + + if not loc_path.is_file(): + errors.append(f"{pack}: 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)}") + 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) + 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"{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}' " + "but skills//SKILL.md not found" + ) + + plugin_depof_skills = { + ref.split("/", 1)[1] + for ref in _refs(plugin_spec, "dependencyOf") + if ref.startswith("airesource:ai5-marketplace/") and ref != plugin_ref + } + for skill in sorted(disk - plugin_depof_skills): + errors.append( + f"{pack}: {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}'" + ) + + if "system:default/agentic-plugins" in _refs(plugin_spec, "dependsOn"): + errors.append( + f"{plugin_path.relative_to(_REPO_ROOT)}: redundant " + "dependsOn system:default/agentic-plugins (use spec.system)" + ) + + skill_depends: dict[str, list[str]] = {} + skill_depof: dict[str, set[str]] = {} + pack_skill_mcp_union: set[str] = set() + + for skill in sorted(disk): + manifest = pack_dir / "skills" / skill / "catalog-info.yaml" + if not manifest.is_file(): + errors.append(f"{pack}: missing {manifest.relative_to(_REPO_ROOT)}") + continue + + raw = manifest.read_text(encoding="utf-8") + if _FORBIDDEN_RELATION_RE.search(raw): + errors.append( + f"{manifest.relative_to(_REPO_ROOT)}: partOf/hasPart not supported on AiResource" + ) + + data = _load_yaml(manifest) + _check_skill_conventions(manifest, data, errors) + spec = data.get("spec", {}) + deps = _refs(spec, "dependsOn") + skill_depends[skill] = deps + skill_depof[skill] = set(_refs(spec, "dependencyOf")) + + if plugin_ref not in deps: + errors.append( + f"{manifest.relative_to(_REPO_ROOT)}: missing dependsOn {plugin_ref}" + ) + + for dep in deps: + if dep.startswith("mcpserver:"): + pack_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 missing_on_plugin: + errors.append( + f"{pack}: {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"MCP refs not used by any skill: {sorted(extra_on_plugin)}" + ) + + for skill, deps in skill_depends.items(): + orchestrator_ref = f"airesource:ai5-marketplace/{skill}" + for dep in deps: + if dep == plugin_ref: + continue + if dep.startswith("airesource:ai5-marketplace/"): + 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" + ) + continue + if orchestrator_ref not in skill_depof.get(target, set()): + errors.append( + f"{pack}/skills/{target}/catalog-info.yaml: missing dependencyOf " + f"{orchestrator_ref} (inverse of {skill} dependsOn)" + ) + elif dep.startswith("mcpserver:"): + if dep in owned_mcps: + mcp_path = owned_mcps[dep] + mcp_spec = _load_yaml(mcp_path).get("spec", {}) + if orchestrator_ref not in set(_refs(mcp_spec, "dependencyOf")): + errors.append( + f"{mcp_path.relative_to(_REPO_ROOT)}: missing dependencyOf " + f"{orchestrator_ref} (inverse of {skill} dependsOn {dep})" + ) + elif not _is_allowed_dangling_mcp(dep): + errors.append( + f"{pack}/skills/{skill}/catalog-info.yaml: unknown mcpserver ref {dep}" + ) + + for dep in _refs(plugin_spec, "dependsOn"): + if dep.startswith("mcpserver:") and dep in owned_mcps: + mcp_path = owned_mcps[dep] + mcp_spec = _load_yaml(mcp_path).get("spec", {}) + if plugin_ref not in set(_refs(mcp_spec, "dependencyOf")): + errors.append( + f"{mcp_path.relative_to(_REPO_ROOT)}: missing dependencyOf " + f"{plugin_ref} (inverse of plugin dependsOn {dep})" + ) + + +def main() -> int: + errors: list[str] = [] + owned_mcps = load_owned_mcps() + + if not _ROOT_CATALOG.is_file(): + errors.append( + f"missing root catalog Location: {_ROOT_CATALOG.relative_to(_REPO_ROOT)}" + ) + else: + for pack in registered_packs(): + validate_pack(pack, owned_mcps, errors) + + if errors: + print("Compass manifest validation failed:", file=sys.stderr) + for err in errors: + print(f" • {err}", file=sys.stderr) + return 1 + + print("✓ Compass manifest validation passed") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) From 12d8efb7cc32f7b05b5b20d5257833e1ba9980c8 Mon Sep 17 00:00:00 2001 From: rhartuv Date: Sun, 6 Sep 2026 10:52:04 +0300 Subject: [PATCH 09/10] fix: change hardcode lifecycle --- .../compass-manifest-maintenance/SKILL.md | 19 +++++++++++++------ .../assets/plugin-catalog-info.yaml | 1 + .../assets/skill-catalog-info.yaml | 3 ++- .../references/relationship-rules.md | 5 +++++ CLAUDE.md | 10 ++++------ 5 files changed, 25 insertions(+), 13 deletions(-) diff --git a/.claude/skills/compass-manifest-maintenance/SKILL.md b/.claude/skills/compass-manifest-maintenance/SKILL.md index 99238abc..b200cf36 100644 --- a/.claude/skills/compass-manifest-maintenance/SKILL.md +++ b/.claude/skills/compass-manifest-maintenance/SKILL.md @@ -62,6 +62,7 @@ test -f CLAUDE.md && echo "✓ repo root" || echo "✗ wrong directory" 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) - `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)) @@ -73,26 +74,31 @@ test -f CLAUDE.md && echo "✓ repo root" || echo "✗ wrong directory" - Other skills: orchestration or documented `/other-skill` invocations in `SKILL.md` - Script-only skills: no `mcpserver:` entries -4. **Write** `/skills//catalog-info.yaml` from [assets/skill-catalog-info.yaml](assets/skill-catalog-info.yaml): +4. **Set `spec.lifecycle`** (do not hardcode `beta`): + - 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): - `namespace: ai5-marketplace` - `labels.distribution: external` - `agents: []` - - `lifecycle: beta` + - `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) -5. **Update inverse manifests** ([relationship-rules.md](references/relationship-rules.md)): +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/` - Each `mcpserver:` in skill `dependsOn` → matching `mcps/*.yaml` `dependencyOf` - Each skill in skill `dependsOn` → that skill's `dependencyOf` includes orchestrator -6. **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 pack skill manifests. ### 2. Register a new pack in Compass -1. Create `/-plugin.yaml` from [assets/plugin-catalog-info.yaml](assets/plugin-catalog-info.yaml). +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`. @@ -128,7 +134,8 @@ Report violations with file path and fix per workflow §1. Do not weaken checks. ## Self-review checklist -- [ ] Skill manifest matches repo Compass conventions (`agents: []`, `labels.distribution: external`, `namespace: ai5-marketplace`, `owner: group:redhat/ai5-marketplace`). +- [ ] Skill `spec.lifecycle` matches plugin default or a less mature value (never above the plugin). +- [ ] 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. 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 6ad07267..8d319976 100644 --- a/.claude/skills/compass-manifest-maintenance/assets/plugin-catalog-info.yaml +++ b/.claude/skills/compass-manifest-maintenance/assets/plugin-catalog-info.yaml @@ -1,5 +1,6 @@ # 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). apiVersion: backstage.io/v1alpha1 kind: AiResource metadata: 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 29852449..596feb3f 100644 --- a/.claude/skills/compass-manifest-maintenance/assets/skill-catalog-info.yaml +++ b/.claude/skills/compass-manifest-maintenance/assets/skill-catalog-info.yaml @@ -1,5 +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 apiVersion: backstage.io/v1alpha1 kind: AiResource metadata: @@ -22,7 +23,7 @@ metadata: icon: github spec: type: skill - lifecycle: beta + lifecycle: # from /-plugin.yaml; same or less mature than plugin owner: group:redhat/ai5-marketplace disciplines: - diff --git a/.claude/skills/compass-manifest-maintenance/references/relationship-rules.md b/.claude/skills/compass-manifest-maintenance/references/relationship-rules.md index 573fa288..5cd75908 100644 --- a/.claude/skills/compass-manifest-maintenance/references/relationship-rules.md +++ b/.claude/skills/compass-manifest-maintenance/references/relationship-rules.md @@ -31,6 +31,11 @@ Compass does **not** auto-generate inverse relations for custom kinds (`AiResour 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`. + ## Files to touch when adding a skill 1. `skills//catalog-info.yaml` — new or updated entity diff --git a/CLAUDE.md b/CLAUDE.md index d127d2aa..7987b134 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -103,7 +103,8 @@ All entities (skills, plugins, and MCP servers) share a single namespace: `ai5-m #### Adding Compass Manifests for a New Skill -When adding a skill, create `skills//catalog-info.yaml`: +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`. + ```yaml apiVersion: backstage.io/v1alpha1 kind: AiResource @@ -126,16 +127,13 @@ metadata: icon: github spec: type: skill - lifecycle: beta + lifecycle: # from -plugin.yaml; same or less mature than plugin owner: group:redhat/ai5-marketplace disciplines: - categories: - - agents: - - claude-code - - opencode - - cursor + agents: [] dependsOn: - airesource:ai5-marketplace/ # Add mcpserver and airesource (skill) dependencies as needed From f5bc0660102f6fd2664da8c19f2bf0b3f762d0fa Mon Sep 17 00:00:00 2001 From: rhartuv Date: Mon, 7 Sep 2026 13:52:56 +0300 Subject: [PATCH 10/10] fix: update network-policy-architect lifecycle --- ocp-admin/skills/network-policy-architect/catalog-info.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ocp-admin/skills/network-policy-architect/catalog-info.yaml b/ocp-admin/skills/network-policy-architect/catalog-info.yaml index d03aae3d..98f96d16 100644 --- a/ocp-admin/skills/network-policy-architect/catalog-info.yaml +++ b/ocp-admin/skills/network-policy-architect/catalog-info.yaml @@ -25,7 +25,7 @@ metadata: icon: github spec: type: skill - lifecycle: beta + lifecycle: development owner: group:redhat/ai5-marketplace disciplines: - security