Go to production

A prototype puts a provider key in the app. A shipped app must not — keys are extractable from any binary. In production you name an agent profile, and AgentKit Cloud resolves the provider, model, system prompt, and tool schemas server-side.

One line changes

.backendRouterCloud(
    endpoint: URL(string: "https://api.agkit.cloud/v1/agent/stream")!,
    agentId: "video-editor",
    tier: "pro",
    maxOutputTokens: 2048,            // a ceiling you propose; the cloud clamps it
    publishableKey: "ak_pk_live_…",   // public app identifier — safe to embed
    userToken: endUserJWT             // the real auth: a short-lived signed JWT
)

Your domains, guards, and UI don't change. Tools still execute on-device — the backend never touches your app state.

Why a profile, not a key

  • No app update to change models. A new model, or switching providers for cost, is a server-side profile change. The app never knew which model it was using.
  • Many agents per project. agentId selects the use case (video-editor gets a top model, assembler a cheaper one); tier selects the capability level per user (pro vs free). The pair resolves to a model in the cloud.
  • No secrets in the binary. The publishable key is a public identifier, like a Stripe pk_. The only credential that authorizes a request is the short-lived user JWT, verified by signature server-side.

The JWT comes from an issuer the cloud trusts for your project — Sign in with Apple, Firebase Auth, or your own backend. For per-request token refresh and App Attest, use the signer: overload. Both are covered in AgentKit Cloud.

Keep an offline path

The on-device model runs behind the same domains with no key and no network (it requires macOS 26+ / iOS 26+ / visionOS 26+, so the branch carries an availability check). A common pattern is to branch once and leave everything else untouched:

let provider: AgentProviderSpec
if !isOnline, #available(macOS 26.0, iOS 26.0, visionOS 26.0, *) {
    provider = .appleFoundationModels()
} else {
    provider = .backendRouterCloud(endpoint: endpoint, agentId: "editor", tier: tier,
                                   maxOutputTokens: 2048,
                                   publishableKey: publishableKey, userToken: jwt)
}

See on-device with Apple for what the small model can and can't do.

The checklist

  • Switch the provider line to .backendRouterCloud(...) — no provider key, no model name in the app.
  • Define each (agentId, tier) profile in the cloud. Your executors must cover the tool names those profiles enable.
  • Mint a short-lived end-user JWT from a trusted issuer; embed only the publishable key.
  • Handle typed cloud errors with their retry guidance — see when it fails.
  • Keep an on-device fallback behind the same domains if your app should work offline.