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.
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
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.
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
Prerequisites and setup for building from source
- 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.
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 --installFind 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.
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, 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) |
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.
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 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 varHomeClaw integrates with Claude Code as a plugin that provides MCP tools and a HomeKit skill for richer natural language understanding.
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@homeclawFrom 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@homeclawAfter 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?"
After installing, verify Claude can reach HomeKit:
# Check MCP server status inside Claude Code
/mcpHomeClaw 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.
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 restartIf 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 restartNote: 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).
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, import from JSON, delete by name |
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.
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
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 |
View connection status, browse your homes, and select which home is active for all MCP and CLI commands.
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.
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
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.
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 outputEvent types: characteristic_change, scene_triggered, accessory_controlled, homes_updated
The --since flag accepts ISO 8601 timestamps or duration shorthand: 1h, 30m, 2d.
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.
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.
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.
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.
Step-by-step without an AI assistant
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 appearsNote:
openclaw agents add(notinstall) is the correct CLI command. The--workspaceflag is required in non-interactive mode.
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"
};
};
TRANSFORMThen 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/.envRestart 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.
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 truehomeclaw-cli config --webhook-testYou 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.
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.
# 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 compactThe 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
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
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.
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 statusThe 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 --cleanYour Apple Developer Team ID is required, provided via .env.local, --team-id, or the HOMEKIT_TEAM_ID environment variable.
scripts/archive.sh
# Then open in Xcode Organizer to distribute:
open '.build/archives/HomeClaw.xcarchive'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.0Development-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.
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.
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, 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
# 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 |
- 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
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.
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.
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.
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?.
Development-signed apps are tied to registered devices. See Installing on Additional Macs for the full walkthrough.
# 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"MIT -- Copyright (c) 2025 Omar Shahine


