Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🛡️ Heimdall

An App Store submission gatekeeper for Claude Code.

Heimdall audits your iOS app against 141 checks derived from the App Store Review Guidelines and the highest-volume rejection reasons, scores your odds of passing review out of 100, and fixes what it finds.

Heimdall guards the Bifröst. Nothing crosses without being seen.

Roughly a third of first submissions get rejected, and most of those rejections are preventable — a dead privacy policy URL, a missing Restore Purchases button, a demo account that expired, a screenshot of a feature you cut. Heimdall finds those before Apple does.


Install

git clone https://github.com/UppercutLabs/heimdall.git ~/.claude/skills/heimdall

That's it. Claude Code picks up skills from ~/.claude/skills/ automatically. Restart your session and run /heimdall.

For a project-scoped install, clone into .claude/skills/heimdall inside the repo instead.

Strongly recommended: the App Store Connect CLI

Heimdall works standalone, but about 60 of its 141 checks live on Apple's side — metadata, screenshots, IAP state, agreements, age rating, build status, review history. Without API access those become "unknown" and cost you points.

brew install asc

Then create an API key at App Store Connect → Integrations and log in:

asc auth login --name "Heimdall" --key-id "KEY_ID" --issuer-id "ISSUER_ID" --private-key ./AuthKey.p8

asc is App-Store-Connect-CLI by Rork — a separate project, and a very good one. Heimdall will prompt you to install it if it's missing, and runs in a degraded mode if you'd rather not.


Use

/heimdall
Command What it does
/heimdall Full audit — codebase plus App Store Connect
/heimdall quick Codebase only, no API calls, ~2 minutes
/heimdall fix Audit, then apply every safe fix
/heimdall paywall Guideline 3.1 deep dive — IAP, subscriptions, paywall UX
/heimdall metadata Guideline 2.3 — name, keywords, screenshots, description
/heimdall privacy Guideline 5.1 — labels, ATT, purpose strings, account deletion
/heimdall completeness Guideline 2.1 — the single largest rejection bucket
/heimdall report Re-render the last findings as a shareable page

Works with native Swift/Objective-C, React Native, Expo, Flutter, and Capacitor projects.


What it checks

141 checks across nine categories, weighted by how often each one actually causes a rejection rather than by how many checks it contains:

Category Guideline Weight Checks
App completeness & functionality 2.1 22 22
Privacy, data & permissions 5.1 16 20
IAP, subscriptions & paywalls 3.1 15 27
Metadata, screenshots & listing 2.3 14 18
Design, minimum functionality & spam 4.0–4.3 10 10
Login, accounts & reviewer access 4.8 / 5.1.1 8 9
Technical, build & binary 2.5 8 19
Account, agreements & declarations 4 10
Safety & user-generated content 1.x 3 6

A sample of what that means in practice:

  • Paywalls that show "$4.99/mo" for an annual plan without the annual total
  • Free-trial toggle switches (rejected as misleading, and very common)
  • Missing Restore Purchases, Terms of Use, or Privacy Policy links on the paywall
  • Apps with accounts and no in-app account deletion
  • Tracking SDKs that initialise before the ATT prompt
  • Missing PrivacyInfo.xcprivacy or required-reason API declarations
  • Staging URLs, debug menus, and Lorem ipsum in the release build
  • Demo accounts that expired, or 2FA codes only your phone can receive
  • Social login without Sign in with Apple
  • 1024px app icons with an alpha channel
  • Support and privacy policy URLs that 404

Scoring

The score is computed by scripts/score.py, not estimated by the model.

Each check carries points by severity — blocker 5, major 3, minor 1 — and earns a fraction of them by status:

Status Credit
pass 100%
warn 50%
unknown 35%
fail 0%
na excluded

Two decisions worth explaining:

unknown costs points. A check that couldn't be verified scores below a pass, so guessing is never cheaper than asking you. Any check that goes unreported is scored as unknown automatically — silence can't pass as a pass.

Confirmed blockers cap the score. One caps it at 55, two at 45, three or more at 35. Without this, an app with a dead privacy policy URL and everything else immaculate scores in the low 90s — which is exactly backwards, since that one thing gets it rejected.

Categories that don't apply drop out and the remaining weights renormalise, so a free app with no accounts isn't scored against IAP or account-deletion checks.

Score Band
90–100 Bifröst Open — known preventable failure modes cleared
75–89 Watch Set — likely pass, a few soft spots
60–74 Horn Within Reach — coin flip, real fixable risk
40–59 Gates Barred — likely rejection, fix blockers first
0–39 Gjallarhorn — will be rejected as-is

Heimdall predicts. It does not guarantee. App Review is done by people with discretion, and clean apps are still occasionally rejected — often for something subjective about the concept rather than compliance. A high score means the known preventable failure modes are cleared.


It will not submit your app

Heimdall never runs asc review submit, asc publish appstore, or any other command that puts your app in front of Apple. It prepares the submission; you press the button.

Every write to App Store Connect is shown to you and confirmed first, with a dry run where the API supports one. Reads happen freely. Age rating and content-rights answers are legal declarations about your app, so Heimdall writes only what you tell it — it never guesses.


How it's built

SKILL.md                      the workflow Claude follows
references/checks.json        141 checks: IDs, categories, severities, applicability
references/checklist.md       how to verify each check, and what makes it a failure
references/asc-cookbook.md    App Store Connect CLI commands mapped to check IDs
references/codebase-audit.md  grep patterns per stack — native, RN, Expo, Flutter, Capacitor
references/paywall.md         Guideline 3.1 deep dive
references/fixes.md           remediation playbook and the auto-fix boundary
references/report.md          scoring model and report format
scripts/score.py              the scoring engine
assets/findings.template.json every check ID, pre-listed, so nothing gets skipped

checks.json is the machine-readable spine. If you want to add a check, add it there and give it a verification row in checklist.mdscore.py will pick it up and flag it as unreported until the audit covers it.


Caveats

The App Store Review Guidelines change, and anything with a date attached goes stale. Heimdall re-checks the version-dependent items (SDK requirements, external purchase link rules, age rating tiers, screenshot dimensions) against Apple's live documentation during a full audit, and prefers asc screenshots sizes --all over any hardcoded dimension list. If you spot a bundled fact that's out of date, please open an issue.

App Privacy nutrition labels aren't exposed by the App Store Connect API, so those checks are confirmed by asking you — Heimdall lists the data types it found in your code so the confirmation is a real comparison rather than a rubber stamp.


Contributing

Issues and pull requests welcome, particularly:

  • Checks that caught a real rejection Heimdall would have missed
  • Rejection reasons from recent submissions, with the guideline cited
  • Framework coverage — grep patterns that miss on a stack not listed above
  • Guideline changes that make a bundled fact stale

License

MIT — see LICENSE.

Not affiliated with or endorsed by Apple Inc.

About

App Store submission gatekeeper for Claude Code — audits your iOS app against 141 App Store Review Guideline checks, scores your odds of passing review, and fixes what it finds.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages