- name
- surge-gateway
- description
- Control and troubleshoot the user's household Surge for Mac gateway via surge-cli. Use when the user asks about Surge, proxy mode/group/selection, network routing, DNS/cache, node latency, recent requests, household device identification, waking or SSH-ing into LAN Macs, or split-routing config. Do NOT use for general networking questions unrelated to Surge.
- type
- routine
- version
- 2.5.2
- tags
- ["surge","proxy","network","routing","dns","gateway"]
- related_skills
- ["unifi-ops","openwrt-router"]
# Surge Gateway
## 🚨 Red Flags: DO NOT SKIP THIS SKILL
| Excuse | Why it's wrong |
|--------|---------------|
| "I know how surge-cli works, I don't need the skill" | This Surge is the family gateway. Generic CLI knowledge misses household context: device inventory, safety posture, impact radius. |
| "The command looks safe, I'll just run it" | A `stop` or `reload` during active traffic disrupts everyone. Every command has a safety classification — check it first. |
| "I'll test all the nodes to find the fastest" | `test-all-policies` floods the network. Use targeted `test-policy` or `test-group`. |
| "The inventory is stale, I'll skip refreshing it" | Stale IPs/MACs lead to wrong device targeting (wrong Mac for WoL, wrong DHCP lease). Refresh when it matters. |
| "I see RULE-SET errors in `dump event`, the config must be broken" | 🔴 **Event logs are historical — they may reflect an old config that has since been updated.** Always cross-reference with the actual config file first. `grep` the relevant RULE-SET URL in the active profile, then test the URL with `curl -sI`. Only report a config issue if the CURRENT config's URLs fail. The event log alone is not a reliable indicator of the active config's health. |
| "The group isn't in `mine.conf`, so it doesn't exist" | 🔴 **Wrong for policy-path profiles.** The local profile can be a short/stale base profile; remote policy groups are injected into the live effective profile. Always check `dump profile effective` before declaring a group/rule missing. |
| "DIP should fix ChatGPT, so if it fails the config must be wrong" | 🔴 **DIP is not magic.** Dedicated IP, Akamai, and shared/premium nodes must be tested against the actual target domain (`chatgpt.com`/Codex), not generic probes. Cloudflare can drop target TLS for one node while another works. |
## 🔀 Decision Tree
```
Network/routing/proxy/DNS/device task?
├── YES → This skill
│ ├── Read-only diagnostic? → Use safe commands freely
│ ├── Mutation (set/reload/switch/flush)? → Explain impact, confirm, then act
│ ├── Device identification? → Refresh inventory → triangulate (ARP+DHCP+Surge requests)
│ ├── Wake/SSH to LAN Mac? → references/lan-access.md
│ ├── Split routing for similar domains? → references/split-routing.md
├── "Review my Surge config for issues"? → references/config-audit-checklist.md
│ ├── Game download speed (Steam/Epic/etc.)? → references/game-download-speed-diagnosis.md
│ ├── App download/transfer slow (WeChat, DingTalk, etc.)? → references/app-cdn-routing-diagnosis.md
│ ├── Smart group behavior questions? → references/smart-group-nuances.md
│ ├── API intermittently fails through proxy (some succeed, some time out)?
│ │ → references/tls-connectivity-diagnostics.md — systematic multi-region TLS sweep
│ ├── ChatGPT/Codex OAuth TLS fails (`SSL_ERROR_SYSCALL`, `UNEXPECTED_EOF`, HTTP 000)?
│ │ → references/chatgpt-codex-tls-diagnosis.md — effective profile + actual target-domain route + candidate-node comparison
│ ├── Need to fix Hermes adapter for unstable proxy TLS? → references/adapter-keepalive-fix.md
│ ├── Node label says "USA-Boston" but `colo=NRT`? Geo discrepancy?
│ │ → references/domain-based-routing-detection.md — domain-based splitting, ipquality.sh
│ └── "Which command to X?" → references/cli-cheatsheet.md
└── NO → General networking? → Don't load
```
## 🔗 与 `unifi-ops` / `openwrt-router` 的交叉引用
本 skill 管理代理网关层(Surge for Mac, <internal IP redacted>),`unifi-ops` 管理物理网络层(AP/交换机/Controller),`openwrt-router` 管理 OpenWrt/iStoreOS 路由器层(WAN/LAN、DHCP、DNSMasq、NAT/firewall、UCI/opkg)。三者互补:
| 场景 | 先用 | 原因 |
|------|------|------|
| Surge 显示断网但 WiFi 信号正常 | unifi-ops | 可能是 AP 故障/信道干扰/固件问题 |
| 特定区域 WiFi 信号弱 | unifi-ops | 查 AP satisfaction + 信道利用率 |
| 设备物理位置定位 | unifi-ops | 查该设备连到哪个 AP |
| 新设备接入识别(MAC OUI) | unifi-ops | UniFi Controller 有完整设备清单 |
| 上传带宽跑满 | unifi-ops | 交换机端口流量统计 |
| 默认网关/DHCP/NAT/firewall 异常 | openwrt-router | Surge 位于代理层,不能修路由器底层服务 |
| LuCI/Dropbear/opkg/iStoreOS 插件问题 | openwrt-router | OpenWrt/iStoreOS 系统与包管理 |
| 设备无法联网(全链路) | unifi-ops → openwrt-router → surge-gateway | 先物理关联,再 DHCP/网关,最后代理规则 |
> Surge 网关 IP <internal IP redacted>,OpenWrt/iStoreOS 网关常见 IP <internal IP redacted>,Controller IP <internal IP redacted>
## Context
The user's **Surge for Mac is the household network gateway**. Actions may affect the whole family's internet access — treat it as a high-impact control plane.
```bash
SURGE_CLI="/Applications/Surge.app/Contents/Applications/surge-cli"
```
The binary is bundled inside Surge.app and not necessarily on `PATH`. Always call by absolute path.
Config locations (check both — user may use iCloud sync):
- Local: `~/Library/Application Support/Surge/Profiles/mine.conf`
- iCloud: `~/Library/Mobile Documents/iCloud~com~nssurge~inc/Documents/*.conf`
When the active config isn't in the expected location, search: `find ~/Library/Mobile\ Documents -name "*.conf"`
> **Surge.app built-in skill**: Surge for Mac ships its own agent skill at `/Applications/Surge.app/Contents/Resources/Skills/surge/` (including `/Applications/Surge.app/Contents/Resources/Skills/surge/SKILL.md`, `/Applications/Surge.app/Contents/Resources/Skills/surge/references/command-reference.md`, and `/Applications/Surge.app/Contents/Resources/Skills/surge/agents/openai.yaml`). The `agents/openai.yaml` defines Surge's native OpenAI-compatible agent interface. This skill (`surge-gateway`) is the household-gateway-specific superset — it extends the built-in command reference with safety posture, device inventory, config auditing, and domain-specific diagnostic workflows.
## Safety Posture
### Read-only — OK to run
`environment`, `dump` (all types: `active`, `recent`, `request`, `dns`, `traffic`, `policy`, `rule`, `map-remote`, `map-local`, `profile`, `event`, `summary`, `temp-rule`, `virtual-ip-db`, `smart-group-info`, `auto-test-group-result`, `policy-group-sub-policies`, `traffic-stat`, `traffic-stat-host`), `test-network`, `test-policy`, `test-policy-udp`, `test-policy-external-ip`, `test-policy-nat-type`, `test-policy-bandwidth`, `test-group`, `test` (all types: `v4-router`, `dns`, `encrypted-dns`, `external-ip`, `nat-type`), `test-ponte`, `show-policy`, `proxy-runtime-status`, `retrieve-data`, `external-resource list`, `get-resource`, `watch`, `diagnostics`, `stop-diagnostics`
### Mutation — explain impact first, DO NOT execute until user confirms
`flush dns`, `reload`, `switch-profile`, `set`, `set-log-level`, `kill`, `external-resource update`, `test-all-policies`, `add-temp-rule`, `del-temp-rule`, `update-temp-rule`, `flush-temp-rule`
**CRITICAL**: When the user says anything resembling "别改" / "先商量" / "别急着动手" / "我们探讨一下", STOP immediately. Do not edit the config. Discuss the approach and wait for explicit confirmation like "修" / "改吧" / "可以". The user's Surge config is household-critical — even small changes warrant discussion first.
### Dangerous — avoid unless explicitly requested
`stop` — shuts down the household gateway. `update-profile` — edits live profile. `script evaluate` — executes arbitrary JS on the gateway. `unattended-upgrade` — upgrades Surge without supervision.
## Core Workflows
### 0. Refresh device inventory
When using Surge CLI for household network tasks, refresh the inventory unless it's a narrow urgent request where extra reads distract:
```bash
"$SURGE_CLI" dump request --raw > /tmp/surge_requests_latest.json
arp -a > /tmp/arp_a.txt
```
Merge into `~/.hermes/notes/household-network-device-inventory.md`. Don't notify the user just because inventory was refreshed — mention only when relevant.
### 1. "What mode / node is X using?"
1. `environment` → inspect `ProxyMode`, `AllProxyModePolicyNameKey`, `ProxyGroupSelection`
2. If a domain/app is mentioned, `dump request` for recent matching requests → report the matched rule/policy
### 2. "Network is slow / family internet is weird"
1. `test-network` for baseline latency
2. `dump active` for active connections
3. `dump event` for Surge errors
4. Only flush DNS/reload after identifying a likely reason
5. **If DNS-related**: load `references/dns-review.md` for full DNS parameter audit checklist
### 3. "Which node should I use?"
1. `dump policy` to identify candidate policy names/groups
2. Use targeted `test-policy` or `test-group` — NOT `test-all-policies`
3. Summarize latency; don't change policy unless asked
4. **Smart groups caveat**: `update-interval` is LESS critical for `smart` than for `url-test`/`fallback` — Smart groups do real-time dynamic optimization (handshake latency, packet loss, RTT) and adaptive retry. `update-interval` on Smart groups mainly controls periodic re-sync of member lists. Smart groups are designed to self-adapt without it.
### 4. "A site/app is broken"
1. Ask user to reproduce, or use `watch request` briefly to capture
2. `dump request` → find domain, rule, and policy
3. `dump dns` if DNS issue suspected
4. `flush dns` is lower risk than `reload` or profile switching
### 5. Detailed workflows → see references
- **Split routing**: `references/split-routing.md`
- **Wake/SSH to LAN Mac**: `references/lan-access.md`
- **Device identification**: `references/device-inventory-triangulation.md`
- **Full command catalog**: `references/cli-cheatsheet.md`
- **Smart group nuances**: `references/smart-group-nuances.md`
### 6. UDP / video call / real-time traffic issues
When a device behind the Surge gateway has stuttering video calls, game lag, or VoIP dropouts:
1. **Check the UDP fallback setting** in the active profile:
```bash
grep 'udp-policy-not-supported-behaviour' ~/Library/Application\ Support/Surge/Profiles/mine.conf
```
- `reject` → UDP packets silently dropped when proxy doesn't support UDP. This is the **default in many Surge configs** and is a common root cause.
- `direct` → falls back to direct connection. **Recommended for household gateways.**
2. **If `reject`, change to `direct`:**
```bash
sed -i '' 's/udp-policy-not-supported-behaviour = reject/udp-policy-not-supported-behaviour = direct/' ~/Library/Application\ Support/Surge/Profiles/mine.conf
"$SURGE_CLI" reload
```
3. **Verify the target IP's routing:**
- If the destination IP matches `GEOIP,CN` → routes to `🎯 全球直连` (DIRECT), UDP is unaffected by the `reject` setting
- If the destination is foreign → may hit a proxy policy, and UDP gets rejected if node doesn't support it
4. **Check Surge events log** for UDP-related errors:
```bash
"$SURGE_CLI" dump event | python3 -c "import json,sys; [print(e['content']) for e in json.load(sys.stdin)['events'] if 'udp' in str(e).lower() or 'UDP' in str(e).lower()]"
```
5. **If UDP rejection is confirmed but not the root cause**, the issue is likely server-side throttling (WeChat, TikTok, etc. rate-limit UDP uploads).
**Key insight:** Even if the current target routes to DIRECT, keep `direct` as the fallback — any future rule change that routes a UDP service through a proxy would silently break with `reject`.
### 7. Multi-region API testing via proxy switching
When diagnosing an API outage — especially for Cloudflare-proxied services — use Surge's proxy groups to test from different geographic regions. Different CF edges returning the same error = global origin outage. Different edges returning different results = regional issue.
1. **List available proxy groups** with geographic diversity (`environment` → `ProxyGroupSelection`)
2. **Switch the catch-all group** (`🐟 漏网之鱼`) to a specific region:
```bash
"$SURGE_CLI" set "ProxyGroupSelection.🐟 漏网之鱼=🇭🇰 香港节点"
sleep 2
```
3. **Test the target API** and capture `CF-RAY` header to identify which edge handled the request:
```bash
curl -s -D - -o /dev/null --http1.1 --connect-timeout 10 --max-time 15 \
"https://api.target.com/health" 2>&1 | grep -iE 'HTTP/|cf-ray'
```
4. **Check CF-RAY suffixes**: `-HKG` (Hong Kong), `-LAX` (Los Angeles), `-NRT` (Tokyo). Different suffixes = independent edge tests.
5. **Key diagnostic signals**: `cfOrigin;dur=0` → origin unreachable. POST 400 + GET 404 → edge processes, origin dead. Marketing site 200 + API 404 → CDN healthy, API-specific outage.
6. **Restore routing**: `"$SURGE_CLI" set "ProxyGroupSelection.🐟 漏网之鱼=🚀 节点选择1"`
Full workflow with edge location table and example: `references/multi-region-api-testing.md`.
### 8. Config Audit ("review my Surge config")
When the user asks to review their Surge configuration for issues:
1. Read `~/Library/Application Support/Surge/Profiles/mine.conf`
2. Scan for: duplicate RULE-SETs, aggressive `test-timeout`, `proxy-test-url` using Google (prefer `http://cp.cloudflare.com/`), smart group `update-interval=0`, missing RULE-SET for existing policy groups, `external-controller-access` on `0.0.0.0`
3. Report findings with severity (🔴 fix now / 🟡 consider / ⚪ note)
4. Do NOT edit the config unless the user explicitly asks
Full checklist: `references/config-audit-checklist.md`
### 9. Intermittent API TLS Failures (Cloudflare Rate-Limiting)
When an API behind Cloudflare intermittently times out through the proxy (sometimes works, sometimes doesn't):
**Key diagnostic signal**: first connection after a pause succeeds, subsequent rapid connections hang during TLS handshake. `time_connect=0` on failures.
1. **Confirm direct connectivity**: test with `--noproxy '*'` — if direct works 100%, the proxy is the bottleneck
2. **Measure proxy failure rate**: 5 sequential requests with 2s gaps → >50% HTTP 000 = Cloudflare rate-limiting
3. **Rule out node-specific issues**: switch proxy nodes and retest — if failure rate unchanged, it's the provider's IP range, not a single node
4. **Rule out token/auth**: if some requests return 4xx (not 000), the issue is auth, not TLS
5. **Fix**: add a `DOMAIN-SUFFIX,<domain>,DIRECT` rule for the affected endpoint
Full diagnostic workflow and case study: `references/cloudflare-tls-rate-limiting.md`.
### 10. ChatGPT/Codex OAuth TLS failures
When `chatgpt.com/backend-api/codex`, `hermes auth add openai-codex`, or ChatGPT endpoints fail with `SSL_ERROR_SYSCALL`, `UNEXPECTED_EOF`, or HTTP `000` through Surge:
1. **Do not use generic IP checkers as proof of target exit.** `ipinfo.io`/`ifconfig.me` may route through a different policy than `chatgpt.com`.
2. **Read the live effective profile, not just local `mine.conf`:** `dump profile effective` may include remote `policy-path` groups missing from the local base file.
3. **Use target-domain evidence:** test `https://chatgpt.com/cdn-cgi/trace` and inspect `dump request --raw` notes for `Policy decision path`, `policyName`, `remoteAddress`, `outBytes/inBytes`, and TLS/socket timing.
4. **Separate proxy TLS from target TLS:** `Proxy TLS handshake completed` only proves Surge reached the proxy server; `outBytes > 0` and `inBytes = 0` to `chatgpt.com` means target TLS is hung/dropped.
5. **Compare candidate nodes against `chatgpt.com` itself** (DIP 08/09, Akamai, etc.). DIP is not automatically superior; Akamai may work when DIP is dropped by Cloudflare.
6. **Respect mutation safety:** switching `ProxyGroupSelection.*` for tests is a mutation — ask for explicit confirmation and restore the original selection afterward.
Full case study and command sequence: `references/chatgpt-codex-tls-diagnosis.md`.
Ver en GitHub