Skip to main content
skill CX Codex

asc-ad-hoc-distribution — Claude Code skill: setup and usage

Builds and publishes private iOS ad hoc installs to S3-compatible storage for registered test devices without TestFlight. Works with .xcarchive packages and standalone IPAs.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add rorkai/app-store-connect-cli-skills --skill asc-ad-hoc-distribution -a claude-code
Open on GitHub

What asc-ad-hoc-distribution does

The skill coordinates private iOS releases using the asc distribute CLI. For a full run starting from an .xcarchive, it runs through plan, apply, resume, and verify. The planning phase is read-only and outputs an exact execution blueprint. Nothing gets written remotely until you explicitly approve the 64-character plan hash.

Keep in mind that v1 plans fail if the archive contains Watch apps, App Clips, or app extensions. It requires a single main app target. You also need an existing S3-compatible bucket, an App Store Connect account, and a local PKCS#12 identity. The tool generates install links, but it will not create buckets or push apps onto phones.

What it helps with

  • generate private iOS install links from an .xcarchive
  • register missing test devices in App Store Connect
  • reconcile ad hoc provisioning profiles
  • upload signed IPA artifacts to S3-compatible storage

Example prompts for the agent

  • Create a distribution plan for .asc/artifacts/App.xcarchive using .asc/distribution/config.json
  • Apply the authorized ad hoc distribution plan using the hash from plan.json
  • Inspect the progress of the current run with asc distribute status

How to install asc-ad-hoc-distribution

1Skills CLI (Vercel)

npx skills add rorkai/app-store-connect-cli-skills --skill asc-ad-hoc-distribution -a claude-code

2Manually: put the files in place

~/.claude/skills/asc-ad-hoc-distribution/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/asc-ad-hoc-distribution/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about asc-ad-hoc-distribution

How to install asc-ad-hoc-distribution in Claude Code?

Run npx skills add rorkai/app-store-connect-cli-skills --skill asc-ad-hoc-distribution -a claude-code in your terminal.

What does asc-ad-hoc-distribution do?

It packages and publishes ad hoc iOS builds to private S3-compatible storage, allowing registered devices to install apps outside TestFlight.

What are the limitations of the v1 plan in asc-ad-hoc-distribution?

The initial plan version only supports an archive with a single main app target. Watch apps, extensions, and App Clips are not supported and will mark the plan as not ready.

Source text

SKILL.md · MIT
---
name: asc-ad-hoc-distribution
description: Prepare, publish, resume, and verify private iOS release-testing installs with asc distribute. Use when distributing an IPA to registered devices outside TestFlight, reconciling ad hoc profiles, publishing through caller-owned S3-compatible storage, or diagnosing a resumable private distribution run.
---

# ASC ad hoc distribution

Use the experimental `asc distribute` workflow to turn an existing iOS archive
into a private, verified install link for registered devices. Use TestFlight or
the App Store release skills instead when the build should go through Apple-hosted
distribution.

Confirm the installed contract before acting:

```bash
asc distribute --help
asc distribute plan --help
asc distribute apply --help
asc distribute resume --help
asc distribute status --help
asc distribute verify --help
```

## Choose the workflow

- Use `plan` -> `apply` -> `resume`/`status` -> `verify` for an end-to-end,
  hash-authorized run starting from an `.xcarchive`.
- Use `inspect` -> `prepare` -> `publish` only when the caller already owns the
  ad hoc IPA and wants to operate the lower-level boundaries separately.

## Guardrails

- Treat the distribution spec, devices file, PKCS#12 identity, password file,
  run state, and exact install-link artifact as private. Keep them out of Git and
  require owner-only permissions.
- Never put S3 credentials or presigned URLs in the distribution spec, command
  output, logs, issues, or chat. Use `ASC_S3_ACCESS_KEY_ID`,
  `ASC_S3_SECRET_ACCESS_KEY`, and optional `ASC_S3_SESSION_TOKEN`, or the
  standard AWS SDK credential chain.
- `plan` is read-only and may exit successfully with `ready: false`. Inspect the
  typed blockers and effects before continuing.
- `apply` can register missing devices, create safe App IDs and successor ad hoc
  profiles, write local artifacts, and publish immutable objects. Run it only
  after the user authorizes the exact plan hash and effect inventory.
- The orchestrated workflow supports private access to an existing
  S3-compatible bucket. It does not create buckets, change policies, delete old
  builds, install the app, or launch it.
- Input drift, an immutable-object conflict, expired signing material, or an
  expired private link requires a new plan. Do not force the old run forward.

## Preconditions

- An existing iOS `.xcarchive` with one main app target. Embedded apps,
  extensions, Watch apps, and App Clips make the v1 plan not ready.
- A local iOS distribution PKCS#12 identity and optional protected password file.
- A protected strict-v1 devices file. For example:

```json
{"schemaVersion":1,"devices":[{"name":"Test iPhone","udid":"DEVICE_UDID","platform":"IOS"}]}
```

- App Store Connect authentication with access to devices, Bundle IDs,
  certificates, and profiles.
- An existing S3-compatible bucket and valid credentials.

## 1. Create the private distribution spec

Relative paths resolve from the spec directory. The spec does not interpolate
environment variables or accept credentials. A representative private config is:

```json
{
  "schemaVersion": 1,
  "devicesFile": "devices.json",
  "signing": {
    "identity": {
      "format": "pkcs12",
      "path": "../signing/distribution.p12",
      "passwordFile": "../secrets/distribution-p12-password"
    },
    "minimumValidityDays": 7,
    "maxMutations": 32
  },
  "publication": {
    "endpoint": "https://objects.example.com",
    "downloadEndpoint": "https://downloads.example.com",
    "region": "auto",
    "bucket": "ios-builds",
    "prefix": "team/app",
    "addressingStyle": "path",
    "urlTtl": "24h",
    "downloadGrace": "1h",
    "verifyTimeout": "30s"
  },
  "metadata": {
    "title": "App",
    "channel": "pull-request-42",
    "sourceRevision": "abc123",
    "sourceUrl": "https://example.com/team/app/commit/abc123"
  }
}
```

`passwordFile`, `certificateSha256`, `downloadEndpoint`, and every metadata field
are optional. An omitted password file means the PKCS#12 must use an empty
password. Protect the config and secret inputs before planning:

```bash
chmod 600 ".asc/distribution/config.json" ".asc/distribution/devices.json"
chmod 600 ".asc/signing/distribution.p12" ".asc/secrets/distribution-p12-password"
```

## 2. Plan without mutation

```bash
asc distribute plan \
  --archive-path ".asc/artifacts/App.xcarchive" \
  --config ".asc/distribution/config.json" \
  --plan ".asc/distribution/plan.json" \
  --state-dir ".asc/distribution/runs" \
  --output json
```

Inspect `ready`, `planHash`, signing validity, destination, and the complete
ordered `effects` inventory. Resolve blockers and create a new plan when
`ready` is false. Do not infer readiness from exit code alone.

## 3. Apply the exact authorized plan

After approval of the exact effects, pass the full 64-character hash:

```bash
PLAN_HASH="$(jq -er '.planHash' ".asc/distribution/plan.json")"
asc distribute apply \
  --plan ".asc/distribution/plan.json" \
  --confirm "$PLAN_HASH" \
  --output json
```

Missing, malformed, or unequal confirmation is rejected before side effects.
Success means publication and live fetch verification completed; it does not
mean a device installed or launched the app.

## 4. Inspect, resume, and verify

Use the returned `runId`:

```bash
asc distribute status --run "RUN_ID" --state-dir ".asc/distribution/runs" --output json
asc distribute resume --run "RUN_ID" --state-dir ".asc/distribution/runs" --output json
asc distribute verify --run "RUN_ID" --state-dir ".asc/distribution/runs" --timeout 30s --output json
```

`status` is local-only and succeeds for `running`, `recoverable`, and `blocked`
runs; branch on typed fields rather than prose. `resume` revalidates durable
evidence before retrying and never blindly repeats a remote write. `verify` is
read-only but performs live fetches. Add `--device "DEVICE_SELECTOR"` only when
the user asks to observe the matching installed bundle, version, and build on a
connected device; this observation does not prove IPA byte identity.

The exact private install URL is a bearer credential stored only in the
owner-private link artifact reported by the completed run. Share it only with
the intended tester through an approved private channel.

## Lower-level IPA workflow

Use this lane when signing and export are already complete. Pass the exact
`bundleDir` returned by `prepare` to `publish`:

```bash
asc distribute inspect --ipa ".asc/artifacts/App.ipa" --output json
asc distribute prepare --ipa ".asc/artifacts/App.ipa" --channel "pull-request-42" --output json
asc distribute publish \
  --bundle-dir ".asc/distribution/com.example.app/1.2-42-IPA_SHA_PREFIX" \
  --endpoint "https://objects.example.com" \
  --region "auto" \
  --bucket "ios-builds" \
  --prefix "team/app" \
  --receipt ".asc/publishes/app-1.2-42.json" \
  --link-path ".asc/publishes/app-1.2-42-link.json" \
  --output json
```

`inspect` omits raw device UDIDs unless `--include-devices` is explicitly
needed. `prepare` never overwrites a bundle and reuses only an exact equivalent.
Private `publish` is the default and writes exact presigned links only to the
mode-0600 link artifact. Public publication is a separate explicit lane using
`--access public --public-base-url`; it assumes anonymous reads are already
configured and never changes storage policy.

© rorkai · MIT · rorkai/app-store-connect-cli-skills

Similar skills

Everything for Mobile →

From the same set24

asc-crash-triage Triages TestFlight crashes, beta feedback, and build performance metrics using the asc CLI to produce actionable iOS reports. CX Codex +1 6,400installs asc-aso-audit Runs an offline ASO audit on local App Store metadata in ./metadata, flagging wasted keyword space, bad separators, and missing fields. CX Codex +1 6,200installs asc-revenuecat-catalog-sync Reconciles App Store Connect subscriptions and in-app purchases with RevenueCat catalog resources. Use it before release or when the two catalogs have drifted apart. CX Codex +1 6,100installs asc-wall-submit Files or updates your app's Wall of Apps entry in the App-Store-Connect-CLI repo: a dry run first, then a confirmed submit with a PR plan. CX Codex +1 5,800installs asc-whats-new-writer Turn commits, bullet points, or a plain description into localized App Store release notes. Useful when preparing update copy across the locales already in your metadata. CX Codex +1 5,700installs asc-screenshot-resize This skill prepares screenshots for App Store Connect by finding current size rules, resizing files, and checking them before upload. CX Codex +1 5,100installs asc-apple-ads A skill that teaches your agent to run Apple Ads through the asc CLI: campaigns, targeting, reports and recommendations. Useful once App Store ads are live. CX Codex +1 3,000installs asc-analytics-reports This skill pulls every segment of an App Store Connect analytics report through the asc CLI and checks each file against its size and MD5 before analysis. CX Codex +1 863installs

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor