Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Build VoIP calling apps on iOS using Telnyx WebRTC SDK. Covers authentication, making/receiving calls, CallKit integration, PushKit/APNS push notifications, call quality metrics, and AI Agent integration. Use when implementing real-time voice communication on iOS.
.claude/skills/team-telnyx-telnyx-webrtc-client-ios/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 216% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 398% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 363% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 388% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 617% | 0% |
Build real-time voice communication into iOS applications using Telnyx WebRTC.
> Prerequisites: Create WebRTC credentials and generate a login token using the Telnyx server-side SDK. See the telnyx-webrtc-* skill in your server language plugin (e.g., telnyx-python, telnyx-javascript).
rubypod 'TelnyxRTC', '~> 0.1.0'
Then run:
bashpod install --repo-update
https://github.com/team-telnyx/telnyx-webrtc-ios.gitmain branchInfo.plist:xml <key>NSMicrophoneUsageDescription</key> <string>Microphone access required for VoIP calls</string>
swiftimport TelnyxRTC let telnyxClient = TxClient() telnyxClient.delegate = self let txConfig = TxConfig( sipUser: "your_sip_username", password: "your_sip_password", pushDeviceToken: "DEVICE_APNS_TOKEN", ringtone: "incoming_call.mp3", ringBackTone: "ringback_tone.mp3", logLevel: .all ) do { try telnyxClient.connect(txConfig: txConfig) } catch { print("Connection error: \(error)") }
swiftlet txConfig = TxConfig( token: "your_jwt_token", pushDeviceToken: "DEVICE_APNS_TOKEN", ringtone: "incoming_call.mp3", ringBackTone: "ringback_tone.mp3", logLevel: .all ) try telnyxClient.connect(txConfig: txConfig)
| Parameter | Type | Description | |-----------|------|-------------| | sipUser / token | String | Credentials from Telnyx Portal | | password | String | SIP password (credential auth) | | pushDeviceToken | String? | APNS VoIP push token | | ringtone | String? | Audio file for incoming calls | | ringBackTone | String? | Audio file for ringback | | logLevel | LogLevel | .none, .error, .warning, .debug, .info, .all | | forceRelayCandidate | Bool | Force TURN relay (avoid local network) |
swiftlet serverConfig = TxServerConfiguration( environment: .production, region: .usEast // .auto, .usEast, .usCentral, .usWest, .caCentral, .eu, .apac ) try telnyxClient.connect(txConfig: txConfig, serverConfiguration: serverConfig)
Implement TxClientDelegate to receive events:
swiftextension ViewController: TxClientDelegate { func onSocketConnected() { // Connected to Telnyx backend } func onSocketDisconnected() { // Disconnected from backend } func onClientReady() { // Ready to make/receive calls } func onClientError(error: Error) { // Handle error } func onIncomingCall(call: Call) { // Incoming call while app is in foreground self.currentCall = call } func onPushCall(call: Call) { // Incoming call from push notification self.currentCall = call } func onCallStateUpdated(callState: CallState, callId: UUID) { switch callState { case .CONNECTING: break case .RINGING: break case .ACTIVE: break case .HELD: break case .DONE(let reason): if let reason = reason { print("Call ended: \(reason.cause ?? "Unknown")") print("SIP: \(reason.sipCode ?? 0) \(reason.sipReason ?? "")") } case .RECONNECTING(let reason): print("Reconnecting: \(reason.rawValue)") case .DROPPED(let reason): print("Dropped: \(reason.rawValue)") } } }
swiftlet call = try telnyxClient.newCall( callerName: "John Doe", callerNumber: "+15551234567", destinationNumber: "+18004377950", callId: UUID() )
swiftfunc onIncomingCall(call: Call) { // Store reference and show UI self.currentCall = call // Answer the call call.answer() }
swift// End call call.hangup() // Mute/Unmute call.muteAudio() call.unmuteAudio() // Hold/Unhold call.hold() call.unhold() // Send DTMF call.dtmf(digit: "1") // Toggle speaker // (Use AVAudioSession for speaker routing)
swiftimport PushKit class AppDelegate: UIResponder, UIApplicationDelegate, PKPushRegistryDelegate { private var pushRegistry = PKPushRegistry(queue: .main) func initPushKit() { pushRegistry.delegate = self pushRegistry.desiredPushTypes = [.voIP] } func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) { if type == .voIP { let token = credentials.token.map { String(format: "%02X", $0) }.joined() // Save token for use in TxConfig } } func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) { if type == .voIP { handleVoIPPush(payload: payload) } completion() } }
swiftfunc handleVoIPPush(payload: PKPushPayload) { guard let metadata = payload.dictionaryPayload["metadata"] as? [String: Any] else { return } let callId = metadata["call_id"] as? String ?? UUID().uuidString let callerName = (metadata["caller_name"] as? String) ?? "" let callerNumber = (metadata["caller_number"] as? String) ?? "" // Reconnect client and process push let txConfig = TxConfig(sipUser: sipUser, password: password, pushDeviceToken: token) try? telnyxClient.processVoIPNotification( txConfig: txConfig, serverConfiguration: serverConfig, pushMetaData: metadata ) // Report to CallKit (REQUIRED on iOS 13+) let callHandle = CXHandle(type: .generic, value: callerNumber) let callUpdate = CXCallUpdate() callUpdate.remoteHandle = callHandle provider.reportNewIncomingCall(with: UUID(uuidString: callId)!, update: callUpdate) { error in if let error = error { print("Failed to report call: \(error)") } } }
swiftimport CallKit class AppDelegate: CXProviderDelegate { var callKitProvider: CXProvider! func initCallKit() { let config = CXProviderConfiguration(localizedName: "TelnyxRTC") config.maximumCallGroups = 1 config.maximumCallsPerCallGroup = 1 callKitProvider = CXProvider(configuration: config) callKitProvider.setDelegate(self, queue: nil) } // CRITICAL: Audio session handling for WebRTC + CallKit func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) { telnyxClient.enableAudioSession(audioSession: audioSession) } func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) { telnyxClient.disableAudioSession(audioSession: audioSession) } func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) { // Use SDK method to handle race conditions telnyxClient.answerFromCallkit(answerAction: action) } func provider(_ provider: CXProvider, perform action: CXEndCallAction) { telnyxClient.endCallFromCallkit(endAction: action) } }
Enable with debug: true:
swiftlet call = try telnyxClient.newCall( callerName: "John", callerNumber: "+15551234567", destinationNumber: "+18004377950", callId: UUID(), debug: true ) call.onCallQualityChange = { metrics in print("MOS: \(metrics.mos)") print("Jitter: \(metrics.jitter * 1000) ms") print("RTT: \(metrics.rtt * 1000) ms") print("Quality: \(metrics.quality.rawValue)") switch metrics.quality { case .excellent, .good: // Green indicator case .fair: // Yellow indicator case .poor, .bad: // Red indicator case .unknown: // Gray indicator } }
| Quality Level | MOS Range | |---------------|-----------| | .excellent | > 4.2 | | .good | 4.1 - 4.2 | | .fair | 3.7 - 4.0 | | .poor | 3.1 - 3.6 | | .bad | ≤ 3.0 |
swiftclient.anonymousLogin( targetId: "your-ai-assistant-id", targetType: "ai_assistant" )
swift// After anonymous login, destination is ignored let call = client.newInvite( callerName: "User", callerNumber: "user", destinationNumber: "ai-assistant", // Ignored callId: UUID() )
swiftlet cancellable = client.aiAssistantManager.subscribeToTranscriptUpdates { transcripts in for item in transcripts { print("\(item.role): \(item.content)") // role: "user" or "assistant" } }
swiftlet success = client.sendAIAssistantMessage("Hello, can you help me?")
swiftclass MyLogger: TxLogger { func log(level: LogLevel, message: String) { // Send to your logging service MyAnalytics.log(level: level, message: message) } } let txConfig = TxConfig( sipUser: sipUser, password: password, logLevel: .all, customLogger: MyLogger() )
| Issue | Solution | |-------|----------| | No audio | Ensure microphone permission granted | | Push not working | Verify APNS certificate in Telnyx Portal | | CallKit crash on iOS 13+ | Must report incoming call to CallKit | | Audio routing issues | Use enableAudioSession/disableAudioSession in CXProviderDelegate | | Login fails | Verify SIP credentials in Telnyx Portal |
<!-- BEGIN AUTO-GENERATED API REFERENCE -- do not edit below this line -->
references/webrtc-server-api.md has the server-side WebRTC API — credential creation, token generation, and push notification setup. You MUST read it when setting up authentication or push notifications.
CLASS
TxClientswiftpublic class TxClient
The TelnyxRTC client connects your application to the Telnyx backend, enabling you to make outgoing calls and handle incoming calls.
// Initialize the client
extension ViewController: TxClientDelegate {
enableAudioSession(audioSession:)swiftpublic func enableAudioSession(audioSession: AVAudioSession)
Enables and configures the audio session for a call. This method sets up the appropriate audio configuration and activates the session.
provider(_:didActivate:) callbackto properly handle audio routing when using CallKit integration.
Example usage:
swiftfunc provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) { print("provider:didActivateAudioSession:") self.telnyxClient.enableAudioSession(audioSession: audioSession) }
Parameters
| Name | Description | | ---- | ----------- | | audioSession | The AVAudioSession instance to configure |
disableAudioSession(audioSession:)swiftpublic func disableAudioSession(audioSession: AVAudioSession)
Disables and resets the audio session. This method cleans up the audio configuration and deactivates the session.
provider(_:didDeactivate:) callbackto properly clean up audio resources when using CallKit integration.
Example usage:
swiftfunc provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) { print("provider:didDeactivateAudioSession:") self.telnyxClient.disableAudioSession(audioSession: audioSession) }
Parameters
| Name | Description | | ---- | ----------- | | audioSession | The AVAudioSession instance to reset |
init()swiftpublic init()
TxClient has to be instantiated.
deinitswiftdeinit
Deinitializer to ensure proper cleanup of resources
connect(txConfig:serverConfiguration:)swiftpublic func connect(txConfig: TxConfig, serverConfiguration: TxServerConfiguration = TxServerConfiguration()) throws
Connects to the iOS cloglient to the Telnyx signaling server using the desired login credentials.
signaling server and TURN/ STUN servers. As default we use the internal Telnyx Production servers.Parameters
| Name | Description | | ---- | ----------- | | txConfig | The desired login credentials. See TxConfig docummentation for more information. | | serverConfiguration | (Optional) To define a custom signaling server and TURN/ STUN servers. As default we use the internal Telnyx Production servers. |
disconnect()swiftpublic func disconnect()
Disconnects the TxClient from the Telnyx signaling server.
isConnected()swiftpublic func isConnected() -> Bool
To check if TxClient is connected to Telnyx server.
true if TxClient socket is connected, false otherwise.answerFromCallkit(answerAction:customHeaders:debug:)swiftpublic func answerFromCallkit(answerAction: CXAnswerCallAction, customHeaders: [String:String] = [:], debug: Bool = false)
Answers an incoming call from CallKit and manages the active call flow.
This method should be called from the CXProviderDelegate's provider(_:perform:) method when handling a CXAnswerCallAction. It properly integrates with CallKit to answer incoming calls.
extension CallKitProvider: CXProviderDelegate {
endCallFromCallkit(endAction:callId:)swiftpublic func endCallFromCallkit(endAction: CXEndCallAction, callId: UUID? = nil)
To end and control callKit active and conn
disablePushNotifications()swiftpublic func disablePushNotifications()
To disable push notifications for the current user
getSessionId()swiftpublic func getSessionId() -> String
Get the current session ID after logging into Telnyx Backend.
anonymousLogin(targetId:targetType:targetVersionId:userVariables:reconnection:serverConfiguration:)swiftpublic func anonymousLogin( targetId: String, targetType: String = "ai_assistant", targetVersionId: String? = nil, userVariables: [String: Any] = [:], reconnection: Bool = false, serverConfiguration: TxServerConfiguration = TxServerConfiguration() )
Performs an anonymous login to the Telnyx backend for AI assistant connections. This method allows connecting to AI assistants without traditional authentication.
If the socket is already connected, the anonymous login message is sent immediately. If not connected, the socket connection process is started, and the anonymous login message is sent once the connection is established.
Parameters
| Name | Description | | ---- | ----------- | | targetId | The target ID for the AI assistant | | targetType | The target type (defaults to “ai_assistant”) | | targetVersionId | Optional target version ID | | userVariables | Optional user variables to include in the login | | reconnection | Whether this is a reconnection attempt (defaults to false) | | serverConfiguration | Server configuration to use for connection (defaults to TxServerConfiguration()) |
sendRingingAck(callId:)swiftpublic func sendRingingAck(callId: String)
Send a ringing acknowledgment message for a specific call
Parameters
| Name | Description | | ---- | ----------- | | callId | The call ID to acknowledge |
sendAIAssistantMessage(_:)swiftpublic func sendAIAssistantMessage(_ message: String) -> Bool
Send a text message to AI Assistant during active call (mixed-mode communication)
Parameters
| Name | Description | | ---- | ----------- | | message | The text message to send to AI assistant |
sendAIAssistantMessage(_:base64Images:imageFormat:)swiftpublic func sendAIAssistantMessage(_ message: String, base64Images: [String]?, imageFormat: String = "jpeg") -> Bool
Send a text message with multiple Base64 encoded images to AI Assistant during active call
Parameters
| Name | Description | | ---- | ----------- | | message | The text message to send to AI assistant | | base64Images | Optional array of Base64 encoded image data (without data URL prefix) | | imageFormat | Image format (jpeg, png, etc.). Defaults to “jpeg” |
CLASS
Callswiftpublic class Call
A Call represents an audio or video communication session between two endpoints: WebRTC Clients, SIP clients, or phone numbers. The Call object manages the entire lifecycle of a call, from initiation to termination, handling both outbound and inbound calls.
A Call object is created in two scenarios:
// Initialize the client
class CallHandler: TxClientDelegate {
swift// Access local audio tracks for visualization if let localStream = call.localStream { let audioTracks = localStream.audioTracks // Use audio tracks for waveform visualization }
remoteStreamswiftpublic var remoteStream: RTCMediaStream?
The remote media stream containing audio and/or video tracks received from the remote party. This stream represents the media being received from the other participant in the call. Can be used for audio visualization, remote video display, or other media processing.
swift// Access remote audio tracks for visualization if let remoteStream = call.remoteStream { let audioTracks = remoteStream.audioTracks // Use audio tracks for waveform visualization }
STRUCT
TxConfigswiftpublic struct TxConfig
This structure is intended to used for Telnyx SDK configurations.
init(sipUser:password:pushDeviceToken:ringtone:ringBackTone:pushEnvironment:logLevel:customLogger:reconnectClient:debug:forceRelayCandidate:enableQualityMetrics:sendWebRTCStatsViaSocket:reconnectTimeOut:useTrickleIce:enableCallReports:callReportInterval:callReportLogLevel:callReportMaxLogEntries:)swiftpublic init(sipUser: String, password: String, pushDeviceToken: String? = nil, ringtone: String? = nil, ringBackTone: String? = nil, pushEnvironment: PushEnvironment? = nil, logLevel: LogLevel = .none, customLogger: TxLogger? = nil, reconnectClient: Bool = true, debug: Bool = false, forceRelayCandidate: Bool = false, enableQualityMetrics: Bool = false, sendWebRTCStatsViaSocket: Bool = false, reconnectTimeOut: Double = DEFAULT_TIMEOUT, useTrickleIce: Bool = false, enableCallReports: Bool = true, callReportInterval: TimeInterval = 5.0, callReportLogLevel: String = "debug", callReportMaxLogEntries: Int = 1000 )
Constructor for the Telnyx SDK configuration using SIP credentials.
.none)Parameters
| Name | Description | | ---- | ----------- | | sipUser | The SIP username for authentication | | password | The password associated with the SIP user | | pushDeviceToken | (Optional) The device’s push notification token, required for receiving inbound call notifications | | ringtone | (Optional) The audio file name to play for incoming calls (e.g., “my-ringtone.mp3”) | | ringBackTone | (Optional) The audio file name to play while making outbound calls (e.g., “my-ringbacktone.mp3”) | | pushEnvironment | (Optional) The push notification environment (production or debug) | | logLevel | (Optional) The verbosity level for SDK logs (defaults to .none) | | customLogger | (Optional) Custom logger implementation for handling SDK logs. If not provided, the default logger will be used | | reconnectClient | (Optional) Whether the client should attempt to reconnect automatically. Default is true. | | debug | (Optional) Enables WebRTC communication statistics reporting to Telnyx servers. Default is false. | | forceRelayCandidate | (Optional) Controls whether the SDK should force TURN relay for peer connections. Default is false. | | enableQualityMetrics | (Optional) Controls whether the SDK should deliver call quality metrics. Default is false. | | sendWebRTCStatsViaSocket | (Optional) Whether to send WebRTC statistics via socket to Telnyx servers. Default is false. | | reconnectTimeOut | (Optional) Maximum time in seconds the SDK will attempt to reconnect a call after network disruption. Default is 60 seconds. | | useTrickleIce | (Optional) Controls whether the SDK should use trickle ICE for WebRTC signaling. Default is false. | | enableCallReports | (Optional) Enable automatic call quality reporting to voice-sdk-proxy. Default is true. | | callReportInterval | (Optional) Interval in seconds for collecting call statistics. Default is 5.0. | | callReportLogLevel | (Optional) Minimum log level to capture for call reports. Default is “debug”. | | callReportMaxLogEntries | (Optional) Maximum number of log entries to buffer per call. Default is 1000. |
init(token:pushDeviceToken:ringtone:ringBackTone:pushEnvironment:logLevel:customLogger:reconnectClient:debug:forceRelayCandidate:enableQualityMetrics:sendWebRTCStatsViaSocket:reconnectTimeOut:useTrickleIce:enableCallReports:callReportInterval:callReportLogLevel:callReportMaxLogEntries:)swiftpublic init(token: String, pushDeviceToken: String? = nil, ringtone: String? = nil, ringBackTone: String? = nil, pushEnvironment: PushEnvironment? = nil, logLevel: LogLevel = .none, customLogger: TxLogger? = nil, reconnectClient: Bool = true, debug: Bool = false, forceRelayCandidate: Bool = false, enableQualityMetrics: Bool = false, sendWebRTCStatsViaSocket: Bool = false, reconnectTimeOut: Double = DEFAULT_TIMEOUT, useTrickleIce: Bool = false, enableCallReports: Bool = true, callReportInterval: TimeInterval = 5.0, callReportLogLevel: String = "debug", callReportMaxLogEntries: Int = 1000 )
Constructor for the Telnyx SDK configuration using JWT token authentication.
.none)Parameters
| Name | Description | | ---- | ----------- | | token | JWT token generated from https://developers.telnyx.com/docs/v2/webrtc/quickstart | | pushDeviceToken | (Optional) The device’s push notification token, required for receiving inbound call notifications | | ringtone | (Optional) The audio file name to play for incoming calls (e.g., “my-ringtone.mp3”) | | ringBackTone | (Optional) The audio file name to play while making outbound calls (e.g., “my-ringbacktone.mp3”) | | pushEnvironment | (Optional) The push notification environment (production or debug) | | logLevel | (Optional) The verbosity level for SDK logs (defaults to .none) | | customLogger | (Optional) Custom logger implementation for handling SDK logs. If not provided, the default logger will be used | | reconnectClient | (Optional) Whether the client should attempt to reconnect automatically. Default is true. | | debug | (Optional) Enables WebRTC communication statistics reporting to Telnyx servers. Default is false. | | forceRelayCandidate | (Optional) Controls whether the SDK should force TURN relay for peer connections. Default is false. | | enableQualityMetrics | (Optional) Controls whether the SDK should deliver call quality metrics. Default is false. | | sendWebRTCStatsViaSocket | (Optional) Whether to send WebRTC statistics via socket to Telnyx servers. Default is false. | | reconnectTimeOut | (Optional) Maximum time in seconds the SDK will attempt to reconnect a call after network disruption. Default is 60 seconds. | | useTrickleIce | (Optional) Controls whether the SDK should use trickle ICE for WebRTC signaling. Default is false. | | enableCallReports | (Optional) Enable automatic call quality reporting to voice-sdk-proxy. Default is true. | | callReportInterval | (Optional) Interval in seconds for collecting call statistics. Default is 5.0. | | callReportLogLevel | (Optional) Minimum log level to capture for call reports. Default is “debug”. | | callReportMaxLogEntries | (Optional) Maximum number of log entries to buffer per call. Default is 1000. |
validateParams()swiftpublic func validateParams() throws
Validate if TxConfig parameters are valid
<!-- END AUTO-GENERATED API REFERENCE -->
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 14,183 | 6,899 | -51% | 1 | 1 | 0% | 2,999 | 9,475 | +216% | 0 | 0 | — |
case-02 | fail→pass | 9,610 | 5,922 | -38% | 1 | 1 | 0% | 1,851 | 9,212 | +398% | 0 | 0 | — |
case-03 | fail→fail | 22,896 | 7,714 | -66% | 1 | 1 | 0% | 5,011 | 9,647 | +93% | 0 | 0 | — |
case-04 | pass→pass | 10,652 | 6,896 | -35% | 1 | 1 | 0% | 1,882 | 9,266 | +392% | 0 | 0 | — |
case-05 | pass→pass | 3,282 | 2,508 | -24% | 1 | 1 | 0% | 578 | 8,354 | +1345% | 0 | 0 | — |
case-06 | fail→fail | 12,092 | 4,353 | -64% | 1 | 1 | 0% | 2,188 | 8,744 | +300% | 0 | 0 | — |
case-07 | pass→pass | 8,952 | 4,077 | -54% | 1 | 1 | 0% | 1,713 | 8,732 | +410% | 0 | 0 | — |
case-08 | fail→pass | 10,814 | 3,305 | -69% | 1 | 1 | 0% | 1,841 | 8,523 | +363% | 0 | 0 | — |
case-09 | fail→pass | 8,742 | 4,792 | -45% | 1 | 1 | 0% | 1,836 | 8,964 | +388% | 0 | 0 | — |
case-10 | pass→pass | 9,318 | 7,705 | -17% | 1 | 1 | 0% | 1,771 | 9,513 | +437% | 0 | 0 | — |
case-11 | fail→pass | 6,037 | 3,782 | -37% | 1 | 1 | 0% | 1,206 | 8,648 | +617% | 0 | 0 | — |
case-12 | pass→pass | 28,055 | 7,536 | -73% | 1 | 1 | 0% | 2,825 | 9,524 | +237% | 0 | 0 | — |
case-13 | pass→pass | 12,891 | 8,339 | -35% | 1 | 1 | 0% | 2,388 | 9,719 | +307% | 0 | 0 | — |
case-14 | fail→pass | 13,196 | 6,277 | -52% | 1 | 1 | 0% | 2,417 | 9,220 | +281% | 0 | 0 | — |
case-15 | fail→pass | 11,667 | 5,150 | -56% | 1 | 1 | 0% | 2,093 | 9,042 | +332% | 0 | 0 | — |
case-16 | fail→pass | 14,162 | 9,731 | -31% | 1 | 1 | 0% | 2,515 | 9,946 | +295% | 0 | 0 | — |
case-17 | fail→pass | 11,757 | 4,194 | -64% | 1 | 1 | 0% | 2,294 | 8,754 | +282% | 0 | 0 | — |
case-18 | fail→pass | 14,982 | 6,911 | -54% | 1 | 1 | 0% | 2,773 | 9,334 | +237% | 0 | 0 | — |
case-19 | fail→pass | 11,114 | 3,047 | -73% | 1 | 1 | 0% | 2,141 | 8,462 | +295% | 0 | 0 | — |
case-20 | fail→pass | 8,579 | 5,079 | -41% | 1 | 1 | 0% | 1,646 | 8,969 | +445% | 0 | 0 | — |
case-21 | fail→pass | 14,347 | 8,960 | -38% | 1 | 1 | 0% | 2,754 | 9,732 | +253% | 0 | 0 | — |
case-22 | fail→fail | 17,650 | 7,793 | -56% | 1 | 1 | 0% | 2,970 | 9,320 | +214% | 0 | 0 | — |
case-23 | fail→fail | 10,828 | 7,342 | -32% | 1 | 1 | 0% | 2,133 | 9,226 | +333% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +57 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.