内容
# 夸脱甲板
**从克劳德代码驱动远程开发。** 克劳德代码在VS Code中本地运行,但您的代码位于远程Linux服务器上 - 包括太大(数百TB)而无法克隆的存储库。夸脱甲板为代理提供了一组`remote_*`工具,以便它通过SSH连接,搜索,读取和编辑服务器上的代码,运行命令和测试,并在本地聊天中报告。只读挂载允许您在VS Code资源管理器中浏览相同的树。
它是一个薄的,自托管的控制甲板:一个服务器注册表,一个固定的MCP服务器,一些挂载脚本和代理遵循的一套规则。您需要自带服务器和克劳德代码。
---
## 要求
- **克劳德代码** 在VS Code中,带有活跃的Anthropic计划。
- **一个或多个远程Linux服务器** ,您可以通过SSH到达,每个服务器都有`bash`,`python3`和`git`。`ripgrep`(`rg`)很好(快速搜索);如果没有,搜索会退回到`grep`。
- **无密码SSH** 到这些服务器通过`~/.ssh/config`(`ssh <host> true`必须成功且无提示 - 代理无法输入密码)。
- 本地工具:`tmux` ≥ 3.0,`uv`(提供`uvx`),以及`rclone`(仅用于文件树挂载)。
## 快速入门
```bash
# 1. 安装本地依赖项(macOS)
brew install tmux rclone
curl -LsSf https://astral.sh/uv/install.sh | sh # 如果您还没有uv
# 2. 克隆并在VS Code中打开
git clone https://github.com/avanturist322/quarterdeck.git
code quarterdeck
```
打开文件夹,克劳德代码扩展程序会检测到[.mcp.json](.mcp.json)并要求批准项目MCP服务器`remote-ssh` - 批准它。代理现在拥有`remote_*`工具。
```bash
# 3. 检查先决条件
tests/smoke.sh # 预期 "0 fail"
```
**添加服务器。** 在`~/.ssh/config`中添加一个别名(基于密钥,无密码),然后在[remotes.conf](remotes.conf)中添加一行 - `name ssh-host path-to-repo`:
```
# 共享账户;有rg,git,python3。
example-gpu-box my-gpu-box /home/you/code/awesome-project
```
*名称* 是您在聊天中引用服务器的方式;*ssh-host* 是`~/.ssh/config`中的别名;*路径* 是服务器上的存储库目录。您也可以直接告诉代理"添加一个服务器example-gpu-box,主机my-gpu-box,存储库/home/you/code/awesome-project",它将追加该行并验证连接。
**工作。** 无需手动运行 - 只需与代理聊天,指定服务器:
> 我们来处理example-gpu-box。找到`load_config`的定义并将其重命名为`read_config`,更新所有调用站点。
代理读取`remotes.conf`中的主机和路径,运行`remote_connect`(始终带有`agent_forwarding=false`),检查`git status`(是否有人在共享帐户上遗留了未提交的工作?),使用`remote_grep`搜索(**在服务器上** - 任意存储库大小),读取,编辑,运行测试,并显示差异。代理遵循的规则在[CLAUDE.md](CLAUDE.md)中。
**浏览树。** `bin/rmount example-gpu-box`使服务器的存储库出现在资源管理器中为`mounts/example-gpu-box/` - 只读,延迟(打开文件仅获取其字节),因此200 TB存储库像本地文件夹一样浏览。`bin/rumount example-gpu-box`将其删除。
**验证服务器端到端:** `python3 tests/acceptance.py example-gpu-box`(〜1分钟,预期`0 fail`)。详细信息请参见[tests/ACCEPTANCE.md](tests/ACCEPTANCE.md)。
## 项目文件夹:并行处理多个存储库
每个远程存储库都有一个文件夹[projects/](projects/)`<name>/`(名称与`remotes.conf`和挂载中的名称匹配)。里面有三个具有不同角色的文件:
| 文件 | 谁编写它 | 内容 |
|---|---|---|
| `PROJECT.md` | 您 | 护照:服务器,目标,上下文,约束 |
| `TASKS.md` | 您(代理勾选完成) | 任务:进行中 / 待办 / 已完成 |
| `JOURNAL.md` | 代理 | 会话日志:已完成的内容,遗留问题(作业,日志) |
循环:您在`TASKS.md`中编写任务 → 说“让我们处理`<name>`” → 代理读取`PROJECT.md`和`TASKS.md`,连接并执行 → 完成后,它会勾选任务并追加到`JOURNAL.md`。新的聊天会话不会丢失任何上下文 - 代理从这些文件中恢复它。参见[projects/example-gpu-box/](projects/example-gpu-box/)的填充示例,以及[projects/_template/](projects/_template/)以启动新项目(复制到`projects/<name>/`,填写`PROJECT.md`,在`remotes.conf`中添加一行 - 或要求代理“设置项目...”)。
## 跟踪进度
**实时查看代理。** 每个连接都是笔记本上的tmux会话。在VS Code集成终端中:
```bash
tmux ls # 活动会话
tmux attach -t remote-ssh-mcp/<host> # 实时查看代理的命令
# 断开:Ctrl-b d (不要关闭会话!)
```
代理在服务器上运行的每个命令都是可见的 - 透明度而不是魔术。
**长时间运行的作业(训练等)。** 说“启动训练并关注日志”。代理在`~/.quarterdeck-jobs/<job>-<date>.log`服务器上启动它,日志在`~/.quarterdeck-jobs/`中。聊天不会被阻塞,作业在连接断开后继续运行。询问“训练进展如何”,代理会跟踪日志并`pgrep`进程。您可以关闭笔记本;在后续会话中,说“检查example-gpu-box上的训练”,代理会找到日志。
## 工作原理
```
笔记本(macOS) 服务器(Linux)
┌─────────────────────────────────────┐ ┌──────────────────────────┐
│ VS Code + 克劳德代码扩展 │ │ (通常是共享帐户) │
│ │ │ │ │
│ ├─ MCP服务器 remote-ssh(uvx) │── ssh ───▶│ 任意大小的存储库 │
│ │ └─ tmux会话每主机 │ (tmux) │ (无需完整复制) │
│ │ remote_run/read/write/… │ │ │
│ │ │ │ │
│ └─ bin/rmount(rclone nfsmount) │── sftp ──▶│ 相同的树形结构,可在资源管理器中查看 │
│ mounts/<name>/ — 只读 │ (延迟) │ │
└─────────────────────────────────────┘ └──────────────────────────┘
```
两个独立的通道:
- **工作通道 - MCP服务器 [remote-ssh-mcp](https://github.com/avanturist322/remote-ssh-mcp)** (从[.mcp.json](.mcp.json)自动启动)。每个服务器一个持久的tmux+SSH会话:shell状态(cwd,venv,变量)在命令之间保持,就像您自己坐在SSH上一样。代理的工具:`remote_connect`,`remote_run`,`remote_read`,`remote_write`,`remote_edit`,`remote_grep`,`remote_glob`,`remote_status`,`remote_disconnect`。
- **眼睛通道 - 只读挂载** 通过`rclone nfsmount`([bin/rmount](bin/rmount)):存储库树在VS Code资源管理器中显示为`mounts/<name>/`。无需macFUSE,无需管理员权限。列表和字节按需加载;不会写入磁盘(缓存≤1 GB)。
### 大型存储库:重要的事情
- **不会完整复制** - 代理的硬性规定。搜索(`remote_grep`,`remote_glob`)在服务器上运行;只有匹配的行通过网络返回。
- `remote_read`每次调用最多返回1 MB,对于大于〜300 KB的文件,以**256 KB块**(`offset`/`limit`)读取 - 调用大限制的单个调用会因tmux通道限制而挂起约2分钟。这被测试覆盖(1.5 MB → 6块 → 字节对字节)。
- 挂载是延迟的:目录列表是一个sftp请求;打开文件仅获取其字节。rclone缓存上限为1 GB并自动失效。
## 共享帐户上的安全性
多个人员通常在这些服务器上以一个用户身份工作。因此规则(内置于[CLAUDE.md](CLAUDE.md);代理自身遵循):
- **`agent_forwarding=false`,始终。** 使用ssh-agent转发(`ssh -A`)时,代理套接字可被同一用户服务器上的每个进程访问 - 同一帐户下的同事可以使用您的密钥。接受度测试会检查这一点。
- **Git卫生。** 编辑前后 - `git status`/`git diff`:他人未提交的工作立即可见,代理报告并予以保留。`remote_edit`是读取-替换-写入:如果文件在下方更改,旧字符串消失,则编辑失败,其他人的更改存活(由“与同事编辑冲突”的测试覆盖)。
- **破坏性操作** (`rm -rf`,`kill`,`git reset/checkout/clean/push`,切换分支,安装软件包)仅在明确确认后发生。
- **透明度:** 每个代理命令在tmux会话中可见(`tmux attach`) - 包括对同一帐户上的同事可见。
## 故障排除
| 症状 | 原因和解决方法 |
|---|---|
| ssh输出中的`Address already in use` | `~/.ssh/config`中的`LocalForward`与第二个连接冲突。不是错误 - 脚本使用`ClearAllForwardings=yes`;如果MCP服务器很吵闹,请添加一个无转发别名。 |
| `remote_connect`超时(〜45秒) | 插件从未看到提示:自定义PS1与检测器不匹配(`[$#>❯»]\s*$`)或MOTD非常慢。在服务器的`~/.bashrc`中简化PS1以适应非交互式会话。 |
| 会话“挂起”(命令不返回) | shell可能正在等待更多输入。`tmux attach -t remote-ssh-mcp/<host>`查看;如果无法修复,`tmux kill-session -t remote-ssh-mcp/<host>`并重新连接。 |
| `REMOTE HOST IDENTIFICATION HAS CHANGED` | 服务器的主机密钥已更改(重新安装/新IP)。确认后,`ssh-keygen -R <host>`。 |
| `remote_run`返回退出255 | 这是ssh自己的代码:连接断开或未打开。检查`ssh <host> true`,网络,VPN。 |
| `remote_read`“挂起”〜2分钟然后失败 | 您请求的块太大。文件> 〜300 KB - 仅限256 KB块(`limit=262144`,参见上文)。每个调用的限制为1 MB。 |
| `rmount`显示“挂载未出现” | 检查`ssh <host> true`。如果正常,请查看日志:`pkill -f "rclone nfsmount.*<name>"`并手动运行,不带`--daemon`,带`-vv`。在精简的sshd(例如jupyter)上,`shell_type=unix,disable_hashcheck=true`选项内置到rmount中。 |
| 挂载无法释放 | `bin/rumount <name>`自行升级:`umount`→强制→停止rclone进程。关闭从挂载打开的任何文件并重试。 |
## 固定MCP服务器
在[.mcp.json](.mcp.json)中,remote-ssh-mcp固定到特定提交 - 防止上游交换:增加版本号是该文件的刻意编辑。要更新:在[存储库](https://github.com/avanturist322/remote-ssh-mcp)中选择新的提交/标签,替换`@`后的哈希,重启会话,并对服务器运行`python3 tests/acceptance.py`。
> 该项目固定了[avanturist322/remote-ssh-mcp](https://github.com/avanturist322/remote-ssh-mcp)的分支以保持长期稳定。原始版本是[Square596/remote-ssh-mcp](https://github.com/Square596/remote-ssh-mcp) - 感谢上游作者。
## 存储库布局
```
quarterdeck/
├── CLAUDE.md # 代理规则 + 指向注册表的指针(始终在上下文中)
├── remotes.conf # 服务器注册表:名称,ssh-host,存储库路径
├── projects/<name>/ # 护照,任务和每个项目的日志(_template - 模板)
├── .mcp.json # 远程ssh MCP服务器(uvx,提交固定)
├── bin/rmount,bin/rumount # 服务器文件树的只读挂载
├── bin/lmount # 本地存储库的实时挂载(混合项目)
├── mounts/<name>/ # 挂载点(gitignored)
├── tests/smoke.sh # 先决条件和连接性
├── tests/acceptance.py # 完整的MCP JSON-RPC端到端测试(30个检查)
├── tests/ACCEPTANCE.md # 验收:自动化 + 手动检查清单
├── .vscode/settings.json # mounts/ 排除在VS Code索引之外
└── .claude/settings.json # 远程_*和bin/*的权限
```
## 许可证
[MIT](LICENSE) © 2026 Egor Cherepanov