Skip to content

Commit f1ffc91

Browse files
Merge pull request #2 from Iterable/add-cursor-plugin-packaging
Package as a Cursor plugin (skill + Context7 MCP)
2 parents 7fb5b14 + b69bc34 commit f1ffc91

9 files changed

Lines changed: 349 additions & 28 deletions

File tree

.cursor-plugin/marketplace.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "iterable",
3+
"owner": { "name": "Iterable" },
4+
"metadata": {
5+
"description": "Iterable's official skills for AI coding assistants — mobile SDK integration guidance.",
6+
"version": "0.1.0"
7+
},
8+
"plugins": [
9+
{
10+
"name": "iterable-sdk",
11+
"source": "./",
12+
"description": "Iterable mobile SDK skill"
13+
}
14+
]
15+
}

.cursor-plugin/plugin.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "iterable-sdk",
3+
"version": "0.1.0",
4+
"description": "Reliable Iterable mobile SDK integration guidance for AI coding assistants — version-pinned snippets + silent-failure pitfalls. Android today; iOS/RN/Web later.",
5+
"author": { "name": "Iterable" },
6+
"repository": "https://github.com/Iterable/iterable-sdk-skill",
7+
"license": "MIT",
8+
"keywords": ["iterable", "android", "sdk", "mobile", "push", "in-app"],
9+
"skills": ["./iterable-android"]
10+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: Validate plugin manifests
2+
3+
# Lightweight gate for Cursor/Claude plugin packaging — no Java/Kotlin needed.
4+
5+
on:
6+
push:
7+
branches: [main]
8+
paths:
9+
- .cursor-plugin/**
10+
- .claude-plugin/**
11+
- mcp.json
12+
- .mcp.json
13+
- pipeline/src/validate-plugins.ts
14+
- pipeline/package.json
15+
- .github/workflows/validate-plugins.yml
16+
pull_request:
17+
branches: [main]
18+
paths:
19+
- .cursor-plugin/**
20+
- .claude-plugin/**
21+
- mcp.json
22+
- .mcp.json
23+
- pipeline/src/validate-plugins.ts
24+
- pipeline/package.json
25+
- .github/workflows/validate-plugins.yml
26+
workflow_dispatch:
27+
28+
permissions:
29+
contents: read
30+
31+
jobs:
32+
validate-plugins:
33+
runs-on: ubuntu-latest
34+
timeout-minutes: 5
35+
steps:
36+
- name: Checkout
37+
uses: actions/checkout@v4
38+
39+
- name: Setup pnpm
40+
uses: pnpm/action-setup@v4
41+
with:
42+
version: 9
43+
44+
- name: Setup Node
45+
uses: actions/setup-node@v4
46+
with:
47+
node-version: 20
48+
cache: pnpm
49+
cache-dependency-path: pipeline/pnpm-lock.yaml
50+
51+
- name: Install pipeline deps
52+
working-directory: pipeline
53+
run: pnpm install --frozen-lockfile
54+
55+
- name: Validate plugin manifests
56+
working-directory: pipeline
57+
run: pnpm validate:plugins

.mcp.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
"mcpServers": {
33
"context7": {
44
"type": "http",
5-
"url": "https://mcp.context7.com/mcp"
5+
"url": "https://mcp.context7.com/mcp",
6+
"headers": {
7+
"CONTEXT7_API_KEY": "${env:CONTEXT7_API_KEY}"
8+
}
69
}
710
}
811
}

README.md

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,30 @@ callback, and more).
2121

2222
This installs the skill and wires up its documentation source in one step.
2323

24-
**Cursor (or a manual install)** — symlink the skill directory into your
25-
assistant's skills folder:
24+
**Cursor** — install it as a plugin, which wires up the skill **and** its
25+
documentation source (the Context7 MCP server) in one step. Cursor 3.9+ supports
26+
Agent Skills and plugins natively.
27+
28+
Clone the repo and symlink it into Cursor's local-plugins folder, then restart
29+
Cursor (or reload the window):
2630

2731
```bash
28-
git clone --depth 1 git@github.com:Iterable/iterable-sdk-skill.git ~/iterable-skills
29-
ln -s ~/iterable-skills/iterable-android ~/.cursor/skills/iterable-android
32+
git clone --depth 1 https://github.com/Iterable/iterable-sdk-skill.git ~/iterable-skills
33+
ln -s ~/iterable-skills ~/.cursor/plugins/local/iterable-sdk
3034
```
3135

36+
A Cursor team admin can instead publish it to the whole org via **Dashboard →
37+
Plugins → Add Marketplace → Import from Repo**, pointing at this repo.
38+
39+
> **Just the skill, no plugin?** Cursor 3.9+ auto-loads Agent Skills from
40+
> `~/.cursor/skills/` — symlink only the skill directory:
41+
> `ln -s ~/iterable-skills/iterable-android ~/.cursor/skills/iterable-android`.
42+
> This skips the doc source; to add it, paste this into your browser to install
43+
> the Context7 MCP server:
44+
> ```
45+
> cursor://anysphere.cursor-deeplink/mcp/install?name=context7&config=eyJ1cmwiOiJodHRwczovL21jcC5jb250ZXh0Ny5jb20vbWNwIn0=
46+
> ```
47+
3248
Either way, the skill activates automatically whenever you mention Iterable: it
3349
loads its always-on rules and `PITFALLS.md`, then pulls the documentation for
3450
whatever feature you're working on (see [How it works](#how-it-works)).
@@ -39,15 +55,16 @@ The skill carries a copy of the Iterable documentation inside it
3955
(`iterable-android/snapshot/`), so it always has the docs on hand — even offline.
4056
This snapshot is the active source today.
4157
42-
The Claude Code plugin also connects to [Context7](https://context7.com), a
43-
service that hosts docs for AI assistants to query on demand. That connection is
44-
bundled and ready, but stays dormant until Iterable's curated library is
45-
published there; once it is, the skill fetches the latest docs live, with the
46-
snapshot as its fallback. No reinstall needed when that happens.
58+
The plugin (both Claude Code and Cursor) also connects to
59+
[Context7](https://context7.com), a service that hosts docs for AI assistants to
60+
query on demand. That connection is bundled and ready, but stays dormant until
61+
Iterable's curated library is published there; once it is, the skill fetches the
62+
latest docs live, with the snapshot as its fallback. No reinstall needed when
63+
that happens.
4764
4865
> Context7 works without an API key at a lower rate limit. To raise it, get a
49-
> free key at [context7.com](https://context7.com) and add it as a
50-
> `CONTEXT7_API_KEY` header on the `context7` MCP server.
66+
> free key at [context7.com](https://context7.com) and set the `CONTEXT7_API_KEY`
67+
> environment variable — the bundled MCP config forwards it automatically.
5168
5269
## What it covers
5370
@@ -67,6 +84,10 @@ polished/ the docs in agent-ready form (what gets published to Context
6784
pipeline/ tooling that builds polished/ from sources/, CI-gated
6885
sources/ raw Iterable docs, fetched at pinned commits
6986
context7.json Context7 manifest
87+
.claude-plugin/ Claude Code plugin + marketplace manifests
88+
.cursor-plugin/ Cursor plugin + marketplace manifests
89+
mcp.json Context7 MCP server (Cursor plugin auto-discovery)
90+
.mcp.json same config (Claude Code auto-discovery; kept in sync by CI)
7091
```
7192
7293
## Staying current

iterable-android/SKILL.md

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ human readers but omit several silent-failure traps documented in
3333
Do this **first**, before Preflight and before any edits. The SDK covers many
3434
features — push, in-app, mobile inbox, embedded, deep links, event tracking,
3535
user profiles. Do **not** assume the developer wants all of them, and do **not**
36-
start implementing on a guessed scope. Ask which features they want via
37-
`AskUserQuestion`. Set `multiSelect: true` so they can pick several, and offer
38-
**at most 4 options** (the tool rejects more than 4 per question) — group the
39-
long tail under one bucket, e.g.:
36+
start implementing on a guessed scope. Ask which features they want. If your
37+
host exposes an interactive multi-select question tool (in Claude Code,
38+
`AskUserQuestion` with `multiSelect: true`; in Cursor, `AskQuestion` with
39+
`allow_multiple: true`), use it and offer **at most 4 options** (those tools
40+
reject more than 4 per question); otherwise ask in plain text. Either way, group
41+
the long tail under one bucket, e.g.:
4042

4143
- Push notifications (FCM)
4244
- In-app messages
@@ -88,17 +90,19 @@ pauses for a missing input is **always better** than one that compiles by
8890
faking the input — the latter ships a broken or misleading state that looks
8991
done.
9092

91-
> **Always ask via selectable options, not prose — every time.** For *any*
92-
> question to the developer — the Step 0 scope question, the inputs below, the
93-
> identity model, region, and "what would you like to do next?" — use the
94-
> `AskUserQuestion` tool so they get interactive choices, not a plain-text list
95-
> they must answer by typing. Offer realistic options with a short description
96-
> each (e.g. identity: "Stable per-install UUID via `setUserId`" / "Account
97-
> email via `setEmail`"; region: "US" / "EU"). **Offer at most 4 options per
98-
> question** — the tool rejects more than 4 and the call fails with an
99-
> "invalid parameters" error. If you have more than 4, group them or split into
100-
> a second question. Only fall back to plain text if the question genuinely has
101-
> no enumerable options.
93+
> **Prefer selectable options over prose — every time.** For *any* question to
94+
> the developer — the Step 0 scope question, the inputs below, the identity
95+
> model, region, and "what would you like to do next?" — if your host exposes an
96+
> interactive question tool (in Claude Code, `AskUserQuestion`; in Cursor,
97+
> `AskQuestion`), use it so they get interactive choices instead of a plain-text
98+
> list they must answer by typing. Offer realistic options with a short
99+
> description each (e.g. identity: "Stable per-install UUID via `setUserId`" /
100+
> "Account email via `setEmail`"; region: "US" / "EU"). With those tools,
101+
> **offer at most 4 options per question** — they reject more than 4 and the
102+
> call fails with an "invalid parameters" error; if you have more than 4, group
103+
> them or split into a second question. If no such tool is available, ask in
104+
> plain text with the options clearly enumerated. Only skip options entirely if
105+
> the question genuinely has none.
102106
103107
| Input | Needed when | If missing |
104108
|---|---|---|

mcp.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"mcpServers": {
3+
"context7": {
4+
"type": "http",
5+
"url": "https://mcp.context7.com/mcp",
6+
"headers": {
7+
"CONTEXT7_API_KEY": "${env:CONTEXT7_API_KEY}"
8+
}
9+
}
10+
}
11+
}

pipeline/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"fetch:sources": "tsx src/fetch.ts",
1111
"polish:a": "tsx src/polish-layer-a.ts",
1212
"validate:polished": "tsx src/validate-polished.ts",
13+
"validate:plugins": "tsx src/validate-plugins.ts",
1314
"check:snippets": "tsx src/check-snippets.ts",
1415
"lint:chunking": "tsx src/lint-chunking.ts",
1516
"recompute:manifest": "tsx src/recompute-manifest.ts",
@@ -20,7 +21,7 @@
2021
"eval:run": "tsx src/eval-run.ts run",
2122
"eval:report": "tsx src/eval-report.ts",
2223
"typecheck": "tsc --noEmit",
23-
"check:all": "pnpm typecheck && pnpm validate:polished && pnpm snapshot:verify && pnpm check:snippets && pnpm lint:chunking"
24+
"check:all": "pnpm typecheck && pnpm validate:polished && pnpm validate:plugins && pnpm snapshot:verify && pnpm check:snippets && pnpm lint:chunking"
2425
},
2526
"devDependencies": {
2627
"@types/node": "^22.7.0",

0 commit comments

Comments
 (0)