mcpField
B
Binky

Binky

本地服务
github.com/andreisilva1开发工具113 周前更新

关于 Binky

Binky 为每个 Git worktree 创建独立本地环境,协调端口、环境变量、服务进程以及共享数据库或其他服务的资源切片。它面向需要在同一台机器上并行运行编码 Agent 或分支的团队。

主要功能

  1. 01为每个 worktree 隔离端口、URL 和环境
  2. 02为服务配置独立资源切片
  3. 03启动、停止并检查 worktree 服务
  4. 04准入控制与后台进程监管
  5. 05命令行与实时 worktree 面板

适用场景

  1. 01并行运行编码 Agent,避免端口冲突
  2. 02为每个分支分配独立数据库切片
  3. 03向测试或 Agent 提供 worktree URL 和环境

MCP 相关

`binky mcp`通过 stdio 运行 MCP 服务,提供`up`、`down`、`status`、`env`和`verify`工具,并通过与命令行相同的守护进程执行操作。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"andreisilva1-binky": {
"command": "uvx",
"args": [
"binky"
]
}
}
}
启动命令uvx binky

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypibinky0.1.2

工具

5

收录的工具列表 · 更新于 3 周前

参数类型必填说明
rootstring否
groupstring否
worktreestring是

详细介绍

README 配图

Binky

每个 git worktree 都有一个隔离的本地环境——端口、环境变量、数据库、URL。

这样,一群编码 Agent 就能在一台机器上并行运行,互不冲突。

CI PyPI Python License

文档 · 快速入门 · 适配器 · 命令 · 面向 Agent · 工作原理 · 故障排除


docker-compose 是为一次运行一个进程而构建的。Binky 则是为同时运行十五个进程而构建的。

状态:alpha。 核心功能已端到端可用——worktree 隔离、端口、适配器、进程监管、协调器、准入控制、代理、HTTPS。配置格式已稳定;CLI 仍可能调整。

问题

你让三个 Agent 处理同一个仓库。第二个运行 pnpm dev,结果遇到 EADDRINUSE。 第三个运行迁移,删除了第一个正在读取的表。你开始手动编辑 .env 文件,现在你成了调度器。

Binky 就是调度器。每个 Agent 运行一次 binky up <branch>,就能获得自己的端口、自己的 数据库和自己的 URL——全部来自同一份已提交的配置。

安装

需要 Python 3.11+ 和 git,支持 Linux 或 Windows——Binky 目前在这两个平台上经过实际测试。 macOS 目前还不是支持目标平台;欢迎为其移植并充分测试,作为一项贡献。

uv tool install binky          # or: pipx install binky
binky --version

也可以从克隆的仓库安装,以运行尚未发布的 main 分支或参与开发:

git clone https://github.com/andreisilva1/binky && cd binky
uv tool install .               # or: pipx install .

需要驱动程序的适配器会作为额外依赖提供——安装用于 Redis 的 Binky 时,不会拉取 boto3:

uv tool install "binky[postgres]"        # or [redis], [mysql], [mongodb], [s3], [kafka]
uv tool install "binky[all-adapters]"    # the whole matrix

快速入门

已经有 docker-compose.yml?从它开始:

binky init                 # writes a binky.toml you can read and edit
binky check                # validate it

也可以手动编写——这就是完整的配置:

[project]
name = "acme"

[services.web]
cmd = "pnpm dev --port ${self.port}"
url = "web"                              # → web.<worktree>.acme.localhost
depends_on = ["api"]
env = { API_URL = "${api.url}" }

[services.api]
cmd = "go run ./cmd/server"
url = "api"                              # asking for a URL is what asks for a port
depends_on = ["db"]
env = { DATABASE_URL = "${db.url}" }

[services.db]
adapter = "postgres"                     # a private database per worktree
admin_url = "${env.POSTGRES_ADMIN_URL}"
migrate = "make migrate"
seed = "make seed"
clone_from = "golden"                    # migrate+seed once, then copy per worktree

然后并行启动 worktree:

$ binky up login-fix
  api  pid 16560  :4846
  web  pid 29732  :4504
✓ up: login-fix (2 service(s))

$ binky up checkout-v2
  api  pid 21768  :4137
  web  pid 46336  :4605
✓ up: checkout-v2 (2 service(s))

$ binky status
acme
  checkout-v2  [running]
      api  :4137
      web  :4605
  login-fix  [running]
      api  :4846
      web  :4504

两个分支、四个进程、四个无需手动挑选的端口。把某个 worktree 的连接信息交给需要它的人或程序——shell、Agent、测试运行:

$ binky env login-fix --dotenv
WEB_URL=http://web.login-fix.acme.localhost
API_URL=http://api.login-fix.acme.localhost

以及其余的生命周期操作:

binky down login-fix       # pause (keeps files + ports); `up` again is instant
binky remove login-fix     # destroy it (refuses if there are uncommitted changes)

没有任何内容是硬编码的,也不会在运行时进行发现:每个进程启动时都已知晓完整的端口映射,包括自身和依赖项的端口。

务必牢记一条规则。 服务声明 url 或 ports 后才会获得端口——端口必须显式请求。两者都未声明的服务不会获得端口;对于工作进程或一次性任务,这完全正确,但如果你随后在其 cmd 中写入 ${self.port},就会掉进陷阱。未知的占位符会原样保留,而不会被清空,因此字面量 ${self.port} 会传到 shell,进程会在自身的参数解析阶段失败。服务出现这种情况时,binky check 会发出警告。

运行 N 个世界的成本

我们的主张是,N 个隔离世界的成本不应该是单个世界的 N 倍。不是口说无凭—— benchmarks/worlds.py 位于此仓库中,可以复现下表(postgres:16,每个世界 200,000 行数据, 在 Windows 11 上使用 Docker Desktop):

worldsRAM:每个世界一个容器RAM:Binky时间:每个世界一个容器时间:Binky
1150 MiB174 MiB6s4s
2298 MiB182 MiB11s6s
4596 MiB228 MiB20s10s
81197 MiB295 MiB40s16s

第 8 个世界如果使用单独的容器,需要额外 150 MiB 和 4.8s;如果使用 Binky,则只需额外 17 MiB 和 1.7s。

也请看第一行。只有一个世界时,Binky 反而更慢——它需要运行一个服务和一个暂时无人使用的黄金模板,直到第二个世界出现才开始收回成本。而且磁盘空间并没有优势: CREATE DATABASE ... TEMPLATE 会复制文件,而不是采用写时复制,因此每个世界仍然都是完整的数据副本。Binky 去掉的是每个世界对应的服务,而不是每个世界对应的数据量。它也不会降低你自己的应用进程成本——每个工作树运行一个开发服务器,无论哪种方式成本都一样。

python benchmarks/worlds.py --sweep 1,2,4,8 --rows 200000

哪些情况下不需要 Binky

这点值得直说,因为表格的第一行已经说明了:

  • 一次只使用一个分支。 如果你从不同时运行两个世界,Binky 就只是一个你用不上的守护进程和配置 文件。等第二个 Agent 出现时再用它。
  • 所有内容已经在容器中运行,而且运行得很好。 Binky 的优势在于移除每个世界对应的服务。 如果你的 compose 技术栈足够小,能轻松容纳 N 个副本,那就没有什么可节省的。
  • 你需要真正的隔离,而不只是本地隔离。 Binky 会以你的身份在你的机器上运行命令。它不是沙箱——请参阅安全性。

适配器

适配器会从一个共享服务中划分出一个隔离的切片——例如数据库、键前缀或存储桶——而不是为每个工作树运行一个服务。共 16 个名称、10 种实现,并且每一种都在 CI 中针对真实服务进行了测试。

切片适配器
数据库postgres · mysql · mariadb · percona · mongodb · clickhouse
键前缀redis · valkey
存储桶 / 前缀s3 · minio
虚拟主机 / 主题前缀rabbitmq · kafka · redpanda
集合qdrant
索引前缀elasticsearch · opensearch

协议兼容的名称会共用同一种实现,而不会复制一份——valkey 是 Redis 适配器,percona 是 MySQL 适配器,opensearch 是 Elasticsearch 适配器。

clone_from:迁移和填充数据只需付费一次

使用 clone_from 后,第一次运行 binky up 会构建一个黄金模板——完成配置、迁移和数据填充——之后的每个工作树都从该模板复制而来。模板根据 migrate 和 seed 命令的哈希值确定,因此更改其中任意一项都会自动重建模板。

适用于服务可在服务端复制切片的情况(postgres、mysql、mariadb、percona、mongodb)。如果服务不支持,或者克隆因环境问题失败——例如客户端二进制文件太旧,无法通过身份验证,或缺少授权——Binky 会回退到为该工作树执行配置、迁移和数据填充,并记录 clone_fallback。正确性从不依赖克隆,只有速度才依赖。

还有一个值得注意的细节:哈希涵盖的是迁移和数据填充的命令,而不是这些命令调用的文件。修改命令运行的脚本不会重建模板——删除 ~/.binky/golden/ 下的标记文件即可强制重建。

编写自己的适配器

两个层级,一套契约。两者都实现相同的四个动词:

动词作用
provision(slice)创建切片(CREATE DATABASE ...)
resolve(slice)返回其地址 → ${db.url}
teardown(slice)销毁它
capabilities()返回它支持的功能,例如 {"clone": true}

进程内适配器是此仓库中的 Python 类,按名称发现。外部适配器是任何语言编写的可执行文件,通过 PATH 上的 binky-adapter-<name> 发现,并通过一次性子进程 + JSON 协议驱动:

$ binky-adapter-filestore provision   <<< '{"slice": "acme_login-fix", "config": {}}'
{"ok": true}
$ binky-adapter-filestore resolve     <<< '{"slice": "acme_login-fix", "config": {}}'
{"ok": true, "address": "file:///tmp/binky-filestore/acme_login-fix"}

Python 开发者可以直接使用该协议 — binky.adapter_sdk.run() 会将普通适配器类桥接到该协议。完整且无需依赖的示例见 examples/adapters/filestore.py,仅有 30 行。

命令

命令作用
binky init [dir] [--force]根据 docker-compose.yml + .env 写入初始 binky.toml
binky check [path]验证 binky.toml 并指出易踩的坑
binky up <name> [--group g]创建或使用分支的工作树、分配端口、配置资源并启动服务
binky reload <name> [--group g]原地重启 — 停止后,在相同端口和数据上重新启动
binky down <name>停止工作树的进程(保留其文件和端口)
binky remove <name> [--force]销毁工作树 — 停止进程、删除其切片并移除文件
binky status [.]列出工作树(按项目分组);. = 仅当前项目
binky env <name> [--dotenv]输出工作树公开的连接信息,供你或 Agent 使用
binky curl <name> <service> [path]通过代理调用服务,并自动填入 Host 标头(-X/-d/-H/-i/-f)
binky verify <name>运行项目的 agents.verify 检查;失败时返回非零退出码
binky logs <name>输出工作树捕获的服务日志
binky gc清理崩溃后遗留的、配置了一半的孤立适配器切片
binky config显示机器级全局设置(RAM/磁盘预留、代理端口)
binky reserve [--ram %] [--disk gb]设置 Binky 永久保留的空闲 RAM/磁盘空间
binky port [--proxy p] [--https p]设置代理/HTTPS 端口
binky dashboard显示所有工作树的实时 TUI
binky doctor诊断安装和守护进程;出现问题时返回非零退出码
binky metrics以 JSON 格式输出守护进程的即时指标
binky mcp运行 MCP 服务,让 Agent 能将 Binky 的动词作为工具调用
binky daemon start|stop|status管理后台守护进程

面向 Agent

binky mcp 通过 stdio 使用 MCP,提供 up、down、status、env 和 verify — 与 CLI 调用相同的动词,使用相同的守护进程。

在 Claude Code 中,只需一行即可完成配置:

claude mcp add binky -- binky mcp

任何其他支持该协议的客户端,也可通过配置块使用同一个 stdio 服务 — 各处配置相同,只是文件不同:

{ "mcpServers": { "binky": { "command": "binky", "args": ["mcp"] } } }

若要在不安装任何内容的情况下运行,可将其交给 uvx — 使用 claude mcp add binky -- uvx --from "binky[mcp]" binky mcp,或用配置块表示:"command": "uvx"、"args": ["--from", "binky[mcp]", "binky", "mcp"]。如果项目的工作树需要配置适配器切片,也要添加相应的额外依赖,例如 binky[mcp,postgres](若要使用完整的适配器矩阵,则用 binky[mcp,all-adapters])。

Binky 已发布到 MCP Registry,名称为 io.github.andreisilva1/binky,因此支持注册表的客户端可以在其中发现并安装它。

工具列表和面向 Agent 的使用指南,请参阅 AGENTS.md。

工作原理

一个全局唯一的守护进程位于工作树与机器之间:

flowchart TB
    CLI["agents · CLI · MCP"] -->|"up · down · status"| D(("binky daemon<br/>machine-global"))

    D --> ADM{"admission<br/>RAM · disk · max_parallel"}
    ADM -.->|"no room → queue / suspend"| Q["waiting"]
    ADM -->|"admit"| W["worktree<br/>git worktree per name"]
    W --> P["ports<br/>whole map before start"]
    P --> R["adapters<br/>isolated slice per worktree"]
    R --> S["supervisor<br/>depends_on · health · logs"]
    S --> X["proxy<br/>svc.worktree.domain → port"]

    D -.->|"reads · writes"| ST[("~/.binky<br/>SQLite + settings")]
  1. 工作树 — 按名称创建或使用一个 git 工作树。
  2. 端口 — 全局分配器会在任何进程启动前为其分配端口,并注入完整的映射,因此不会发生冲突(${self.port}、${api.url}……)。
  3. 资源 — 适配器会为每个工作树划分出一个隔离的资源片段,并在移除时将其清理。
  4. 监督 — 按 depends_on 顺序启动服务,等待健康检查通过,并收集日志。
  5. 代理 — 将 <service>.<worktree>.<domain> 路由到正确的端口(也包括 WebSocket/HMR)。 设置 https = true 后,如果 Caddy 位于 PATH 中,Binky 会通过 Caddy 使用本地 CA 提供 TLS。
  6. 准入 — 使用 FIFO 队列,仅在机器有足够资源时启动工作树:运行中的工作树少于 max_parallel,并且有足够的可用 RAM(保留一定百分比)和可用磁盘空间(固定的 GB 余量)。如果运行中的工作树群之后超过 RAM 保留额度,守护进程会暂停最新的工作树以缓解压力;待资源充足后,再按公平顺序恢复。使用 binky reserve 调整保留额度;使用 binky config 查看。

状态存储在 ~/.binky/ 中(一个 SQLite 注册表和一个设置存储,在升级时原地迁移)。所有操作都在本地运行,Binky 绝不会主动联系开发方。

示例

  • examples/hello — 最简单的项目。
  • examples/rag — 向量搜索,每个工作树都有自己的嵌入式语料库。 这是共享数据库反而有害的场景:两个 Agent 重新索引,一个执行 TRUNCATE。
  • examples/adapters/filestore.py — 完整的外部适配器。

安全

Binky 会以你的身份在你的机器上运行你的命令。它是面向单用户工作站的开发工具,不是多租户沙箱——binky.toml 与 Makefile 一样值得信任;在你不信任的仓库上运行 binky up,就如同在该仓库上运行 make。SECURITY.md 中说明了威胁模型以及明确不在防护范围内的事项。

这里值得重申的一条规则是:绝不要将凭据直接写入已提交的 binky.toml。请使用 ${env.NAME} 或 env_file。如果你这样做,binky check 会发出警告,而 binky init 绝不会写入凭据。

遇到问题?

TROUBLESHOOTING.md 涵盖了实际遇到的问题——被外部程序占用的端口、忽略 $PORT 的开发服务器、过时的黄金模板、无法解析的 *.localhost。请从 binky doctor 开始排查。

开发

python -m venv .venv && . .venv/bin/activate   # or .venv\Scripts\activate on Windows
pip install -e ".[dev,all-adapters]"
pytest
ruff check src tests examples benchmarks

除非指定真实服务器,否则适配器集成测试会跳过——BINKY_TEST_PG、BINKY_TEST_REDIS、BINKY_TEST_MYSQL、BINKY_TEST_MONGO、BINKY_TEST_S3、BINKY_TEST_RABBITMQ、BINKY_TEST_KAFKA、BINKY_TEST_QDRANT、BINKY_TEST_CLICKHOUSE、BINKY_TEST_ELASTICSEARCH。CI 会提供所有这些服务器。

参与贡献

欢迎提交错误报告、新适配器和 PR——请参阅 CONTRIBUTING.md 了解如何设置开发环境,并参阅 ARCHITECTURE.md 了解内部结构。

许可证

Apache-2.0 — 请参阅 LICENSE 和 NOTICE。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。