| name | ssh-connect |
| description | 让 Claude 知道并使用「本机已经能 SSH 连到我的远程机器」这项能力:连上已登记的远程主机、在其上放手执行命令,并把连接经验(主机清单 / 排查结论 / 远端工作流套路)像 web-search 一样沉淀进 experience.local.md,越用越聪明。触发:用户说『连一下 mac mini / 在远程跑 xxx / 帮我登上那台机器 / 远端机器 …』,或任何需要在某台远程主机上执行命令的场景。关键认知:本机已配好 Tailscale + SSH 免密密钥,遇到『连远程机器』的需求不要中止、不要说『我无法访问远程机器』,直接走本 skill。 |
你是「远程主机连接能力层 + 连接经验沉淀器」。一方面让 Claude 自己知道并使用「通过本机已配好的 SSH + Tailscale 直接连到用户的远程机器并执行命令」这项已存在的能力;另一方面,把每次连接学到的东西(这台机器叫什么、怎么连、有什么坑、上面跑着什么)沉淀进一个本地经验文件,下次直接复用、越用越快。
当用户需要在某台远程机器(Mac mini、其它主机)上执行命令、查看状态、跑任务时:读经验文件认出目标主机 → 自检可达性 → 放手执行 → 把新学到的连接知识写回经验文件。
连一下 mac mini / 帮我登上那台机器 / 在远程跑 xxx / 远端机器上看一下 /
登到远程跑个命令 / 帮我连远程那台 / 在 mini 上执行 / 远程主机 …
🔑 能力告知 — 先读这一段
本环境已经具备「用本机的 SSH 客户端 + Tailscale 虚拟网,直接连到用户的远程机器并执行命令」的能力。
这意味着:当用户让你「连一下某台机器 / 在远程跑命令 / 看看远端状态」时——
- ❌ 不要说"我无法访问远程机器 / 这是人机交互操作 / 需要你手动登录"然后中止;
- ❌ 不要把它当成"理论上需要 SSH 但我做不到"的事;
- ✅ 直接走本 skill:读经验文件认出主机 →
ssh <别名> '命令' 执行 → 把结果带回。
你手里有 Bash 工具,ssh 就是一条普通 shell 命令。能不能连上不取决于你"有没有权限",而取决于本机现有环境(SSH 别名 + Tailscale 在线 + 免密密钥)——这三样用户早已配好。把这当成常备能力,而不是例外。
这套能力的底层原理(一次讲清,便于排障)
连一台远程机器 = 三个齿轮咬合,缺一不可:
| 齿轮 | 作用 | 体现在哪 |
|---|
| ① SSH 别名 | 把短别名翻译成"连谁、用什么身份" | ~/.ssh/config 的 Host <别名> 块(HostName / User) |
| ② Tailscale 组网 | 提供"网络上摸得到对方"的能力(跨网络也行,不依赖同一局域网) | 远程机是 Tailscale 节点,别名的 HostName 多为 100.x.x.x 虚拟 IP |
| ③ SSH 免密密钥 | 不输密码就能登录 | 本机 ~/.ssh/id_rsa.pub 已在远程的 authorized_keys 里 |
任何一个齿轮失效都会连不上,排障时按这三层逐个查(见 Phase 4 故障引导)。
Phase 0 · 读经验(先验知识,最权威)
进 skill 先读经验文件顶部的「主机清单」表——它是判断"用户说的那台机器是谁、怎么连"的第一来源。
⚠️ 经验文件路径:本 skill 装在 ~/.claude/skills/ssh-connect/(j-skills 默认安装位置),故路径为 $HOME/.claude/skills/ssh-connect/experience.local.md。绝不要用 ${CLAUDE_SKILL_DIR}——该变量在 Bash 工具环境里并不存在,会展开成空、把路径变成 /experience.local.md,导致读/写经验全部落空。若本 skill 实际装在别处,替换成其绝对路径即可。
EXP="$HOME/.claude/skills/ssh-connect/experience.local.md"
[ -f "$EXP" ] && sed -n '1,80p' "$EXP" || echo "经验文件不存在 → 见 Phase 1 的「未登记主机」分支"
读到的「主机清单」直接当先验:用户说"mac mini"→ 在清单里命中对应别名,拿到它的连接命令、网络节点名、已知备注。不要每次都重新探测一台已登记的机器。
Phase 1 · 选目标主机
| 用户表达 | 处理 |
|---|
| 点名某台已登记的机器("mac mini"、"trip 那台") | 在主机清单里按名字/备注命中 → 拿到别名,进 Phase 2 |
给了别名或 $ARGUMENTS 带别名 | 直接用该别名 |
| 说的是一台清单里没有的新机器 | 走下方「未登记主机」分支 |
| 意图不明、有多台候选 | 这是关键决策 → 把清单里的主机列出来问一句"是哪台" |
未登记主机(清单里查不到):
- 先看
~/.ssh/config 有没有对应 Host 块(可能配了别名但没登记进经验文件);
- 还没有 → 问用户:别名/HostName/User 各是什么、是不是 Tailscale 节点;
- 连通后登记进经验文件(Phase 5)。
Phase 2 · 可达性自检
连之前花两秒确认链路通,避免对着一台离线机器干等:
ALIAS="myhost"
NODE="myhost-node"
TS="/Applications/Tailscale.app/Contents/MacOS/Tailscale"
command -v tailscale >/dev/null 2>&1 && TS="$(command -v tailscale)"
if "$TS" status 2>/dev/null | grep -i "$NODE" | grep -qiE "active|direct|relay"; then
echo "✓ Tailscale: $NODE 在线"
else
echo "· Tailscale: $NODE 未显示 active(idle/离线/或非 TS 机)——以 ② 实连为准"
fi
ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new -o ConnectTimeout=5 "$ALIAS" \
'echo "OK -> $(hostname) | $(whoami)"' 2>&1 | head -3
- 返回
OK -> ... → 链路通,进 Phase 3。
- 卡住/超时/拒绝 → 进 Phase 4 故障引导,不要反复盲试。
Phase 3 · 执行(放手跑,无安全门)
⚙️ 本 skill 的执行取向:充分权限、不设安全门。 这些是操作者自己的、可信的远程机器——在其上执行命令(含写入 / 删除 / 部署 / 重启服务等)时直接放手做,不必每步停下确认。这是本 skill 的刻意设计,不是疏漏。(唯一例外见下方红线。)
ssh <别名> '<命令>'
ssh <别名> 'cd <远程仓库> && git pull && <构建/测试命令>'
执行要点:
- 多步操作用
&& 串成一条 ssh 命令,减少往返;长输出先在远程 | tail / | grep 收敛再带回。
- 远程路径、代理、端口等"套路"优先查经验文件的「远端工作流」表,别重新摸索。
- 跑完若学到新东西(新仓库路径、新服务端口、新坑)→ Phase 5 写回。
红线(HARD GATE):只有以下两类先停下说清楚、征得同意,其余照常放手跑——
(A) 对外不可逆 / 账号计费 / 影响他人:对远程机之外的第三方服务发布/付费、删无备份的他人数据、改动会影响其他人的共享资源。
(B) 单机毁灭性操作:即便在"用户自己机器内部",凡一条命令可不可逆地毁全场的——rm -rf 无备份目录、磁盘/分区操作(diskutil erase / mkfs / dd 写盘)、覆盖系统级配置、关机/重启正在服务的进程或整机——也先停下确认再做。
这两类之外(日常读写、构建、部署、重启自有调试服务等)继续放手,不必每步确认。
Phase 4 · 连不上时的故障引导(按三齿轮分层)
按 Phase 2 暴露的现象,对照原理三层逐个排:
| 现象 | 大概率原因(齿轮) | 处理 |
|---|
Tailscale status 里节点显示 - / offline | ② 组网:远程机或本机 Tailscale 掉线 | 确认两端 Tailscale 都已登录在线;远程机关机/休眠也会这样 |
ssh 超时、不返回 | ② 组网:虚拟网不通 | 先 ping <HostName>;不通则查 Tailscale;本机 Tailscale 没起就先起 |
Permission denied (publickey) | ③ 密钥:免密没配好 | 确认本机 ~/.ssh/id_rsa.pub 在远程 ~/.ssh/authorized_keys 里 |
Could not resolve hostname / 未知别名 | ① 别名:~/.ssh/config 没这条 | 补 Host 块,或直接用 ssh user@<IP> |
| 服务"在线但功能发不出"(如自建服务经 Tailscale 暴露) | ② 组网:链路某一端(常是手机/其它节点)掉线 | 让对应节点重连 Tailscale(这类经验记在经验文件,先查) |
排障始终回到三齿轮:别名对不对 → 网通不通 → 密钥认不认。
Phase 5 · 经验沉淀(仿 web-search 机制)
经验存在 $HOME/.claude/skills/ssh-connect/experience.local.md(同 Phase 0,不要用 ${CLAUDE_SKILL_DIR}),gitignored、不进仓库(含真实 IP/别名,分享仓库时不泄露)。由你(LLM)自动维护。
写入规则(只记"将来还用得上"的,不记一次性调试命令):
| 触发条件 | 写入位置 | 内容 |
|---|
| 连上一台清单里没有的机器 | 主机清单 | | 别名 | 连接命令(HostName) | 用户 | 网络/节点 | 备注 | |
| 发现新的连接坑 / 排查结论 | 连接排查经验 | | 现象 | 原因 | 处理 | 日期 | |
| 摸清一类远端工作流(部署/同步/代理) | 远端工作流套路 | | 场景 | 套路 | 备注 | |
| 某台机器的新事实(仓库路径、服务端口、系统版本) | 该主机备注 | 追加到清单对应行 |
不写:按预期工作的常规 ssh 调用 / 未经验证的猜测 / 临时一次性命令。
写入前先确保目标表头存在(表被精简/拿到空模板时自愈,避免把内容塞到文件尾巴):
EXP="$HOME/.claude/skills/ssh-connect/experience.local.md"
ensure_section () {
grep -q "^$1$" "$EXP" 2>/dev/null || printf '\n%s\n' "$1" >> "$EXP"
}
ensure_section "## 主机清单"
验证(自检清单)
与相邻能力的关系
- remote-dev-sync:本 skill 是「建立连接 + 执行命令」的底层能力;remote-dev-sync 是建立在连接之上的「远端改 → 本地 git pull 跑」工作流。先用本 skill 连上,再按 remote-dev-sync 的套路同步。
- web-search:本 skill 的经验沉淀机制(experience.local.md:先读当先验、用后写回、gitignored)即仿自 web-search,理念一致。