# Swift Binding Assistant

> Guide users through creating .NET C# bindings for Swift or Objective-C Apple platform libraries (iOS, macOS, Mac Catalyst, tvOS). Takes a user from an SPM package URL or xcframework to a validated NuGet package using the SwiftBindings.Sdk. Handles prerequisites, xcframework building, binding generation, error diagnosis, and optional binding review. Auto-detects whether the framework is Swift, Obj…

- **Type:** Skill
- **Install:** `agentstack add skill-justinwojo-claude-skills-swift-binding-assistant`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [justinwojo](https://agentstack.voostack.com/s/justinwojo)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [justinwojo](https://github.com/justinwojo)
- **Source:** https://github.com/justinwojo/claude-skills/tree/main/swift-binding-assistant

## Install

```sh
agentstack add skill-justinwojo-claude-skills-swift-binding-assistant
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Swift & ObjC Binding Assistant

Guide users through creating .NET C# bindings for Swift or Objective-C Apple platform libraries using the SwiftBindings.Sdk. Supports iOS, macOS, Mac Catalyst, and tvOS. The generator auto-detects framework type (Swift, ObjC, or mixed) and runs the correct pipeline — no flags needed.

## Documentation

The authoritative docs live in the [project wiki](https://github.com/justinwojo/swift-dotnet-bindings/wiki). **Always fetch the latest version** from the raw URLs below when you need to reference them — do NOT rely on memorized content, as it may be outdated. Use whatever fetch mechanism is available (e.g., `WebFetch`, `curl`, browser, or built-in web tools).

| Doc | URL |
|-----|-----|
| Getting Started | `https://raw.githubusercontent.com/wiki/justinwojo/swift-dotnet-bindings/Getting-Started.md` |
| FAQ | `https://raw.githubusercontent.com/wiki/justinwojo/swift-dotnet-bindings/FAQ.md` |
| Troubleshooting | `https://raw.githubusercontent.com/wiki/justinwojo/swift-dotnet-bindings/Troubleshooting.md` |
| Known Limitations | `https://raw.githubusercontent.com/wiki/justinwojo/swift-dotnet-bindings/Known-Limitations.md` |
| Supported Features | `https://raw.githubusercontent.com/wiki/justinwojo/swift-dotnet-bindings/Supported-Features.md` |
| How Bindings Map | `https://raw.githubusercontent.com/wiki/justinwojo/swift-dotnet-bindings/How-Bindings-Map.md` |
| Customization | `https://raw.githubusercontent.com/wiki/justinwojo/swift-dotnet-bindings/Customization.md` |
| SwiftUI Interop | `https://raw.githubusercontent.com/wiki/justinwojo/swift-dotnet-bindings/SwiftUI-Interop.md` |
| NativeAOT Deployment | `https://raw.githubusercontent.com/wiki/justinwojo/swift-dotnet-bindings/NativeAOT-Deployment.md` |
| Ownership & Disposal | `https://raw.githubusercontent.com/wiki/justinwojo/swift-dotnet-bindings/Ownership.md` |
| Upgrading | `https://raw.githubusercontent.com/wiki/justinwojo/swift-dotnet-bindings/Upgrading.md` |
| Architecture | `https://raw.githubusercontent.com/wiki/justinwojo/swift-dotnet-bindings/Architecture.md` |
| **Multi-Framework Libraries** | `https://raw.githubusercontent.com/wiki/justinwojo/swift-dotnet-bindings/Multi-Framework-Libraries.md` |
| **Publishing** | `https://raw.githubusercontent.com/wiki/justinwojo/swift-dotnet-bindings/Publishing.md` |

Fetch docs proactively when:
- The user hits a build error (fetch Troubleshooting)
- The user asks what's supported (fetch Supported Features, Known Limitations)
- The user asks how Swift types map to C# (fetch How Bindings Map)
- You need to explain a gap or skip reason (fetch Known Limitations)
- The user asks about memory management or disposal (fetch Ownership)
- The user asks about upgrading versions (fetch Upgrading)
- The user is binding more than one framework from the same vendor (fetch Multi-Framework Libraries)
- The user is preparing to publish a NuGet package, sets up CI release workflows, or needs pack metadata details (fetch Publishing)
- The user has a general question (fetch FAQ first — it may already be answered)

## Workflow Overview

```
User Input
├── SPM package URL → Build xcframework (spm-to-xcframework)
├── GitHub release with xcframework → Download it
├── Local xcframework → Use directly
└── Vendor xcframework → Verify requirements
         │
         ▼
   Check prerequisites
         │
         ▼
   Create binding project (dotnet new swift-binding)
   Copy xcframework into project
   Configure dependencies if needed
         │
         ▼
   dotnet build
         │
    ┌────┴────┐
  Success   Errors → Diagnose (fetch Troubleshooting.md)
    │                      │
    ▼                      │
  dotnet pack    ◄─────────┘
    │
    ▼
  NuGet package ready
    │
    ▼
  Ask: "Would you like me to review the generated binding
        for completeness and usability?"

Framework type is AUTO-DETECTED during build — no flags needed:
  Swift  → Parser/Marshaler/Emitter pipeline → {Module}.cs + Swift wrapper
  ObjC   → Clang AST pipeline → ApiDefinition.cs + StructsAndEnums.cs + BgenDelegates.cs
  Mixed  → Both pipelines run → two projects emitted
```

## Step 0: Gather Information

Ask the user what they're starting with:

1. **SPM package URL** — a GitHub URL containing a `Package.swift` (e.g., `https://github.com/kean/Nuke`)
2. **Local xcframework** — a path to a `.xcframework` directory on disk
3. **A library name** — they may not know the format; help them figure out what they have

Also ask:
- What's the library name? (for the NuGet package naming)
- What platform are you targeting? (iOS is the default; also supports macOS, Mac Catalyst, tvOS)
- Is it a Swift framework, an Objective-C framework, or are you unsure? (The tool auto-detects, but knowing upfront helps set expectations for output format.)
- Does the library depend on any other frameworks? (for framework dependencies)

## Step 1: Check Prerequisites

Run these checks and report results to the user:

```bash
# Host OS check — Apple platform binding generation requires macOS + Xcode.
# If this prints anything other than "Darwin", STOP and tell the user the
# workflow can't proceed on this host (Linux/Windows have no Xcode toolchain
# and can't compile the Swift wrapper xcframework).
uname -s

# Xcode check — requires Xcode 26 or later (not just Command Line Tools)
xcode-select -p
# Must show /Applications/Xcode.app/Contents/Developer or similar
# If it shows /Library/Developer/CommandLineTools, tell the user:
#   sudo xcode-select -s /Applications/Xcode.app

# Verify Xcode version
xcodebuild -version
# Must be Xcode 26.x or later

# .NET SDK check
dotnet --version
# Must be 10.x or later

# Platform workload check
dotnet workload list
# Must include the workload for the target platform:
#   iOS:           "ios"           → dotnet workload install ios
#   macOS:         "macos"         → dotnet workload install macos
#   Mac Catalyst:  "maccatalyst"   → dotnet workload install maccatalyst
#   tvOS:          "tvos"          → dotnet workload install tvos

# Template check
dotnet new list swift-binding
# If not found: dotnet new install SwiftBindings.Templates
```

If any prerequisite is missing, guide the user through installing it before proceeding. Do not continue until all prerequisites pass.

**Hard stop on non-macOS hosts**: if `uname -s` is not `Darwin`, the workflow cannot proceed — Apple platform bindings require Xcode, which only runs on macOS. Inform the user and stop. Do not try to suggest cross-compilation, Docker, or remote-build workarounds; there isn't a supported path today.

## Step 2: Obtain the xcframework

### From SPM (Swift Package Manager)

If the user provides an SPM package URL:

1. Clone the spm-to-xcframework tool (if not already present):
   ```bash
   git clone https://github.com/justinwojo/spm-to-xcframework.git /tmp/spm-to-xcframework
   ```

2. Determine the latest release tag for the Swift package. **Do not use `tail -5` on unsorted ls-remote output** — git returns tags in lexicographic order, so `1.10.0` would sort before `1.2.0` and you'd pick the wrong version. Use a version-aware sort instead:
   ```bash
   # Sort tags by semver descending; suffix=- pushes prereleases (-rc1, -beta) below stable releases
   git -c versionsort.suffix=- ls-remote --tags --sort=-version:refname --refs  \
     | head -10
   # Output: abc1234  refs/tags/12.7.3
   #         def5678  refs/tags/12.7.2
   #         ...
   # The first line after filtering prereleases is your latest stable tag.
   ```
   If the project uses non-semver tags or has unusual versioning, fall back to the GitHub releases page (`https://github.com///releases/latest`) or ask the user which version they want.

3. Build the xcframework (**capture output — this can take several minutes**):
   ```bash
   cd /tmp/spm-to-xcframework && swift run spm-to-xcframework \
     --url  \
     --version  \
     --output /tmp/xcframeworks 2>&1 | tee /tmp/spm-build.txt
   ```
   For a local Package.swift directory:
   ```bash
   cd /tmp/spm-to-xcframework && swift run spm-to-xcframework \
     --path /path/to/package \
     --output /tmp/xcframeworks 2>&1 | tee /tmp/spm-build.txt
   ```
   The output xcframework(s) will be in `/tmp/xcframeworks/`.

4. If the library has multiple products, ask the user which one to bind (or use `--product ` to target one).

5. If the library has dependencies that the user also wants to bind, use `--include-deps`.

The tool handles `BUILD_LIBRARY_FOR_DISTRIBUTION=YES` and dynamic framework building automatically.

### From a local/vendor xcframework

Verify the xcframework meets requirements:

```bash
# Check it exists and has expected structure
ls /Library.xcframework/

# Check it's a dynamic framework (not static)
# Look for a .framework bundle with a Mach-O binary inside
# Use the appropriate slice directory for your target platform:
#   iOS:           ios-arm64_x86_64-simulator or ios-arm64
#   macOS:         macos-arm64
#   Mac Catalyst:  ios-arm64-maccatalyst
#   tvOS:          tvos-arm64_x86_64-simulator or tvos-arm64
file /Library.xcframework//Library.framework/Library
# Should say "dynamically linked shared library"
# If it says "current ar archive" → it's static, needs rebuild

# Check for Swift module (use appropriate slice directory)
ls /Library.xcframework//Library.framework/Modules/*.swiftmodule 2>/dev/null
# If present → Swift framework (uses ABI JSON pipeline)
# If empty → ObjC framework (uses Clang AST pipeline) — both are fully supported

# For ObjC frameworks, verify headers and module map exist
ls /Library.xcframework//Library.framework/Headers/ 2>/dev/null
ls /Library.xcframework//Library.framework/Modules/module.modulemap 2>/dev/null
# ObjC frameworks need public headers AND a module.modulemap for binding generation
# The generator uses module.modulemap as the validity check for ObjC frameworks
```

**If the xcframework is static:**
- Static xcframeworks **are supported for ObjC frameworks** (e.g., Firebase/Google SDKs ship static xcframeworks and bind correctly).
- Static xcframeworks **are NOT supported for Swift frameworks** — they must be rebuilt as dynamic with `BUILD_LIBRARY_FOR_DISTRIBUTION=YES`.
- If the user controls the build, they can rebuild it. If not, suggest [spm-to-xcframework](https://github.com/justinwojo/spm-to-xcframework) if the source is available as SPM.
- If neither option works, point them to [Maui.NativeLibraryInterop](https://github.com/CommunityToolkit/Maui.NativeLibraryInterop) as an alternative approach (hand-written C wrappers, works with any xcframework).

## Step 3: Create the Binding Project

```bash
# Pick a working directory
mkdir -p ~/swift-bindings && cd ~/swift-bindings

# Create the project — naming convention:
#   Single library:        .Swift.           (e.g., Nuke.Swift.iOS)
#   Multi-vendor SDK set:  SwiftBindings..          (e.g., SwiftBindings.Stripe.Core)
# Platform suffixes: iOS, macOS, MacCatalyst, tvOS
# Use --platform to set the target (default: ios)

# iOS (default)
dotnet new swift-binding -n .Swift.iOS

# macOS
dotnet new swift-binding -n .Swift.macOS --platform macos

# Mac Catalyst
dotnet new swift-binding -n .Swift.MacCatalyst --platform maccatalyst

# tvOS
dotnet new swift-binding -n .Swift.tvOS --platform tvos

# Copy the xcframework into the project
cp -r  .Swift./
```

The generated `.csproj` will look like:
```xml

  
    net10.0-ios  
  

```

The SDK version (`X.Y.Z`) is pinned by the template at install time.

The SDK auto-detects the target platform from the TFM — no additional configuration needed beyond setting the correct TFM.

**The same `.csproj` and SDK work for both Swift and ObjC frameworks.** The SDK auto-detects the framework type during the build and runs the correct pipeline. No additional configuration is needed for ObjC frameworks.

### Framework Dependencies

If the library imports other Swift frameworks, the user needs to provide them.

**Auto-detection (default):** The SDK ships with `true` enabled by default. The build analyzes the xcframework's binary linkage, finds matching sibling binding projects in the solution, and auto-injects `` items. If a needed dependency is missing, it emits **SWIFTBIND080** with a suggested fix. In most multi-project solutions, you do not need to declare dependencies manually.

**Option 1: `` (multi-project solutions — preferred)**

For multi-product vendors (e.g., Stripe) where you're binding several frameworks in the same solution:

```xml

  

```

The SDK automatically resolves dependency xcframework search paths and module databases during wrapper compilation, propagates native references to the consumer's app bundle, and converts the reference into a transitive `` during `dotnet pack` — no manual configuration needed.

**Option 2: `` (external/pre-built or internal dependencies)**

For dependencies that are pre-built xcframeworks (not sibling projects), or internal helper frameworks (e.g., ObjC-only support modules) that won't be published as their own NuGet package:

```xml

  
  

  
  

```

Each dependency also needs to be a built xcframework. If the user used `spm-to-xcframework --include-deps`, these will already exist in the output directory.

For published dependencies, both `PackageId` and `PackageVersion` are required for NuGet pack to declare the dependency (`SWIFTBIND040` warns if missing). For internal helpers that won't be published separately, the warning is intentional — consumers will need to add a `` for the internal framework manually. See the **Multi-Framework Libraries** wiki page for the full pattern.

## Step 4: Build

**Always capture build output to a temp file** — it can be very long:

```bash
cd .Swift.
dotnet build 2>&1 | tee /tmp/swift-binding-build.txt
```

Then read the output file to check the result.

### On Success

**For Swift frameworks**, the build automatically:
- Extracts ABI metadata from the xcframework
- Runs the binding generator (produces `.cs` and `.swift` wrapper files)
- Compiles the Swift wrapper into an xcframework
- Builds the C# bindings into a DLL

**For ObjC frameworks**, the build automatically:
- Runs `clang -ast-dump=json` on the framework's umbrella header
- Parses the Clang AST into ObjC declarations
- Filters platform type stubs (types already in .NET iOS SDK)
- Generates `ApiDefinition.cs` (always), plus `StructsAndEnums.cs` and `BgenDelegates.cs` if applicable
- Runs the .NET iOS binding tools (bgen) to compile the binding
- No Swift wrapper is needed — ObjC frameworks link directly

**For mixed frameworks** (both Swift and ObjC surface), both pipelines run and two projects are emitted.

Tell the user the build succeeded and move to Step 5.

### On Failure

**Immediately fetch the troubleshooting guide** from the URL in the doc table above, then diagnose the error. Here's a quick-reference for the most common errors:

| Error | Cause | Fix |
|-------|-------|-----|
| **SWIFTBIND001** | No xcframework in project dir | Copy xcframework into the project, or add explicit `` item |
| **SWIFTBIND002** | Multiple xcframeworks found | One xcframework per project — create separate binding projects for each |
| **SWIFTBIND003** | xcframework path doesn't exist | Check the path in `` item |
| **SWIFTBIND010** | Unsupported target framework | Use Apple platform TFM: `net10.0-ios`, `net10.0-macos`, `net10.0-maccatalyst`, `net10.0-tvos` |
| **SWIFTBIND011** | Consumer targets older platform version than library requires | Update `SupportedOSPlatformVersion` to the version shown in the warning |
| **SWIFTBIND030** | Missing architectures for packing | Set `all` |
| **SWIFTBIND031** | Wrapper xcframework missing device or simulator slice | Verify xcframework has both slices, or set `false` for local-only |
| **SWIFTBIND035** | Cannot resolve platform version for NuGet pack | Use a versioned TFM (`net10.0-ios26.0`) or install the platform workload |
| **SWIFTBIND040** | `` missing `PackageId`/`PackageVersion` | Add metadata if the dep is publi

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [justinwojo](https://github.com/justinwojo)
- **Source:** [justinwojo/claude-skills](https://github.com/justinwojo/claude-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-justinwojo-claude-skills-swift-binding-assistant
- Seller: https://agentstack.voostack.com/s/justinwojo
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
