Public binary distribution for the SwiftPython runtime on macOS.
This repository is intentionally public so SwiftPython users can depend on it with Swift Package Manager. SwiftPython is available under three paths: AGPL-3.0 for AGPL-compliant open source applications, a free Small Organization Commercial Grant for individuals and organizations with fewer than 10 total employees and contractors, or a written commercial license for larger proprietary/closed-source use. The SwiftPython source code, generator pipeline, and implementation internals remain private. You do not need the private repository to build an app against this package.
Current release: 0.5.15
Product page: Best Byte AI
| Use case | Path |
|---|---|
| AGPL-compliant open source app or service | AGPL-3.0 |
| Individual or organization under 10 total employees/contractors | Free Small Organization Commercial Grant |
| Organization with 10 or more total employees/contractors | Written SwiftPython Commercial license |
The small-organization threshold counts parent companies, subsidiaries, and controlled affiliates. This table is only a summary; see LICENSE for the exact terms.
| Artifact | Purpose |
|---|---|
SwiftPythonRuntime.xcframework |
Swift runtime API and binary library |
SwiftPythonWorker |
Local worker sidecar for PythonProcessPool |
VMWorker/ |
Python supervisor and worker scripts for VM tenants |
Entitlements/ |
Hardened runtime, sandbox, and VM entitlement templates |
Examples/IrisDemo/ |
Complete macOS IRIS app built against the public runtime |
Examples/CoreRuntimeSmoke/ |
Minimal CLI: in-process Python.run |
Examples/ProcessPoolSmoke/ |
Minimal CLI: withProcessPool + invokeResult |
Examples/BridgingRing/ |
Pool IPC tour: Swift↔Python callbacks, WorkerCallbackContext, evalEvents |
Examples/SharedTensorPipeline/ |
Headline demo: shared-memory arena + out-of-band streaming + concurrent IPC |
docs/api-guide/ |
Public API guide and integration recipes |
scripts/consumer_path_smoke.sh |
Verifies a separate Swift package can consume this checkout by local path |
Keep the XCFramework, worker binary, and VMWorker/ scripts on the same tag.
Do not mix artifacts from different releases.
Use Swift Package Manager, a tagged source archive, or a complete
SwiftPythonCommercial-<version>.zip release asset when available. Those
include the package manifest, worker sidecar, VMWorker/ scripts, entitlements,
examples, and docs.
SwiftPythonRuntime.xcframework.zip is the runtime binary artifact only. It is
not a complete installable distribution by itself for PythonProcessPool,
SandboxPool, or the examples because those also need the matched worker and
support files from the same release tag.
- macOS 15.0+
- Swift 6.0+
- Python 3.13, Homebrew recommended for development
- Xcode command line tools
- Apple Silicon Mac for the shipped
SwiftPythonWorkersidecar and VM/SandboxPool path
For Python 3.13 via Homebrew:
brew install python@3.13The package and examples auto-detect Homebrew's Apple Silicon and Intel
prefixes. For custom Python layouts, set SWIFTPYTHON_PYTHON_LIB_DIR,
PYTHON_HOME, or PYTHONHOME before building.
// Package.swift
dependencies: [
.package(
url: "https://github.com/mikhutchinson/swiftpython-commercial.git",
from: "0.5.15"
)
].target(
name: "YourAppCore",
dependencies: [
.product(name: "SwiftPythonRuntime", package: "swiftpython-commercial")
],
linkerSettings: [
.unsafeFlags([
"-L/opt/homebrew/opt/python@3.13/Frameworks/Python.framework/Versions/3.13/lib",
"-lpython3.13"
])
]
)Import the runtime:
import SwiftPythonRuntimelet version: String = try await Python.run {
try String(pythonObject: Python.sys.version)
}
print(version)For worker execution:
try await withProcessPool(workers: 2) { pool in
let value: Double = try await pool.invokeResult(
module: "math",
function: "sqrt",
args: [.python(144.0)]
)
print(value)
}Start here: docs/api-guide.
For runnable samples, see Examples (including IrisDemo). The examples resolve this checkout by local path by default; no package URL or version environment variables are needed when running them from a clone.
First-run smoke from a local checkout:
swift build
swift test
swift run swiftpython-smoke
swift run --package-path Examples/CoreRuntimeSmoke
swift run --package-path Examples/ProcessPoolSmoke
swift run --package-path Examples/BridgingRing
swift run -c release --package-path Examples/SharedTensorPipeline
scripts/consumer_path_smoke.shThe root package includes a small swiftpython-smoke executable only to make
first contact obvious. The richer examples live under Examples/.
scripts/consumer_path_smoke.sh creates a temporary external Swift package,
depends on this checkout by path, and verifies both Python.run and
withProcessPool.
Most existing Swift ↔ Python bridges put CPython in your app's address
space: one interpreter, one GIL, one crash domain. SwiftPython runs the
same Python.run model in-process and a multi-process PythonProcessPool
with a documented IPC protocol on top.
| Axis | In-process bridge (e.g. PythonKit) | SwiftPython |
|---|---|---|
| Process model | Embeds libpython in your app |
In-process Python.run plus PythonProcessPool worker processes |
| Parallelism | Limited by a single GIL | One CPython + one GIL per worker; multiple workers run in parallel |
| Crash isolation | Python crash takes down the host | Worker crashes are surfaced as Swift errors; respawn is built-in |
| Native extensions (NumPy, Torch, …) | Yes, in the host process | Yes — in workers, where a crashing extension does not kill your app |
| Shared-memory tensors across processes | N/A | pool.createSharedTensor + withSharedBuffer (typed Swift access into POSIX shm) |
| Out-of-band streaming | N/A | SharedRingBuffer (POSIX shm) or SocketOOBStreamBuffer (UDS / vsock) — stream without holding the worker IPC socket, process-pool or VM tenant |
| Python → Swift callbacks | N/A | registerCallback, registerReentrantCallback, registerStreamingCallback, registerAsyncCallback |
| Worker telemetry | Manual host logging | Structured ProcessPoolTelemetryEvent stream with command spans, worker identity, callback/stream state, respawn evidence, Python exception metadata, and host correlation context |
| VM-isolated tenants | N/A | SandboxPool with Linux VM guests (execShell, execShellPTY) |
This is a positioning summary, not a claim of feature parity in either direction; PythonKit-style in-process bridges remain a perfectly good fit when your workload is small, trusted, and never needs to leave the app process. SwiftPython is built for the cases where you want isolation, parallelism, or large shared buffers in addition to the in-process surface.
For a single executable that exercises the shared-memory arena, out-of-band
streaming, and concurrent IPC together, see
Examples/SharedTensorPipeline.
The guide covers:
- in-process
Python.run, - Swift/Python conversion and buffers,
PyHandleandOwnedPyHandle,PythonProcessPool,- structured ProcessPool telemetry,
- streaming values and progress,
- DAG orchestration,
- Python-to-Swift callbacks,
- app-level wrappers for Python packages,
- VM tenants and shell/PTY exec through
SandboxPool.
For .app bundles, copy SwiftPythonWorker into Contents/MacOS next to your
main executable.
YourApp.app/
Contents/
MacOS/
YourApp
SwiftPythonWorker
Info.plist
If your app uses VM tenants and cannot rely on the SPM checkout at runtime,
deploy VMWorker/ with your app and set:
SWIFTPYTHON_VM_WORKER_DIR=/absolute/path/to/VMWorkerFor development tools and CLIs, you can point directly at the worker:
SWIFTPYTHON_WORKER_PATH=/absolute/path/to/SwiftPythonWorkeror pass workerExecutablePath: when creating PythonProcessPool.
Finder-launched apps do not inherit your shell environment. If using Homebrew
Python, set PYTHONHOME and PATH before starting your real app binary.
Example wrapper:
#!/bin/bash
export PYTHONHOME="/opt/homebrew/opt/python@3.13/Frameworks/Python.framework/Versions/3.13"
export PATH="$PYTHONHOME/bin:$PATH"
exec "$(dirname "$0")/YourApp.bin"Apps that bundle Python should set these paths to their bundled framework or virtual environment instead.
Python native extensions often require hardened runtime exceptions for dynamic library loading and executable memory. The worker is a separate executable, so it must be signed separately from your app.
Sign the worker after copying it into the app:
codesign --force --sign "$SIGN_ID" --options runtime \
--entitlements Entitlements/SwiftPythonWorker.entitlements \
"YourApp.app/Contents/MacOS/SwiftPythonWorker"Sign the app with the consumer entitlement template:
codesign --force --sign "$SIGN_ID" --options runtime \
--entitlements Entitlements/ConsumerApp.entitlements \
"YourApp.app/Contents/MacOS/YourApp"Sign inner binaries first, then the outer app.
During development, an Apple Development signing identity avoids repeated keychain prompts that happen with ad-hoc signing:
IDENTITY=$(security find-identity -v -p codesigning | grep "Apple Development" | head -1 | awk -F'"' '{print $2}')
SIGN_ID="${IDENTITY:--}"Use Entitlements/SwiftPythonWorker-sandbox.entitlements only when the parent
app is sandboxed. It includes sandbox inheritance for the worker.
Do not sign a worker with sandbox inheritance if the parent app is not sandboxed; the worker will get a restrictive default sandbox and may be unable to load Python packages.
VM-backed features require Apple's Virtualization.framework entitlement. Use the provided VM entitlement template as the starting point for tools that build or boot VM tenants.
Build or locate a prepared Ubuntu image, then create a pool:
let builder = UbuntuImageBuilder(
outputDir: "/Users/me/Library/Application Support/MyApp/Images",
swiftpythonVersion: "0.5.15"
)
let image = try await builder.build()
let sandbox = try await SandboxPool(
baseImagePath: image,
cloneDir: "/Users/me/Library/Application Support/MyApp/Sandboxes"
)
let tenantID = SandboxTenantID(rawValue: "default")
let tenant = try await sandbox.acquire(tenantID: tenantID)
let result = try await sandbox.execShell(
tenantID: tenant.id,
"python3 --version"
)
print(String(decoding: result.stdout, as: UTF8.self))
try await sandbox.release(tenant)
await sandbox.shutdown()See Sandbox and VM Exec for tenant lifetime, shell streaming, PTY sessions, events, and VM configuration.
| Issue | Fix |
|---|---|
Library not loaded: libpython3.13.dylib |
Set PYTHONHOME, PATH, and linker flags for the Python 3.13 runtime you ship |
workerNotFound(searchedPaths:) |
Copy SwiftPythonWorker into the app or pass workerExecutablePath: |
protocolError mentioning protocol v5 |
Runtime, worker, and VM scripts are not from the same release tag |
Bad CPU type in executable launching SwiftPythonWorker |
Use Apple Silicon for the shipped sidecar, or build and ship your own matching worker for Intel |
| Worker starts in Terminal but not Finder | Your app launch environment is missing Python paths |
| Python package imports in app but not worker | Worker process sees a different Python environment; set app launch environment consistently |
VMWorker scripts not found |
Deploy VMWorker/ or set SWIFTPYTHON_VM_WORKER_DIR |
| SPM fingerprint mismatch | Delete .build/, Package.resolved, and SwiftPM fingerprint cache, then resolve again |
| Version | Notes |
|---|---|
| 0.5.15 | Bounded-stream-channel overflow now reports streamChannelOverflow instead of a confusing pool-admission .backpressure; Linux IPC logging now respects SWIFTPYTHON_IPC_LOG instead of printing every message unconditionally; snapshot restore-secret hashing no longer touches disk on non-CryptoKit platforms |
| 0.5.14 | Busy-worker-safe idle shedding: shedIdleWorkers(force:) never shuts down a worker with an active command/stream response channel or an unanswered worker→host callback, so critical-pressure force sheds cannot fail a live stream with a spurious "Worker N is not responding", orphan in-flight callbacks, or trigger an immediate self-defeating respawn |
| 0.5.13 | Structured ProcessPool telemetry/tracing: command spans, worker PID/generation, host correlation context, callback/stream/side-channel state, respawn evidence, timeout/no-response classification, redaction-safe Python exception diagnostics, and Swift 6 main-actor-safe ProcessPoolTelemetry.withContext |
| 0.5.12 | Superseded by 0.5.13; initial telemetry release needed the Swift 6 withContext sendability correction for main-actor consumer entry points |
| 0.5.10 | Respawn recovery: default per-worker respawn budget is 9, repeated identical-error recovery is capped at 3 SHA-256-matched attempts, and forced cleanup interrupts blocked host sockets so a forced recycle cannot hang behind its own reader/writer |
| 0.5.9 | macOS spawn admission: worker startup now allows normal reclaimable-memory states such as 69% pressure with about 1.8 GiB available, while still rejecting genuinely scarce memory and hard thermal pressure |
| 0.5.8 | Host resource-pressure gating: ProcessPool now throttles on aggregate host CPU pressure, gates cold worker spawn before selection, marks initial workers idle for shedding, and avoids Python resource_tracker warnings for Swift-owned OOB shared memory |
| 0.5.6 | Shutdown-safe stream recovery: active value/event streams and manual respawn skip worker repair after pool drain or shutdown |
| 0.5.5 | Typed ProcessPool callback overloads through four arguments across sync, async, and reentrant APIs |
| 0.5.4 | Oversized-payload channel recovery: send-side payload caps and parent-side frame draining keep IPC channels usable after typed payload-too-large failures |
| 0.5.3 | Public distribution polish: local-clone example resolution, first-run smoke target, consumer path dependency smoke, free Small Organization Commercial Grant, full distribution release zip, cleaned XCFramework metadata, and matched worker discovery from SwiftPM workspaces |
| 0.5.2 | Runtime reliability patch: callback registration ownership, bounded stream demux backpressure, OOB writer failure signaling, VM health ping timeouts, SandboxPool active tenant locks, and release artifact checksum/upload generation |
| 0.5.1 | ProcessPool reliability patch: CI-exercised reentrant callback fast-fail, bounded per-stream timeout cleanup, typed oversized-command errors, and failed-init worker cleanup |
| 0.5.0 | ProcessPool async callbacks: registerAsyncCallback, worker swift_bridge.call_async, protocol-v5 callback IPC, and matched VM/Sandbox worker parity |
| 0.4.0 | SandboxPool and VM supervisor runtime: Ubuntu image builder, VM tenant pool, shell capture/stream/PTY, quota and policy controls, packaged VMWorker/ scripts |
| 0.3.0 | Multi-stream worker protocol and public streaming surface cleanup |
| 0.2.1 | Public worker respawn API with force-kill path |
| 0.2.0 | Streaming overhaul: keepalive, progress events, owned handles, pool events, callback orphan observability |
| 0.1.x | Initial commercial binary releases, worker hardening, app bundle fixes, shared buffer support |
License: AGPL-3.0, free Small Organization Commercial Grant, or written commercial license. See LICENSE.