# Ops Home

> Smart home command center via Homey Pro. Devices, flows, scenes, energy, climate, presence, alarms. Works via Homey local API (preferred) + Athom cloud API fallback. Configure once via /ops:setup.

- **Type:** Skill
- **Install:** `agentstack add skill-lifecycle-innovations-limited-claude-ops-ops-home`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [Lifecycle-Innovations-Limited](https://agentstack.voostack.com/s/lifecycle-innovations-limited)
- **Installs:** 0
- **Category:** [Cloud & Infrastructure](https://agentstack.voostack.com/c/cloud-infrastructure)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [Lifecycle-Innovations-Limited](https://github.com/Lifecycle-Innovations-Limited)
- **Source:** https://github.com/Lifecycle-Innovations-Limited/claude-ops/tree/main/claude-ops/skills/ops-home
- **Website:** https://github.com/Lifecycle-Innovations-Limited/claude-ops/wiki

## Install

```sh
agentstack add skill-lifecycle-innovations-limited-claude-ops-ops-home
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# OPS ► HOME — Smart Home Command Center (Homey Pro)

## Runtime Context

Before executing, load available context:

1. **Preferences**: Read `${CLAUDE_PLUGIN_DATA_DIR:-$HOME/.claude/plugins/data/ops-ops-marketplace}/preferences.json`
   - `timezone` — display all timestamps in user's timezone
   - `home_automation.homey_local_url` — e.g. `http://192.168.1.100` (preferred path, faster, no cloud dependency)
   - `home_automation.homey_local_token` — Personal Access Token for local API
   - `home_automation.homey_cloud_token` — Athom OAuth token for cloud fallback
   - `home_automation.homey_id` — Homey ID (cloud resolution)

2. **Daemon health**: Read `${CLAUDE_PLUGIN_DATA_DIR}/daemon-health.json`
   - If `action_needed` is not null → surface it before running any Homey operations
   - On any auth/connectivity failure in this skill, write `action_needed` back to daemon-health.json

3. **Secrets**: Resolve Homey credentials via userConfig → env vars → Doppler → keychain (see Phase 1 below)

## CLI/API Reference

### Homey Pro Web API v3 — LOCAL (preferred)

Base URL: `${HOMEY_LOCAL_URL}` (e.g. `http://192.168.1.100`)

| Endpoint                                                   | Method | Description                                           |
| ---------------------------------------------------------- | ------ | ----------------------------------------------------- |
| `/api/manager/devices/device`                              | GET    | List all devices                                      |
| `/api/manager/devices/device/{id}`                         | GET    | Get one device with capabilities                      |
| `/api/manager/devices/device/{id}/capability/{capability}` | PUT    | Set capability (onoff, dim, target_temperature, etc.) |
| `/api/manager/flow/flow`                                   | GET    | List all flows                                        |
| `/api/manager/flow/flow/{id}/trigger`                      | POST   | Run a flow                                            |
| `/api/manager/zones/zone`                                  | GET    | List zones (rooms)                                    |
| `/api/manager/energy/live`                                 | GET    | Live power draw (watts)                               |
| `/api/manager/energy/report`                               | GET    | Historical energy report (kWh)                        |
| `/api/manager/presence`                                    | GET    | Presence status (who is home)                         |
| `/api/manager/alarms/alarm`                                | GET    | Active alarms (smoke, water, security)                |
| `/api/manager/system`                                      | GET    | Homey system info (firmware, name, uptime)            |

**Auth header (local)**: `Authorization: Bearer ${HOMEY_LOCAL_TOKEN}`

### Athom Cloud API — FALLBACK

Base URL: `https://api.athom.com`

| Endpoint                                   | Method | Description       |
| ------------------------------------------ | ------ | ----------------- |
| `/v2/homey/${HOMEY_ID}/devices`            | GET    | Devices via cloud |
| `/v2/homey/${HOMEY_ID}/flows`              | GET    | Flows via cloud   |
| `/v2/homey/${HOMEY_ID}/flows/{id}/trigger` | POST   | Trigger a flow    |
| `/v2/homey/${HOMEY_ID}/zones`              | GET    | Zones via cloud   |

**Auth header (cloud)**: `Authorization: Bearer ${HOMEY_CLOUD_TOKEN}`

### Common capability strings (Homey)

`onoff`, `dim` (0.0–1.0), `target_temperature`, `measure_temperature`, `measure_humidity`, `measure_power`, `meter_power`, `alarm_motion`, `alarm_smoke`, `alarm_water`, `alarm_contact`, `locked`, `windowcoverings_state`, `light_hue`, `light_saturation`, `volume_set`.

## Agent Teams support

If `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` is set, use **Agent Teams** for parallel hub probing:

```
TeamCreate("home-team")
Agent(team_name="home-team", name="devices-scanner", prompt="List all Homey devices, group by zone, return online/offline state and current capabilities")
Agent(team_name="home-team", name="flows-scanner", prompt="List all flows and their last-fired timestamps")
Agent(team_name="home-team", name="energy-scanner", prompt="Pull live power draw + today's kWh + top consumers, flag anomalies vs 7-day baseline")
Agent(team_name="home-team", name="presence-scanner", prompt="Return presence state and active alarms")
```

If the flag is NOT set, dispatch `ops:home-agent` as standard fire-and-forget subagents per scope (devices, flows, energy, presence, alarms).

## Phase 1 — Resolve credentials

Resolve Homey credentials in this order. Local path is preferred (faster, works offline, lower latency):

```bash
PREFS_PATH="${CLAUDE_PLUGIN_DATA_DIR:-$HOME/.claude/plugins/data/ops-ops-marketplace}/preferences.json"

# 1. Plugin userConfig (preferences.json)
HOMEY_LOCAL_URL=$(jq -r '.home_automation.homey_local_url // empty' "$PREFS_PATH" 2>/dev/null)
HOMEY_LOCAL_TOKEN=$(jq -r '.home_automation.homey_local_token // empty' "$PREFS_PATH" 2>/dev/null)
HOMEY_CLOUD_TOKEN=$(jq -r '.home_automation.homey_cloud_token // empty' "$PREFS_PATH" 2>/dev/null)
HOMEY_ID=$(jq -r '.home_automation.homey_id // empty' "$PREFS_PATH" 2>/dev/null)

# 2. Environment variables (override userConfig if set)
[ -n "$HOMEY_LOCAL_URL" ] || HOMEY_LOCAL_URL="${HOMEY_LOCAL_URL:-}"
[ -n "$HOMEY_LOCAL_TOKEN" ] || HOMEY_LOCAL_TOKEN="${HOMEY_LOCAL_TOKEN:-}"
[ -n "$HOMEY_CLOUD_TOKEN" ] || HOMEY_CLOUD_TOKEN="${HOMEY_CLOUD_TOKEN:-${HOMEY_ACCESS_TOKEN:-}}"
[ -n "$HOMEY_ID" ] || HOMEY_ID="${HOMEY_ID:-}"

# 3. Doppler fallback (project: homey-pro)
if [ -z "$HOMEY_LOCAL_TOKEN" ] && command -v doppler &>/dev/null; then
  HOMEY_LOCAL_TOKEN=$(doppler secrets get HOMEY_LOCAL_TOKEN --project homey-pro --plain 2>/dev/null)
fi
if [ -z "$HOMEY_CLOUD_TOKEN" ] && command -v doppler &>/dev/null; then
  HOMEY_CLOUD_TOKEN=$(doppler secrets get HOMEY_ACCESS_TOKEN --project homey-pro --plain 2>/dev/null)
fi
if [ -z "$HOMEY_LOCAL_URL" ] && command -v doppler &>/dev/null; then
  HOMEY_LOCAL_URL=$(doppler secrets get HOMEY_LOCAL_URL --project homey-pro --plain 2>/dev/null)
fi
if [ -z "$HOMEY_ID" ] && command -v doppler &>/dev/null; then
  HOMEY_ID=$(doppler secrets get HOMEY_ID --project homey-pro --plain 2>/dev/null)
fi

# 4. Keychain fallback
[ -z "$HOMEY_LOCAL_TOKEN" ] && HOMEY_LOCAL_TOKEN=$(security find-generic-password -s "homey-local-token" -w 2>/dev/null)
[ -z "$HOMEY_CLOUD_TOKEN" ] && HOMEY_CLOUD_TOKEN=$(security find-generic-password -s "homey-cloud-token" -w 2>/dev/null)
```

If neither a (`HOMEY_LOCAL_URL` + `HOMEY_LOCAL_TOKEN`) pair nor (`HOMEY_CLOUD_TOKEN` + `HOMEY_ID`) is resolvable, tell the user and exit gracefully:

```
No Homey credentials configured. Run /ops:setup --section home to configure your Homey Pro hub.
```

Write `action_needed: "configure_homey"` to `daemon-health.json` and exit.

Set helpers used by all phases below:

```bash
HOMEY_BASE_LOCAL="${HOMEY_LOCAL_URL}/api/manager"
HOMEY_BASE_CLOUD="https://api.athom.com/v2/homey/${HOMEY_ID}"
HOMEY_AUTH_LOCAL="Authorization: Bearer ${HOMEY_LOCAL_TOKEN}"
HOMEY_AUTH_CLOUD="Authorization: Bearer ${HOMEY_CLOUD_TOKEN}"

# homey_call  [method] [body] — tries local first, falls back to cloud on failure
homey_call() {
  local path="$1" method="${2:-GET}" body="${3:-}"
  local resp http_code
  if [ -n "$HOMEY_LOCAL_URL" ] && [ -n "$HOMEY_LOCAL_TOKEN" ]; then
    resp=$(curl -s -o /tmp/homey_resp -w "%{http_code}" -X "$method" \
      -H "$HOMEY_AUTH_LOCAL" -H "Content-Type: application/json" \
      ${body:+--data "$body"} \
      "${HOMEY_BASE_LOCAL}${path}" 2>/dev/null)
    if [ "$resp" -ge 200 ] && [ "$resp" -lt 300 ]; then
      cat /tmp/homey_resp; return 0
    fi
  fi
  # Fallback to cloud
  if [ -n "$HOMEY_CLOUD_TOKEN" ] && [ -n "$HOMEY_ID" ]; then
    # Map manager-style local paths to cloud equivalents where possible
    local cloud_path="${path/\/devices\/device/\/devices}"
    cloud_path="${cloud_path/\/flow\/flow/\/flows}"
    cloud_path="${cloud_path/\/zones\/zone/\/zones}"
    curl -s -X "$method" \
      -H "$HOMEY_AUTH_CLOUD" -H "Content-Type: application/json" \
      ${body:+--data "$body"} \
      "${HOMEY_BASE_CLOUD}${cloud_path}"
    return $?
  fi
  echo '{"error":"no homey transport available"}'
  return 1
}
```

---

## Phase 2 — Route by $ARGUMENTS

| Input                                   | Action                |
| --------------------------------------- | --------------------- |
| (empty)                                 | Home status dashboard |
| status, dashboard                       | Home status dashboard |
| devices, device, lights, locks, sensors | Devices manager       |
| flow, flows                             | Trigger / list flows  |
| scene, scenes                           | Trigger scene (alias) |
| energy, power, kwh                      | Energy dashboard      |
| climate, temp, thermostat, heating      | Climate manager       |
| presence, who, home                     | Presence              |
| alarm, alarms, arm, disarm, security    | Alarms / security     |
| health, diagnose, outage                | Health / outage scan  |
| sonos, speaker, music, play, volume, group | Sonos audio control   |
| setup, configure, init, token           | Setup flow            |

---

## STATUS (default — empty $ARGUMENTS)

One-screen home dashboard. Run devices/flows/energy/presence/alarms calls in parallel (separate Bash calls or Agent Team), then render.

```bash
# Devices online state
homey_call "/devices/device" | jq '{
  total: (. | length),
  online: ([.[] | select(.available == true)] | length),
  offline: ([.[] | select(.available == false)] | length)
}'

# Flows
homey_call "/flow/flow" | jq '{
  total: (. | length),
  enabled: ([.[] | select(.enabled == true)] | length),
  last_fired: ([.[] | select(.lastExecuted != null)] | sort_by(.lastExecuted) | reverse | .[0] | {name, lastExecuted})
}'

# Live energy
homey_call "/energy/live" | jq '{watts: .totalPower // 0}'

# Presence
homey_call "/presence" | jq '[.[] | select(.present == true) | .name]'

# Alarms (active)
homey_call "/alarms/alarm" | jq '[.[] | select(.active == true)]'

# Zones
homey_call "/zones/zone" | jq '[.[] | .name]'
```

Desktop render:

```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 OPS ► HOME — [hub-name] — [timestamp]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

HUB          [name]  ([firmware version])
TRANSPORT    local | cloud  ([latency-ms]ms)

DEVICES      [N online] / [N total]   [N offline]
FLOWS        [N enabled] / [N total]
LAST FLOW    [name] fired [N min] ago

POWER        [W] now    [kWh] today
ZONES        [N rooms]
PRESENCE     [name1], [name2]   — home

ALARMS       [N active]
  [type] in [zone] — [device]    (if active)

──────────────────────────────────────────────────────
 [d] devices   [f] flows   [e] energy
 [c] climate   [p] presence   [a] alarms
 /ops:ops-home setup — configure credentials
──────────────────────────────────────────────────────
```

Mobile mode (`$SSH_CONNECTION` set or `$OPS_MOBILE=1`): plain text only, 5–8 lines max, no banners.

```
home: [N]/[N] devices · [W]W now · [kWh] today.
flows: [N] enabled · last "[name]" [N]m ago.
presence: [names] home.
alarms: [N] active.
next: /ops-home devices | flows | energy
```

If `[N] alarms active` is non-zero AND any are critical (smoke/leak/security), surface immediately at top of output and suggest piping to `/ops:ops-comms` to broadcast.

Use `AskUserQuestion` for next-action selection (max 4 options per Rule 1).

---

## DEVICES

List devices, group by zone. Support filter and bulk-toggle.

```bash
# All devices with zone + capabilities
homey_call "/devices/device" | jq '[.[] | {
  id: .id,
  name: .name,
  zone: .zoneName,
  driverId: .driverId,
  class: .class,
  available: .available,
  capabilities: .capabilities,
  capabilityValues: (.capabilitiesObj // {} | to_entries | map({key: .key, value: .value.value}))
}]'

# Zones for grouping
homey_call "/zones/zone" | jq '[.[] | {id: .id, name: .name}]'
```

Apply filter from `$ARGUMENTS`:

- `devices lights` → filter `class == "light"` or capability includes `dim`/`light_hue`
- `devices locks` → filter `class == "lock"` or capability includes `locked`
- `devices climate` → filter capability includes `target_temperature` or `measure_temperature`
- `devices sensors` → filter capability starts with `measure_` or `alarm_`
- `devices --off` → set `onoff=false` on filtered set (REQUIRES `AskUserQuestion` confirmation — destructive)
- `devices --on` → set `onoff=true` on filtered set (REQUIRES `AskUserQuestion` confirmation)

Render grouped by zone:

```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 OPS ► HOME ► DEVICES — [filter] — [timestamp]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[ZONE: Living Room]
  [Living Room Lamp]      light    on    dim:0.65    online
  [Sofa Outlet]           socket   off                online
  [Thermostat]            climate  22.5°C → 21.0°C   online

[ZONE: Kitchen]
  [Kitchen Ceiling]       light    on    dim:1.0     online
  ...

OFFLINE
  [Garage Sensor]         sensor                     offline 2h

──────────────────────────────────────────────────────
 Actions:
 a) Toggle a specific device
 b) Turn all [filter] off
 c) Filter by zone
 d) View device capabilities
──────────────────────────────────────────────────────
```

For toggle / set capability:

```bash
# Set onoff
homey_call "/devices/device/${DEVICE_ID}/capability/onoff" PUT '{"value": false}'

# Set dim (0.0 - 1.0)
homey_call "/devices/device/${DEVICE_ID}/capability/dim" PUT '{"value": 0.5}'

# Set target temperature
homey_call "/devices/device/${DEVICE_ID}/capability/target_temperature" PUT '{"value": 21.0}'
```

Bulk operations REQUIRE `AskUserQuestion` confirmation (Rule 5 — destructive-like behavior). Show device count + sample before executing.

---

## FLOWS (and SCENES — alias)

Homey calls scenes "flows". Both `flow` and `scene` arguments route here.

```bash
# List flows
homey_call "/flow/flow" | jq '[.[] | {
  id: .id,
  name: .name,
  enabled: .enabled,
  lastExecuted: .lastExecuted,
  triggerable: .triggerable
}]'
```

If `$ARGUMENTS` includes a flow name (e.g. `flow movie-time`, `scene good-night`), fuzzy-match by name (case-insensitive substring), then trigger:

```bash
FLOW_ID="[matched id]"
homey_call "/flow/flow/${FLOW_ID}/trigger" POST '{}'
```

If multiple flows match, present top 4 via `AskUserQuestion` (Rule 1) and let user pick.

If `flow list` or no flow name provided, render the list with last-fired age.

Common scene names users may try: `movie-time`, `good-night`, `leaving-home`, `coming-home`, `wake-up`, `dinner`, `away`. Fuzzy match handles variations (`goodnight`, `good night`, `night`).

```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 OPS ► HOME ► FLOWS — [timestamp]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

ENABLED FLOWS ([N])
  [name]                 fired [N min] ago
  [name]                 never
  ...

DISABLED ([N])
  [name]
  ...

──────────────────────────────────────────────────────
 Actions:
 a) Trigger a flow
 b) Enable / disable a flow
 c) View flow definition
──────────────────────────────────────────────────────
```

Trigger results: confirm `{"success": true}` or surface the error.

---

## ENERGY

Live power draw + today's kWh + top consumers + anomaly detection.

```bash
# Live power
homey_call "/energy/live" | jq '{
  totalWatts: .totalPower // 0,
  byDevice: [.devices // {} | to_entries[] | {id: .key, watts: .value.power}] | sort_by(-.watts) | .[:10]
}'

# Today's energy report
TODAY=$(date -u +"%Y-%m-%d")
homey_call "/energy/report?period=today" | jq '{
  todayKwh: .totalEnergy // 0,
  byZone: .zones // {}
}'

# 7-day baseline for anomaly detection
homey_call "/energy/report?period=last7days" | jq '.dailyAverage // 0'
```

Compute anomaly: if `todayKwh > 1.5 * dailyAverage`, flag as anomaly.

Render:

```
━━

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [Lifecycle-Innovations-Limited](https://github.com/Lifecycle-Innovations-Limited)
- **Source:** [Lifecycle-Innovations-Limited/claude-ops](https://github.com/Lifecycle-Innovations-Limited/claude-ops)
- **License:** MIT
- **Homepage:** https://github.com/Lifecycle-Innovations-Limited/claude-ops/wiki

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-lifecycle-innovations-limited-claude-ops-ops-home
- Seller: https://agentstack.voostack.com/s/lifecycle-innovations-limited
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
