Symx collects Apple system symbols and uploads them into a GCS-backed symbol store.
In practice, Symx is not a long-running service. Today it consists of:
- scheduled and manually-triggered GitHub Actions workflows,
- a shared Google Cloud Storage bucket that holds metadata, mirrored artifacts, and uploaded symbols,
- Sentry for traces, logs, and metrics,
- local admin clients—a native macOS app plus the existing TUI/CLI—for inspecting failure states and queueing curated reruns.
- Apple artifact and extraction terminology — start here for terms such as DSC, primary, cache family, SystemOS image, and materialization
- Architecture and state model
- Operations, local setup, deployment, and debugging
- Coverage stats page
If you only read one thing after this README, read docs/architecture.md. Keep the domain terminology open when an Apple firmware or extraction term is unfamiliar.
Symx has three processing lanes today:
-
IPSW
- imports metadata from AppleDB,
- mirrors selected IPSW files into GCS,
- extracts symbols from mirrored IPSWs,
- uploads the resulting symbol files.
-
OTA
- fetches OTA metadata via the
ipswCLI, - mirrors OTA zip files into GCS,
- extracts symbols from mirrored OTAs,
- uploads the resulting symbol files.
- fetches OTA metadata via the
-
Simulator runtimes
- inspects the simulator dyld caches present on GitHub macOS runners,
- extracts and uploads symbols from those caches.
A key nuance: IPSW processing state is tracked per source file, while OTA processing state is tracked per artifact. The shared enum lives in symx/model.py, but each pipeline uses only part of it. The detailed state tables and diagrams are in docs/architecture.md.
flowchart TD
AppleDB[AppleDB] --> IPSWMeta[IPSW meta-sync workflow]
AppleOTA[Apple OTA endpoints] --> OTAMirror[OTA mirror workflow]
IPSWMeta --> IPSWMetaJson[(GCS: IPSW meta store)]
OTAMirror --> OTAMetaJson[(GCS: OTA meta store)]
IPSWMetaJson --> IPSWMirror[IPSW mirror workflow]
IPSWMirror --> IPSWMirrorStore[(GCS: IPSW mirror store)]
IPSWMetaJson --> IPSWExtract[IPSW extract workflow]
IPSWMirrorStore --> IPSWExtract
OTAMetaJson --> OTAExtract[OTA extract workflow]
OTAMirror --> OTAMirrorStore[(GCS: OTA mirror store)]
OTAMirrorStore --> OTAExtract
IPSWExtract --> Symbols[(GCS: symbol store)]
OTAExtract --> Symbols
Sim[Simulator extract workflow] --> Symbols
More detail, including the "who processes what when" walkthrough and the state diagrams, lives in docs/architecture.md.
| Workflow | Runner | Purpose |
|---|---|---|
symx-ipsw-meta-sync.yml |
Ubuntu | Refresh ipsw_meta.json from AppleDB |
symx-ipsw-mirror.yml |
Ubuntu | Mirror recent indexed IPSWs into GCS |
symx-ipsw-extract.yml |
macOS | Extract symbols from mirrored IPSWs |
symx-ota-mirror.yml |
Ubuntu | Refresh OTA metadata and mirror indexed OTAs |
symx-ota-extract.yml |
macOS | Extract symbols from mirrored OTAs |
symx-simulator-extract.yml |
GitHub macOS matrix | Upload simulator-cache symbols |
symx-admin-meta-sync.yml |
Ubuntu | Build snapshot inputs for local admin clients |
symx-admin-apply.yml |
Ubuntu | Apply curated admin rerun batches |
symx-coverage-pages.yml |
Ubuntu | Publish the coverage stats page to GitHub Pages |
The workflow files in .github/workflows/ are the authoritative deployment config. GitHub Actions bootstrap dependency pins and bump instructions live in
docs/gha-dependencies.md.
To extract the newest Apple artifacts, keep both macOS and Xcode current. macOS 27 and Xcode 27 are recommended for extracting 27-era artifacts. Requirements depend on the artifact: older artifacts may work with older macOS and Xcode versions. The latest versions are still recommended, because tooling cannot provide a soft fallback path for every OTA and IPSW out there.
Apple artifacts can rely on host features: macOS supplies Apple Archive compression support such as lzraven,
while Xcode supplies dsc_extractor.bundle for splitting dyld caches such as arm64e_x1. Updating ipsw alone
cannot add these capabilities. Make sure the intended full Xcode installation is selected via xcode-select.
Symx logs the actual host and selected Xcode for diagnostics; it does not enforce macOS or Xcode versions. Metadata, mirroring, and CLI/TUI administration can still run on Linux. See tooling requirements by task.
Symx uses uv for its Python application and tools. The native admin app uses SwiftPM directly.
Helpful install/download links:
uvipswlatest release /ipswHomebrew formula (at least version 3.1.721)ghCLI- Google Cloud CLI /
gcloud symsorterlatest GitHub release
uv sync --dev- Admin / workflow inspection only
ghinstalled and authenticated- for the native app: macOS 27 and the Swift toolchain included with Xcode 27 are recommended; see the app README
- GCS-backed runs (
ipsw meta-sync,ipsw mirror,ipsw extract,ota mirror,ota extract,sim extract)gcloudcredentials available via ADC /GOOGLE_APPLICATION_CREDENTIALS- a storage URI such as
gs://my-bucketorgs://my-project@my-bucket
- OTA metadata/mirroring and extraction commands
ipsw3.1.721 or newer installed and onPATH
- Extraction commands
- executable
./symsorterin the repo root - macOS and a selected Xcode installation suitable for the artifact; see Extraction environment
- executable
Inspect workflow health with the GitHub CLI:
gh workflow list
gh run list --workflow "Extract OTA symbols" --status failure --limit 20
gh run view <run-id> --logOpen the native macOS admin app:
cd apps/SymxAdmin
swift runThe existing TUI remains available as a fallback:
uv run symx adminSync the admin cache without starting either client:
uv run symx admin syncGenerate the coverage HTML page from the active admin snapshot:
uv run symx stats coverage-html --output /tmp/symx-coverage.htmlReproduce extraction from a local file:
uv run symx ipsw extract-file /path/to/file.ipsw -p iOS -o /tmp/symx-ipsw
uv run symx ota extract-file /path/to/file.zip -p ios -V 18.2 -b 22C152 -o /tmp/symx-otaRun a GCS-backed command against a bucket you control:
uv run symx ipsw meta-sync -s gs://my-project@my-bucket
uv run symx ipsw mirror -s gs://my-project@my-bucket -t 60
uv run symx ota mirror -s gs://my-project@my-bucketCaution
The GCS-backed commands mutate the configured storage directly. Use a non-production bucket unless you intentionally want to operate on production data.
The shortest useful operator loop is usually:
- inspect failing or slow runs in GitHub Actions,
- look at the corresponding Sentry transaction,
- inspect a local admin snapshot in the native app or TUI (either client can sync it),
- when needed, download the failing artifact from the TUI and reproduce with
extract-filelocally.
Useful entry points:
- GitHub Actions inspection: docs/operations.md#github-actions
- Admin clients and local SQLite snapshots: docs/operations.md#admin-tui-and-local-snapshots
- Sentry tags, transactions, and metrics: docs/operations.md#sentry
- Failure-state diagrams: docs/architecture.md#artifact-state-model
- GitHub Actions dependency pins and bumping: docs/gha-dependencies.md
A few things are important to know up front:
- GCS is the shared source of truth for the current workflow state.
- GitHub Actions is the scheduler/executor, not just CI.
- IPSW sync is conservative: new artifacts are inserted, but significant changes to already-known IPSW artifacts are only logged today, not automatically merged.
- OTA sync is more aggressive: OTA metadata is merged into the stored set while preserving local processing progress.
- The shared processing-state enum is reused across IPSW and OTA, but some states are domain-specific and
ignoredis manual-only. - The current admin surface is intentionally narrow: it syncs snapshots, inspects failures, downloads artifacts, and supports curated rerun batches. It is not a general-purpose state editor.
| Directory | Description |
|---|---|
symx/ipsw/ |
IPSW metadata import, mirroring, extraction, storage backends |
symx/ota/ |
OTA metadata retrieval, mirroring, extraction, storage backends |
symx/sim/ |
simulator-runtime extraction |
symx/admin/ |
local admin cache, SQLite snapshot builder, TUI, download helpers |
apps/SymxAdmin/ |
native macOS admin app over the shared local snapshot |
symx/stats/ |
snapshot-based reporting and HTML generation |
.github/workflows/ |
production scheduling and deployment wiring |
tests/ |
unit tests |
Use uv for all Python commands. Use the declared SwiftPM toolchain for the native admin app.
Before considering a change "done", run the full check suite:
uv run ruff check --fix
uv run ruff format
uv run ty check
uv run pytestThe native admin package has an additional local check:
cd apps/SymxAdmin
swift format lint --strict --recursive --parallel Sources Tests Package.swift
swift test