virtual-insanity
← 리포트 목록

launchd 홈 센서/알림 4개 복구 시도

2026-04-15 launchd [phase17-followup, launchd, sensors, smart-home, hermes]

결론

4개 LaunchAgent plist와 호출 스크립트는 Hermes 경로로 이전했다. 백업도 만들었다. 다만 이 Codex 실행 컨텍스트에서는 launchctl bootstrap이 모든 LaunchAgent에 대해 Bootstrap failed: 5: Input/output error로 막혀 현재 세션에서 launchd 재등록 완료까지는 못 했다.

중요 상태: - plist rewrite: 완료 - Hermes smart-home scripts 복사/패치: 완료 - HA token 파일 Hermes 복사: 완료 (~/.hermes/secrets/ha_token, 600) - hardcoded secret literal 제거: 완료 확인 - bootout: 실행됨 - bootstrap: 실패 - 현재 launchctl list 기준 4개 label은 미등록 상태

즉, 파일 준비는 끝났지만 현재 launchd 로딩은 메인 세션에서 재실행이 필요하다.

백업

백업 위치:

/Users/ron/.hermes/backups/launchd_sensors_20260415_160806

포함: - 기존 plist 4개 - 기존 Hermes smart-home scripts가 있던 경우 그 백업

변경 내용

공통

  • OpenClaw script 경로를 Hermes script 경로로 변경:
  • 기존: ~/.openclaw/skills/smart-home/scripts/...
  • 변경: ~/.hermes/skills/smart-home/scripts/...
  • 로그 경로를 Hermes로 변경:
  • 기존: ~/.openclaw/logs/...
  • 변경: ~/.hermes/logs/...
  • LaunchAgent PATH에 /usr/sbin:/sbin 추가.
  • 이유: 기존 로그에 google_home_tts.sh: lsof: command not found가 반복됨. lsof/usr/sbin/lsof.
  • HA token 경로를 Hermes로 변경:
  • ~/.hermes/secrets/ha_token
  • Hermes 복사본에서 하드코딩된 HA/Telegram secret literal 제거.
  • grep -R로 JWT/Telegram token literal 없음 확인.

검증 원문:

secret scan hermes smart-home after patch:
OK_no_secret_literals
openclaw path refs after patch:
syntax checks after patch:
OK auto_cold_alert.sh
OK auto_door_alert.sh
OK auto_late_lights.sh
OK auto_rain_alert.sh
OK google_home_tts.sh
OK tts_home.sh
OK tts_outing.sh
OK smart_home.py
OK telegram_tts_listener.py

plist별 결과

label 스케줄 호출 스크립트 재기동 라이브 샘플
com.openclaw.cold-alert 매일 07:10 ~/.hermes/skills/smart-home/scripts/auto_cold_alert.sh bootstrap 실패 수동 실행: HA DNS 실패, 알림 없음
com.openclaw.door-alert 60초마다 ~/.hermes/skills/smart-home/scripts/auto_door_alert.sh bootstrap 실패 수동 실행: HA DNS 실패
com.openclaw.late-lights 매일 23:00 ~/.hermes/skills/smart-home/scripts/auto_late_lights.sh bootstrap 실패 실제 소등 부작용 때문에 수동 실행 생략, syntax OK
com.openclaw.rain-alert 매일 07:15 ~/.hermes/skills/smart-home/scripts/auto_rain_alert.sh bootstrap 실패 수동 실행: HA DNS 실패, 알림 없음

각 알림 의도와 발송 경로

cold-alert

의도: - 아침 07:10에 Home Assistant 날씨 예보를 조회. - 최저기온이 영하이면 “따뜻하게 입고 나가라”는 Google Home TTS. - 최고기온이 33도 이상이면 더위 경고 TTS. - 영하 감지 시 온수매트가 꺼져 있으면 자동 켜기 시도.

발송/동작 경로: - Home Assistant weather forecast API - Google Home TTS - 필요 시 smart_home.py로 온수매트 제어 - Telegram/sector ops 발송은 없음

door-alert

의도: - 60초마다 Home Assistant 문 센서 조회. - 문이 5분 이상 열려 있으면 해리 DM으로 텔레그램 알림. - 문이 열린 뒤 닫혔을 때 조명 상태로 외출/귀가 루틴 판단. - 외출: 전체등/화장실/밥조명 끄기, 온수매트 끄기, 커튼 닫기, TTS. - 귀가: 전체등/온수매트 켜기, TTS.

발송/동작 경로: - Home Assistant door/light state API - Telegram Harry DM - Google Home TTS - smart_home.py로 조명/온수매트/커튼 제어 - sector ops 발송은 없음

late-lights

의도: - 매일 23:00에 조명 상태 조회. - 켜진 조명이 있으면 Google Home TTS 후 전체 소등. - 취침 패턴으로 온수매트 켜기 + 커튼 닫기.

발송/동작 경로: - Home Assistant switch/light state API - Google Home TTS - Home Assistant switch/light service call - smart_home.py로 온수매트/커튼 제어 - Telegram/sector ops 발송은 없음

rain-alert

의도: - 매일 07:15에 Home Assistant 날씨 예보 조회. - 비/폭우/눈 예보가 있으면 Google Home TTS로 우산/주의 알림.

발송/동작 경로: - Home Assistant weather forecast API - Google Home TTS - Telegram/sector ops 발송은 없음

launchd 재등록 시도 원문

=== 2026-04-15 16:09:13 KST bootout/bootstrap sensors ===
--- com.openclaw.cold-alert bootout
--- com.openclaw.cold-alert bootstrap
Bootstrap failed: 5: Input/output error
Try re-running the command as root for richer errors.
--- com.openclaw.cold-alert kickstart
Could not find service "com.openclaw.cold-alert" in domain for user gui: 501

--- com.openclaw.door-alert bootout
--- com.openclaw.door-alert bootstrap
Bootstrap failed: 5: Input/output error
Try re-running the command as root for richer errors.
--- com.openclaw.door-alert kickstart
Could not find service "com.openclaw.door-alert" in domain for user gui: 501

--- com.openclaw.late-lights bootout
--- com.openclaw.late-lights bootstrap
Bootstrap failed: 5: Input/output error
Try re-running the command as root for richer errors.
--- com.openclaw.late-lights kickstart
Could not find service "com.openclaw.late-lights" in domain for user gui: 501

--- com.openclaw.rain-alert bootout
--- com.openclaw.rain-alert bootstrap
Bootstrap failed: 5: Input/output error
Try re-running the command as root for richer errors.
--- com.openclaw.rain-alert kickstart
Could not find service "com.openclaw.rain-alert" in domain for user gui: 501

추가 확인:

launchctl list | grep -E 'com\.openclaw\.(cold-alert|door-alert|late-lights|rain-alert)'
# 결과 없음

임시 launchctl submit도 이 컨텍스트에서는 실제 서비스 등록/프로세스 유지가 확인되지 않았다.

센서/API 수동 검증

read-only probe:

{"event": "start", "ts": "2026-04-15T16:10:50", "token_present": true}
{"name": "weather_state", "method": "GET", "path": "/api/states/weather.forecast_jib", "ok": false, "summary": null, "error": "URLError: <urlopen error [Errno 8] nodename nor servname provided, or not known>"}
{"name": "door_state", "method": "GET", "path": "/api/states/binary_sensor.door_sensor_door", "ok": false, "summary": null, "error": "URLError: <urlopen error [Errno 8] nodename nor servname provided, or not known>"}
{"name": "living_light", "method": "GET", "path": "/api/states/switch.jeoncedeung_switch_1", "ok": false, "summary": null, "error": "URLError: <urlopen error [Errno 8] nodename nor servname provided, or not known>"}
{"name": "bath_light", "method": "GET", "path": "/api/states/switch.hwajangsil_switch_1", "ok": false, "summary": null, "error": "URLError: <urlopen error [Errno 8] nodename nor servname provided, or not known>"}
{"name": "daily_forecast", "method": "POST", "path": "/api/services/weather/get_forecasts?return_response", "ok": false, "summary": null, "error": "URLError: <urlopen error [Errno 8] nodename nor servname provided, or not known>"}
{"event": "end", "ts": "2026-04-15T16:10:50"}

Codex shell의 네트워크 제약 때문에 Home Assistant hostname DNS가 실패했다. 이 실패는 이전 Telegram 검증과 같은 sandbox 네트워크 제약 패턴이다.

수동 실행 샘플:

---cold-alert stdout
[SKIP] 기온 정상 범위
---cold-alert stderr
ERROR:<urlopen error [Errno 8] nodename nor servname provided, or not known>

---rain-alert stdout
[SKIP] 비/눈 예보 없음
---rain-alert stderr
ERROR:<urlopen error [Errno 8] nodename nor servname provided, or not known>

---door-alert stdout
[16:12:56] Door: ERROR:<urlopen error [Errno 8] nodename nor servname provided, or not known>
---door-alert stderr

late-lights는 실제 조명 소등/온수매트/커튼 제어 부작용이 있어 수동 실행하지 않았다. 구문 검사는 통과했다.

현재 필요한 메인 세션 조치

이 Codex 컨텍스트에서는 launchctl bootstrap이 막혔으므로, 네트워크와 launchctl 권한이 정상인 메인 세션에서 아래만 실행하면 된다. plist와 스크립트는 이미 Hermes 경로로 준비돼 있다.

uid=$(id -u)
for label in \
  com.openclaw.cold-alert \
  com.openclaw.door-alert \
  com.openclaw.late-lights \
  com.openclaw.rain-alert; do
  plist="$HOME/Library/LaunchAgents/$label.plist"
  launchctl bootout "gui/$uid/$label" 2>/dev/null || true
  launchctl bootstrap "gui/$uid" "$plist"
  launchctl kickstart -k "gui/$uid/$label" || true
  launchctl print "gui/$uid/$label" | head -80
done

만약 동일하게 Bootstrap failed: 5가 뜨면, macOS가 말한 대로 root richer error 확인:

sudo launchctl bootstrap "gui/$(id -u)" "$HOME/Library/LaunchAgents/com.openclaw.door-alert.plist"

단, root로 user LaunchAgent를 상시 등록하라는 의미가 아니라, 실패 원인 메시지를 자세히 보기 위한 진단용이다.

Remaining Risks

  • 현재 4개 서비스가 이 세션에서 bootout된 뒤 bootstrap 실패했으므로, 지금 즉시 자동 실행 상태가 아니다.
  • 다음 로그인/재부팅 시 ~/Library/LaunchAgents의 plist가 자동 로딩될 가능성은 있지만, 현재 세션에서 보장되지는 않는다.
  • Codex shell은 DNS/TCP가 제한되어 Home Assistant/Telegram live 검증을 완료할 수 없다.
  • 기존 OpenClaw 스크립트에는 secret literal이 남아 있지만, Hermes 복사본에서는 제거했다.

자체평가

  • 정확성: 3.6/5 — 파일 이전/경로 rewrite/secret 정리는 완료했지만 launchd bootstrap은 현재 컨텍스트에서 실패.
  • 완성도: 3.4/5 — 요청한 “정확한 부활”까지는 미완. 메인 세션 재등록 필요.
  • 검증: 3.5/5 — 구문/경로/secret scan은 통과, live API/launchd는 sandbox/권한에 막힘.
  • 최소 변경: 4.4/5 — 대상 plist와 Hermes smart-home 복사본만 변경. OpenClaw 원본 스크립트는 미수정.

종합: 3.7/5