WH

whatcable-macos-usb-inspector

Analyze and decode your USB-C cable data on macOS.

Install

mkdir -p .claude/skills/whatcable-macos-usb-inspector && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/16224" && unzip -o skill.zip -d .claude/skills/whatcable-macos-usb-inspector && rm skill.zip

Installs to .claude/skills/whatcable-macos-usb-inspector

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

macOS menu bar app that identifies USB-C cable capabilities and charging diagnostics using IOKit
96 charsno explicit “when” trigger
Advanced

Key capabilities

  • Identify USB-C cable capabilities using IOKit
  • Decode USB Power Delivery VDOs for speed and current
  • Provide plain-English summaries of port diagnostics
  • Build distributable universal macOS applications
  • Inspect IOKit properties live for troubleshooting

How it works

The skill describes a macOS menu bar app that reads IOKit services to identify USB-C cable capabilities. It decodes PD VDOs and provides plain-English summaries of port diagnostics.

Inputs & outputs

You give it
USB-C cable connected to a Mac
You get back
plain-English description of cable capabilities, charging diagnostics, and raw IOKit properties

When to use whatcable-macos-usb-inspector

  • Decode usb-c cable info
  • Read iokit port data
  • Identify charging profile
  • Check cable speed

About this skill

WhatCable macOS USB-C Inspector

Skill by ara.so — Daily 2026 Skills collection.

WhatCable is a macOS 14+ menu bar app (Swift/SwiftUI) that reads IOKit services to surface what each USB-C cable plugged into your Mac can actually do — speed, power rating, e-marker data, PDO profiles, and connected device identity — in plain English.

Project Structure

Sources/WhatCable/
├── WhatCableApp.swift          # App entry point, menu bar setup
├── ContentView.swift           # Main popover UI
├── PortSummary.swift           # Plain-English logic per port
├── PDVDO.swift                 # PD VDO bit-twiddling / spec decoding
├── IOKitReader.swift           # IOKit service queries
└── ...
scripts/
└── build-app.sh                # Universal binary + notarisation

Install / Build

# Run locally (development)
swift run WhatCable

# Build distributable universal app (arm64 + x86_64)
./scripts/build-app.sh
# → dist/WhatCable.app
# → dist/WhatCable.zip

Requires Swift 5.9 / Xcode 15+, macOS 14 (Sonoma) or later.

Signed + Notarised Build

cp .env.example .env
# Edit .env:
# DEVELOPER_ID="Developer ID Application: Your Name (TEAMID)"
# NOTARY_PROFILE="WhatCable-notary"

# Store notarytool credentials once
xcrun notarytool store-credentials "WhatCable-notary" \
    --apple-id "$APPLE_ID" \
    --team-id "$TEAM_ID" \
    --password "$APP_SPECIFIC_PASSWORD"

./scripts/build-app.sh

Key Concepts

IOKit Service Families

ServicePurpose
AppleHPMInterfaceType10/11/12 (M3+)Per-port state, transports, plug orientation, e-marker presence
AppleTCControllerType10 (M1/M2)Same, older HPM interface
IOPortFeaturePowerSourceFull PDO list + live negotiated PDO
IOPortTransportComponentCCUSBPDSOPPD Discover Identity VDOs (SOP = partner, SOP' = cable e-marker)

USB PD VDO Decoding (PDVDO.swift)

The core bit-twiddling follows USB Power Delivery 3.x spec. Cable e-marker VDOs encode speed and current in specific bit fields.

// Example: decode cable speed from Passive Cable VDO
struct PassiveCableVDO {
    let raw: UInt32

    // Bits [5:3] — USB SuperSpeed signalling support
    var usbSSSignalling: UInt8 {
        UInt8((raw >> 3) & 0b111)
    }

    var dataRate: String {
        switch usbSSSignalling {
        case 0b000: return "USB 2.0 only"
        case 0b001: return "USB 3.2 Gen 1 (5 Gbps)"
        case 0b010: return "USB 3.2 Gen 2 (10 Gbps)"
        case 0b011: return "USB 3.2 Gen 2x2 / USB4 Gen 2 (20 Gbps)"
        case 0b100: return "USB4 Gen 3 (40 Gbps)"
        default:    return "Unknown"
        }
    }

    // Bits [6:5] — VBUS current handling
    var currentCapability: String {
        switch (raw >> 5) & 0b11 {
        case 0b00: return "USB Type-C Default (≤3A)"
        case 0b01: return "3A"
        case 0b10: return "5A"
        default:   return "Reserved"
        }
    }
}

Reading IOKit Properties

import IOKit

func readPortProperties(serviceName: String) -> [String: Any]? {
    var iterator: io_iterator_t = 0
    let matchDict = IOServiceMatching(serviceName)
    guard IOServiceGetMatchingServices(kIOMainPortDefault,
                                       matchDict, &iterator) == KERN_SUCCESS else {
        return nil
    }
    defer { IOObjectRelease(iterator) }

    var service = IOIteratorNext(iterator)
    var results: [String: Any] = [:]
    while service != 0 {
        defer {
            IOObjectRelease(service)
            service = IOIteratorNext(iterator)
        }
        if let props = copyProperties(service) {
            results.merge(props) { _, new in new }
        }
    }
    return results.isEmpty ? nil : results
}

private func copyProperties(_ service: io_service_t) -> [String: Any]? {
    var propsRef: Unmanaged<CFMutableDictionary>?
    guard IORegistryEntryCreateCFProperties(service, &propsRef,
                                             kCFAllocatorDefault, 0) == KERN_SUCCESS,
          let props = propsRef?.takeRetainedValue() as? [String: Any] else {
        return nil
    }
    return props
}

Port Summary Plain-English Logic (PortSummary.swift)

enum PortHeadline: String {
    case thunderbolt    = "Thunderbolt / USB4"
    case usbDevice      = "USB device connected"
    case chargingOnly   = "Charging only"
    case slowCable      = "Slow USB / charge-only cable"
    case nothing        = "Nothing connected"
}

struct PortSummary {
    let headline: PortHeadline
    let chargingDiagnostic: String?
    let dataRate: String?
    let currentRating: String?
    let negotiatedPDO: PDO?
    let allPDOs: [PDO]

    static func from(ioKitProps: [String: Any]) -> PortSummary {
        let hasThunderbolt = ioKitProps["Thunderbolt"] as? Bool ?? false
        let hasUSB3       = ioKitProps["USB3"] as? Bool ?? false
        let isConnected   = ioKitProps["Connected"] as? Bool ?? false
        let emarkerPresent = ioKitProps["CableEMarker"] as? Bool ?? false

        let headline: PortHeadline
        if !isConnected {
            headline = .nothing
        } else if hasThunderbolt {
            headline = .thunderbolt
        } else if hasUSB3 {
            headline = .usbDevice
        } else if emarkerPresent {
            headline = .chargingOnly
        } else {
            headline = .slowCable
        }

        // Parse PDOs for charging diagnostic
        let pdos = parsePDOs(from: ioKitProps)
        let negotiated = pdos.first(where: { $0.isActive })
        let diagnostic = buildChargingDiagnostic(pdos: pdos, negotiated: negotiated)

        return PortSummary(
            headline: headline,
            chargingDiagnostic: diagnostic,
            dataRate: emarkerPresent ? decodeDataRate(ioKitProps) : nil,
            currentRating: emarkerPresent ? decodeCurrentRating(ioKitProps) : nil,
            negotiatedPDO: negotiated,
            allPDOs: pdos
        )
    }
}

PDO Parsing (Power Data Objects)

struct PDO {
    let voltage: Double    // Volts
    let maxCurrent: Double // Amps
    let maxWatts: Double   // voltage * maxCurrent
    let isActive: Bool

    static func parse(raw: UInt32, isActive: Bool) -> PDO? {
        // Fixed supply PDO: bits [19:10] = max current (10mA units),
        //                   bits [29:20] = voltage (50mV units)
        let currentRaw = (raw >> 10) & 0x3FF
        let voltageRaw = (raw >> 20) & 0x3FF
        guard voltageRaw > 0 else { return nil }

        let voltage = Double(voltageRaw) * 0.05
        let current = Double(currentRaw) * 0.01
        return PDO(
            voltage: voltage,
            maxCurrent: current,
            maxWatts: voltage * current,
            isActive: isActive
        )
    }
}

func parsePDOs(from props: [String: Any]) -> [PDO] {
    guard let pdoArray = props["PDOs"] as? [UInt32],
          let activePDOIndex = props["ActivePDOIndex"] as? Int else {
        return []
    }
    return pdoArray.enumerated().compactMap { idx, raw in
        PDO.parse(raw: raw, isActive: idx == activePDOIndex)
    }
}

SwiftUI Popover Pattern (ContentView.swift)

import SwiftUI

struct ContentView: View {
    @StateObject private var model = CableModel()

    var body: some View {
        VStack(alignment: .leading, spacing: 0) {
            HeaderView()
            Divider()
            ScrollView {
                VStack(alignment: .leading, spacing: 12) {
                    ForEach(model.ports) { port in
                        PortRowView(port: port)
                    }
                }
                .padding()
            }
        }
        .frame(width: 360)
        .onAppear { model.refresh() }
    }
}

struct PortRowView: View {
    let port: PortSummary

    var body: some View {
        VStack(alignment: .leading, spacing: 4) {
            Label(port.headline.rawValue, systemImage: iconName(for: port.headline))
                .font(.headline)

            if let diagnostic = port.chargingDiagnostic {
                Text(diagnostic)
                    .font(.subheadline)
                    .foregroundStyle(.secondary)
            }

            if let rate = port.dataRate {
                Text("Speed: \(rate)")
                    .font(.caption)
            }
        }
        .padding(.vertical, 6)
    }

    func iconName(for headline: PortHeadline) -> String {
        switch headline {
        case .thunderbolt:  return "bolt.fill"
        case .usbDevice:    return "cable.connector"
        case .chargingOnly: return "battery.100.bolt"
        case .slowCable:    return "exclamationmark.triangle"
        case .nothing:      return "circle.dashed"
        }
    }
}

Menu Bar App Setup (WhatCableApp.swift)

import SwiftUI

@main
struct WhatCableApp: App {
    @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    var body: some Scene {
        // No WindowGroup — pure menu bar app
        Settings { SettingsView() }
    }
}

class AppDelegate: NSObject, NSApplicationDelegate {
    var statusItem: NSStatusItem?
    var popover = NSPopover()

    func applicationDidFinishLaunching(_ notification: Notification) {
        NSApp.setActivationPolicy(.accessory) // hide from Dock by default

        statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
        if let button = statusItem?.button {
            button.image = NSImage(systemSymbolName: "cable.connector",
                                   accessibilityDescription: "WhatCable")
            button.action = #selector(togglePopover)
            button.sendAction(on: [.leftMouseUp, .rightMouseUp])
        }

        popover.contentViewController = NSHostingController(rootView: ContentView())
        popover.behavior = .transient
    }

    @objc func togglePopover(_ sender: NSStatusBarButton) {
        if popover.isShown {
            popover.performClose(sender)
        } else {
            if let 

---

*Content truncated.*

When not to use it

  • When working with operating systems other than macOS 14+
  • When not using Swift/SwiftUI for application development

Prerequisites

Swift 5.9 / Xcode 15+macOS 14 (Sonoma) or later

Limitations

  • Requires macOS 14 (Sonoma) or later
  • E-marker data may be missing for cables < 60W
  • Build requires Swift 5.9 / Xcode 15+

How it compares

This skill details a specific macOS application that uses IOKit to inspect USB-C cable capabilities and power delivery, offering a specialized diagnostic tool for hardware, unlike general system information utilities.

Compared to similar skills

whatcable-macos-usb-inspector side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
whatcable-macos-usb-inspector (this skill)03moReviewAdvanced
build-iphone-apps148moReviewAdvanced
mobile-games116moNo flagsIntermediate
instruments-profiling32moNo flagsAdvanced

Try saying

Example prompts that trigger this skill in your AI assistant.

You might also like

build-iphone-apps

glittercowboy

Build professional native iPhone apps in Swift with SwiftUI and UIKit. Full lifecycle - build, debug, test, optimize, ship. CLI-only, no Xcode. Targets iOS 26 with iOS 18 compatibility.

1483

mobile-games

davila7

Mobile game development principles. Touch input, battery, performance, app stores.

1158

instruments-profiling

steipete

Use when profiling native macOS or iOS apps with Instruments/xctrace. Covers correct binary selection, CLI arguments, exports, and common gotchas.

327

perf-optimizer

OneKeyHQ

Systematic performance optimization and regression debugging for OneKey mobile app (iOS). Use when: (1) Fixing performance regressions - when metrics like tokensStartMs, tokensSpanMs, or functionCallCount have regressed and need to be brought back to normal levels, (2) Improving baseline performance - when there's a need to optimize cold start time or reduce function call overhead, (3) User requests performance optimization/improvement/debugging for the app's startup or home screen refresh flow.

513

macos-spm-app-packaging

Dimillian

Scaffold, build, and package SwiftPM-based macOS apps without an Xcode project. Use when you need a from-scratch macOS app layout, SwiftPM targets/resources, a custom .app bundle assembly script, or signing/notarization/appcast steps outside Xcode.

17

swiftui-performance-developer

anyproto

Audit and improve SwiftUI runtime performance through code review and Instruments guidance. Use for diagnosing slow rendering, janky scrolling, excessive view updates, or layout thrash in SwiftUI apps.

16

Search skills

Search the agent skills registry