Dots Agent

by duyongan• 158•• Scanned•Claim this listing•Request removal
Coding Agentsai agentautomationautonomous agentsdeepagentslanggraph

一个会主动发现任务的智能体

Dots Agent is an open-source ai agent by duyongan, written mainly in Python, with 158 GitHub stars and the MIT license. Its code was last updated Oct 20, 2026. The latest PyPI release is dots-agent 1.2.0, published Oct 20, 2026, with 81 downloads last week.

dots-agent

一个会主动发现任务、主动积累技能的智能体。

包名 dots-agent,命令是 dots(装完就有)。两种用法:命令行,或者 Windows 桌面窗口。

2.0 起它不止会接活,还能把一条需求从头送到尾:

  • 全流程流水线:需求分析 → 原型设计 → 开发 → 测试 → 修复 → 归档,阶段推进看产物不看嘴。 见 全流程流水线。
  • 本体库:从公司库(PG / MySQL / Mongo)采元数据,存成一份可以手改的 JSON, 再派生文档和代码;改完一条命令,全流程的文档和代码一起变。见 本体库。
  • MCP:飞书、Jira、Sigma、GitLab 的工具直接挂到手上,走同一套审批闸门。见 MCP。
  • 微信群 BUG 监控:用本机微信 UI 自动化(pyweixin)扫群,或让桥写 spool; 报错自动去重、进台账、开修复流水线。见 微信群 BUG 监控。

安装

命令行

pip install dots-agent

国内镜像(清华、阿里等)同步新包有延迟,刚发布的几天可能报 No matching distribution found。加官方源即可:

pip install dots-agent -i https://pypi.org/simple

或者不装,直接在仓库里跑(两种方式命令都通用):

git clone https://github.com/duyongan/dots-agent
cd dots-agent
python -m dots serve

桌面版(Windows)

怎么打开

日常使用双击 dots.exe(或者桌面/开始菜单里的 dots 快捷方式)。装好之后它在:

%LOCALAPPDATA%\Programs\dots\dots.exe

dots-<版本>-setup.exe 只是安装器,装一次就行,不是日常打开方式。

安装

安装包由打包命令生成到 release/(该目录不进仓库):

release/dots-<版本>-setup.exe

双击安装。安装器是按用户安装,不需要管理员权限,默认装到 %LOCALAPPDATA%\Programs\dots。安装过程中可以改目录;会创建桌面快捷方式和开始菜单项。 卸载走 Windows 的「设置 → 应用 → 已安装的应用 → dots」。

安装包自带一份嵌入式 Python 和全部依赖(resources/runtime/),机器上没装过 Python 也能跑。

不想安装也可以直接运行 release/win-unpacked/dots.exe。它旁边必须保留 resources/ 目录(运行时都在里面),不能只把这个 exe 单独拷走。

自己打包:

cd desktop
python make-runtime.py    # 首次,或 dots/ 源码改动后(Windows 没 Bash 也能跑)
npm run dist              # 生成 release/dots-<版本>-setup.exe

有 Git Bash 的机器也可以用等价的 bash make-runtime.sh; 两个脚本做的事一样(下载嵌入式 Python + pip --target + 拷贝 dots)。

在仓库里开发

cd desktop
npm start

开发模式不打包,直接用系统上的 Python;工作目录是仓库根,所以会读仓库根或 ~/.dots/ 下的 dot.toml。

快速开始

dots init --global         # 配一次,以后 cd 到哪都能敲 dots
dots doctor                # 体检一下
dots goal "把 inbox 里的东西整理成一份报告"
dots serve --web           # 常驻跑起来,同时开活动视图

--global 把配置写到 ~/.dots/,数据和 workspace/ 也跟着放那儿 —— 一份到处用,换个目录不用再 init。不带参数就是 dots init,只写当前目录, 那样每个目录都得配一次。

也可以不带子命令,直接进交互终端。里面直接打字就是和它说话, / 开头才是命令:

$ dots
dots> 工作区里现在有什么?帮我看看该先处理哪件事
      (它自己去翻文件,然后回你)

dots> /goal "把 inbox 整理成一份周报"     ← 交给后台慢慢跑
dots> /ls
dots> /exit
输入干什么
直接打字和它对话。记得上下文,能接着追问
/命令命令行那些命令,前面加个 /(见下表)
/help看全部命令
/exit退出(Ctrl-D、Ctrl-C 也行)

对话走的是同一个大脑、同一个工作区,但它不是目标:不进 dot ls, 后台 tick 也不碰它,所以不会算进你的目标队列。要让它后台跑,用 /goal。 它想在对话里做 ask 类动作(比如发邮件)时会当场问你 y/n,不走邮件审批。

每条命令都会重新读一遍配置,所以改完 dot.toml 不用退出来重进。

打开 http://127.0.0.1:8765/ 看它在干什么。

想先不配模型试一遍:

dots selftest              # 不联网、不调模型

桌面界面

一个窗口装下 dots 的全部日常操作:看它在干什么、给它派活、批准它想做的事、跟它说话。 不用开终端,不用背命令。它和命令行版共用同一份配置、同一个数据库、同一个工作区。

第一次启动前必须先有配置

这是最容易卡住的一步:

后端找不到 dot.toml 会直接退出,界面顶栏变成「后端已停」,所有按钮变灰。 此时连「生成全局配置」也点不动 —— 那个按钮要求后端已经就绪。

所以第一次使用,先在终端里生成一份全局配置:

pip install -e .          # 或按上面的方式安装 dots-agent
dots init --global        # 写到 ~/.dots/dot.toml
dots doctor               # 体检,确认模型、目录、数据库都没问题

dots init 会自动探测环境变量里的模型 key。没探到就手填 ~/.dots/dot.toml 的 [model] 段。

打包版查找配置的顺序:

  1. %APPDATA%\dots-desktop\dot.toml(也就是应用的当前工作目录)
  2. ~/.dots\dot.toml

你的数据跟着配置文件走:全局配置在 ~/.dots/,数据库和工作区也都在那儿。

启动过程

双击图标后:

  1. Electron 先画窗口;
  2. 拉起 python -m dots bridge;
  3. 后端导入 langchain 那一整串依赖,约 10 秒;
  4. 后端发出 ready,顶栏从「正在启动后端…」变成「值守中」。

这 10 秒里输入框和按钮是灰的。不是卡死。不要在这个时候狂点 —— 虽然界面会拦住, 但后端准备好之前发的命令会堆在管道里,顺序不可控。

如果后端起不来,顶栏显示「后端已停」,同时底部弹出输出面板,里面是 Python 的 stderr 尾部(常见的:「没找到配置」「ModuleNotFoundError」「API key 缺失」)。

界面总览

窗口从上到下五段:

┌────────────────────────────────────────────────────┐
│ 顶栏:dots  ● 值守中  每 60s 一轮  [停止]   [体检]  │
├────────────────────────────────────────────────────┤
│ 待批横幅(只在有事等你时出现)                       │
├────────────────────────────────────────────────────┤
│ 目标        │ 技能          │ 活动                  │
│ (三栏监控区)                                        │
├────────────────────────────────────────────────────┤
│ 对话                                                │
│ 你/它 的消息……                                      │
│ [ 说点什么…(回车发送)                        ]      │
├────────────────────────────────────────────────────┤
│ ▴ 全部命令(展开后是一整排中文按钮)                 │
└────────────────────────────────────────────────────┘

窗口最小 720×520。窗口高度不足 640px 时,命令抽屉会自动收起且把手不可点, 保证上面的内容不被挤没。

顶栏:状态与值守开关

后端状态:

文字含义
正在启动后端…Python 子进程正在导入依赖,按钮全灰
值守中后端就绪,可以操作
正在停止…正在优雅退出后端
后端已停进程退出或起不来,详情看输出面板

顶栏中间显示:

  • 每 60s 一轮:循环在跑。数字来自 [dot] tick_seconds。
  • 循环已停:循环没跑,但后端还活着,你仍然可以手动「跑一轮」、聊天、点命令。

右边按钮:

  • 停止:请求停下循环。如果它正跑着一个目标,不会立刻停 —— 要等这一轮结束。 按钮会一直是「停止」,直到后端推来 loop_stopped。急着关窗口也没事, 关闭时会先把没跑完的目标放回队列。
  • 开始值守:重新启动循环。

循环默认在界面启动时自动开启。它的存在感就是「主动」:不用你喊,它每轮自己找活干。

顶栏最右边「体检」= dots doctor。逐项检查:配置文件、读配置、审批规则、依赖、模型、 工作区可写、数据库、事件源、审批通道、技能库、bot、成本上限。每项失败都会给一句 「下一步怎么做」。

待批横幅:它停下来等你

只有存在挂起审批时才出现,是整个界面唯一用琥珀色强调的地方。

⚠ a7f3 想发邮件给 alice:「周会改到周四」  (还有 2 个)
   a7f3 [批准] [拒绝]   b91c [批准] [拒绝] …
  • 摘要会尽量说人话:send_email 显示收件人和主题,run_shell 显示命令, 其它动作显示工具名。
  • 每个审批有唯一编号(token)。点「批准」= dots approve <token>, 「拒绝」= dots reject <token>。
  • 决定写进 approvals 表,下一轮 tick 自动续跑对应目标。邮件回复和这里点按钮 走的是同一条路径。
  • 一直不批:超过 [approval] timeout_hours(默认 72 小时)自动按拒绝处理。 这比无限等待好 —— 一个永远等不到回复的审批就是一个悄悄卡死的目标。

哪些动作需要批,由 dot.toml 的 [approval.rules] 决定:

[approval.rules]
send_email = "ask"     # 挂起,等人批
save_skill = "allow"   # 直接执行
run_shell  = "deny"    # 永不执行

没写到的动作一律 ask(默认从严)。

目标面板

目标 = 一件要它做的事。每行显示:

列含义
编号目标 id,也是交接/日志里的标识
状态见下表
目标原文你写的或它自己派生的任务
结论agent 完成时给的 summary
证据工作区路径、邮件 id、URL 等可核对的东西
数字这个目标累计消耗的 token
时间最后更新的时间(12s / 3m / 2h / 2d)
日志只看这个目标的活动记录

七种状态:

界面文字内部值含义
待批准pendingagent 自己派生出来的目标,要你点头才跑
排队中ready等着被某一轮 tick 领走
在跑running正在执行
停下等你interrupted撞上审批闸门,等批准/拒绝
待复核pending_review它说完成了但没给证据,需要人看一眼
完成done完成且给了证据
失败failed执行失败

「待复核」值得单独说:一个没有证据的结论没法核对,所以不会直接算完成。

面板按钮:

按钮等价命令行为
新建目标原生 goal弹输入框,写进 goals 表,状态直接 ready(你亲手写进去的,视为授权)
跑一轮dots tick手动跑一轮就退,调试用。循环运行时按钮置灰;后端也会拦住并发的 tick
全部目标dots ls输出完整列表(界面里的 60 条只是快照)
活动日志dots log输出最近 30 条活动

「新建目标」走的是 bridge 的原生命令,不是 CLI:不会在输出面板里打印 「跑起来:python -m dots serve」这种在界面里很误导的提示。它固定交给默认 bot dot。

目标列表最多显示最近 60 条,多了会静默截断。

技能面板

技能是 agent 干活时自己总结出来的可复用流程,存在工作区里,每份是一个目录, 里面有 SKILL.md(YAML frontmatter + 正文)。

面板每行显示技能名和一句话描述。技能库是渐进披露的:只有「名字 + 描述」每轮会进 系统提示,正文等真用到时才读。所以描述被硬性限制在 60 字符,超出部分每轮都会被截断。

按钮等价命令行为
学习dots learn <材料或描述>弹输入框;创建一个 origin=cli:learn 的 ready 目标,让 agent 把材料总结成技能。它不会立刻执行,要等循环或手动跑一轮
技能库dots skills输出技能表(名称、描述长度、描述)
整理技能dots curate创建整理目标,让 agent 合并重复、删除没价值的。会真的删改文件,会先弹确认;技能少于 2 份时命令直接说没什么好整理的

每行右侧还有两个小按钮:

  • 看:dots skill show <名>,在输出面板里显示 SKILL.md 全文。
  • 删:dots skill rm <名>,删除整个技能目录。会弹确认,确认按钮写「删掉」。

技能库为空时,面板会提示:它干活时会自己攒,「学习」也能喂材料。

活动面板

完整流水:收了事件、建了目标、被哪条规则拦下、什么时候跑完、循环启停、错误栈。

数据来源有两份,合并后按时间排序,最多显示最近 120 行:

  1. 数据库 audit 表的快照(最近 60 条);
  2. 本次运行期间后端实时推来的 log / fatal / loop / 协议错误(最多缓存 300 条)。

每行是 时间 | 类型 | 详情。出问题时先看这里。

按钮等价命令说明
用量dots cost今日和累计 token 用量
自检dots selftest不联网、不调模型,跑四个模块的 demo() + 全套测试,约 30 秒

对话区

直接打字就是跟它说话,回车发送。它用的是同一个大脑、同一个工作区:让它读文件、 查资料、写东西,它会真的动手,不是只描述打算怎么做。

特点:

  • 不是流式的:发送后显示「正在想…」,慢模型下可能要等十几秒才出整段回答。
  • 有上下文:对话用固定的 thread_id = "chat",checkpoint 存在 dot.db 里, 关掉应用再打开,之前的对话还在。
  • 和后台目标是两条线:聊天不占目标队列,后台 tick 也不碰它。要让一件事在后台慢慢跑, 用「新建目标」。
  • 界面里最多保留最近 300 条消息用于显示,更早的仍在 checkpoint 里。

聊天时它如果想做 ask 类动作,会当场弹窗,不走待批队列:

它想干这个
send_email
{ "to": "alice@example.com", "subject": "周会改到周四", ... }
[拒绝] [批准]
  • 你在弹窗里做的决定只影响这一次对话。
  • 拒绝之后它会记住:同一件事再做,它会引用规则告诉你「被拒了不要重试」。
  • 最多等 10 分钟(600 秒)。超时按拒绝处理;如果你在超时后才点「批准」, 界面会明确告诉你「这个审批已经过期了,agent 早按拒绝处理了」,不会假装成功。
  • 弹窗期间聊天线程阻塞等待,但读 stdin 的是另一条线程,所以界面不会卡死。

对话功能是懒启动的:第一次发消息才建图,要几秒钟。不聊天就不付这个成本。

命令抽屉:全部按钮

底部「▴ 全部命令」展开后,是 dots 的全部日常子命令。按钮上写中文,不写原始命令名; 鼠标悬停会说明它做什么,并带出对应的 dots xxx。

展开状态记在本地(localStorage),下次打开还是那样。

分组按钮实际命令需要参数二次确认
配置生成配置dots init——
配置生成全局配置dots init --global—✓
配置体检dots doctor——
配置自检dots selftest——
目标新建目标原生 goal目标文本—
目标跑一轮dots tick——
目标全部目标dots ls——
目标活动日志dots log——
审批批准dots approve <编号>编号(只用行内/横幅按钮)—
审批拒绝dots reject <编号>编号(只用行内/横幅按钮)—
技能学习dots learn <内容>材料或一句描述—
技能技能库dots skills——
技能看技能dots skill show <名>技能名—
技能删技能dots skill rm <名>技能名✓(按钮写「删掉」)
技能整理技能dots curate—✓
成本用量dots cost——

serve 和 bridge 不在抽屉里:常驻循环由顶栏按钮管;再起一个 worker 会抢同一个数据库。

几个按钮的细节:

  • 生成配置:在当前工作目录写一份 dot.toml。打包版的当前目录是 %APPDATA%\dots-desktop,开发版是仓库根。文件已存在时不会覆盖。
  • 生成全局配置:写到 ~/.dots/dot.toml,之后在任何目录都能用。
  • 跑一轮:只跑一轮就退。循环正在跑时按钮置灰;即使绕过界面,后端也会因为抢不到 tick 锁而拒绝,避免两个 worker 同时写同一个 checkpoint 和事件表。
  • 学习:创建的是 ready 目标,真正执行要等后台循环或手动 tick。 [skills] enabled = false 时命令会拒绝。
  • 整理技能:真的会删文件和改文件;技能少于 2 份时不会创建目标。
  • 批准 / 拒绝:只出现在待批横幅和行内,不出现在抽屉里(抽屉里没有编号可填)。

命令跑在独立的命令线程上,串行排队。一条在跑时点下一条,它会在后面等。 输出以流式事件推到输出面板,面板最终以应答里的完整输出为准。 界面给每条命令 180 秒超时;超时只是界面不再等,后端那条命令可能仍在跑完。

输出面板

命令输出从底部升起,覆盖在界面下方:

  • 标题是按钮的中文名;
  • 内容是流式追加;
  • 跑完显示「退出码 0」或红色「退出码 N」;
  • 复制:把全部输出放进剪贴板;
  • 关闭:收起面板,不影响命令本身。

「新建目标」不产生输出面板内容(成功时静默,失败时弹面板说明原因)。

界面没覆盖的功能

界面只放了日常操作。下面这些仍然要用命令行(或 dots 交互终端):

功能命令为什么不在界面里
常驻循环 + 只读网页活动视图dots serve --web [--web-port 8765]循环已由顶栏管;web 是另一条监听
干跑(不真发邮件,审批打终端)dots serve --dry-run / dots tick --dry-run调试用途
手动跑一轮(带 dry-run)dots tick --dry-run同上
指定 bot 接活dots goal --bot ops "..."界面固定用 dot
按状态筛目标dots ls --status running界面显示全部
控制日志条数dots log -n 100 [--goal <id>]界面固定 30 / 按目标查
交互终端直接敲 dots需要真人在终端前
指定配置文件dots -c path/to/dot.toml ...界面固定用自动发现的那份

交互终端里,/ 开头是命令(如 /ls、/goal "..."),裸文本是和 agent 说话, 和桌面版「对话区」是同一个能力。

网页界面(可选)

不想用桌面窗口,也可以走浏览器:

dots gui

它在本机 127.0.0.1 起一个页面并自动打开,四个页签:聊天、活动(目标/审批/流水)、 配置(模型预设 + API Key、事件源、SMTP、审批规则、预算)、技能(增删改查)。 写操作要带页面内生成的随机 token,只监听本机。

源码/pip 模式默认用 ~/.dots/。1.1.x 的 Windows 安装包里也带这个界面 (开始菜单「dots(网页界面)」,无控制台启动器 dots-gui.exe);1.2.0 起的 桌面版是 Electron 窗口,内置的不是这套网页。

命令

命令干什么
dots不带子命令 = 进交互终端。直接打字是对话,命令前加 /
dots init生成 dot.toml,扫环境变量自动配好 [model]。--global 写到 ~/.dots/
dots doctor体检:配置、密钥、模型、目录、数据库、事件源逐项查
dots goal "..."下一个目标。--bot <名> 指定交给谁做
dots serve常驻跑。--web 开活动视图,--once 只跑一轮,--dry-run 不真发邮件
dots tick手动跑一轮就退(调试用)
dots ls列目标。--status <状态> 过滤
dots log活动流水。-n 50 条数,--goal <id> 只看一个
dots approve <token>批准一个挂起的动作
dots reject <token>拒绝一个挂起的动作
dots costtoken 用量
dots learn "..."把一段材料总结成技能
dots skills列出技能库
dots skill show <名>看技能正文
dots skill rm <名>删掉技能
dots curate让 agent 整理技能库:合并重复、删掉没价值的
dots mcp list看接了哪些外部系统、缺哪个环境变量
dots mcp add jira|feishu|gitlab|sigma把一家现成的 MCP 配置写进 dot.toml
dots ontology init建一份空的 ontology/ontology.json
dots ontology sync [数据源]从公司库采元数据,合并进本体库,再派生文档和代码
dots ontology show [实体]看实体列表,或某个实体的完整定义
dots ontology edit用编辑器手改本体库,存盘后自动校验并重新派生
dots ontology apply按当前本体库重新生成派生文档和代码
dots ontology status派生层是不是落后于本体库
dots sdlc new "..."开一条流水线。--track bugfix 走缺陷轨迹,--jira 绑单号
dots sdlc ls / dots sdlc show <id>列流水线 / 看某条的阶段、产物、历史
dots sdlc sync把本体库变更同步进所有流水线文档
dots sdlc advance <id>人工跳过当前阶段(卡住时用,会留痕)
dots bugs缺陷台账(微信群报的 BUG 都在这儿)
dots bugs fix <id>...给一条或多条缺陷开修复流水线
dots bugs close <id>关掉一条缺陷
dots wechat ingest "..."手动灌一条群消息(补录 / 联调)
dots wechat collect用本机微信 UI 自动化采一次群消息
dots wechat check检查 pyweixin / 微信登录 / UI 可见性
dots wechat hook --port 8790起本机 webhook,接收桥推来的消息
dots wechat statusspool 在哪、读到哪了
dots selftest不联网不调模型跑一遍自检

找配置的顺序:-c 指定的路径 → 当前目录的 ./dot.toml → ~/.dots/dot.toml。 到处能用靠的是最后一个,dots init --global 才会写它。

-c 指了路径就不会再往下兜底 —— 写错名字直接报错,不会偷偷用上全局那份。

配置

dots init 生成一份 dot.toml,所有相对路径都相对这个文件所在目录。 密钥只写环境变量名,不写进文件。

[dot]

[dot]
tick_seconds = 60        # 心跳间隔。这就是「主动」的节拍
workspace = "workspace"  # agent 的工作目录 = 沙箱
db = "dot.db"

[model]

dots init 会自动探测,一般不用手改。支持的 key:

DeepSeek / Kimi / 通义 / 智谱 / 豆包 / 硅基流动 / Claude / OpenAI / Gemini。

第三方端点要三件套:

[model]
name = "openai:deepseek-chat"
base_url = "https://api.deepseek.com"
api_key_env = "DEEPSEEK_API_KEY"
max_tokens = 4096
temperature = 0.2

api_key_env 填的是环境变量名,不是密钥本身。打包版从开始菜单启动时继承的是 系统环境变量,不是你在某个终端里 export 的那个。

[smtp]

审批邮件和汇报从这里发出去。不配也能跑,审批退化成 dots approve。

[smtp]
host = "smtp.example.com"
port = 587
user = "me@example.com"
sender = "me@example.com"
to = "me@example.com"        # 审批邮件发给谁(通常就是你自己)
password_env = "DOT_SMTP_PASSWORD"
use_tls = true

[sources.*] 事件源

决定「没人说话的时候,什么唤醒它」。至少开一个。

[sources.fs]
enabled = true
paths = ["inbox"]        # workspace 下的相对目录
interval = 120
[sources.imap]
enabled = true
host = "imap.example.com"
port = 993
user = "me@example.com"
folder = "INBOX"
password_env = "DOT_IMAP_PASSWORD"
interval = 300
verify_tls = true        # 自建 Dovecot 用自签证书就设 false
[sources.ical]
enabled = true
url = "https://example.com/cal.ics"
interval = 900

[approval] 审批

[approval]
subject_prefix = "[dot#"
timeout_hours = 72       # 超时没人批就按拒绝处理。0 = 永远等

[approval.rules]
send_email = "ask"       # ask = 挂起等你批
run_shell = "deny"       # deny = 永不执行
save_skill = "allow"     # allow = 直接放行
# fs_* = "allow"         # 支持通配

三个值:allow 直接执行、ask 挂起等你、deny 永不执行。 没写到的动作一律 ask。 匹配优先级:精确名 > 通配 > 默认 ask。

[skills] 技能

[skills]
enabled = true
dir = "skills"           # workspace 下的相对目录

关掉后技能面板为空,「学习」「整理」会被拒绝。

[bots.*] 多 bot

[bots.ops]
prompt = "你是执行侧..."
tools = ["send_email"]   # 只给这些工具;留空 = 给全部

dot 这个 bot 永远存在,不用配。交接后新 bot 用同一条对话线(同一个 thread_id), 能看到前任做过什么。

[handoff] 交接

[handoff]
max_hops = 3             # 一个目标最多被交接几次,防乒乓

[safety] 成本

[safety]
daily_token_budget = 0   # 0 = 不限。填了数字,超了当天就不再跑新目标

[sources.wechat] 微信群监控

[sources.wechat]
enabled = false
backend = "spool"              # spool | pyweixin
library_path = ""              # pyweixin 源码目录(pywechat/src)
python_exe = ""                # 采集用哪个解释器;留空 = 当前进程
collect_timeout = 240          # 子进程采集超时(秒)
collect_interval = 300         # pyweixin 采集间隔(秒)
max_pull = 20                  # 每个会话一次最多拉多少条
spool = "wechat/inbox.jsonl"   # 两种方式共同的落地文件
groups = []                    # 空 = 全部会话;["项目A-线上问题"] = 只看这些群
keywords = []                  # 空 = 内置的报错关键词
interval = 60
max_batch = 100                # 一次最多读多少条新消息
token_env = "DOT_WECHAT_TOKEN" # webhook 鉴权;留空 = 不校验(仍然只听 127.0.0.1)

[mcp] 外部系统

[mcp]
enabled = false

[mcp.servers.jira]
transport = "stdio"                     # stdio | sse | streamable_http
command = "uvx"
args = ["mcp-atlassian"]
pass_env = ["JIRA_URL", "JIRA_USERNAME", "JIRA_API_TOKEN"]
env = { JIRA_PROJECTS_FILTER = "OPS" }  # 固定值写这里,密钥走 pass_env
timeout = 60
prefix = "jira"                         # 工具名前缀,默认就是 server 名

dots mcp add jira 会直接生成这样一段。参数和 URL 里可以写 ${VAR}, 连接时才展开 —— 所以像飞书那种必须把 app_secret 放命令行的服务, dot.toml 里也只留变量名。

[ontology] 本体库

[ontology]
enabled = true
dir = "ontology"          # ontology.json + history/
derived = "generated"     # 派生产物,整体可重建,别手改
inject_prompt = true      # 每轮把实体摘要塞进系统提示
prompt_entities = 40      # 摘要里最多列多少个实体

[ontology.datasources.crm]
kind = "postgres"         # postgres | mysql | mongodb
dsn_env = "DOT_CRM_DSN"   # 连接串放环境变量
schema = "public"         # MySQL 用 database 当 schema
include = []              # 只看这些表/集合,支持通配
exclude = ["alembic_*", "tmp_*", "sys_*"]
sample_size = 50          # mongo 采样条数

[sdlc] 流水线

[sdlc]
enabled = true
dir = "projects"          # 一条流水线一个子目录
max_fix_rounds = 3        # 测试 FAIL → 修复 → 再测,最多来回几次
auto_from_bug = true      # 微信群报的 BUG 自动起修复流水线

后台一轮 tick 做了什么

每轮固定四步:

  1. 收事件:sources.poll_all() 扫描事件源(工作区文件、IMAP 邮件、iCalendar、微信群 spool), 新事件落 events 表。UNIQUE(source, key) 保证同一件事只收一次。
  2. 路由事件:主题带 [dot# 的审批回信写进 approvals 表;群消息先过 BUG 判定和台账去重; 其它事件建成 ready 目标。
  3. 处理已决定的审批:超时的按拒绝过期,已批准/拒绝的续跑对应目标。
  4. 跑一个 ready 目标。目标完成且给了证据后,如果它属于某条流水线,就推进阶段并派下一段。

然后睡 tick_seconds 秒,再下一轮。停止请求能在睡眠中被打断,不用等满一分钟。

几个容易误解的点:

  • 界面和命令行没有 IPC。dots goal 插一行、dots approve 改一行, 常驻进程下一轮自己看见。GUI 里的按钮同理。
  • 被 kill 后卡在 running 的目标,下次启动会被 recover_stale_runs() 放回 ready; checkpoint 还在,是接着跑,不是重跑。
  • agent 往被监听目录写的东西会被自己的文件源当成新事件。后端会把本轮新增文件预插成 status='self' 挡掉,否则它会对着自己的产出无限套娃。

全流程流水线(需求→原型→开发→测试→修复)

一条需求进来,分阶段跑完,每个阶段只干自己那段,产物落盘给下一段读:

需求分析(pm) → 原型设计(designer) → 开发(dev) → 测试(qa) → 修复(fixer) → 归档(pm)
dots sdlc new "把订单导出成 CSV,只要已支付的" --jira OPS-42
dots sdlc ls
dots sdlc show <id>
dots serve                 # 后台每轮推进一步

目录长这样(相对 workspace/):

projects/<slug>/
├── pipeline.json          状态机:阶段、轮次、目标 id、历史。人可以改
├── PRD/requirements.md    需求:背景 / 用户故事 / 验收标准 / 非目标 / 待确认问题
├── PRD/questions.md       澄清问题清单,每题带 2-4 个选项
├── design/prototype.md    原型说明:页面 / 交互 / 状态
├── design/prototype.html  能点的静态原型
├── dev/spec.md            技术方案 + 任务拆分
├── dev/tasks/T01-*.md     一个任务一个文件 = 一次做完并自测的最小单元
├── dev/src/               代码
├── test/report.md         测试报告,最后一个非空行必须是 VERDICT: PASS 或 FAIL
├── fix/fix-log.md         缺陷 / 根因 / 改动 / 回归
└── archive/summary.md     功能点 / 怎么跑 / 已知限制,给以后排查

推进靠产物,不靠模型说自己做完了:

  • 每阶段有必须落盘的文件和必须包含的小节。缺了就不推进,重派一次; 两次还缺就停下并记 audit —— 悄悄往前推比卡住更糟。
  • VERDICT: FAIL 会进修复阶段,修完再测,max_fix_rounds 轮还不收敛就停。
  • 目标完成时 evidence 里的路径和 Jira/MR 单号会留在 pipeline.json 里, 下一个阶段不用猜上一段干了什么。
  • 阶段目标由 worker 自动派发,进程重启、断点续跑都不会把流水线卡在半路。 实在卡住了:dots sdlc advance <id> 人工跳过,会留痕。

缺陷轨迹走同一条流水线,只是从修复开始:

dots sdlc new --track bugfix "导出接口 500" --jira OPS-77
dots bugs fix <id1> <id2>     # 多条一起修,先按根因归类

本体库

三层,各管各的:

物理层   公司库里的表 / 集合 / 字段。只读。
   ↓ dots ontology sync
语义层   ontology/ontology.json:实体、字段、关系、枚举、术语。人可以手改。
   ↓ dots ontology apply
派生层   generated/:数据字典、ER 图、DDL、Python 模型、TS 类型
dots ontology init              # 建一份空的
dots ontology sync              # 采所有数据源并合并
dots ontology sync crm          # 只采一个
dots ontology show              # 实体列表
dots ontology show orders       # 某个实体的完整定义
dots ontology edit              # 用 $EDITOR 手改,存盘后自动校验 + 派生
dots ontology apply             # 手改 JSON 之后重新生成
dots ontology status            # 派生层是否落后

JSON 的形状(节选):

{
  "version": 1,
  "entities": [
    {
      "id": "orders",
      "label": "订单",
      "status": "confirmed",
      "curated": true,
      "source": { "datasource": "crm", "schema": "public", "table": "orders" },
      "primary_key": ["id"],
      "fields": [
        { "name": "status", "label": "状态", "semantic": "enum",
          "enum": ["paid", "unpaid"], "nullable": false }
      ],
      "relations": [
        { "field": "customer_id", "target": "customer", "kind": "many_to_one" }
      ]
    }
  ],
  "enums": [{ "id": "order_status", "values": [{ "value": "paid", "label": "已支付" }] }],
  "glossary": [{ "term": "GMV", "definition": "成交总额" }]
}

手改规则(有意不对称):

  • curated: true 的实体/字段,下一次 sync 不会覆盖你的标注、枚举、关系; 库里新增的列只报冲突,不静默加进来。
  • 没改过的实体:字段跟着库走,新字段自动补。
  • 库里消失的表只标 missing,不删 —— 删了人工标注就没了。

改完之后全流程一起变:

  • generated/ 下的数据字典、schema.sql、models.py、types.ts、er.mmd 全部重写。
  • 每条流水线的每份 md 里,「数据模型(本体库自动生成)」那一节整段重写。
  • 系统提示里的本体摘要跟着变;阶段目标里也带着它,所以 next 阶段拿到的字段名是新的。
  • dots ontology status 会告诉你派生层是不是忘了 apply;手改过派生文件也会被点出来。

MCP:飞书 / Jira / Sigma / GitLab

dots mcp add jira       # 写一段现成配置进 dot.toml
dots mcp add feishu
dots mcp add gitlab
dots mcp add sigma
dots mcp list           # 看状态、缺哪个环境变量

dots mcp add 只会写变量名,凭据要 export:

export JIRA_URL=https://your-team.atlassian.net
export JIRA_USERNAME=you@example.com
export JIRA_API_TOKEN=...

工具名统一带前缀(jira__create_issue、gitlab__create_merge_request), 所以审批规则可以按系统写通配:

[approval.rules]
"jira__*" = "ask"
"feishu__send_*" = "ask"
"gitlab__create_*" = "deny"
  • 没装适配器:pip install 'dots-agent[mcp]'。没装也不影响别的功能,tick 照跑。
  • 一个 server 连不上不影响其它 server,也不影响这一轮 tick。
  • 连一次很贵(要起 npx / uvx 子进程),同一进程内会缓存。

微信群 BUG 监控

两种采集方式,消息最终都落到同一个 workspace/wechat/inbox.jsonl:

方式一(推荐,直接用本机微信):用 pywechat 里的 pyweixin 做 UI 自动化 —— 扫未读会话 → 打开对应群拉最新消息 → 写进 spool。

[sources.wechat]
enabled = true
backend = "pyweixin"
# pywechat 仓库里的源码目录
library_path = "C:/Users/you/Documents/project/pywechat/src"
# 用哪个解释器跑采集。留空 = 当前进程内 import;填了就起子进程
python_exe = "C:/Users/you/anaconda3/python.exe"
collect_interval = 300     # 每 5 分钟扫一次
max_pull = 20              # 每个群一次最多拉 20 条
groups = ["项目A-线上问题"]  # 按微信备注名精确匹配;空 = 全部会话
dots wechat check      # 微信在跑吗、登录了吗、UI 树可见吗
dots wechat collect    # 立刻采一次(--chat 群名 只采一个)
dots wechat status     # 看 backend / spool / 上次采集时间

要点:

  • dot 和 pyweixin 的依赖可以不在同一个 Python 环境。dots 要 langchain, pyweixin 要 pywinauto/pyautogui;python_exe 填能跑 pyweixin 的那个解释器, 采集就走子进程,崩了也不会带倒常驻 agent。
  • 依赖:pip install 'dots-agent[wechat]'(或按 pywechat 仓库的 scripts/requirements.txt 装全),微信 4.x + Windows 10/11。
  • 微信的 UI 树必须可见(开启 Windows 无障碍/讲述人),否则自动化取不到控件。
  • collect_interval 是独立于 tick 的:UI 自动化会动窗口,不要每轮都扫。
  • 不用 pyweixin 就 backend = "spool",消息由桥(Wechaty / wechatferry / 企业微信机器人 / 人工导出)写进同一个文件,下游完全一样。

spool 的格式(一行一条 JSON,msg_id 有就去重、没有就按内容算):

{"group": "项目A-线上问题", "sender": "张三", "text": "订单导出报 500", "msg_id": "abc"}

桥不方便写文件时,用内置本机 webhook(只听 127.0.0.1):

export DOT_WECHAT_TOKEN=change-me
dots wechat hook --port 8790

curl -X POST http://127.0.0.1:8790/wechat \
  -H "Content-Type: application/json" -H "X-Dots-Token: change-me" \
  -d '{"group":"项目A-线上问题","sender":"张三","text":"导出报 500"}'

一条群消息进来之后:

  1. 关键词判定:报错 / 500 / 异常 / traceback / 崩溃 …… 闲聊不进台账。
  2. 指纹去重:异常类型 + 顶部文件名、错误码、或归一化后的正文骨架。 同一条错换个措辞、换个行号还是同一个指纹 —— 群里十个人报不会开十个目标。
  3. 进台账:bugs 表记次数、首末时间、样本;dots bugs 看全部。
  4. 派活:新 BUG 自动起一条 bugfix 流水线(修 → 测 → 归档); 把 [sdlc] auto_from_bug 关掉就退化成普通目标。
  5. 回归:已经修复/关闭的又出现,状态回 open 并重新开流水线,不会安静地留在已修复里。
dots wechat ingest "导出报 500" --group 项目A-线上问题 --sender 张三   # 联调用
dots bugs
dots bugs show <id>
dots bugs fix <id1> <id2>
dots bugs close <id>

数据放在哪

打包版的数据跟着配置文件走。默认全局配置下:

~/.dots/
├── dot.toml          配置(密钥只写环境变量名)
├── dot.db            目标、事件、审批、缺陷台账、审计、对话 checkpoint
├── dot.db-wal        正常运行时存在
├── dot.db-shm        正常运行时存在
└── workspace/        它的工作区 = 沙箱
    ├── inbox/        往里扔文件,它下一轮自己发现
    ├── skills/       它攒的技能,每份一个目录 + SKILL.md
    ├── ontology/     本体库:ontology.json + history/ 快照
    ├── generated/    本体库派生的文档和代码(整体可重建,别手改)
    ├── projects/     流水线,一条一个子目录(PRD/design/dev/test/fix/archive)
    └── wechat/       群消息 spool(inbox.jsonl)

在仓库里开发时,如果用的是仓库根的 dot.toml,数据就在仓库根下。

想换位置:改 dot.toml 里的 workspace 和 db(相对路径相对配置文件目录)。

不要删除正在使用的 dot.db:后端、checkpointer、每个请求各开自己的 SQLite 连接, Windows 上连接没关时文件删不掉(WinError 32)。先关应用再删。

常见用法

让文件触发它

往 workspace/inbox/ 扔个文件,下一轮 tick 它自己就会发现并处理。

printf '把这三件事排个优先级\n- 修打印机\n- 回邮件\n- 整理数据\n' > workspace/inbox/todo.txt
dots tick
dots ls

用邮件审批

配好 [smtp] 和 [sources.imap] 后,它想执行 ask 的动作会给你发一封邮件, 主题里带一个编号:

[dot#a7f3] 发邮件给 alice: 周会改到周四

回复这封邮件,第一行写 y / 同意 或 n / 拒绝 即可。

没配邮件也能用 CLI。dots ls 会把等审批的目标和编号直接列出来:

dots ls
# ID      STATUS       TOKEN  TOKENS  UPDATED  TEXT
# 43e86d  interrupted  a7f3   29,047  12s      给 alice 发一封邮件...
#
# 1 个在等你。批准:dots approve <编号>   拒绝:dots reject <编号>

dots log --goal 43e86d         # 先看它到底想干什么
dots approve a7f3

桌面版则在待批横幅里点「批准」/「拒绝」,和邮件回复走的是同一条路径。

攒技能

它干活的时候会自己把可复用的流程记下来。你也可以喂材料:

dots learn "workspace/weekly-template.md 里的周报模板,以后按这个格式写周报"
dots tick
dots skills

技能存在 workspace/skills/<名>/SKILL.md,是普通 markdown 文件,可以手改。 桌面版在技能面板里点「学习」「技能库」「看」「删」「整理技能」。

交接给别的 bot

dots goal --bot ops "把报告发给 alice"

跑起来之后它也能自己换人,你在 dots log 里会看到 handoff 那一条。

看活动视图

dots serve --web --web-port 8765

三张表:待批准、目标(带结论和证据)、最近的流水。10 秒自刷新。 只听本机,没有鉴权,别绑到 0.0.0.0。

常驻跑

dots serve

Ctrl-C 停。没跑完的目标留在库里,下次启动接着跑。

安全边界

  • 界面窗口只加载本地文件,CSP 禁止任何远程脚本/样式/字体。
  • 渲染进程 sandbox: true、nodeIntegration: false、contextIsolation: true; preload 只暴露一个白名单 API,不把 ipcRenderer 交出去。
  • 活动视图(dots serve --web)只听 127.0.0.1,没有鉴权,不要改成对外地址。
  • run_shell 是 shell=True + 靠 cwd 兜着,不是沙箱,默认规则是 deny。 要用它必须显式在 [approval.rules] 里放宽,并接受风险。
  • 所有模型/邮件/工具输出在活动视图里都会被转义渲染;桌面界面一律用 textContent 写入,不拼 innerHTML。
  • dot.toml、dot.db、workspace/ 都在 .gitignore 里,不要提交。

常见问题

双击后一直显示「正在启动后端…」

正常要 10 秒左右(导入 langchain 一整串依赖)。超过 30 秒还没变,看是否:

  • 安装目录被杀毒软件拦了;
  • %APPDATA%\dots-desktop\ 不可写;
  • 输出面板里有 Python 栈。顶栏变成「后端已停」时会自动弹出原因。

顶栏显示「值守中」,但状态是「循环已停」,活动里写着「循环自己崩了」

后端活着,只是 tick 循环崩了。最常见的是从开始菜单启动时进程环境里没有模型 key, 活动面板会写出具体原因,例如:

fatal tick: SystemExit: [model] api_key_env = 'DEEPSEEK_API_KEY' 但那个环境变量是空的
loop 循环自己崩了

把 key 设进系统环境变量(不是某个终端的临时 export),重启应用,再点「开始值守」。

顶栏「后端已停」,按钮全灰

说明 Python 子进程退出了。最常见的原因是找不到配置:

dots init --global

其它原因看输出面板的 stderr 尾部:依赖缺失、TOML 语法错误、模型 key 不存在等。

提示找不到 API key

密钥必须放在系统环境变量里。从开始菜单启动时,进程继承的是系统环境, 不是你在某个终端里临时 export 的。设置完要重启应用(必要时重启资源管理器/注销)。

点「停止」之后按钮没马上变

循环可能正在跑一个目标。等这一轮结束,后端会推 loop_stopped。 停止期间按钮保持「停止」是刻意的,避免你误以为已经停了。

「跑一轮」是灰的

后台循环正在跑。两个 tick 会抢同一个数据库,所以界面禁用、后端也会拒绝。 先「停止」,再手动跑一轮。

审批挂着不动

  • 看横幅里的编号,确认你批的是对的;
  • 超过 timeout_hours 会自动按拒绝处理;
  • 如果刚点完,决定要等下一轮 tick 才会续跑目标,不是立即生效。

聊天里点「批准」提示审批已过期

聊天审批只等 10 分钟。超时后 agent 已按拒绝处理,界面不会假装成功。 重新让它做一次即可。

命令一直转圈 / 显示失败但后端还在跑

界面给命令 180 秒超时。selftest 约 30 秒,正常不会超;如果前面排着长命令, 等待时间会累加。超时只是界面不再等,后端那条命令可能仍在跑完。

装完启动报「安装包里没找到自带运行时」

resources/runtime/python/python.exe 缺失,说明打包时 extraResources 没带上 desktop/runtime/。重新执行 python make-runtime.py(或 bash make-runtime.sh) 再 npm run dist。

dots ontology sync 报「缺驱动」或连不上

按库装驱动,都只在你真要采那个库时才需要:

pip install 'psycopg[binary]'   # postgres
pip install pymysql             # mysql
pip install pymongo             # mongodb

连接串只从 dsn_env 指的环境变量读。先在同一个终端 export DOT_CRM_DSN=... 再跑, 不要把连接串写进 dot.toml。报「一个实体都没采到」时检查 schema / database 和 include / exclude —— MySQL 的 schema 是库名,不是 public。

改了本体库,但文档/代码没变

dots ontology status 会告诉你派生层落后了没有。改 JSON 后跑 dots ontology apply; 用 dots ontology edit 存盘会自动做这一步(校验不过则不会动派生文件)。 派生文件本身别手改 —— 它整体可重建,手改会在 status 里被标成 hand_edited。

MCP 工具没出现在 agent 手里

按顺序查:

  1. dots mcp list —— 有没有 server、是不是「就绪」、缺哪个环境变量;
  2. pip install 'dots-agent[mcp]' —— 适配器装了没;
  3. [mcp] enabled = true —— dots mcp add 会自动打开,手写配置时容易漏;
  4. command 里的 npx / uvx 在 PATH 里吗(飞书和 GitLab 要 Node,GitLab/Jira 要 uv);
  5. 工具名有前缀(jira__create_issue),审批规则别按裸名写。

微信群消息没反应

先看是哪条路:

  1. dots wechat status —— 源开没开、backend 是什么、spool 在哪、读到的偏移是多少;
  2. backend = "pyweixin" 时先跑 dots wechat check:微信没登录 / UI 树不可见 / library_path 指错 / python_exe 里没装 pywinauto,都会在这一步说清楚;
  3. 消息是不是进了 groups 白名单,文本是不是命中了报错关键词;
  4. 同一句话报第二遍不会开新目标(这是故意的):dots bugs 里看计数;
  5. 想联调不接微信:dots wechat ingest "导出报 500" --group 项目A 然后 dots tick。

流水线卡在某一阶段

dots sdlc show <id> 看「缺什么」那列:产物文件没落盘或少了必须的小节,阶段就不会推进。 让 agent 再跑一次(dots tick),或者人工补文件;确实已经在别处做完了, 用 dots sdlc advance <id> 跳过并留痕。两次都没落盘的话流水线会被标成 blocked, 不会继续烧 token。

想彻底重来

  1. 关闭应用;
  2. 备份或删除 ~/.dots/(会丢目标、审批、审计、对话历史、技能和工作区文件);
  3. 重新 dots init --global。

一页速查

启动应用          → 等 10 秒 → 顶栏「值守中」
派活              → 目标面板「新建目标」→ 写一句话
看它干了什么      → 活动面板 / 目标行「日志」
它要发邮件        → 待批横幅点「批准」或「拒绝」
跟它说话          → 底部输入框,回车发送
让它学一套流程    → 技能面板「学习」→ 等下一轮
开一条流水线      → dots sdlc new "需求一句话"
看流水线走到哪    → dots sdlc ls → dots sdlc show <id>
采公司库元数据    → 配 [ontology.datasources.*] → dots ontology sync
手改本体          → dots ontology edit → 存盘自动派生
群里的 BUG        → dots wechat check → dots bugs → dots bugs fix <id>
接外部系统        → dots mcp add jira|feishu|gitlab|sigma
换模型            → 改 ~/.dots/dot.toml 的 [model] → 重启应用
出问题            → 顶栏「体检」→ 看输出面板 → 活动面板

一个提醒

每次运行都会重新过一遍系统提示和工具描述,固定开销不小 —— 往 inbox/ 扔一个文件大约几万 token 起。先让 daily_token_budget = 0 跑一天, 用 dots cost(或桌面版活动面板的「用量」)看真实数字,再决定填多少。

许可

MIT

Dots Agent alternatives

View more →

Similar ai agents in Coding Agents, ranked by GitHub stars. Compare licence, recent activity and scan status before you choose.

NameStarsLicenceLast updatedScan
Dots Agent (this page)
duyongan
158MITOct 20, 2026Scanned, no flagged issues
AutoGPT
Significant-Gravitas
188kNone foundNov 1, 2026Not scanned yet
Langchain
langchain-ai
149kMITNov 1, 2026Scanned, no flagged issues
Gemini CLI
google-gemini
109kApache-2.0Nov 1, 2026Scanned, no flagged issues
MetaGPT
FoundationAgents
71kMITJan 21, 2026Scanned, no flagged issues
Oh My Openagent
code-yeongyu
71kNone foundNov 1, 2026Not scanned yet