兼容 Claude Code、可以自己部署成多机集群的编程智能体。
兼容 Claude Code · 一个 Postgres 配任意多个工人 · 哪个工人都能接着跑任何任务 · 等人回复不占进程
文档 ·
快速上手 ·
设计与原理 ·
跑分 ·
English
---
**noeta** 是一个编程智能体:在模型看来它就是 Claude Code,在你看来它是一个服务端程序。
模型拿到的工具、提示词规则、提醒和请求结构都和 Claude Code 一样,所以模型在 Claude Code 上练出来的
习惯原样有效,你现有的 Claude Code 设置、hooks、技能、子代理、MCP 服务器和插件也都能用。底层每个
任务都是存储里的一条日志:让任意多个工人连同一个 Postgres,哪个工人都能接着跑任何任务;等人回复的
任务一个进程都不占。单机用 SQLite 也照样能跑,可以在终端里直接用,也可以嵌进 Python 程序。
## 亮点
- 🌐 **自己部署,工人想加几个加几个。** 一个 Postgres 存储,任意多个 `noeta worker` 进程,前面一个
`noeta serve`。任务不归哪个工人所有:每一步都是先认领、再执行、再追加到任务日志里,所以下一步在
哪个工人上跑都行。发版重启、进程崩溃、整台机器没了,任务只是换个工人接着跑;当时正在执行的工具
调用会如实告诉模型「结果未知」,绝不会悄悄再跑一遍。
- ⏸️ **等待不占进程。** 等审批、问人问题、等子代理、等定时器,任务都会挂起:它只是存储里的一行记录
和一条日志,背后没有进程也没有工人,几分钟还是几周后回复到了再醒。
- 🧠 **兼容 Claude Code,而且有核对。** 工具名和参数、提示词规则、提醒、上下文压缩都跟着 Claude Code
走。`make parity` 会离线重放录下来的 Claude Code 真实会话,把 noeta 发出的每个请求和 Claude Code
的逐个比对;有意保留的差异都单独列出并写明原因。设置、hooks、技能、子代理、MCP、插件目录都用
Claude Code 的格式。
- 💻 **单机也能用。** 同一套代码在一个进程里用 SQLite 就能跑:终端界面、`noeta -p`,或者当作库嵌进
你的 Python 程序。
- 🔌 **怎么接都行。** 全屏终端界面、Claude Code 的 `-p` 和 `stream-json` 协议(Agent SDK 可以直接
接上)、给 Zed 等编辑器用的 ACP、HTTP / WebSocket API、Python SDK;另有网页版和桌面版,都还在
实验阶段,需要从源码构建。
- 🤖 **模型随便换。** Claude、DeepSeek,或者任何 OpenAI 兼容 / Responses 接口,包括你自己部署的
vLLM 或网关。
- 🧩 **一切都是插件。** 文件、shell、权限、hooks、技能、子代理、MCP、记忆、压缩,全都实现同一个
`Extension` 接口,内置插件和你写的插件加载方式完全一样。
- 🔒 **不往外发任何东西。** 没有遥测、不上传日志、不检查更新。除了你配置的模型服务商,
只有模型按你的权限规则调用工具时才会联网。
## 跑分
两边用的是同一个模型 DeepSeek V4.1 Flash(effort `high`),不是 Claude 模型;同一批任务、同样的
限制、同一台机器:
| 测试集 | noeta | Claude Code | 差值(标准误) |
|---|---|---|---|
| SWE-rebench 07-2026(111 题,两轮合并) | 50.5 % | 45.0 % | +5.4(3.6) |
| 跑完 111 题一轮的花费 | $5.01–5.77 | $5.70–6.25 | |
结论是持平或略好:差值大约是 1.5 个标准误,不算显著,单跑一轮本身就会上下浮动 5 个百分点左右。
每一轮的结果、重试情况、答案泄露的题目,见[完整跑分报告](https://initxy.github.io/noeta/zh/benchmarks)。
## 快速上手
需要 Python 3.11 以上。
```bash
uv tool install 'noeta[tui]' # 或者:pip install 'noeta[tui]'
export ANTHROPIC_API_KEY=sk-ant-... # 用别的模型见下面
export NOETA_MODEL=claude-sonnet-5-5
noeta # 在当前目录打开全屏终端界面
noeta -p "这个仓库是做什么的?" # 问一句,打印回答
```
用别的模型(DeepSeek、OpenAI 兼容接口、自建网关)
```bash
export NOETA_PROVIDER=openai_compat NOETA_BASE_URL=https://api.deepseek.com/v1
export NOETA_MODEL=deepseek-flash NOETA_API_KEY=...
```
`openai_compat` 的地址以 `/v1` 结尾;`anthropic` 只写到域名;`openai_responses` 写完整的
`…/v1/responses`。这些设置也可以用命令行参数(`--model`、`--provider`、`--base-url`)或者写进
`~/.noeta/config.toml`。详见[模型与服务商](https://initxy.github.io/noeta/zh/guides/models)。
日常用法
- `noeta -c` 接着这个目录里最近的一次对话;`noeta -r` 列出所有对话。
- 项目说明读 `NOETA.md`,没有就读 `AGENTS.md`。
- 技能从项目里和家目录下的 `.noeta/skills`、`.agents/skills` 加载。
- 项目自己的 `.noeta/` 设置、子代理、技能和插件,要先 `noeta trust` 才会加载。
- `noeta -p --output-format stream-json --input-format stream-json --verbose` 说的是 Claude Code
的 SDK 协议,Claude Agent SDK 可以直接驱动它。
可选组件
| 组件 | 提供 |
|---|---|
| `tui` | 终端界面(`noeta-tui`,和 noeta 同版本发布) |
| `acp` | `noeta acp`:给 Zed 等编辑器用的 Agent Client Protocol |
| `server` | `noeta serve`:HTTP / WebSocket API |
| `postgres` | Postgres 存储,多工人部署用 |
| `keyring` | 插件设置里用 `{keyring:service/user}` 引用密钥 |
一次装几个:`uv tool install 'noeta[tui,server,postgres]'`。
## 部署到多台机器
一个 Postgres、任意多个工人、前面一个 HTTP API:
```bash
export NOETA_STORE=postgres://noeta:...@db.internal/noeta
noeta worker --concurrency 16 # 每台工人机器上跑
noeta serve --no-worker --host 0.0.0.0 # API(需要 bearer token)
noeta --server http://api.internal:8642 # 终端界面连过去
```
工人挂了什么也不会留下:别的工人从日志停下的地方接手。详见[作为服务端运行](https://initxy.github.io/noeta/zh/guides/server)。
想先在一台 Docker 主机上试试,[`deploy/`](https://github.com/initxy/noeta/tree/main/deploy) 里有
Dockerfile 和一份 compose 文件(Postgres、`noeta serve` 加三个工人),说明见
[用 Docker 部署](https://initxy.github.io/noeta/zh/guides/docker)。
## 嵌进 Python
```python
import asyncio
import noeta
from noeta.core.events import ModelReplied
async def main() -> None:
store = noeta.store("sqlite:///tasks.db")
agents = {a.name: a for a in noeta.default_agents("claude-sonnet-5-5")}
model = noeta.provider("anthropic", api_key="sk-ant-...")
runtime = noeta.Runtime(store=store, agents=agents, provider_for=lambda _name: model)
client = noeta.Client(store)
task = await client.create("main", "What does this repository do?", config={"cwd": "."})
await runtime.run_until_idle()
replies = [r.event for r in await client.events(task) if isinstance(r.event, ModelReplied)]
print(replies[-1].response.message.text)
asyncio.run(main())
```
`noeta.LocalApp` 把存储、工人和客户端放在一个进程里;`noeta.connect(url)` 连一个存储地址或者
`noeta serve` 服务。详见[嵌入到程序里](https://initxy.github.io/noeta/zh/start/embedding)。
## 扩展
用 Python 写插件,通过 entry point 发布,或者直接丢一个文件到 `~/.noeta/plugins/`。子代理是
Claude Code 格式的 markdown 文件,提示词都有名字、可以覆盖,Claude Code 的插件目录原样加载。
[写插件](https://initxy.github.io/noeta/zh/guides/plugins) ·
[和 Claude Code、pi、DeepSeek Harness 的对比](https://initxy.github.io/noeta/zh/operations/comparison)
## 原理
```
终端界面 · -p / stream-json · ACP · HTTP API · 网页 · 桌面 · Python
│ 同一套客户端 API
▼
┌─────────────────────────────┐
│ 存储:每个任务一条日志 │ SQLite 或 Postgres
└─────────────────────────────┘
▲ 认领 · 重放 · 走一步 · 追加
工人 工人 工人 … (模型看到的内容由插件拼出来)
```
工人认领一个任务,把日志重放成当前状态,调一次模型,跑完工具,再把发生的事追加回日志。每次写入
都带着它预期的位置和手里的认领凭证,所以一个卡住、丢了认领的工人永远写不进去。
[设计与原理](https://initxy.github.io/noeta/zh/how-it-works/)讲了每个部分怎么做、为什么这么做。
## 参与贡献
欢迎提 issue 和 PR。先看 [CONTRIBUTING.md](https://github.com/initxy/noeta/blob/main/CONTRIBUTING.md);
术语表在 [CONTEXT.md](https://github.com/initxy/noeta/blob/main/CONTEXT.md),设计决策在
[docs/adr/](https://github.com/initxy/noeta/blob/main/docs/adr/index.md)。安全问题见
[SECURITY.md](https://github.com/initxy/noeta/blob/main/SECURITY.md),变更记录见
[CHANGELOG.md](https://github.com/initxy/noeta/blob/main/CHANGELOG.md)。
## 许可证
[Apache-2.0](https://github.com/initxy/noeta/blob/main/LICENSE)