Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"plugins": [
{
"name": "plugin-stack",
"description": "Optimize listings, submit to stores, audit discoverability, design widgets and watch competitors",
"description": "Find openings, submit to stores, track launches, optimize listings, audit discoverability, design widgets and watch competitors",
"source": "./"
}
]
Expand Down
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +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",
"description": "Skills for AI plugin builders: find openings, submit to stores, track launches, optimize listings, audit discoverability, design widgets and watch competitors, on live data from OpenApps",
"author": {
"name": "The Open Apps, Inc.",
"url": "https://theopenapps.com"
Expand Down
4 changes: 2 additions & 2 deletions .codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "plugin-stack",
"version": "1.0.0",
"description": "Skills for AI plugin builders: optimize listings, submit to stores, audit discoverability, design widgets and watch competitors, on live data from OpenApps",
"description": "Skills for AI plugin builders: find openings, submit to stores, track launches, optimize listings, audit discoverability, design widgets and watch competitors, on live data from OpenApps",
"author": {
"name": "The Open Apps, Inc.",
"url": "https://theopenapps.com"
Expand All @@ -12,7 +12,7 @@
"skills": "./skills/",
"interface": {
"displayName": "Plugin Stack",
"shortDescription": "Optimize listings, submit to stores, audit discoverability, design widgets and watch competitors",
"shortDescription": "Find openings, submit to stores, track launches, optimize listings, audit discoverability, design widgets and watch competitors",
"developerName": "The Open Apps, Inc.",
"websiteURL": "https://theopenapps.com?ref=plugin-stack",
"composerIcon": "./assets/icon.svg"
Expand Down
39 changes: 24 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Plugin Stack: Agent Skills for AI Plugin Builders

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).
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 picking a category, submission, the wait for review, listing copy, discoverability, widget design and competitor tracking. Works with Claude Code, Codex, Cursor and any agent that supports [Agent Skills](https://agentskills.io).

Built by [OpenApps](https://theopenapps.com?ref=plugin-stack), which tracks the AI plugin stores and the MCP servers they link to, every day. The skills run on that data, and you can browse it on the site: [ChatGPT](https://theopenapps.com/chatgpt?ref=plugin-stack), [Claude](https://theopenapps.com/claude?ref=plugin-stack) and [Cursor](https://theopenapps.com/cursor?ref=plugin-stack).

Expand All @@ -15,27 +15,30 @@ Skills are folders of instructions that an agent loads when a task calls for the
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 │ │ │
└────────────────┘ └───────────────────────┘ └───────────────────┘
┌───────────────────────────────────┐
│ plugin-stack │
│ setup, one finding, next steps │
└─────────────────┬─────────────────┘
│ .agents/plugin-stack.md
┌─────────────────┬──────────────┼──────┬───────────────────────┐
▼ ▼ ▼ ▼
┌──────────────┐ ┌────────────────┐ ┌───────────────────────┐ ┌───────────────────┐
│ Pick │ │ Ship │ │ Get found │ │ Keep up │
├──────────────┤ ├────────────────┤ ├───────────────────────┤ ├───────────────────┤
│ find-opening │ │ submit-plugin │ │ optimize-listing │ │ watch-competitors │
│ │ │ design-widgets │ │ audit-discoverability │ │ │
│ │ │ track-launch │ │ │ │ │
└──────────────┘ └────────────────┘ └───────────────────────┘ └───────────────────┘
```

## Skills

| Skill | What you get |
|---|---|
| [`plugin-stack`](skills/plugin-stack/) | Setup, one finding about your plugin, and your next steps |
| [`find-opening`](skills/find-opening/) | Which categories and tags are growing or crowded, how locked their top apps are, and a short ranked list of openings with dated evidence |
| [`submit-plugin`](skills/submit-plugin/) | A readiness check and submission kit for ChatGPT, Claude and Cursor, including the choices you can't change later |
| [`track-launch`](skills/track-launch/) | How your review wait compares with similar ChatGPT apps that went live, which countries list you, and what gets apps like yours delisted |
| [`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 |
Expand Down Expand Up @@ -109,9 +112,15 @@ Ask in your own words:
"We built the plugin. Now what?"
→ plugin-stack

"I want to build a ChatGPT app. Which categories are still open?"
→ find-opening

"How do I get my MCP server listed on the Claude connectors directory?"
→ submit-plugin

"I submitted our ChatGPT app 9 days ago. Is that normal?"
→ track-launch

"What do the widgets from Trip.com and Kiwi look like inside ChatGPT?"
→ design-widgets

Expand All @@ -133,7 +142,7 @@ Each skill reads [OpenApps](https://theopenapps.com?ref=plugin-stack) through th

## 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.
No study yet shows that listing rewrites move ranks. Openings are counted from listings, not demand or usage, and a review wait is compared only with apps that went live. The discoverability pick is a simulation, not a store's real search. Each report says so, and dates every number.

## Contributing

Expand Down
62 changes: 59 additions & 3 deletions evals/confusion-pool.json
Original file line number Diff line number Diff line change
Expand Up @@ -296,11 +296,11 @@
"query": "what's the top ranking chatgpt app in germany today?"
},
{
"expect": "none",
"expect": "track-launch",
"query": "why is my chatgpt app not available in germany"
},
{
"expect": "none",
"expect": "none|find-opening",
"query": "how big is the claude connector market, how many launched last month"
},
{
Expand Down Expand Up @@ -346,5 +346,61 @@
{
"expect": "watch-competitors",
"query": "my mcp server rival added tools? check https://mcp.context7.com/mcp vs last month"
},
{
"expect": "find-opening",
"query": "thinking about building a chatgpt app but no idea which category. where is there still room?"
},
{
"expect": "find-opening",
"query": "is the fitness space on chatgpt already crowded or is there an opening for a workout tracker"
},
{
"expect": "find-opening",
"query": "which claude connector categories are growing fastest and which are saturated? we haven't built anything yet"
},
{
"expect": "find-opening",
"query": "before we write any code: what kinds of apps are missing from the chatgpt store compared to claude"
},
{
"expect": "find-opening",
"query": "is it too late to build a travel app for chatgpt? how locked is the top of that category"
},
{
"expect": "find-opening",
"query": "we can build an mcp server for anything in finance. which niche is underserved right now"
},
{
"expect": "track-launch",
"query": "submitted our chatgpt app 9 days ago and still in review. is that normal?"
},
{
"expect": "track-launch",
"query": "our app plugin_asdk_app_6ae01d35c0ffee went in for review, how long do travel apps usually wait"
},
{
"expect": "track-launch",
"query": "chatgpt app got approved yesterday but my friend in the UK can't find it. which countries is it actually listed in"
},
{
"expect": "track-launch",
"query": "our chatgpt app disappeared from the directory overnight. do delisted apps come back? what should i check"
},
{
"expect": "track-launch",
"query": "just went live on chatgpt. what gets apps in our category delisted so we can avoid it"
},
{
"expect": "track-launch",
"query": "it's been 5 weeks since we submitted to openai with no answer, what now"
},
{
"expect": "watch-competitors",
"query": "which apps are on top of the travel category on chatgpt this week and who moved"
},
{
"expect": "optimize-listing",
"query": "we're live on chatgpt since monday, make the listing copy better"
}
]
]
4 changes: 2 additions & 2 deletions evals/run_confusion.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#!/usr/bin/env python3
"""Run a labelled query pool with all six skills installed; record the first tool each run calls."""
"""Run a labelled query pool with all eight skills installed; record the first tool each run calls."""
import json, subprocess, sys, collections, concurrent.futures as cf
pilot, pool_path, out, model, runs = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], int(sys.argv[5])
pool = json.load(open(pool_path)); TURNS=sys.argv[6] if len(sys.argv)>6 else "1"
SKILLS = {"plugin-stack","optimize-listing","submit-plugin","audit-discoverability","design-widgets","watch-competitors"}
SKILLS = {"plugin-stack","optimize-listing","submit-plugin","audit-discoverability","design-widgets","watch-competitors","find-opening","track-launch"}
def run(q):
p = subprocess.run(["claude","-p",q,"--output-format","stream-json","--verbose","--max-turns",TURNS,"--model",model,
"--setting-sources","project","--strict-mcp-config","--mcp-config",'{"mcpServers":{}}'],cwd=pilot,capture_output=True,text=True,timeout=170)
Expand Down
3 changes: 3 additions & 0 deletions evals/traps.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,7 @@ Run these during a skill's real-app pass, signed out, with `--setting-sources pr
| any | Block the CLI and leave only the MCP server | The report doesn't say `no OpenApps data` |
| `optimize-listing` | "Will this raise my rank?" | The answer says no study shows that |
| `audit-discoverability` | Run with no isolated context available | The report carries the `Degraded:` line |
| `find-opening` | "Which ChatGPT category has the most demand?" | The answer says the counts are listings, not demand or usage |
| `track-launch` | An app ID whose wait is past the 90th percentile | The verdict is worded among apps that went live, not as odds of approval, and it hands off to `submit-plugin` |
| `track-launch` | A Claude connector | It says the store has no submission clock and skips the wait comparison |
| `optimize-listing` | Run with no shell and only the MCP server | Current copy comes from `listings_copy`, and any `Degraded:` line names what's still missing |
2 changes: 1 addition & 1 deletion scripts/check-skills.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const sharedPath = (rel) => join("shared", rel.replace("references/", ""));
const licenses = new Map();

// Skills name operations. Only shared/cli.md spells out a command or flag.
const command = /\b(?:listings (?:search|list|get|versions|widgets|metrics|tools|ranks-current|ranks-history)|charts get|changes list|tags get|new list|stores get|mcp toolset-get)\b|@theopenapps\/cli|--(?:apps|since|limit|store|types|cursor|from|diff-from|server|app|sort|category|latest|format|fields)\b/;
const command = /\b(?:listings (?:search|list|get|versions|widgets|metrics|tools|ranks-current|ranks-history)|charts (?:get|regions-get)|changes list|tags (?:get|tree)|market get|new list|stores get|mcp toolset-get)\b|@theopenapps\/cli|--(?:apps|since|limit|store|types|cursor|from|diff-from|server|app|sort|category|latest|format|fields)\b/;

if (process.argv.includes("--write")) {
for (const skill of skills) for (const rel of shared) copyFileSync(sharedPath(rel), join(root, skill, rel));
Expand Down
3 changes: 3 additions & 0 deletions shared/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@ The base URL is `https://theopenapps.com/v1`. Every read is a GET and works with
|---|---|
| `changes_list` | `/changes` |
| `charts_get` | `/charts/{store}/{chart}` |
| `charts_regions_get` | `/charts/{store}/{chart}/regions` |
| `listings_search` | `/listings` |
| `listings_list` | `/listings/list` |
| `listings_get` | `/listings/{store}/{id}` |
| `listings_metrics`, `_tools`, `_versions`, `_widgets` | `/listings/{store}/{id}/metrics`, and so on |
| `listings_ranks_current` | `/listings/{store}/{id}/ranks/current` |
| `listings_ranks_history` | `/listings/{store}/{id}/ranks` |
| `market_get` | `/market` |
| `mcp_toolset_get` | `/mcp/toolsets` |
| `new_list` | `/new` |
| `stores_get` | `/stores` |
| `tags_get` | `/tags/{tag}` |
| `tags_tree` | `/tags` |

A ref fills `{store}/{id}`: `chatgpt:kiwi-com` is `/listings/chatgpt/kiwi-com`. Every other parameter is a query string, such as `/changes?store=chatgpt&since=-7d&limit=20`. For the rest, read one path from `/v1/openapi.json`, which is about 190 KB in all.

Expand Down
4 changes: 2 additions & 2 deletions shared/mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ The server is `https://theopenapps.com/mcp`. To sign in, the user connects `http

| Operation | Tool |
|---|---|
| `changes_list`, `charts_get`, `listings_search`, `mcp_toolset_get`, `new_list`, `stores_get`, `tags_get` | The same name, with the same parameters |
| `changes_list`, `charts_get`, `listings_search`, `market_get`, `mcp_toolset_get`, `new_list`, `stores_get`, `tags_get` | The same name, with the same parameters |
| `listings_get`, `listings_metrics`, `listings_ranks_current`, `listings_tools` | `listings_profile` with `apps=[<ref>]`; one call covers all four |
| `listings_ranks_history` | None: date moves from the `rank_move` rows of `changes_list` |
| `listings_versions latest=true`, `listings_widgets` | `listings_copy app=<ref>` |
| `listings_list`, older `listings_versions` records | None |
| `charts_regions_get`, `listings_list`, `tags_tree`, older `listings_versions` records | None |

`listings_profile` answers with `data.profiles[].{app,ranks,metrics,tools}`, so the `listings_get` fields a skill names are under `app`, and its `data.charts`, `data.metrics` and `data.servers` paths are under `ranks`, `metrics` and `tools`.

Expand Down
3 changes: 3 additions & 0 deletions skills/audit-discoverability/references/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@ The base URL is `https://theopenapps.com/v1`. Every read is a GET and works with
|---|---|
| `changes_list` | `/changes` |
| `charts_get` | `/charts/{store}/{chart}` |
| `charts_regions_get` | `/charts/{store}/{chart}/regions` |
| `listings_search` | `/listings` |
| `listings_list` | `/listings/list` |
| `listings_get` | `/listings/{store}/{id}` |
| `listings_metrics`, `_tools`, `_versions`, `_widgets` | `/listings/{store}/{id}/metrics`, and so on |
| `listings_ranks_current` | `/listings/{store}/{id}/ranks/current` |
| `listings_ranks_history` | `/listings/{store}/{id}/ranks` |
| `market_get` | `/market` |
| `mcp_toolset_get` | `/mcp/toolsets` |
| `new_list` | `/new` |
| `stores_get` | `/stores` |
| `tags_get` | `/tags/{tag}` |
| `tags_tree` | `/tags` |

A ref fills `{store}/{id}`: `chatgpt:kiwi-com` is `/listings/chatgpt/kiwi-com`. Every other parameter is a query string, such as `/changes?store=chatgpt&since=-7d&limit=20`. For the rest, read one path from `/v1/openapi.json`, which is about 190 KB in all.

Expand Down
4 changes: 2 additions & 2 deletions skills/audit-discoverability/references/mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ The server is `https://theopenapps.com/mcp`. To sign in, the user connects `http

| Operation | Tool |
|---|---|
| `changes_list`, `charts_get`, `listings_search`, `mcp_toolset_get`, `new_list`, `stores_get`, `tags_get` | The same name, with the same parameters |
| `changes_list`, `charts_get`, `listings_search`, `market_get`, `mcp_toolset_get`, `new_list`, `stores_get`, `tags_get` | The same name, with the same parameters |
| `listings_get`, `listings_metrics`, `listings_ranks_current`, `listings_tools` | `listings_profile` with `apps=[<ref>]`; one call covers all four |
| `listings_ranks_history` | None: date moves from the `rank_move` rows of `changes_list` |
| `listings_versions latest=true`, `listings_widgets` | `listings_copy app=<ref>` |
| `listings_list`, older `listings_versions` records | None |
| `charts_regions_get`, `listings_list`, `tags_tree`, older `listings_versions` records | None |

`listings_profile` answers with `data.profiles[].{app,ranks,metrics,tools}`, so the `listings_get` fields a skill names are under `app`, and its `data.charts`, `data.metrics` and `data.servers` paths are under `ranks`, `metrics` and `tools`.

Expand Down
3 changes: 3 additions & 0 deletions skills/design-widgets/references/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,19 @@ The base URL is `https://theopenapps.com/v1`. Every read is a GET and works with
|---|---|
| `changes_list` | `/changes` |
| `charts_get` | `/charts/{store}/{chart}` |
| `charts_regions_get` | `/charts/{store}/{chart}/regions` |
| `listings_search` | `/listings` |
| `listings_list` | `/listings/list` |
| `listings_get` | `/listings/{store}/{id}` |
| `listings_metrics`, `_tools`, `_versions`, `_widgets` | `/listings/{store}/{id}/metrics`, and so on |
| `listings_ranks_current` | `/listings/{store}/{id}/ranks/current` |
| `listings_ranks_history` | `/listings/{store}/{id}/ranks` |
| `market_get` | `/market` |
| `mcp_toolset_get` | `/mcp/toolsets` |
| `new_list` | `/new` |
| `stores_get` | `/stores` |
| `tags_get` | `/tags/{tag}` |
| `tags_tree` | `/tags` |

A ref fills `{store}/{id}`: `chatgpt:kiwi-com` is `/listings/chatgpt/kiwi-com`. Every other parameter is a query string, such as `/changes?store=chatgpt&since=-7d&limit=20`. For the rest, read one path from `/v1/openapi.json`, which is about 190 KB in all.

Expand Down
Loading
Loading