From appmate
Generates prioritized feature recommendations from app reviews and competitor evidence. Use for product roadmap input or feature ideation.
How this skill is triggered — by the user, by Claude, or both
Slash command
/appmate:feature-ideationThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> This skill is the single authoritative reference for the feature ideation flow. Re-read it before every run.
This skill is the single authoritative reference for the feature ideation flow. Re-read it before every run. v3: removed mechanical review bucketing (rating thresholds + trigger-word list) and removed the direct AppMate RAG dependency. The LLM now classifies each raw review on its own; competitors come from the
competitor-researchskill's output. v2 had been the prior "negative + wishlist buckets + RAG seed" design.
Every step in this skill calls App Store Connect APIs. Before any other step, run:
python3 scripts/appmate_config.py check
If exit code ≠ 0, STOP. Do not invoke any other part of this skill, do not run scripts/feature_ideate.py. Tell the user AppMate credentials are not configured, show the precheck output verbatim, and tell them to invoke the appmate-setup skill. The downstream script also enforces this gate (exits 2 with the same message).
competitor-research skill if missingThis workflow consumes data/competitors_<slug>.json, the final artifact produced by the competitor-research skill (invoked for the same <app>). Both skills compute slug via slugify(canonical_app_name, market), so passing the same app argument to both guarantees the slug matches.
Decision rule — before invoking feature_ideate.py:
<app> (read data/apps_full.json, call find_app(<arg>) → name, then pick main market via the largest 30-day downloads in sales_cache.json with the same fallbacks the script uses — primaryLocale, then US). Compute expected = data/competitors_<slugify(name, market)>.json.expected exists.competitor-research skill end-to-end for the same <app> argument first — all three stages: Stage 1 script analyze, Stage 2 LLM tokenization, Stage 3 LLM relevance pass + final-JSON + markdown write. Paste the rivals markdown back into the conversation per that skill's own rules. Then return here and proceed to Step 1 of feature-ideation. The user gets two reports out of one ask: rivals first, then features. That is intentional — both are useful, and the rivals card is also the new evidence basis for feature ideas.competitors_generated_at; if it is > 30 days old, mention staleness when delivering the final feature report (do not auto-refresh unless the user asks).No RAG fallback. No placeholder competitors. The only two paths are: the cached file, or a fresh competitor-research skill run. The earlier (v2) direct appmate_rag_client.search(...) call is gone for good — competitor evidence is unified through the competitor-research flow so the two workflows stay coherent.
Safety net: feature_ideate.py still exits 2 with competitors JSON not found if the file is missing at script-execution time. This catches the case where the script was invoked outside the skill (cron, manual CLI). When it fires, treat it the same way — invoke competitor-research for the same app, then re-run.
Given a live app → the script aggregates raw reviews (last 90 days, ≤ 150) plus the kept competitors from competitors_<slug>.json → the LLM reads each review and classifies it itself (complaint / suggestion / praise), then scores ideas internally on 4 dimensions → a markdown report with two sentences per feature (what it is + why), with no scores shown.
| Item | Content |
|---|---|
| Trigger | the user says "run feature ideation for <app>" |
| Input | data/apps_full.json (reviews) + data/competitors_<slug>.json (from the competitor-research skill — auto-chained on first run for an app, then cached) |
| Output | data/phase_a_feature_<slug>.json (intermediate) + data/feature_ideas_<slug>.md (final) + Claude pastes the full markdown back into the conversation |
| Intervention points | 2 (trigger + receive); optional follow-up "detail one of the ideas" |
feature_ideate.py) — app fuzzy match (reuses aso_optimize_v2) → pull raw reviews from last 90 days (≤ 150, no filter) → load competitors from data/competitors_<slug>.json (Claude should have already auto-chained the competitor-research skill per §0.2 if the file was missing; script exits 2 as a safety net otherwise) → data/phase_a_feature_<slug>.json.data/feature_ideas_<slug>.md; paste the full markdown back into the conversation.Reuses aso_optimize_v2.find_app() — accepts App Store ID / bundle ID / SKU / fuzzy name match.
Main-market selection:
data/sales_cache.json).primaryLocale.collect_raw_reviews() does the bare minimum — no rating threshold, no trigger-word list, no semantic split. The LLM in Step 2 reads each body and decides what it is.
| Rule | Value |
|---|---|
| Age cutoff | last 90 days (createdDate ≥ today − 90) |
| Cap | first 150 entries after newest-first sort |
| Per-entry schema | {rating, title, body, locale, created_at} (body is Apple's original field name) |
| Cross-language | no language filter — reviews in all locales pass through; the LLM handles translation |
v2 → v3 change: v2 had two pre-computed buckets —
reviews_negative(rating ≤ 3+ body ≥ 10 chars) andreviews_wishlist(rating ≥ 4+ a trigger word from a hardcoded list). Both were leaky: rating ∈ {4, 5} entries often carried strong suggestions, low-rating entries were sometimes just venting with nothing actionable, and the trigger-word list missed many real signals. v3 sends raw reviews and lets the LLM do the semantic call.
load_competitors(app_name, market) reads OUTPUT_DIR / f"competitors_{slugify(app_name, market)}.json". The file is the final artifact of the competitor-research skill (see skills/competitor-research/SKILL.md). Per §0.2, Claude should ensure this file exists before invoking the script — by auto-chaining that skill when it's missing.
| Step | Behavior |
|---|---|
| File missing | return None → build_phase_a returns None → main() prints a safety-net message pointing at the competitor-research skill and exits 2. Normally never fires when the skill flow was followed; fires if the script was invoked directly. |
| File present | read payload["filtered"] (already top-10 by threat_score, already passed the LLM relevance pass) and copy these fields per entry: name, description_short, outranked_keywords, relevance_reason, threat_score, rating, review_count |
| Stale data | the script does not check generated_at freshness; it surfaces the timestamp in phase_a so the LLM can flag staleness in the report if it looks old (> 30 days) |
v2 → v3 change: v2 called
appmate_rag_client.search(query=seed, region=market, top_k=10, ...)directly with a seed-word it picked from the app's name. The seed-extraction was fragile (compound brand names like便签Prolost their context, English-onlyappfallback returned useless rivals), and the RAG result was a different shape than the SERP-overlap rivals produced by thecompetitor-researchskill. v3 reuses the already-curated, already-LLM-filtered result of that skill, so the two workflows produce a coherent picture of the same competitive landscape.
{
"app": "<name>",
"app_id": "<id>",
"bundle_id": "<bid>",
"market": "<country>",
"downloads_30d_in_market": 1300,
"generated_at": "2026-05-13T...",
"reviews": [
{"rating": 2, "title": "", "body": "...", "locale": "CHN", "created_at": "2026-05-05T..."},
{"rating": 5, "title": "", "body": "希望加...", "locale": "CHN", "created_at": "..."}
],
"competitors_source": "<absolute path to competitors_<slug>.json>",
"competitors_generated_at": "<timestamp from competitors_<slug>.json>",
"competitors": [
{"name": "...", "description_short": "...", "outranked_keywords": ["..."],
"relevance_reason": "...", "threat_score": 42, "rating": 4.7, "review_count": 1234}
]
}
Before brainstorming, walk the reviews[] array once. For each entry decide which bin it falls into — no fixed rating rules, use the body content:
| Bin | Looks like |
|---|---|
| Complaint | crash report, sync loss, billing dispute, broken core flow, uninstall warning |
| Suggestion | "希望加 X / would love Y / 能否 / please add / 不能 X / 为什么没有 Y / I wish" — explicit feature ask |
| Praise + hidden signal | rating ≥ 4 but the body mentions a workflow they wish was smoother, or a competitor they prefer for one feature |
| Noise | spammy / "good" / non-actionable rating-only entry — ignore |
You may discount or skip noise; this is not a "first 50" cap. A rating ∈ {4, 5} body that contains a strong suggestion still goes into the suggestion bin — do not anchor on the star count.
Brainstorm 15-20 candidates internally, pulling 15-20 from the two evidence sources (your bins from §2a + competitors), then cross-dedup → trim to 5-10 finalists by composite score. Rationale: experience says the candidate count should be 5× the finalist count for comparative filtering to be meaningful.
The following is the LLM's internal ranking methodology (based on RICE). The final markdown output does not show scores — items are only arranged from high to low score; the user sees only a sorted feature list.
Each candidate is scored 1-5 on 4 dimensions:
| Internal dimension | 1-5 scoring basis |
|---|---|
| Reach | reviews mention ≥ 10 → 5; validated by multiple competitors → 4; single evidence → 2 |
| Impact | solves a payment blocker / prevents uninstall → 5; improves retention → 4; experience detail → 2 |
| Confidence | reviews ≥ 3 + competitor validation → 5; single source only → 2; pure speculation → 1 |
| Effort | macOS solo dev: half a day → 1; 2+ weeks → 5 |
Composite score = (R × I × C) / E (range 0.2 - 125, for LLM internal ranking only).
| Rule | Application |
|---|---|
| ❌ Single evidence | Confidence ≤ 2 AND Reach ≤ 2 → cut directly |
| ❌ Platform violation | a mac app proposing "add GPS / push / an iOS-only sensor" → delete |
| ❌ Vague words | "improve performance / nicer / smarter" → must be specific to a behavior |
| ❌ Rename-style non-action | "rename a button" must state "which interaction changed" |
competitor-research skill" warning at the top.Core rules:
- Do not show any scores (composite score, 4-dimension scores all hidden) — scores are only the LLM's internal ranking basis.
- No jargon:
RICE / R / I / C / E / Reach / Impact / Confidence / Effort / Explore / Exploit / Core value / Onboarding / Delight.- Two sentences per item only: the first says "what it is / how it interacts", the second says "why do it / what the evidence is".
- Arrange by composite score high to low (but do not show the score).
Rendered in the same language the user has been using in this conversation. Default to English; if the user has been writing in Chinese / Japanese / Spanish / etc., translate the template headers, labels and prose accordingly. App Store metadata strings (title / subtitle / keywords / competitor app names) must remain in the App Store's source locale (e.g. zh-Hans names stay zh-Hans) — only the surrounding explanation follows the user's conversation language.
The template below is written with English placeholders. Substitute the equivalent words in the user's conversation language when rendering.
# 🚀 <App name> · Feature recommendations
> ⚠️ <evidence-thin warning — only shown when total reviews < 10 OR total competitors == 0. Example: "Evidence thin: only 7 reviews + 0 competitors. Recommend running the competitor-research skill first to add competitor evidence, then revisit this report.">
**1. <Feature title>** — <one sentence: what the feature is, how it interacts>. <one sentence: why do it, what's the evidence>.
**2. <Feature title>** — <same structure>.
... (5-10 items total) ...
**N. <Feature title>** — <same structure>.
---
**Top N**: #X / #Y / #Z — short summary of each item's core value (one sentence each).
Want one expanded? Tell me the number and I can help you write a mini PRD (user stories / acceptance criteria / sprint breakdown).
RICE / Reach / Impact / Confidence / Effort / Explore / Exploit / Core value / Onboarding / Delight — always use plain prose in the user's conversation language.。 for Chinese, . for English).**N. Title** followed by — (em dash, full-width when the surrounding text is CJK).| File | Purpose |
|---|---|
scripts/feature_ideate.py | Step 1 script (runs by app name; hard-depends on data/competitors_<slug>.json) |
data/phase_a_feature_<slug>.json | intermediate artifact (overwritten each run) |
data/feature_ideas_<slug>.md | final deliverable (overwritten each run) |
| Direction | Content |
|---|---|
| Upstream auto-chain | data/apps_full.json + data/competitors_<slug>.json. When the competitors file is missing, this skill first invokes the competitor-research skill for <app> end-to-end (rivals markdown gets pasted back as a side effect), then continues. |
| Side-chain trigger | the aso-daily-report skill finds an app's rank dropping out → trigger this flow to find new features as a fix |
| Downstream upgrade (v4) | add a feature_detail_<slug>.py to expand a single idea into a PRD |
# from the plugin repo root
# Step 0 prerequisite (one-time per app, also refresh whenever the SERP shifts):
python3 scripts/competitor_research.py analyze "<app>"
# ...then Claude tokenizes + the rank pass + Claude writes data/competitors_<slug>.json
# (handled by the competitor-research skill end-to-end)
# Step 1: aggregate reviews + competitors → phase_a JSON
python3 scripts/feature_ideate.py "<app>"
# the app argument accepts: App Store ID / bundle ID / SKU / fuzzy name match
# examples:
# python3 scripts/feature_ideate.py "Sticky Note Pro"
# python3 scripts/feature_ideate.py "com.fengyiqi.PostItnoteForMac"
# python3 scripts/feature_ideate.py "1482080766"
# Steps 2-3: Claude reads the phase_a JSON and generates + renders per §2 / §3 rules
If feature_ideate.py exits 2 with competitors JSON not found, that is the safety net firing — invoke the competitor-research skill for <app> end-to-end, then re-run this command. (In normal skill-driven runs you should not hit this, because §0.2 instructs Claude to auto-chain that skill when the file is missing, before ever invoking the script.)
competitor-research skill was last run for this app — staleness shows up in competitors_generated_at; if it's > 30 days old, suggest re-running the prereq before trusting the report.RICE / Reach / Impact / Confidence / Effort / Explore / Exploit / Core value / Onboarding / DelightR / I / C / E**N. Name** bold + em dash — (full-width when surrounding text is CJK)data/feature_ideas_<slug>.mdnpx claudepluginhub fengyiqicoder/appmate --plugin appmateGenerates a stage-diagnosed growth strategy for an app, including phase diagnosis and 3-5 actionable strategies. Auto-chains competitor-research when competitor data is missing.
Provides Chief Product Officer expertise with frameworks like Jobs-to-be-Done, Lean Startup, and Hook Model for product strategy, market analysis, competitive positioning, feature prioritization, and business models.
Fetches low-star App Store and Google Play reviews, clusters them into broken-promise patterns, and generates a ranked copy brief with positioning opportunities.