Skip to content

网页、桌面与编辑器 ​

除了终端界面,noeta 还有网页版(web/)、桌面版(desktop/),以及给编辑器用的 Agent Client Protocol 接入(noeta acp)。本页讲每种怎么跑,以及怎样把它们连到服务器上。

底下只有一套接口 ​

每个前端都只是同一套客户端接口(noeta/core/client.py:create、send、answer、cancel、read、watch)的翻译。前端都不保存任务状态,显示的内容全部从任务日志读出来,所以同一个任务可以先在终端里打开,再到浏览器里,再到编辑器里,每处看到的都是完整对话。

前端 协议翻译 前端用的接口 同一套接口 终端界面 noeta noeta -p · Agent SDK Claude Code 的 stream-json 编辑器(ACP) Zed · JetBrains · Neovim 网页版 浏览器里的页面 桌面版 Electron 窗口 无界面协议 stream_json.py ACP 适配层 acp.py AppAPI LocalApp 存储和工人都在本地 RemoteApp 同样的调用走 HTTP noeta serve HTTP · SSE · WebSocket 客户端接口 create · send · answer cancel · read · watch noeta/core/client.py 存储 任务日志 · 收件箱 · 认领 工人 认领任务,跑一步 --server 桌面版自己启动一个 认领 · 追加 前端不保存任务状态:都从任务日志读,所以哪个前端都能打开任意任务。
所有入口最后都落到同一套客户端接口上,背后是同一个存储和同一批工人
前端连的是代码
终端界面AppAPI:本进程里的 LocalApp,或加 --server 时的 RemoteApptui/、noeta/host/app.py、noeta/host/remote.py
noeta -p、Agent SDKClaude Code 的 stream-json 协议,本进程内noeta/cli/headless.py、noeta/host/stream_json.py
网页版noeta serve 的 HTTP 接口web/src/api/client.ts、noeta/host/http.py
桌面版网页版,连它自己启动的 noeta servedesktop/src/server.ts
编辑器(Zed、JetBrains、Neovim 等)stdio 上的 ACP,本进程内或 --servernoeta/host/acp.py
你自己的程序noeta.Client / noeta.LocalApp,或 noeta.RemoteClientPython 接口

要接入新的外部协议,就在 noeta/host 里再加一层翻译,绝不另起一套接口。

网页版 ​

网页版是一个 React 页面,调用 noeta serve 的 HTTP 接口(和 RemoteClient 调的是同一批)。它有按目录分组的对话列表、流式显示的 markdown 对话、工具卡片(Bash 输出、改文件显示成 diff、子代理嵌套显示)、和 Claude Code 选项一致的审批卡片、AskUserQuestion 表单、计划审阅、任务清单面板、斜杠命令菜单、从任务目录补全的 @ 引用、粘贴和拖入图片、模式和模型选择、用量和上下文占用、回退、重命名、归档和搜索、亮暗两种主题,以及手机尺寸的布局(web/screenshots/README.md 逐项配了截图)。

先构建,再让服务器顺带提供它:

bash
cd web && npm install && npm run build      # 输出到 web/dist
noeta serve --web web/dist                  # 需要 server 这个 extra

noeta serve 第一次生成令牌时会打印出来;打开它打印的地址(默认 http://127.0.0.1:8642/),页面会要你输入一次令牌。也可以直接放在地址里:http://127.0.0.1:8642/#token=…(# 后面的部分不会发给服务器;页面把令牌存进浏览器本地存储,并从地址栏里去掉)。点"Disconnect"会忘掉它。

页面文件本身不需要令牌就能取到(里面不含令牌),并带一条内容安全策略,只允许页面和自己的服务器通信。如果页面放在别的地方,只有你点名的来源才能调接口:noeta serve --allow-origin https://ui.example.com。

要改页面本身,在 web/ 里运行 npm run dev:它启动 Vite,把接口请求转发给一个正在运行的 noeta serve(NOETA_SERVER,默认 http://127.0.0.1:8642)。

没有的东西:云端环境、仓库和分支选择(noeta 就在服务器的目录里跑)、终端面板和文件树。对话不能删除,因为存储会保留每个任务的日志;想让它不出现在列表里就归档。

桌面版 ​

桌面版就是装进 Electron 窗口的网页版,后面连一个它自己启动、自己关闭的本地 noeta serve。不用连接、不用粘贴任何东西:启动时它找到 noeta,挑一个空闲的本机端口,为这次运行生成一个新令牌,然后启动

text
noeta serve --host 127.0.0.1 --port <空闲端口> --web <构建好的网页版> [--allow-root DIR …]

令牌放在服务器进程的环境变量里(NOETA_SERVER_TOKEN),从不出现在命令行上(desktop/src/server.ts)。退出应用时服务器随之停止。

bash
cd desktop && npm install
npm run web          # 先构建 ../web
npm start            # 构建并打开应用
npm run dist         # 安装包:macOS dmg、Linux AppImage 和 deb(未签名)

它在 PATH 以及 ~/.local/bin、/opt/homebrew/bin、/usr/local/bin 里找 noeta(从程序坞启动的应用拿不到登录 shell 的 PATH);要指定别的位置,设 NOETA_DESKTOP_NOETA,或在应用的 settings.json(Settings,⌘,)里写 noetaPath。找不到时窗口里会显示安装命令,那条命令带着 server extra。File > Open Project Folder(⌘O)选新对话的工作目录。服务器在你的主目录里运行,所以主目录下的文件夹直接就能用;主目录以外的文件夹会加成服务器的 --allow-root,服务器因此要重启(有对话正在跑或在等你时会先问一句;desktop/src/main.ts)。本地服务器挂了,窗口会显示它最后的输出,View > Reload 重新启动它。窗口在后台时,某个对话需要你、或者跑完了,会弹系统通知。

桌面版总是跑自己的本地服务器;要连远端服务器,打开那台服务器提供的网页版。

编辑器:noeta acp ​

noeta acp 在 stdin 和 stdout 上提供 Agent Client Protocol,Zed、JetBrains 系列 IDE、Neovim 等 ACP 客户端都能把 noeta 当作自己的代理。需要 acp 这个 extra:

bash
uv tool install --reinstall --with 'noeta-tui @ git+https://github.com/initxy/noeta#subdirectory=tui' \
  'noeta[acp] @ git+https://github.com/initxy/noeta'

在 Zed 里,把它加进 settings.json:

json
{
  "agent_servers": {
    "noeta": { "command": "noeta", "args": ["acp"] }
  }
}

模型和 provider 和终端界面一样,读 noeta 自己的设置(编辑器的环境变量会传给这个进程,所以在那里设 NOETA_MODEL 和 NOETA_API_KEY 也行)。args 里写上 --effort(或者用 NOETA_EFFORT、config.toml 的 effort)和 --permission-mode(如 ["--permission-mode", "acceptEdits", "acp"]),就定下了每个新会话起步时的推理强度和权限模式。

对应关系(noeta/host/acp.py):

  • 一个 ACP 会话就是一个 noeta 任务。 session/new 在编辑器的目录里建任务;session/load 打开已有任务并重放历史。任务记下的东西一落进日志,就翻译成 ACP 的会话更新:文字、思考过程、带类别和 diff 的工具调用、计划(任务清单)。
  • 审批以 ACP 权限请求的形式交给编辑器,选项和终端里的卡片一样(改文件的带 diff);子代理的审批也一样冒上来。ACP 没有提问表单:AskUserQuestion 以文字加选项的形式显示,你的下一句话就是回答。
  • 模式和模型对应会话的 modes(任务提供的权限模式)和一个模型选项(目录里的模型和别名,外加 default,即代理自己的模型)。
  • 斜杠命令是代理插件提供的命令,再加适配层自己的四个:/model [name]、/context、/cost、/rewind [n] [both|conversation|code](文件在本地改回去;那句提问之前的对话在一个新会话里继续,需要你去加载)。
  • 编辑器为会话指定的 MCP 服务器只交给这棵任务树的 MCP 插件,并且只放在内存里:它们的环境变量和请求头是凭据,绝不进任务日志。
  • 提问里的图片和嵌入的上下文都能接收。

连到服务器 ​

终端界面和 noeta acp 都可以不在本地跑,改为操作服务器上的任务;网页版和桌面版本来就是这样。

bash
# 在服务器上
export NOETA_SERVER_TOKEN=$(openssl rand -hex 32)
noeta serve --host 0.0.0.0 --allow-host api.internal

# 在你的机器上
export NOETA_SERVER_TOKEN=...                   # 同一个令牌
noeta --server http://api.internal:8642         # 终端界面
noeta acp --server http://api.internal:8642     # 编辑器(写进 agent_servers)

noeta serve 总是要求 bearer 令牌(只有监听本机回环地址时才能用 --no-token);没设 NOETA_SERVER_TOKEN 时,它第一次启动会生成一个、只打印这一次,~/.noeta/server-token 里只存它的 SHA-256。客户端启动前会带着令牌请求一次 GET /agents,不通就说清楚哪里不对(noeta/cli/server_token.py)。

连到服务器的前端不需要自己的模型。新任务用服务器的模型、在服务器的目录里跑,除非 --model 指定了模型,或 --cwd PATH 指定了服务器上的目录(不在服务器目录和它的 --allow-root 范围内的会被拒绝)。插件、代理、技能和设置都是服务器那边的:--plugin-dir 会被拒绝,/reload-plugins 会让你去重启工人。请求只能设置客户端被允许设置的那些任务配置(模型、推理强度、权限模式等);服务器启动时没加 --allow-bypass-permissions,bypassPermissions 一律拒绝。noeta -p 总在本地跑,拒绝 --server;程序想对服务器用无界面协议,就连它的 /stream-json WebSocket。

部署、工人、工作区和令牌的细节见作为服务端运行;所有接口见 HTTP / WebSocket 接口。