Different things entirely. Just has the same name to match the XState web API. I considered renaming them agent for the Swift API since I figured people would ask about this, and hey it's software so we could still refactor it maybe if it's a problem for anyone.
But the README on the repo explains it (pasted the relevant section below).
The below partial diagram of the SwiftXChess sample app shows the role of a Swift actor as a network handler in our system, in which InspectBridgeState (magenta dashed box) is a Swift concurrency actor specifically because it's the serial interface to the network when we stream JSON events and state snapshots over the websocket for live visualization/debugging/logging etc.
Concurrency: SwiftXState Actor vs Swift actor
This distinction matters everywhere in the docs and samples — including SwiftXChess.
What is a SwiftXState Actor?
SwiftXState.Actor is a reference-type interpreter (final class) that runs a StateMachine configuration. It:
- Owns a mailbox of events processed on an internal serial
DispatchQueue
- Maintains a
MachineSnapshot (value, context, tags, children, history)
- Spawns and supervises child actors via
invoke / spawnChild
- Schedules delayed transitions and raises via a pluggable
Clock
- Emits inspection events compatible with Stately Inspector
let actor = createActor(machine).start()
actor.send(Event("SUBMIT"))
let snap = actor.snapshot
Naming matches XState v5's createActor on purpose. A SwiftXState Actor is the unit of behavior — the running state machine process.
What is a Swift actor?
A Swift actor is a language-level concurrency primitive: the compiler enforces isolated mutable state, and callers must await cross-actor access. It is unrelated to the XState actor model except in name.
actor SessionStore {
var sessions: [String: ReplaySession] = [:]
func save(_ session: ReplaySession) { sessions[session.id] = session }
}
How SwiftXState uses Swift concurrency today
SwiftXState does not implement the interpreter as a Swift actor. Instead, it uses Swift concurrency inside child actor logic:
| XState concept |
SwiftXState API |
Concurrency |
fromPromise |
fromTask |
async throws child runs in a Task |
fromCallback |
fromCallback |
receive, sendBack, emit; sync setup + dispose cleanup |
| — |
fromTaskGroup |
withThrowingTaskGroup for parallel child work |
| Observable |
fromObservable |
Subscribable + async delivery |
The parent Actor stays on its serial queue. Async children report back via sendToParent, DoneActorEvent, ErrorActorEvent, and optional onSnapshot sync. That keeps transition logic deterministic while still embracing async/await for I/O.
Cancellation, cleanup, and restore policy
Task and task-group children are wrapped in withTaskCancellationHandler. Pass an onCancel closure to fromTask / fromTaskGroup to flush SwiftData writes, delete partial batches, or checkpoint before the child tears down:
fromTask(onCancel: { scope in
await store.deletePendingBatch(scope.input?.get(String.self))
}) { scope in
for job in jobs {
try scope.checkCancellation() // or: if scope.isCancelled { return }
await store.write(job)
}
return jobs.count
}
TaskActorScope and TaskGroupScope also expose isCancelled, checkCancellation(), and withCancellationHandler for nested cleanup inside long operations.
When hydrating from a persisted snapshot, opaque invokes default to restart (fresh child). Set opaqueRestorePolicy on InvokeConfig or SpawnRef to defer auto-spawn until your entry logic reconciles external stores:
| Policy |
Behavior on start(from:) |
.restart (default) |
Spawn a new task/callback/taskGroup child |
.skipIfActive |
Skip spawn if persisted opaque child was .active |
.skipIfPresent |
Skip spawn whenever any opaque child snapshot exists |
Pair .skipIfActive with entry actions that read SwiftData, clear or resume partial work, then transition or manually re-invoke.
Anticipated role of Swift actor in SwiftXState apps
Swift actor is a complementary tool, not a replacement for SwiftXState.Actor:
-
App shell and bridges — A Swift actor can own UI-adjacent or cross-boundary state (network clients, BLE, Core Data facades, C++ game engines bridged through Swift) and send Eventable values into a SwiftXState Actor from fromCallback or fromTask children.
-
Persistence and replay services — ReplayPersistenceStore-style services may be modeled as Swift actors to serialize disk access while the machine interpreter handles domain transitions.
-
Future interpreter isolation — We may offer an optional Swift-actor-backed mailbox implementation behind the same Actor API for apps that want compiler-checked isolation instead of DispatchQueue. The public XState-shaped API would remain stable.
-
Not planned: renaming Actor — Consistency with XState and Stately Inspector outweighs avoiding the keyword collision. Documentation and type context (SwiftXState.Actor) make the distinction clear.
Rule of thumb: use SwiftXState.Actor for orchestration and statecharts; use Swift actor for resource ownership and async isolation at the edges; connect them with invoke / fromTask / fromCallback.