Regenerate iOS Debug Bridge

Regenerates the iOS debug bridge from the latest upstream gstack templates. Updates Swift files and @Observable accessors after a gstack upgrade.

Sby Skills Guide Bot
DevelopmentIntermediate
108/29/2026
Claude Code
#ios#debug-bridge#gstack#code-generation#swift

Recommended for


name: ios-sync preamble-tier: 2 version: 1.0.0 description: | Regenerate the iOS debug bridge against the latest upstream gstack templates. Updates StateServer.swift, DebugOverlay.swift, Package.swift, and the typed @Observable state accessors. Use after you upgrade gstack or add new ViewModels/properties that need accessor coverage. Use when asked to "resync the iOS debug bridge", "regenerate iOS accessors", or "update the gstack iOS instrumentation". (gstack) voice-triggers:

  • "resync the iOS debug bridge"
  • "regenerate iOS accessors"
  • "update the gstack iOS instrumentation" allowed-tools:
  • Bash
  • Read
  • Write
  • Edit
  • Glob
  • Grep
  • AskUserQuestion triggers:
  • resync the ios debug bridge
  • regenerate ios accessors
  • update the gstack ios instrumentation

{{PREAMBLE}}

Resync the iOS debug bridge

After /ios-qa is installed in an app, the user may:

  1. Add new @Observable classes or properties that need accessor coverage.
  2. Upgrade gstack to a newer version with hardening fixes.
  3. Move the // @Snapshotable generator marker comment to a different field.

This skill regenerates the relevant artifacts in place.

Templates live in upstream gstack. The installed gstack-ios-qa-regen launcher resolves its own gstack root and copies only the supported bridge files from ios-qa/templates/. The fork's HTTP-fetch and wildcard-copy patterns are gone.

Phase 1: Detect installed version

  1. Read <app>/DebugBridgeGenerated/.gstack-version (written by /ios-qa during install). If missing, treat the install as "unknown old version".
  2. Read upstream version from $GSTACK_ROOT/VERSION.
  3. If versions match AND no new @Observable classes were added, exit early with "already up to date".

Phase 2: Regenerate codegen output

Run the deterministic regenerator once. --app-source is the directory the accessor scanner should inspect; --bridge-dir is the local Swift package that the app links in Debug builds:

~/.claude/skills/gstack/bin/gstack-ios-qa-regen \
  --app-source "$APP_SOURCE_DIR" \
  --bridge-dir "$APP_SOURCE_DIR/DebugBridge"

The command removes only the known obsolete generated files from the former flat DebugBridgeGenerated/ layout before emitting the current accessor. Generation accepts file-scope observable classes and JSON-native scalar, array, String-keyed dictionary, and Optional field types. It rejects custom types, implicitly unwrapped Optionals, nested observable classes, and duplicate snapshot keys before writing a completion marker.

The composite-hash cache key handles whether anything actually needs regenerating; if Swift version, generator git rev, lockfile, source content, and platform triple all match the cache, this is a ~50ms no-op.

Phase 3: Review the generated diff

  1. Review changes under <app>/DebugBridge/ and <app>/DebugBridgeGenerated/StateAccessor.swift.
  2. Confirm the command did not modify the app's handwritten Swift files.
  3. Keep app-specific wiring in the app target; canonical bridge package files are regenerated from upstream and should not be hand-edited.

Phase 4: Verify

  1. swift build succeeds against the app's package.
  2. xcodebuild -scheme <SchemeName> succeeds.
  3. Re-launch the app on the device; daemon connects + rotates token.
  4. GET /state/snapshot returns the new accessor schema hash.

Failure modes

| Symptom | Action | |---|---| | Swift compile fails after regen | Revert via git restore + AskUserQuestion: surface the compile error | | Codegen reports an invalid marked declaration | Use a file-scope observable class and a writable instance var with an explicit JSON-native type, internal/public setter, and a key unique across models; otherwise remove the // @Snapshotable marker. | | Schema hash unchanged after adding new @Observable | No field has the standalone // @Snapshotable marker comment — codegen excludes unmarked state correctly. Add the comment immediately above each field that should be snapshotted. | | Scanner sees generated bridge sources | Pass the narrow app source directory; the regenerator automatically excludes DebugBridgeGenerated and StateAccessor.swift. |

Related skills