LedgeKitDocs
Developer documentation

Record your first request

Record a native Foundation Models response and inspect its span.

1. Add LedgeKit

Add https://github.com/noahtovares/ledgekit-ios to your Xcode project and link the LedgeKit product. See installation for the exact revision and toolchain requirements.

2. Create an app and write key

In the console, create an app with service name my-app. Select its Test environment and create a write key. Supply that key through local configuration. The key selects the app and environment; serviceName must match the app. Read keys cannot upload traces.

3. Record a summary

FirstTrace.swift
import Foundation
import FoundationModels
import LedgeKit

struct SummaryArguments: Codable, Sendable { let text: String }
enum SummaryError: Error { case modelUnavailable }

@available(iOS 27.0, macOS 27.0, *)
func recordSummary(writeKey: String) async throws -> String {
    guard SystemLanguageModel.default.availability == .available else {
        throw SummaryError.modelUnavailable
    }
    let client = try LedgeClient(serviceName: "my-app", writeKey: writeKey)
    let agent = try LedgeAgent(name: "summarizer", version: 1)
    let session = client.session(
        instructions: "Summarize the text in one sentence.",
        agent: agent
    )
    let input = SummaryArguments(text: "A durable outbox saves spans before uploading them.")
    let response = try await session.respond(
        to: "Summarize: \(input.text)",
        recording: .init(input: input)
    )
    let delivery = await client.flush()
    print("Delivered: \(delivery.delivered); pending: \(delivery.pending)")
    return response.content
}

The native response passes through unchanged. This standalone call creates one trace named summarizer, containing one span for the same agent. The adapter finishes the trace on success, failure, or cancellation. Startup and recovery are automatic. Keep one client alive at application scope for repeated calls.

4. Inspect the result

Open Traces in the same app's Test environment. Select summarizer and its span to inspect model input, model output, original application input, agent version, and timing. Full provider capture retains the native transcript.

flush() reports delivery state; a temporary failure leaves the payload pending. See delivery if the trace has not arrived.

Continue with structured responses, grouped traces, or datasets.

On this page