关于 Corral
Corral 是用于整理多个代码仓库克隆的命令行工具,可从多个代码托管平台克隆并管理本地工作区。它还提供 MCP 服务,让编码 Agent 搜索本地克隆中的代码和符号,无需网络调用。
主要功能
- 01跨托管平台克隆并整理仓库
- 02增量同步与并发处理
- 03跨仓库执行 Git 命令
- 04交互式终端选择界面
- 05提供本地工作区 MCP 服务
适用场景
- 01集中整理多个代码托管平台的仓库
- 02批量同步或执行跨仓库命令
- 03让编码 Agent 搜索本地代码和符号
MCP 相关
`corralctl mcp` 将本地工作区暴露给编码 Agent,使其可跨克隆仓库搜索代码与符号;该查询无需网络调用。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
docker run -i --rm ghcr.io/sebastienrousseau/corral:0.0.36本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
ghcr.io/sebastienrousseau/corral:0.0.36stdio工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
corralctl
使用便于 Finder 浏览的集合、生态系统和元数据,自动从 GitHub、GitLab、Gitea、Forgejo、Codeberg 和 Bitbucket 克隆并整理代码仓库。
目录
开始使用
功能与能力
- 功能 — 结构化布局、并发与安全
- 架构 — 从 API 获取到按仓库分发的端到端流程
- 交互式 TUI 模式 — 快捷键、命令与自动补全
- 布局自定义 — Apple 风格集合、生态系统与自定义模板
- 智能同步 — 网络优化的增量更新
- 执行模式 — 并发批量执行 Git 命令
- 镜像到其他代码托管平台 —
corralctl sync将目录树推送到 GitLab、Gitea、Forgejo、Codeberg、Bitbucket 或 GitHub - MCP 服务 — 向 AI 编码 Agent 开放本地工作区
- 跨仓库符号查找 — 查找每个克隆仓库中任意内容的定义位置
参考与运维
项目
- 文档 — 手册、API 参考、开发者文档
- 何时不应使用 corralctl — 坦诚说明限制
- 要求与工具链政策 — Go 版本下限及其调整时机
- 稳定性保证 — 此处所说的重大变更意味着什么
- 安全与加固 — 漏洞报告、安全状况、模糊测试
- 许可证
安装
mise(macOS / Linux)
mise use -g github:sebastienrousseau/corralctl
这会安装最新发布的 corralctl 二进制文件,并由 mise 与其他工具一并管理。
Homebrew(macOS)
brew install sebastienrousseau/tap/corralctl
这里的 Homebrew 使用的是 cask,这是一种仅限 macOS 的机制——在 Linux 上运行 brew install 会被拒绝。在 Linux 上,请使用 .deb/.rpm 软件包或每个发布版本附带的 tarball,也可以通过 mise 或 Go 工具链安装。
Arch Linux(AUR)
yay -S corralctl-bin # or: paru -S corralctl-bin
Nix(任何平台)
nix run github:sebastienrousseau/corralctl -- --help # run without installing
nix profile install github:sebastienrousseau/corralctl # install
flake 会随二进制文件一并提供 man 手册页和 Shell 自动补全;nix develop 则会提供一个 Shell,其中包含项目 CI 检查所需的所有工具,并由 flake.lock 锁定版本。
Go 工具链
go install github.com/sebastienrousseau/corralctl/cmd/corralctl@latest
安装到 $(go env GOPATH)/bin(如果设置了 $GOBIN,则安装到该目录)。请注意,以这种方式构建的二进制文件会报告 corralctl version dev:实际版本由发布流水线通过 -ldflags 写入,而 go install 不会应用此参数。如果需要 --version 显示有效版本,请使用发布制品。
从源代码构建
需要 Git 和不低于 go.mod 中 go 指令指定版本的 Go,但不能使用 Go 1.27.0 至 1.27.2,因为这些版本存在可被远程利用的 crypto/x509 安全公告(参见最低工具链政策):
git clone https://github.com/sebastienrousseau/corralctl.git
cd corral
make install # installs ~/.local/bin/corralctl
平台先决条件
macOS
brew install go git gh
Fedora / RHEL
sudo dnf install golang git gh
快速开始
使用所有者名称(GitHub 用户名或组织)运行 corralctl clone,即可克隆所有仓库,并自动将它们整理到清晰的本地目录层级中:
# Log in to GitHub CLI first (or set GITHUB_TOKEN)
gh auth login
# Clone and organise every repository for your profile
corralctl clone my-username
直接使用 corralctl my-username 也能完成相同操作。一个二进制文件,一个基础命令,所有操作都是它的子命令:
| 命令 | 功能 |
|---|---|
corralctl clone <owner> | 克隆缺失的仓库,将过时的仓库拉取到最新状态,并整理到相应目录结构中 |
corralctl sync --to <forge> | 将整理好的目录树镜像到另一个代码托管平台——参见镜像到其他代码托管平台 |
corralctl status | 清点本地克隆及其状态 |
corralctl plan <owner> | 预览同步计划,不对磁盘进行任何更改 |
corralctl prune <owner> | 移除上游已不存在的克隆,但会拒绝移除含有未发布工作的克隆 |
corralctl exec <cmd> | 在所有克隆上运行命令——参见 Exec Mode |
corralctl mcp | 向 AI Agent 提供工作区服务——参见 MCP Server |
这会将本地目录结构整理成结构化镜像:
~/Code/
├── Public/
│ ├── Go/
│ │ └── corral/
│ ├── Rust/
│ │ └── my-crate/
│ └── Web/
│ └── project.github.io/
├── Private/
│ └── Python/
│ └── internal-tool/
├── Forks/
│ └── Rust/
│ └── upstream-project/
└── Work/
在 macOS 上,corralctl 还会为仓库文件夹写入原生 Finder 标签,同时保留你自行添加的标签。这样既能保持物理目录层级浅而简洁,也能让 Finder 搜索和智能文件夹在不同生态系统中发挥作用。
功能
| 功能 | 描述 |
|---|---|
| Apple 风格的目录布局 | 将源代码仓库分类到 Public/、Private/ 和 Forks/,并使用 Go、Rust、Python 和 Web 等便于 Finder 识别的生态系统名称。 |
| Finder 标签 | 应用 macOS 原生生命周期颜色和可搜索的可见性、生态系统、所有者、派生仓库、归档、模板及镜像元数据,同时不替换个人标签。 |
| 智能同步 | 比较远程 pushed_at 元数据,以跳过不必要的网络调用,将同步速度提升 10 到 50 倍。 |
| 交互式选择 | 功能齐全的终端界面(TUI)选择面板,可用于搜索、预览和选择要克隆的仓库。 |
| 旧版布局迁移 | 自动将现有的扁平目录布局迁移到新结构,并清理空文件夹。 |
| 并发处理 | 并发处理克隆和拉取操作,并支持配置工作线程数量上限(--concurrency)。 |
| 批量命令 | 使用 exec 在所有已克隆的仓库上并发批量执行 Git 命令。 |
| 零配置 | 无需配置文件——采用简单合理的默认设置,开箱即用。 |
架构
单次运行会解析 git,从代码托管平台(GitHub、GitLab、Gitea、Forgejo、Codeberg 或 Bitbucket)并发获取所有仓库;你也可以选择交互式挑选部分仓库,随后由工作线程池分派克隆、智能同步或跳过操作。智能同步会查询每个仓库对应的 .corral-state.json 旁文件;如果上游 pushed_at 未变化,就会跳过 git pull。
graph TD
A[User Shell] --> B{corralctl}
B --> C[Pre-flight: exec.LookPath git]
C -- Missing --> Z1[Exit: git not found on PATH]
C -- OK --> D[Resolve auto/token/gh auth]
D --> E[Forge API: list repos]
E --> E1["First page<br/>+ resp.LastPage"]
E1 --> E2{LastPage > 1?}
E2 -- Yes --> E3["Concurrent fetch<br/>pages 2..N (max 5)"]
E2 -- No --> F
E3 --> F[Filtered repository set]
F --> F1{TUI selector?}
F1 -- "--select" --> F2[Interactive TUI<br/>/sort, /all, /none, search]
F1 -- No --> G
F2 --> G[Layout template render<br/>Collection/Bucket/Name]
G --> H["Worker pool<br/>(--concurrency)"]
H --> I{Already cloned?}
I -- No --> J["git clone (+ blobless/<br/>depth/single-branch)"]
I -- "Yes (--no-sync)" --> K[SKIP]
I -- Yes --> L{Smart sync:<br/>pushed_at advanced?}
L -- No --> M[SKIP up-to-date]
L -- "Yes (or --force-sync)" --> LG{"Operation in progress,<br/>local commits ahead,<br/>or no upstream?"}
LG -- Yes --> LR[ERROR: pull refused]
LG -- No --> N[git pull --rebase --autostash]
N --> N1["+ optional submodule update<br/>(--ignore-submodule-failures)"]
J & N1 --> O[Stamp .corral-state.json]
O & K & M & LR --> P{All workers done?}
P -- No --> H
P -- Yes --> Q[Cleanup empty legacy dirs]
Q --> R{--orphans?}
R -- Yes --> S[Walk baseDir<br/>parse .git/config]
R -- No --> T[Print summary]
S --> T
交互式 TUI 模式
传入 -i 或 --interactive 标志,即可启动选择面板:
./corralctl -i my-username
快捷键
[space]— 切换当前仓库的选中状态。[ctrl+a]— 选中当前筛选结果中的所有仓库。[ctrl+n]— 取消选中当前筛选结果中的所有仓库。[/]— 进入命令/筛选模式。[enter]— 确认选择并开始克隆/同步。[esc]— 静默退出应用。
会话内命令
在 TUI 中按 / 进入命令模式。命令支持基于前缀的自动补全(按 [tab] 或 [right-arrow] 自动补全):
/sort <field>— 对仓库排序。字段:name— 按仓库名称的字母顺序排序。language/lang— 按语言的字母顺序排序。visibility/vis— 按可见性(Private/Public)的字母顺序排序。public— 将公共仓库优先排在顶部。private— 将私有仓库优先排在顶部。
/all— 选择所有筛选后的仓库。/none— 取消选择所有筛选后的仓库。/exit//quit— 取消并静默退出。/help— 显示会话内帮助面板浮层。
布局自定义
默认情况下,corralctl 使用 Apple 风格的布局 {{.Collection}}/{{.Bucket}}/{{.Name}}。Fork 使用 Forks 集合,而 .github.io 仓库无论检测到何种语言,都会使用 Web 分类。你可以使用 --layout 标志覆盖此设置:
./corralctl --layout "{{.Owner}}/{{.Name}}" my-org
支持的占位符:
{{.Owner}}— GitHub 所有者名称。{{.Name}}— 仓库名称。{{.Collection}}— 规范根目录(Public、Private或Forks)。{{.Bucket}}— Finder 显示的生态分类(Go、Rust、Web等)。{{.Language}}— 转换为小写的主要语言。{{.Visibility}}— 转换为小写的仓库可见性。
macOS Finder 颜色标签与标记
macOS 上默认启用 Finder 标记,可通过
--finder-tags=false 禁用。corralctl 会使用 macOS 原生扩展属性(com.apple.metadata:_kMDItemUserTags 和
com.apple.FinderInfo)自动为每个仓库文件夹分类,并应用可视化颜色圆点和文件夹颜色标签:
高信号运维分类体系
| 颜色 | 标记名称 | 含义与触发信号 |
|---|---|---|
| 🔴 红色 | Needs Fix | 同步错误或合并冲突。发生合并冲突、跟踪分支分歧,或需要人工干预的同步失败时应用。 |
| 🟢 绿色 | In-Flight | 正在进行的主动修改。存在未提交更改、未推送提交或暂存时应用。 |
| 🟣 紫色 | Worktree / Experiment | 关联工作树与实验性克隆。应用于活跃的关联工作树、上游开源 Fork、模板仓库和镜像。 |
| 🔵 蓝色 | Pristine | 干净、已同步的事实来源。仓库干净、已推送且与上游同步时应用。 |
| 🟡 黄色 | On Hold | 已归档的仓库。远程仓库已归档且为只读时应用。 |
| ⚪ 灰色 | Dormant | 未触碰的参考仓库。仓库干净且超过 60 天没有收到提交时应用。 |
| 🟠 橙色 | New Repo | 未跟踪的本地候选仓库。corralctl adopt 会将其应用于未受管理的本地仓库。 |
Finder 文件夹颜色同步
corralctl 会同步 Spotlight 元数据(_kMDItemUserTags)和 macOS 原生
Finder 目录标签(com.apple.FinderInfo 字节 9 的第 1–3 位)。这可确保
Finder 窗口的列表视图、图标徽标和 Finder 侧边栏颜色筛选器能实时反映
每个仓库的准确运维状态。
你可以随时审查并重新同步所有工作区文件夹标记:
corralctl doctor ~/Code --refresh-tags
可搜索的元数据标签
除了彩色圆点,corralctl 还会写入纯文本标签,macOS Finder 和 Spotlight 会自动为其建立索引:
Ecosystem: <Language>:可按语言类别搜索(例如,Ecosystem: Go、Ecosystem: Rust、Ecosystem: Python、Ecosystem: Web)。Visibility: <Visibility>:Visibility: Public或Visibility: Private。Collection: <Collection>:Collection: Public、Collection: Private、Collection: Forks或Collection: Work。Owner: <Owner>:仓库所有者或组织命名空间(例如,Owner: sebastienrousseau)。- Forge 标识:
GitHub、GitLab、Gitea、Forgejo、Codeberg或Bitbucket。 - 仓库特征:
Fork、Template、Mirror、Archived。
Finder 搜索与智能文件夹
你可以在 macOS Finder 中组合这些标签,整理和浏览代码:
- Finder 侧边栏:点击 Finder 侧边栏中的任意颜色(例如,点击 Green 查看进行中的项目,或点击 Blue 查看未经修改的参考克隆)。
- Spotlight 与 Finder 搜索:在 Finder 中按
Cmd+F并搜索:tag:"In-Flight"- 查看有未提交或未推送更改的活跃项目tag:Pristine- 查看已验证干净的克隆tag:"Needs Fix"- 查找损坏或存在冲突的仓库tag:Go或tag:"Ecosystem: Go"- 按语言筛选所有集合中的内容
- 智能文件夹:将搜索保存为 Finder 侧边栏中的持久智能文件夹。
保留个人标签
corralctl 绝不会删除或覆盖用户定义的标签(例如 Client、Urgent 或 Review)。它会读取现有文件标签,仅更新受管理的分类体系,并在不丢失数据的情况下妥善合并你的自定义标签。
智能同步
corralctl 会将同步元数据存储在每个仓库的 .git/ 文件夹旁边的 .corral-state.json 伴随文件中:
- 避免冗余拉取: 如果远程仓库自上次同步以来没有收到新的推送,则完全跳过
git pull。 - 覆盖设置: 要绕过智能检查并强制 corralctl 执行完整的
git pull,请传入--force-sync标志。 - 完全跳过同步: 传入
--no-sync,跳过所有已克隆仓库的更新。
执行模式
在整理后的仓库中并发执行任意 shell 命令:
# Check git status for all Go/Rust private repositories
./corralctl exec "git status -s" --languages go,rust --visibility private
- **Shell:**命令会在 Unix 上通过
/bin/sh -c运行,在 Windows 上通过cmd.exe /C运行,无论$SHELL指向什么。如需使用其他 shell,请在 命令中指定。 - 截止时间:
--timeout 2m为每个仓库单独设置截止时间(默认值为0,表示不限制)。超时的命令会与其子进程一起被终止,并计为失败。 - 集合:
--visibility可接受all或任意顶层集合:public、private、work或forks。 - 机器可读输出:
--output json或--output ndjson会为每个仓库写入一条记录 (repo、exit_code、duration_ms、stdout、stderr、timed_out)。
镜像到其他代码托管平台
corralctl sync 是工作流的出站部分:clone 从一个代码托管平台拉取内容,sync 则推送到其他平台,让整理好的目录树成为你关注的每个主机上镜像的事实来源。
export GITLAB_TOKEN=glpat-… # scope: api
export GITEA_TOKEN=… # scope: write:repository
corralctl sync --to gitlab --to gitea@https://git.example.com --dry-run
corralctl sync --to gitlab --to gitea@https://git.example.com
对于每个目标平台上的基础目录下的每个仓库,sync 会在目标平台尚不存在该仓库时创建它,设置一个以代码托管平台命名的远程仓库,并通过一次往返完成推送:
git push --prune --no-verify <forge> refs/heads/*:refs/heads/* +refs/tags/*:refs/tags/*
推送完成后,目标平台上会有每个本地分支和标签,不会有其他内容。分支绝不会被强制推送:如果目标平台上的分支已有更新,操作会被拒绝并报告,而不会覆盖。标签遵循本地命名空间。
“本地”指克隆自身的分支(refs/heads/*),因此目标平台镜像的是你的克隆,而不是其源仓库。通过 corralctl clone 或 git clone 创建的克隆只会在本地保留默认分支;其他所有上游分支仅作为远程跟踪引用(origin/<name>)存在,不会被推送。由于推送会清理目标平台上的多余分支,这些分支也会从目标平台上已存在的位置删除,直接在目标平台上创建的分支也一样。要保留某个分支,请在运行 sync 前在本地检出它(git switch <name>)。
只有满足以下两个条件时,新目标仓库才会创建为公开仓库:源代码托管平台上次由 corralctl clone 列出该仓库时将其报告为公开仓库(此信息记录在克隆的状态 sidecar 文件中),且该克隆位于 Public/ 目录下。其他情况都会创建为私有仓库,包括 corral 未创建的克隆,以及在 0.0.54 之前创建的克隆。仅凭目录名称无法确定可见性,而且上游已设为私有的仓库仍可能位于 Public/ 下。请先为所有者运行 corralctl clone,确保记录是最新的,再运行 sync;--dry-run 会显示每个目标仓库将采用的可见性。
目标地址格式为 <forge>[:<owner>][@<url>]:
--to | 镜像到 |
|---|---|
gitlab | gitlab.com,位于令牌所属账号下 |
gitlab:my-group | gitlab.com,位于某个群组下 |
github:my-org | github.com,位于某个组织下 |
codeberg · bitbucket:workspace | 公共实例 |
gitea@https://git.example.com | 可自托管的 Gitea 或 Forgejo |
凭据与 clone 用于从代码托管平台列出仓库的环境变量相同:GITHUB_TOKEN(或 gh CLI)、GITLAB_TOKEN、BITBUCKET_TOKEN,以及 Gitea 系列使用的 GITEA_TOKEN、FORGEJO_TOKEN 或 CODEBERG_TOKEN;这些变量也都接受带 CORRAL_ 前缀的形式。默认使用 HTTPS 时,同一个令牌会用于验证推送身份,且作用域限定在相应代码托管平台的源站;令牌绝不会写入 .git/config。--protocol ssh 则使用你的密钥。
内置三种拒绝情况。两个本地仓库同名(例如将 fork 与原仓库放在一起)时,它们会对应到同一个目标路径,因此会报告这两个仓库,且不会推送其中任何一个;目录树中的其他仓库会继续处理。绝不会将仓库推送到其 origin 所在的代码托管平台——corral 会从六种代码托管平台克隆,因此目录树中可能包含一个其 origin 本身就是目标平台的克隆,而针对自己的上游执行清理操作并不算镜像。如果目标平台上已有同名但可见性不同的仓库,也会报错,绝不会静默复用。
结果会以 --output text、json 或 ndjson 格式输出到 stdout;只要有任何仓库失败,退出代码就非零,因此 cron 作业可以据此发出告警。此命令取代了独立的 corral-sync 工具,并保留了 gitlab 和 gitea 远程名称,以便现有克隆可以原样沿用。
MCP 服务(面向 AI Agent)
corralctl 提供一个 Model Context Protocol 服务,将本地由 corralctl 组织的工作区开放给 AI 编码 Agent 使用——Claude Code、Cursor、Cline、Codex CLI、Aider,以及任何支持 MCP 的工具。在默认只读模式下,不会发起网络调用,也不会联系 GitHub API;该服务只是访问磁盘上已有克隆的窗口。(--enable-mutations 会添加 corral_clone_repo 和 corral_sync_repo,它们会调用网络——通过 shell 执行 git。仍然不会联系 GitHub API。)
GitHub 自带的 MCP 服务覆盖远程 API(问题、PR、搜索),而 corral-mcp 覆盖了只有它才能提供的维度——你的本地镜像,按可见性和语言组织,无需往返请求即可查询。
工具
corral_list_repos— 按可见性 / 语言 / 名称 / 同步状态筛选本地克隆corral_find_repo— 将模糊名称解析为一个克隆(存在歧义时返回候选项)corral_get_repo_metadata— 获取一个克隆的完整元数据,包括当前分支corral_status_summary— 工作区摘要:按可见性和语言统计数量corral_workspace_index— 一次调用获取完整的结构化索引corral_find_symbol— 查找符号在所有克隆中的声明位置corral_search_code— 查找文本在所有克隆中的出现位置corral_repo_overview— 一次调用了解一个仓库的结构corral_discover_repos— 发现本地磁盘上未跟踪或未管理的仓库
写入工具(v0.0.12,通过 --enable-mutations 选择启用):
corral_sync_repo— 对一个克隆运行git pull --rebase --autostash,并执行corralctl clone拉取前的检查:如果克隆没有 origin,或自读取索引后 origin 已发生变化,或没有提交,或当前分支不是origin/HEAD指定的默认分支,则会拒绝操作,确保 Agent 无法变基功能分支。它与corral_delete_repo使用相同的逐克隆锁。与sync一样,如果正在进行变基、合并、拣选、还原或二分查找,或者分支包含其上游没有的提交,或分支没有上游,也会拒绝操作。corral_clone_repo— 将 URL 克隆到沙盒化的目标路径corral_adopt_repo— 接管本地仓库,可选择迁移位置并创建远程仓库。自托管的forge_url必须是操作者传给corralctl mcp --forge-url的 URLcorral_delete_repo— 移除克隆。需要--enable-destructive-mutations。如果存在未提交 / 未推送的更改,则会拒绝操作;并会要求人员批准每次删除
每次变更都会向
$XDG_STATE_HOME/corral/mutations.log(或 ~/.local/state/corral/mutations.log)
写入一条 JSONL 审计记录,其中包含工具、目标、参数、结果和时间戳。每次变更写入两条记录:操作开始前写入一条持久化的意图记录,完成后写入一条通过操作 ID 关联的记录。如果无法记录意图,则不会执行变更。
使用 --audit-log <path> 覆盖日志位置。文件达到 8 MiB 时会轮转,并保留三个历史版本(mutations.log.1 … .3),避免长时间运行的服务占满磁盘。
提示词(v0.0.12)
explain_workspace— 要求 Agent 通过只读工具检查工作区并总结identify_stale_repos— 要求 Agent 找出.corral-state.json显示近期未同步的克隆(默认:30 天)
资源
corral://workspace/indexcorral://repo/{owner}/{name}/statecorral://repo/{owner}/{name}/treecorral://repo/{owner}/{name}/file/{path}(上限为 1 MiB;防止路径遍历)
安装
Claude Code:
claude mcp add corral -- corralctl mcp
Cursor / Cline(mcp.json):
{
"mcpServers": {
"corral": {
"command": "corralctl",
"args": ["mcp"]
}
}
}
Docker(无需本地安装) — 与 MCP Registry 声明的二进制文件相同,并挂载到你的工作区:
{
"mcpServers": {
"corral": {
"command": "docker",
"args": [
"run", "--rm", "-i",
"--user", "1000:1000",
"-v", "${HOME}/Code:/workspace:ro",
"ghcr.io/sebastienrousseau/corralctl:latest",
"mcp", "--root", "/workspace"
]
}
}
}
参数说明:
--user 1000:1000— 替换为你的主机 UID:GID(id -u:id -g),这样容器化扫描器就能以与你的主机用户相同的权限读取挂载的工作区。如果不这样做,镜像会在容器内以系统 UID 运行,并在工作区中任何对组用户或其他用户设为私有的目录上遇到permission denied。-v … :ro— 只读挂载。v0 工具本身就是只读的;挂载时指定:ro既说明了这一点,也能防止恶意 Agent 要求服务执行它无权执行的写入操作。--root /workspace— 容器内的沙盒根目录。所有工具和资源路径检查都限定在此前缀范围内;无论 Agent 请求什么,范围之外的请求都会被拒绝。
将其他根目录设为沙盒(默认使用 --base-dir,然后是 $HOME/Code):
corralctl mcp --root /custom/workspace
传输方式
stdio 是默认方式:客户端启动 corralctl mcp,并管理管道。
另外两种方式会监听 --host 和 --port,供连接到他人已启动的服务的客户端使用。
| 命令 | 传输方式 | 端点 | 协议修订版本 |
|---|---|---|---|
corralctl mcp | stdio | — | 在 initialize 时协商 |
corralctl mcp --transport streamable-http --host 127.0.0.1 --port 8000 | Streamable HTTP | http://127.0.0.1:8000/mcp | 2026-07-28(无状态,server/discover)和 2025-11-25(initialize、Mcp-Session-Id),共用一个端点 |
corralctl mcp --transport sse --port 8001 | HTTP+SSE(旧版) | http://127.0.0.1:8001/sse | 2024-11-05 |
--http 127.0.0.1:7777 是 --transport streamable-http 的旧写法,仍然可用。
所有监听型传输方式默认绑定到 loopback:--host 0.0.0.0 或
--http :7777(绑定到所有网络接口)都会被拒绝,因为此服务会暴露其根目录下的所有仓库。只有同时提供 bearer token 时,--allow-remote 才会解除此限制;token 可从文件或环境中读取:
export CORRAL_MCP_TOKEN="$(cat ~/.config/corral/mcp-token)"
corralctl mcp --transport streamable-http --host 0.0.0.0 --allow-remote
# or: corralctl mcp ... --allow-remote --token-file ~/.config/corral/mcp-token
缺少 Authorization: Bearer <token> 请求头或 token 错误的请求,会收到带有 WWW-Authenticate 挑战的 401 响应。--token 仍然可用,但已弃用:命令行中的任何内容都能通过 ps 被机器上的所有用户看到。此服务使用纯 HTTP,没有 TLS 监听器,因此 token 和所有响应在网络传输时都未加密,除非前面有负责终止 TLS 的反向代理;当服务启动并监听可路由地址时,会在 stderr 中提示这一点。此服务不支持 OAuth 资源服务器模式。
浏览器会在每个请求中发送 Origin 请求头,服务会拒绝未列在 --allowed-origins 中的来源。默认情况下,loopback 来源不受信任,因为任何本地开发服务器都可能使用它;请列出浏览器客户端运行所在的页面,例如 --allowed-origins http://localhost:6274。非浏览器客户端不会发送 Origin,因此不受影响。
安全
- 默认只读。
--enable-mutations可启用克隆和同步。删除还需要--enable-destructive-mutations;每次变更都会将意图和完成记录写入审计日志。 - 删除采用默认拒绝策略。 MCP 和 CLI 的清理操作会拒绝以下仓库:工作树有更改;任何本地分支上的提交无法从远程分支到达;存在储藏;存在仅本地拥有或与远程分支有分歧的标签;存在被 Git 忽略的内容(
.env文件、本地数据库、缓存——这些是克隆中最难恢复的内容,而且普通的git status无法显示);子模块中有尚未发布的提交;目标根本不是 Git 仓库;或存在 Git 无法验证的任何状态。每次拒绝都会说明具体原因,并写入审计日志。 - 防止路径遍历。 文件资源查找会规范化所选仓库根目录和候选路径,阻止通过
..和符号链接逃逸到相邻仓库或工作区之外。搜索、符号索引和文件资源绝不会跟随仓库中提交的符号链接。 - 删除需逐次批准。 启用
--enable-destructive-mutations后,每次删除执行前,都会通过 MCP elicitation 提请人员批准。上述层层拒绝机制可以防止误操作;而它能防止被说服的 Agent 选择那个通过所有检查的克隆——再多提示词也做不到这一点。只有在你愿意承担数据丢失风险的无人值守工作区中,才传入--no-confirm-deletes。 - 默认使用 stdio;否则使用 loopback。 不传入
--transport时,服务没有端点,也不会监听端口,而且只会与启动它的父进程通信。--transport streamable-http和--transport sse会监听--host/--port;由于该服务会公开其根目录下的所有仓库,除非同时传入--allow-remote和 bearer token(--token-file或CORRAL_MCP_TOKEN),否则会拒绝非 loopback 地址。意外使用--host 0.0.0.0或--http :7777(会绑定所有网络接口)时,服务不会启动。服务使用普通 HTTP;远程监听时,前面需要有一个负责 TLS 终止的代理。
Forge
克隆适用于六种托管服务:
corralctl <owner> # GitHub (default)
corralctl <owner> --forge github --forge-url https://ghe.example.com # GitHub Enterprise Server
corralctl <group> --forge gitlab # GitLab
corralctl <owner> --forge codeberg # Codeberg
corralctl <owner> --forge gitea --forge-url https://git.example.com
corralctl <owner> --forge forgejo --forge-url https://forgejo.example.com
corralctl <workspace> --forge bitbucket # Bitbucket Cloud
Gitea 和 Forgejo 没有单一的公共实例,因此需要 --forge-url。GitLab 和 Codeberg 默认使用各自的实例。主机可识别时,只需设置 --forge-url——--forge-url https://codeberg.org 表示 Codeberg。
对于 GitHub,--forge-url 指定一个 GitHub Enterprise Server 实例:列表请求会发送到其 /api/v3 API;如果 URL 不是带有主机的 http 或 https URL,则会被拒绝,而不会替换为 github.com。其令牌来自 GH_ENTERPRISE_TOKEN(或 GITHUB_ENTERPRISE_TOKEN),然后是 gh auth token --hostname <host>,与 gh CLI 使用的名称相同。github.com 令牌绝不会发送到 Enterprise Server。
凭据来自环境变量,变量名沿用各 Forge 自身工具已使用的名称:GITLAB_TOKEN(或 CI_JOB_TOKEN),以及 GITEA_TOKEN / FORGEJO_TOKEN / CODEBERG_TOKEN 和 BITBUCKET_TOKEN。如果同时设置了 CORRAL_GITLAB_TOKEN 或 CORRAL_FORGE_TOKEN,则优先使用 corral 专用令牌。GitHub 保留现有的令牌选择顺序——显式令牌、环境变量,然后是 gh CLI。
在所有 Forge 上,同一令牌也用于通过 HTTPS 克隆和拉取私有仓库,并按各 Forge 预期的方式传递(GitLab 使用 oauth2,Bitbucket 使用 x-token-auth,Gitea 系列将令牌用作密码)。令牌只会发送到 Forge 自身的 HTTPS 源站,绝不会通过纯 http:// 发送。
--forge 适用于所有与托管服务交互的操作:corralctl <owner>、plan、profile 和 prune。孤立仓库检测和 prune 会根据你列出仓库时所用的 Forge 进行比较,并按主机划分范围——同一所有者名下的 GitLab 克隆绝不会被视为 GitHub 孤立仓库。
配置文件可以指定自己的 Forge,因此一份配置可以涵盖多个服务上的所有者:
{
"profiles": {
"work": { "owners": ["acme"], "settings": { "forge": "gitlab" } },
"personal": { "owners": ["me"] },
"upstream": { "owners": ["forgejo"], "settings": { "forge": "codeberg" } }
}
}
读取操作从不受主机限制。 索引、MCP 服务、符号查找和内容搜索都基于克隆运行,因此你从任何地方手动克隆的仓库一直都是一等公民。
从其他工具迁移
迁移指南位于 docs/migrating/:
从 ghq 迁移、从
手写克隆脚本 迁移、从
单仓库代码索引 迁移,
或从未排序的 ~/src 迁移。
每份指南都会说明哪些内容可以沿用、哪些地方确实不同,以及
corral 不会做什么——无需重新克隆任何内容,而 corralctl plan 会在任何更改发生前展示结果。
跨仓库符号查找
每个代码上下文服务都能告诉 Agent 某个符号在它当前打开的仓库中定义于何处。corralctl 是唯一能在机器上的所有克隆仓库中查找的工具,因为只有它知道这些仓库都在哪里。
// corral_find_symbol { "name": "CanonicalRemote" }
{
"query": "CanonicalRemote",
"repositories_search": 2,
"total_matched": 1,
"symbols": [
{
"repo": "Public/go/corral",
"symbol": "CanonicalRemote",
"kind": "func",
"file": "internal/git/git.go",
"line": 266,
"exported": true,
"language": "go"
}
]
}
可按 kind(func、method、type、interface、const、var)筛选,限定到单个 repo,按 substring 匹配,或仅搜索 exported_only 范围内的内容。方法可按其名称,或按 Receiver.Name 查找。默认排除测试声明——在测试充分的仓库中,它们的数量会超过其他所有声明;设置 include_tests 可将其纳入。
corral_repo_overview 只需一次调用即可概述一个仓库:包括其来源、文件数、按类型统计的声明数,以及最重要的导出类型和函数。读取文件前可以先调用它。
corral_search_code 是 corral_find_symbol 的对应工具:find_symbol 回答某项内容在哪里声明,search_code 则回答它在哪里出现——调用点、配置键,或工单中提到的错误字符串。默认按字面值搜索;使用 regex 可启用 RE2,也可按 repo、language 或 path_glob 缩小范围。
它只搜索文件资源会提供的文件,因此凭据文件绝不会匹配——否则,搜索就能逐行读取被拒绝访问的文件。除非设置 include_tests,否则会排除测试文件;达到上限时,响应会明确说明,而不会把不完整的结果说成完整结果。
已索引的语言:Go、Python、TypeScript、JavaScript、Rust。
Go 使用 go/ast 解析——这是编译器自身的解析器,因此索引天然与语言保持一致。其余语言由逐行扫描器读取,沿袭 ctags 的做法:它识别声明语法,而不构建语法树,因为这些语言的成熟解析器要么依赖 CGO(tree-sitter),要么是滞后于语言发展的移植版本,要么比 corral 本身还大。ADR-0006 记录了此处无法使用 CGO 的原因。
扫描器处理的是已将注释和字符串内容清空的源代码,因此文档字符串中的 class 或模板字面量中的 function 都不会被识别。
提取出的符号会缓存在 $XDG_CACHE_HOME/corral/symbols 下,因此会话中的首次查找不再耗时。即使命中缓存,仍会遍历仓库——遍历操作会生成条目的键所依据的指纹——因此不会向已编辑的克隆仓库提供过期结果。--symbol-cache off 可禁用缓存;--symbol-cache <dir> 可更改缓存位置。
在一个包含 187 个仓库的实际工作区中,跨仓库查找耗时从 6.9 秒降至 1.3 秒:大部分提升来自并发搜索仓库,而非逐个搜索;其余则来自缓存。它无法解析类型、识别宏展开,也无法追踪不常见的跨行声明——而且它会以低成本出错:漏掉符号时会改为读取文件;误报时则会在正确文件中给出错误行号。但它不会凭空捏造不存在的符号。
用法与标志
位置参数
corralctl <owner> [base_dir] [limit]
<owner>— GitHub 用户名或组织(必填)。[base_dir]— 用于保存仓库的根目录(默认:$HOME/Code)。[limit]— 最多获取的仓库数量(默认:1000)。
命令选项
| 选项 | 短选项 | 默认值 | 说明 |
|---|---|---|---|
--base-dir | — | $HOME/Code | 克隆仓库的根目录 |
--limit | -l | 1000 | 要获取的仓库数量上限 |
--concurrency | -c | 1 | 并发工作线程数 |
--dry-run | -n | 关闭 | 预览操作,不做任何更改 |
--orphans | -o | 关闭 | 检测已不在 GitHub 上的本地仓库 |
--protocol | -p | https | 克隆协议:ssh 或 https |
--no-sync | — | 关闭 | 跳过为现有克隆拉取最新更改 |
--force-sync | — | 关闭 | 无论缓存状态如何,都强制执行 git pull |
--layout | — | ... | 仓库的模板化路径布局 |
--finder-tags | — | 开启(macOS) | 为仓库文件夹应用受管理的原生 Finder 标签 |
--interactive | -i | 关闭 | 启动交互式选择器 TUI 仪表板 |
--recurse-submodules | — | 关闭 | 克隆和同步时初始化子模块 |
--output | — | text | 输出格式:text、json 或 ndjson |
--auth | — | auto | 身份验证模式:auto、token 或 gh |
--visibility | — | all | 按可见性筛选:all、public、private |
--include-forks | — | 开启 | 将派生仓库纳入 Forks/ |
--include-archived | — | 开启 | 纳入已归档仓库,并为其添加 On Hold 标签 |
--languages | — | — | 以逗号分隔的语言筛选条件(例如 go,rust) |
--exclude-languages | — | — | 以逗号分隔的排除语言列表 |
--clone-depth | — | 0 | 浅克隆深度(0 表示禁用浅克隆) |
--api-request-timeout | — | 30s | 单次 GitHub API 请求的截止时间 |
--api-total-timeout | — | 10m | 整个分页获取过程(包括重试和退避)的截止时间 |
--api-timeout | — | — | 已弃用。 曾同时应用于上述两项,将整个列表请求限制在 30s 内。指定时会同时设置两项;警告会输出到 stderr |
--log-level | — | info | stderr 上的诊断详细程度:error、warn、info、debug |
诊断信息
结果会按照 --output 选择的格式输出到 stdout。诊断信息——跳过了什么、采取了什么变通措施以及原因——会输出到 stderr,因此无论运行过程有多嘈杂,--output json 的输出都可直接通过管道传递。
--log-level 控制 stderr 输出的详细程度。CORRAL_LOG_LEVEL 可为整个 shell 会话设置相同的选项。
# Why did that repository not migrate? Turn the detail up.
corralctl sebastienrousseau --log-level debug
# Machine-readable results, quiet stderr, both at once.
corralctl sebastienrousseau --output json --log-level error > repos.json
# For a bug report: full detail, everything captured.
CORRAL_LOG_LEVEL=debug corralctl sebastienrousseau > out.json 2> diagnostics.log
默认值 info 是 corral 一直以来的输出级别。
同步选项
corralctl sync [base_dir] 接受持久化的 --base-dir、--dry-run 和 --log-level 标志,此外还接受:
| 选项 | 短选项 | 默认值 | 说明 |
|---|---|---|---|
--to | — | — | 目标,格式为 <forge>[:<owner>][@<url>];可重复指定,且至少需要一个 |
--protocol | -p | https | 推送传输协议:https(使用令牌进行身份验证)或 ssh(使用你的密钥进行身份验证) |
--concurrency | -c | 4–8 | 同时镜像的仓库数,根据主机进行设置 |
--timeout | — | 5m | 单个仓库在单个目标上的截止时间 |
--output | — | text | 输出格式:text、json 或 ndjson |
--auth | — | auto | GitHub 身份验证模式:auto、token 或 gh |
--api-request-timeout | — | 30s | 单次 forge API 请求的截止时间 |
运维命令
corralctl status --base-dir ~/Code
corralctl doctor ~/Code
corralctl doctor ~/Code --refresh-tags
corralctl doctor ~/Code --prune-worktrees
corralctl doctor ~/Code --exclude winget-pkgs --timeout 30s
corralctl plan sebastienrousseau --base-dir ~/Code
corralctl prune sebastienrousseau --base-dir ~/Code --dry-run
corralctl prune sebastienrousseau --base-dir ~/Code --yes
corralctl adopt ~/Projects --forge github --owner sebastienrousseau
status 会盘点本地克隆,doctor 会审查工作区卫生状况、工作树、磁盘预算、排除项和 Finder 标签,并列出被中断的 corral_delete_repo 操作遗留的任何 .corral-deleting-* 目录(它绝不会删除这些目录;请检查后再删除或重命名以恢复),plan 会输出不修改任何内容的协调计划,prune 只会移除通过未发布工作检查的上游孤立克隆,而 adopt 会发现未跟踪的本地仓库,将其迁移并关联到远程 forge。每个命令都支持 JSON 输出。
多所有者配置使用严格的 JSON 配置文件(默认路径为
~/.config/corral/config.json),并通过 corralctl profile <name> 运行:
{
"profiles": {
"work": {
"owners": ["org-one", "org-two"],
"base_dir": "/home/me/Code",
"layout": "{{.Owner}}/{{.Visibility}}/{{.Language}}/{{.Name}}",
"concurrency": 4
}
}
}
示例
如需查看软件包布局并以编程方式运行 corralctl 模块,请参阅 examples 目录中可独立运行、可复制粘贴的 Go 代码示例:
- 交互式选择器 — 以编程方式配置并在 AltScreen 模式下启动选择清单 TUI。
- GitHub 仓库获取器 — 使用
github.FetchReposWithOptions查询 GitHub REST API,并按 star 数排序、限制语言。 - Git 同步 — 调用
git辅助包执行克隆、查询分支并解析 origin URL。 - 引擎编排器 — 集成核心引擎
engine.Run,使用自定义筛选条件、布局结构和试运行预检来运行仓库同步。
故障排除
| 错误消息 | 原因 | 解决方案 |
|---|---|---|
ERROR: git not found on PATH | 未安装 Git,或当前 PATH 环境中缺少 Git。 | 通过软件包管理器安装 git。 |
ERROR: GITHUB_TOKEN environment variable not set | 指定了 --auth token,但未设置相应环境变量。 | 运行 export GITHUB_TOKEN=$(gh auth token),或切换为 --auth auto。 |
FAILED: owner/repo | 克隆/拉取时发生身份验证错误或网络故障。 | 检查网络连接,并确认 gh auth status 显示有效会话。 |
常见问题
- 能用于 GitLab 或其他托管平台吗?
可以。corralctl 集成了六种主流 Git 托管平台:GitHub、GitLab、Gitea、Forgejo、Codeberg 和 Bitbucket。 - 远程托管平台上已删除的仓库会怎样?
常规对账操作不会删除它们。--orphans会报告这些仓库;显式的prune命令可在通过--yes确认后移除经验证安全的孤立仓库。 - 可以在 Cron 或 systemd 定时器中运行吗?
可以。该命令默认以非交互方式运行。所有 Git 命令的凭据提示都会被绕过,以确保自动化任务不会卡住。 - 没有主要语言的仓库会存储在哪里?
默认归入Other/生态类别(例如Public/Other/my-repo)。
架构师 ᛫ Sebastien Rousseau
引擎 ᛞ EUXIS ᛫ 企业统一执行智能系统
文档
| 资源 | 位置 |
|---|---|
| 用户手册 | https://doc.corrallib.com |
| API 参考 | https://pkg.go.dev/github.com/sebastienrousseau/corralctl |
| 开发者文档 | DEVELOPMENT.md — 工具链及所有 CI 检查门禁的本地复现方法 |
| 架构 | docs/ARCHITECTURE.md |
| 决策记录 | docs/adr/ |
| 安全模型 | docs/security-model.md |
| 打包 | docs/packaging.md — 面向发行维护者 |
| 支持 | SUPPORT.md |
安装后,man corralctl 可离线使用,每个子命令也都有自己的手册页(man corralctl-mcp)。
何时不应使用 corralctl
corralctl 有自己的主张,并非人人都适用。
- 你需要完整镜像或备份。 corralctl 会克隆工作副本,供读取和编辑。归档镜像请使用
git clone --mirror或专用工具;corralctl 不会保留每个 ref,也不保证副本完整无缺。 - 你需要从 corral 未列出的代码托管平台获取仓库。 支持 GitHub、GitLab、Gitea、Forgejo、Codeberg 和 Bitbucket;不支持其他平台。读取不受代码托管平台限制——来自任何主机的克隆都是索引、MCP 服务和符号查找中的一等公民——但
corralctl <owner>只识别这六个平台。 - 你的仓库必须留在原处。 corralctl 的价值在于统一布局,而默认布局会将克隆整理到
Collection/Bucket/Name。如果固定路径很重要,可以使用--layout匹配现有目录树,或者改用其他工具。 - 你需要代码智能功能。 MCP 服务会为符号编制索引,并搜索所有克隆中的文件内容,但能力有限:一个声明只有名称、类型、文件和行号。它不会解析类型、查找引用或重命名——这些由 LSP 完成,且一次处理一个项目;而 corral 是告知 Agent 应打开哪个项目的那一层。
- 你需要在不使用 WSL 的情况下运行于 Windows。 虽然会发布 Windows 二进制文件,但 macOS Finder 标签在 Windows 上不起作用,而且 Windows 上的体验尚未像 macOS 和 Linux 上那样经过充分测试。
要求与工具链政策
| Go | go.mod 中的 go 指令——目前为 1.26.10 |
| git | 2.31 或更高版本,并位于 PATH 中(凭据通过 GIT_CONFIG_COUNT 传递给 git,该变量由 2.31 引入) |
| gh | 可选;仅用于 --auth gh |
Go 最低版本只在一个地方声明:go.mod;CI 会设置
GOTOOLCHAIN=auto,以免它与工作流输入不一致。
提高最低版本的政策。 任何版本发布时,只要标准库修复或语言特性足以构成理由,就可以提高最低版本;理由会记录在该版本的 CHANGELOG 条目中。corralctl 不承诺兼容各发行版的长期支持版本——如果没有对照发行版工具链与最低版本的表格,这种愿景式承诺还不如不作承诺。打包人员每次升级版本时都应检查 go.mod,而不要假定最低版本保持不变。
稳定性保证
corralctl 尚未达到 1.0 版本,遵循 SemVer;在 1.0 之前,任何变更都会递增补丁版本号。
破坏性变更涉及行为,而非签名。 对于会移动和删除目录的工具,即使标志或函数签名没有变化,只要对工作区的操作方式发生变化,也属于破坏性变更。具体而言,以下情况会被视为破坏性变更:
- 默认布局发生变化,或仓库映射到路径的方式发生变化
--output json/ndjson的输出发生变化,新增字段除外- 退出代码发生变化
- 从拒绝变为允许:任何 corralctl 过去会拒绝删除、清理或迁移,现在却继续执行的情况
- MCP 工具或资源的接口发生变化,导致现有客户端能够察觉
新增字段、默认不启用的新标志,以及新增的拒绝情况都不属于破坏性变更。
弃用期限。 弃用的标志或工具至少会在宣布弃用的版本之后再保留一个次要版本,并在 stderr 上发出警告——绝不会写入 stdout,因为 stdout 承载所选输出格式。
安全与加固
报告漏洞。 请勿创建公开 Issue。请按照 SECURITY.md 中的私密流程操作;响应 SLA 也在其中说明。
安全态势。 corralctl 使用用户自己的凭据,在用户自己的机器上运行,因此威胁模型关注的是限制影响范围,而非跨越权限边界。详情请参阅 docs/security-model.md。
- 凭据绝不会进入
argv或.git/config。 Forge 的令牌会作为作用域限定于该 Forge HTTPS 源站(https://github.com/、https://gitlab.com/或你的实例)的http.extraheader传给 git,因此其他主机上的子模块无法看到该令牌。Clone 错误会特意省略参数,以免嵌入 URL 的凭据进入日志。 - Git 始终以非交互方式运行。 设置
GIT_TERMINAL_PROMPT=0等选项,确保无人值守的运行会失败,而不是卡在提示上。 - 没有证据时会拒绝破坏性操作。 如果克隆中有未提交、未推送、已暂存、子模块或 被 git 忽略 的工作内容,
prune和corral_delete_repo会拒绝执行。之所以也检查最后一种情况,是因为git status会隐藏远程端恰好没有副本的文件。 - MCP 服务受到沙箱隔离和权限控制。 路径解析会规范化两端的符号链接,并比较路径段而非字符串前缀;不会通过符号链接读取任何仓库文件。写入工具需要启用
--enable-mutations;删除操作还需要另一个标志。每项变更都会在尝试执行前写入审计日志。 - 内存安全性由 Go 提供;项目中完全不使用 CGO(
CGO_ENABLED=0),因此发布的二进制文件是静态的,不依赖 libc。
模糊测试。 模糊测试目标覆盖解析和路径解析的边界,包括布局评估、语言规范化、远程 URL 解析,以及必须确保路径不会逃出根目录的沙箱检查。每次推送都会运行固定时长的模糊测试。corralctl 未加入 OSS-Fuzz。
供应链。 发布版本使用无密钥 cosign 签名,附带 SLSA 构建来源证明和 CycloneDX SBOM,并使用 -trimpath 和固定到提交的时间戳构建,确保同一提交的两次构建在字节层面完全一致。每个 GitHub Action 都固定到提交 SHA,容器基础镜像则固定到摘要。每次推送都会运行 govulncheck。
许可证
根据 GNU 通用公共许可证 v3.0 授权。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。