Pinecone Codex Plugin — Contributor Guide

How this repo is wired up: the sync pipeline from pinecone-io/skills, the validators, and the release workflow. Open this file in a browser — it is self-contained.

1. Overview

Pinecone publishes one base skills library — pinecone-io/skills — that is intentionally environment-agnostic. The base repo fans out to one downstream plugin repo per agentic IDE: Claude Code, Cursor, and (this repo) Codex. Nothing rewrites a skill after it leaves the base repo. Every Codex-specific value — the bare skill names, the codex_plugin: source tag, the per-target wording — comes from targets/codex.yaml upstream, and tools/build.py renders the tree before it is ever copied here. Read a sync PR as content, not as a transform.

┌─────────────────────────┐ │ pinecone-io/skills │ author edits a skill, pushes to main │ (base, IDE-agnostic) │ └────────────┬────────────┘ │ tools/build.py renders skills/ + targets/codex.yaml ▼ ┌─────────────────────────────────────────────────────────────────┐ │ dist/codex/ — the finished tree, already in Codex conventions │ └────────────┬────────────────────────────────────────────────────┘ │ sync-skills.yml (matrix over downstream repos) ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Opens PR on: │ │ pinecone-io/pinecone-claude-code-plugin │ │ pinecone-io/pinecone-cursor-plugin │ │ pinecone-io/pinecone-codex-plugin ◄── this repo │ │ Branch: sync/skills │ └────────────────────────────┬────────────────────────────────────┘ │ validate.yml runs on every PR ▼ ┌─────────────────────────────────────────────────────────────────┐ │ scripts/check_all.py — manifest, marketplace, skills, │ │ source_tags, links. All green = ready for human review. │ └────────────────────────────┬────────────────────────────────────┘ │ maintainer merges ▼ ┌─────────────────────────────────────────────────────────────────┐ │ release.yml bumps version, updates CHANGELOG, tags vX.Y.Z, │ │ creates a GitHub release. │ └─────────────────────────────────────────────────────────────────┘

2. Repo layout

PathPurpose
.codex-plugin/plugin.jsonRequired Codex plugin manifest. Identity, version, install-surface metadata, pointers to skills/ and .mcp.json.
.agents/plugins/marketplace.jsonMarketplace metadata so users can codex plugin marketplace add pinecone-io/pinecone-codex-plugin.
.mcp.jsonBundled Pinecone MCP server config (npx -y @pinecone-database/mcp).
skills/One directory per skill. Each has a SKILL.md, optionally references/*.md and scripts/*.py.
scripts/check_*.pyValidators. See §4.
.github/workflows/validate.ymlRuns check_all.py on every PR and on pushes to main.
.github/workflows/release.ymlOn merge to main, bumps version, updates CHANGELOG, tags release.
README.mdUser-facing install and usage docs.
CHANGELOG.mdVersion history, populated by release.yml.
docs/index.htmlThis file.

3. Sync pipeline (upstream → here)

The base repo's .github/workflows/sync-skills.yml is dispatch-only. It renders every target with uv run tools/build.py --all --check, runs tools/reconcile.py against this repo to report what the sync is about to change, then rsync -a --deletes dist/codex/skills/ over skills/ here and opens a PR on branch sync/skills, labelled skill-sync.

The --delete matters: skills/ is owned entirely by the base repo, so a file you add there by hand is removed by the next sync. Everything outside skills/ — .codex-plugin/, .agents/, .mcp.json, scripts/, docs/, README.md — is owned here and the rsync never sees it.

A PLUGIN_SYNC_PAT personal access token gives the upstream workflow push permission on this repo. The PR body carries the reconcile report and a git checkout plus build.py command that reproduces the diff byte for byte.

Changing what lands here: edit the skill in pinecone-io/skills, or edit targets/codex.yaml there if the difference is Codex-specific. Both live upstream, not in this repo.

4. Validators

All validators are plain Python 3 — stdlib only, no uv or pyyaml needed in CI. Run the whole suite locally:

python3 scripts/check_all.py
ScriptWhat it enforces
check_manifest.py .codex-plugin/plugin.json parses; has name, version, description, skills; name is lowercase kebab-case; version is semver; every path field (skills, mcpServers, hooks, apps, interface.composerIcon, interface.logo, interface.screenshots) starts with ./ and resolves to a real file; interface.brandColor is #RRGGBB if present.
check_marketplace.py .agents/plugins/marketplace.json parses; each entry has name, policy.installation, policy.authentication; each local source.path starts with ./, stays inside the repo, points at a directory containing .codex-plugin/plugin.json.
check_skills.py Every skills/*/SKILL.md has YAML frontmatter with name and description; name matches the directory name and does NOT start with pinecone- (catches a mis-rendered sync); no allowed-tools key (Claude-only); description is a single line, ≤ 1000 chars; body has no AskUserQuestion reference.
check_source_tags.py Every source_tag= literal in skills/**/*.py matches ^codex_plugin:[a-z0-9_]+(:[a-z0-9_]+)?$. Catches leakage from pinecone_skills:*, claude_code_plugin:*, cursor_plugin:*, etc.
check_links.py Every relative markdown link in skill docs (and README.md) resolves to an existing file inside the repo. HTTP(S), mailto, and anchor-only links are skipped.
check_all.py Thin wrapper that runs all of the above and aggregates exit codes. CI calls this.
If a validator fails in CI: the failure message names the file and the rule that tripped. Fix the file (don't relax the rule unless you're changing the conventions deliberately). Common culprits — a hand-edited SKILL.md whose name: no longer matches its directory, or a Python script carrying another plugin's source_tag prefix. If a sync PR trips either, the bug is in targets/codex.yaml upstream, not in the file here.

5. Release workflow

.github/workflows/release.yml fires on pull_request.types: [closed] against main and only proceeds when github.event.pull_request.merged == true. Bump type is decided by PR labels:

The job:

  1. Reads .codex-plugin/plugin.json, bumps the version, writes it back.
  2. Generates changelog bullets from gh pr view --json commits --jq '.commits[].messageHeadline', filtering out chore: and create-pull-request entries.
  3. Inserts a ## [X.Y.Z] - YYYY-MM-DD block after the # Changelog header.
  4. Commits as github-actions[bot], pushes the version-bump commit and a v<version> tag.
  5. Creates a GitHub release with auto-generated notes.

6. Codex plugin spec essentials

.codex-plugin/plugin.json shape

{
  "name": "pinecone",              // required, lowercase kebab-case
  "version": "0.1.0",              // semver
  "description": "...",            // user-facing summary
  "skills": "./skills/",           // path, must start with ./
  "mcpServers": "./.mcp.json",     // path, must start with ./
  "interface": {
    "displayName": "Pinecone",
    "category": "Productivity",
    "capabilities": ["Read", "Write"],
    "defaultPrompt": ["Use Pinecone to ...", "..."],
    "brandColor": "#10A37F"
  }
}

Path rules: every path is relative to the plugin root, must start with ./, and must stay inside the plugin root. Assets (icons, logos, screenshots) belong under ./assets/ when present.

.agents/plugins/marketplace.json shape

{
  "name": "pinecone-codex-plugins",
  "interface": { "displayName": "Pinecone for Codex" },
  "plugins": [
    {
      "name": "pinecone",
      "source": { "source": "local", "path": "./" },
      "policy": {
        "installation": "AVAILABLE",
        "authentication": "ON_INSTALL"
      },
      "category": "Productivity"
    }
  ]
}

For Git-backed entries the source object uses "source": "git-subdir" with url, path, and a ref or sha.

7. Adding a new skill manually

Skills belong in pinecone-io/skills, and the next sync deletes anything added here by hand. Add a skill directly only for a throwaway local test:

  1. Create skills/<skill-name>/SKILL.md. The directory name is the slug (bare, no pinecone- prefix).
  2. Frontmatter must contain name: <same-as-directory> and a single-line description. No allowed-tools key.
  3. If the skill ships Python helpers, put them in skills/<skill-name>/scripts/. Every Pinecone(...) call that sets source_tag= must use codex_plugin:<skill>[_<operation>].
  4. Run python3 scripts/check_all.py. Iterate until green.
  5. Update README.md's skills table.
  6. Open a PR. validate.yml will run. Merge once green and the release workflow will tag a new version.

8. Troubleshooting

SymptomLikely cause / fix
check_skills.py fails: "name still has pinecone- prefix" targets/codex.yaml upstream has the wrong skill_name. It must be "{slug}", with no prefix. Fix it there and re-run the sync; editing the file here is undone by the next one.
check_skills.py fails: "allowed-tools is a Claude Code field" Upstream copied a Claude-plugin SKILL.md by mistake. Strip the allowed-tools: frontmatter line.
check_source_tags.py fails with claude_code_plugin: or pinecone_skills: targets/codex.yaml upstream has the wrong source_tag. It must be codex_plugin. The suffix comes from the base script and is not per-target.
check_links.py fails on a references/foo.md path The reference file was moved or renamed; update the link or restore the file.
Release ran but didn't tag The release job only runs when the PR is merged (not just closed). Check the PR's merge state and the workflow logs for the "Determine bump type" step.
MCP not loading after install Codex needs npx on PATH; install Node.js. Confirm PINECONE_API_KEY is exported in the same shell that launched Codex.

Source: pinecone-io/pinecone-codex-plugin · base skills: pinecone-io/skills · Codex plugin docs: developers.openai.com/codex/plugins/build.