Control your Apple HomeKit smart home from AI assistants, the terminal, and automation tools.
HomeClaw exposes your HomeKit accessories through a command-line tool, a stdio MCP server, and plugins for Claude Code and OpenClaw. It runs as a lightweight macOS menu bar app.
Why HomeClaw?
Apple HomeKit has no public API, no CLI, and no way to integrate with AI assistants or automation pipelines. HomeClaw bridges that gap with a Mac Catalyst app that talks to HomeKit on your behalf and exposes a clean API surface.
- Ask Claude or OpenClaw to "turn off all the lights" or "set the thermostat to 72"
- Script your smart home from the terminal
- Build automations that go beyond what the Home app offers
- Search and control devices by name, room, category, or semantic type
Architecture
Claude Code --> Plugin (.claude-plugin/) --> stdio MCP server (Node.js) --+
Claude Desktop --> stdio MCP server (Node.js) ----------------------------+
OpenClaw --> Plugin (openclaw/) --> homeclaw-cli --------------------------+
v
Unix socket (JSON newline-delimited)
|
HomeClaw (Mac Catalyst app)
+-- HomeKitManager (direct, in-process)
+-- SocketServer (for CLI/MCP clients)
+-- macOSBridge.bundle (NSStatusItem menu bar)
Single-process design. Apple's HMHomeManager requires a UIKit/Catalyst app with the HomeKit entitlement. By making the entire app Catalyst, HomeKit access is direct (no IPC), signing is unified (single archive), and App Store submission is clean. The macOSBridge plugin bundle provides the native macOS menu bar via NSStatusItem.
Install
TestFlight (Recommended)
The easiest way to install HomeClaw is via TestFlight:
- Join the TestFlight Beta
- Install HomeClaw from TestFlight
- Launch the app -- grant HomeKit access when prompted
- The menu bar icon appears. Click it to see your connected homes.
TestFlight builds are signed for App Store distribution, so HomeKit works without any developer account setup.
Once running, set up your AI integrations:
- Claude Desktop -- one-click install from Settings > Integrations, or add the MCP server config manually
- Claude Code -- install the plugin from GitHub
- OpenClaw -- one-click install from Settings > Integrations, or set up manually
Build from Source
Prerequisites and setup for building from source
Prerequisites
- macOS 26 (Tahoe) or later
- Xcode 26+ with Swift 6.2
- XcodeGen:
brew install xcodegen - Node.js 20+ (for the MCP server wrapper)
- Apple Developer account with HomeKit capability enabled
Why is a developer account required? Apple does not provide a public HomeKit API for macOS. The only way to access HomeKit is through
HMHomeManager, which requires thecom.apple.developer.homekitentitlement and a provisioning profile that covers your Mac's hardware UDID. Apple restricts this entitlement to development signing and App Store distribution -- it cannot be included in Developer ID (notarized) builds. This means every Mac that runs HomeClaw must be registered as a development device in your Apple Developer portal, and the app must be built with your team's signing identity. There is no way around this; it's an Apple platform restriction, not a HomeClaw limitation.
Setup
git clone https://github.com/omarshahine/HomeClaw.git cd HomeClaw # Configure your Apple Developer Team ID (one-time setup) echo "HOMEKIT_TEAM_ID=YOUR_TEAM_ID" > .env.local # Install Node.js dependencies npm install # Build everything and install scripts/build.sh --release --install
Find your Team ID at developer.apple.com/account under Membership Details.
Launch from /Applications or: open "/Applications/HomeClaw.app"
On first launch, grant HomeKit access when prompted. The menu bar icon appears -- click it to see your connected homes.
Note: Apple restricts the HomeKit entitlement to development signing and App Store distribution. Developer ID builds cannot access HomeKit. See Why Development Signing? for details.
MCP Tools
The stdio MCP server wraps homeclaw-cli and exposes these tools:
| Tool | Description |
|---|---|
homekit_status |
Check bridge connectivity and accessory count |
homekit_accessories |
List, get details, search, or control accessories |
homekit_rooms |
List rooms and their accessories |
homekit_scenes |
List, get details, trigger, import, or delete scenes |
homekit_device_map |
LLM-optimized device map with semantic types and aliases |
homekit_events |
Query recent HomeKit events (characteristic changes, scene triggers, control actions) |
homekit_webhook |
Manage webhook configuration: setup (configure + auto-test), test, reset circuit breaker, status |
homekit_config |
View or update configuration (set active home, filtering) |
Connecting an MCP Client
Any MCP-compatible client can connect via the stdio server, which wraps homeclaw-cli and requires no authentication (the HomeClaw app must be running for the socket). Add this to your MCP client config (e.g. claude_desktop_config.json):
{
"mcpServers": {
"homeclaw": {
"command": "node",
"args": ["/Applications/HomeClaw.app/Contents/Resources/mcp-server.js"]
}
}
}The mcp-server.js is bundled inside the app. You can also use the Integrations tab in Settings to install this automatically.
CLI
The homeclaw-cli command-line tool communicates directly over the Unix domain socket. All read commands support --json for machine-readable output.
# List accessories homeclaw-cli list homeclaw-cli list --room "Kitchen" homeclaw-cli list --category thermostat # Control devices homeclaw-cli set "Living Room Light" brightness 75 homeclaw-cli set "Front Door Lock" lock_target_state locked homeclaw-cli set "Thermostat" target_temperature 72 # Disambiguate when a characteristic exists on multiple services (e.g. bridged TVs) homeclaw-cli set "TV" active 0 --service-type 000000D8-0000-1000-8000-0026BB765291 # Get detailed device info homeclaw-cli get "Kitchen Light" --json # Search across all homes homeclaw-cli search "bedroom" --category lightbulb # Scenes homeclaw-cli scenes homeclaw-cli get-scene "Good Night" --json # Full detail: all actions homeclaw-cli trigger "Good Night" # Scene management homeclaw-cli delete-scene "Old Scene" homeclaw-cli import-scene scene.json --dry-run # Preview before creating homeclaw-cli import-scene scene.json # Create scene from JSON homeclaw-cli assign-rooms rooms.json --dry-run # Preview room assignments homeclaw-cli assign-rooms rooms.json # Bulk-assign accessories to rooms # LLM-optimized device map homeclaw-cli device-map # Status and configuration homeclaw-cli status homeclaw-cli config --default-home "Main House" homeclaw-cli config --filter-mode allowlist homeclaw-cli config --list-devices # Event log homeclaw-cli events # Recent events (last 50) homeclaw-cli events --since 1h # Events from the last hour homeclaw-cli events --since 2d --json # Last 2 days, JSON output homeclaw-cli events --type scene_triggered # Filter by event type # Webhook configuration homeclaw-cli config --webhook-url "http://127.0.0.1:18789" homeclaw-cli config --webhook-token "your-secret-token" homeclaw-cli config --webhook-enabled true homeclaw-cli config --webhook-test # Send test event, show HTTP response homeclaw-cli config --webhook-reset # Reset circuit breaker without toggling # Webhook triggers homeclaw-cli triggers # List all triggers homeclaw-cli triggers add --label "Front Door" --accessory-id "<uuid>" homeclaw-cli triggers add --label "Mailbox Open" --accessory-id "<uuid>" --characteristic contact_state homeclaw-cli triggers update "<trigger-id>" --wake-mode now homeclaw-cli triggers remove "<trigger-id>" # Dry-run mutations (validate without actuating) homeclaw-cli set "Front Door" lock_target_state locked --dry-run homeclaw-cli delete-scene "Movie Night" --dry-run # Auto-JSON: all commands output JSON when piped or when env var is set homeclaw-cli status | jq . # Auto-detects non-TTY OUTPUT_FORMAT=json homeclaw-cli list # Force JSON via env var
Using with Claude Code
HomeClaw integrates with Claude Code as a plugin that provides MCP tools and a HomeKit skill for richer natural language understanding.
Installing the Plugin
Install from a local clone or directly from GitHub.
From a local clone:
# Clone if you haven't already git clone https://github.com/omarshahine/HomeClaw.git ~/GitHub/HomeClaw # Inside Claude Code, register the marketplace and install /plugin marketplace add ~/GitHub/HomeClaw /plugin install homeclaw@homeclaw
From GitHub (no local clone needed):
# Inside Claude Code, add the GitHub repo as a marketplace /plugin marketplace add https://github.com/omarshahine/HomeClaw # Install the plugin /plugin install homeclaw@homeclaw
After installing, restart Claude Code. Then just ask:
"Turn on the kitchen lights and set them to 50% brightness" "Lock all the doors" "What's the thermostat set to?" "Run the movie time scene" "Which lights are on in the living room?"
Verifying the Connection
After installing, verify Claude can reach HomeKit:
# Check MCP server status inside Claude Code
/mcpUsing with OpenClaw
HomeClaw includes an OpenClaw plugin that registers a HomeKit skill on the gateway. The skill calls homeclaw-cli by name, so it must be in your PATH.
Same-Mac Install (Recommended)
If HomeClaw and OpenClaw run on the same Mac, use the one-click installer:
- Open Settings > Integrations and click Install in the OpenClaw section.
This handles all four steps automatically: installs the plugin, enables it, symlinks homeclaw-cli into your PATH, and restarts the gateway.
Or from the terminal:
# 1. Install the plugin from the bundled files openclaw plugins install "/Applications/HomeClaw.app/Contents/Resources/openclaw/" openclaw plugins enable homeclaw # 2. Symlink the CLI into PATH (the skill calls homeclaw-cli by name) # Apple Silicon (M1/M2/M3/M4): ln -sf '/Applications/HomeClaw.app/Contents/MacOS/homeclaw-cli' /opt/homebrew/bin/homeclaw-cli # Intel: ln -sf '/Applications/HomeClaw.app/Contents/MacOS/homeclaw-cli' /usr/local/bin/homeclaw-cli # 3. Restart the gateway to load the plugin openclaw gateway restart
Remote Gateway
If OpenClaw runs on a different machine:
# Clone the repo on the gateway git clone https://github.com/omarshahine/HomeClaw.git ~/GitHub/HomeClaw # Install the plugin openclaw plugins install ~/GitHub/HomeClaw/openclaw openclaw plugins enable homeclaw # Symlink the CLI into PATH ln -sf /path/to/homeclaw-cli /opt/homebrew/bin/homeclaw-cli # Restart the gateway openclaw gateway restart
Note: The
homeclaw-clibinary must be accessible from the gateway (in PATH), and the HomeClaw app must be running on the same Mac (connected via Unix socket).
Supported Accessories
HomeClaw supports the full range of HomeKit accessory categories:
| Category | Controllable Characteristics |
|---|---|
| Lights | power, brightness (0-100), hue (0-360), saturation (0-100), color temperature (140-500 mireds) |
| Thermostats | target temperature, HVAC mode (off/heat/cool/auto), target humidity |
| Locks | lock/unlock (accepts locked, unlocked, 0, 1) |
| Doors & Garage Doors | open/close, obstruction detection (read-only) |
| Fans | active, rotation speed, rotation direction, swing mode |
| Window Coverings | target position (0-100%) |
| Switches & Outlets | power on/off |
| Sensors | motion, contact, temperature, humidity, light level, battery (all read-only) |
| Doorbells | ring detection via input_event (single/double/long press), motion (read-only) |
| Programmable Switches | button press detection (single/double/long press) (read-only) |
| Scenes | trigger by name or UUID, inspect actions, import from JSON, delete by name |
Scene Import Format
The import-scene command accepts a JSON file defining a scene and its actions:
{
"name": "Movie Night",
"actions": [
{"accessory": "Living Room Light", "room": "Living Room", "property": "brightness", "value": "30%"},
{"accessory": "TV Backlight", "room": "Living Room", "property": "power_state", "value": "ON"},
{"accessory": "Overhead", "room": "Living Room", "property": "power_state", "value": "OFF"}
]
}The assign-rooms command accepts a JSON file mapping accessories to rooms:
{
"assignments": [
{"accessory": "Kitchen Light", "room": "Kitchen"},
{"accessory": "Desk Lamp", "room": "Office"}
]
}Both commands support --dry-run to preview changes without modifying HomeKit.
Menu Bar App
The menu bar provides at-a-glance status and quick actions:
- HomeKit connection status -- shows home names when connected, or error states with reasons
- Launch at Login toggle
- Settings link and Quit
Settings
Five configuration tabs accessible from the menu bar:
| Tab | Features |
|---|---|
| HomeKit | Connection status, home list with accessory and room counts, active home selector |
| Devices | Filter mode (all/allowlist), per-device toggles with category icons and state badges, grouped by room, search, bulk select/deselect |
| Event Log | Enable/disable event logging, configure file rotation (size limit + backup count), view storage stats, purge logs, reveal in Finder |
| Webhook | Configure webhook base URL + bearer token, select which scenes and accessories trigger webhooks with category icons and state badges. Accessories with multiple characteristics (e.g., a sensor with both contact and motion) show individual toggles per characteristic; battery characteristics are excluded. Per-trigger delivery mode (Batched/Immediate). Circuit breaker banners with Reset button, delivery stats, and last HTTP status. Test webhook connectivity from CLI or manage triggers via homeclaw-cli triggers. |
| Integrations | One-click install for Claude Desktop, Claude Code plugin detection, OpenClaw gateway setup |
HomeKit
View connection status, browse your homes, and select which home is active for all MCP and CLI commands.
Devices
Control which accessories are exposed to MCP clients and the CLI. Switch between All Accessories (everything visible) and Selected Only (allowlist mode). Accessories are grouped by room with a search filter and room-level toggles for quick bulk selection.
Integrations
Install and manage connections to AI assistants. The app detects existing configurations and guides you through setup:
- Claude Desktop -- one-click install of the bundled stdio MCP server (requires Node.js)
- Claude Code -- detects the installed plugin (
homeclaw@homeclaw) - OpenClaw -- detects plugin configuration on the remote gateway and provides setup instructions
Event Log
HomeClaw records all HomeKit events to a JSONL file in ~/Library/Application Support/HomeClaw/events.jsonl. Events include characteristic changes (a light turned on), scene triggers, and control actions from the CLI or MCP.
Configuration
Open Settings > Event Log to configure:
- Enable/disable event logging
- Max file size (10-500 MB) -- when the log reaches this size, it's rotated
- Rotated backups (0-10) -- how many old log files to keep before deleting the oldest
- Purge -- delete all event log files
- Show in Finder -- reveal the log directory
Or configure via CLI:
homeclaw-cli events # Show recent events homeclaw-cli events --since 1h # Last hour homeclaw-cli events --type characteristic_change # Filter by type homeclaw-cli events --limit 200 --json # JSON output
Event types: characteristic_change, scene_triggered, accessory_controlled, homes_updated
The --since flag accepts ISO 8601 timestamps or duration shorthand: 1h, 30m, 2d.
Webhook
HomeClaw pushes HomeKit events to OpenClaw via mapped webhooks. Only accessories and scenes with configured triggers fire webhooks -- untriggered events are logged to disk but not pushed. A dedicated HomeClaw agent receives all events, classifies them by severity, and escalates noteworthy ones to the main agent.
Note: OpenClaw 2026.3.x has a known bug where
/hooks/wakesilently drops events (#33271). HomeClaw uses mapped webhooks (/hooks/homeclaw) which route throughhooks.mappingsand are not affected.
How It Works
HomeClaw POSTs all triggered events to a single mapped endpoint: /hooks/homeclaw. OpenClaw's hooks.mappings config resolves the "homeclaw" key and routes each event to a dedicated HomeClaw agent that classifies and triages events.
HomeKit event --> HomeClaw event logger --> POST /hooks/homeclaw
--> OpenClaw hooks.mappings --> HomeClaw Agent (dedicated)
--> Classifies: CRITICAL / NOTABLE / AMBIENT
--> If notable/critical: a2a to main agent
--> If ambient: log to agent memory only
HomeClaw doesn't need to know about agentId, channel, or sessionKey -- all routing intelligence lives in the OpenClaw config.
Trigger Delivery Modes
Each trigger has a delivery mode that controls timing:
| Mode | Behavior | Set via |
|---|---|---|
| Batched (default) | Event queued until next heartbeat cycle | Settings UI segmented control |
| Immediate | Event delivered right away | Settings UI segmented control |
In Settings > Webhook, each enabled trigger shows a Batched / Immediate picker. Use Immediate for events you want to react to right away (leak sensors, door locks, scene triggers). Use Batched for ambient events (light toggles, temperature changes) to avoid noise.
Setup with AI Assistant
Paste this prompt into OpenClaw or Claude Code to configure webhooks end-to-end. The prompt is idempotent -- it verifies each step and skips anything already configured:
Prerequisites: HomeClaw must be installed and running (menu bar icon visible). If using Claude Code, the
homeclawplugin must be registered (/plugin install homeclaw@homeclaw). Thehomeclaw-clibinary must be in your PATH.Set up HomeClaw mapped webhooks with a dedicated HomeClaw agent. Verify each step first -- skip any that are already configured.
1. HomeClaw agent workspace:
- Check if
homeclawagent exists:openclaw agents list- If missing, install from the bundled app:
openclaw agents install homeclaw /Applications/HomeClaw.app/Contents/Resources/openclaw/agents/homeclaw- Copy agent docs (IDENTITY/SOUL/AGENTS/TOOLS.md) from the app bundle to the local agent dir if newer
- Configure agent: model
claude-sonnet-4, restricted tools (memory, sessions/a2a, read/write only -- no exec, no browser, no external services)2. OpenClaw gateway hooks config:
- Check
~/.openclaw/openclaw.jsonfor ahooks.mappings.homeclawentry- If missing, add:
"hooks": { "enabled": true, "token": "${HOMECLAW_WEBHOOK_TOKEN}", "mappings": { "homeclaw": { "agentId": "homeclaw", "sessionKey": "hook:homeclaw", "deliver": true, "channel": "last", "allowUnsafeExternalContent": true } } }
- Create a transform at
~/.openclaw/hooks/transforms/homeclaw-transform.jsto convert HomeClaw state-change payloads into agent messages- Check
~/.openclaw/.envforHOMECLAW_WEBHOOK_TOKEN. If missing, generate one:openssl rand -base64 24 | tr '+/' '-_' | tr -d '='and add it- Remove any legacy
defaultSessionKeyentries that are no longer needed with dedicated mapping- Restart gateway only if config changed:
openclaw gateway restart3. HomeClaw webhook config:
- Check current config:
homeclaw-cli config --json- Verify:
webhook.enabledis true,webhook.urlishttp://127.0.0.1:18789,webhook.tokenmatches theHOMECLAW_WEBHOOK_TOKENfrom step 2, andwebhook_endpointis/hooks/homeclaw- Fix any mismatches via HomeClaw Settings UI or CLI
- If circuit breaker shows old failures, reset it
4. End-to-end test:
- Run
homeclaw-cli config --webhook-test-- expect HTTP 200- Verify circuit state is
closedandlast_successis recentReport what was already configured, what was changed, and the test result.
Manual Setup
Step-by-step without an AI assistant
1. Create the Agent Workspace
The agent docs are bundled inside the HomeClaw app. Because the app bundle is read-only, you need a local copy for OpenClaw to use as the agent directory:
# Create local agent dir with workspace mkdir -p ~/.openclaw/agents/homeclaw/{agent,workspace} # Copy agent docs from app bundle cp /Applications/HomeClaw.app/Contents/Resources/openclaw/agents/homeclaw/*.md \ ~/.openclaw/agents/homeclaw/agent/ # Register the agent openclaw agents add homeclaw \ --agent-dir ~/.openclaw/agents/homeclaw/agent \ --workspace ~/.openclaw/agents/homeclaw/workspace openclaw agents list # verify it appears
Note:
openclaw agents add(notinstall) is the correct CLI command. The--workspaceflag is required in non-interactive mode.
2. Configure OpenClaw
Add the hooks block with mappings to ~/.openclaw/openclaw.json:
"hooks": { "enabled": true, "token": "${HOMECLAW_WEBHOOK_TOKEN}", "mappings": { "homeclaw": { "agentId": "homeclaw", "sessionKey": "hook:homeclaw", "deliver": true, "channel": "last", "allowUnsafeExternalContent": true } } }
The mappings entry routes all /hooks/homeclaw POSTs to the dedicated HomeClaw agent in a persistent hook:homeclaw session.
Create a transform to convert HomeClaw payloads into agent messages. The hook mapping requires a message field in the payload -- without a transform, payloads with only text + mode will get a 400 error:
mkdir -p ~/.openclaw/hooks/transforms cat > ~/.openclaw/hooks/transforms/homeclaw-transform.js << 'TRANSFORM' // Convert HomeClaw webhook payload {text, mode} into agent message format module.exports = function(payload) { return { message: payload.text || JSON.stringify(payload), mode: payload.mode || "next-heartbeat" }; }; TRANSFORM
Then reference the transform in the mapping:
"homeclaw": { "agentId": "homeclaw", "sessionKey": "hook:homeclaw", "deliver": true, "channel": "last", "allowUnsafeExternalContent": true, "transform": "homeclaw-transform" }
Generate a token and add it to ~/.openclaw/.env:
# Generate a secure token openssl rand -base64 24 | tr '+/' '-_' | tr -d '=' # Add to .env echo 'HOMECLAW_WEBHOOK_TOKEN=<your-generated-token>' >> ~/.openclaw/.env
Restart the gateway: openclaw gateway restart
Warning: The gateway rewrites
openclaw.jsonon restart. Verify your mapping and transform entries survived by checking the file after restart. If a newly-added mapping is stripped, restart a second time -- there may be a race condition with first-time mappings.
3. Configure HomeClaw
Option A -- GUI: Open Settings > Webhook. Toggle Enable, enter http://127.0.0.1:18789 as the base URL, paste the same token from step 2.
Option B -- CLI (note: the CLI updates the running daemon only -- it does not persist to config.json. Use the Settings UI or edit the config file directly for persistent changes):
homeclaw-cli config --webhook-url "http://127.0.0.1:18789" \ --webhook-token "your-token" \ --webhook-enabled true
4. Test the Pipe
homeclaw-cli config --webhook-test
You should see an HTTP 200 response. If it fails, check the token matches and the OpenClaw gateway is running.
Note: Test events update
total_deliveredandlast_http_statusin the circuit breaker stats. After running--webhook-test, checkhomeclaw-cli config --jsonto confirm the values were updated.
5. Create Triggers
In Settings > Webhook, check the accessories and scenes you want to fire webhooks. Only checked items generate events. Accessories with multiple characteristics (e.g., a sensor with both contact state and motion) show individual toggles so you can choose exactly which state changes fire webhooks. Battery-related characteristics are automatically excluded.
Note: Trigger creation is GUI-only. The CLI can list and manage existing triggers (
homeclaw-cli triggers list,triggers remove), but new triggers must be created in the HomeClaw app's Settings > Webhook tab.
6. Test End-to-End
# Verify HomeClaw is connected and webhook is healthy homeclaw-cli status # Toggle a light from the Home app, then check events homeclaw-cli events --since 5m # Check webhook delivery log homeclaw-cli webhook-log # Check HomeClaw delivery logs log show --predicate 'process == "HomeClaw" AND category == "webhook"' --last 5m --style compact
Circuit Breaker
The webhook system includes a tiered circuit breaker that prevents runaway delivery failures from hammering a down endpoint, while ensuring critical events are never silently dropped.
| State | Trigger | Behavior | Recovery |
|---|---|---|---|
| Normal | -- | All webhooks delivered | -- |
| Soft Open | 5 consecutive failures | Non-critical paused | Auto-resumes after 5 minutes |
| Hard Open | 3 soft trips without any success | All non-critical stopped | Reset button in Settings, --webhook-reset CLI, or toggle off/on |
Critical triggers (critical: true) always attempt delivery regardless of circuit state.
The circuit state is visible in:
- Menu bar -- warning icon when paused or disabled
- Settings > Webhook -- orange (paused) or red (disabled) banner with countdown
- CLI --
homeclaw-cli statusshows circuit state, dropped count, and recovery hint
How Events Flow
Home app / physical device / Siri
|
v
HomeKit (HMAccessoryDelegate callback)
|
+-- Cache warmup? --> Update cache only (no logging, no webhooks)
|
+-- Battery event? --> Update cache only (silently dropped)
|
v
HomeClaw event logger (writes to events.jsonl)
|
+-- Trigger matches? --> POST /hooks/homeclaw
|
+-- No trigger --> Logged to disk only (no webhook sent)
v (trigger matched)
OpenClaw gateway validates Bearer token
|
v
hooks.mappings resolves "homeclaw"
|
v
HomeClaw Agent (dedicated)
+-- Classifies: CRITICAL / NOTABLE / AMBIENT
+-- If notable/critical: a2a to main agent
+-- If ambient: log to agent memory only
Authentication
Uses Authorization: Bearer <token> with idempotency headers (X-Request-ID, X-Event-Timestamp). See SKILL.md for the full trigger fields reference, scenario cookbook, and troubleshooting.
Device Filtering
Use the Devices tab in Settings or the CLI to control which accessories are exposed:
homeclaw-cli config --filter-mode allowlist homeclaw-cli config --allow-accessories "uuid1,uuid2,uuid3" homeclaw-cli config --list-devices # shows allowed/filtered status
Building
The build script uses XcodeGen to generate the Xcode project and xcodebuild to compile all targets (HomeClaw Catalyst app, macOSBridge bundle, homeclaw-cli tool):
# Full release build + install to /Applications scripts/build.sh --release --install # Override team ID on the command line scripts/build.sh --release --install --team-id ABCDE12345 # Debug build (faster) scripts/build.sh --debug # Clean build artifacts first scripts/build.sh --clean
Your Apple Developer Team ID is required, provided via .env.local, --team-id, or the HOMEKIT_TEAM_ID environment variable.
Archiving for App Store / TestFlight
scripts/archive.sh # Then open in Xcode Organizer to distribute: open '.build/archives/HomeClaw.xcarchive'
Version Bumping
Version is derived from git tags at build time. To release a new version:
scripts/bump-version.sh 0.2.0 # Updates source files + prints tag commands npm run build:mcp # Rebuild MCP server with new version git add -A && git commit -m "Bump version to 0.2.0" git tag -a v0.2.0 -m "HomeClaw v0.2.0" git push && git push origin v0.2.0
Installing on Additional Macs
Development-signed builds are tied to registered devices. To run HomeClaw on another Mac:
-
Get the target Mac's Provisioning UDID -- on that Mac, run:
system_profiler SPHardwareDataType | grep "Provisioning UDID"
-
Register the device at developer.apple.com/account/resources/devices/add:
- Platform: macOS
- Device Name: a descriptive name (e.g. "Living Room MacBook Air")
- Device ID: the Provisioning UDID from step 1
-
Rebuild on your development machine (Xcode regenerates the provisioning profile to include the new device):
scripts/build.sh --release --install --clean
-
Copy
/Applications/HomeClaw.appto the target Mac (AirDrop, USB, network share, etc.) -
Grant HomeKit access on first launch when prompted.
Note: The target Mac must be signed into iCloud with an account that has HomeKit home data. HomeKit homes are tied to iCloud accounts, not to the app.
Why Development Signing?
Apple restricts the com.apple.developer.homekit entitlement to development signing and Mac App Store distribution. It cannot be included in Developer ID provisioning profiles. A Developer ID build would pass Gatekeeper but have no HomeKit access (HMHomeManager returns zero homes). This is an Apple platform restriction, not a bug.
Project Structure
Sources/
homeclaw/ Unified Catalyst app (Xcode target via XcodeGen)
App/ UIApplicationDelegate entry point, scene delegates
Bridge/ BridgeProtocols.swift (Mac2iOS, iOS2Mac)
HomeKit/ HomeKitManager, SocketServer, CharacteristicMapper,
AccessoryModel, DeviceMap, CharacteristicCache,
HomeEventLogger, WebhookCircuitBreaker
Views/ SettingsView, IntegrationsSettingsView
Shared/ AppConfig, AppLogger, HomeClawConfig
macOSBridge/ AppKit bundle (NSStatusItem menu bar)
MacOSController.swift NSStatusItem + NSMenu via iOS2Mac protocol
Info.plist NSPrincipalClass: MacOSController
homeclaw-cli/ CLI tool (SPM executable + Xcode target)
Commands/ list, get, set, search, scenes, get-scene, status, config, device-map,
events, triggers, delete-scene, import-scene, assign-rooms
SocketClient.swift Direct socket communication
Resources/ Info.plist, entitlements, app icons
scripts/
build.sh Build, sign, and install
archive.sh Archive for App Store / TestFlight
bump-version.sh Update version across source files
mcp-server/ Node.js stdio MCP server (wraps homeclaw-cli)
openclaw/ OpenClaw plugin (HomeClaw)
skills/homekit/ HomeKit skill with full characteristic reference
App bundle layout (after build):
Contents/MacOS/HomeClaw Catalyst app executable
Contents/MacOS/homeclaw-cli Bundled CLI binary
Contents/Resources/macOSBridge.bundle AppKit menu bar plugin
Contents/Resources/mcp-server.js Node.js stdio MCP server
Contents/Resources/openclaw/ Bundled OpenClaw plugin files
Debugging
# Check if HomeClaw is running and HomeKit is ready echo '{"command":"status"}' | nc -U ~/Library/Group\ Containers/group.com.shahine.homeclaw/homeclaw.sock # Or via the CLI homeclaw-cli status # Verify HomeKit entitlement on installed app codesign -d --entitlements :- "/Applications/HomeClaw.app" # View HomeClaw logs log show --predicate 'process == "HomeClaw"' --last 10m --style compact # Check TCC (privacy) permissions sqlite3 ~/Library/Application\ Support/com.apple.TCC/TCC.db \ "SELECT client, auth_value FROM access WHERE service = 'kTCCServiceWillow'"
| Symptom | Cause | Fix |
|---|---|---|
0 homes, ready: false |
Missing HomeKit entitlement | Verify with codesign -d --entitlements |
All characteristic values nil |
Accessory unreachable | Check device power and network |
| "HomeKit Unavailable" in menu | iCloud not signed in | Sign into iCloud with HomeKit data |
| CLI crashes with SIGTRAP | Missing bundle ID in sandbox | Rebuild with CREATE_INFOPLIST_SECTION_IN_BINARY: YES |
Tech Stack
- Swift 6 with strict concurrency (
@MainActor,actorisolation) - Mac Catalyst (UIKit) for HomeKit framework access
- AppKit (via macOSBridge bundle) for native menu bar
- Swift Argument Parser for CLI
- Node.js + @modelcontextprotocol/sdk for stdio MCP server
- XcodeGen for Xcode project generation
- GCD + Unix domain sockets for CLI/MCP communication
FAQ
spctl --assess says "rejected" -- is that a problem?
No. spctl checks Gatekeeper, which only trusts Developer ID and App Store signing. HomeClaw uses development signing (required for HomeKit on macOS), so Gatekeeper will always reject it. This is expected and doesn't prevent the app from running -- AMFI handles development-signed apps separately via the embedded provisioning profile.
Can I use a different Apple ID for HomeKit than my developer account?
Yes. The two accounts serve completely different purposes:
- Apple Developer account -- only matters at build time. Xcode uses it to create the provisioning profile and sign the code.
- iCloud account (on the Mac running HomeClaw) -- determines which HomeKit homes appear. This is the account linked to your Home app data.
These are independent. You can build HomeClaw with your developer account and run it on a Mac signed into a completely different iCloud account that has HomeKit homes. The HomeKit data follows the iCloud account, not the signing identity.
When should I use --clean?
Use scripts/build.sh --clean when:
- Switching Apple Developer Team IDs
- After major Xcode version updates
- Build fails with signing or entitlement errors
- You see code signature errors after rebuilding
The --clean flag removes all build artifacts before building fresh.
HomeKit shows 0 homes
The app is running but can't see any HomeKit data. Check in order:
- iCloud signed in? HomeKit data lives in iCloud. Open System Settings > Apple Account and verify.
- HomeKit entitlement present? Run:
You should see
codesign -d --entitlements :- "/Applications/HomeClaw.app"com.apple.developer.homekit->true. - TCC permission granted? On first launch, macOS asks for HomeKit access. If you denied it, re-grant in System Settings > Privacy & Security > HomeKit.
- Using Developer ID signing? Only development signing supports the HomeKit entitlement. See Why Development Signing?.
How do I install on another Mac?
Development-signed apps are tied to registered devices. See Installing on Additional Macs for the full walkthrough.
How do I see what's happening?
# HomeClaw app logs log show --predicate 'process == "HomeClaw"' --last 10m --style compact # Check HomeKit status directly over the socket homeclaw-cli status # Verify code signature and entitlements codesign -d --entitlements :- "/Applications/HomeClaw.app"
License
MIT -- Copyright (c) 2025 Omar Shahine


