Distributing AI Skills at Enterprise Scale

Package, sign, and distribute agent skills as OCI artifacts — using the same registries and trust chains you already run for container images.

OCI Artifacts ORAS Sigstore Image Volumes

Pavel Anni · Office of CTO · Red Hat

What is a skill?

  • A text (Markdown) file with instructions for the LLM
    • That includes a frontmatter explaining when and how to use it
    • The format is defined by https://agentskills.io/ specification
  • An optional set of additional files, e.g.:
    • Resource/reference files: web page style instructions
    • Scripts or other executable files
  • Introduced by Anthropic in October 2025
    • Used by other agents widely

Today's skill distribution is ad-hoc

Method How it works Drawback
Copy from a Friend Slack messages, email, shared drives No versioning. No provenance. No audit trail.
Clone from GitHub git clone the repo, copy the directory No signing. No atomic versioning. Auth is coarse-grained.

These get you started, but none provide the versioning, provenance, signing, and auditability that enterprise deployments require.

Toxic Skills are real

Out of 3,984 skills from ClawHub and skills.sh (as of Feb 5th, 2026):

  • 36.8% (1,467 skills) have at least one security flaw
  • 13.4% (534 skills) have at least one critical-level security issue

Data by Snyk (Feb 5th, 2026)
https://snyk.io/blog/toxicskills-malicious-ai-agent-skills-clawhub/

Enterprise deployments need trust infrastructure

  • 🔒 Signing — Cryptographic proof of who published a skill and that it hasn't been tampered with
  • 📋 Auditability — Registry logs show who pulled what, when, and where it was deployed
  • 🔄 Versioning — Immutable tags, semantic versions, rollback to a known-good skill set
  • 📌 Reproducibility — Pin skills by digest (sha256) for byte-identical deployments across environments
  • 🔑 Access control — Registry RBAC, pull secrets, org-scoped namespaces — the same policies you use for images

We have solved this problem already

The OCI Distribution Spec is content-agnostic. Any blob + manifest + media type = a valid artifact. ORAS makes this practical.

Helm Charts WASM Modules ML Models Policy Bundles Agent Skills

┌────────────────────────────────────────────────────┐
│      OCI Registry (Quay / GHCR / Harbor / Zot)     │
└────────────────────────────────────────────────────┘
    ↓  Same protocol, same auth, same RBAC  ↓
┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│  Container   │  │    Helm      │  │    Agent     │
│   Images     │  │   Charts     │  │   Skills ★   │
└──────────────┘  └──────────────┘  └──────────────┘

Your agent is only as good as its skills

Skills are the unit of specialization. Each skill gives the agent domain expertise.

  • SKILL.md — instructions in Agent Skills spec format
  • skill.yaml — metadata: versioning, compatibility, licensing
  • Scripts — executable files (Python, Bash, etc.)
  • Anything else — supporting files, models, tools
skills/
├── resume-screener/
│   ├── SKILL.md
│   └── skill.yaml
└── policy-comparator/
    ├── SKILL.md
    └── skill.yaml

A skill becomes an OCI artifact

Skill Directory  →  skillctl build  →  OCI Image  →  skillctl push  →  Registry

What goes into the image:

  • SKILL.md — instructions
  • skill.yaml — SkillCard metadata
  • Any supporting files in the directory

What the registry provides:

  • Immutable digest + mutable tags
  • RBAC & pull secrets
  • Cosign / sigstore signatures

How to package skills: build, tag, push

# Build skill into a local OCI image
$ skillctl build skills/resume-screener/
Built resume-screener:1.0.0-draft (sha256:65af...)

# Tag with registry tag
$ skillctl tag resume-screener:1.0.0-draft \
    quay.io/myorg/resume-screener:1.0.0-draft


# Push to registry
$ skillctl push quay.io/myorg/resume-screener:1.0.0-draft

Every skill has a machine-readable identity

$ skillctl inspect quay.io/myorg/resume-screener:1.0.0
Name:     myorg/resume-screener    Version: 1.0.0
Status:   published                License: Apache-2.0
Authors:  Red Hat OCTO             Compat:  claude-3.5-sonnet
Tags:     ["hr","screening"]

What SkillCard enables:

  • Discovery — search by name, namespace, tags, author
  • Lifecycle — draft → testing → published → deprecated
  • Compatibility — target model compatibility hints
  • Governance — license, author, namespace for trust policies

Deploy as image volumes: mount skills directly

On OpenShift 4.20+ / K8s 1.33+, mount an OCI image as a read-only volume.

volumes:
  - name: resume-screener
    image:
      reference: quay.io/myorg/resume-screener:1.0.0
      pullPolicy: IfNotPresent
containers:
  - name: agent
    volumeMounts:
      - name: resume-screener
        mountPath: /skills/resume-screener
  • Kubelet pulls and caches skill images automatically
  • Read-only mount — immutable at runtime
  • Same pull policies, pull secrets, and mirrors as container images

KEP-4639 · Kubernetes 1.33+ · OpenShift 4.20+

Init container for older clusters

For K8s < 1.33 / OpenShift < 4.20, use skillctl as an init container.

initContainers:
  - name: skill-puller
    image: ghcr.io/redhat-et/skillctl:latest
    command: ["skillctl", "pull", "--verify",
              "-o", "/skills",
              "quay.io/myorg/resume-screener:1.0.0"]
    volumeMounts:
      - name: skills
        mountPath: /skills
  • Pull and verify signatures at pod startup
  • Cache on a PVC across restarts
  • Share the volume with the agent container

Install for personal use

# Install into a target directory
skillctl pull -o TARGET_DIR

# Install for a specific agent
skillctl install --target claude

Supported targets:

  • claude ~/.claude/skills/
  • cursor ~/.cursor/skills/
  • windsurf ~/.codeium/windsurf/skills/
  • opencode ~/.config/opencode/skills/
  • openclaw ~/.openclaw/skills/

From ad-hoc to supply chain

Before After (OCI)
Distribution git clone or manual copy skillctl install from registry
Versioning Branch/tag only Semver tags + immutable digests
Upgrades Manual re-clone skillctl upgrade with version check
Signing None Cosign / sigstore signing
Audit No trail Registry access logs
Auth Repo level only Per-namespace RBAC + pull secrets
Runtime Mutable Read-only image volume mount

Disconnected and air-gapped environments

oc-mirror mirrors skill images alongside operator bundles to internal registries.

Connected                           Disconnected
┌──────────┐   oc-mirror   ┌────────────────────────┐
│ Quay.io  │ ────────────▸ │ Internal OCP Registry  │
└──────────┘               └────────────────────────┘
  Skills + Operators         Mirrored with signatures
  • OLM integration — skills as related images, mirrored automatically
  • Internal registry — same skillctl pull workflow, no external access
  • Signatures preserved — cosign signatures survive the mirror

Multiple consumption paths

Skills are standard OCI images — any tool that pulls images can consume them.

Method Command Best for
skillctl install skillctl install <ref> --target claude Developer workstations
Image volume Pod spec volumes.image K8s 1.33+ / OCP 4.20+
Init container skillctl pull -o /skills Older clusters
Container extract podman create + podman cp No skillctl installed
# One-command install (auto-pulls from registry):
$ skillctl install quay.io/myorg/resume-screener:1.0.0 --target claude

Brew-style skill management

Like dnf for AI skills — install, list, upgrade in one command each.

$ skillctl install quay.io/myorg/code-reviewer:1.0.0 --target claude
Installed to ~/.claude/skills/code-reviewer

$ skillctl list --installed --upgradable --target claude
NAME            VERSION  LATEST  SOURCE                             TARGET
code-reviewer   1.0.0    2.0.0   quay.io/myorg/code-reviewer:2.0.0  claude

$ skillctl upgrade code-reviewer --target claude
Upgraded code-reviewer 1.0.0 → 2.0.0 (claude)

$ skillctl upgrade --all --target claude
All skills are up to date.

Try it today

  • 💻 Install: brew install pavelanni/tap/skillctl — build, push, install, upgrade in minutes
  • 🔄 Full lifecycle: build → promote → push → install → upgrade → remove
  • 🤝 Community: SkillCard aligns with the Agent Skills OCI Artifacts Specification
  • 🔏 Next milestone: sigstore integration for keyless skill signing and verification
  • 🏢 OpenShift alignment: oc-mirror, OLM integration, and admission control

github.com/redhat-et/skillimage

Thank you

Pavel Anni · Office of CTO · Red Hat

Tips: Arrow keys or click to navigate. Press N to toggle notes. Project: github.com/redhat-et/skillimage

Each of these methods gets progressively closer to enterprise readiness — ConfigMaps are already Kubernetes-native — but all three lack the supply chain guarantees (signing, versioning, audit) that regulated environments require. ConfigMaps have a 1 MiB size limit (etcd constraint), so larger skills with examples or data files won't fit.

This is the core motivation. When you deploy AI agents in a regulated enterprise, you need the same supply chain guarantees you have for container images: signed artifacts, vulnerability scanning, access control, and audit logs. Reproducibility matters because you need to prove which exact skill version produced an agent's output — especially in regulated industries (finance, healthcare, government).

ORAS (OCI Registry As Storage): oras.land The OCI Distribution Specification was designed to be content-agnostic. Media types let registries and tools distinguish content without special handling. Helm charts have been distributed as OCI artifacts since Helm 3.8 (2022). WASM modules, ML models, and policy bundles are also distributed this way. Key insight: your Quay/Harbor/GHCR registry can already store and serve non-image content. No infrastructure changes needed.

Agent Skills Specification: agentskills.io/specification Skills are the unit of specialization for an agent. Each skill is a self-contained directory with instructions (SKILL.md) and optional metadata (skill.yaml). The agent discovers and loads them at startup. Think of skills like plugins: the agent provides the runtime, skills provide domain expertise.

Skills are packaged as standard OCI images (FROM scratch), not ORAS artifacts. This means podman pull, skopeo copy, and Kubernetes ImageVolumes all work natively. Media types used: - application/vnd.oci.image.layer.v1.tar+gzip (skill content layer) - application/vnd.oci.image.config.v1+json (config) Skill metadata is stored in OCI manifest annotations (io.skillimage.*) for fast inspection without pulling the full layer.

skillctl build produces standard OCI images (FROM scratch). Since skills are OCI images, podman pull, skopeo copy, and Kubernetes ImageVolumes all work natively. Install auto-pulls from remote registries if the image isn't in the local store. Provenance (source registry and digest) is recorded in the installed skill's skill.yaml for later upgrade tracking.

SkillCard schema: skillimage.io/v1alpha1 kind: SkillCard. The metadata travels inside the OCI manifest annotations, so 'skillctl inspect' reads it without pulling the full layer. The SkillCard schema is intentionally extensible: additional fields (compatibility matrix, test results, usage metrics) can be added without breaking existing skills.

Image Volumes (KEP-4639): GA in Kubernetes 1.33 / OpenShift 4.20. The kubelet pulls the image via the container runtime and mounts it read-only into the pod. No init container, no PVC, no emptyDir. The image is cached in the node's container image store — subsequent pods that use the same skill image don't need to pull again. This is the exact same mechanism used for container images, so existing image pull policies (IfNotPresent, Always), pull secrets, and registry mirrors all work.

For older clusters, the init container approach uses skillctl to pull skills from the registry before the main container starts. Use a PVC (not emptyDir) to persist the skill cache across pod restarts and avoid filling node ephemeral storage. Signature verification happens at pull time: --verify + --key flags enforce cosign verification before extracting the skill.

skillctl install is the easiest way to get started. It pulls the skill image from the registry and extracts it into the target directory. The --target flag lets you specify the agent you're installing for, so the skill is extracted to the correct location.

The before/after contrast highlights what OCI distribution adds to the picture. All the "after" properties come for free from the OCI ecosystem — registries, sigstore, RBAC, pull policies — we're just reusing existing infrastructure.

The OpenShift platform team is also building support for this. The oc-mirror tool needs a recognizable MIME type (application/vnd.redhat.agentskill.layer.v1+tar) to identify skill artifacts for mirroring. skillctl supports this as an optional media type alongside the standard OCI types. For air-gapped clusters, the internal OpenShift registry (image-registry.openshift-image-registry.svc:5000) serves the same role as Quay.io — skillctl pull works the same way. OLM integration: operators can declare skills as related images in their ClusterServiceVersion. When oc-mirror processes the operator catalog, it automatically includes the skill images.

skillctl install is the simplest path for developers. Supports Claude Code, Cursor, Windsurf, OpenCode, and OpenClaw. Since skills are standard OCI images, any container runtime can also pull and extract the content.

skillctl tracks provenance (source registry and digest) in each installed skill's skill.yaml. This lets it check for newer published versions and upgrade in place. The upgrade command only considers published versions (no -draft or -testing suffixes) and uses strict semver comparison. Local skills without provenance are skipped.

Resources: - Project: github.com/redhat-et/skillimage - Agent Skills OCI Spec: github.com/ThomasVitale/agents-skills-oci-artifacts-spec - ORAS project: oras.land - Zot registry: zotregistry.dev

Thank you for your time. Questions and feedback welcome.