内容
# Ghantika
> 🚧 **早期阶段**。该项目仍处于初期阶段,发展迅速。后台命令运行器和所有六种工具(运行、状态、列表、输出、跟踪和终止)都是真实且经过测试的,由轮询驱动。Tasks扩展程序也将在README中描述,这是项目的发展方向,但尚未实施(参见路线图);如果您遇到其他问题,请将其视为不完善的产品,而不是隐藏的缺陷。
**Ghantika在后台运行命令,并在命令完成后立即通知您的代理,以便您的代理可以启动长时间的任务并继续工作,而不是等待命令完成。**
[](https://github.com/yaanfpv/ghantika/actions/workflows/ci.yml)
[](LICENSE)
[](https://modelcontextprotocol.io)
当您要求AI代理执行需要长时间的任务(例如构建、渲染、大型上传或训练运行)时,今天它会做以下两件令人讨厌的事情之一。它要么每隔几秒钟检查一次任务,浪费令牌在每次检查上;要么它直接阻塞,等待命令完成,什么也不做。
Ghantika解决了这个问题。当您给Ghantika一个命令时,它立即在后台运行,不会阻塞。代理获得一个作业ID,可以继续执行其他任务。命令产生输出或完成时,Ghantika会通知代理,代理可以继续处理结果。
**只需设置一次,即可 everywhere使用**。它是一个标准的[MCP](https://modelcontextprotocol.io)服务器,通过stdio运行,因此每个支持MCP的客户端都可以使用相同的六种工具启动作业并读取它们,只需通过轮询。通知是未来的发展方向:主机在作业更改时直接唤醒,而不是通过询问。每个客户端今天都以相同的方式读取相同的作业,并且作业运行不受任何观察。
---
## 您可以用它做什么
**启动构建并继续工作**。“在后台运行测试套件,并在完成后通知我。”您的代理启动测试套件,继续执行其他任务,并在Ghantika通知时返回,获取退出代码和输出。
**链接一个不需要阻塞代理的管道**。渲染场景,编码输出,上传它,等待处理,发布它。链条中的每个长时间步骤都是Ghantika运行的命令,当命令完成时,Ghantika会通知代理,因此代理不会在它们之间闲置。
还有很多其他功能,适用于每种类型的用户:
| 配方 | 适用对象 | 在后台运行 |
| --- | --- | --- |
| 自运行代理团队 | 代理构建者 | 每个队友等待下一个消息 |
| ComfyUI渲染到发布视频 | AI艺术家、创作者 | 渲染,然后上传处理 |
| 等待CI变为绿色 | 开发者 | 拉取请求的检查运行到完成 |
| 等待大下载或导出 | 每个人 | 下载或导出本身 |
| 等待训练运行完成 | 机器学习工程师 | 整个运行,耗时数小时 |
## 它是如何工作的
您给Ghantika一个命令,就像在终端中输入一样:一个argv数组或一个shell字符串(如果需要管道和重定向)。它以真正的后台进程启动命令,并立即返回作业ID,而命令不一定产生任何输出。调用`run`不会阻塞。
从那里,代理通过轮询与作业保持同步:`status`获取作业的当前状态和退出信息,`output`或`tail`获取作业的输出。直接通知支持Tasks的主机,作业产生输出或退出,而不是代理询问,是计划中的功能,尚未实施(参见路线图)。无论哪种方式,作业都是真实的,不受影响:在`run`返回后,作业在Ghantika的管理下运行,无论是否有人正在监视它。
作业的输出在产生时被捕获,stdout和stderr分别跟踪,因此`output`和`tail`读取进程实际写入的内容,而不是快照。每个流都保留一个有界的窗口:最近10,000行或1 MiB,先到先得。例外情况是单个行超过限制:该行将全部保留(以及一点开销用于其自身的延续标记),而不是进一步截断。
## 需求
- **Node.js 22+**
每个直接运行时依赖项都固定为确切版本,没有可能悄悄更改的`^`/`~`范围,并且在项目的CI中作为其自身的一部分进行结构检查,因此不会在不知不觉中发布宽松的范围。
## 安装
全局安装使用`npm install -g ghantika`,或跳过安装直接从npm运行(`npx -y ghantika`),或克隆此仓库并指向`dist/index.js`。
## 设置
### Codex
添加到`~/.codex/config.toml`:
```toml
[mcp_servers.ghantika]
command = "ghantika"
args = []
```
### Claude Code
```bash
claude mcp add ghantika -- ghantika
```
### Cursor、Cline、Claude Desktop等
这些读取一个JSON配置文件,其中包含一个`mcpServers`对象。添加一个Ghantika的条目:
```json
{ "mcpServers": { "ghantika": { "command": "ghantika", "args": [] } } }
```
### 任意其他代理
将代理的MCP配置指向`ghantika`命令(或`node /path/to/dist/index.js`)。它是一个标准的MCP服务器,通过stdio运行,因此如果您的代理支持MCP,它就起作用了。
## 使用它
您不需要调用任何东西。只需告诉您的代理要运行什么以及您不想被阻塞:
> 在后台运行构建,并在完成后告诉我。
> 启动上传,完成后让我知道,以便我可以分享链接。
> 启动训练运行。当它退出时,报告最终数字。
您的代理启动命令,继续工作,并在结果准备好时取回结果。
<details>
<summary>内部工作原理,供好奇者参考</summary>
您的代理发送一个`tools/call`请求,命名`run`:
```json
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": { "name": "run", "arguments": { "command": ["npm", "test"] } }
}
```
并在作业尚未产生其spawn事件、写入字节或退出之前获取作业:
```json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [{ "type": "text", "text": "{ \"job_id\": \"a1b2c3d4\", ... }" }],
"structuredContent": {
"job_id": "a1b2c3d4",
"state": "starting",
"started_at": "2026-03-11T18:42:05.117Z",
"command_summary": "npm",
"label": "job a1b2c3d4",
"counts": { "stdout_lines": 0, "stdout_bytes": 0, "stderr_lines": 0, "stderr_bytes": 0 }
}
}
}
```
</details>
## 它与代理已经具备的功能有何不同
一些代理运行时提供一个简单的“运行命令”工具。以下是Ghantika在此基础上添加的内容:
- 普通的运行命令工具会阻塞整个回合,直到进程退出。Ghantika立即返回作业ID,进程继续运行,无论是否有人正在监视它。
- 将进程后台化,而不提供稍后检查的方法,意味着进程完成的那一刻在您转移注意力后就会丢失。Ghantika在服务器运行期间将作业的状态和输出存储为ID可访问,因此`status`/`output`/`tail`在您实际询问时给出正确答案。
- 固定的睡眠和重新检查循环每次猜测需要多长时间都会消耗一个完整的往返。Ghantika根据作业的实际状态(而不是您预先估计的计时器)给出答案;直接在状态更改时通知,而不是等待询问,是计划中的功能(参见路线图)。
新增功能不是运行后台命令,而是永远不必在阻塞它和丢失跟踪之间做出选择。
## 配置
`run`工具接受:
| 参数 | 类型 | 必需 | 含义 |
| --- | --- | --- | --- |
| `command` | string[] \| string | 是 | 要运行的命令。默认情况下为argv数组;shell字符串需要`shell: true`。 |
| `shell` | boolean | 否 | 将`command`作为shell字符串运行,而不是argv数组。 |
| `cwd` | string | 否 | 作业的工作目录。默认为Ghantika自己的目录。 |
| `env` | object | 否 | `{ "mode": "merge" \| "replace", "vars": { ... } }`。`vars`将变量名映射到值。`merge`(默认)在`PATH`和`HOME`的最小基数上层叠`vars`,或在Windows上为`PATH`、`SystemRoot`和`USERPROFILE`;`replace`仅传递`vars`而不带任何基数。 |
| `label` | string | 否 | 作业的简短人类可读名称,在`list`中显示。 |
Ghantika从不将完整环境交给作业。即使在`merge`模式下,子进程也从最小基数开始,什么都没有,只有您传递的内容。
`status`、`output`和`tail`都接受`job_id`。`tail`还接受可选的`stream`(`stdout`/`stderr`/`both`)和`lines`;`output`接受`stream`以及`after_cursor`和`limit`用于分页浏览长作业。`kill`接受`job_id`。每个工具的完整输入模式都通过`tools/list`公开,因此代理(或您)可以直接询问Ghantika,而不是信任可能已过时的文档。
## 路线图
- 上述通知:MCP Tasks扩展使Ghantika直接通知代理,而不是要求轮询,并且将其实施到位。
- 通过真正的Job Object进行原生Windows进程树终止,关闭`taskkill`留下的狭窄竞争窗口(参见下面的平台说明)。
- 为需要根据作业更改做出反应的任何内容提供文档化的稳定扩展点。
## 贡献
欢迎贡献。设计故意保持小规模,因此在开始任何大型项目之前,请先创建一个问题,我们将确定它是否适合这里。一个人们真正坐下来等待的作业配方是最有用的贡献。
## 许可证
MIT。参见[LICENSE](LICENSE)。由[@YaanFPV](https://github.com/YaanFPV)构建。
## 平台说明
在POSIX上,用信号杀死作业会同时向作业的整个进程组发送信号,这是原子的 - 没有窗口使部分树被信号,而部分没有。在Windows上,没有等效的进程组,因此kill改为调用`taskkill /pid <pid> /t /f`:真正的递归杀死整个进程树,但不是原子的 - 窗口存在竞争风险,真正的Windows Job Object会关闭它。目前,该项目没有本地/FFI依赖项来实现正确的Job Object,因此`taskkill`是诚实的回退,而不是声称它提供的保证;真正的Job Object是一个跟踪的未来增强功能。
将一行无效的JSON发送到Ghantika的标准输入会得到真正的JSON-RPC `-32700`解析错误回复(`id: null`),连接正常后继续工作 - 下一个请求单独服务。 这是惯例的JSON-RPC行为,但它不是自动的:Ghantika在其底层MCP SDK上添加了此功能,SDK本身会静默丢弃解析失败的行,而不是回复它。 如果您编写客户端并且发送的格式错误的邮件没有回复,那是您这边的问题,而不是Ghantika故意保持沉默。
## 开发
需要Node.js 22或更高版本。克隆后每个安装都通过`npm ci`,而不是`npm install`,因此每个人都会获得`package-lock.json`中记录的确切依赖树:
```bash
npm ci
npm run build
npm test
```