From apple-kit-skills
Controls smart-home accessories and commissions Matter devices using HomeKit and MatterSupport. Useful for managing homes/rooms/accessories, action sets, triggers, and characteristic reads/writes.
How this skill is triggered — by the user, by Claude, or both
Slash command
/apple-kit-skills:homekitThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Control home automation accessories and commission Matter devices. HomeKit manages
Control home automation accessories and commission Matter devices. HomeKit manages the home/room/accessory model, action sets, and triggers. MatterSupport handles device commissioning into your ecosystem. Targets Swift 6.3 / iOS 26+.
NSHomeKitUsageDescription to Info.plist:<key>NSHomeKitUsageDescription</key>
<string>This app controls your smart home accessories.</string>
For Matter commissioning into your own ecosystem:
MatterAddDeviceExtensionRequestHandler subclassNSBonjourServices entries for _matter._tcp, _matterc._udp, and
_matterd._udpcom.apple.developer.matter.allow-setup-payload only if the caller
supplies a Matter setup payload programmaticallyimport HomeKit
let homeManager = HMHomeManager()
// HomeKit is available on iPhone, iPad, Apple TV, Apple Watch,
// Mac Catalyst, and Vision Pro.
// Authorization is handled through the delegate:
homeManager.delegate = self
HomeKit organizes home automation in a hierarchy:
HMHomeManager
-> HMHome (one or more)
-> HMRoom (rooms in the home)
-> HMAccessory (devices in a room)
-> HMService (functions: light, thermostat, etc.)
-> HMCharacteristic (readable/writable values)
-> HMZone (groups of rooms)
-> HMActionSet (grouped actions)
-> HMTrigger (time or event-based triggers)
Create a single HMHomeManager and implement the delegate to know when
data is loaded. HomeKit loads asynchronously -- do not access homes until
the delegate fires.
import HomeKit
final class HomeStore: NSObject, HMHomeManagerDelegate {
let homeManager = HMHomeManager()
override init() {
super.init()
homeManager.delegate = self
}
func homeManagerDidUpdateHomes(_ manager: HMHomeManager) {
// Safe to access manager.homes now
let homes = manager.homes
let primaryHome = manager.primaryHome
print("Loaded \(homes.count) homes")
}
func homeManager(
_ manager: HMHomeManager,
didUpdate status: HMHomeManagerAuthorizationStatus
) {
if status.contains(.authorized) {
print("HomeKit access granted")
}
}
}
guard let home = homeManager.primaryHome else { return }
let rooms = home.rooms
let kitchen = rooms.first { $0.name == "Kitchen" }
// Room for accessories not assigned to a specific room
let defaultRoom = home.roomForEntireHome()
Use HomeKit and MatterSupport for home-model work: homes, rooms, HMAccessory services and characteristics, action sets, triggers and automations, HomeKit accessory setup UI, and Matter commissioning. If the same request asks about lower-level Bluetooth or Wi-Fi accessory discovery or authorization, name AccessorySetupKit as the boundary for discovery descriptors, picker authorization, ASAccessorySession events, and migration. After AccessorySetupKit setup, explicitly name both post-setup handoff targets: CoreBluetooth/GATT for Bluetooth accessories and NetworkExtension for Wi-Fi accessory network flows; neither handoff is HomeKit automation logic.
// System UI for accessory discovery
home.addAndSetupAccessories { error in
if let error {
print("Setup failed: \(error)")
}
}
for accessory in home.accessories {
print("\(accessory.name) in \(accessory.room?.name ?? "unassigned")")
for service in accessory.services {
print(" Service: \(service.serviceType)")
for characteristic in service.characteristics {
print(" \(characteristic.characteristicType): \(characteristic.value ?? "nil")")
}
}
}
guard let accessory = home.accessories.first,
let bedroom = home.rooms.first(where: { $0.name == "Bedroom" }) else { return }
home.assignAccessory(accessory, to: bedroom) { error in
if let error {
print("Failed to move accessory: \(error)")
}
}
let characteristic: HMCharacteristic = // obtained from a service
characteristic.readValue { error in
guard error == nil else { return }
if let value = characteristic.value as? Bool {
print("Power state: \(value)")
}
}
// Turn on a light
characteristic.writeValue(true) { error in
if let error {
print("Write failed: \(error)")
}
}
Enable notifications for real-time updates:
characteristic.enableNotification(true) { error in
guard error == nil else { return }
}
// In HMAccessoryDelegate:
func accessory(
_ accessory: HMAccessory,
service: HMService,
didUpdateValueFor characteristic: HMCharacteristic
) {
print("Updated: \(characteristic.value ?? "nil")")
}
An HMActionSet groups characteristic writes that execute together:
home.addActionSet(withName: "Good Night") { actionSet, error in
guard let actionSet, error == nil else { return }
// Turn off living room light
let lightChar = livingRoomLight.powerCharacteristic
let action = HMCharacteristicWriteAction(
characteristic: lightChar,
targetValue: false as NSCopying
)
actionSet.addAction(action) { error in
guard error == nil else { return }
print("Action added to Good Night scene")
}
}
home.executeActionSet(actionSet) { error in
if let error {
print("Execution failed: \(error)")
}
}
var timeOfDay = DateComponents()
timeOfDay.hour = 22
timeOfDay.minute = 30
let firstFireDate = Calendar.current.nextDate(
after: Date(),
matching: timeOfDay,
matchingPolicy: .nextTime
)!
let trigger = HMTimerTrigger(
name: "Nightly",
fireDate: firstFireDate,
recurrence: DateComponents(day: 1) // Repeat every day after firstFireDate
)
home.addTrigger(trigger) { error in
guard error == nil else { return }
// Attach the action set to the trigger
trigger.addActionSet(goodNightActionSet) { error in
guard error == nil else { return }
trigger.enable(true) { error in
print("Trigger enabled: \(error == nil)")
}
}
}
let motionDetected = HMCharacteristicEvent(
characteristic: motionSensorCharacteristic,
triggerValue: true as NSCopying
)
let eventTrigger = HMEventTrigger(
name: "Motion Lights",
events: [motionDetected],
predicate: nil
)
home.addTrigger(eventTrigger) { error in
// Add action sets as above
}
Use MatterAddDeviceRequest to commission a Matter device into your ecosystem.
This is separate from the HMHome home-automation model; it handles the
Matter setup flow and calls into your MatterSupport extension.
import MatterSupport
func addMatterDevice() async throws {
guard MatterAddDeviceRequest.isSupported else {
print("Matter not supported on this device")
return
}
let topology = MatterAddDeviceRequest.Topology(
ecosystemName: "My Smart Home",
homes: [
MatterAddDeviceRequest.Home(displayName: "Main House")
]
)
let request = MatterAddDeviceRequest(
topology: topology,
setupPayload: nil,
showing: .allDevices
)
// Presents system UI for device pairing
try await request.perform()
}
When providing a setup code directly, import Matter and pass an
MTRSetupPayload as setupPayload; this is the case that requires the
setup-payload entitlement.
// Only show devices from a specific vendor
let criteria = MatterAddDeviceRequest.DeviceCriteria.vendorID(0x1234)
let request = MatterAddDeviceRequest(
topology: topology,
setupPayload: nil,
showing: criteria
)
Combine criteria with .all([.vendorID(...), .not(.productID(...))]) or use
.any(...) when any one criterion is enough.
For full ecosystem support, create a MatterSupport Extension. The extension
handles commissioning callbacks. Override the needed methods, but do not call
super from those overrides.
import MatterSupport
final class MatterHandler: MatterAddDeviceExtensionRequestHandler {
override func validateDeviceCredential(
_ deviceCredential:
MatterAddDeviceExtensionRequestHandler.DeviceCredential
) async throws {
// Validate the device attestation certificate
// Throw to reject the device
}
override func rooms(
in home: MatterAddDeviceRequest.Home?
) async -> [MatterAddDeviceRequest.Room] {
// Return rooms in the selected home
return [
MatterAddDeviceRequest.Room(displayName: "Living Room"),
MatterAddDeviceRequest.Room(displayName: "Kitchen")
]
}
override func configureDevice(
named name: String,
in room: MatterAddDeviceRequest.Room?
) async {
// Save the device configuration to your backend
print("Configuring \(name) in \(room?.displayName ?? "no room")")
}
override func commissionDevice(
in home: MatterAddDeviceRequest.Home?,
onboardingPayload: String,
commissioningID: UUID
) async throws {
// Use the onboarding payload to commission the device
// into your fabric using the Matter framework
}
}
// WRONG -- homes array is empty until delegate is called
let manager = HMHomeManager()
let homes = manager.homes // Always empty here
// CORRECT -- wait for delegate
func homeManagerDidUpdateHomes(_ manager: HMHomeManager) {
let homes = manager.homes // Now populated
}
// WRONG -- using HomeKit accessory setup for a Matter ecosystem app
home.addAndSetupAccessories { error in }
// CORRECT -- use MatterAddDeviceRequest for Matter ecosystem commissioning
let request = MatterAddDeviceRequest(
topology: topology,
setupPayload: nil,
showing: .allDevices
)
try await request.perform()
Matter ecosystem commissioning needs the MatterSupport extension, principal handler class, and Matter Bonjour services. Add the setup-payload entitlement only when your app provides setup codes directly.
// WRONG -- each instance loads the full database independently
class ScreenA { let manager = HMHomeManager() }
class ScreenB { let manager = HMHomeManager() }
// CORRECT -- single shared instance
@Observable
final class HomeStore {
static let shared = HomeStore()
let homeManager = HMHomeManager()
}
// WRONG -- writing a value outside the valid range
characteristic.writeValue(500) { _ in }
// CORRECT -- check metadata first
if let metadata = characteristic.metadata,
let maxValue = metadata.maximumValue?.intValue {
let safeValue = min(brightness, maxValue)
characteristic.writeValue(safeValue) { _ in }
}
NSHomeKitUsageDescription present in Info.plistHMHomeManager instance shared across the appHMHomeManagerDelegate implemented; homes not accessed before homeManagerDidUpdateHomesHMHomeDelegate set on homes to receive accessory and room changesHMAccessoryDelegate set on accessories to receive characteristic updatesNSBonjourServices entries addedcom.apple.developer.matter.allow-setup-payload used only when providing setup codesMatterAddDeviceRequest.isSupported checked before performing requestscommissionDevice(in:onboardingPayload:commissioningID:)trigger.enable(true))npx claudepluginhub dpearson2699/swift-ios-skills --plugin all-ios-skillsControls HomeKit smart home accessories like lights, doors, thermostats via HomeClaw MCP tools. Runs scenes, lists devices/rooms, queries events/status, manages automations/config, references characteristics.
Operates Home Assistant through HA NOVA relay with local OS-backed auth. Handles setup verification, self-update checks, and build self-reports.
Integrates with Home Assistant REST and WebSocket APIs to manage entity states, call services, subscribe to events, and handle authentication. Use for HA API calls and real-time integrations.