diff --git a/.agents/plugins/marketplace.json b/.agents/plugins/marketplace.json new file mode 100644 index 0000000..e55c740 --- /dev/null +++ b/.agents/plugins/marketplace.json @@ -0,0 +1,20 @@ +{ + "name": "theopenapps", + "interface": { + "displayName": "OpenApps" + }, + "plugins": [ + { + "name": "plugin-stack", + "source": { + "source": "local", + "path": "./" + }, + "policy": { + "installation": "AVAILABLE", + "authentication": "ON_INSTALL" + }, + "category": "Developer Tools" + } + ] +} diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 38940df..15802ee 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -5,8 +5,7 @@ "url": "https://theopenapps.com" }, "metadata": { - "description": "Skills for AI plugin builders, on live data from OpenApps", - "version": "0.1.0" + "description": "Skills for AI plugin builders, on live data from OpenApps" }, "plugins": [ { diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 24ba6ce..ebc1130 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,6 @@ { "name": "plugin-stack", "description": "Skills for AI plugin builders: optimize listings, submit to stores, audit discoverability, design widgets and watch competitors, on live data from OpenApps", - "version": "0.1.0", "author": { "name": "The Open Apps, Inc.", "url": "https://theopenapps.com" diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json index 8c90609..8ce23af 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -1,7 +1,6 @@ { "name": "plugin-stack", "description": "Skills for AI plugin builders: optimize listings, submit to stores, audit discoverability, design widgets and watch competitors, on live data from OpenApps", - "version": "0.1.0", "author": { "name": "The Open Apps, Inc.", "url": "https://theopenapps.com" diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml new file mode 100644 index 0000000..49be653 --- /dev/null +++ b/.github/workflows/check.yml @@ -0,0 +1,19 @@ +name: Check + +on: + push: + branches: [main] + pull_request: + +jobs: + check: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + - run: node scripts/check-skills.mjs + - run: npm install -g @anthropic-ai/claude-code @openai/codex + - run: scripts/test-installs.sh diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..c5d1d6e --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,3 @@ +# Agents + +Read [CONTRIBUTING.md](CONTRIBUTING.md) before changing a skill. Run `node scripts/check-skills.mjs` when you finish. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..43c994c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..e6544d9 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,42 @@ +# Contributing + +Open an issue for a bug, a wrong number or a skill you'd like. For a change, open a pull request against `main`. Every commit on `main` reaches plugin users as an update, so merge only what's ready. + +## Layout + +```text +skills// + SKILL.md When to use the skill, and its steps + references/ What a step needs, one level deep + LICENSE.txt +shared/ data.md, cli.md, mcp.md and api.md, copied into every skill's references/ +evals/ Routing queries and traps +scripts/ check-skills.mjs and test-installs.sh +.claude-plugin/ Claude Code plugin and marketplace +.codex-plugin/ Codex plugin +.agents/plugins/ Codex marketplace +``` + +## Rules + +`scripts/check-skills.mjs` enforces the first three. + +- A skill works alone. A single-skill install copies only that skill's folder, so a skill can't link to anything outside it. +- Skills name operations, such as `listings_versions`. Commands, tools and paths live in `shared/`. Edit `shared/`, then run `node scripts/check-skills.mjs --write` to copy it into every skill. +- Each store file starts with `Checked: YYYY-MM-DD against `. +- `SKILL.md` holds the steps. Anything only some runs need goes in `references/`, with a step in `SKILL.md` saying when to read it. +- Every number has a date and a basis, and a report says what it couldn't read. Leave out a claim you can't back. + +## Before you open a pull request + +```bash +node scripts/check-skills.mjs +``` + +```bash +scripts/test-installs.sh +``` + +The second installs the skills into clean folders, as plugins for Claude Code and Codex and through `npx skills` for 11 agents, and checks that each one got all of them. CI runs both. Add `--run` to also ask each signed-in agent on your machine to use a skill, which spends model credits. + +If you change a skill's description, run its queries from `evals/confusion-pool.json` with `evals/run_confusion.py`. If you change what a skill does, run its row in `evals/traps.md`. diff --git a/README.md b/README.md index 255929f..95293eb 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,143 @@ -# plugin-stack +# Plugin Stack: Agent Skills for AI Plugin Builders -**You built the plugin. Now get it picked.** +A collection of agent skills for getting an AI plugin into the stores, found and picked. Built for developers who ship ChatGPT apps, Claude plugins and connectors, Cursor plugins and MCP servers, and want their coding agent to help with submission, listing copy, discoverability, widget design and competitor tracking. Works with Claude Code, Codex, Cursor and any agent that supports [Agent Skills](https://agentskills.io). -Agent skills for AI plugins: ChatGPT apps, Claude plugins and connectors, Cursor plugins and MCP servers. They run on live store data from [OpenApps](https://theopenapps.com), which tracks about 29,000 listings across six stores and the MCP servers they link to, in 48 ChatGPT countries, every day. +Built by [OpenApps](https://theopenapps.com?ref=plugin-stack), which tracks about 29,000 listings across six stores and the MCP servers they link to, in 48 ChatGPT countries, every day. The skills run on that data. -## Install +Found a problem, or want a skill changed? [Open an issue](https://github.com/theopenapps/plugin-stack/issues). + +## What are skills? + +Skills are folders of instructions that an agent loads when a task calls for them. Once these are installed, ask your agent about your plugin in your own words. It picks the skill, reads live store data, and gives you a report or copy you can paste. + +## How the skills work together + +Start with `plugin-stack`. It reads your repo and the stores, saves what it learns to `.agents/plugin-stack.md`, and suggests your next steps. The other skills read that file if it's there, and each one also works alone. + +```text + ┌─────────────────────────────────┐ + │ plugin-stack │ + │ setup, one finding, next steps │ + └────────────────┬────────────────┘ + │ .agents/plugin-stack.md + ┌──────────────────────┼────────────────────────┐ + ▼ ▼ ▼ +┌────────────────┐ ┌───────────────────────┐ ┌───────────────────┐ +│ Ship │ │ Get found │ │ Keep up │ +├────────────────┤ ├───────────────────────┤ ├───────────────────┤ +│ submit-plugin │ │ optimize-listing │ │ watch-competitors │ +│ design-widgets │ │ audit-discoverability │ │ │ +└────────────────┘ └───────────────────────┘ └───────────────────┘ +``` + +## Skills + +| Skill | What you get | +|---|---| +| [`plugin-stack`](skills/plugin-stack/) | Setup, one finding about your plugin, and your next steps | +| [`submit-plugin`](skills/submit-plugin/) | A readiness check and submission kit for ChatGPT, Claude and Cursor, including the choices you can't change later | +| [`design-widgets`](skills/design-widgets/) | Rendered widgets from live ChatGPT apps, a critique of yours, and a redesign that says which moves have precedent | +| [`optimize-listing`](skills/optimize-listing/) | The words to target, field-by-field verdicts against your competitors, and paste-ready copy within the store's limits | +| [`audit-discoverability`](skills/audit-discoverability/) | Whether your listing and tools answer the prompts you care about, with a labeled simulated pick against competitors | +| [`watch-competitors`](skills/watch-competitors/) | Ranks, featuring, listing rewrites and tool changes side by side, and what changed since your last check | + +## Installation + +### Any agent: `npx skills` (recommended) ```bash npx skills add theopenapps/plugin-stack ``` -Add `--skill optimize-listing` to install one skill. Each one works alone. +Add `--skill optimize-listing` to install one skill. The CLI finds your agents and asks where to install. Inside an agent session it doesn't ask and writes only to `.agents/skills/`, which Claude Code doesn't read, so name your agent there: -In Claude Code you can also install it as a plugin: +```bash +npx skills add theopenapps/plugin-stack -a claude-code +``` + +### Claude Code plugin ```text /plugin marketplace add theopenapps/plugin-stack /plugin install plugin-stack@theopenapps ``` -## Skills +From a shell, use `claude plugin marketplace add theopenapps/plugin-stack`, then `claude plugin install plugin-stack@theopenapps`. To update, run `claude plugin marketplace update theopenapps`, then `claude plugin update plugin-stack@theopenapps`. -Ask your agent what to do next for your plugin. `plugin-stack` reads your repo and the stores, saves what it learns to `.agents/plugin-stack.md`, and suggests two or three next steps. The other skills read that file if it's there. +### Codex plugin -| Skill | What you get | -|---|---| -| `plugin-stack` | Setup, one finding about your plugin, and your next steps | -| `optimize-listing` | The words to target, field-by-field verdicts against your competitors, and paste-ready copy within the store's limits | -| `submit-plugin` | A readiness check and submission kit for ChatGPT, Claude and Cursor, including the choices you can't change later | -| `audit-discoverability` | Whether your listing and tools answer the prompts you care about, with a labeled simulated pick against competitors | -| `design-widgets` | Rendered widgets from live ChatGPT apps, a critique of yours, and a redesign that says which moves have precedent | -| `watch-competitors` | Ranks, featuring, listing rewrites and tool changes side by side, and what changed since your last check | +```bash +codex plugin marketplace add theopenapps/plugin-stack +``` -## What they can't tell you +```bash +codex plugin add plugin-stack@theopenapps +``` -No study yet shows that listing rewrites move ranks. The discoverability pick is a simulation, not a store's real search. Each report says so, and dates every number. +To update, run `codex plugin marketplace upgrade theopenapps`. + +### Copy a folder + +Each folder in `skills/` is complete, so you can copy one into your agent's skills folder: + +```bash +git clone https://github.com/theopenapps/plugin-stack +``` + +```bash +cp -r plugin-stack/skills/optimize-listing .claude/skills/ +``` + +### What we've tested + +Last run on 2026-11-05 from GitHub. + +| Agent | `npx skills` | Plugin | +|---|---|---| +| Claude Code 2.1.303 | Session | Session | +| Codex 0.166.0 | Session | Session | +| Cursor 2026.10.14 | Session | | +| OpenCode, Amp, Gemini CLI, GitHub Copilot, Windsurf, Cline, Goose, Pi | Files in place | | + +In a session, the agent found the skill, read its reference file and read OpenApps data. For the others we checked that the files landed and didn't run the agent. `scripts/test-installs.sh --run` repeats this on your machine. + +## Usage + +Ask in your own words: + +```text +"We built the plugin. Now what?" +→ plugin-stack + +"How do I get my MCP server listed on the Claude connectors directory?" +→ submit-plugin + +"What do the widgets from Trip.com and Kiwi look like inside ChatGPT?" +→ design-widgets + +"Is our live Claude plugin's store description good enough?" +→ optimize-listing + +"My app has installs but nobody's agent calls it. How do I figure out what's wrong?" +→ audit-discoverability + +"Kiwi rewrote their description last week. What did they change?" +→ watch-competitors +``` + +In Claude Code you can also call one by name: `/watch-competitors`, or `/plugin-stack:watch-competitors` from the plugin. ## Data Each skill reads OpenApps through the CLI when it has a shell, the MCP server when it doesn't, and the REST API when all it can do is fetch a URL. You don't need an account. Signed out, the skills read the United States and 7 days of history. A free account adds every country, 30 days and more rows per list: run `npx -y @theopenapps/cli@latest auth login`. If a limit cuts something from a report, the report says what's missing. -## Changing the skills +## What they can't tell you + +No study yet shows that listing rewrites move ranks. The discoverability pick is a simulation, not a store's real search. Each report says so, and dates every number. + +## Contributing -Skills name operations, such as `listings_versions`. Commands, tools and paths live in `shared/`, which every skill carries a copy of, so a single-skill install still works. Edit `shared/`, then run `node scripts/check-skills.mjs --write`. +Fixes and new skills are welcome. [CONTRIBUTING.md](CONTRIBUTING.md) covers how a skill is laid out and how to check it. ## License diff --git a/scripts/check-skills.mjs b/scripts/check-skills.mjs index 5c66278..bba6aea 100644 --- a/scripts/check-skills.mjs +++ b/scripts/check-skills.mjs @@ -78,6 +78,11 @@ for (const skill of skills) { if (licenses.size > 1) fail("LICENSE.txt", `differs across skills: ${[...licenses.values()].map((s) => s.join(", ")).join(" | ")}`); +// Claude Code holds back an update until the version changes. With no version, every commit on main is an update. +for (const manifest of [".claude-plugin/plugin.json", ".codex-plugin/plugin.json"]) { + if ("version" in JSON.parse(readFileSync(manifest, "utf8"))) fail(manifest, "has a version"); +} + if (errors.length) { console.error(errors.join("\n")); process.exit(1); diff --git a/scripts/test-installs.sh b/scripts/test-installs.sh new file mode 100755 index 0000000..3e3f4cd --- /dev/null +++ b/scripts/test-installs.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +# Installs the skills the way a user would, into clean folders, and checks that each agent got all of them. +# scripts/test-installs.sh from this checkout +# scripts/test-installs.sh theopenapps/plugin-stack from GitHub +# scripts/test-installs.sh --run [source] then asks each signed-in agent here to use a skill (spends model credits) +set -uo pipefail +cd "$(dirname "$0")/.." +run=; [ "${1:-}" = --run ] && { run=1; shift; } +source=${1:-$PWD} +want=$(ls skills | wc -l | tr -d ' ') +tmp=$(mktemp -d); trap 'rm -rf "$tmp"' EXIT +failed=0 + +report() { printf '%-5s %s\n' "$1" "$2"; [ "$1" != FAIL ] || failed=1; } +expect() { # label, folder, how many skills + local got; got=$(find "$2" -name SKILL.md 2>/dev/null | wc -l | tr -d ' ') + if [ "$got" = "$3" ]; then report ok "$1: $got skills"; else report FAIL "$1: $got skills, wanted $3"; fi +} +has() { command -v "$1" >/dev/null; } + +claude_cache="$tmp/claude/plugins/cache/theopenapps/plugin-stack" +codex_cache="$tmp/codex/plugins/cache/theopenapps/plugin-stack" + +if has claude; then + [ "$source" != "$PWD" ] || claude plugin validate "$PWD" >/dev/null 2>&1 || report FAIL "claude plugin validate" + export CLAUDE_CONFIG_DIR="$tmp/claude" + { claude plugin marketplace add "$source" && claude plugin install plugin-stack@theopenapps; } >"$tmp/claude.log" 2>&1 + unset CLAUDE_CONFIG_DIR + expect "Claude Code plugin" "$claude_cache" "$want" +else report skip "Claude Code plugin: no claude here"; fi + +if has codex; then + mkdir -p "$tmp/codex" + { CODEX_HOME="$tmp/codex" codex plugin marketplace add "$source" && CODEX_HOME="$tmp/codex" codex plugin add plugin-stack@theopenapps; } >"$tmp/codex.log" 2>&1 + expect "Codex plugin" "$codex_cache" "$want" +else report skip "Codex plugin: no codex here"; fi + +for agent in claude-code codex cursor opencode amp gemini-cli github-copilot windsurf cline goose pi; do + mkdir -p "$tmp/skills/$agent" + (cd "$tmp/skills/$agent" && npx -y skills add "$source" -a "$agent" --copy -y) >"$tmp/skills/$agent.log" 2>&1 + expect "npx skills -a $agent" "$tmp/skills/$agent" "$want" +done + +mkdir -p "$tmp/one" +(cd "$tmp/one" && npx -y skills add "$source" --skill optimize-listing -a claude-code --copy -y) >"$tmp/one.log" 2>&1 +expect "npx skills, one skill" "$tmp/one" 1 +for file in data cli mcp api; do + [ -f "$tmp/one/.claude/skills/optimize-listing/references/$file.md" ] || report FAIL "one skill: references/$file.md is missing" +done + +if [ -n "$run" ]; then + ask='Use the optimize-listing skill. Read its references/data.md, pick an OpenApps surface the way that file says, then read the top 3 apps on the ChatGPT store Featured chart. Reply with exactly three lines: SKILL=, SURFACE=, TOP3=.' + session() { # label, folder, command + local label=$1 dir=$2 out; shift 2; out="$tmp/$(echo "$label" | tr ' ' -).txt" + has "$1" || { report skip "$label: no $1 here"; return; } + (cd "$dir" && perl -e 'alarm shift; exec @ARGV' 300 "$@" "$out" 2>&1 + if grep -q "SKILL=.*$(basename "$tmp").*optimize-listing/SKILL.md" "$out" && grep -q 'TOP3=.' "$out"; then + report ok "$label: $(grep 'TOP3=' "$out" | tail -1)" + elif grep -qiE 'billing|log ?in|expired|unauthorized|not authenticated' "$out"; then + report skip "$label: not signed in" + else report FAIL "$label: $(tail -1 "$out" | cut -c1-120)"; fi + } + codex_args=(exec --skip-git-repo-check --dangerously-bypass-approvals-and-sandbox -c model_reasoning_effort=low) + [ -z "${CODEX_MODEL:-}" ] || codex_args+=(-m "$CODEX_MODEL") + mkdir -p "$tmp/w" "$tmp/codex-empty" + ln -sf "$HOME/.codex/auth.json" "$tmp/codex/auth.json"; ln -sf "$HOME/.codex/auth.json" "$tmp/codex-empty/auth.json" + session "Claude Code plugin session" "$tmp/w" claude -p "$ask" --plugin-dir "$(find "$claude_cache" -mindepth 1 -maxdepth 1 -type d | head -1)" --strict-mcp-config --model sonnet --dangerously-skip-permissions & + CODEX_HOME="$tmp/codex" session "Codex plugin session" "$tmp/w" codex "${codex_args[@]}" "$ask" & + session "Claude Code skills session" "$tmp/skills/claude-code" claude -p "$ask" --strict-mcp-config --model sonnet --dangerously-skip-permissions & + CODEX_HOME="$tmp/codex-empty" session "Codex skills session" "$tmp/skills/codex" codex "${codex_args[@]}" "$ask" & + session "Cursor skills session" "$tmp/skills/cursor" cursor-agent -p "$ask" --force --output-format text & + session "OpenCode skills session" "$tmp/skills/opencode" opencode run "$ask" & + session "Amp skills session" "$tmp/skills/amp" amp -x "$ask" --dangerously-allow-all & + wait +fi + +[ "$failed" = 0 ] && echo "installs pass" || { echo "installs failed"; exit 1; }