Files
FTStore/manager/AGENTS.md
T
Felitendo 17e5452769 feat: merge ftstore-manager into the monorepo
the manager lands in manager/, next to ios/ and web/. it is a fork of
this repo's own app, not of feather, so scripts/apply-rebrand.sh
excludes it the same way it excludes web/ — the generic feather-to-
ftstore rule would rewrite its app.ftstore.manager identity and mangle
the lineage notes in its docs.

zsign and idevicekitten were vendored copies in the old repo. they are
registered as submodules here instead, pinned to the same commits ios/
uses and verified byte-identical to what was vendored. that keeps 71 MB
of duplicated source out of the tree and leaves the xcode project's
relative paths intact, so project.pbxproj needed no edits.

the server moves to ftstore.app in both apps: managerrepoclient, the
seeded default source and managerconfig's fallback. downloadmanager
keeps the old admin host in its user-agent allowlist — that check is permissive,
not identifying, and dropping it would stop sending the header to
installs whose stored override still names the old host.

the rest of the admin rename lands too: the client id, the base-url
environment variable, the info.plist key, and user-facing errors. the
userdefaults override key is renamed with a
one-time migration read, so an existing install keeps the address its
owner configured instead of falling back to the default.

tags gain a third namespace: manager-v* for releases, manager-dev for
the rolling prerelease. both repos published to a tag called `dev`
before; sharing it here would make each build overwrite the other's
release assets.
2026-08-03 13:21:48 +02:00

3.6 KiB

FTStore Manager — project guide for AI agents

FTStore Manager is a stripped-down fork of FTStore (itself a fork of Feather, GPL-3.0). Its only job: install and update FTStore from a private FTStore Admin, after the user imports a signing certificate.

Monorepo. This used to be the separate FTStuff/FTStore-Manager repo; it now lives in manager/ inside FTStuff/FTStore, alongside ios/ (the app it installs) and web/ (the FTStore Admin server it talks to). Read the root AGENTS.md first — it owns the tag namespaces (manager-v*, manager-dev) and the rule that scripts/apply-rebrand.sh must never touch this directory. Zsign and IDeviceKitten are submodules here, not vendored copies; clone with --recurse-submodules.

Brand / identity

  • App name FTStore Manager · bundle id app.ftstore.manager (must differ from app.ftstore so installing FTStore is never a self-install → OTA works without pairing).
  • Internal Xcode target/scheme/product name is still FTStore (only the display name and bundle id changed), so make and the project file work unchanged.

How it works (the important part)

  • The GitHub PAT is never in the app. Downloads go through the FTStore Admin proxy (FTStore Admin repo: src/app/api/ftstore-app/manifest + /download), which holds the token server-side. The app only knows the FTStore Admin base URL.
  • Channels: stable = newest non-dev release with an FTStore*.ipa asset (version = tag); dev = the dev-tagged release, tracked by the asset's updatedAt (the version string is constant). Compare logic lives in FTStore/Manager/FTStoreUpdateManager.swift.
  • Install: OTA only (itms-services via Vapor ServerInstaller). The device-pairing method was removed. InstallPreviewView already uses OTA for a non-self-install.

Where things live

  • New Manager code: FTStore/Manager/* + FTStore/FTStoreManagerApp.swift (the @main).
  • Reused engine (unchanged): Backend/Storage, Backend/Server, Backend/Observable (DownloadManager, AppInstallManager, OptionsManager, UpdateManager [inert]), Utilities/Handlers (sign/archive/cert/zsign/tweak), Utilities/{FR,CertificateReader,MachO,ARDecompression}, Extensions, and the certificate/install/signing-setup views under Views/.
  • Config: FTStore.xcconfig (FEATHER_PRODUCT_BUNDLE_IDENTIFIER, FTSTORE_ADMIN_BASE_URL) → injected into Info.plist (FTStoreAdminBaseURL). Never commit a real PAT.

Integration seams (when changing the engine)

  • AppInstallManager.install(InstallRequest) is the Manager's entry into the existing download → cert-gate → sign → install pipeline (reuses the private _startStoreDownload).
  • FTStoreUpdateManager reads installed state from Storage.newestSignedApp(identifier: "app.ftstore").

Dependencies

Vendored (no submodules): Zsign, NimbleKit, AltSourceKit, IDeviceKitten. Remote SPM: Vapor, Zip, SWCompression, Nuke, LicensePlist. AltSourceKit/IDeviceKitten/ LicensePlist stay linked because the engine still references a few helpers from them; they can be pruned in Xcode if desired.

Build / validate

  • macOS + Xcode only. make → packages/FTStore-Manager.ipa, or the Manager Release GitHub Action.
  • Static checks (CI/Linux ok): plistlib/json parse, and grep the repo + built binary for ghp_ / any token — there must be none (the proxy design guarantees it).

GPL-3.0

Keep LICENSE and Feather/FTStore attribution intact; keep source public.