Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .agents/plugins/marketplace.json
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",
Copy link
Copy Markdown
Collaborator

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

"description": "Up-to-date documentation lookup for libraries, frameworks, SDKs, and APIs.",
"version": "1.0.0"
}
]
}
75 changes: 75 additions & 0 deletions .github/workflows/sync-plugins.yml
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
4 changes: 3 additions & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ export default tseslint.config({
ecmaVersion: 2020,
sourceType: "module",
parser: tseslint.parser,
parserOptions: {},
parserOptions: {
tsconfigRootDir: import.meta.dirname,
},
globals: {
// Add Node.js globals
process: "readonly",
Expand Down
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
"lint:check": "pnpm -r run lint:check",
"format": "pnpm -r run format",
"format:check": "pnpm -r run format:check",
"sync:plugins": "tsx scripts/sync-plugins.ts",
"sync:plugins:check": "tsx scripts/sync-plugins.ts --check",
"release": "pnpm build && changeset publish",
"release:snapshot": "changeset version --snapshot canary && pnpm build && changeset publish --tag canary --no-git-tag"
},
Expand Down Expand Up @@ -51,6 +53,7 @@
"eslint-config-prettier": "^10.1.1",
"eslint-plugin-prettier": "^5.2.5",
"prettier": "^3.6.2",
"tsx": "^4.20.3",
"typescript": "^5.8.2",
"typescript-eslint": "^8.28.0"
},
Expand Down
41 changes: 41 additions & 0 deletions plugins/codex/context7/.codex-plugin/plugin.json
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"
}
}
8 changes: 8 additions & 0 deletions plugins/codex/context7/.mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"mcpServers": {
"context7": {
"type": "http",
"url": "https://mcp.context7.com/mcp"
}
}
}
44 changes: 44 additions & 0 deletions plugins/codex/context7/README.md
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
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The 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
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can update the examples to next 16 maybe?

```
Binary file added plugins/codex/context7/assets/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions plugins/codex/context7/assets/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions plugins/codex/context7/skills/context7-mcp/SKILL.md
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
8 changes: 4 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

92 changes: 92 additions & 0 deletions scripts/sync-plugins.ts
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);
}
Loading