Skill: dios-man/gateway-config-guardian (version 1.1.0)

--- name: gateway-guardian description: > Three-layer protection for the OpenClaw gateway: real-time config monitoring with auto-rollback, systemd crash recovery, and fixed-target notifications via Feishu/Telegram/Discord. All notifications go to configured FALLBACK_TARGET (DM) and/or STAFF_GROUP_CHAT_ID (group). No dynamic session detection. Use when: (1) user shares a GitHub link and says "install this" / "帮我安装", (2) user asks for status: "gateway-guardian status" / "guardian 运行正常吗", (3) user asks to uninstall: "uninstall gateway-guardian" / "卸载 gateway-guardian". metadata: openclaw: requires: bins: - inotifywait - nc - python3 - journalctl - systemctl - openclaw --- # Gateway Guardian — Skill Instructions ## Triggers Activate this skill when the user: - Shares `https://github.com/Dios-Man/gateway-guardian` and asks to install it - Says "install gateway-guardian", "帮我安装", "install this skill", or similar - Says "gateway-guardian status", "guardian status", "guardian 运行正常吗", or similar - Says "uninstall gateway-guardian", "卸载 gateway-guardian", or similar - Sends a message matching `设置通知群: <id>` or `set guardian group: <id>` --- ## Installation (AI-executed) ### Pre-flight checks 1. Confirm the system is Linux with `systemd --user` available: ```bash systemctl --user status 2>&1 | head -3 ``` 2. Check and install `inotify-tools` if missing: ```bash if ! which inotifywait > /dev/null 2>&1; then sudo apt-get install -y inotify-tools 2>/dev/null || apt-get install -y inotify-tools 2>/dev/null || true fi ``` If `apt-get` fails (no sudo), ask the user to run: `sudo apt-get install -y inotify-tools` 3. Confirm OpenClaw is installed and the gateway is running. ### Determine notification fallback **Before writing guardian.conf, resolve the following values from the current conversation context:** | Variable | How to resolve | |---|---| | `FALLBACK_CHANNEL` | The channel name from inbound metadata (e.g. `feishu`, `telegram`, `discord`) | | `FALLBACK_TARGET` | See rules below | `FALLBACK_TARGET` rules: - **Feishu**: always `user:{sender_id}` (DM to installer, even if installed from a group) - **Telegram**: use `{chat_id}` for direct chats; for groups, ask: "What is your personal Telegram numeric ID? (needed for DM notifications)" - **Discord**: ask: "What is your Discord DM channel ID? (needed for direct notifications)" These resolved values replace `{detected channel}` and `{determined fallback target}` in Step 4. ### Determine notification language (LOCALE) Detect the language the user is communicating in during this conversation: - User is writing in Chinese → `LOCALE=zh` - User is writing in English → `LOCALE=en` - Language is unclear or mixed → ask the user: "Should notifications be sent in Chinese or English?" ### Installation steps **Step 1 — Back up current config** ```bash TIMESTAMP_DIR="$HOME/.openclaw/config-backups" mkdir -p "$TIMESTAMP_DIR" cp "$HOME/.openclaw/openclaw.json" \ "$TIMESTAMP_DIR/openclaw.json.$(date +%Y%m%d-%H%M%S).preinstall" echo "Backup created: $(ls -t $TIMESTAMP_DIR | head -1)" ``` **Step 2 — Download skill files** ```bash SKILL_DIR="$HOME/.openclaw/workspace/skills/gateway-guardian" mkdir -p "$SKILL_DIR" BASE_URL="https://raw.githubusercontent.com/Dios-Man/gateway-guardian/main" for f in config-lib.sh config-watcher.sh gateway-recovery.sh pre-stop.sh; do # Skip if file already present (e.g. installed via clawhub install) [ -f "$SKILL_DIR/$f" ] && continue curl -fsSL "$BASE_URL/$f" -o "$SKILL_DIR/$f" done ``` **Step 3 — Ask bot name (optional)** Ask the user: "What name should I use for myself in team notifications? (e.g. Claw, MyBot, OpenClaw — press Enter to skip and use the default 'OpenClaw')" Record as `BOT_NAME`. If the user skips, use `OpenClaw`. **Step 4 — Write guardian.conf** Substitute resolved values before running. Replace: - `{FALLBACK_CHANNEL}` → resolved channel name (e.g. `feishu`) - `{FALLBACK_TARGET}` → resolved target (e.g. `user:ou_xxx` for Feishu) - `{LOCALE}` → `zh` or `en` - `{BOT_NAME}` → bot display name from Step 3 ```bash SKILL_DIR="$HOME/.openclaw/workspace/skills/gateway-guardian" cat > "$SKILL_DIR/guardian.conf" << GUARDIANCONF # Auto-generated by gateway-guardian installer. Do not upload to GitHub. # Fallback notification target (used when dynamic session detection fails) FALLBACK_CHANNEL={FALLBACK_CHANNEL} FALLBACK_TARGET={FALLBACK_TARGET} # Notification language: zh (Chinese) | en (English) LOCALE={LOCALE} # Bot display name used in staff/team notifications BOT_NAME={BOT_NAME} # Team group/channel notification (optional) # Leave empty to disable. Supported formats: # Feishu: oc_xxx # Telegram: -100xxxxxxxxxx (supergroup/channel numeric id) # Discord: 123456789012345678 (channel id, digits only) # Only effective if the channel is configured and running in OpenClaw. STAFF_GROUP_CHAT_ID= GUARDIANCONF ``` **Step 5 — Set execute permissions** ```bash SKILL_DIR="$HOME/.openclaw/workspace/skills/gateway-guardian" chmod +x "$SKILL_DIR/config-watcher.sh" chmod +x "$SKILL_DIR/gateway-recovery.sh" chmod +x "$SKILL_DIR/pre-stop.sh" ``` **Step 6 — Register config-watcher service** ```bash SKILL_DIR="$HOME/.openclaw/workspace/skills/gateway-guardian" cat > ~/.config/systemd/user/openclaw-config-watcher.service << EOF [Unit] Description=OpenClaw Gateway Guardian - File Watcher After=openclaw-gateway.service [Service] Type=simple ExecStart=/bin/bash $SKILL_DIR/config-watcher.sh Restart=always RestartSec=3 [Install] WantedBy=default.target EOF ``` **Step 7 — Register gateway-recovery service** ```bash SKILL_DIR="$HOME/.openclaw/workspace/skills/gateway-guardian" cat > ~/.config/systemd/user/openclaw-recovery.service << EOF [Unit] Description=OpenClaw Gateway Guardian - Crash Recovery After=network.target [Service] Type=oneshot ExecStart=/bin/bash $SKILL_DIR/gateway-recovery.sh EOF ``` **Step 8 — Register OnFailure drop-in and ExecStopPost hook** ```bash SKILL_DIR="$HOME/.openclaw/workspace/skills/gateway-guardian" mkdir -p ~/.config/systemd/user/openclaw-gateway.service.d/ cat > ~/.config/systemd/user/openclaw-gateway.service.d/recovery.conf << EOF [Unit] OnFailure=openclaw-recovery.service [Service] StartLimitBurst=3 StartLimitIntervalSec=60 ExecStopPost=/bin/bash $SKILL_DIR/pre-stop.sh EOF ``` **Step 9 — Start services** ```bash systemctl --user daemon-reload systemctl --user enable openclaw-config-watcher.service systemctl --user start openclaw-config-watcher.service ``` **Step 10 — Verify installation** ```bash systemctl --user is-active openclaw-config-watcher.service cat ~/.config/systemd/user/openclaw-gateway.service.d/recovery.conf tail -5 /tmp/config-watcher.log ``` **Step 11 — Report result to user** Reply with a summary in the user's language (match LOCALE): --- ✅ **Gateway Guardian installed** 🔔 Notification channel: {channel} (fallback target: {FALLBACK_TARGET}) 🌐 Notification language: {zh | en} 🤖 Bot name: {BOT_NAME} 📋 Service status: {Active line from systemctl output} 📝 Log: `/tmp/config-watcher.log` To uninstall, tell me: "uninstall gateway-guardian" / "卸载 gateway-guardian" --- **Optional — Team group notification** If OpenClaw is used by multiple people, you can configure a group to receive recovery notifications. zh prompt: > 如果团队有多人使用，可以配置一个通知群，网关恢复后自动通知大家。 > 请发送以下消息完成配置（支持飞书 / Telegram / Discord）： > `设置通知群: oc_xxx` en prompt: > If your team uses OpenClaw together, you can set up a group notification. > When the gateway recovers, your team will be notified automatically. > Send me this to configure (Feishu / Telegram / Discord supported): > `set guardian group: oc_xxx` **When you receive the config command:** - Parse the group ID from the message - Write it to `STAFF_GROUP_CHAT_ID` in `guardian.conf` - Confirm back to the user --- ## Status Check (AI-executed) When the user asks for status: ```bash systemctl --user status openclaw-config-watcher.service tail -10 /tmp/config-watcher.log ls -lt ~/.openclaw/config-backups/ | head -5 ``` Report: service active/inactive, recent log lines, number of config backups on hand. --- ## Set Team Group (AI-executed) When the user sends a message matching `设置通知群: <id>` or `set guardian group: <id>`: 1. Extract the group ID from the message 2. Determine the channel based on ID format: - Starts with `oc_` → feishu - Starts with `-100` → telegram - Pure digits → discord 3. Update `guardian.conf`: ```bash SKILL_DIR="$HOME/.openclaw/workspace/skills/gateway-guardian" sed -i "s|^STAFF_GROUP_CHAT_ID=.*|STAFF_GROUP_CHAT_ID={extracted_id}|" "$SKILL_DIR/guardian.conf" ``` 4. Confirm to the user (zh/en based on LOCALE): - zh: `✅ 已配置团队通知群，网关恢复后会自动通知群里的成员。` - en: `✅ Team group configured. Members will be notified automatically when the gateway recovers.` --- ## Uninstall (AI-executed) When the user asks to uninstall: ```bash systemctl --user stop openclaw-config-watcher.service systemctl --user disable openclaw-config-watcher.service rm -f ~/.config/systemd/user/openclaw-config-watcher.service rm -f ~/.config/systemd/user/openclaw-recovery.service rm -f ~/.config/systemd/user/openclaw-gateway.service.d/recovery.conf systemctl --user daemon-reload systemctl --user reset-failed openclaw-gateway.service 2>/dev/null ``` Ask the user whether to also delete config backups: ```bash # Only run if user confirms rm -rf ~/.openclaw/config-backups/ ``` Confirm removal is complete. --- ## Notes - This skill must be installed via an OpenClaw AI agent — no manual install script is provided. - Installation requires an active message context (in-conversation metadata is used for notification setup). - `guardian.conf` contains private notification config and is never uploaded to GitHub. - Config backups in `~/.openclaw/config-backups/` are retained across uninstalls unless the user explicitly requests deletion. - 群通知（`_send_group`）：配置了 `STAFF_GROUP_CHAT_ID` 则发送，未配置则跳过。 - 私聊通知（`_send_dm`）：始终发送到 `FALLBACK_TARGET`。 - 所有通知类型（success/urgent/status）均同时发私聊 + 群。无动态 session 检测。

path: CHANGELOG.md
content: # Changelog

All notable changes to gateway-guardian are documented here.

## [1.6.2] - 2026-03-24

### Fixed

- **SKILL.md: guardian.conf placeholder resolution** — added explicit table showing how to
  resolve `FALLBACK_CHANNEL` and `FALLBACK_TARGET` from conversation context before writing
  the conf file; Step 4 now clearly states placeholders must be substituted before running
- **inotify-tools install**: added non-sudo fallback and manual install prompt for
  environments without elevated permissions

---

## [1.6.1] - 2026-03-24

### Fixed

- **SKILL.md: removed hardcoded bot name** — replaced all references to '小木' with
  generic terms (`通知群`, `网关`) so the skill works correctly for any user, not just
  installations where the bot is named '小木'

---

## [1.6.0] - 2026-03-24

### Added

- **Team/staff group notifications** — optional group notification on gateway recovery
  - New `STAFF_GROUP_CHAT_ID` field in `guardian.conf` (empty by default, opt-in only)
  - New `BOT_NAME` field in `guardian.conf` — display name used in staff messages (default: `OpenClaw`)
  - Recovery message uses `BOT_NAME` so teams with custom agent names get friendly, branded notifications
  - Supported channels: Feishu (`oc_xxx`), Telegram (`-100xxx`), Discord (numeric channel id)
  - `notify_success()` calls `_send_staff_group_notify()` after owner notification; urgent alerts do NOT notify the group
  - Gracefully skipped when `STAFF_GROUP_CHAT_ID` is empty — no config change required for existing installs

- **Post-install team group setup flow** in SKILL.md
  - Installer now asks for `BOT_NAME` during setup
  - After install, AI prompts user with optional group config command (`设置小木通知群: oc_xxx` / `set guardian group: <id>`)
  - New "Set Team Group" skill section handles the config command and updates `guardian.conf`

### Changed

- `guardian.conf` template expanded with `BOT_NAME` and `STAFF_GROUP_CHAT_ID` fields (both optional, with inline format docs)
- Installation steps renumbered (Step 3 split into bot-name prompt + conf write)

### Design principles

- Default behavior unchanged: existing installs continue to work without any config update
- Staff sees human-friendly message; owner sees technical detail — two separate notification paths
- Failed/urgent alerts never reach the staff group (employees can't fix gateway crashes)

## [1.5.0] - 2026-03-16

### Reverted

- **Removed maintenance mode** (`MAINTENANCE_FLAG`, `check_maintenance()`) — introduced a new
  failure path: if maintenance mode was left on, core config monitoring silently stopped.
  The problem it solved (imprecise upgrade notifications) was cosmetic; the risk introduced
  was real. Reverted to keep the guardian simple and reliable.
- **Removed `upgrade-openclaw.sh`** — existed solely to manage maintenance mode; no longer needed.
- **Removed upgrade flag handling** in `pre-stop.sh` and `monitor_gateway_recovery()` —
  dead code without the maintenance mode that wrote the flag.
- **Removed maintenance-related language strings** from `config-lib.sh`.
- **Cleaned up SKILL.md** — removed maintenance mode and upgrade script sections.

### Principle applied

> "Don't let cosmetic improvements introduce breaking risks."
> If the old behavior was merely imperfect (not broken), keep it.
> Maintenance mode made upgrade notifications prettier but made the guardian itself fragile.

---

## [1.4.3] - 2026-03-16

### Added

- **`upgrade-openclaw.sh`** — safe upgrade script that wraps `npm install -g openclaw`
  with automatic maintenance mode management
  - Step 1: enables maintenance mode (sends 🔧 notification)
  - Step 2: runs `npm install -g openclaw@<version>`
  - Step 3: validates config (auto-rollback on failure)
  - Step 4: disables maintenance mode (triggers ⚙️ upgrade notification)
  - `trap EXIT` ensures maintenance flag is always cleaned up, even on failure
  - Usage: `bash upgrade-openclaw.sh` or `bash upgrade-openclaw.sh 2026.3.13`

- **SKILL.md**: "Upgrading OpenClaw" section now documents script-based upgrade workflow
  as the required method; direct `npm install -g openclaw` is discouraged

### Motivation

During testing (2026-03-15), manual maintenance mode was forgotten/interrupted multiple
times, causing incorrect notifications. The upgrade script eliminates human error by
making maintenance mode an intrinsic part of the upgrade process.

---

## [1.4.2] - 2026-03-15

### Fixed

- **Upgrade notification lost on process restart** — when gateway restarts during upgrade,
  config-watcher process itself gets restarted by systemd, causing the upgrade notification
  sent by `monitor_gateway_recovery()` to be lost mid-flight
- **check_maintenance()**: when maintenance mode turns OFF, now checks if `upgrade` flag
  exists in `MANAGED_RESTART_FLAG` — if so, sends deferred upgrade notification instead of
  the generic maintenance-off message
- Upgrade notification is now guaranteed to be delivered regardless of process restarts

### Result: reliable 2-notification upgrade sequence
1. 🔧 维护模式已开启 (on `touch` maintenance flag)  
2. ⚙️ 检测到 OpenClaw 升级 — 网关已自动重启 (on `rm` maintenance flag)

---

## [1.4.1] - 2026-03-15

### Fixed

- **Upgrade notification race condition** — previously required manually writing
  `echo "upgrade" > /tmp/guardian-managed-restart` before upgrading, which was
  unreliable and easily lost to timing issues
- **pre-stop.sh**: when maintenance mode is active during a clean gateway stop,
  now writes `upgrade` flag instead of sending the generic "restarting" notification
- **monitor**: upgrade flag path now correctly triggers `_MSG_UPGRADE_DETECTED`
  ("检测到 OpenClaw 升级 — 网关已自动重启")

### New upgrade workflow (no manual flag needed)
```bash
touch ~/.openclaw/.guardian-maintenance   # pause monitoring
npm install -g openclaw@latest            # upgrade
rm ~/.openclaw/.guardian-maintenance      # resume → upgrade notification sent automatically
```

---

## [1.4.0] - 2026-03-15

### Added

- **Maintenance mode** (`touch ~/.openclaw/.guardian-maintenance`)
  - Pauses config monitoring during planned operations (upgrades, config edits)
  - Guardian sends a Feishu/Telegram/Discord notification when maintenance mode turns on/off
  - Monitoring resumes automatically when the file is deleted
  - Startup validation is also skipped while maintenance mode is active

- **Upgrade-aware notifications**
  - New managed restart flag type `upgrade` (write `echo "upgrade" > /tmp/guardian-managed-restart` before upgrading)
  - When gateway recovers after an upgrade, notification reads "OpenClaw upgrade detected — gateway restarted automatically" instead of the generic restart message
  - Distinguishes planned upgrade restarts from crash recovery and manual restarts

- **Maintenance mode language strings** (zh + en)
  - `_MSG_MAINTENANCE_ON` / `_MSG_MAINTENANCE_OFF` / `_MSG_MAINTENANCE_SKIPPED`
  - `_MSG_UPGRADE_DETECTED`

### Motivation

Discovered during a live OpenClaw upgrade (2026-03-15): guardian could not be stopped via
`pkill` because systemd auto-restarted it immediately. The only workaround was
`systemctl --user stop openclaw-config-watcher.service`, which required remembering the exact
service name. The maintenance flag provides a simpler, script-friendly alternative.

Also observed that guardian's gateway-restart notification used the generic "restart complete"
message even when triggered by an upgrade — making it hard to tell in chat history whether
the restart was intentional.

---

## [1.3.0] - 2026-03-08

### Added
- Dynamic session detection: finds the most recently active direct session at runtime
- `guardian.conf` fallback when session detection fails
- Bilingual support (zh/en): all notifications and log messages in both languages
- `LOCALE` setting in `guardian.conf` (auto-detected from user's conversation language)

### Changed
- Notifications now use `openclaw message send` instead of hardcoded curl calls
- SKILL.md includes `LOCALE` configuration instructions

---

## [1.2.0] - 2026-03-05

### Added
- `gateway-recovery.sh`: systemd OnFailure handler for crash recovery
- `pre-stop.sh`: ExecStopPost hook — sends "gateway restarting" notification before clean stops
- Background monitor in `config-watcher.sh`: detects gateway down→up transitions
- `MANAGED_RESTART_FLAG` coordination to avoid duplicate notifications across scripts

### Changed
- Three-layer architecture: config watcher + crash recovery + pre-stop hook

---

## [1.1.0] - 2026-03-02

### Added
- Timestamp-based config backups (`~/.openclaw/config-backups/`)
- Multi-source rollback: timestamp backups → openclaw native backups
- Lock file (`/tmp/openclaw-config.lock`) prevents concurrent config writes

---

## [1.0.0] - 2026-02-28

### Initial release
- `config-watcher.sh`: inotifywait-based config file monitor
- Auto-rollback on invalid config (JSON syntax + openclaw schema validation)
- Feishu notification on rollback success/failure
- systemd user service (`openclaw-config-watcher.service`)


path: README.en.md
content: # Gateway Guardian

<p align="center"><a href="https://github.com/Dios-Man/gateway-guardian/blob/main/README.md">中文</a>丨English</p>

<p align="center">
  <img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT">
  <img src="https://img.shields.io/badge/platform-Linux-blue.svg" alt="Platform: Linux">
  <img src="https://img.shields.io/badge/OpenClaw-Skill-brightgreen.svg" alt="OpenClaw Skill">
</p>

> An OpenClaw skill that automatically rolls back corrupted configs, restarts a crashed gateway, and notifies you the moment something goes wrong.

---

## What problem does it solve?

OpenClaw's AI capabilities depend entirely on the gateway. If the gateway goes down, you lose access to your AI.

There are two common causes:

**1. Corrupted config file**  
When an AI modifies your config (e.g., adding an API key or switching models), a formatting error or missing field can make `openclaw.json` invalid. The gateway will fail to start on the next restart.

**2. Unexpected gateway crash**  
Memory issues, resource exhaustion, or intermittent bugs can bring the gateway down mid-session.

Gateway Guardian handles both automatically and notifies you right away.

---

## How it works

### Config protection (real-time)

Every time `openclaw.json` changes, Guardian validates it in milliseconds across three checks:

1. Valid JSON syntax
2. Required fields present (`gateway.port` must exist)
3. OpenClaw's own schema validation

If validation fails, Guardian immediately rolls back to the most recent valid backup. The whole process is automatic — you don't need to do anything.

### Crash recovery (OnFailure)

If the gateway crashes 3 times within 60 seconds, Guardian takes over:
1. Checks the config (rolls back if needed)
2. Restarts the gateway
3. Waits up to 30 seconds for the port to become available
4. Sends a success notification if recovered, or an urgent alert if not

### Notifications

Whether Guardian fixes things automatically or needs your help, it sends a notification to your messaging channel (Feishu / Telegram / Discord / etc.).

---

## Notification examples

**Config auto-fixed (no action needed):**

```
✅ OpenClaw Gateway Guardian

⏰ Time: 2026-03-09 22:10
📋 Event: Config file corrupted — auto-rolled back and recovered
🔧 Rolled back to: openclaw.json.20260309-221005
📝 Recent log:
[22:10:03] ❌ Config invalid: missing gateway.port
[22:10:04] ✅ Rolled back to timestamp backup
[22:10:04] ✅ Gateway is running

💬 If this alert was triggered by my own action, please forward this message to me directly — no explanation needed. I'll understand the context and continue automatically.
```

**Gateway crash — auto-recovered (no action needed):**

```
✅ OpenClaw Gateway Guardian — Gateway Recovered

⏰ Time: 2026-03-09 22:10
📋 Event: Gateway crashed (config healthy) — auto-restarted
🔧 Action: Reset failed count + restart gateway
✅ Result: Gateway is back online

💬 If this alert was triggered by my own action, please forward this message to me directly — no explanation needed. I'll understand the context and continue automatically.
```

**Manual intervention required:**

```
🚨 OpenClaw Gateway Guardian — Gateway Recovery Failed

⏰ Time: 2026-03-09 22:10
📋 Event: Gateway crashed and could not be restarted automatically
❌ Reason: Gateway still unresponsive after restart attempts
📝 Recent log:
[22:10:03] Gateway failed repeatedly — starting recovery
[22:10:36] ❌ Gateway still unresponsive after 30s
🔍 Gateway log:
Mar 09 22:10:06 node[xxx]: Error: EADDRINUSE: port 18789 already in use

Please log into the server to handle this manually.
```

**When the gateway restarts (two messages):**

```
⚙️ Gateway is restarting, please wait...
```
```
✅ Gateway recovered. You can continue your conversation.
```

> **About "forward this message to me":**  
> A gateway restart interrupts any task that was in progress. If the AI was in the middle of helping you when the restart happened, just forward this notification back to it — no explanation needed. It will pick up where it left off. Alternatively, you can just say "the gateway just restarted" and it will understand.

---

## Installation

**Requirements:**
- Linux with `systemd --user` available
- OpenClaw Gateway running
- `inotify-tools` (auto-installed if missing, or manually: `sudo apt-get install -y inotify-tools`)

Once the requirements are met, send the following link to your OpenClaw agent and say "install this":

```
https://raw.githubusercontent.com/Dios-Man/gateway-guardian/main/SKILL.md
```

OpenClaw will automatically detect your messaging channel and user ID, and configure everything. It will also set the notification language based on the language you're using in the conversation.

**What the installation does:**
1. Backs up your current config (pre-install snapshot)
2. Pulls script files from the GitHub repository
3. Registers the `openclaw-config-watcher` service (persistent config file monitor)
4. Registers the `openclaw-recovery` service (triggered on gateway crash via OnFailure)
5. Adds an `ExecStopPost` hook to the gateway service (sends notification before stop)
6. Generates `guardian.conf` (stores your fallback notification config)

---

## Uninstall

Tell your OpenClaw agent: "uninstall gateway-guardian"

Or run manually:

```bash
systemctl --user stop openclaw-config-watcher.service
systemctl --user disable openclaw-config-watcher.service
rm -f ~/.config/systemd/user/openclaw-config-watcher.service
rm -f ~/.config/systemd/user/openclaw-recovery.service
rm -f ~/.config/systemd/user/openclaw-gateway.service.d/recovery.conf
systemctl --user daemon-reload
systemctl --user reset-failed openclaw-gateway.service 2>/dev/null
```

Config backups in `~/.openclaw/config-backups/` are kept after uninstall. To delete them:

```bash
rm -rf ~/.openclaw/config-backups/
```

---

## Logs

```bash
tail -f /tmp/config-watcher.log    # Config monitor + notification log
tail -f /tmp/gateway-recovery.log  # Crash recovery log
ls -lt ~/.openclaw/config-backups/ # Timestamped backup list
```

---

## FAQ

**Q: Will Guardian interfere with normal OpenClaw operation?**  
No. The config-watcher uses inotifywait (event-driven), so it has near-zero CPU usage at rest. It only runs briefly when the config file changes.

**Q: What if notifications aren't coming through?**  
Check `FALLBACK_CHANNEL` and `FALLBACK_TARGET` in `guardian.conf`, or reinstall the skill to let OpenClaw re-detect your channel.

**Q: Where do notifications get sent?**  
Before each notification, Guardian queries the most recently active session and prefers DMs. If detection fails, it falls back to the channel and target stored in `guardian.conf` during installation.

**Q: Will Guardian roll back my intentional config changes?**  
No. As long as your changes are valid (correct JSON, required fields present), Guardian saves them as a new backup. Only invalid configs get rolled back.

**Q: Is `guardian.conf` safe?**  
It only stores your messaging channel and user ID (fallback config) — no API keys or passwords. It is never uploaded to GitHub.

---

## Architecture

```
config-watcher service starts
    ↓
Startup check: validate current config
    ├─ Valid → save backup
    └─ Invalid → rollback → notify user

openclaw.json changes
    ↓
config-watcher (inotifywait, persistent)
    ├─ Valid → save timestamped backup
    └─ Invalid → rollback → notify user

Gateway process crashes
    ↓
systemd auto-restart
    ↓
3 failures in 60s → OnFailure triggered
    ↓
gateway-recovery
    ├─ Check config (rollback if needed)
    ├─ Restart gateway
    ├─ Wait up to 30s for port
    ├─ Recovered → notify user
    └─ Failed → urgent alert (with error logs)

Gateway intentional restart
    ↓
ExecStopPost (pre-stop.sh) → send "restarting" notification
    ↓
config-watcher background monitor (polls every 5s)
    └─ Detects recovery → send "recovered" notification
```

---

## License

MIT


path: README.md
content: # Gateway Guardian

<p align="center">中文丨<a href="https://github.com/Dios-Man/gateway-guardian/blob/main/README.en.md">English</a></p>

<p align="center">
  <img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT">
  <img src="https://img.shields.io/badge/platform-Linux-blue.svg" alt="Platform: Linux">
  <img src="https://img.shields.io/badge/OpenClaw-Skill-brightgreen.svg" alt="OpenClaw Skill">
</p>

> 一个给 OpenClaw 用户的网关防护 Skill。  
> 配置写坏了自动回滚，网关崩溃了自动重启，出事第一时间通知你。

---

## 它解决什么问题？

OpenClaw 的 AI 能力完全依赖网关（Gateway）。网关一旦挂掉，你就联系不上 AI 了。

常见的"网关挂掉"原因有两种：

**1. 配置文件被写坏**  
AI 在修改配置（比如添加 API Key、切换模型）时，可能因为格式错误或字段缺失，让 `openclaw.json` 变成无效文件。下次网关重启时直接起不来。

**2. 网关进程意外崩溃**  
内存问题、系统资源紧张、偶发性 bug，都可能让网关在运行中突然挂掉。

Gateway Guardian 会自动处理这两种情况，并在第一时间通知你。

---

## 工作方式

### 配置守护（实时）

每次 `openclaw.json` 发生变化，Guardian 会在毫秒内完成三关验证：

1. JSON 语法是否正确
2. 关键字段是否存在（`gateway.port` 必须有）
3. OpenClaw 自身的 schema 校验

验证失败时立刻回滚到最近一个合法备份。整个过程自动完成，无需你介入。

### 崩溃恢复（OnFailure）

如果网关在 60 秒内连续崩溃 3 次，Guardian 接管：
1. 检查配置是否有问题（有则先回滚）
2. 重启网关
3. 等待最多 30 秒确认端口可用
4. 成功则通知你，失败则发紧急告警

### 通知

无论是自动修复还是需要人工处理，都会推送通知到你的消息渠道（飞书 / Telegram / Discord 等）。

---

## 通知示例

**配置自动修复（无需操作）：**

```
✅ OpenClaw 网关守护

⏰ 时间：2026-03-09 22:10
📋 事件：配置文件损坏，已自动回滚并恢复
🔧 回滚至：openclaw.json.20260309-221005
📝 关键日志：
[22:10:03] ❌ Config invalid: missing gateway.port
[22:10:04] ✅ Rolled back to timestamp backup
[22:10:04] ✅ Gateway is running

💬 如果此次告警是由我的操作引起的，请将这条消息直接转发给我，
无需添加任何说明，我会自动了解情况并继续处理。
```

**网关崩溃恢复（无需操作）：**

```
✅ OpenClaw 网关守护 - 网关已恢复

⏰ 时间：2026-03-09 22:10
📋 事件：网关崩溃（配置正常），已自动重启
🔧 处置：重置失败记录 + 重启网关
✅ 结果：网关已恢复正常运行

💬 如果此次告警是由我的操作引起的，请将这条消息直接转发给我，
无需添加任何说明，我会自动了解情况并继续处理。
```

**需要人工处理：**

```
🚨 OpenClaw 网关守护 - 需要人工处理

⏰ 时间：2026-03-09 22:10
📋 事件：网关崩溃，自动恢复失败
❌ 原因：多次重启后网关仍无响应
📝 关键日志：
[22:10:03] Gateway failed repeatedly — starting recovery
[22:10:36] ❌ Gateway still unresponsive after 30s
🔍 网关日志：
Mar 09 22:10:06 node[xxx]: Error: EADDRINUSE: port 18789 already in use

请登录服务器手动处理。
```

**网关主动重启时（两条）：**

```
⚙️ 网关正在重启中，请稍候...
```
```
✅ 已恢复，请发消息继续对话。
```

> **关于"请将消息转发给我"：**  
> 网关重启会中断正在进行的任务。如果是 AI 在帮你做某件事时发生了重启，直接把这条通知转发给 AI，它就能立刻了解情况并继续。不转发也没关系，直接告诉 AI"刚才网关重启了"效果一样。

---

## 安装

**前置条件：**
- Linux 系统，`systemd --user` 可用
- OpenClaw Gateway 正在运行
- `inotify-tools`（安装时自动检测并安装，或手动：`sudo apt-get install -y inotify-tools`）

满足条件后，将以下链接发给你的 OpenClaw，并说"帮我安装"：

```
https://raw.githubusercontent.com/Dios-Man/gateway-guardian/main/SKILL.md
```

OpenClaw 会自动检测你的消息渠道和用户 ID，完成全部配置，并根据你的对话语言设置通知语言。

**安装过程：**
1. 备份当前配置（安装前快照）
2. 从 GitHub 拉取脚本文件
3. 注册 `openclaw-config-watcher` 服务（常驻监听配置文件）
4. 注册 `openclaw-recovery` 服务（网关崩溃时 OnFailure 触发）
5. 为网关服务添加 `ExecStopPost` 钩子（停止前发送通知）
6. 生成 `guardian.conf`（保存通知渠道兜底配置）

---

## 卸载

告诉 OpenClaw："卸载 gateway-guardian"

或者手动执行：

```bash
systemctl --user stop openclaw-config-watcher.service
systemctl --user disable openclaw-config-watcher.service
rm -f ~/.config/systemd/user/openclaw-config-watcher.service
rm -f ~/.config/systemd/user/openclaw-recovery.service
rm -f ~/.config/systemd/user/openclaw-gateway.service.d/recovery.conf
systemctl --user daemon-reload
systemctl --user reset-failed openclaw-gateway.service 2>/dev/null
```

卸载不会删除已有的配置备份（`~/.openclaw/config-backups/`），需要的话手动删除：

```bash
rm -rf ~/.openclaw/config-backups/
```

---

## 日志

```bash
tail -f /tmp/config-watcher.log    # 配置监听 + 通知日志
tail -f /tmp/gateway-recovery.log  # 崩溃恢复日志
ls -lt ~/.openclaw/config-backups/ # 时间戳备份列表
```

---

## 常见问题

**Q：Guardian 会影响 OpenClaw 的正常运行吗？**  
不会。config-watcher 使用 inotifywait 事件驱动，平时接近零 CPU 占用，只在配置发生变化时短暂运行。

**Q：通知发不出去怎么办？**  
检查 `guardian.conf` 里的 `FALLBACK_CHANNEL` 和 `FALLBACK_TARGET` 是否正确，或重新安装让 OpenClaw 重新检测。

**Q：通知发到哪里？**  
每次发通知前，Guardian 会查询最近活跃的对话 session，优先发私信。检测失败时兜底使用 `guardian.conf` 中的配置。

**Q：我手动改了配置，Guardian 会把我的改动回滚掉吗？**  
不会。只要改动合法（JSON 格式正确且包含必要字段），Guardian 会将其保存为新备份。只有无效配置才会被回滚。

**Q：`guardian.conf` 里的内容安全吗？**  
`guardian.conf` 只保存消息渠道和用户 ID（兜底配置），不含 API Key 或密码，且不会被上传到 GitHub。

---

## 技术架构

```
config-watcher 服务启动
    ↓
启动检查：验证当前配置
    ├─ 验证通过 → 保存备份
    └─ 验证失败 → 回滚 → 通知用户

openclaw.json 发生变化
    ↓
config-watcher（inotifywait 常驻）
    ├─ 验证通过 → 保存时间戳备份
    └─ 验证失败 → 回滚 → 通知用户

网关进程崩溃
    ↓
systemd 自动重启
    ↓
重启失败超过 3 次/60s → OnFailure 触发
    ↓
gateway-recovery
    ├─ 检查配置（有问题先回滚）
    ├─ 重启网关
    ├─ 等待 30s 确认端口可用
    ├─ 恢复成功 → 通知用户
    └─ 恢复失败 → 紧急通知（含错误日志）

网关主动重启
    ↓
ExecStopPost（pre-stop.sh）→ 发送"重启中"通知
    ↓
config-watcher 后台监测（每 5s 探测）
    └─ 检测到恢复 → 发送"已恢复"通知
```

---

## License

MIT


path: config-watcher.sh
content: #!/bin/bash
# config-watcher.sh — Watch openclaw.json for changes, validate, and rollback if needed
# Managed by systemd. Installed via SKILL.md — do not run manually.

LOG="/tmp/config-watcher.log"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/config-lib.sh"

log "=== config-watcher started ==="

# ── Background: monitor gateway recovery (detects down→up transition) ─────────
monitor_gateway_recovery() {
    local was_down=0

    # Delay 10s on startup to give the gateway time to come up (After= doesn't guarantee port readiness)
    sleep 10
    nc -z 127.0.0.1 $GATEWAY_PORT 2>/dev/null || was_down=1

    while true; do
        sleep 5
        if nc -z 127.0.0.1 $GATEWAY_PORT 2>/dev/null; then
            if [ "$was_down" = "1" ]; then
                was_down=0
                if [ -f "$MANAGED_RESTART_FLAG" ]; then
                    local flag_type
                    flag_type=$(cat "$MANAGED_RESTART_FLAG" 2>/dev/null)
                    rm -f "$MANAGED_RESTART_FLAG"
                    if [ "$flag_type" = "recovery" ] || [ "$flag_type" = "watcher" ]; then
                        # recovery.sh / config-watcher already sent the notification — skip
                        log "[monitor] Managed restart ($flag_type) — skipping notification"
                    else
                        # Planned restart complete (initiated by pre-stop.sh)
                        log "[monitor] Gateway restart complete"
                        notify_status "$_MSG_RESTART_DONE"
                    fi
                else
                    # Human-fixed or unknown recovery
                    log "[monitor] Gateway recovered (unmanaged) — sending notification"
                    notify_status "$_MSG_HUMAN_FIXED"
                fi
            fi
        else
            was_down=1
        fi
    done
}

monitor_gateway_recovery &
MONITOR_PID=$!
log "[monitor] Background monitor started (PID: $MONITOR_PID)"

# ── On startup: validate current config under lock ────────────────────────────
(
    flock -w 60 9 || { log "Lock timeout on startup"; exit 1; }
    handle_change
) 9>"$LOCK_FILE"

# ── Watch directory in monitor mode (-m), only process openclaw.json changes ──
inotifywait -q -m -e close_write -e moved_to \
    --format '%f' "$BACKUP_DIR" 2>>"$LOG" | \
while IFS= read -r filename; do
    [[ "$filename" == "openclaw.json" ]] || continue
    log "Config change detected"
    (
        flock -w 60 9 || { log "Lock timeout, skipping this change"; exit 1; }
        handle_change
    ) 9>"$LOCK_FILE"
done


Security scan verdicts — ClawScan: clean | static analysis: suspicious | VirusTotal:  | SkillSpector:  ()