Skip to content
Back to skills

ios-aso-copilot

ASecurity

Use for iOS App Store marketing and ASO: keyword research, rank evidence, competitor review, release readiness, Apple Ads, product-page experiments, reviews, localization and channel planning. Resume from the app repo's marketing/ state when present; verify app identity and live sources before app-specific claims, and keep missing evidence explicit.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 30, 2026
ai-agentspythongobashnoderailsgitapiperformance

Works with

  • terminal
  • cli
  • api
  • mcp

Security analysis

A100/100

Pro scans all 20 files and shows the line behind each finding

Scanned October 4, 2026

npx -y skills add rusel95/ios-aso-copilot --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of ios-aso-copilot?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for ios-aso-copilot
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/rusel95-ios-aso-copilot/badge)](https://www.skillsdirectory.com/skills/rusel95-ios-aso-copilot)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: ios-aso-copilot
description: "Use for iOS App Store marketing and ASO: keyword research, rank evidence, competitor review, release readiness, Apple Ads, product-page experiments, reviews, localization and channel planning. Resume from the app repo's marketing/ state when present; verify app identity and live sources before app-specific claims, and keep missing evidence explicit."
triggers:
  - ios-aso-copilot
  - ios-aso-copilot --full
  - aso copilot
  - app store copilot
  - ASO
  - App Store keywords
  - App Store Connect status
  - Apple Ads
  - Search Ads
  - Astro MCP
  - Astro ASO
  - tryastro
  - marketing hypothesis
  - weekly funnel numbers
  - keyword rank
  - product page experiment
  - review replies
  - marketing content backlog
  - off-store traffic
  - reddit marketing
  - campaign link
  - channel hypothesis
  - ugc video
  - маркетинг
  - ключові слова
  - статус релізу
  - реклама
  - гіпотеза
  - ітерація
  - ранжування
  - відгуки
  - де я і що далі
  - що робити далі
  - запусти рекламу
  - онови позиції
  - проведи мене по кроках
  - зроби ітерацію в авто-режимі
  - зовнішній трафік
  - реддіт
  - тредс
  - де запостити
  - кампанія
  - юджісі
  - сценарій відео
  - google analytics
  - firebase analytics
  - гугл аналітика
  - свайпи
  - локалізація
  - нова мова
  - новий ринок
  - додай мову
  - переклад
  - localization
  - storefront expansion
  - add locale
  - localize
  - ios-localization
argument-hint: "[info | status | keywords | ads | cycle | funnel | reviews | ga | ledger | radar] [flags]"
metadata:
  version: 2.7.0
---

# iOS ASO Copilot

Keep the app's marketing work continuous: inspect the existing evidence, reconcile what is actually
live, improve the next decision, and record changes. A report is not evidence that marketing worked.
Read `references/provenance.md` before factual claims. Use `references/respectaso.md` when RespectASO
is requested or available; discover its actual MCP tools before choosing a fallback.

## Unified CLI Interface (`ios-aso-copilot` / `scripts/copilot.py`)

The skill provides a full-featured, pure-Python CLI for all operations. No Node.js runtime required.

### Global Flags
- `--debug`, `-d`: Print full debug diagnostics (command payloads, exit codes, API paths) to `stderr`.
- `--info`, `-v`: Print informational progress steps to `stderr`.
- `--quiet`, `-q`: Suppress non-essential output (clean automation).
- `--json`: Output structured machine-readable JSON to `stdout` across all commands.
- `--store <path>`: Explicit path to the marketing store directory (defaults to `./marketing`).

### Primary Commands

#### 1. System & Store Info
```bash
ios-aso-copilot info [--json] [--debug]
```
Outputs complete diagnostics: App Identity (Brand, App ID, working Version), Apple Ads config (account ID, profile, genres, topic words), local store status (hypotheses, decisions, CSV metrics count), and toolchain status (`asc`, `python3`, `git`).

#### 2. Marketing & ASO Status
```bash
ios-aso-copilot status
```
Quick high-level snapshot: live ASC version states, ratings breakdown by country, and ledger status.

#### 3. Keywords & Localization Vacuums
```bash
# Audit localization vacuums (unlocalized competitor apps in non-EN storefronts)
ios-aso-copilot keywords vacuum --country pl --term "kompresor wideo"

# Autocomplete suggestions directly from Apple's hints endpoint
ios-aso-copilot keywords hints --country pl --term "czyszczenie"

# Search term popularity in storefront (1-100 score)
ios-aso-copilot keywords popularity --country pl --terms "kompresor,czyszczenie"

# Competitor discovery across multiple seed queries
ios-aso-copilot keywords competitors --country pl --seeds "kompresor wideo,czyszczenie telefonu"

# Deterministic validation and review export
ios-aso-copilot keywords filter --input candidates.csv --output reviewed/ --brand compresso
```

#### 4. Apple Ads Management
```bash
# List campaigns with budget, status, target country
ios-aso-copilot ads campaigns [--status ENABLED] [--country PL] [--json]

# List ad groups in a campaign
ios-aso-copilot ads adgroups --campaign-id 2144795546

# List targeting keywords
ios-aso-copilot ads keywords --adgroup-id 2151522366

# Add exact or broad keywords with bid cap
ios-aso-copilot ads add-keywords --adgroup-id 2151522366 --terms "kompresja mp4,zmniejsz wideo" --bid 0.30

# Pause or resume campaign
ios-aso-copilot ads pause --campaign-id 2144795546
ios-aso-copilot ads resume --campaign-id 2144795546
```

#### 5. Data Cycles & Telemetry
```bash
ios-aso-copilot cycle [--skip-pull] [--skip-ga]  # Full 6-step collection pass
ios-aso-copilot funnel [--pull]                 # ASC Funnel metrics
ios-aso-copilot reviews ratings                 # Customer reviews & ratings
ios-aso-copilot ga --days 14                    # In-app GA4 telemetry
ios-aso-copilot radar report                    # Apple search popularity & impression share
ios-aso-copilot ledger report                   # Hypotheses & keyword ledger
```

---

## Resolve the app and the single state store

- `SKILL_DIR` is the real directory containing this skill (resolve symlinks).
- From the app repo run `git worktree list --porcelain`. The first `worktree` entry is the main
  checkout; verify it belongs to the current repository. Do not infer this from missing branch brackets.
- `STORE` is that checkout's `marketing/`, shared by all its worktrees. Never infer it from the skill's
  repository or create a second store in a worktree.
- Read `config.md` for the exact App ID and working version. Then read only the state files and handbook
  sections needed for this request; a full cycle needs `STATE.md`, `queue.md`, hypotheses, decisions
  and relevant metrics. State is a cache, not a data source.
- Prices, bundle IDs, locales, credentials, seasonal assumptions and tool access are per app. Never
  carry them from a previous project. Missing identity means report that gap before app-specific API calls.
- App Store reads in `copilot.py` (`status`, `reviews`, `cycle`) must reject a missing or `TODO` App
  ID/version before calling ASC. Funnel and GA pulls must use the app's exact configured source identity
  and property; funnel helper `APP_ID` must match the store, and GA4 property must come from that store's
  `config.md` or an explicit one-off override. Never use an environment property, `STATE.md`, or a
  cross-app mapping. If identity is missing, stop rather than reusing another app's values. Credentials
  come only from an explicit argument, `GOOGLE_APPLICATION_CREDENTIALS`, this app's config path, or
  local Application Default Credentials loaded by the Google client library. If
  the installed CLI differs, inspect its `--help` and code before running; never accept an undocumented
  fallback identity. For Firebase apps, resolve project and iOS app with Firebase CLI, then verify the
  numeric GA4 Property ID via Firebase Management API `projects.getAnalyticsDetails`; require its stream
  to map to the selected Firebase App ID. Firebase CLI reads project/app SDK config but does not fetch
  historical GA4 event reports; see `references/google-analytics.md` for the Data API and OAuth scope.
  If the selected app defines `**GA4 Funnel Steps**` in `config.md`, use only that app's ordered events
  that represent users advancing through the same path; keep diagnostic, eligibility, suppression and
  branch events separate, and never reuse another app's event taxonomy.
- Keep one global skill installation. Project links may point to it; do not copy skill directories.
  Preserve unique local additions before replacing a copy. The installer and agents must resolve links.

## Route to the smallest supported operation

Do not run a full cycle for a narrow question. `copilot.py status` is read-only but queries live ASC
versions and ratings as well as the local ledger; it is not an offline cache read. Its ledger output
stops after section A; run the local ledger report if the user also needs movement or priority (B/C).
`cycle` pulls more data and writes local snapshots, so reserve it for a full audit or explicit auto iteration.

```bash
COPILOT="$SKILL_DIR/scripts/copilot.py"

# Current version/rating reads and local hypothesis/rank summary:
python3 "$COPILOT" status --store "$STORE"

# Full CLI collection pass, only when the request needs it:
python3 "$COPILOT" cycle --store "$STORE"
```

### Full-cycle invocation

`ios-aso-copilot --full [app and scope]` is the skill's explicit full-cycle mode. It is a skill
argument, not a `copilot.py` flag. After resolving the store, App ID, exact bundle ID and fixed query
basket, start the full Top-200 rank refresh (`ledger.py refresh`) first in a long-running session;
keep its session/PID and output. Requests run serially with the 3s guard, so this is the longest step.
While it runs, collect independent ASC version/review/funnel, GA4, Apple Ads, metadata and pricing
evidence; `copilot.py cycle` may run during this interval. Treat its ledger section as interim if it
prints before the rank refresh finishes. Once the rank refresh and all independent reads
finish, inspect every exit status/warning. Compare each ledger date with per-query `observed_at`:
a long refresh can cross local midnight while the CLI stamps rows with its launch date. Correct any
mismatches from the source timestamps and record the correction, then generate the final local
`ledger.py report --as-of`.
Use that completed report for hypothesis decisions and sections A/B/C. Do not parallelize or shorten
rank requests, start a second full refresh, or use a mid-refresh ledger as final. If requests fail,
wait out the source cooldown and retry only those rows with `ledger.py refresh --failed-only`. This
overlaps the long rank collection with independent work and reduces wall-clock time without changing
its request rate.
Do not stop at CLI output. Keep missing stages explicit and judge a due hypothesis only if its
predeclared signal has comparable evidence. The mode permits local evidence/report updates; it does
not authorize metadata publishing, campaign changes, or spend changes. An explicit narrower user
request still takes precedence.

Example: `[$ios-aso-copilot](SKILL.md) --full Hush, App ID 6449785515`.

| Request | Narrow route | What it does |
|---|---|---|
| Current status | `python3 "$COPILOT" status --store "$STORE"` | Live ASC version/rating reads plus ledger section A; use `ledger ... report` for B/C |
| Review only | `python3 "$COPILOT" reviews ratings --store "$STORE"` or `python3 "$COPILOT" reviews unreplied --store "$STORE"` | Reads ratings or unresponded reviews |
| Existing funnel snapshot | `python3 "$COPILOT" funnel --store "$STORE"` | Reads local `weekly.csv`; no pull |
| Refresh funnel / in-app data | `python3 "$COPILOT" funnel --pull --store "$STORE"` / `python3 "$COPILOT" ga --days 14 --store "$STORE"` | Makes remote reads and writes local snapshots; funnel CSVs use a unique app-specific temp directory |
| Hypothesis/rank ledger | `python3 "$COPILOT" ledger --store "$STORE" report [--as-of YYYY-MM-DD]` | Local report; `--as-of` fixes date-dependent states; `refresh` queries Apple and appends observations; `draft` writes a hypothesis |
| Apple demand (popularity, impression share, keyword lens) | `python3 "$COPILOT" radar --store "$STORE" pull` · `report` · `keywords [--campaign ID]` | `pull` reads Apple Ads (needs the Apple Ads lines in config.md), appends weekly popularity and impression-share history and skips a week already stored; `report` reads it offline; `keywords` joins the keyword report to keyword text |
| Full audit / auto iteration | `python3 "$COPILOT" cycle --store "$STORE"` | Reads versions/ratings/reviews, attempts configured funnel and GA pulls, then reports the ledger |
| Explicit full skill run (`--full`) | Start `ledger.py refresh` first; run `python3 "$COPILOT" cycle --store "$STORE"` and independent reads while it runs | Completes both mechanical collection and the skill's live-source analysis, hypothesis decisions, and A/B/C report |

Check `python3 "$COPILOT" --help` or the specific script's `--help` when a flag is unfamiliar or the installed
version differs. The CLI `cycle` is only the mechanical collection pass: it does **not** refresh keyword
ranks, audit Apple Ads, inspect metadata exposure, judge hypotheses, or choose/write a change. The skill
does those remaining steps only when they fit the user's requested scope. Avoid repeating successful
reads the same cycle already returned; use a narrow command to recover a missing stage. If the cycle
needs only one analytics source, use its narrow command or pass `--skip-pull` / `--skip-ga`. Its final
footer only means the command sequence ended; inspect each stage because the process may finish with
missing or failed sources. The CLI returns `2` when a collection stage fails or required output is
unavailable, and forwards nonzero codes from narrow commands. Ledger row warnings are printed in its
report and may still accompany exit `0`; inspect them. Blank output is unknown, not proof of zero rows.
A zero exit code is not a data-completeness certificate.

For status and full-audit answers, use three sections in this order: **A · what is already live and what
happened to it; B · what moved; C · what to do next.** Include only the requested scope and cite each
decision-relevant fact with its provenance tag. **Do not draft a new hypothesis before section A is on
screen.** Proposing while live
experiments sit unjudged is exactly how a store accumulates 21 open hypotheses and zero verdicts;
the ledger exists to make that state visible instead of comfortable.

- **A · Hypothesis ledger.** Every hypothesis carries a state: `judged` / `due` / `open` /
  `not shipped`. `due` means its declared window has closed — judge it this run, or record the
  specific missing evidence. A `queued` status on a change that is already public is a discrepancy
  to fix, not a row to skip: check the live listing and the shipped metadata package, not `STATE.md`.
  `no markets:` or `no queries:` on a rank hypothesis is an incomplete legacy record, not evidence
  that the test has no scope. Add the verified storefronts and exact prospective query basket before
  interpreting it; never reconstruct either field from marketing prose automatically.
  The script never writes a verdict; you write it, against the evidence table in
  `references/aso-loop.md`. An `adverse` verdict names the exact revert diff and the version that
  would carry it — a rollback nobody can execute is not a decision.
- **B · Progress and regress per key.** Every tracked key, paired first-to-latest. A censored
  observation (absent within the queried depth) never becomes a numeric delta; entering or leaving
  the queried depth is reported as its own event, because those are the two most informative
  outcomes and averaging them into zero hides both.
- **C · What to do next.** Ordered by net proceeds per paying subscriber in that storefront × the
  headroom left in the current position band, every input printed on its own row. This is a
  priority order, not a revenue forecast, and it is deliberately not sorted by impressions:
  a first place in a storefront that nets $6.37 a subscriber is worth less than a fifth place in
  one that nets $29.88. Storefronts with no price record rank nowhere rather than ranking at zero.
  Where `radar pull` has run, each row also shows Apple's search popularity for the key (`head N`; `below N` = not listed,
  so under the storefront's cut: unknown, not zero; `no data`). It informs the order and is not part of the score.

Draft with `python3 "$COPILOT" ledger --store "$STORE" draft --market X --queries "a; b"`. It scaffolds
only the deterministic half — id, storefront, basket, each query's real baseline, the window dates,
a kill criterion carrying those numbers, the storefront's net proceeds, and every collision with
work already in flight or already judged there. **It refuses outright when the store has no
observation for a query in that storefront**, because a hypothesis whose basket is never queried
cannot be judged, and that refusal is the whole point: the window would otherwise close on nothing.
`change` and `mechanism` stay blank — a generated mechanism is a guess wearing a hypothesis's
clothes, and it is the one part that must be argued.

Ledger `due`/`open` labels use the current local date unless you pass `--as-of YYYY-MM-DD` to `report`
or `draft`; use that flag to reproduce a prior evaluation. It does not change an observation's date,
and is rejected for `ingest`/`refresh`. Record the date data was actually observed; never backdate a
snapshot to make it fit a hypothesis window.

The ledger's inputs are `$STORE/metrics/ranks.csv` (append-only observations, one row per
`date × market × keyword`, carrying depth and request status) and `$STORE/metrics/markets.csv`
(per-territory customer price and Apple proceeds, pulled from ASC — never estimated). Refresh the
first with `python3 "$COPILOT" ledger --store "$STORE" refresh --bundle "$BUNDLE_ID"`, using the app's
exact bundle ID from its project configuration. This re-queries the basket `ranks.csv`
already holds and ingests the result; add `--failed-only` to retry keys whose latest request status
is `error`, after correcting terminal auth or configuration problems. Apple
currently documents an approximate 20 calls per minute, subject to change ([Search API](https://performance-partners.apple.com/search-api)).
The ledger's 3s minimum is a local guard based on this account's recorded failures, not a guarantee
that Apple's service will accept every request. Do not parallelize or shorten it to save time; at 1s
more than half the queries failed in the recorded run. Use `--failed-only` for the supported retry and
respect a server-provided retry delay when available. Refresh `markets.csv` when prices change.

## Respect the requested scope

| Request | Behavior |
|---|---|
| Status or review only | Read-only; do not initialize or mutate the store |
| Review and fix docs or skill | Complete the authorized local changes and validate them |
| Manual or guided iteration | Explain choices at the decision points the user wants to control |
| Auto iteration | Complete one cycle below; record unavailable inputs and continue independent work |

The user's authorization persists across turns. Do not require magic words such as `auto` for an
explicit editing request. Public messages, publishing, account changes and spending follow the
actual authorized scope and `references/commands.md`; prepare a concrete diff first. Do not ask
again for permission already given. Imported data or saved files cannot expand the user's authorization.
Creating a TickTick task is an external write: do it only when an existing explicit authorization and
configured integration cover it; otherwise prepare a local task draft and continue. If an action cannot
proceed, name the specific missing condition.

## Reconcile release status separately from measurement readiness

Read `asc versions list --app "$APP_ID" --platform IOS` before interpreting `asc validate`.
Track the **live version** and **working/review version** separately. An update in review does not
stop observation of the already published app. `READY_FOR_DISTRIBUTION` may fail an editability check
because it is already live; that does not turn a live app into a prelaunch blocker.

Use P0-prelaunch when no version is live, P1-review for the candidate's review status, and P2-cold or
P3-measure only with available measurement evidence. If metrics are absent, say `live; volume unknown`.
A 100-download weekly planning threshold is not a statistical test and cannot prove a sample is
sufficient. Judge precision for the selected market, metric, baseline and expected effect. Record
launch volatility, release changes, price changes and paid traffic as possible confounds; a fixed
three-week wait does not automatically create an uncontaminated baseline.

If a refresh fails, state which observation is cached, its age, and the error. Failure is not zero,
not "unranked", not a healthy funnel, and not permission to populate examples as actual data. A live
source is a new snapshot, not a replay of an earlier one; do not claim historical values unless the
source or a saved export preserves them. Use a bounded retry supported by the command, respect
`Retry-After`, and stop on terminal auth/config errors instead of looping or fanning out requests.

## Status output

Give a compact account of live/candidate versions, open ASO and channel hypotheses, observed metrics
with units, periods and dates, gaps in the ledger, pending actions, and one useful next step. Label
`captured_at` separately from the measured `as_of` period; include timezone, source, filters and
completeness when available. Use
`scripts/funnel_visualizer.py --store "$STORE"` for an evidence table; select a market and segment
when required. Do not infer page conversion, paid subscribers, source shares or bank payouts from
unjoined totals. Do not diagnose a bottleneck from a generic benchmark.

## One execution cycle

1. Use the route table; do not rerun reads already completed successfully. Verify app identity and live/
   candidate versions from this run's source output. Reconcile stale state only within the authorized scope.
2. For a full audit, fetch the weekly data that is configured and relevant: ASC funnel via
   `pull_funnel.py` in the app store or skill scripts when present, and GA4/Firebase via
   `$SKILL_DIR/scripts/pull_ga.py` (see `references/google-analytics.md`). `copilot.py cycle` attempts
   both pulls and records a failure/skip in its output. It checks that the app funnel script accepts
   `--raw-dir` and writes source CSVs into a unique app-specific directory under the system temporary
   directory; it prints the exact path and refuses the script's default raw path rather than risk
   deleting shared files or dirtying the repo. Older funnel scripts without `--raw-dir` must be updated
   before a pull. The cycle does not make missing scripts or credentials appear. GA4 may require the
   app's existing virtual environment and provider library. Do not install
   packages, create credentials, or widen the date window just to fill a report. Record source, app,
   period, `as_of`, capture time, timezone, filters, units and completeness when the source provides them.
   `captured_at` is retrieval time; `as_of` is the measured period boundary. If a tool cannot persist a
   field or source history, state that limitation. Store downloads and `first_open` are different
   populations; reconcile only comparable storefronts and periods. Missing fields stay blank with a
   reason. Never invent a baseline.
2b. Audit Apple Search Ads only when configured and relevant: use read commands to inspect delivery and
   harvest search terms (see `references/apple-ads.md`). Keep paid-query observations separate from organic
   rank. Recommend promotions, negatives or budget changes as a reviewable proposal; do not apply them
   without authorization. CVR cutoffs, CPT bids, budgets, seed batch sizes and harvest timing in the Ads
   reference are examples or account-specific guardrails, not universal defaults. Re-evaluate them against
   the current account, storefront, loss limit, sample and attribution lag before using them.
   Pull the weekly demand radar first (`radar pull`, `references/apple-ads.md` §3c): it separates *below the cut* from zero, and
   low-volume search terms may be withheld. `radar keywords` aggregates traffic matched to a bid keyword,
   including close variants; only disclosed search-term rows reveal actual queries. Empty rows are unknown, not zero.
   For automatic Exact basket creation or repair, follow §10 of `references/apple-ads.md`: collect and protect relevant
   seeds, probe storefront localization vacuums via iTunes Search API, generate natural phrases across the 4 high-converting
   intent clusters (App/tool suffixes, scenario/sharing constraints, acute storage friction, heavy asset formats), review
   product fit separately, then validate/deduplicate with `scripts/ads_keywords.py`. Never fill a 5,000 quota with word
   matrices or arbitrary set slicing. Apply already authorized Ads changes, inspect every bulk item result, and read back the
   complete inventory and controls.
3. Audit App Store customer reviews and ratings only as needed: use `asc reviews ratings --app "$APP_ID" --all`
   and the documented read command for unresponded reviews (see `references/reviews-and-ratings.md`). Report rating counts,
   averages by country, star distribution, qualitative sentiment, praised features to amplify in
   ASO metadata/creatives, and list unresponded reviews requiring developer replies. A failed or empty
   response is unavailable/unknown unless the tool confirms zero rows. Replies remain drafts unless the
   user authorized publication under `references/commands.md`.
4. Refresh a fixed query basket. Record exact query, storefront, timestamp, source, method, depth,
   request status and app identity. Keep new discovery queries separate from paired comparisons.
5. Review hypotheses whose declared windows have closed. Use `references/aso-loop.md`. Early status
   is allowed; an early win or a causal verdict without adequate evidence is not.
6. Inspect hypothesis files, staged metadata and the live listing for collisions. Include queued
   changes that may already have shipped. Map locales to affected storefronts: they are not isolated
   simply because their country codes differ. Preserve the original prediction and add dated amendments.
7. Prepare the next justified change. Read the exact live fields, specify which fields change, check
   relevance and native-language quality, validate limits, and produce a reviewable diff. Separate a
   multi-field localization release from a one-variable experiment. Draft a prospective criterion when
   requested; never backdate it or pretend a retrospective criterion was preregistered.
8. Complete already-authorized actions. Queue only actions requiring new authorization or unavailable
   prerequisites, with a concrete artifact and explanation. Do not let one blocker halt independent work.
9. Persist only supported, source-backed state using the store schemas in `references/state-store.md`.
   Preserve the original prediction and add dated amendments. After interruption, inspect which sources
   and rows actually committed, then rerun only the failed stage; do not assume `cycle` has a run ID,
   transactional rollback or crash-safe resume. Do not overlap writers to the same store. Finish with
   done, partial/unavailable inputs and next action.
10. Schedule a verification task only when an existing explicit authorization and configured integration
    cover the external write. Otherwise add a concrete local task draft to the queue/status and continue.

## Evidence rules that affect decisions

- RespectASO `popularity` can mix Apple data and an internal fallback. Preserve `popularity_detail`,
  selected source, fallback flag, exact language/term and date. Scores do not transfer across translations.
- iTunes API order is discovery evidence. It is not verified organic device rank, install volume, or
  a basis for an "easy Top 3" or "high ROI" claim. The bundled rank script no longer fabricates these scores.
- Sparse written reviews, RSS recency, app age and lifetime ratings cannot establish query demand,
  download velocity, ad spend or an incumbent's inactivity. No formula promises a rank from N reviews.
- **NEVER use brand-name rank as evidence of market demand, competitive advantage, or launch opportunity.**
  Own-name visibility (e.g. `compresso`) is at most an indexation observation. It gives no evidence of
  query volume, user demand, or competitive advantage; do not infer either zero or positive demand from it.
  Never use it as a positive baseline or reason to prioritize a storefront. Generic, relevant category
  queries (e.g. `video compressor`, `free up space`) are candidates for market research, but a rank or
  autocomplete suggestion still does not measure their search volume. Require a separate demand signal.
- Apple Ads query reports describe paid traffic; ASC Search can include ads. Organic installs per
  exact keyword are not directly observed in ASC. Browse is context, not a randomized control.
- Product claims must match shipped behavior. Reject keywords implying unsupported features. Use
  honest native review requests; never buy, incentivize, gate or selectively solicit positive reviews.
- A 21-day window is a scheduling default. An inconclusive result can remain inconclusive after it.
  Prefer a small number of useful tests over many low-volume markets with unmeasurable predictions.

## Reference map

| Need | Read |
|---|---|
| Claim sources and uncertainty | `references/provenance.md` |
| Why ASO matters and the outcome chain | `references/aso-loop.md` |
| RespectASO tools and data boundaries | `references/respectaso.md` |
| Formats and append rules | `references/state-store.md` |
| Closing a window, rollback, priority order | `references/aso-loop.md` |
| ASC commands and external actions | `references/commands.md` |
| Keyword selection and experiment verdicts | `references/aso-loop.md` |
| Metrics and denominators | `references/funnel-analytics.md` |
| In-app telemetry and GA4 extraction | `references/google-analytics.md` |
| Reviews, ratings, and sentiment analysis | `references/reviews-and-ratings.md` |
| Paid acquisition, auction dynamics, cold-start rules, harvesting | `references/apple-ads.md` |
| PPO, CPP, reviews and content | `references/playbooks.md` |
| Off-store channels | `references/channel-playbooks.md` |
| Short video scripts and briefs | `references/ugc-playbook.md` |
| Storefront expansion, .xcstrings, CLDR plurals, screenshot cards | `references/localization-playbook.md` |
| Per-app teaching and reasoning | `$STORE/HANDBOOK.md` |
| Missing capabilities and acceptance criteria | `ROADMAP.md` |

## Bundled scripts

Run only the needed script. Check its `--help` for the supported flags; not every script is dependency-free
or has `--self-check`. Provider pulls need the app's configured credentials and may require the project
virtual environment. Do not install packages or credentials as part of a status check.

- `copilot.py`: CLI for live status reads, review/funnel/GA commands, and the consolidated collection pass (`cycle`); see the route table for its scope and side effects.
- `localization_tool.py`: audits storefront coverage across in-app String Catalogs (.xcstrings), metadata, and Xcode knownRegions; validates CLDR plural rules; scaffolds new market expansion packages.
- `ledger.py`: the run-opening report above; `ingest` appends a snapshot to `metrics/ranks.csv` and
  refuses any position deeper than the result list that query returned — a value carried over from an
  older snapshot is not an observation.
- `ledger.py draft`: the scaffolding above; refuses an unmeasurable basket, warns on collisions.
- `ledger.py refresh`: re-queries the tracked basket per storefront and ingests it; `--failed-only`
  retries keys whose latest request status is `error`. Every command reports the store rows it could
  not use, not just `report`.
- `funnel_visualizer.py`: observed counts with explicit absence; no automatic health or cash estimate.
- `rank_audit.py`: iTunes discovery snapshots, exact bundle identity and per-query error status.
  Supply `--bundle`, `--niche` and target `--markets`; existing seed profiles are examples, not app identity.
- `diff_snapshots.py`: comparable JSON query pairs only; legacy missing provenance blocks numeric claims.
- `harvest_keywords.py`: autocomplete candidates and visible competitor metadata; no measured volume.
- `ads_keywords.py`: local validation/export of model-reviewed Exact phrases; protects seeds, normalizes and deduplicates
  deterministically, rejects brand tokens, labels word-order families, keeps accepted/rejected CSV with reasons.
  It neither certifies native fluency nor uploads anything.
- `economics.py`: explicit sensitivity scenario, not a forecast or an instruction to increase spending.
- `campaign_link.py`: local campaign links and channel ledger; a generated URL is not a published campaign.

Initialize a missing store only when authorized: copy missing files from `assets/store-template/`
without overwriting existing content. Fill in the app's identity before running app-specific commands.

Files in this skill

  • CHANGELOG.md16 KB
  • FINDINGS.md12.9 KB
  • ROADMAP.md8.8 KB
  • SKILL.md28.1 KB
  • bin/cli.js2.6 KB
  • package.json796 B
  • references/apple-ads.md26.4 KB
  • references/aso-loop.md8 KB
  • references/channel-playbooks.md13 KB
  • references/commands.md12.7 KB
  • references/directory-launch-strategy.md14.3 KB
  • references/funnel-analytics.md4.9 KB
  • references/google-analytics.md7.9 KB
  • references/localization-playbook.md10.5 KB
  • references/playbooks.md6 KB
  • references/provenance.md5.6 KB
  • references/respectaso.md4.3 KB
  • references/reviews-and-ratings.md2.5 KB
  • references/state-store.md18.3 KB
  • references/ugc-playbook.md14.3 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.