Skip to main content
The base ChappieSDK product handles auth, transport, streaming, and host-tool execution. When you need conversations to survive app launches — so users can return to a thread they started yesterday — add the optional ChappieSDKRuntime product. It layers durable thread storage and normalized turn events on top of ChappieClient, keeping the base package lean for apps that have no persistence requirements.

Add ChappieSDKRuntime to Your Target

ChappieSDKRuntime is a separate product in the same Swift package. Link it only to app targets that need persistent storage; never add it to framework or library targets that might be distributed independently.
1

Open Package Dependencies

In Xcode, go to File → Add Package Dependencies… and enter the Chappie SDK repository URL:
https://github.com/b-nnett/chappie-sdk.git
2

Add ChappieSDKRuntime to your app target

When Xcode shows the product list, tick ChappieSDKRuntime in addition to ChappieSDK. Both products must be linked to the same app target.In a Package.swift manifest, the dependency looks like this:
.package(url: "https://github.com/b-nnett/chappie-sdk.git", from: "0.1.0")
Then add both products to your target’s dependencies array:
.product(name: "ChappieSDK", package: "chappie-sdk"),
.product(name: "ChappieSDKRuntime", package: "chappie-sdk"),
3

Import both modules

At the top of any file that creates or uses a thread store, import both modules:
import ChappieSDK
import ChappieSDKRuntime

Basic Setup

After importing both modules, create a store, attach it to a runtime, and start sending messages. The runtime records every turn automatically — no extra calls required.
import ChappieSDK
import ChappieSDKRuntime

let store = ChappieFileThreadStore()
let runtime = Chappie.client().runtime(store: store)

let reply = try await runtime.send("Summarize this project.")
let threads = try await runtime.listThreads()
let usage = try await store.usage()
runtime.send(_:) behaves like client.send(_:) but persists the full turn to the store before returning. listThreads() returns the active (non-archived) threads sorted by recency. store.usage() reports how many bytes the store is currently using against the configured cap.

Choosing a Store

Chappie ships two store implementations. Pick the one that matches your app’s needs.

ChappieFileThreadStore

Persists complete thread JSON to the app’s support directory. Transcripts survive app launches, device restarts, and upgrades. Use this for any production conversation surface.

ChappieInMemoryThreadStore

Keeps threads in memory only. Threads vanish when the process exits. Use this for unit tests, UI tests, and short-lived sessions where disk I/O would add noise.
// Production — survives launches
let store = ChappieFileThreadStore()

// Tests and short-lived sessions
let memoryStore = ChappieInMemoryThreadStore()
Both stores apply identical retention defaults and expose the same ChappieThreadStore protocol. You can swap between them or provide a fully custom implementation without changing any other code.

Default Retention Policy

Both stores apply the same retention defaults out of the box. You do not need to configure anything for the defaults to take effect.
ParameterDefault value
Total stored transcript cap256 MiB
Archive inactive threads after30 days
Delete archived threads afterA further 60 days

Customizing Retention

Pass a ChappieThreadStoreRetentionPolicy to tighten or relax the defaults. All time values are in seconds.
let store = ChappieFileThreadStore(
    retentionPolicy: ChappieThreadStoreRetentionPolicy(
        maximumStoredTranscriptBytes: 512 * 1024 * 1024,
        archiveInactiveAfter: 14 * 24 * 60 * 60,   // 14 days
        deleteArchivedAfter: 45 * 24 * 60 * 60       // 45 days
    )
)
To disable all size and time limits entirely, use the .unlimited preset:
let unlimitedStore = ChappieFileThreadStore(retentionPolicy: .unlimited)
.unlimited stores every thread indefinitely and applies no size cap. Use it only during development or when your app manages its own eviction strategy. Leaving it enabled in production can exhaust the user’s device storage over time.

File Protection on iOS

ChappieFileThreadStore defaults to NSFileProtectionComplete on iOS. This means transcript files are encrypted at rest and inaccessible while the device is locked. That is the right default for most apps. If your app needs to read or write transcripts while the device is locked — for example, a background extension that logs assistant turns during a background task — switch to .completeUntilFirstUserAuthentication:
let backgroundStore = ChappieFileThreadStore(
    storagePolicy: ChappieFileThreadStoreStoragePolicy(
        fileProtection: .completeUntilFirstUserAuthentication
    )
)
Only loosen file protection when your app has a genuine background-access requirement. Keep the default NSFileProtectionComplete for any store that is only ever accessed from the foreground.
On macOS, Chappie relies on the app sandbox and platform filesystem protections rather than a file-protection attribute.

Archived Threads

Threads that have been inactive for longer than archiveInactiveAfter move to an archived state. Archived threads are hidden from listThreads() by default so your chat list UI stays clean. You can still access archived threads in two ways:
// Returns both active and archived threads
let allThreads = try await runtime.listThreads(includeArchived: true)
Resuming an archived thread by ID reactivates it automatically, resetting its inactivity timer.

Backup Exclusion

Transcript directories and JSON files are excluded from iCloud backups by default. This keeps potentially sensitive conversation history off iCloud Drive and avoids bloating the user’s backup quota. You cannot opt back into iCloud backup through the public ChappieFileThreadStoreStoragePolicy API.

Privacy and Transcript Content

ChappieFileThreadStore stores complete thread JSON to disk. That can include user text, assistant text, tool call arguments, tool outputs, raw payloads, metadata, errors, and compaction summaries. The store does not redact any of this content automatically.If your app must not persist certain fields — for example, authentication tokens passed as tool arguments, or personally identifiable information in user messages — redact that data before it reaches the store, or implement a custom type that conforms to ChappieThreadStore and applies your redaction logic.
A custom store that conforms to ChappieThreadStore is the right extension point when you need field-level control over what gets written to disk. The runtime calls the same protocol methods regardless of which concrete store you provide.