rivetkit-client-swift

from rivet-dev/skills

Generated skill files for Rivet AI integrations

1 stars0 forksUpdated Jan 26, 2026
npx skills add https://github.com/rivet-dev/skills --skill rivetkit-client-swift

SKILL.md

RivetKit Swift Client

Use this skill when building Swift clients that connect to Rivet Actors with RivetKitClient.

Version

RivetKit version: 2.0.42-rc.1

Install

Add the Swift package dependency and import RivetKitClient:

// Package.swift
dependencies: [
    .package(url: "https://github.com/rivet-dev/rivetkit-swift", from: "2.0.0")
]

targets: [
    .target(
        name: "MyApp",
        dependencies: [
            .product(name: "RivetKitClient", package: "rivetkit-swift")
        ]
    )
]

Minimal Client

Endpoint URL

import RivetKitClient

let config = try ClientConfig(
    endpoint: "https://my-namespace:pk_...@api.rivet.dev"
)
let client = RivetKitClient(config: config)

let handle = client.getOrCreate("counter", ["my-counter"])
let count: Int = try await handle.action("increment", 1, as: Int.self)

Explicit Fields

import RivetKitClient

let config = try ClientConfig(
    endpoint: "https://api.rivet.dev",
    namespace: "my-namespace",
    token: "pk_..."
)
let client = RivetKitClient(config: config)

let handle = client.getOrCreate("counter", ["my-counter"])
let count: Int = try await handle.action("increment", 1, as: Int.self)

Stateless vs Stateful

import RivetKitClient

let config = try ClientConfig(endpoint: "http://localhost:3000/api/rivet")
let client = RivetKitClient(config: config)

let handle = client.getOrCreate("counter", ["my-counter"])

// Stateless: each call is independent
let current: Int = try await handle.action("getCount", as: Int.self)
print("Current count: \(current)")

// Stateful: keep a connection open for realtime events
let conn = handle.connect()

// Subscribe to events using AsyncStream
let eventTask = Task {
    for await count in await conn.events("count", as: Int.self) {
        print("Event: \(count)")
    }
}

_ = try await conn.action("increment", 1, as: Int.self)

eventTask.cancel()
await conn.dispose()
await client.dispose()

Getting Actors

import RivetKitClient

struct GameInput: Encodable {
    let mode: String
}

let config = try ClientConfig(endpoint: "http://localhost:3000/api/rivet")
let client = RivetKitClient(config: config)

// Get or create an actor
let room = client.getOrCreate("chatRoom", ["room-42"])

// Get an existing actor (fails if not found)
let existing = client.get("chatRoom", ["room-42"])

// Create a new actor with input
let created = try await client.create(
    "game",
    ["game-1"],
    options: CreateOptions(input: GameInput(mode: "ranked"))
)

// Get actor by ID
let byId = client.getForId("chatRoom", "actor-id")

// Resolve actor ID
let resolvedId = try await room.resolve()
print("Resolved ID: \(resolvedId)")

await client.dispose()

Actions support positional overloads for 0–5 args:

import RivetKitClient

let config = try ClientConfig(endpoint: "http://localhost:3000/api/rivet")
let client = RivetKitClient(config: config)
let handle = client.getOrCreate("counter", ["my-counter"])

let count: Int = try await handle.action("getCount")
let updated: String = try await handle.action("rename", "new-name")
let ok: Bool = try await handle.action("setScore", "user-1", 42)

print("Count: \(count), Updated: \(updated), OK: \(ok)")
await client.dispose()

If you need more than 5 arguments, use the raw JSON fallback:

import RivetKitClient

let config = try ClientConfig(endpoint: "http://localhost:3000/api/rivet")
let client = RivetKitClient(config: config)
let handle = client.getOrCreate("counter", ["my-counter"])

let args: [JSONValue] = [
    .string("user-1"),
    .number(.int(42)),
    .string("extra"),
    .string("more"),
    .string("args"),
    .string("here")
]
let ok: Bool = try await handle.action("setScore", args: args, as: Bool.self)
print("OK: \(ok)")

await client.dispose()

Connection Parameters

import RivetKitClient

struct ConnParams: Encodable {
    let authToken: String
}

let config = try ClientConfig(endpoint: "http://localhost:3000/api/rivet")
let client = RivetKitClient(config: config)

let chat = client.getOrCreate(
    "chatRoom",
    ["general"],
    options: GetOrCreateOptions(params: ConnParams(authToken: "jwt-token-here"))
)

let conn = chat.connect()

// Use the connection...
for await status in await conn.statusChanges() {
    print("Status: \(status.rawValue)")
    if status == .connected {
        break
    }
}

await conn.dispose()
await client.dispose()

Subscribing to Events

import RivetKitClient

let config = try ClientConfig(endpoint: "http://localhost:3000/api/rivet")
let client = RivetKitClient(config: config)
let conn = client.getOrCreate("chatRoom", ["general"]).connect()

// Subscribe to events using AsyncStream
let messageTask = Task {
    for await (from, body) in await conn.events("message", as: (String, String).self) {
        print("\(from): \(body)")
    }
}

// For one-time events, break after receiving
let gameOverTask = Task {
    for a

...
Read full content

Repository Stats

Stars1
Forks0