# App Store Connect Onboarding (setup Step 3b)

Loaded on demand by `/multi-agent:setup` Step 3b (iOS only, optional). The SKILL.md carries the step intro; this file is the full flow.

Runs inside Step 3 alongside the other missing credentials, not as a late add-on:
a user who already has an App Store Connect credential in their keychain gets it
mapped by Step 1 discovery like any other token, and only the genuinely missing
pieces reach this flow.

Three of the four entries do not go through the normal Token Save Flow, because
what they hold is not a pasteable secret:

| Entry | Holds | Flow |
|---|---|---|
| `appstore_connect_key_id` | an identifier | plain value, not a secret; still mapped so it is read through the mapping layer |
| `appstore_connect_issuer_id` | an identifier | same |
| `appstore_connect_apple_id` | an email address | same |
| `appstore_connect_password_item` | a keychain ITEM NAME | the password lives in Apple's own keychain item, referenced as `-p @keychain:<item>` and never read by the pipeline |

All four entries are **iOS-only and optional**: skip them all and the pipeline
still works, it just reports Gate 2 of `/multi-agent:store-ready` as `SKIPPED`,
never as a pass.

The tiers mirror the Figma 3-tier shape: Tier 1 = API key (`appstore_connect_key_id`
+ `appstore_connect_issuer_id`), Tier 2 = Apple ID + app-specific password
(`appstore_connect_apple_id` + `appstore_connect_password_item`), Tier 3 = nothing
configured.

Ask which tier to configure (picker): **API key** / **Apple ID + app-specific
password** / **Skip**. Lead with the second when the user says they cannot create
an API key: creating one needs an Admin or App Manager role in App Store Connect,
while an app-specific password is generated by the account holder at
`appleid.apple.com` with no team permission at all.

**API key.** The private key is a FILE and is never copied into the credential
store. It must sit in a directory `altool` already searches:

```bash
ls ~/.appstoreconnect/private_keys/AuthKey_*.p8 2>/dev/null \
  || echo "MISSING: put AuthKey_<keyId>.p8 in ~/.appstoreconnect/private_keys/"
```

**Apple ID + app-specific password.** Use Apple's own keychain helper. The secret
never enters chat and never becomes a shell argument, per the Token Save Flow rule:

```bash
# the user exports AC_PASSWORD_ONCE in their own shell, for this one command
xcrun altool --store-password-in-keychain-item "<item-name>" \
  -u "<apple-id>" -p @env:AC_PASSWORD_ONCE
```

Then map only `<item-name>` as `appstore_connect_password_item`.

**Multi-provider accounts.** A corporate Apple ID often belongs to several
providers, and `altool` fails opaquely without one. Resolve it once with
`ios_testflight_validate({list_providers: true, <credentials just configured>})`
and store the answer under
`prefs.projects[<key>].appStoreConnect.providerPublicId`  -  per-project, since a
user can ship for more than one team.

**Verify + expiry.** Re-run the `list_providers` probe and report the resolved
tier. A credential that resolves but is rejected (401/403) follows the
Expired-token decision in `refs/keychain.md` Rule 1  -  Regenerate / Use a
different token / Skip and continue  -  never a silent drop.

