Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
f84e929
ci(swift): add auto-tag workflow on push to main
josuediazflores Feb 2, 2026
e728114
Merge pull request #1 from josuediazflores/ci/swift-auto-tag
josuediazflores Feb 2, 2026
30c23a6
Phase 2 Complete
josuediazflores Feb 2, 2026
00c1eba
Fix
josuediazflores Feb 2, 2026
cb07423
Fix Again
josuediazflores Feb 2, 2026
9dfb4ec
ci(swift): create semver tag in Phase 2 for SPM resolution
josuediazflores Feb 2, 2026
37ad693
validation: point swift-spm-consumer at fork for Phase 2 test
josuediazflores Feb 2, 2026
cfe813b
chore(swift): use remote binaries on main for consumer (v0.17.5)
josuediazflores Feb 2, 2026
fcbe222
SDKTestApp, TTS/LLM UI, upstream URLs, SDK improvements
josuediazflores Feb 2, 2026
1328ad3
ci(swift): Swift CI/CD only – auto-tag, build-release, release, Packa…
josuediazflores Feb 2, 2026
7f21179
ci(swift): harden tag build release workflows
josuediazflores Feb 2, 2026
98336e9
ci(swift): ensure commons built before swift package build
josuediazflores Feb 2, 2026
9127453
ci(swift): pin Xcode 15.4 for swift-v tag build
josuediazflores Feb 3, 2026
459abcf
feat(ios): add SDKTestApp demo app
josuediazflores Feb 3, 2026
2139b85
fix(swift): resolve strict concurrency build errors
josuediazflores Feb 3, 2026
6d83bcb
Merge branch 'main' into ci/swift-cd-only
josuediazflores Feb 3, 2026
892c82a
fix(swift): Swift 6 strict concurrency – temp storage, Sendable ref
josuediazflores Feb 3, 2026
0c5f063
fix(swift): use resultPtr.pointee in Foundation Models generate catch
josuediazflores Feb 3, 2026
b1fa241
fix(ci): correct zip path for release-assets (3 levels up from common…
josuediazflores Feb 3, 2026
3f4934d
fix(ci): checkout main before pushing Package.swift, merge tag steps
josuediazflores Feb 3, 2026
93ddf5e
chore: trigger PR refresh
josuediazflores Feb 3, 2026
129a799
fix(ci): build commons once; Swift SDK step only consumes 3 XCFrameworks
josuediazflores Feb 3, 2026
c884700
fix(ci): discard local Package.swift changes before checkout main
josuediazflores Feb 3, 2026
124fa8b
fix(ci): guard tag/main alignment; use git pull --ff-only to prevent …
josuediazflores Feb 3, 2026
7055a3d
fix(codeql): C/C++ manual build for runanywhere-commons; disable defa…
josuediazflores Feb 4, 2026
7c38b94
chore: trigger CodeQL run with latest workflow
josuediazflores Feb 4, 2026
0d4c26b
fix(ci): run tag/main guard only on upstream; allow release on forks …
josuediazflores Feb 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions .github/workflows/swift-auto-tag.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# =============================================================================
# Swift SDK Auto-Tag (Phase 1 CI/CD)
#
# Merges to main automatically create a new git tag swift-vX.Y.Z to mark
# official Swift SDK release points. Full build/publish automation will be
# added later. No builds, no publishing, no macOS runners in this phase.
#
# PR description: Merges to main auto-create swift-vX.Y.Z tags to mark
# official Swift SDK release points. Full build/publish automation will be
# added later.
# =============================================================================

name: Swift SDK Auto-Tag

on:
push:
branches: [main]

permissions:
contents: write

Comment on lines +15 to +21
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Broad trigger: tags on every push to main

This workflow triggers on any push to main (including merges, reverts, and automated commits from other workflows). If Phase 2 commits to main, that commit will also trigger Phase 1 and create another tag unless you add a guard (e.g., skip when actor is github-actions[bot] or when commit message matches the checksum update). Otherwise you can end up in a tag churn/feedback loop.

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/swift-auto-tag.yml
Line: 15:21

Comment:
[P1] Broad trigger: tags on every push to `main`

This workflow triggers on any push to `main` (including merges, reverts, and automated commits from other workflows). If Phase 2 commits to `main`, that commit will also trigger Phase 1 and create another tag unless you add a guard (e.g., skip when actor is `github-actions[bot]` or when commit message matches the checksum update). Otherwise you can end up in a tag churn/feedback loop.

How can I resolve this? If you propose a fix, please make it concise.

jobs:
tag:
name: Create Swift SDK Tag
if: github.actor != 'github-actions[bot]'
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

- name: Compute Next Tag
id: next_tag
run: |
set -e
SDK_VERSION=$(grep -E 'let sdkVersion = "' Package.swift | head -1 | sed -E 's/.*"([^"]+)".*/\1/')
if [ -z "$SDK_VERSION" ]; then
echo "Unable to determine sdkVersion from Package.swift"
exit 1
fi
NEW_TAG="swift-v$SDK_VERSION"
echo "tag=$NEW_TAG" >> "$GITHUB_OUTPUT"
echo "Computed tag from Package.swift sdkVersion: $NEW_TAG"

- name: Skip If Tag Exists
id: skip
run: |
NEW_TAG="${{ steps.next_tag.outputs.tag }}"
if git rev-parse "$NEW_TAG" >/dev/null 2>&1; then
echo "Tag $NEW_TAG already exists, skipping (idempotent rerun)"
echo "skip=true" >> "$GITHUB_OUTPUT"
else
echo "skip=false" >> "$GITHUB_OUTPUT"
fi

- name: Create and Push Tag
if: steps.skip.outputs.skip != 'true'
run: |
NEW_TAG="${{ steps.next_tag.outputs.tag }}"
git tag -a "$NEW_TAG" -m "Swift SDK Release $NEW_TAG"
git push origin "$NEW_TAG"
echo "Pushed tag: $NEW_TAG"
222 changes: 222 additions & 0 deletions .github/workflows/swift-sdk-build-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
# =============================================================================
# Swift SDK Build & Release (Phase 2 CI/CD)
#
# When a swift-v* tag is pushed (from Phase 1), build native XCFrameworks via
# build-ios.sh and the Swift SDK via build-swift.sh on macOS, compute SHA256
# checksums of the ZIPs, update Package.swift with those checksums and
# sdkVersion, commit and push to main, move the tag to that commit, then
# create a GitHub Release and attach the built artifacts. SPM consumers then
# resolve the tag and get correct checksums for the release assets.
#
# Phase 1 decides when (tag on merge to main). Phase 2 performs what
# (build + package + release assets + checksum update).
#
# PR description: Swift SDK builds are automated on swift-v* tag push:
# build-ios.sh and build-swift.sh run on macOS, and the resulting XCFrameworks
# are attached to the GitHub Release. No CocoaPods/App Store; no cross-SDK
# orchestration.
# =============================================================================

name: Swift SDK Build & Release

on:
push:
tags:
- 'swift-v*'

permissions:
contents: write

env:
COMMONS_DIR: sdk/runanywhere-commons
SWIFT_SDK_DIR: sdk/runanywhere-swift

jobs:
build-and-release:
name: Build & Release Swift SDK
runs-on: macos-14

steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
fetch-tags: true

- name: Determine Version
id: version
run: |
TAG="${GITHUB_REF#refs/tags/}"
VERSION="${TAG#swift-v}"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "Building Swift SDK $TAG (version $VERSION)"

- name: Build Native XCFrameworks
run: |
./${COMMONS_DIR}/scripts/build-ios.sh --clean
echo "XCFrameworks:"
ls -la ${COMMONS_DIR}/dist/*.xcframework/ 2>/dev/null || true

- name: Verify Required XCFrameworks
run: |
set -e
COMMONS_DIST="${COMMONS_DIR}/dist"
REQUIRED="RACommons RABackendLLAMACPP RABackendONNX"
for name in $REQUIRED; do
if [ ! -d "${COMMONS_DIST}/${name}.xcframework" ]; then
echo "Missing required framework: ${name}.xcframework"
exit 1
fi
done
echo "All required XCFrameworks are present."

- name: Build Swift SDK
run: |
./${SWIFT_SDK_DIR}/scripts/build-swift.sh --local --build-commons --release
echo "Swift build complete"

- name: Prepare Release Assets
id: assets
run: |
VERSION="${{ steps.version.outputs.version }}"
COMMONS_DIST="${COMMONS_DIR}/dist"
mkdir -p release-assets
for name in RACommons RABackendLLAMACPP RABackendONNX; do
if [ -d "${COMMONS_DIST}/${name}.xcframework" ]; then
zip_name="${name}-ios-v${VERSION}.zip"
(cd "${COMMONS_DIST}" && zip -r "${GITHUB_WORKSPACE}/release-assets/${zip_name}" "${name}.xcframework")
echo "Created release-assets/${zip_name}"
fi
done
echo "assets_dir=release-assets" >> "$GITHUB_OUTPUT"
ls -la release-assets/

- name: Compute Checksums
id: checksums
run: |
VERSION="${{ steps.version.outputs.version }}"
for name in RACommons RABackendLLAMACPP RABackendONNX; do
if [ ! -f "release-assets/${name}-ios-v${VERSION}.zip" ]; then
echo "Missing required asset: release-assets/${name}-ios-v${VERSION}.zip"
exit 1
fi
done
COMMONS_CHECKSUM=$(shasum -a 256 "release-assets/RACommons-ios-v${VERSION}.zip" | cut -d ' ' -f 1)
LLAMACPP_CHECKSUM=$(shasum -a 256 "release-assets/RABackendLLAMACPP-ios-v${VERSION}.zip" | cut -d ' ' -f 1)
ONNX_CHECKSUM=$(shasum -a 256 "release-assets/RABackendONNX-ios-v${VERSION}.zip" | cut -d ' ' -f 1)
echo "commons=$COMMONS_CHECKSUM" >> "$GITHUB_OUTPUT"
echo "llamacpp=$LLAMACPP_CHECKSUM" >> "$GITHUB_OUTPUT"
echo "onnx=$ONNX_CHECKSUM" >> "$GITHUB_OUTPUT"
echo "RACommons: $COMMONS_CHECKSUM"
echo "RABackendLLAMACPP: $LLAMACPP_CHECKSUM"
echo "RABackendONNX: $ONNX_CHECKSUM"

- name: Ensure Main Matches Tag
run: |
TAG="${{ steps.version.outputs.tag }}"
git fetch origin main --prune
TAG_COMMIT=$(git rev-parse "${TAG}^{commit}")
MAIN_COMMIT=$(git rev-parse "origin/main")
if [ "$TAG_COMMIT" != "$MAIN_COMMIT" ]; then
echo "Tag ${TAG} points to ${TAG_COMMIT}, but origin/main is ${MAIN_COMMIT}"
echo "Refusing to update Package.swift on main to avoid mismatched assets."
exit 1
fi
git checkout -B main origin/main

- name: Update Package.swift Checksums and Version
run: |
VERSION="${{ steps.version.outputs.version }}"
COMMONS_CHECKSUM="${{ steps.checksums.outputs.commons }}"
LLAMACPP_CHECKSUM="${{ steps.checksums.outputs.llamacpp }}"
ONNX_CHECKSUM="${{ steps.checksums.outputs.onnx }}"
# Ensure production mode for release (remote binaries)
sed -i '' 's/let useLocalBinaries = true/let useLocalBinaries = false/' Package.swift
# Update sdkVersion
sed -i '' 's/let sdkVersion = "[^"]*"/let sdkVersion = "'"$VERSION"'"/' Package.swift
# Update the three binary target checksums (range: url line through checksum line)
sed -i '' '/RACommons-ios-v.*zip/,/checksum:/ s/checksum: "[^"]*"/checksum: "'"$COMMONS_CHECKSUM"'"/' Package.swift
sed -i '' '/RABackendLLAMACPP-ios-v.*zip/,/checksum:/ s/checksum: "[^"]*"/checksum: "'"$LLAMACPP_CHECKSUM"'"/' Package.swift
sed -i '' '/RABackendONNX-ios-v.*zip/,/checksum:/ s/checksum: "[^"]*"/checksum: "'"$ONNX_CHECKSUM"'"/' Package.swift
echo "Updated Package.swift sdkVersion and checksums"
grep -A1 "RACommons-ios" Package.swift | head -4

- name: Commit and Push Package.swift Update
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add Package.swift
if git diff --staged --quiet; then
echo "No Package.swift changes to commit"
else
git commit -m "chore(swift): update Package.swift checksums for swift-v${{ steps.version.outputs.version }}"
git push origin HEAD:main
fi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P0] Committing to main on a tag-triggered workflow can fail without checking out main

This workflow triggers on tag pushes, so actions/checkout checks out the tagged commit in a detached HEAD state. git push origin HEAD:main can be rejected if main has advanced since the tag commit. If you intend to update main reliably, you’ll need to explicitly fetch/checkout main and merge/rebase (or otherwise ensure you’re pushing atop the current main).

Prompt To Fix With AI
This is a comment left during a code review.
Path: .github/workflows/swift-sdk-build-release.yml
Line: 110:120

Comment:
[P0] Committing to `main` on a tag-triggered workflow can fail without checking out `main`

This workflow triggers on tag pushes, so `actions/checkout` checks out the tagged commit in a detached HEAD state. `git push origin HEAD:main` can be rejected if `main` has advanced since the tag commit. If you intend to update `main` reliably, you’ll need to explicitly fetch/checkout `main` and merge/rebase (or otherwise ensure you’re pushing atop the current `main`).

How can I resolve this? If you propose a fix, please make it concise.


- name: Create Semver Tag for SPM
run: |
VERSION="${{ steps.version.outputs.version }}"
# SPM resolves versions from semver tags (e.g. 0.1.2 or v0.1.2)
# Create v${VERSION} on the checksum-updated commit so consumers can use from: "X.Y.Z"
SEMVER_TAG="v${VERSION}"
git tag -a "${SEMVER_TAG}" -m "Swift SDK ${SEMVER_TAG}"
git push origin "${SEMVER_TAG}"
echo "Semver tag ${SEMVER_TAG} created for SPM resolution"

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ steps.version.outputs.version }}
name: RunAnywhere Swift SDK v${{ steps.version.outputs.version }}
body: |
## RunAnywhere Swift SDK v${{ steps.version.outputs.version }}

Privacy-first, on-device AI SDK for iOS and macOS. Built automatically on swift-v* tag push (Phase 2 CI).

### Installation

**Swift Package Manager:**
```swift
dependencies: [
.package(
url: "https://github.com/RunanywhereAI/runanywhere-sdks",
from: "${{ steps.version.outputs.version }}"
)
]
```

Then add the products you need:
```swift
.target(
name: "YourApp",
dependencies: [
.product(name: "RunAnywhere", package: "runanywhere-sdks"),
.product(name: "LlamaCPPRuntime", package: "runanywhere-sdks"),
.product(name: "ONNXRuntime", package: "runanywhere-sdks"),
]
)
```

### Features
- **LLM**: On-device text generation via llama.cpp
- **STT**: Speech-to-text via Sherpa-ONNX Whisper
- **TTS**: Text-to-speech via Sherpa-ONNX Piper
- **VAD**: Voice activity detection
- **Privacy**: All processing happens on-device

### Requirements
- iOS 17.0+ / macOS 14.0+
- Swift 5.9+
- Xcode 15.0+

### Documentation
[Swift SDK README](https://github.com/RunanywhereAI/runanywhere-sdks/tree/main/sdk/runanywhere-swift)

---
Built from runanywhere-sdks @ ${{ github.sha }}
files: release-assets/*.zip
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
6 changes: 3 additions & 3 deletions .github/workflows/swift-sdk-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,9 @@ name: Swift SDK Release
# .package(url: "https://github.com/RunanywhereAI/runanywhere-sdks", from: "1.0.0")
# =============================================================================

# Phase 2 workflow (swift-sdk-build-release.yml) runs on swift-v* tag push.
# This workflow runs only when called by release-all or manually.
on:
push:
tags:
- 'swift-v*'
workflow_call:
inputs:
version:
Expand Down Expand Up @@ -451,6 +450,7 @@ jobs:
startsWith(github.ref, 'refs/tags/swift-v') ||
startsWith(github.ref, 'refs/tags/v') ||
github.event_name == 'workflow_dispatch' ||
github.event_name == 'workflow_call' ||
github.event_name == 'push'
)
runs-on: ubuntu-latest
Expand Down
10 changes: 5 additions & 5 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ let onnxRuntimeMacOSPath = "\(packageDir)/sdk/runanywhere-swift/Binaries/onnxrun
// ./scripts/build-swift.sh --set-remote (sets useLocalBinaries = false)
//
// =============================================================================
let useLocalBinaries = true // Toggle: true for local dev, false for release
let useLocalBinaries = false // Toggle: true for local dev, false for release

// Version for remote XCFrameworks (used when testLocal = false)
// Updated automatically by CI/CD during releases
Expand Down Expand Up @@ -219,23 +219,23 @@ func binaryTargets() -> [Target] {
} else {
// =====================================================================
// PRODUCTION MODE (for external SPM consumers)
// Download XCFrameworks from GitHub releases
// Download XCFrameworks from GitHub releases (v* or swift-v* from Phase 2 CI)
// =====================================================================
return [
.binaryTarget(
name: "RACommonsBinary",
url: "https://github.com/RunanywhereAI/runanywhere-sdks/releases/download/v\(sdkVersion)/RACommons-ios-v\(sdkVersion).zip",
checksum: "ba367c89a468513b33fb167b5996574a8797bf2c00a21e01579ec59458813559"
checksum: "38e871517017610185057e83b14ebf4ac1021d53247f7f85d12d411217ef5247"
),
.binaryTarget(
name: "RABackendLlamaCPPBinary",
url: "https://github.com/RunanywhereAI/runanywhere-sdks/releases/download/v\(sdkVersion)/RABackendLLAMACPP-ios-v\(sdkVersion).zip",
checksum: "9e58e33e2984f5f0498bdad69387aec306fd2d31e6690eab38b9f1d1a21fb0ca"
checksum: "5c8b1c68d32e72561559cb366125f4413968114cdfb1c118141d186c37f3eb4c"
),
.binaryTarget(
name: "RABackendONNXBinary",
url: "https://github.com/RunanywhereAI/runanywhere-sdks/releases/download/v\(sdkVersion)/RABackendONNX-ios-v\(sdkVersion).zip",
checksum: "e760044abfe97d2bde9386d801b0e11421c3782980f4088edce6d6d976f48a84"
checksum: "42a61542fb299f7aaf127a8590ead58d8b159db4ba5ea67fd48a835da3c6289e"
),
.binaryTarget(
name: "ONNXRuntimeBinary",
Expand Down