Skip to content

Skill Installation

Skills from the opendatahub-io/skills-registry are pre-installed into every runner and sandbox image at build time. Each harness (Claude Code, OpenCode, Codex) uses a different installation mechanism that matches the tool's native plugin system.

Claude Code: plugin seed

Claude Code images use the official plugin seed mechanism. At build time, native CLI commands populate a seed directory that Claude Code reads at startup without re-cloning anything.

Build-time flow

The Containerfile runs two steps as the non-root user:

RUN git config --global url."https://github.com/".insteadOf "git@github.com:" \
    && export CLAUDE_CODE_PLUGIN_CACHE_DIR=/home/agent-ci/.claude-seed \
    && export DISABLE_AUTOUPDATER=1 \
    && claude plugin marketplace add opendatahub-io/skills-registry \
    && agentic-ci install-plugins \
    && git config --global --unset-all url."https://github.com/".insteadOf
  1. claude plugin marketplace add — registers the skills-registry marketplace and clones it into the seed directory.
  2. agentic-ci install-plugins — reads the marketplace.json, calls claude plugin install <name>@<marketplace> for each plugin, and generates the plugin-skills manifest.

The git config override forces HTTPS cloning since the container has no SSH keys. It is removed at the end of the same RUN layer so the final image has clean git config.

Runtime

Two environment variables control plugin loading:

Variable Purpose
CLAUDE_CODE_PLUGIN_SEED_DIR Points to the pre-built seed directory. Claude Code reads it on startup (read-only, no auto-updates).
CLAUDE_CODE_SYNC_PLUGIN_INSTALL Set to 1. Required for skills to load synchronously in non-interactive (-p) mode.

Seed directory structure

~/.claude-seed/
  known_marketplaces.json
  installed_plugins.json
  marketplaces/
    opendatahub-skills/           # full git clone of skills-registry
      .claude-plugin/
        marketplace.json
  cache/
    opendatahub-skills/
      odh-git/0.1.0/              # plugins/odh-git subdirectory (git-subdir source)
        skills/git-shallow-clone/
          SKILL.md
      code-review-skills/0.1.0/
        skills/gitlab-code-review/
          SKILL.md
          scripts/review.py
      ...

OpenCode: file-based skill discovery

OpenCode has no native marketplace or seed mechanism. It discovers skills by scanning directories for SKILL.md files. The build copies skill directories from each plugin repo into OpenCode's global skills path.

Build-time flow

RUN git clone --depth 1 --quiet https://github.com/opendatahub-io/skills-registry.git /tmp/skills-registry \
    && agentic-ci install-plugins --harness opencode \
       --marketplace-json /tmp/skills-registry/.claude-plugin/marketplace.json \
    && rm -rf /tmp/skills-registry

agentic-ci install-plugins --harness opencode reads the marketplace.json, then for each plugin:

  1. Clones the plugin's source repo.
  2. Copies skill directories to ~/.config/opencode/skills/. Uses explicit skills paths from the marketplace entry when present (e.g. "skills": ["./.claude/skills"] for rhoai-security-reviewer), otherwise falls back to standard paths (.claude/skills/, .agents/skills/, .opencode/skills/, skills/). The .agents/skills/ fallback applies to OpenCode installs as well as Codex compatibility installs.
  3. Records the plugin→skill mapping in the plugin-skills manifest.

Skills directory structure

~/.config/opencode/skills/
  git-shallow-clone/
    SKILL.md
  code-review/
    SKILL.md
  gitlab-code-review/
    SKILL.md
    scripts/review.py
  ...

All skills are flat in one directory — no plugin namespacing. OpenCode discovers them by scanning for SKILL.md files.

Codex: native plugins with legacy compatibility

Codex has a native plugin and marketplace system. At build time, agentic-ci install-plugins --harness codex --marketplace-json <path> adds the marketplace with codex plugin marketplace add, installs its native Codex plugins, and records their bundled skills in the plugin-skills manifest.

The existing skills registry also contains legacy Claude-compatible marketplaces whose packages do not yet include Codex plugin manifests. If Codex reports no native packages for such a marketplace, agentic-ci clones the entries and installs their skills under $CODEX_HOME/skills.

The marketplace clone is kept in the image at $CODEX_HOME/marketplaces/skills-registry. Codex records it as a local marketplace source, and codex plugin list (which enable-plugins runs at container start) fails if that directory is missing. The manifest records the install path that codex plugin add --json reports, because codex plugin list --json does not include one.

agentic-ci does not yet provide an images/runner/codex image. Codex runner images are user-supplied through --image or CODEX_CONTAINER_IMAGE and must include the codex binary until that directory exists.

Plugin-skills manifest

Both install scripts generate a manifest at /usr/local/share/agentic-ci/plugin-skills.manifest.json that maps plugin names to the skills they contain:

{
  "odh-git": ["aipcc-commit-suggest", "gist-upload", "git-shallow-clone", ...],
  "code-review-skills": ["gitlab-code-review"],
  "rfe-creator": ["rfe.create", "rfe.review", ...]
}

Each entry lists the skills the harness actually loads from that plugin, not every SKILL.md in its repository:

  • Claude Code: the direct children of the plugin's skills/ directory, plus the paths declared by the marketplace entry or .claude-plugin/plugin.json. Symlinks are followed inside the plugin.
  • Codex native plugins: the skills paths from the plugin manifest, or skills/ when it declares none, searched recursively.
  • OpenCode and the Codex compatibility layer: the skills copied into the skills directory.

Plugins that provide no skills are left out.

For Claude Code, the manifest is informational (debugging, auditing). For OpenCode and Codex, the manifest is functional — enable-plugins uses it to apply per-skill filtering at runtime (see below).

Filtering plugins at runtime

The AGENT_ENABLED_PLUGINS environment variable controls which plugins are active. If unset, all plugins are enabled. If set to a comma-separated list of plugin names, only those plugins are active.

# Enable only odh-git — all other plugins are disabled
AGENT_ENABLED_PLUGINS=odh-git agentic-ci run "do something" ...

# Enable two plugins
AGENT_ENABLED_PLUGINS=odh-git,code-review-skills agentic-ci run ...

The ODH AI Helpers skills ship as focused odh-* plugins (odh-git, odh-jira, odh-python-packaging, ...). The deprecated odh-ai-helpers umbrella that re-exports them under the old odh-ai-helpers:* names only works under Claude Code: its skills are symlinks, which the OpenCode and Codex installs skip. Enable the odh-* plugins you need instead.

How filtering works

The enable-plugins script runs at container startup (called by entrypoint.sh for Podman, or by the env script for OpenShell). It reads AGENT_ENABLED_PLUGINS and AGENT_TOOL to decide which mechanism to use:

Claude Code (AGENT_TOOL=claude): Sets enabledPlugins entries to false in ~/.claude/settings.json for unwanted plugins. Claude Code reads this at startup and skips disabled plugins.

OpenCode (AGENT_TOOL=opencode): Reads the plugin-skills manifest to find which skills belong to unwanted plugins, then removes unwanted skill directories from the ephemeral runtime filesystem before OpenCode starts.

Codex (AGENT_TOOL=codex): Uses codex plugin list/remove for native plugins and removes only manifest-managed compatibility skills for unwanted plugins from $CODEX_HOME/skills. Personal skills that are not managed by the manifest are left intact.

Error handling

If a requested plugin name doesn't match any installed plugin, the script exits with an error and reports which names were unmatched:

Matched: odh-git
ERROR: unknown plugin(s) in AGENT_ENABLED_PLUGINS: nonexistent-plugin

Under OpenCode and the Codex skills compatibility layer, a plugin that installed no skills is unknown too, since skills are all they install. Claude Code and native Codex plugins can also carry MCP servers, hooks or agents, so there an enabled plugin with no skills in the manifest only prints a warning:

WARNING: enabled plugin(s) provide no skills: odh-ai-helpers

Plugins without skills

The image build ends with one line naming every marketplace plugin that installed no skills, whether its install failed, its skills path no longer exists, or (OpenCode) its skill names collide with a plugin installed earlier:

WARN: 3 plugin(s) provide no skills: patternfly, pf-mcp, spike-executor

MCP-only plugins and bundles such as pf-mcp and patternfly are expected here. Anything else usually means the skills-registry entry needs fixing.

CLI subcommands

Plugin installation and filtering are agentic-ci subcommands (implemented in src/agentic_ci/plugins.py):

Command When Purpose
agentic-ci install-plugins Build time Install plugins for Claude Code (reads seed dir), OpenCode, or Codex (--marketplace-json <path>)
agentic-ci enable-plugins Runtime Filter active plugins based on AGENT_ENABLED_PLUGINS

The container entrypoint (images/runner/shared/entrypoint.sh) calls agentic-ci enable-plugins at startup. For OpenShell sandboxes, the env script calls it before the agent runs.

Adding skills without rebuilding

Mount a directory containing SKILL.md files and point Claude Code at it:

podman run --rm \
  -v ./my-skills:/opt/extra-skills:ro \
  -e CLAUDE_CODE_PLUGIN_SEED_DIR=/opt/extra-skills \
  quay.io/aipcc/agentic-ci/claude-runner:latest

For OpenCode, mount into the skills directory directly:

podman run --rm \
  -v ./my-skills:/home/agent-ci/.config/opencode/skills:ro \
  quay.io/aipcc/agentic-ci/opencode-runner:latest