@appeeky/spec 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/assets/cover.gif +0 -0
- package/LICENSE +110 -0
- package/README.md +483 -2
- package/dist/ads.d.ts +39 -0
- package/dist/ads.js +67 -0
- package/dist/appeeky-api.d.ts +62 -0
- package/dist/appeeky-api.js +240 -0
- package/dist/attribution-setup.d.ts +28 -0
- package/dist/attribution-setup.js +65 -0
- package/dist/attribution.d.ts +121 -0
- package/dist/attribution.js +170 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +4 -0
- package/dist/category.d.ts +71 -0
- package/dist/category.js +198 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +1387 -0
- package/dist/competitors.d.ts +74 -0
- package/dist/competitors.js +143 -0
- package/dist/control.d.ts +21 -0
- package/dist/control.js +53 -0
- package/dist/core.d.ts +15 -0
- package/dist/core.js +15 -0
- package/dist/coverage.d.ts +46 -0
- package/dist/coverage.js +115 -0
- package/dist/data.d.ts +48 -0
- package/dist/data.js +298 -0
- package/dist/diff.d.ts +11 -0
- package/dist/diff.js +33 -0
- package/dist/experiments.d.ts +115 -0
- package/dist/experiments.js +85 -0
- package/dist/files.d.ts +27 -0
- package/dist/files.js +129 -0
- package/dist/history.d.ts +43 -0
- package/dist/history.js +55 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +24 -0
- package/dist/limits.d.ts +15 -0
- package/dist/limits.js +30 -0
- package/dist/lint.d.ts +16 -0
- package/dist/lint.js +159 -0
- package/dist/loops.d.ts +37 -0
- package/dist/loops.js +197 -0
- package/dist/measure.d.ts +40 -0
- package/dist/measure.js +159 -0
- package/dist/metrics.d.ts +270 -0
- package/dist/metrics.js +250 -0
- package/dist/output.d.ts +21 -0
- package/dist/output.js +79 -0
- package/dist/project.d.ts +19 -0
- package/dist/project.js +35 -0
- package/dist/report.d.ts +5 -0
- package/dist/report.js +71 -0
- package/dist/reviews.d.ts +130 -0
- package/dist/reviews.js +287 -0
- package/dist/schema.d.ts +519 -0
- package/dist/schema.js +218 -0
- package/dist/screenshots.d.ts +23 -0
- package/dist/screenshots.js +116 -0
- package/dist/setup.d.ts +45 -0
- package/dist/setup.js +226 -0
- package/dist/storefronts.d.ts +15 -0
- package/dist/storefronts.js +89 -0
- package/dist/stores/app-store.d.ts +33 -0
- package/dist/stores/app-store.js +159 -0
- package/dist/stores/google-play.d.ts +13 -0
- package/dist/stores/google-play.js +61 -0
- package/dist/stores/types.d.ts +34 -0
- package/dist/stores/types.js +2 -0
- package/dist/suggest.d.ts +73 -0
- package/dist/suggest.js +135 -0
- package/dist/text.d.ts +18 -0
- package/dist/text.js +55 -0
- package/dist/transport.d.ts +98 -0
- package/dist/transport.js +170 -0
- package/dist/verify.d.ts +70 -0
- package/dist/verify.js +134 -0
- package/dist/visibility.d.ts +149 -0
- package/dist/visibility.js +239 -0
- package/package.json +76 -4
- package/skills/appeeky-spec/SKILL.md +146 -0
- package/skills/appeeky-spec-experiments/SKILL.md +83 -0
- package/skills/appeeky-spec-localize/SKILL.md +52 -0
- package/skills/appeeky-spec-review/SKILL.md +75 -0
- package/skills/appeeky-spec-targets/SKILL.md +66 -0
- package/skills/appeeky-spec-visibility/SKILL.md +79 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: appeeky-spec-review
|
|
3
|
+
description: Review what past store listing changes did in an Appeeky Spec repo, decide whether to keep or revert them, update the playbook and plan the next change. Use when asked "did the last listing change work?", "should we revert?", for a weekly ASO review, to close experiments, or to summarize listing releases for a team update or PR.
|
|
4
|
+
metadata:
|
|
5
|
+
version: 1.2.0
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Review listing releases with Appeeky Spec
|
|
9
|
+
|
|
10
|
+
Each push in `appeeky/releases/` holds the before/after values, the hypothesis (`note`) and the search ranks from right before it. `verify` measures again on day 7 and day 14.
|
|
11
|
+
|
|
12
|
+
Run commands as `npx @appeeky/spec <command> --json`.
|
|
13
|
+
|
|
14
|
+
## 1. Measure
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npx @appeeky/spec verify --playbook --json
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
This only measures releases that reached day 7 or day 14 and have not been measured for that day. Use `verify --now <release-id>` only when the user wants an early look, and say that early ranks are noisy. With `APPEEKY_API_KEY` set, each check also has `metrics`: conversion, downloads, revenue, trials and ads (Apple Search Ads, plus the Meta and TikTok campaigns under `ads:`) before and after the push, each marked `better`, `worse` or `flat`, and due experiments on those metrics are closed for you (`closedExperiments`). The JSON lists experiments that still need a value (`dueExperiments`).
|
|
21
|
+
|
|
22
|
+
## 2. Read the verdict
|
|
23
|
+
|
|
24
|
+
| Verdict | Meaning | Usual action |
|
|
25
|
+
| --- | --- | --- |
|
|
26
|
+
| `won` | More targets rose (3+ places) than fell | Keep. Note what worked in the playbook |
|
|
27
|
+
| `lost` | One top-10 target, or two top-20 targets, fell out of the top 20 by 10+ places | Propose `revert` |
|
|
28
|
+
| `mixed` | Some rose, as many or more fell | Look at which targets moved and their popularity before deciding |
|
|
29
|
+
| `flat` | Nothing moved 3+ places | Wait for day 14; then treat as no effect |
|
|
30
|
+
|
|
31
|
+
When the check has `control`, read `net`: the places the changed storefronts gained beyond the unchanged ones. A "won" with a small net was turned into "mixed" (see `note`): the whole store moved. A metric change marked flat with a `noise` larger than the change is within its normal week-to-week range; do not credit or blame the release for it.
|
|
32
|
+
|
|
33
|
+
When no rank moved and the check has `decidedBy`, the verdict came from those outcome metrics, in this order:
|
|
34
|
+
|
|
35
|
+
1. organic installs and revenue,
|
|
36
|
+
2. else conversion,
|
|
37
|
+
3. else downloads,
|
|
38
|
+
4. else the category rank.
|
|
39
|
+
|
|
40
|
+
Say so: "won on organic installs, ranks unchanged".
|
|
41
|
+
|
|
42
|
+
A verdict decided by `category_rank` is the weakest kind. The chart moves with ads, featuring and season too, so say that and prefer waiting for day 14.
|
|
43
|
+
|
|
44
|
+
Two more metrics can be in `metrics.changes` (see appeeky-spec-visibility):
|
|
45
|
+
|
|
46
|
+
- `ai_visibility`: the share of AI assistant answers that name the app. Assistants update slowly, so read it on day 14.
|
|
47
|
+
- `category_rank`: lower is better, so a negative change is good.
|
|
48
|
+
|
|
49
|
+
Before recommending, check:
|
|
50
|
+
|
|
51
|
+
- **Popularity.** One popular term lost can outweigh three tiny ones gained.
|
|
52
|
+
- **Conversion and revenue.** When a check has `metrics` (or `conversion`), more ranks with lower conversion or revenue is not a win, and flat ranks with better conversion can be. Lead with the outcome the user cares about: revenue and trials before downloads, downloads before ranks.
|
|
53
|
+
- **Other causes.** A new app version, a featuring, a competitor's change (`appeeky/competitors/changes.md`), an ad campaign starting (`ads --json`) or seasonality in the same window. Say when the result could be noise.
|
|
54
|
+
- **Day 7 vs day 14.** App Store ranking changes settle over one to two weeks; prefer the day-14 check when it exists.
|
|
55
|
+
|
|
56
|
+
## 3. Revert when it lost
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npx @appeeky/spec revert <release-id>
|
|
60
|
+
npx @appeeky/spec diff --json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`revert` only edits the files. Push only when the user agrees, with a note: `push --note "Revert <id>: lost '<keyword>' (<before> → <after>)"`. App Store fields other than promotional text need a new version.
|
|
64
|
+
|
|
65
|
+
## 4. Close experiments
|
|
66
|
+
|
|
67
|
+
`verify` closes due experiments on `conversion`, `downloads`, `revenue`, `trial_conversion`, `cpa`, `meta_cpi`, `tiktok_cpa` and the other measured metrics. With `attribution:` in the spec, checks also carry `organic_installs`, `organic_revenue` and `organic_paid`: whether more people found the app in search and paid. For UGC, creator or ad experiments, start them with `--link` so their installs are counted exactly. `appeeky-spec ads --json` shows spend and cost per install per paid channel; `--save` keeps a copy in `appeeky/ads/`. For the rest (installs per 1,000 views, tap-through rate), ask the user for the value or read it from the data they point to, then `experiment close <id> --value <n> --note "..." --playbook`. When starting one, prefer a measured metric: `experiment add --metric trial_conversion` takes its baseline from the last days.
|
|
68
|
+
|
|
69
|
+
## 5. Update the playbook and plan
|
|
70
|
+
|
|
71
|
+
`appeeky/playbook.md` gets one line per result from `--playbook`. Add a short "why" in your own words when the cause is clear (for example: "subtitle words beat keyword-field words for 'white noise'"). Then propose the next single change, with a hypothesis that does not repeat a losing one.
|
|
72
|
+
|
|
73
|
+
## Summaries
|
|
74
|
+
|
|
75
|
+
`log --markdown -n <count>` prints releases as Markdown tables with the note and the latest verdict, ready for a PR description or a team update.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: appeeky-spec-targets
|
|
3
|
+
description: Choose and prioritize the searches an app should be found for (the `targets` in appeeky.spec.yaml), from personas, competitors and keyword popularity. Use when asked which keywords to target, to do keyword research, to fill or clean up targets, to define personas, or to react to a competitor changing its title or subtitle.
|
|
4
|
+
metadata:
|
|
5
|
+
version: 1.0.0
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Choose targets with Appeeky Spec
|
|
9
|
+
|
|
10
|
+
`targets` in `appeeky.spec.yaml` are the searches the app should be found for, per storefront. Coverage, suggestions, rank baselines and release verdicts are all measured against them, so wrong targets make every later step wrong. Pick them before editing any listing.
|
|
11
|
+
|
|
12
|
+
Run commands as `npx @appeeky/spec <command> --json`.
|
|
13
|
+
|
|
14
|
+
## 1. Start from people, not words
|
|
15
|
+
|
|
16
|
+
Write down who the app is for as `personas`, with how each one searches:
|
|
17
|
+
|
|
18
|
+
```yaml
|
|
19
|
+
personas:
|
|
20
|
+
- id: new-parents
|
|
21
|
+
name: New parents
|
|
22
|
+
description: Need their baby to fall asleep, often at night with one hand free.
|
|
23
|
+
searches: [baby sleep sounds, white noise baby, lullaby]
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Ask the user when you cannot tell from the repo, website or current listing. `searches` are seeds, not final targets. Experiments refer to personas by id.
|
|
27
|
+
|
|
28
|
+
The same personas are the source of the AI visibility intents (`aiVisibility.intents`, see appeeky-spec-visibility). A persona's need ("fall asleep to rain sounds") is an intent. How they would ask an assistant is a prompt; it is longer and more conversational than a store search.
|
|
29
|
+
|
|
30
|
+
## 2. Collect candidates
|
|
31
|
+
|
|
32
|
+
From, in this order:
|
|
33
|
+
|
|
34
|
+
1. The personas' `searches`.
|
|
35
|
+
2. `suggest --json`: missing target words and Appeeky keyword ideas (with `APPEEKY_API_KEY`).
|
|
36
|
+
3. Competitors: `competitors pull` writes the searches each competitor ranks best for to `appeeky/competitors/`, and what the top apps for the seed searches put in their titles and subtitles. With the Appeeky MCP server connected, use its keyword and competitor tools for popularity, difficulty, rankings and recent metadata changes.
|
|
37
|
+
4. Store search suggestions in the storefront's language.
|
|
38
|
+
|
|
39
|
+
Drop other apps' brand names and trademarks, generic one-word terms the category giants own ("music", "photo"), and searches the app does not actually serve.
|
|
40
|
+
|
|
41
|
+
## 3. Prioritize
|
|
42
|
+
|
|
43
|
+
For each candidate, look at popularity (how many search it), difficulty (how strong the apps ranking for it are) and relevance (would someone searching this install this app?).
|
|
44
|
+
|
|
45
|
+
- Relevance first: an irrelevant search that ranks still does not convert.
|
|
46
|
+
- Prefer specific phrases with decent popularity over head terms a small app cannot reach ("screenshot organizer" over "screenshot").
|
|
47
|
+
- Keep about 5 to 15 targets per storefront. More cannot be covered by a 30 + 30 + 100 character listing and cannot be measured clearly.
|
|
48
|
+
- Put the most important target first; it should go in the name or the title.
|
|
49
|
+
|
|
50
|
+
## 4. Write them
|
|
51
|
+
|
|
52
|
+
```yaml
|
|
53
|
+
targets:
|
|
54
|
+
us: [screenshot organizer, screenshot search, screenshot manager]
|
|
55
|
+
de: [screenshots organisieren, bildschirmfotos suchen]
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Then `coverage --json`: anything `missing` is the next listing change (see appeeky-spec). Each language market needs its own research, never translated targets (see appeeky-spec-localize).
|
|
59
|
+
|
|
60
|
+
## Competitor moves
|
|
61
|
+
|
|
62
|
+
When a competitor drops a word from its title or subtitle, the search can open up; when it adds one of your targets, expect pressure on that rank. Check whether the word is one of your targets and how your rank moves, and propose a listing change only for a target that matters. Desktop lists these under ASO → Competitor moves.
|
|
63
|
+
|
|
64
|
+
## Changing targets later
|
|
65
|
+
|
|
66
|
+
Targets are the yardstick of every release. Change them deliberately, say why in the commit, and do not swap targets in the same release as a listing change you want to measure.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: appeeky-spec-visibility
|
|
3
|
+
description: Get an app named when people ask ChatGPT, Claude, Gemini or Perplexity for an app like it, and track its category chart rank, in an Appeeky Spec repo. Use when asked about AI visibility, AI search, LLM or GEO/AEO recommendations, "does ChatGPT recommend us", which questions to track, why a competitor is named instead, or how the app ranks in its category.
|
|
4
|
+
metadata:
|
|
5
|
+
version: 1.0.0
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# AI visibility and category rank with Appeeky Spec
|
|
9
|
+
|
|
10
|
+
Two ways people find an app outside a keyword search: they ask an AI assistant, or they browse the category chart. The spec records both and `verify` measures them around every push.
|
|
11
|
+
|
|
12
|
+
Run commands as `npx @appeeky/spec <command> --json`.
|
|
13
|
+
|
|
14
|
+
## AI visibility
|
|
15
|
+
|
|
16
|
+
### The model
|
|
17
|
+
|
|
18
|
+
- An **intent** is what someone wants: "fall asleep to rain sounds". Labels need 8+ characters.
|
|
19
|
+
- A **prompt** is one way to ask for it: "what app plays rain sounds to help me sleep". Prompts need 15+ characters.
|
|
20
|
+
- Both live in `appeeky.spec.yaml` under `aiVisibility.intents.<country>`. Appeeky AI Visibility asks each assistant every prompt on a schedule. It records whether the answer names the app, in what position, who else is named and which pages are cited.
|
|
21
|
+
|
|
22
|
+
Needs `APPEEKY_API_KEY` on a plan with AI Visibility.
|
|
23
|
+
|
|
24
|
+
### Set up
|
|
25
|
+
|
|
26
|
+
1. `visibility init`. If Appeeky already tracks intents, they are written into the spec. If not, Appeeky writes them from the store listing in the background; run `init` again a few minutes later.
|
|
27
|
+
2. Read the intents with the user. Keep the ones a real person of a persona would ask (see `personas` in the spec). Drop vague ones.
|
|
28
|
+
3. After the user approves the edits (in a pull request), run `visibility sync`. It only adds. It lists what exists only in Appeeky and archives it only with `--prune`, which you run only when the user asks.
|
|
29
|
+
|
|
30
|
+
Good prompts:
|
|
31
|
+
|
|
32
|
+
- Sound like a person typing: "best white noise app for a newborn", not "white noise app".
|
|
33
|
+
- Never contain the app's own name (that measures nothing) or a competitor's name.
|
|
34
|
+
- Each intent gets 2 to 4 prompts phrased differently: a question, a request for a list ("top 5…"), a comparison need ("an app like X but free" is fine without naming X).
|
|
35
|
+
- Use the storefront's language. A `de` intent gets German prompts written for German speakers, not translations.
|
|
36
|
+
|
|
37
|
+
### Read the results
|
|
38
|
+
|
|
39
|
+
`visibility pull` writes `appeeky/visibility/<country>.yaml`:
|
|
40
|
+
|
|
41
|
+
| Field | Meaning |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| `summary` | intents by status: `winning` (named in 25%+ of answers), `weak`, `missing`, `noData` (not scanned yet) |
|
|
44
|
+
| `intents[].you` | share of answers that name the app, averaged over the assistants, 0–100 |
|
|
45
|
+
| `intents[].byModel` | the same per assistant: one assistant can name you while another never does |
|
|
46
|
+
| `intents[].namedInstead` | who the assistants name instead, with their share |
|
|
47
|
+
| `sources` | pages the assistants cite (mostly Perplexity), most cited first; `yours: true` is the app's own site |
|
|
48
|
+
| `fixes` | open suggestions from Appeeky for an intent |
|
|
49
|
+
|
|
50
|
+
`appeeky/visibility/changes.md` keeps what moved between pulls: an intent that went from `missing` to `winning`, or the app's site starting to be cited.
|
|
51
|
+
|
|
52
|
+
### Improve it
|
|
53
|
+
|
|
54
|
+
Assistants repeat what the web says about an app. In order of what you can change:
|
|
55
|
+
|
|
56
|
+
1. **The listing.** The first lines of the description and the subtitle should say what the app does in the intent's words ("rain sounds for sleep", not "an immersive audio experience"). This is a normal listing change: propose it in a pull request and measure it like any release (see appeeky-spec).
|
|
57
|
+
2. **The app's own website.** A page per main use case, in plain words, with the app's name and store links. When `sources` shows the assistants cite pages like it from competitors, the same kind of page is the gap.
|
|
58
|
+
3. **Cited third-party pages.** `sources` lists them: review sites, Reddit threads, "best apps for…" articles. Tell the user which ones name the competitors in `namedInstead` but not the app. Getting listed there is the user's outreach, not something to fake.
|
|
59
|
+
4. **`fixes`.** Read each one. Propose the ones that are listing or website edits; summarize the rest for the user.
|
|
60
|
+
|
|
61
|
+
Never write fake reviews, posts or comments, and never make claims the app does not live up to. Assistants also read those.
|
|
62
|
+
|
|
63
|
+
### Measure it
|
|
64
|
+
|
|
65
|
+
`verify` reads Appeeky's daily series as `ai_visibility`, the 0–1 share of answers that name the app. It compares the days before a push with the days after. Assistant answers change slowly and scans may be weekly, so a day-7 move is a hint and day 14 counts. `visibility scan` asks the assistants now. It uses AI Visibility credits: run it only when the user asks.
|
|
66
|
+
|
|
67
|
+
## Category rank
|
|
68
|
+
|
|
69
|
+
`category pull` adds today's rank in the category chart (top 100) for each storefront to `appeeky/category.csv`.
|
|
70
|
+
|
|
71
|
+
- **App Store:** reads Apple's chart, no key. The genre comes from the app, and a paid app is read from top-paid.
|
|
72
|
+
- **Google Play:** needs `APPEEKY_API_KEY` and `category.googlePlay` in the spec (e.g. `HEALTH_AND_FITNESS`). Ask the user for the category if it is not set.
|
|
73
|
+
- An empty rank means not in the top 100.
|
|
74
|
+
|
|
75
|
+
The rank mostly follows downloads, so it moves with everything: listing changes, ads, featuring, seasonality. Read it as a sign, not a cause:
|
|
76
|
+
|
|
77
|
+
- `verify` reads it as `category_rank`, where lower is better. When no target search moved and there is no analytics data, it decides the release (`decidedBy: ["category_rank"]`). Say so.
|
|
78
|
+
- A jump on the day an ad campaign started is the ad, not the listing. Check `appeeky ads` and `loops.md` first.
|
|
79
|
+
- It needs history: run it daily (the daily workflow does) so there are days before each push.
|