插件协议 byk.json
每个 byk 插件的发布入口是仓库根目录下的 byk.json 文件。它定义了插件的安装方式、下载资源和注册的命令。本文档面向插件发布者,说明如何编写这个文件。
文件位置
将 byk.json 放在 GitHub 仓库的根目录。byk 通过 raw.githubusercontent.com 拉取该文件:
https://raw.githubusercontent.com/{owner}/{repo}/{branch}/byk.json
设计哲学
byk.json 是一个过程式操作脚本,按顺序声明操作块:
1. pip-keep → 安装 Python 依赖到虚拟环境(卸载时保留)
2. pip → 安装 Python 依赖到虚拟环境(卸载时自动清理)
3. downloads → 统一下载/拷贝文件到 plugins/<plugin_key>/
4. download-to-workdir → 下载到当前工作目录
5. download-to-alias → 下载到 ~/.byk/alias/
6. command → 注册单个命令(命令名 = 插件 key)
7. commands → 注册多个命令到路由表
8. alias → 部署别名到 *.byk.json 文件
推荐:单命令插件用 command,多命令插件用 commands。两者可以共存,但不要在同名 key 上重复定义。
JSON key 的声明顺序即执行顺序,阅读即执行。
整体结构
byk.json 是一个 JSON 对象,每个顶级 key 为一个插件 key(即 byk add <key> 中的 <key>),值为该插件的操作定义:
{
"$default": "<plugin-key>",
"<plugin-key>": {
"pip": [...],
"commands": { ... }
}
}
一个 byk.json 可以包含多个插件 key,用户通过 byk add <key> 指定要安装哪个。
$default
$default 字段指定当用户不指定 key 时(byk add user/repo)默认安装哪个插件。
{
"$default": "pym",
"pym": "./plugins/py-module/byk.json",
"pys": "./plugins/py-script/byk.json"
}
::::note
$default 的值必须是 byk.json 中存在的有效 key,否则安装时报错
- 只有一个 key 时无需声明
$default,byk 会自动推断
- 有效 key 指不以
$ 开头的顶级字段
::::
$var
$var 字段用于定义可复用的变量,减少路径或 URL 中的重复字符串。定义后可在任意位置的字符串值中使用 {变量名} 语法引用。
{
"$var": {
"p": "./plugins"
},
"pym": "{p}/py-module/byk.json",
"pys": "{p}/py-script/byk.json",
"pyb": "{p}/py-bin/byk.json"
}
上例中三个 plugin key 的路径前缀 ./plugins 被提取到 $var.p,通过 {p} 引用,等价于:
{
"pym": "./plugins/py-module/byk.json",
"pys": "./plugins/py-script/byk.json",
"pyb": "./plugins/py-bin/byk.json"
}
平台特定值
$var 的值不仅可以是字符串,还可以是平台映射对象。当值为一个对象时,byk 根据当前运行平台自动选择对应的字符串:
{
"$var": {
"BASE": {
"linux-x86_64": "https://cdn.linux.example.com",
"linux-arm64": "https://cdn.linux-arm.example.com",
"darwin-x86_64": "https://cdn.darwin-intel.example.com",
"darwin-arm64": "https://cdn.darwin-arm.example.com",
"windows-x64": "https://cdn.windows.example.com"
}
},
"my-tool": {
"downloads": {
"tool": "[exe] {BASE}/my-tool"
}
}
}
变量也常用于减少 pip 中的重复 URL:
{
"$var": {
"url": "https://github.com/fcbyk/byk/releases/download/assets"
},
"pym": {
"pip": "byk_pym @ {url}/byk_pym-2026.6.21-py3-none-any.whl",
"commands": { ... }
}
}
规则
处理顺序
byk.json 文件
→ 1. 解析 JSON,提取 $var
→ 2. 在原始 JSON 字符串上逐变量替换 {var} 占位符
→ 3. 解析 Ref 引用(已替换为完整路径)
→ 4. Ref 引用的文件回到步骤 1(独立的 $var 作用域)
::::note
$var 的 value 同样参与替换,交叉引用(如 "a": "{b}/foo")会逐变量传递替换
$var 不会传递到 Ref 引用的子文件,每个 byk.json 拥有独立的变量作用域
- 变量替换发生在 Ref 解析之前,因此
"{p}/py-module/byk.json" 会先变成 "./plugins/py-module/byk.json",再作为相对路径被解析
- 平台对象在变量替换阶段解析为对应平台的字符串值
::::
操作块
pip-keep
pip-keep 是插件内部的保留 pip 依赖,卸载时保留。结构与 pip 完全相同,支持单字符串或字符串数组写法:
{
"plugin-a": {
"pip-keep": ["rich", "click>=8.0"],
"pip": ["my-plugin-a"],
"commands": { ... }
}
}
也可以写为单字符串(只有一个包时):
{
"plugin-a": {
"pip-keep": "rich",
"pip": "my-plugin-a",
"commands": { ... }
}
}
pip-keep 适合声明插件的基础共享依赖(如 rich、click),卸载插件时这些包会被保留。与 pip 不同,pip-keep 中的包不会随插件卸载而删除。
pip
通过 pip 安装 Python 包到 byk 的隔离虚拟环境,卸载插件时自动执行 pip uninstall。
{
"hello": {
"pip": ["byk-hello"],
"commands": { ... }
}
}
pip 字段支持两种写法:
- 单字符串:
"pip": "requests" — 只有一个包时更简洁
- 字符串数组:
"pip": ["rich", "click>=8.0"] — 多个包时使用
字段说明
pip 中的每一项可以是:
- 包名:
"rich"、"click>=8.0"、"requests==2.28.0" — 从 PyPI 安装
- URL:
"https://github.com/.../xxx.whl" — 从远程 URL 安装
- name @ url:
"my-pkg @ https://github.com/.../xxx.whl" — 指定包名 + URL,卸载时用包名执行 pip uninstall
纯 URL 无法卸载:如果 pip 中写的是纯 URL(无 name @ 前缀),卸载时静默跳过,因为无法知道包名。如需自动卸载,请使用 "name @ url" 格式。
示例:单字符串写法
{
"hello": {
"pip": "my-hello @ https://github.com/fcbyk/byk/releases/download/plugins/byk_hello-2026.6.21-py3-none-any.whl",
"commands": { ... }
}
}
downloads
downloads 是统一下载区块,将文件下载到 plugins/<plugin_key>/ 目录。支持三种写法:
- 裸 URL 字符串:文件名从 URL 自动提取
- 对象映射:
{ "<文件名>": "<URL>" },支持 [tar] / [exe] 前缀
- 目录树:
{ "<目录名>": { "<文件名>": "<URL>", ... } },递归嵌套
裸 URL 字符串
最简单的写法,文件名从 URL 的最后一个路径段自动提取:
{
"my-tool": {
"downloads": "[exe] https://github.com/xxx/releases/download/v1.0/my-tool",
"command": {
"type": "bin",
"entry": "my-tool",
"desc": "My binary tool"
}
}
}
对象映射
key 为保存的文件名,value 为 URL。URL 前缀控制下载后行为:
{
"my-tool": {
"downloads": {
"my-tool": "[exe] https://github.com/xxx/releases/download/v1.0/my-tool",
"runner.py": "https://example.com/runner.py"
},
"command": {
"type": "bin",
"entry": "my-tool",
"desc": "My platform-specific binary tool"
}
}
}
压缩包解压([tar] 前缀)
{
"my-tool": {
"downloads": {
"my-tool": "[tar] https://github.com/xxx/releases/download/v1.0/my-tool.tar.gz"
},
"command": {
"type": "bin",
"entry": "my-tool/my-tool",
"desc": "My tool from archive"
}
}
}
解压后目录结构:plugins/my-tool/my-tool/my-tool,entry 对应 my-tool/my-tool。
目录树
当需要下载一组文件到子目录时,可以使用嵌套对象结构:
{
"my-app": {
"downloads": {
"mylib": {
"main.py": "https://example.com/main.py",
"utils": {
"helper.py": "https://example.com/helper.py"
}
}
}
}
}
下载后文件结构:
plugins/my-app/
└── mylib/
├── main.py
└── utils/
└── helper.py
目录树中的叶子节点同样支持 [tar] / [exe] 前缀。
字段说明
::::note
downloads 按声明顺序逐一处理,下载失败立即终止并报错
- 相对路径仅支持
./xxx 和 xxx 两种写法,../、/xxx、~ 不被允许
- 使用
--cdn 时,raw.githubusercontent.com 的 URL 自动转换为 jsDelivr CDN 加速
[tar] 使用系统 tar 命令解压,支持 .tar.gz / .tgz / .zip 格式,要求 Windows 10 1803+(内置 tar)
[exe] 在非 Windows 系统自动设置执行权限(chmod 755)
- 解压时一个 key 对应一个独立子目录,不同插件互不干扰,卸载时直接删除整个目录
::::
download-to-workdir
download-to-workdir 与 downloads 结构相同,但下载到当前工作目录而非 plugins/。适合下载配置文件、模板等需要放在项目目录中的资源。
{
"config-tool": {
"download-to-workdir": {
"$name": "my-configs",
"settings.json": "https://example.com/settings.json",
"templates": {
"default.tmpl": "https://example.com/default.tmpl"
}
}
}
}
下载后文件结构(当前工作目录):
./
└── my-configs/
├── settings.json
└── templates/
└── default.tmpl
$name
Map 模式下支持 $name 键指定容器目录名。$name 不会创建实体文件,仅用作目录前缀。
- 指定
$name:文件放入 <cwd>/<name>/ 目录
- 不指定
$name:默认容器目录名为 "downloads"
字段说明
download-to-alias
download-to-alias 与 downloads 结构相同,但下载到 ~/.byk/alias/ 目录。适合部署别名脚本等全局可重用的资源。
{
"my-aliases": {
"download-to-alias": {
"my-script.py": "https://example.com/my-script.py"
}
}
}
command
为单命令插件注册命令,命令名自动取插件 key。推荐只有一个命令的插件使用此字段。
{
"hello": {
"pip": "byk-hello",
"command": {
"type": "python-m",
"entry": "hello.one",
"desc": "Say hello"
}
}
}
安装后,用户通过 byk hello 即可执行该命令。
字段说明
commands
声明插件提供的多个命令。commands 中的内容会被零解析直接合并到 plugins.cmd.json,无需中间转换。
{
"commands": {
"hello": {
"type": "python-m",
"entry": "hello.one",
"desc": "Example subcommand to verify dynamic registration."
},
"world": {
"type": "python-m",
"entry": "hello.two",
"desc": "Second command to verify dynamic registration."
}
}
}
字段说明
命令类型
一个插件可以注册多个命令,每个命令对应一个独立的入口点。
与 command 共存:command 和 commands 可以同时使用。command 注册的命令名 = 插件 key,commands 注册额外的命名命令。但 commands 中不能定义与插件 key 同名的子命令,否则安装时报错。
python 入口点
对于 python 类型的命令,entry 是相对于 plugins/<plugin_key>/ 的文件路径,指代通过 downloads 下载的脚本文件:
{
"jiahao": {
"downloads": {
"jiahao.py": "https://raw.githubusercontent.com/user/repo/main/scripts/jiahao.py"
},
"command": {
"type": "python",
"entry": "jiahao.py",
"desc": "装 x 命令"
}
}
}
bin 入口点
对于 bin 类型的命令,entry 指代 plugins/<plugin_key>/ 目录下的相对路径。可以是纯文件名,也可以带子目录路径。二进制文件通过 downloads 下载:
{
"my-tool": {
"downloads": {
"my-tool": "[exe] https://github.com/xxx/releases/download/v1.0/my-tool"
},
"command": {
"type": "bin",
"entry": "my-tool",
"desc": "My binary tool"
}
}
}
alias
alias 字段用于在安装插件时自动部署别名到 *.byk.json 文件。
{
"my-plugin": {
"pip": "my-plugin",
"commands": { ... },
"alias": {
"@myapp": {
"run": "python main.py",
"test": "pytest"
},
"@@global-tool": {
"lint": "ruff check ."
}
}
}
}
解析规则
- 文件不存在 → 创建,直接写入
- 文件已存在 → 顶层 key 直接覆盖,不影响其他 key
alias 会在所有下载和命令注册完成后执行
文件名不能包含 . 或 @ 字符。
Ref 引用
当一个 key 的值为字符串时,byk 会将其视为引用,从该位置拉取另一个 byk.json,并在其中查找同名 key。
URL 引用
如果字符串以 http:// 或 https:// 开头,byk 直接将其作为 URL 拉取:
{
"lansend": "https://raw.githubusercontent.com/fcbyk/byk-lansend/main/byk.json",
"hello": {
"pip": "byk-hello",
"commands": { ... }
}
}
当用户执行 byk add user/repo/lansend 时,byk 会:
- 发现
lansend 的值是一个 URL
- 从该 URL 拉取完整的
byk.json
- 在新拉取的内容中查找 key 为
lansend 的条目
- 使用该条目的操作定义执行安装
相对路径引用
如果字符串不以 http 开头,byk 将其视为相对路径,相对于当前 byk.json 所在目录解析:
- 远程模式(
byk add user/repo):拼接到 https://raw.githubusercontent.com/{user}/{repo}/{branch}/ 后
- 本地模式(
--file):相对于当前 byk.json 所在目录解析
{
"hello": "./plugins/python/byk.json"
}
当用户执行 byk add user/repo/hello 时,byk 会:
- 发现
hello 的值是相对路径 ./plugins/python/byk.json
- 拼接为
https://raw.githubusercontent.com/user/repo/main/plugins/python/byk.json
- 拉取该文件,查找 key 为
hello 的条目
- 使用该条目的操作定义执行安装
路径规则:
::::note
./ 前缀可选,plugins/python/byk.json 与 ./plugins/python/byk.json 等效
- URL 引用不受安装模式影响,始终直接拉取
../ 等路径逃逸写法不被允许,如需引用外部资源请使用完整 URL
- 相对路径引用适用于将插件定义拆分到子目录的场景
- 每个 byk.json 自治:嵌套 byk.json 中的相对路径始终相对于自身所在目录
::::
配合 $var 使用:$var 可以进一步减少 Ref 路径中的重复前缀,详见 $var — 变量替换。
Ref 适合将插件定义分散到各自仓库或子目录中维护,主仓库只做索引。
远程仓库
任何 GitHub 仓库只要在根目录放一个 byk.json,即可作为 byk 插件源使用:
github.com/myuser/my-byk-plugins/blob/main/byk.json
{
"my-tool": {
"pip": "my-byk-tool",
"command": {
"type": "python-m",
"entry": "mybyktool.cli",
"desc": "My custom tool"
}
}
}
用户安装方式:
byk add myuser/my-byk-plugins/my-tool # 指定 key
byk add myuser/my-byk-plugins # 安装 byk.json 中的默认 key
完整示例
一个包含多个插件、使用 Ref 引用和完整操作块的 byk.json:
{
"lansend": "https://raw.githubusercontent.com/fcbyk/byk-lansend/main/byk.json",
"hello": {
"pip": "byk_hello @ https://github.com/fcbyk/byk/releases/download/plugins/byk_hello-2026.6.21-py3-none-any.whl",
"commands": {
"hello": {
"type": "python-m",
"entry": "hello.one",
"desc": "Example subcommand to verify dynamic registration."
},
"world": {
"type": "python-m",
"entry": "hello.two",
"desc": "Second command to verify dynamic registration."
}
}
},
"jiahao": {
"downloads": {
"jiahao.py": "https://raw.githubusercontent.com/fcbyk/pyodd/refs/heads/main/scripts/jiahao.py"
},
"pip": ["rich", "click"],
"command": {
"type": "python",
"entry": "jiahao.py",
"desc": "装 x 命令"
}
},
"my-tool": {
"downloads": {
"my-tool": "[exe] https://github.com/xxx/releases/download/v1.0/my-tool"
},
"download-to-workdir": {
"$name": "configs",
"default.json": "https://example.com/default.json"
},
"command": {
"type": "bin",
"entry": "my-tool",
"desc": "My platform-specific binary tool"
},
"alias": {
"@tool": {
"run": "byk my-tool",
"config": "byk my-tool --config"
}
}
}
}
注意事项
byk.json 中的 key 不能包含 /,因为 / 在 spec 语法中用于分隔仓库地址和 key
- Ref 引用支持 URL(
http(s)://)和相对路径两种写法,相对路径遵循 ./xxx 规则
- 一个插件的
command 和 commands 可以共存,但 commands 中不能定义与插件 key 同名的子命令
- 单命令插件推荐使用
command,多命令插件使用 commands
- 操作块按固定顺序执行:
pip-keep → pip → downloads → download-to-workdir → download-to-alias → commands / command → alias
- 使用
--cdn 时,所有 raw.githubusercontent.com 的 URL 自动转换为 jsDelivr CDN 加速
- 顶层
$var/$default 为系统字段,不会被视为有效 plugin key