agentleFS
alexey1312alexey1312/iPhone-Duo-Agent-Skill/skills/iphone-duo-adaptivity-audit/SKILL.md

iphone-duo-adaptivity-audit

Skill6 starsChanged 37 days agoMITView on GitHub

Find and fix legacy screen, orientation, idiom and lifecycle code that breaks on iPhone Duo's inner display and in other iOS 27 resizable environments (iPhone Mirroring, iPhone apps on iPad, Split View). Use when a developer asks about UIScreen.main or mainScreen, screen bounds or scale, interfaceOrientation or UIDevice orientation checks, userInterfaceIdiom layout forks, keyWindow or connectedScenes.first, migrating from app lifecycle to UIScene lifecycle (required with the latest SDK), UIRequiresFullScreen, a missing launch screen (ITMS-90870), portrait-only apps, or hard-coded Face ID strings and symbols (iPhone Duo has Touch ID; branch on LAContext.biometryType). Covers SwiftUI and UIKit, ships a read-only scanner, and delegates bulk UIKit rewrites to Xcode's own modernization skill when available. Not for app features that merely touch UIScreen or orientation, such as screen brightness, deliberately locking a game to one orientation, or camera and sensor setup.

1 other project uses a version of this, 1 of them edited.

Adopted by

Most recently taken up by

  • Other versions1 project uses a version of this.

    Word for word · 0

    None found.

    Wrote their own version · 0

    None found.

    How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.

  • In this repository5 other files it gives its agents.

The file

We split this skill into the rules it gives an agent

10 rules. About 0 are common, 2 are distinctive, and 8 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 8

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    UIScene lifecycle is required: when building with the latest SDKs.

    line 53
  2. Very specific:

    Remove the key only after the layouts adapt: removal makes the scene resize continuously at once.

    line 58
  3. Very specific:

    Add UIRequiresFullScreenIgnoredStartingWithVersion only after that too: a value of 27 or earlier also makes the scene resize continuously …

    line 60
  4. Very specific:

    Ask first whether a .pad gate means "iPad" or "a big screen".

    line 95
  5. Very specific:

    Check the hardware too: iPhone Duo supports Apple Pencil (USB-C) without hover (references/device-geometry.md), so a hover preview stays …

    line 98
  6. Very specific:

    If it yields uikit-app-modernization (Xcode 27.0) or App Resizability (27.1), use it for bulk UIKit rewrites: it applies …

    line 109
  7. Very specific:

    Typecheck what you touched: Run the project's build, or at least xcrun --sdk iphonesimulator swiftc -typecheck on the edited files at the …

    line 146
  8. Distinctive:

    Orientation replacement is not always width > height: When left versus right matters (cutouts, camera side), ask before replacing.

    line 157
  9. Very specific:

    Leave UIRequiresFullScreen alone in games that need discrete resizing.

    line 170
  10. Very specific:

    Never add UIRequiresFullScreenIgnoredStartingWithVersion as a first step.

    line 172

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

iPhone Duo adaptivity audit

The foundation for everything else: an app that decides layout from the screen, the orientation or the idiom is wrong on iPhone Duo before any foldable-specific work begins.

Facts this skill relies on

  • The outer display behaves like other iPhones; the inner display is regular width × regular height. (Tech Talk 111461, 2:46)
  • The inner display does not honor supported interface orientations; in iOS 27 supported orientations are a preference ignored in resizable environments, and iPhone Mirroring always reports portrait. (111461 2:46; WWDC26 278 6:50)
  • Referencing the main screen is ambiguous on a two-display device and deprecated (the iOS 27 SDK header marks mainScreen deprecated). (111461 3:57; 278 2:51) Concretely: the iPhone Duo simulator's own profile names the outer display as main-screen-*, so an app that asks for the main screen gets the smaller of the two whichever display it is actually on. (references/device-geometry.md, measured)
  • The user interface idiom is not meaningful for layout: an iPhone app stays in the phone idiom while fully resizable. (111461 1:33; 278 6:17) iPhone Duo has no idiom of its own and no API that identifies it (Forums 847775, 847644). An iPhone-only app cannot opt out of resizing on iPad or in iPhone Mirroring either (Forums 847872; 278 1:32).
  • A fold is a size-class and trait change, not a scene event. Opening, closing and folding keep the process and the scene; text input, scroll position and playback survive (Forums 848042, 847644). Do not save a fold state on the way to the background or restore one on the way back: reserved regions and hinge data are current when the scene returns (Forums 848035). windowScene(_:didUpdateEffectiveGeometry:) is guaranteed when the scene moves to the other display (Forums 848021), but layout-time adaptation is the better route, and folding alone does not call it (Booted, scripts/probes/forum_probe.swift in the repository).
  • The SDK alone picks the compatibility tier. No Info.plist key brings back the boxed presentation once the app links the iOS 27 SDK (Forums 847856; references/api-availability.md › What each linked SDK gets).
  • UIScene lifecycle is required when building with the latest SDKs; without it the app no longer launches. (278 2:10)
  • UIRequiresFullScreen no longer opts an app out of resizing from iOS 27: it gives discrete resizing, and iPhone Duo still resizes the app when it opens or closes and scales it on the inner display, including in Split View — meant for games. Remove the key only after the layouts adapt: removal makes the scene resize continuously at once. Add UIRequiresFullScreenIgnoredStartingWithVersion only after that too: a value of 27 or earlier also makes the scene resize continuously on iOS 27. (278 5:46; 111461 4:37; TN3192)
  • App Store Connect requires a launch screen. An upload built with the iOS 27 SDK needs UILaunchScreen, UILaunchScreens, UILaunchStoryboardName or UILaunchStoryboards in the Info.plist, or App Store Connect rejects it with ITMS-90870. An empty UILaunchScreen dictionary or INFOPLIST_KEY_UILaunchScreen_Generation = YES is enough. (TN3208; TN3192)
  • iPhone Duo has Touch ID in the side button and no Face ID (Apple tech specs; references/device-geometry.md). Adaptive apps make no assumptions about device capabilities (111461 2:34): copy, symbols and onboarding that name Face ID are wrong on it.

Workflow

  1. Scan (read-only):
    python3 scripts/duo_scan.py <root> --format markdown
    python3 scripts/duo_scan.py <root> --format json   # for exact IDs
    Rules owned here: DUO001 main screen, DUO002 screen bounds, DUO003 idiom, DUO004 orientation, DUO005 app lifecycle, DUO009 global window state, DUO012 scene delegate without manifest, DUO013 Face ID copy, DUO020 UIRequiresFullScreen, DUO022 no launch screen. Member chains split across lines (connectedScenes … .first) are joined before matching; other multi-line expressions, macros and generated code are not seen, so follow up with targeted searches when the inventory suggests more.
  2. Classify each match by reading the code:
    • Layout decision (sizes, columns, which view to show) → replace.
    • Rendering scale (scale, pixel alignment, image sizes) → replace with trait.
    • Physical question no geometry answers (which end holds a cutout, sensor frame alignment before body protocols) → kept if documented; otherwise ask.
    • Non-layout behavior keyed off idiom (feature availability, analytics) → kept, with a comment naming why. Ask first whether a .pad gate means "iPad" or "a big screen". A feature hidden on iPhone for lack of room stays hidden on the inner display, because iPhone Duo is .phone there too: that gate is a layout decision. Check the hardware too: iPhone Duo supports Apple Pencil (USB-C) without hover (references/device-geometry.md), so a hover preview stays off.
    • Capability assumption (Face ID in strings, faceid symbols, onboarding) → derive from LAContext.biometryType. DUO013 reports medium where nothing in the file ever asked, and low next to an existing biometryType read — confirm those strings sit in the .faceID branch and mark them kept.
  3. Check Xcode's skill. Export into a temporary directory — without --output-dir the command writes into the current directory:
    out="$(mktemp -d)" && xcrun agent skills export --output-dir "$out" >/dev/null 2>&1; ls "$out"
    If it yields uikit-app-modernization (Xcode 27.0) or App Resizability (27.1), use it for bulk UIKit rewrites: it applies deprecate-and-forward patterns, preserves guards and control flow, and tracks file coverage. Review its diff against the approved items. SwiftUI code and anything it leaves as a TODO come back here. Installed as an agent skill, it also triggers on "get my app ready for iPhone Duo" and applies every task it has; scope it to the approved items first.
  4. Recommend in the format of references/recommendation-format.md; wait for approval; apply; build; re-scan.

Replacements

Full before/after code for SwiftUI and UIKit: references/legacy-api-remediation.md.

LegacyUIKit replacementSwiftUI replacement
UIScreen.main.scaletraitCollection.displayScale (auto-tracked in layoutSubviews, draw(_:), updateProperties; else registerForTraitChanges)@Environment(\.displayScale)
UIScreen.main (the screen)view.window?.windowScene?.screen; pass a UIScreen parameter where no view is at handRarely needed — ask what the screen is for
UIScreen.main.bounds for available spaceview.bounds in viewDidLayoutSubviews; scene level: windowScene.effectiveGeometry + windowScene(_:didUpdateEffectiveGeometry:)GeometryReader, onGeometryChange(for:of:action:), containerRelativeFrame
userInterfaceIdiom == .pad for layouttraitCollection.horizontalSizeClass / container size@Environment(\.horizontalSizeClass)
interfaceOrientation, UIDevice.current.orientation for layoutSize classes or bounds.width > bounds.heightSize classes or geometry aspect
Scene interfaceOrientation (deprecated in 27 SDK) where orientation is truly neededwindowScene.effectiveGeometry.interfaceOrientationsame, from the view's window scene
Orientation to align sensor datamotionManager.deviceMotionBody = view, locationManager.headingBody = viewsame, on a hosting view
UIApplication.shared.keyWindow / windows / connectedScenes.firstview.window, view.window?.windowScenethe view's own context; openWindow/dismissWindow environment actions
App lifecycle onlyUIApplicationSceneManifest + UIWindowSceneDelegate; move window setup to scene(_:willConnectTo:options:)@main struct …: App is already scene-based
"Face ID" in copy, faceid symbolsA switch context.biometryType (.faceID, .touchID, default) after canEvaluatePolicy, feeding titles and UIImage(systemName:)The same switch in a small model feeding Label / Button(_:systemImage:)

Applying changes

  • Preserve today's behavior on today's devices. A replacement that is correct on iPhone Duo but turns a two-column portrait / four-column landscape grid into three columns on a small iPhone is a regression. State the before/after on at least one existing device.
  • Kept means kept. For a documented exception, change only the deprecated call it uses (for example scene.interfaceOrientation → effectiveGeometry.interfaceOrientation). Restructuring it — new representables, observers, different data flow — is a separate proposal for the developer to approve, because the documentation exists precisely so that nobody "improves" it unasked.
  • Typecheck what you touched. Run the project's build, or at least xcrun --sdk iphonesimulator swiftc -typecheck on the edited files at the deployment target, and re-run duo_scan.py. Report what was and was not verified.

Pitfalls

  • A size class is not a device. Regular × regular now includes an iPhone. Code that reads "regular means iPad" must become "regular means room for more columns".
  • Don't cache screen-derived values in init or static storage; closing or opening iPhone Duo moves the scene to another display. Recompute on trait or geometry change.
  • Orientation replacement is not always width > height. When left versus right matters (cutouts, camera side), ask before replacing.
  • Scene lifecycle migration touches app state restoration, URL handling, push notification routing and background tasks. Plan it as its own item and read Xcode's scene-lifecycle-task.md reference when available, or Apple's Transitioning to the UIKit scene-based life cycle (Forums 848011).
  • Fold handling in a scene delegate is a finding, not a migration step. State restoration (stateRestorationActivity(for:)) is for a real scene disconnection, not for a fold (Forums 847644).
  • traitCollectionDidChange(_:) is deprecated since iOS 17. It still behaves the same on iPhone Duo (Forums 848021), so move off it as code is touched rather than as a blocker: registerForTraitChanges(_:handler:) or automatic trait tracking (278 2:51). The scan inventory counts it.
  • Leave UIRequiresFullScreen alone in games that need discrete resizing. For other apps, recommend adapting first and removing the key after that. Never add UIRequiresFullScreenIgnoredStartingWithVersion as a first step.
  • Localization catalogs hide biometric copy. The scanner reads Swift and Objective-C only; grep .strings and .xcstrings for "Face ID" and build those sentences from the biometry name instead. Keep NSFaceIDUsageDescription: Face ID devices still need it.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.