-
Notifications
You must be signed in to change notification settings - Fork 2.7k
CTX7-1584: add Codex plugin and plugin sync script #2512
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| { | ||
| "name": "context7-marketplace", | ||
| "interface": { | ||
| "displayName": "Context7" | ||
| }, | ||
| "owner": { | ||
| "name": "Upstash", | ||
| "url": "https://upstash.com" | ||
| }, | ||
| "plugins": [ | ||
| { | ||
| "name": "context7", | ||
| "source": { | ||
| "source": "git-subdir", | ||
| "url": "https://github.com/upstash/context7.git", | ||
| "path": "./plugins/codex/context7", | ||
| "ref": "master" | ||
| }, | ||
| "policy": { | ||
| "installation": "AVAILABLE", | ||
| "authentication": "ON_INSTALL" | ||
| }, | ||
| "category": "Productivity", | ||
| "description": "Up-to-date documentation lookup for libraries, frameworks, SDKs, and APIs.", | ||
| "version": "1.0.0" | ||
| } | ||
| ] | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| name: Sync plugins | ||
|
|
||
| on: | ||
| push: | ||
| branches: [master] | ||
| paths: | ||
| - "rules/**" | ||
| - "skills/**" | ||
| - "scripts/sync-plugins.ts" | ||
| - ".github/workflows/sync-plugins.yml" | ||
| pull_request: | ||
| paths: | ||
| - "rules/**" | ||
| - "skills/**" | ||
| - "plugins/**" | ||
| - "scripts/sync-plugins.ts" | ||
| - ".github/workflows/sync-plugins.yml" | ||
|
|
||
| permissions: | ||
| contents: write | ||
|
|
||
| concurrency: | ||
| group: sync-plugins-${{ github.event.pull_request.head.ref || github.ref }} | ||
| cancel-in-progress: false | ||
|
|
||
| jobs: | ||
| sync: | ||
| if: github.actor != 'github-actions[bot]' | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v6 | ||
| with: | ||
| ref: ${{ github.head_ref || github.ref_name }} | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
| fetch-depth: 0 | ||
|
|
||
| - name: Setup Node | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: "20" | ||
|
|
||
| - name: Setup pnpm | ||
| uses: pnpm/action-setup@v4 | ||
| with: | ||
| version: 10 | ||
|
|
||
| - name: Install dependencies | ||
| run: pnpm install --frozen-lockfile | ||
|
|
||
| - name: Run sync | ||
| id: sync | ||
| run: | | ||
| pnpm sync:plugins | ||
| if [[ -n "$(git status --porcelain)" ]]; then | ||
| echo "changed=true" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "changed=false" >> "$GITHUB_OUTPUT" | ||
| fi | ||
|
|
||
| - name: Commit synced files | ||
| if: steps.sync.outputs.changed == 'true' && (github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository) | ||
| run: | | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | ||
| git add -A -- ':!pnpm-lock.yaml' | ||
| git commit -m "chore: sync plugin files from rules/skills" | ||
| git push | ||
|
|
||
| - name: Fail on drift in fork PR | ||
| if: steps.sync.outputs.changed == 'true' && github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository | ||
| run: | | ||
| echo "Plugins are out of sync with rules/skills." | ||
| echo "Run 'pnpm sync:plugins' locally and commit the result." | ||
| exit 1 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| { | ||
| "name": "context7", | ||
| "version": "1.0.0", | ||
| "description": "Up-to-date documentation lookup for libraries, frameworks, SDKs, and APIs. Pulls version-specific docs and code examples directly from source repositories into Codex.", | ||
| "author": { | ||
| "name": "Upstash", | ||
| "url": "https://upstash.com" | ||
| }, | ||
| "homepage": "https://context7.com", | ||
| "repository": "https://github.com/upstash/context7", | ||
| "license": "MIT", | ||
| "keywords": [ | ||
| "context7", | ||
| "documentation", | ||
| "mcp", | ||
| "library-docs", | ||
| "framework-docs", | ||
| "api-reference", | ||
| "code-examples" | ||
| ], | ||
| "skills": "./skills/", | ||
| "mcpServers": "./.mcp.json", | ||
| "interface": { | ||
| "displayName": "Context7", | ||
| "shortDescription": "Up-to-date code docs for any prompt", | ||
| "longDescription": "Context7 fetches current documentation directly from source repositories so Codex stops relying on stale training data or hallucinated APIs. Ask about any library, framework, SDK, or CLI tool and get version-specific answers grounded in real docs.", | ||
| "developerName": "Upstash", | ||
| "category": "Productivity", | ||
| "websiteURL": "https://context7.com", | ||
| "privacyPolicyURL": "https://upstash.com/trust/privacy.pdf", | ||
| "termsOfServiceURL": "https://upstash.com/trust/terms.pdf", | ||
| "defaultPrompt": [ | ||
| "How do I set up authentication in Next.js 15?", | ||
| "Show me the latest Prisma syntax for relations.", | ||
| "What are the Supabase Row Level Security best practices?" | ||
| ], | ||
| "brandColor": "#059669", | ||
| "composerIcon": "./assets/icon.png", | ||
| "logo": "./assets/logo.svg" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| { | ||
| "mcpServers": { | ||
| "context7": { | ||
| "type": "http", | ||
| "url": "https://mcp.context7.com/mcp" | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| # Context7 Plugin for OpenAI Codex | ||
|
|
||
| Context7 grounds Codex in real documentation. Instead of relying on stale training data, it fetches version-specific docs and code examples directly from source repositories. | ||
|
|
||
| ## What's Included | ||
|
|
||
| - **MCP server** for the Context7 documentation service (`resolve-library-id`, `query-docs`) | ||
| - **Skill** that auto-triggers documentation lookups when you ask about libraries, frameworks, SDKs, or APIs | ||
|
|
||
| The skill body is generated from the canonical rule at [`rules/context7-mcp.md`](../../../rules/context7-mcp.md). The `sync-plugins` GitHub Action regenerates and commits this file whenever the source rule changes. To regenerate locally, run `pnpm sync:plugins` from the repo root. | ||
|
|
||
| ## Installation | ||
|
|
||
| Add the marketplace and install the plugin: | ||
|
|
||
| ```bash | ||
| codex plugin marketplace add upstash/context7 | ||
| codex plugin install context7@context7-marketplace | ||
| ``` | ||
|
|
||
| ## Authentication (optional) | ||
|
|
||
| Most usage works without an API key. For higher rate limits, set: | ||
|
|
||
| ```bash | ||
| export CONTEXT7_API_KEY=your_key | ||
| ``` | ||
|
|
||
| You can get a key at https://context7.com. | ||
|
Comment on lines
+21
to
+29
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe we can slighlt improve this to mention it's important for private sources, research mode etc. and update the url to point to dashboard? |
||
|
|
||
| ## Usage | ||
|
|
||
| The skill activates automatically when you ask about any library or framework, for example: | ||
|
|
||
| - "How do I set up authentication in Next.js 15?" | ||
| - "Show me React Server Components examples" | ||
| - "What's the Prisma syntax for relations?" | ||
|
|
||
| For version-specific docs, mention the version or pass a version-pinned library ID: | ||
|
|
||
| ``` | ||
| /vercel/next.js/v15.1.8 | ||
| /facebook/react/v19.0.0 | ||
|
Comment on lines
+35
to
+43
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we can update the examples to next 16 maybe? |
||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| --- | ||
| name: context7-mcp | ||
| description: This skill should be used when the user asks about libraries, frameworks, API references, or needs code examples. Activates for setup questions, code generation involving libraries, or mentions of specific frameworks like React, Vue, Next.js, Prisma, Supabase, etc. | ||
| --- | ||
|
|
||
| Use Context7 MCP to fetch current documentation whenever the user asks about a library, framework, SDK, API, CLI tool, or cloud service -- even well-known ones like React, Next.js, Prisma, Express, Tailwind, Django, or Spring Boot. This includes API syntax, configuration, version migration, library-specific debugging, setup instructions, and CLI tool usage. Use even when you think you know the answer -- your training data may not reflect recent changes. Prefer this over web search for library docs. | ||
|
|
||
| Do not use for: refactoring, writing scripts from scratch, debugging business logic, code review, or general programming concepts. | ||
|
|
||
| ## Steps | ||
|
|
||
| 1. Always start with `resolve-library-id` using the library name and the user's question, unless the user provides an exact library ID in `/org/project` format | ||
| 2. Pick the best match (ID format: `/org/project`) by: exact name match, description relevance, code snippet count, source reputation (High/Medium preferred), and benchmark score (higher is better). If results don't look right, try alternate names or queries (e.g., "next.js" not "nextjs", or rephrase the question). Use version-specific IDs when the user mentions a version | ||
| 3. `query-docs` with the selected library ID and the user's full question (not single words) | ||
| 4. If you weren't satisfied with the answer, call `query-docs` again for the same library with `researchMode: true`. This retries with sandboxed agents that git-pull the actual source repos plus a live web search, then synthesizes a fresh answer. More costly than the default | ||
| 5. Answer using the fetched docs |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| #!/usr/bin/env tsx | ||
| import { readFileSync, writeFileSync, mkdirSync } from "node:fs"; | ||
| import { dirname, resolve } from "node:path"; | ||
|
|
||
| const repoRoot = process.cwd(); | ||
|
|
||
| type Transform = (body: string) => string; | ||
|
|
||
| interface SyncEntry { | ||
| name: string; | ||
| source: string; | ||
| target: string; | ||
| transform?: Transform; | ||
| } | ||
|
|
||
| // Each entry maps a canonical source file (under rules/ or skills/) to a | ||
| // generated plugin file. Add a new entry when another plugin needs to track | ||
| // a shared source. Keep canonical files editable; targets are regenerated by | ||
| // `pnpm sync:plugins` and by the sync-plugins workflow. | ||
| // | ||
| // - Raw copy (no transform): the target ends up byte-for-byte identical to | ||
| // the source, including any YAML frontmatter the source already carries. | ||
| // - Transform: receives the source body and returns the target content. | ||
| // Transforms can read other canonical files (e.g. to inherit a description | ||
| // from a different skill) so frontmatter stays in lockstep with one place. | ||
| const SYNCS: SyncEntry[] = [ | ||
| { | ||
| name: "claude context7-mcp skill", | ||
| source: "skills/context7-mcp/SKILL.md", | ||
| target: "plugins/claude/context7/skills/context7-mcp/SKILL.md", | ||
| }, | ||
| { | ||
| name: "cursor context7-mcp skill", | ||
| source: "skills/context7-mcp/SKILL.md", | ||
| target: "plugins/cursor/context7/skills/context7-mcp/SKILL.md", | ||
| }, | ||
| { | ||
| name: "codex context7-mcp skill", | ||
| source: "rules/context7-mcp.md", | ||
| target: "plugins/codex/context7/skills/context7-mcp/SKILL.md", | ||
| transform: prependFrontmatterFromSkill("skills/context7-mcp/SKILL.md"), | ||
| }, | ||
| ]; | ||
|
|
||
| // Returns a transform that prepends the YAML frontmatter from another skill | ||
| // file. Used so the codex plugin's skill (whose body is the terse rule, not | ||
| // the long-form skill) still carries the canonical name + description. | ||
| function prependFrontmatterFromSkill(skillPath: string): Transform { | ||
| return (body) => { | ||
| const content = readFileSync(resolve(repoRoot, skillPath), "utf8"); | ||
| const match = content.match(/^---\n[\s\S]*?\n---\n/); | ||
| if (!match) { | ||
| throw new Error(`No YAML frontmatter found in ${skillPath}`); | ||
| } | ||
| return `${match[0]}\n${body}`; | ||
| }; | ||
| } | ||
|
|
||
| const checkOnly = process.argv.includes("--check"); | ||
| const drift: string[] = []; | ||
|
|
||
| for (const { name, source, target, transform } of SYNCS) { | ||
| const sourcePath = resolve(repoRoot, source); | ||
| const targetPath = resolve(repoRoot, target); | ||
| const body = readFileSync(sourcePath, "utf8"); | ||
| const next = transform ? transform(body) : body; | ||
|
|
||
| let current = ""; | ||
| try { | ||
| current = readFileSync(targetPath, "utf8"); | ||
| } catch {} | ||
|
|
||
| if (current === next) { | ||
| console.log(`ok ${name}`); | ||
| continue; | ||
| } | ||
|
|
||
| if (checkOnly) { | ||
| drift.push(name); | ||
| console.error(`drift ${name} -> ${target}`); | ||
| continue; | ||
| } | ||
|
|
||
| mkdirSync(dirname(targetPath), { recursive: true }); | ||
| writeFileSync(targetPath, next); | ||
| console.log(`wrote ${name} -> ${target}`); | ||
| } | ||
|
|
||
| if (checkOnly && drift.length > 0) { | ||
| console.error(`\n${drift.length} file(s) out of sync. Run: pnpm sync:plugins`); | ||
| process.exit(1); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there a developer tool category? I couldn't see other allowed fields in the docs though https://developers.openai.com/codex/plugins/build#package-and-distribute-plugins