一个运行在 Windows 桌面的编程引路智能体——**里交任务,它自己读代码、改文件、跑命令,直到把事情做完;像学长带学弟一样,动手前讲思路,关键处给理由。附赠同核引擎的终端版。
Overview
一个运行在 Windows 桌面的编程引路智能体——**里交任务,它自己读代码、改文件、跑命令,直到把事情做完;像学长带学弟一样,动手前讲思路,关键处给理由。附赠同核引擎的终端版。 - :玻璃拟态风(,切主题即换景;侧栏/顶栏/气泡/工具卡都是磨砂玻璃层),深色/浅色一键切换;会话列表、Markdown 流式对话;(最终回复开始时自动收起,点标题行展开回看);,消息右键有原生菜单(撤销/剪切/复制/粘贴/全选),Ctrl+C/V/X/A 正常可用 - :用户说"还是慢",先量再改 —— 同一件 135 MB 的更新包,这台机器单连接 api.github.com 、browser_download_url ,而**(GitHub 的限速是按连接算的)。于是两件事一起改:(以前是"失败才退下一条",而**,永远退不过去),以及**(四段并行写进同一个 .part,下完整件算一次 sha256 才改名交付)。三条边界:分段那份中间可能有洞,所以顺序那条路看见 mode=parallel 就删掉重来,绝不拼接;摘要最后整件读一遍,不边下边喂;服务器不认 Range 就自动退回单连接 —— 并发是优化,不是新前提。取消后续传是**。 - :上一版有用户反馈"改一行为什么要下 878 MB"。 —— 逐条分桶量出来:那 878 MB 里 (它们跨版本基本不变),而学长自己写的代码在包里只有 。现在发布时多产两件:一份**(实测 135 MiB)和一份**对得上就跳过那 84.6%,只下 135 MiB**退回整包并把原因说出来**老版本升上来的第一次也不用重下整包**自己核对一次内核**就地更新这条路修到能用,外加两样新的(v0.9.177)**上一炉那个"下载点了没反应"修了**查版本那几条有证书兜底、而下安装包那一条没有**下载优先走资产的 API 地址**下一半不用重来**「我的数据」里终于看得见 updates/ 这一格**版本号那串字可以直接点了 = 看历史更新内容**终端里也能插话了**可交互产物**就地显示而不是当代码执行**碰不到宿主、也出不了网**有更新会自己来说,下载就地装好(v0.9.176)**自己弹一张「发现新版本」的卡**核对 sha256 才让装**要点两次**不防 GitHub 账号本身被接管**冷启动那 1.
README
引路学长
一个运行在 Windows 桌面的编程引路智能体——图形界面里交任务,它自己读代码、改文件、跑命令,直到把事情做完;像学长带学弟一样,动手前讲思路,关键处给理由。附赠同核引擎的终端版。
功能
-
桌面 GUI:玻璃拟态风(浅色=校园日景航拍、深色=同一校园的暮色航拍,切主题即换景;侧栏/顶栏/气泡/工具卡都是磨砂玻璃层),深色/浅色一键切换;会话列表、Markdown 流式对话;思考与工具调用收成一条可折叠的「工作过程」(最终回复开始时自动收起,点标题行展开回看);划词即弹「复制选区」,消息右键有原生菜单(撤销/剪切/复制/粘贴/全选),Ctrl+C/V/X/A 正常可用
-
更新提速(v0.9.181):用户说"还是慢",先量再改 —— 同一件 135 MB 的更新包,这台机器单连接
api.github.com0.03 MB/s、browser_download_url0.28 MB/s,而四条连接一起拉 0.85–1.09 MB/s(GitHub 的限速是按连接算的)。于是两件事一起改:下载前两条路线各拉 256 KB 比分快慢、谁快用谁(以前是"失败才退下一条",而慢不是失败,永远退不过去),以及一条连接只负责一段(四段并行写进同一个.part,下完整件算一次 sha256 才改名交付)。三条边界:分段那份中间可能有洞,所以顺序那条路看见mode=parallel就删掉重来,绝不拼接;摘要最后整件读一遍,不边下边喂;服务器不认 Range 就自动退回单连接 —— 并发是优化,不是新前提。取消后续传是四段一起接着下。 -
更新不再等于重下整个产品(v0.9.178):上一版有用户反馈"改一行为什么要下 878 MB"。先量后做 —— 逐条分桶量出来:那 878 MB 里 84.2% 是馆藏库与浏览器内核(它们跨版本基本不变),而学长自己写的代码在包里只有 1.68 MB。现在发布时多产两件:一份**「仅 app」安装包**(实测 135 MiB)和一份带数据身份的发布清单;更新时先比本机那两块数据的凭证(读文件,不重算 1.3 GB 哈希),对得上就跳过那 84.6%,只下 135 MiB。卡上会写清楚这次要下多少、少下了多少;对不上就退回整包并把原因说出来** —— 绝不静默降级。老版本升上来的第一次也不用重下整包(v0.9.180):0.9.178 及更早的包里本来就没带那份内核凭证,现在更新检查会在本机自己核对一次内核再决定(实测 697 MB / 603 个文件 1.0 秒,机械盘十秒级,且只在"否则就要下 878 MB"的时候才付这一次),核得上就同样走 135 MiB 那件,并把凭证留在本机。仍然要点两次、仍然 sha256 核对过才让装。
-
就地更新这条路修到能用,外加两样新的(v0.9.177):①上一炉那个"下载点了没反应"修了 —— 根因不是网络不好,而是这条路上查版本那几条有证书兜底、而下安装包那一条没有(同一个坑在自家文档里写过的地方重犯了一次)。现在四条(查最新 / 列历史 / 取校验清单 / 下安装包)真的共用同一份证书底座,并且下载优先走资产的 API 地址,
github.com那条留作兜底 —— 校园网里github.com慢或不通是常态,而api.github.com通。②下一半不用重来:取消或断网都留着那半截(带着身份条子),下次点「下载更新」接着走,进度条从原位往上;界面会说清"这 N MB 是本机原有的"。被取代的旧安装包现在能一键清掉,而**「我的数据」里终于看得见updates/这一格** —— 920 MB 一件的东西以前连影子都没有。③版本号那串字可以直接点了 = 看历史更新内容(旁边那枚 ↻ 按要求撤了;手动查更新仍在命令面板 Ctrl+Shift+P 里)。④终端里也能插话了:学长正在跑的时候直接打字,回车就进这一条会话的信箱,它会在下一步接上(与桌面版同一个入口、同一份留档);管道/重定向里的输入一个字都不动,行编辑与补全也全保留。⑤可交互产物:学长写下的.html/.svg会在对话里显形成一张可点开的卡,就地显示而不是当代码执行 —— 后端先删掉可执行结构(脚本 /on*=事件属性 / 可执行链接,删了几处如实报数),界面再把它装进sandbox空档位并注入一条断外联的 CSP;它碰不到宿主、也出不了网(这两道各拦一半:实测过沙箱拦得住脚本却拦不住一张普通图片外连,所以两道都要在)。 -
有更新会自己来说,下载就地装好(v0.9.176):查到新版本不再只是聊天栏顶部一条会被人忽略的提示 —— 版本号旁多一枚绿色「更新」徽章,并自己弹一张「发现新版本」的卡(版本 + 日期 + 整段更新日志 + 「查看历史更新内容」)。卡上直接「下载更新」:进度条、可取消、下完核对 sha256 才让装(对不上就当场删掉、按钮是灰的),然后「运行安装程序」。要点两次:下载一次、运行一次,没有静默安装;
update_check:false整条通道一起关(连手动都拒)。⚠ 一句实话:校验清单与安装包来自同一个 Release,它防的是下载坏掉/被截断/链接被换,不防 GitHub 账号本身被接管 —— 本项目没有代码签名证书,这条边界写在SECURITY.md「就地更新的信任边界」。 -
冷启动那 1.3 秒,和 MCP 的「提示模板」终于能用上(v0.9.175):①启动/第一个会话不再卡那一下 —— 系统提示词里那句「共 133 万条书目、纸本多少种」原先是让数据库把 1.31 GB 的馆藏库整个扫一遍算出来的,而库里那两个索引本来就在;拆成各走索引之后本机实测约 1.5 秒 → 0.2 秒,报的四个数一个都没变,也没有往你机器上多存一份缓存文件。②MCP 服务器的「提示模板」现在能用了 —— 让它列给你(名字/要填什么参数/它自己的说明),或按名字取回内容;那是那台服务器写的指示,不是学长自己的规矩,所以每次取都问你一句、引用时注明来源。
-
浅色主题下那批「看不见的文字」修好了 + 更新检查有了入口(v0.9.174):①用户图里「快捷键速查中心」在浅色下看不清,根因不是配色不好看,而是那几个 CSS 变量从来没定义过 ——
--text-soft/--kbd-bg/--text-bright/--border-soft/--shadow-lg/--glass-soft/--text/--ok/--warn九个名字全都不存在,而调用点写的回退值是照着深色写的白色系(rgba(255,255,255,.7)、#fff),浅色玻璃底上等于看不见;--glass-soft连回退值都没有,那 6 条background声明直接被丢掉。修法是不动任何调用点,在两个主题块里各补一组「语义别名」(浅色给深墨、深色给白系),一处补齐九处同时生效。②更新检查原先只有一条路:点一下侧栏那个小版本号 —— 而它长得不像按钮。现在抽成具名动作,版本号旁边挂了一枚 ↻(点它或点版本号都行),命令面板(Ctrl+Shift+P)里也有一条「检查更新」;三条路同一个后端。顺手挖出一个真会让人以为"这功能是坏的"的 bug:有些机器上 HTTPS 被加速器/公司代理接管,它把根证书装进 Windows 证书库、不装进 Python 那份 CA 名单 —— 于是「浏览器上得去、python 一问就失败」,而这功能以前会把失败说成「已是最新版本」。现在证书这关会换系统证书库再试一次,拿不到就把实话说出来,不再骗你。启动时那条提示条照旧(只在真有新版本时出现)。另外:按你的要求语音输入整体撤下(模块/桥/输入行 🎤/冻结针/《使用说明》那条/8 支测试全删)。 -
四条真差距一次补齐(v0.9.173,用户点名):①看图
view_image—— 模型以前看不见自己刚画出来的东西(render_chart画的图对不对、generate_image出的图是不是想要的,只能凭代码猜)。现在可以把工作区里的一张图发进会话,下一轮就看得见;只认工作区内的图(敏感目录 / 凭据文件 / 工作区外一律不看),不支持视觉的模型明说「没有把图发出去」并指路ocr_image。②递话session_message—— 正在跑的子代理与别的活会话之间能留一句话(此前只有「子代理 → 主会话」那一条单向)。递过去的句子落进对方下一次请求的系统侧注记,绝不冒充用户说的话;对方跑完 / 关掉就摘盒,递给一个不在了的对象会得到一句实话。③钩子事件面 7 → 9 类 + 失败语义可配 —— 新增post_tool_failure(失败那半边,让外部系统看得见连续失败,而它改不了「这一步算不算失败」)与subagent_start/subagent_stop(一进一出各附一句话);failure_mode与老名字on_error是同一件事,支持在hooks顶层写全局默认,写错的值一律按「拦」。④工具面按需加载tool_loading—— 三层投影:lazy时把校园生活 / 地图 / 馆藏那一族(22 只、约 8,400 token)换成系统提示词里约 500 token 的一行索引,靠常驻的tool_search取回(取回后本会话一直有效),每轮固定开销约省四分之一。默认all(逐字回到今天),理由写在minicode/tool_profile.py开头:这套设计的核心主张(模型会不会主动去要它需要的工具)在本机验证不了,不拿「我觉得会」去换核心循环的行为。 -
MCP 原语补到 prompts(v0.9.172+ 续四):以前只接 tools 与 resources,对端声明 prompts 时那句能力行会如实说"没实现、不会去调"。现在
prompts/list+prompts/get都接了(声明了才拉,失败不致命),能力行自动收窄成"哪几样真没接"。两个原语明确不接、而且是拒绝而不是忽略:sampling(服务端请客户端替它跑模型 —— 等于让外部服务器替你花额度、还把上下文片段送出去)收到就回一条说清的 JSON-RPC error;elicitation(服务端中途要用户确认)按规范回 decline 并记日志 —— 以前这类请求被静默丢弃,对端会一直干等。把 elicitation 的 schema 编成提问卡是下一轮的设计(卡片是选项式的)。 -
扩展中心(底座第六页,v0.9.172+):五类扩展收一屏 —— 技能(按渠道归组)/ 技能渠道 / 侧边栏三方扩展 / MCP / 工具钩子。这一页存在的理由是侧边栏那半:装了没生效的扩展此前只把原因写进开发者控制台(
console.warn),用户看不见;现在「🧩 扩展」页把没装上的逐条带着原因摊开(目录名 + 具体原因)、已装的连同版本一起列,并给一个「打开数据目录」。只读展示 —— 不给不存在的启停语义做开关,信任模型不变(见 SECURITY.md 专节)。 -
扫描版课件也能读了(v0.9.172+):
ocr_image现在也吃.pdf—— 逐页抽内嵌图(扫描版每页就是一张整页图,pypdf直接拿,零新依赖)、逐页识别,输出按「第 N 页」分段,专治扫描/拍照版课件与教材;矢量或带文字层的 PDF 会如实告诉你那几页没有可抽取的图(走pdf技能直接抽文本)。识别结果仍只当待核对草稿(公式/手写本就不可靠),lecture-notes技能的"做不了"降级成最后一句。 -
有新版本会告诉你(v0.9.162+):每次启动向 GitHub 公开仓库(
MOKO-TB/yinlu-xuezhang)的 Release 接口问一句最新版本号 —— 只问,不下载。比当前版本新就在聊天上方出一行提示,右边「看更新内容」开一张更新日志卡(版本 + 日期 + 这一版改了什么,长文可滚),底下「打开发布页」去 Release 页自己下载安装;侧栏那个版本号(v0.9.x)可以点 = 手动再查一次。不外发任何本机数据(只带 IP 与通用 User-Agent),config.json的update_check: false完全不出网(关掉后手动那条也一起拒,见 SECURITY.md「数据流向」)。 -
侧边栏底座(v0.9.159):右列从「任务监控」单页换成 tab 化的开放页面注册表 —— 内置六页(🛰 任务监控 / 🌿 Git / 🖥 终端 / 🤖 子代理 / 📄 文件 / 💬 侧聊)与三方扩展页走同一个
window.MiniCodePages.register(),注册即出 tab,没有特权通道。Git 页:状态/暂存/提交/历史/影子快照一屏(git 只调 CLI、绝不设身份、绝不 push/pull/fetch);终端页:同一本后台账 + 输入行 —— 用户亲手跑命令,沙箱硬闸照拦(REJECT 级不认人),confirm/accept_edits 档每条先问一次;文件页:围栏内的读与写 + Markdown 渲染,保存前对底账(磁盘被别的来源改过就拒,绝不静默覆盖);子代理页:与任务监控同一份账,整列显示;侧聊页(v0.9.160):不打断主任务的小会话 —— 每条线程是一个 origin=sidechat 的后台会话,主任务在跑也照常回话,事件路由保证它绝不漏进主聊天区;线程跨重启活着(留档在,重开即接上),侧栏/托盘不列它。通知直达也认yinlu:panel=side:git这类页 id。入口收敛与双面板(v0.9.162,ZCode 同款):入口栏回到原样(四颗页面入口撤下),顶栏两颗开关 —— 「切换面板」(Ctrl+Alt+B) 开合右侧底座、**「切换终端」(Ctrl+)** 开合**底部终端坞**(占内容区整行、顶边可拖高 200~560、双击回 280,开合与高度都记在本地)。**面板宽度可拖**(v0.9.161:左缘把手,260~560px,双击回 300,记在本地);旧「后台命令」只读弹窗同轮拆除 —— 终端在底座里安了家。三方扩展 = 数据目录extensions//`(manifest.json + page.js),放进去 = 你亲手装的(信任面与装一个软件同级,SECURITY.md 有专节),工作区里 clone 带来的扩展一个字都不读。 -
撞到上下文超限会自己救一次(v0.9.143):以前端点回一句「太长了」,这轮就以一句模型报错收场(命令行那边还是退出码 1),看着像程序坏了 —— 而窗口是量出来的,超了压一压真能过去。现在:认得出是超限、且确实压动了,就就地压缩一次再发这一发请求,只有一次机会(第二次还超限就照实失败,不拿有损压缩换一次次白等);认不出是超限就一个字都不压(参数写错的 400 与超长的 400 是同一个状态码,认错一次的代价是把不该压的对话压掉了);压了会在对话里留一句人话说明,不静默改你的上下文
-
不会配模型?开「智能配置」(v0.9.142,v0.9.158 成真闸):「编辑模型配置」顶上那颗开关。开着的时候,运行时真会用的那份直接回填进表单(窗口/图片输入/推理档位;灰着的输入框是预览,你自己填的那份原样收着,关掉开关逐字回来),并标清楚这个数是这台机器探测出来的还是内置目录里的。语义是整份声明让位而不是逐键 —— 混着读会造出一个没人能解释的模型。目录里没有、也没探测过的模型,备注里给一颗**「探测一次」**:点一下真发一条请求问这个模型(窗口多大、能不能收图),结论当场落进表单并被记住,模型管理里的徽标同刻跟上;探不成会把服务端的原话摆出来 —— 凭空显示一个窗口数,等于把「不会配」换成「配错了还不知道」。默认全关:今天每一份配置都不该被这次升级改掉
-
出站网址策略(v0.9.141):
config.json里net_policy三档 ——off(默认,与今天逐字一样)、ask(模型要访问不在你allow名单里的域时问一次,每步重新问、不给永久免确认,full档也问)、deny(直接拒)。allow/deny写主机名,支持*.school.edu这种后缀,而evil-school.edu.cn命不中*.school.edu(边界处必须有个点);同一条域既 allow 又 deny 时 deny 赢。管的范围说死:web_crawl/page_parse/browser_open这三条模型能自己填网址的路 ——它是策略不是沙箱,bash里的 curl、你配置的模型/MCP/天气/通知端点、页面自己的子请求都不在它范围内;真要「这台机器只能连这几个域」得靠操作系统层(S5c,本项目还没做,欠账登记在 HANDOFF §6 52) -
回答流出来不卡(v0.9.140):以前模型每吐一个字,程序就单独往窗口里搬一次 —— 量出来的结果是 600 个增量要 1715 ms 全花在这趟往返上(同样的内容放进一次调用里循环只要 5.7 ms)。现在流式增量攒成一批送(600 次往返 → 18 次),相邻同类型的还合成一条;两只兜底是这一笔的关键:一只 80 毫秒的定时器保证"模型说半句停三秒"时那半句照样上屏(不然省下的往返会变成新的卡顿),而任何非增量事件先冲缓冲再送(工具卡、确认框永远不插在正文中间)。停止与关窗也各有一次 flush,最后那半句不会留在缓冲区里
-
模型在想什么,看得见也收得起来(v0.9.138):外层「工作过程」折叠的是整条过程,里层「💭 思考」自己也能点开/收起 —— 思考中默认摊开,旁边一行实时写着「思考中 N 秒 · 约 X token/秒」。那个「约」是认真的:token 数要等服务端回报才准,在那之前只能按字数估,所以答完之后下方那行 ⚡ 才是实测值,两行不是一回事,不拿估算冒充实测
-
后台任务:新建任务 / 切换会话都不会打断正在跑的任务——每个会话有自己的运行器(独立 Agent 与会话上下文),旧任务转后台继续跑完;侧栏对应会话显示转圈与「运行中」,点它即可切回去看实时进度(模型、MCP 连接、沙箱策略在会话间共享,多开一个会话不会重复起进程)
-
内置校园模型,开箱即用:固定使用广州应用科技学院内网模型服务(
deepseek-v4-flash),不需要填 API Key,界面也不提供模型切换入口(顶栏模型标识只展示;内网地址与 Key 都不下发前端)。模型的上下文窗口与「是否支持视觉」由程序启动时自动向服务探测(结论缓存一周),任务面板标签与压缩触发阈值据此自动对齐 —— 学校换模型/换网关不必改代码 -
工作区(自己选文件夹):顶栏「📁 工作区」胶囊点开就能挑一个文件夹当 Agent 的工作台——读写围栏、附件
uploads/、计划plans/、长期记忆memory/、超长工具输出的转存tool-outputs/(v0.9.126:某一步输出超过max_output_chars时,头部照旧、尾巴落在这里,回话点名路径,模型要接着看就read_file,不必重跑那一步;对外/网页版关掉它,因为工作区目录是访客共用的)全部落在那个文件夹里;弹窗列出当前/默认与最近用过的 8 个(可一键移出列表,只动记录不删文件夹),「选择文件夹…」走系统原生对话框。CLI 用/workspace或启动参数--workspace拿到同一份记忆(详见「工作区」一节) -
跑着的时候能补一句(v0.9.127,v0.9.138 改成可反悔的草稿):这一轮正在转时按 Enter 不是"发第二条任务",那句话先落在输入框上方一条
↳ …草稿上,旁边三颗:「↵ 插话」才真的并进这一轮、「✎」拿回输入框改、「🗑」丢掉。以前是按下去立刻塞进正在跑的那一轮 —— 打错一个字也没有反悔的余地,而它已经按那句去取下一步了。句子进了信箱之后仍是在下一个安全边界(某一步跑完、下一次请求发出之前)并入,模型读到的是「它答到哪儿 → 你补的那句 → 接着答」。不停下来打断正在跑的那一步:tool_call与结果必须成对,从中间插一条用户消息就会留下悬空对儿(那表现是从这一轮起每次请求都 400)。按停止不会吃掉你打出去的字:没读完的话留在信箱,下一问开头读到;换会话则不留残草稿。带附件那句当场拒(图要先拼进消息体,那一步只在开新回合时做),排到顶也当场说并原样退回输入框。命令行没做:它正卡在input()上等一句完整的话,没有后台读线程 —— 这条差别是形态的限制,不是漏实现,所以别拿"CLI 也能插话"去写交付说明。 -
同一条消息里的多只工具会一起跑(v0.9.126,补齐竞品那一格):模型一次要三个 grep/读文件,不再一个等一个。只有名单内、只读、没配钩子、且门不会为它开口的那几步才进线程池(资格表与逐条理由在
minicode/tools/concurrency.py);确认框、留档顺序、失败连击这些一律留在主线程按模型给的顺序走。ask_user与浏览器那几只刻意不在名单里——前者弹框发生在 handler 里(从工作线程弹框是不报错的坏法),后者共用一条 CDP 会话。 -
数学公式排得出真式子(v0.9.138):回答里的
$…$、$$…$$、\\(…\\)、\\[…\\]由内置 KaTeX(离线,不联网)排版。两处刻意不当公式:代码块与行内代码里的$(那是用户要照抄的原文)、以及「报名费 $5 和材料费 $10」这种价格(判据与 remark-math 同一条:内容首尾不许空白、闭合$后不许紧跟数字)。公式在交给 markdown 之前先抱出来 —— 否则$s_1$ 与 $s_2$中间那对下划线会被 markdown 当成斜体吃掉,再抱就拼不回来了。某条式子解不开时屏上留的是它的原文,不是一片空白,也不是一句报错。 -
侧栏的任务能改名、能归档(v0.9.138):悬停在某条历史上出现「⋯」(或直接右键那一行)→ 打开 / 重命名 / 归档 / 取消归档 / 复制会话 ID / 删除。重命名是就地编辑而不是弹
window.prompt(内嵌 WebView 里那种对话框可能压根不出现,用户看到的就是"点了没反应");写回的是留档开头那行session_start的title,与 CLI 的/rename同一只手,所以两边不会一个能改一个不能改。归档的口径没变:沉底 + 打标,不删不隐藏(侧栏、/resume、分支审查共用一份序号,一隐藏就把别人的坐标弄破)。 -
分享图能直接粘(v0.9.138):🖼 排完卡片之后,旁边那颗 📋 把刚生成的那一张复制进 Windows 剪贴板(CF_DIB),到微信/文档里直接 Ctrl+V,不用再翻工作区
images/。门面那颗零参数 —— 路径由桥自己记着,界面传不进路径,也就传不进..\指向的任意文件;剪贴板被别的程序占着时它照实说一句,不假装复制成功。 -
预估费用按各家官方页算(v0.9.138):
global:deepseek-v4.1-flash这类带命名空间/展示前缀的名字现在认得出来了(从前明明有价却报「未知」—— 有价说成没价与没价说成 $0 是同一类坏法的两半);但不并档,qwen3.8-flash-pro不许落进 flash 那一行(并档就是贵的那档按便宜的价报,而报出来还是个看着很精确的数)。人民币报价的按¥列、美元报价的按$列,合计也分币种各列一个数 —— 折成一个数要引入一个凭空编的汇率。单价悬停那句写着来源与核对日期,官方有峰谷两档时写明取的是哪一档。价目缺行的模型照实进脚注「未标价(没算进总数,不是 $0)」;要补价:pricing-override.json。 -
沙箱边界:工作区内的路径直接放行、工作区外逐次确认、
~/.yinluxs~/.ssh等敏感目录永远拒之门外;还能禁网命令、加自定义禁配规则、卡命令超时;GUI 顶栏一键开关(详见「沙箱」一节) -
附件上传:聊天框 📎 选文件/图片,自动复制进工作区
uploads/并把路径注入消息;图片按长边 1536 / 1MB 自动压缩,vision: true时以 base64 直接发给视觉模型 -
本地知识库检索:
kb/目录放 JSON 资料库(校园通知、经验库等,自带 credibility 可信度分级与来源网址),search_knowledge工具按 中文 2-gram 打分检索(标题×3+标签×2+正文×1),回答引用时输出来源网址供用户核实,非 A 级数据强制标注"未经核实";未命中时工具回话自带下一步(v0.9.92:用 web_search 联网查证并附来源、查到有长期价值的内容征得同意后 kb_suggest 入库、纯常识不必联网)—— "未命中就联网"从技能里的自觉变成工具回话里每次都在的路径 -
图书馆馆藏查询(离线全库):
library_search直接查本地 SQLite 馆藏库(133 万条 OPAC 书目,毫秒级),返回书名/作者/出版社/索书号/中图法/馆藏册数与馆藏地,并自动把中图法大类映射成楼层。查询会自动逐级放宽:《C程序设计》、C语言程序设计(第5版)、高等数学(上)、三体:地球往事这类带书名号/版次标注/副标题的问法都能命中(以前会漏检并误报"没有这一本书"),且一次检索最多只走一次全表 LIKE,不会因多试几级而变慢 -
SKILL.md 技能系统:
skills/目录放技能(带 name/description 的 SKILL.md),自动注入系统提示词,模型用use_skill工具按需读取全文;内置 git-commit / python-testing / code-review 三个示例 -
权限确认:写文件(带预览)、编辑(带 diff)、执行命令先弹窗确认,可选"本轮总是允许"或切"自动放行"
-
安全兜底:
rm -rf /、format c:、fork 炸弹等灾难性命令硬拒绝;文件工具拒绝越出工作区;仓库的.git里(钩子会被每次提交自动执行)任何档位都要点头 —— 白名单与「本轮总是允许」都批不进去 -
没读过的文件先问一句(v0.9.133):要改的是一份既有文件而这个会话还没读过它 → 确认框多一句「学长手上没有它现在的内容,要替换的那段是按印象写的概率不低」(点「允许」照改,点「拒绝」就先
read_file)。这不是安全门,是正确性门:模型没读过就改,edit_file的逐字匹配要么白烧一轮、要么把错的永久写进你的文件(Claude Code 把这当防幻觉第一道)。四条例子内定好了:自己刚写出去的文件不算没读过(那份内容就是它写的)、新建文件不出声(没有可先读的东西)、读失败不算读过(二进制/编码/越界那几种,判据用的是"内容真进过它的手"而不是"调过一次工具");这本账跟着每个 agent 自己走——子代理各自一份,侦察那一档读过的不替写代码的那档以为它也读过(它拿到的是摘要)。只在还会问人的两个档位生效:变更前确认给本来就有的那张框补一句原因,自动编辑把「工作区内写文件自动放行」改成「没读过的先问一句」;自动放行与完全访问不动 —— 那两档对用户的承诺就是不再问,拿一枚启发式去拆承诺是另一种坏法。不想要了:config.json里read_before_edit: false,行为逐字回到以前 -
/undo回滚(CLI):写前快照;/undo先列这一轮改过的每一处(编号/改还是新建/退下去是恢复还是删除/有没有被别的工具二次动过),/undo diff看「改之前 vs 磁盘上现在」,真要退是/undo·/undo last·/undo all三种,都会先摆出这一处再问 y/n —— 没答就算拒绝,磁盘一个字不动 -
上下文自动压缩:token 估算接近窗口上限时,把早期对话折叠成摘要(按完整轮切分);任务栏「上下文」那一屏把占用与压缩放在一起 —— 「已用 / 窗口」两个绝对数、四栏明细(系统提示词 / 工具定义 / Skill / 对话消息)、一行写清这把尺子是服务端实测顶上来的还是本地估的;🗜 压缩按下去当场回报「占用约 A → B」或「没压掉东西:早期对话还不够多」,数字一变这句就撤。工具定义那一栏跟着 MCP 的增删实时走,不用重启。终端版读同一份数据:
/history报那四栏与来源,/compact回报到底压了没有。 另有一档 microcompact(v0.9.120):整段压缩之前,较早的只读工具结果(搜文件/读文件那一类;失败的那一步与写过的文件永不碰)在每一步请求里换成一句占位,不再整屏重发 —— 一次grep回 3000 字,过去是后面每一步都重发这 3000 字。它只在发出去的那一份副本上做手脚,session.messages与磁盘留档仍是全文(导出/审计/重启恢复看到的都是原文);省下的量不够一个下限就整批一个字都不动(省几百字却打断一次 KV Cache 前缀是亏本买卖),而且要么不动、要动就一次扫到底,之后每一步算出的是同一批,前缀照旧稳定命中。屏幕上每回合最多一句「省略了 N 条(约 X 字)」 -
会话持久化:每轮写入
sessions/*.jsonl;GUI 侧栏一键恢复,CLI/resume -
桌面提醒(v0.9.25):主动推送(今日简报、课前 20 分钟、今天第一节课、临期/逾期待办、校历倒计时、官网新通知、新版本)除了聊天栏顶部那条提示栏,同时弹一条 Windows 桌面通知——窗口最小化在托盘里也能收到,不会再出现"人不在窗口前 = 提醒没发生"。正文只复用聊天里已有的那行文字,缺字段就整条不发,绝不为了"通知看着饱满"编课名或时间;托盘菜单里有「桌面提醒」总开关(打勾状态实时)和「测试一条桌面通知」;对话里也能说「提醒直接弹桌面」「别弹通知」「看不到通知」,走
desktop_notify工具(status / on / off / test,可只动一类)。两条默认克制:窗口正在前景有焦点时不重复弹(那行字本来就读得到)、同一条内容 ~90 秒内只响一次;拿不准是否在前景时按"不在前景"处理(宁可多弹,不能把"快上课了"悄悄吃掉)。偏好落notify-pref.json(坏文件回落默认全开,只读目录写不进去会如实回话)。通道是 Windows 自己的 toast(借系统自带的 PowerShell 5.1 走 WinRT,零新依赖;正文只经环境变量交付、不进命令行),第一次弹之前会自动在当前用户下登记应用身份,通知里就有中文名「引路学长」和图标(显示名要写在那坨注册表键的默认值上、图标路径必须是file:///形式,裸路径会被静默丢掉;而 Windows 第一次见到某个身份就把名字和图标缓存下来,之后再改注册表刷不回来——所以登记一定发生在第一条通知之前,身份串也为此换过一次);旧的托盘气球只作回落,且永远标着「未验证」—— Windows 11 根本不显示气球,两条通道都不通时直说「都没发出去」并指向tray.log,绝不假装已弹。点通知直达(v0.9.72):toast 带协议激活属性 —— 点那条 Windows 通知,窗口弹回前台,课前/简报/待办/校历类提醒直接落到课表面板、心情周报落到心情面板(没有对应面板的类别只弹回窗口);实现是yinlu:协议注册(HKCU 指向 GUI exe,写完读回核对,安装版便携版一致)+ 激活监听(127.0.0.1,端口落activate-port.json)做单实例交接 ——--activate的第二进程先 POST 交接、送达即退绝不双开,没人在跑才自己启动并首屏落面板;协议没注册成功就不给激活属性,不发点了没反应的空激活 -
开机自启 + 补发错过的提醒(v0.9.26):托盘右键菜单多了「开机自动启动」打勾项,对话里直接说「开机自动启动学长」「别开机就启动」也行(
desktop_notify的startup_on/startup_off)。实现是在当前用户的「启动」文件夹里放一个快捷方式——不写注册表 Run 键、不要管理员权限,你自己看得见、也删得掉;建完会读回快捷方式指向核对,指向不是本应用就不说「已开启」,关的时候更绝不动别人的文件(同名快捷方式指向别处只报告、不删除)。自启带的参数是--background:启动后直接收进托盘;而托盘图标万一没建成,照旧把窗口显示出来——宁可多一个窗口,不能留一个"进程在跑但界面永远叫不出来"的隐形进程。补发解决的是同一件事的两头:课前提醒"今天弹过哪几条"原来只记在内存里,一重启就清空,于是错过的那条永远不补、弹过的那条又会再弹一次;现在落成pushed-today.json(按天滚动、最多 200 条),启动后第一轮补两样——① 今天从没推过今日简报就补一条(早上没开机,下午打开也看得到今天几节课、要不要带伞);② 有节课已经开课、且还在 60 分钟内且没提醒过,补一条「错过的提醒:高等数学 08:00 已开课(现在 08:52,过了约 52 分钟)· 教室 B101」,只给最近的一节(一早上错过三节不会连着弹三条刷屏),而且它和到点提醒共用同一把去重键——先弹了"快上课了"就不会再补这条,反过来也一样。文案照旧只用真实字段:课表里没写钟点的课不定时、没写教室就不提教室,课表没有结束时间所以绝不宣称"这节课还在上",只说"已开课约 N 分钟"。账本写不进(只读目录、装进 Program Files)时退回内存集并如实说没记住:本次运行不会再重复弹,重启后可能再弹一次,不假装已经落了盘。指错位置会自愈(v0.9.98):重装/挪位置后「启动」里的快捷方式还指旧路径——勾看着是开、开机却不响;启动时会后台核对一遍,真指错了 toast 一句怎么修,说「修好开机自启」就重新指过来(同应用旧位置才动手,指向别人的文件只报告)。 -
空闲时段看板(v0.9.27):「我这周什么时候有空」终于有了一份算出来的答案——课表面板「本周」每天的格子里,课程下面列空档时段,再把当天要交的待办(⚑)和校历安排叠在同一列;点某一天下钻看那天空档的起止与「这天要交/校历安排」,退回到本周不丢位置。对话里问也走同一条路(
schedule工具的action=free,支持某天/本周/下周),提示词每轮注入「本周空档(学长算好的,不是心算)」。空档有两档口径,取决于本机有没有作息表:没填时只说「第 3-4 节没课」并明确标「只按节次」——课表里没有下课时刻,所以绝不编钟点;点「填作息表」把教务处那张表的逐节起止录一次(存本机period-times.json,只认从第 1 节起的连续段,断一节就退回按节次而不是猜下去),空档立刻升级成「10:00~11:40」,还能「不填了」退回。三条不算错的口径是硬规矩:那天不在学期内(开学前/假期)不等于"整天空着",一律不报空闲;某节课没写节次的那天一条空档都不报,直说「算不准」请你补节次(那门课可能正落在你以为空着的那几节里);没填作息表时只在已排课的首尾之间找空档,不宣称"最后一节之后还空着"。面板、工具、注入提示词共用free_slots这一份算法,前端禁止自己再算一遍(否则会冒出第二个版本的"有空") -
到点提醒器(v0.9.29):「提前 20 分钟催我」不再只属于上课 ——
reminder记的待办只要同时有日期和钟点(「10月8日17:00前交」「周五下午5点报名」),就走课前提醒那条 5 分钟细轮询:到点前 20 分钟催一次,错过了还在 60 分钟窗口内则开机补一条,和「快上课了」共用同一份按天账本与同一个去重键(催过就不再补,改了截止时间会自动重新催一次)。口径跟课表一样硬:只有日期的事项仍按天催,绝不把「10-08」读成「10-08 的某个下午」;钟点认不准也照样丢掉 —— 「3点」没有上/下午就没有唯一答案,猜错等于差 12 小时,宁可只按天催。今日简报里「今天截止」那条会带上 17:00,明细列表则每条都带上你记下的钟点;同一天到期的事项只报最紧的一条,不刷屏 -
循环待办(v0.9.56):「每周三交周记」「每 3 天背一次单词」这类事记一次就够了 ——
reminder支持repeat(只认「每周」与「每N天」),配一个能确定的具体日期作锚点(anchor)。存盘的日期永远是"下一次":错过且补发窗口也关了的那一班,由 5 分钟细轮询自动滚到下一次(带projected与anchor,照校历repeat:"yearly"的先例),所以电脑三天没开,开机也只会得到"下一个该出现的那次",不会补出三条上周的旧账。做完一次说「r 几完成了」,它记下这一次并自动排下一次(整个循环不停;要停就 delete)—— 完成后旧的那条自然不再催,新的一次到点照常催。三条诚实边界:①未来班次照常催、过去班次绝不补发(规则是你亲口定的,推出来的未来一次是功能本身;但"按循环补发历史"就是替你编考勤);②循环规则必须配确凿锚点日期 —— 光说「每周」给不出日期,就按一次性提醒记下并说明,日期确认后删掉重加;③「每月」不认(大小月天数不一样,硬转 30 天就是编),「每两周」要说成「每 14 天」。同一轮里,定时任务底座(v0.9.42 的jobs.py)也接上了两条后台心跳(proactive._run_due_jobs):到期的周期任务跑一次、记一次账,handler 异常也算"跑过这一班"(宁可这一期不发,不要每 5 分钟重试刷屏);A4 的周报两件按方案排在下一轮 -
周报两件(v0.9.57):定时任务表上的头两个真任务,都是只说不做——推一条带「追问」的通知,做不做由你把追问发回来才动,学长绝不自动调模型、绝不自动爬(那会花你的 Key 额度)。每周心情回顾(周日 20:00 后的第一轮):回读
mood.weekly_review同一份真相——这周你记了什么、平均几分、有没有低到两分以下的日子;一周一条没记就整条不发,“你什么都没记"的通知是压力不是帮助,这是情绪模块"不做打卡"口径的延伸。知识库缺口周报(周五 18:00 后的第一轮):聚合kb-gaps.jsonl最近 7 天检索没命中的问法(growth.gap_digest按normalize_query归组变体、数不同日期不数行数——旧账本里的同日重复不会虚报"出现 N 天”),top 5 摆给你看;补语料是显式动作,不管补不补,“库里缺什么"从维护者的直觉变成一行行可看的账。两类都进通知开关表(review/gaps,托盘右键→桌面提醒里按类别关);节奏刻意错开(周日晚上/周五傍晚),jobs.py的 weekly 到期口径是"当天+到点”,机器整晚没开这一班就跳过——"宁可少跑一次"的下周自然再来。(v0.9.98 修一处账:缺口周报登记的 weekday 是周六、文档口径一直是周五——它晚跑了一天,已改回周五并加反证) -
.ics 兜底导出(v0.9.58,A5 半件):「把课表导进系统日历」从此是一条内置工具(
export_ics)——在工作区生成一份「引路学长日历.ics」(课表 + 待办截止 + 校历一起),双击导进 Windows 日历/Outlook,或发到手机用「日历」App 打开;到点响的是系统,学长没在跑、电脑没开机也一样 —— 这是比开机自启更彻底的提醒兜底(v0.9.42 方案 §A5)。格式是手写的 RFC 5545(纯标准库零依赖):CRLF 行尾、75 字节折行(中文不劈开多字节)、TEXT 转义、VEVENT 带 DTSTAMP 与 VALARM;UID 按"种类|标题|首次时刻|RRULE"确定性生成,重复导出再导入是更新不是堆重。三条诚实边界:①课的钟点只认课表+作息表算出来的事实(schedule.row_clock新公开口,含节次连续段校验与 start_time 反查),没填作息表的课降级成全天事件并在回话里点名哪几门、怎么补——绝不编一个 45 分钟;②校历里repeat:"yearly"的投影日子(按往年月日推的,学校还没通知)一律不导——写进系统日历就成了"每年照着过"的事实,与calendar_alerts过滤投影同一口径;③连日期都没有的待办跳过并报数。周次断档(如 1-2,4-5 周)拆成两个 RRULE 段,不假装第 3 周连上;网页版排除此工具(访客不该能在服务器工作区落文件)。GUI 入口(v0.9.75):课表面板底部「导出到日历」按钮一键生成,toast 报分类计数与导入方法;考试周来临的提醒追问「帮我排一份复习计划,按剩余天数分配到每天」点「去看看」即填进输入框 -
成绩单导入与存档(v0.9.59,H 件):「绩点多少」不再靠每次手贴成绩 —— 课表面板新增「导入成绩」,与课表导入同一个三步向导、同一套隐私口径(登录由同学本人在弹出的可见浏览器完成,登录态不进对话、不落盘;学长绝不导航、绝不代提交表单 —— 各校成绩页地址不同还要选学期,替他点就是在猜)。第②步表头认列(「成绩/总评」+「课程」字样才认,课程/成绩/学分/学期按列名对号,数据行缺成绩跳过、表尾「平均分」统计行自己掉),确定性解析认不出才退模型整理(那次会把页面文字真的发给所配模型,所以必须人点);新工具
scores:action=view 看存档、gpa 直接按存档算(两种常见算法 + 「以学校教务处绩点算法为准」口径,缺学分/等级成绩的行如实点名)、clear 清空(刻意非只读,与 mood 同理)。存档scores.json是比课表更私密的个人数据:进.gitignore、打包清理清单、迁移包清单(换电脑默认带走)。诚实边界:没学分的行照存但算绩点时跳过并报数;「优/良/中」照原文收、折算按学校规定;导入整表覆盖,确认前一个字不写 -
成绩那一屏与无边框窗口(v0.9.113):课表面板多一档**「成绩」——五分制绩点 / 4.0 制绩点 / 平均成绩 / 加权平均分 / 科目数量 / 总学分 六个数 + 学期下拉(候选只列存档里真出现过的学期)。数出自
scores.stats(),而它吃的还是gpa._as_score/_gpa5/_gpa4那三个函数 —— 面板与工具算出两个绩点,比没有绩点更坏;没登记课表也看得到成绩,读不到那一项写「—」而不是 0。教务成绩导入第三次报的根因不在表头关键字,在取材拿错了页**(正方登录后停在framework/xsMain.jsp,那张框架页自己就带菜单表,旧写法"第一帧有表就交差"),现在逐张候选页 × 逐帧都翻(browser.page_targets+ImportFlow.scans);认列补了三种真机形状(表头与表体分家、表头跨两行、「成绩标识」这种带成绩二字却不是分数的列),失败时把翻到的表头原样写回屏上,并给一颗「让学长看这一页的表格结构」(点名page_parse,只读、不替你存)。桌面版改成无边框:系统标题栏整个不要(深色下那条白的从根上没了),顶栏中间空白可拖、双击最大化/还原、右上角 −□✕、八条边可拉缩放、最大化让出任务栏 —— 三颗摆不摆由win_state读窗口自己的样式位决定(配置写了无边框不等于这台机器真去掉了);「收起左侧栏」搬到对话区左上角,右缘问答导航离边框留距、悬停凸显 -
第四轮界面账(v0.9.114):窗口右上角三颗画成 SVG 并 flex 居中(字符 −□✕ 各有基线,摆一行必歪;而带 viewBox 的 inline SVG 在 flex 按钮里会被 Chromium 把宽算成 0,所以宽高写在 CSS 上);「✕」改走
destroy()(pywebview 的Window没有close(),上一版那点下去什么也没发生,而测试还把那句钉成了规格);「选学期」换成自绘浮层 +color-scheme让系统画的部分跟着主题走;入口栏不再出滚动条(格子收紧,overflow-y:auto保留 —— 矮窗口里入口看不见等于功能没了);托盘菜单照 Qoder 重排(新建任务 / 最近会话前 5 条 / 设置,全部走同一个open_panel事件,托盘不持有桥)。两个新功能:计划核对单(plan写完弹整张单子:批准 / 改一条 / 重排,与ask_user各一条锁各一个事件 —— 那是问路,这是批单;等不到回答按未确认收口,绝不生成"用户批准了")、技能分享包(skill_pack.py:一个技能连它的assets/打成 zip,三步 打包 → 预览(一个字都不写)→ 落盘(同名先整目录备份、sha256 对不上就停手、越界路径整份拒收);路径校验吃mydata._key_is_safe那一份,不写第二份)。用户点名的第三件「成本日预算」复验后判定 v0.9.108 已做(config.daily_token_budget+agent._note_daily_budget()接近 80%/超支当天各提醒一次 + 界面那一格),本轮没有重做 -
用量示意改版(v0.9.117):「📊 用量」弹窗重做成两栏仪表盘 —— 左栏四块统计砖(近 7 天 / 近 30 天 / 日均 / 有账的会话)+ 模型用量 Top3 占比 + 全期热力图(2D 日历格 / 3D 立方体:零依赖 Canvas 等距投影,格子高度按当天用量开方缩放,悬停看日期与数值) + 风云榜四卡;右栏 TOKEN 总数大数字、估算费用(口径不变:公开挂牌价的本地快照、缺价行明示「未知」绝不当 $0、估算非账单)、日预算进度条(配了预算才出现)、各供应商占比卡与「每日明细 / 模型明细」两页签(千分位全数,对话数 = 当天有账会话去重)。区间五档:日 / 周 / 月 / 总计 / 自定义(起止认不出就明说不合法,绝不猜一个区间)。缓存命中从这版起真的记账:端点回报了才落
cached_tokens列(老库自动补列),没回报的天如实显示「未记录」。数据全部来自本地token-usage.db,不新增任何联网 -
Token 三维透视(v0.9.118):用量弹窗的热力图切到 3D 后,多一颗「⤢ 点击进入 3D 全屏旋转分析模式」—— 全屏分析视图:左侧是同一本账的全期统计(总量 / 估算费用 / 活跃天数占比 / 最长连续活跃 / 单日峰值,外加五档等级「活跃层→锻造之城」的进度与一句基于真实数据的贺辞),右侧是零依赖 Canvas 的可旋转 3D 场景:按住拖拽旋转、滚轮缩放、▷ 自动旋转、↺ 一键复位、四套配色,悬停到任意一天就浮出那天的日期、等级与 TOKEN 数。数据仍全部来自本地
token-usage.db,零新依赖零出网 -
并行子代理 + 确认标签 + 编辑反馈(v0.9.60,对标 Codex/ZCode 的编码能力包):task 工具批量并行的口子从「只读专用」放开到写类型也能并行(上限 4→6)——「同时改三个独立文件、同时查三件事」一次派出,合并报告回填,不再一路路等。当年的顾虑是共享确认通道分不清谁在等,解法是带标签的确认队列:每一路的确认框标题带「第 N 路[类型] 任务摘要」(CLI 面板标题同样),你按路作答;accept_edits/accept_all 档下各路直接并行跑完。硬规矩:并行写各路负责不同文件(两路改同一个文件是内容竞争)。编码手感三件:①edit_file 锚点打不中时反馈「最接近的行」(行号+相似度,多处命中报行号清单)——模型一回合自我修正,省掉再 read_file 一遍的整轮等待;只报告,绝不模糊替换;②覆盖文件的确认框给真 diff(改了哪几行一眼看清,新建文件维持预览);③单发/批量的超时、截断、回滚栈(v0.9.53)口径全部沿用。
-
MCP 收口:断线重连 + 对话里自助管理(v0.9.61):两件挂了四轮的补齐。①断线自动重连 —— MCP 服务器进程死了/管道断了,下一次工具调用自动重连一次再试,结果如实标注「已自动重连后重试成功」或「重连仍失败」;服务器明确拒绝的调用(McpError)不重连 —— 它活着,重连解决不了;通道层失败单独成类(
McpTransportError),与协议错误分得清。②对话里自助管理(mcp工具,46 号):list/add/remove/enable/disable —— add 先真连一次探测,连不上就不写入(绝不静默存一个坏配置),通过才落盘 config.json 并热重载:旧进程关掉、启用的重连、_mcp_tools原列表换内容,现有会话的注册表当场去旧换新,不用重启学长;CLI 没装钩子就照实说「改 config.json 后重启生效」。密钥仍走 ${环境变量} 占位不落盘;网页版排除(改服务器配置并拉起进程,不能交给访客)。 -
MCP 的 OAuth 动态授权(v0.9.156):有些 MCP 服务器的令牌会过期、要按 scope 申请,让用户自己去申请一个长期令牌、手动填进配置、过期了再手动换 —— 那是这条路上最容易出错的一环。现在服务器配置里写一段
oauth就行:连接前自动换一个access_token注进Authorization,按expires_in提前 60 秒作废、过期自动再换;服务器回 401 时重取一次再试一次(一次自愈,不无限重试)。四条口径:①令牌不进日志也不进任何回话(只活在请求头与内存缓存里);②token_url只认 http(s);③拿不到令牌就不许静默退化 —— 那台服务器就当连不上并说清是哪一步失败(而不是"没带头去请求、然后报一个看不懂的 401");④你在headers里手写的Authorization优先于这一块。只支持client_credentials:authorization_code要在你机器上开回调端口、拉起浏览器把重定向接回来,本项目没做 —— 写了它会明确告诉你没实现,不会静默忽略。client_id/client_secret照旧写${环境变量名};stdio服务器用不了它(没有可注入的请求头),令牌走env。 -
校历补录助手(v0.9.62):考试周、寒暑假这些「校历里一直没录」的日子,录入门槛从「手编 JSON」降到「贴通知」——新工具
calendar_edit(47 号)两步走:preview 把模型从通知里抽出的日期候选校验成一张核对单(每条带通知原文引用与可信度),完整念给用户;commit 在用户明确同意后才追加进 kb/school-calendar.json(只追加、绝不改写已有条目;入库前再校验一遍)。三条硬边界:①引用原文是准入门槛 —— 没有引用的日期就是编的,preview 点名列出不收;②可信度跟着来源走 —— 网址按域名白名单定级,口头提供一律「B-待核实」,绝不因为「模型抽的」就给 A;③重复不入 —— 与现有条目同名同日的、批内重复的跳过并说明。录进去的考试周,首页倒计时、考前提醒等现成机制立刻生效(A5 考试闭环的数据口就此打通);录错了也能改(v0.9.73)——删除/修订同样两步走(核对单列条目全文 → 确认才动文件),改写前自动备份到 kb/history(留最近 3 份,备份写不进去就不动数据),修订一次一条、必须给一句原因,轨迹记在条目备注里;网页版排除(访客不能改主人的校历)。 -
@ 文件引用(v0.9.64,Codex/Cursor 同款交互):输入框打
@弹出工作区文件清单(继续输入即过滤),↑↓ 选、回车/Tab 上屏,路径不用手敲;菜单开着时 Enter 被补全吃掉(不会把半句话发出去),Esc 收起。数据源是新的只读接口workspace_search_files(fs.search_files:与 repo_outline 共用跳过名单,依赖/产物/会话目录不出现;浅层优先排序),防抖 150ms 才问桥;菜单开着时 Esc 只关菜单。网页版无此方法时安静退化,不打断输入。 -
/ 动作面板 + 通知收口(v0.9.65):①输入框打
/弹出动作清单(导出/撤销/压缩/主题/地图/课表/心情/计划/监控/技能/记忆/用量/数据/模型管理,14 项),继续输入过滤(label+描述都匹配,所以「导」会同时带出「导出会话」和课表的「导入」),↑↓ 选、回车/Tab 执行 —— 执行 = 原样点左栏那颗真按钮,行为零分叉、零新增后端;执行时输入框里的 /token 被吃掉,不会把半句话发出去。②「模型恢复了」通知从裸 notify 收编成第 11 类(recovery「模型恢复提醒」):进开关表、用户关得掉了(此前是唯一关不掉的通知)。③顺手清掉顶栏死元素#tok(v0.9.04 计数搬进任务面板后的遗留,渲染出来永远是空的)。对话型命令(v0.9.74):/面板里新加带「命令」小标的一栏 —— 「总结」把上面这段对话整理成要点/时间地点/待办,「翻译 / 解释 / 校对 / 精简」选中后光标停在空处、补上文字再回车;表在minicode/slash_commands.py(唯一真相,改文案不动前端),命令只是替你把这句请求说完整,发出后与手打完全一样;无参数的命令回车即发(走与手打同一条链),带参数的只展开不自动发。 -
消息时间戳与会话保留(v0.9.66):①每条落档的消息带
ts(发出时刻),发往模型端点前剥掉(严格端点不认多余字段,session.outbound在请求出口净场);监控栏时间线重启后也能还原真实时刻与耗时(调用→结果的 ts 差 = 真实间隔,实时表永远优先、两者并存不重算;旧留档没有 ts 照旧不给时间 —— 宁可空着不猜);导出 Markdown 逐条带时刻。②session_keep_last(默认 0 = 全保留):启动时按时间删旧留档,当前会话永不删;一个数讲得清,刻意不做年龄/体积的花样。③injection-events.log 与 tray.log 补上 500 行滚动盖(对齐 watchdog 口径 —— 排查现场要留,但不无限长)。 -
功能导览向导(v0.9.67):补上一个盲区 —— 内置校园模型开箱即用,大多数同学永远不会因为"没配密钥"看到首启向导,攒了二十多个版本的入口没人告诉他们。现在首启弹层有两副面孔:配密钥向导(只对没配好的人)与功能导览(独立 dismiss key、面向所有人一次,三步小抄:左栏那排入口 / 输入框的
@·/·托盘提醒开关 / 数据在本机与"以官网为准"的可信边界)。规则:首启向导正在弹时导览让位到下次,两个向导不排队;各自「不再显示」互不影响。文案住在onboarding.py(改字不用动前端)。 -
提醒可靠性收口(v0.9.28):主动提醒从此「不重弹、不漏弹、且查得到」。校历倒计时、临期待办、今天第一节课也走同一份按天账本(
pushed-today.json)—— 同一天里重启三次学长只会弹一条,而进程连着开三天则每天各催一次(以前是"只在启动那一回催",第二天就哑了);一条提醒聊天栏和桌面两个渠道都没送到时不算「今天已推过」,下一轮会再试,不会因为一次失败整天静默。每一次推送的结论(推了 / 被哪道闸门拦下 / 两路都没送到)写进数据目录的watchdog.log,里面只有类别、去重键和结论,绝不写通知正文;觉得「提醒没发」或「弹了好几遍」,直接这么跟学长说,它会用desktop_notify的action=log把最近几十行读回来告诉你走的是哪条路。另外交接文档 §2 的老里程碑归档进docs/handoff/,新增scripts/check_docs.py自动核对版本号、个人数据文件是否都进了清理清单、文档是否又长胖 -
我的数据与迁移包(v0.9.30):顶栏「💾 数据」回答两件以前只能靠猜的事——数据到底存在哪个目录(exe 旁边,或装在只读位置时自动搬到
%LOCALAPPDATA%\引路学长;面板顶部就是真实路径,还能一键「打开数据目录」)、都有哪些文件、各占多大、会不会进迁移包。31 份本机数据按「我的内容 / 设置与偏好 / 统计 / 缓存 / 日志 / 永不导出」六类列开(v0.9.32 起是 32 份,多出来那份是mood.json情绪日记),每行带一句人话说明(schedule.prev.json只为「换回上一版」存在、pushed-today.json带去新机器会把第一条补发误判成"已弹过"),所以清单本身就是文档;以后加一份本机数据是在mydata.TABLE里写一行,面板和导出同时跟着动(不再靠人肉记得)。真正的用途是换电脑:导出一份 zip,到新机器同一面板导入,先预览再落盘——每一项写着会「新增 / 更新 / 本机更新所以保留本机的 / 跳过」以及为什么。三条硬规矩是这一轮的设计核心:①密钥与教务登录态永远不进包——白名单(pack=True)之外还有一道内层黑名单deny_reason()挡credentials.json/config.local.json/browser-profile/,测试会往清单里手塞一条"手滑加进来的密钥"证明下一个人写错也带不出去,而config.json出库前会洗掉里面的 API Key(但保留${环境变量}占位符,那是用户自己配的取法),代价是到新机器要重填一次 Key;②导入只加不删——本机比包新的那份保留本机的,要被替换的先进migrate-backup/只留最近 3 份,任何情况下不删本机东西;③路径不从界面来——存到哪、读哪个包都由系统文件框决定,前端全程只拿到一个预览编号(nonce),所以"导入"这条链路上没有../config.json可写。刻意没有做的:面板是只读的(没有"一键清空/删除"按钮,每类数据该由谁清仍归它自己的功能管)、token-usage.db不进包(Windows 上 SQLite 常驻连接会锁文件,而且用量统计本来就跟着机器走)、也没有定时或增量备份(这是"搬家"工具,不是备份工具) -
内容技能带边界(v0.9.31):论文、题库、笔记、简历这四件事以前只做"生成",这一轮把边界写进技能并让它可测。
paper-writing做的是选题收窄、每节标「要回答什么/要什么材料/字数预算」的提纲、GB/T 7714 顺序编码制的 stdlib 渲染器(缺哪个字段就印【待补:页码】,绝不替他猜作者年份卷期页码 DOI)和降重自查(按 8 字滑窗报"哪几段与原文连续相同",给改写方向而非同义词硬替换)——不代写正文:要"直接给我一篇 5000 字"时说明做不了并给替代(提纲+逐段改),因为被查的是他本人,代写是把他推到学术不端上。question-bank只整理他自己给的那份题(要"某大学十年真题"直接拒:那是学校/老师的材料,而且抓回来的脏题会毁掉整个题库),拍平成一份内部记录后导出 Anki TSV / GIFT / Aiken,导出前必跑校验,专挡两件比缺答案更危险的事——答案错位(他背下的就是错的,且不报错)与选项字母不从 A 连续(Aiken 必串列)。lecture-notes先探"这份文件到底有没有文字":扫描版 PDF 与整页截图的 PPT 直说抽不到、做不了,并给三条出路(要文字版原件 / 他用系统自带识别抠字 / 他口述学长排版),而不是靠标题脑补一章;能抽的部分保留页码锚点,学长补的句子一律标「(补充,非课件原文)」。resume从"生成"改成定向:一份简历只投一类岗位,技术岗(栈与项目在前、按 JD 原词写、GPA 不高就改用单科成绩而绝不虚报)与非技术岗(实践与结果在前、写可核对的量化结果、JD 关键词优先)两套改法,共同红线是只能重排与换重点,不能给他加经历。四份技能的 python 模板会逐块编译,并 exec 出来真调一次(验证【待补】真的会出现在缺字段时、Tab/换行真的不会把一条记录劈成两行)——模板里的代码是模型要照抄去py_script跑的,少一个括号就是用户机器上的一次报错 -
情绪日记(v0.9.32):顶栏「🌱 心情」或直接在对话里说「今天 3 分,因为…」,一天记一条(分数 + 一句话 + 可选标签),同一天再记就是覆盖,回复会说清覆盖了哪条。它是回读工具,不是评估工具:「这周我怎么样」拿到的是你自己记的那几行原话,不足 3 条时连"形状"都不谈(三条样本说趋势是骗人),末尾固定带一句「这不是医疗建议」。四条边界是这一轮定下来的硬规矩:①不给诊断 —— 不说"你这是抑郁",不建议吃什么,要往那边走一律指向学校心理中心或医院;②不做连续打卡 —— 没有连签天数、火焰图标、「你已经 N 天没记了」,也不会有"该记了"的提醒:情绪记录一旦变成不能断的东西,记录本身就成了新的压力源(最近一周没记过,系统提示词里连这一段都不会出现——那是广告不是帮助);③日期不猜 —— 只认「今天」「昨天」和
2026-09-22这类写法,认不出来就当面向你确认,因为猜错一天,「那周」就少一天;④数据最私密 —— 全部写在本机mood.json,它同时进了.gitignore、打包清理清单和「我的数据」面板的清单(随包发给同学 = 把自己的心情史交出去),导出走系统"另存为"、删除要按两次,mood工具也刻意不是只读工具(每一次落盘都该在确认框里看得见)。什么时候会主动开口:记到自伤/活不下去这类话,或最近两周里有 3 天都很低时,把学校心理健康教育中心那段摆出来(校内咨询通常免费,不用先证明自己"够严重"才配去),里面写了地址、朋辈互助社团和 5·25 心理健康月;电话那行原先是「我这里还没有一个核实过的号码,所以不给你猜」的留白,后来用能渲染 JS 的真浏览器打开学校心理中心自己的公众号原文(HTTP 抓取会被反爬页挡死,所以别把"抓不到"当"取不到")才补上:现在写的是原文里的地址(肇庆校区博雅楼 S2 二楼 / 接待室 S2-204)、电话预约0758-2610529、企业微信与朋辈咨询的预约入口、预约时间,以及 24 小时热线(全国统一 12356、肇庆市第三人民医院 0758-2211222),并标了出处日期;配套那条测试也从「扫到 7 位以上数字就红」改成白名单——只允许原文里那几个号段,多一个少一个都红,因为编错一个号码可能把人在最脆弱的时候导向空号。配套地,校历支持repeat:"yearly":每年同一月日重演的事(如 5·25 活动月、新生心理普查)录一次就按当年自动平移,但平移出来的日子一律标「按往年推的」,而且绝不参与倒计时推送(拿自己推的日子催人 = 替学校编日期),没公布日期的事项就留空,被问到时如实说「日期还没录入,以教务处通知为准」 -
走堂第二步:出门前那一句 + 本周最累的一天(v0.9.36):上一步把「要不要换楼」算对了,这一步把它送到你会看的地方。早上的今日简报不再只说「2 处要换教学楼」,而是接着说「最早第 3 节上课前:J1至善楼 → S5致用楼」——一句能照着做的事,不是数字;桌面通知弹出的就是这句话。课表周视图顶部多一句「⚠ 本周 2 天要换教学楼、共 6 处,周三最多(5 处)」,并且只有最多的那一天的徽章加重颜色(前端读后端的
walk_week.worst_date,自己不比大小)。同时修掉一个 v0.9.35 就存在的少报:徽章和「另有 N 处没列出」以前数的是列表长度,一天超过 8 处就会少报,现在统一取walk_total(真实总数)。诚实边界一条没放松:没填作息表时全页(简报、通知、汇总句、下钻列表)一个「N 分钟」都不出现,汇总句还会自己补「只按节次说,没编分钟」。验证:tests/test_walk.py+8 项、tests/test_schedule.py+2 项、tests/test_briefing.py+1 项,scripts/e2e_ui_v0936.py在真 Chromium 里核到汇总句的每个数字、确认全周只有一天被加重、且没换楼的那一周这两样都不出现 -
校园地图(肇庆校区,手绘版):用线下交付的手绘地图 + 36 张单栋标注图做"位置图"——问「图书馆在哪」「E栋怎么走」,agent 会把该建筑在手绘地图上框出来、并给出它的单栋标注图(整图 + 一个红框),面板支持滚轮缩放/拖动平移/点框看大图;也能不用问模型自己找:面板里有搜索框(支持 E栋、s5 这类俗称与「食堂」这类类别词,命中多处会全列出来让你挑)、图例上的类别徽章一点即筛(只看食堂/只看宿舍)、邻近建筑可点跳转、一键复制位置说明;首页首位的「🗺 打开校园地图」按钮点开即是地图并自动聚焦搜索框。A栋~E栋在地图上是两栋楼(学思苑X / 集贤苑X座),工具会返回歧义并把候选都摆出来,绝不自作主张挑一个。这份数据没有路网,所以只答"在哪、旁边是什么",不编路线与步行时间。数据是
frontend/campus-index.json(交付包索引副本),底图与建筑图由scripts/build_campus_assets.py从交付 PNG 生成 -
权限确认解释"为什么":确认框顶部给出「这一步为什么要做 / 这一步会做什么 / 影响」——目的优先取模型填的
reason,没填就用同一轮它写的说明文字,再不行按命令形态做启发式解读(如"用 Python 读取并解析数据文件(一条命令里含多个步骤)"),并标出影响面(只读 / 会写文件 / 会联网 / 删除不可恢复 / bash 改动不在撤销范围) -
74 个内置工具(每加一只都要同步:这句现在由
check_docs.py对着build_default_registry()实测核 —— 以前写的是 47、再后来是 55,漂了三十几个版本没人发现,因为那条闸只管 HANDOFF §1,README 这句不在管辖内;v0.9.105 两处一起对账)):文件与命令read_file/write_file/edit_file/apply_patch(整包统一 diff:一次改多个文件各几行,任一文件对不上就整包不落盘,行尾与编码跟着原文件,路径逐份过同一个围栏,dry_run可预演,v0.9.134) /bash/bash_input(给后台命令的标准输入写一行:解开npm init、REPL、要敲 y 的脚手架这类"下一步取决于上一步输出"的流程 —— 这些用预写文件加重定向是无效的。只对后台生效,超 4000 字拒绝而不截断,不能发 Ctrl+C 也不能给 EOF,v0.9.146) /py_script/glob/grep/repo_outline(工作区结构大纲) /repo_wiki(代码库全景百科:架构/技术栈/常用命令/代码约定,v0.9.163) /symbol_search(跨语言精准符号搜索:类/函数/方法/接口/结构体/常量,v0.9.165) /find_references(跨文件代码引用查找与影响面分析:call/import/inherit/type/assign/read 精确提取与改动风险评估,v0.9.166) /rename_symbol(跨文件代码符号重命名与重构预演:基于 AST 语法自检、影响面风险评估与 Unified Diff 预览,v0.9.167) /call_hierarchy(跨文件代码调用层次结构与依赖拓扑分析:AST与正则双引擎构建Incoming/Outgoing调用树、循环调用防环截断、Fan-In/Fan-Out分析与Mermaid图表导出,v0.9.168) /symbol_definition(跨文件代码符号定义提取与实现跳转:基于 AST 与多语言词法精准提取起止行与实现代码块,支持导入链追踪与实现直读预览,v0.9.169) /code_outline(代码结构大纲与类/成员树:基于 AST 与多语言词法精准提取类/方法/字段/文档与层次大纲树,支持深度折叠与签名预览,v0.9.170) /diagnostics(按扩展名跑检查器:.py→ruff、.ts/.tsx→工作区自己的 tsc、.js→node --check、.go→go vet、.rs→cargo check;检查器不存在或超时会明说"这次没做检查"而不是说"没问题",write_file/edit_file之后也会自动跑一次并把问题回灌,v0.9.147) /test_runner(测试套件运行与自愈诊断:自动识别 Python/Node/Rust/Go 测试框架、受控截断输出、提炼失败用例与 Traceback、持久化测试快照,v0.9.164) + 联网web_crawl/web_search/campus_notices(现拉官网通知栏) /mcp(MCP 服务器自助管理:list/add/remove/enable/disable,add 先真连探测、通过才落盘热重载,v0.9.61) /calendar_edit(校历补录:preview 核对单→commit 入库,引用原文是准入门槛,v0.9.62) + 浏览器browser_open/browser_eval/browser_snapshot/browser_click/browser_fill/browser_screenshot/browser_close/browser_status/page_parse(把页面表格结构化) + 计划与技能plan/use_skill+ 知识与校园search_knowledge/search_history(跨会话记忆) /kb_suggest/campus_calendar/gpa_calc/library_search/library_guide/export_ics(课表+待办+校历导出系统日历文件,v0.9.58) /scores(成绩存档:看 / 按存档算绩点 / 清,v0.9.59) + 个人数据memory/reminder(支持每周/每N天循环,v0.9.56) /mood(情绪日记:记一天 / 回读一周 / 导出 / 清空,刻意非只读——每次落盘都该在确认框里看得见) /schedule/get_weather/desktop_notify(桌面提醒开关、试弹、开机自启与提醒日志) + 地图map_find_place/map_show_list/map_highlight_building/map_drop_pin/map_clear+notify_parent(子代理 → 主会话留一句话,只读;它落在主会话下一次请求的一条系统侧注记上,不会变成「用户说的话」——那是这一只存在的全部理由,详见下面「子代理留话」那一段,v0.9.154) + 视觉与出图(v0.9.39)ocr_image(拍图取字) /render_chart(零依赖 SVG 图表) /generate_image(文生图或本地文字卡片) /view_image(看图:把工作区里的一张图发进会话给模型自己核对 ——render_chart画的图、generate_image出的图、browser_screenshot的截图对不对,不用凭代码猜,v0.9.173) /tool_search(按需取回工具:tool_loading写lazy时,那些没进每轮工具面的工具靠它取回,取回后本会话一直有效,v0.9.173) /session_message(递话:给正在跑的子代理或另一条活会话留一句话,走系统侧注记、不冒充人话,v0.9.173);另有task(子代理派发,由应用装配层注入);v0.9.98 新增export_trace(把当前会话导成可回放的运行轨迹 JSON,报障交给维护者复现)与worktree(Git 工作副本的现状与建议,只读);v0.9.99 新增export_feedback(反馈包:体检表+缺口问法+技能账缝成一个文件发回维护者) -
计划依赖图:
plans/plan.md的步骤可以声明depends_on(文件里落成- 依赖: 1, 2),写入时校验未知依赖/自依赖/环(不合法就不落盘);读计划时附一份「调度视图」——哪一步正在进行中(标[/],v0.9.33)、哪些步可执行(依赖已满足,可并行)、哪些被上游失败卡住(标[!]后下游自动判卡住,不会静默跳过)。老计划文件(无依赖行)照常读写 -
GUI 计划面板(v0.9.24):顶栏「🗂 计划」(带
已完成/总数角标)打开后是进度条 + 「现在能动」与「被上游失败卡住」两栏 + 每步的依赖与备注(每一步四种状态:待办 / 进行中(v0.9.33,行左边转圈)/ 已完成 / 失败);模型每plan(action=update)一次面板就自己动(plan_changed推送)。面板严格只读——打勾仍由 plan 工具写文件,免得"文件即状态"变成两处真相;「↩ 派发到输入框」把「接着做哪几步」按依赖顺序填进输入框,用户过一眼再发(刻意不并发派写子代理:并发写会互相踩文件、确认门还会串到别的答案上) -
对话流里的计划卡片(v0.9.33):不用为了"做到哪了"再点一次顶栏——模型
plan一更新状态,一张清单就落在你正在看的那段对话里:进度条 + 每步一行(待办空心圈、进行中那行转圈、完成打勾、失败标红、被上游卡住列在脚注),脚注直接写「步骤 2/5 · 正在做第 3 步 · 点标题看依赖与备注」。三件事是刻意的:①只由实时事件画 —— 开机/换工作区/手动刷新都不补画,因为挂着「进行中」的旧计划其实没人在做,给它转圈就是撒谎(那种情况下"做到哪了"的正确答案是顶栏角标的 3/5);②一个计划一张卡 —— 目标与步数没变就原地更新,换了目标或改了步数才另起一张,上一张留在原处当历史;③回合结束不装忙 —— 这一轮停下后还挂着「进行中」的那一步会立刻停转、变成琥珀实心环,脚注点名「2. 做幻灯片 还挂着「进行中」」。卡片也只读,点标题行只是打开上面那个面板。要看到进度自己在动,前提是模型动手做某一步之前先plan(action=update, status="in_progress")(工具描述与每次回话都在提醒它,做完再标done) -
右侧「任务监控」栏(v0.9.34 开在顶栏、当时标「🧭 动态」;v0.9.37 改版成四段并改名「任务监控」;v0.9.39 起入口在最左边的入口栏「🛰 监控」)把对话右侧让出第三栏,回答"这一轮它到底做了什么、东西在哪"。五类由
minicode/activity.py扫真会话消息算出来(纯函数,不碰界面):🤖 子代理(并行派发的几个探索各列一行,报告全文点开才展开)、📝 产出(同一路径多次改动合成一行、次数累加)、🌐 网页查阅(打开过哪个页面、搜过哪个词)、🔗 来源(真的进了上下文的页面,广告级链接不算来源)、🧠 记忆(这一轮改了哪条)。判定标准是"能不能当事实看",所以四条口径写死:①每一行都由一条真实的工具调用撑起来 —— 没调用过task就不会有子代理行,类别为空整段直接不显示,不摆一排"暂无";②产出行每次都回磁盘上核一遍(在不在、多大、改于几点)—— 模型说"已生成 report.docx"而文件其实被删了(或压根没写成)是真实会发生的事,那一行会改口成「已不在磁盘」并失去可点的样子,面板不跟着一起装;③运行中与失败分开标,判失败用聊天里工具卡片同一份前缀口径,不会出现"聊天说失败、右侧说完成"的自相矛盾;④每一行点了都要有真后果 —— 来源行打开网址、产出行在资源管理器里定位文件(文件没了就只是灰字,不给"看着能点、点了没用")、搜索行把这句话回填进输入框等你改完再发、子代理/记忆行展开的是后端存的那份全文。只读、且关着就不问后端:开着时跟着tool_start/tool_done防抖自刷(别的会话在跑什么不会混进你正看的这一栏),收起后清空内容与角标,下一次打开重新按后端数据画。它不假装能翻出被上下文压缩掉的早期动作,标题写的是「本次会话(可见)」。验证在scripts/e2e_ui_v0934.py:32 项断言的界面数据出自真实bridge.get_activity()(真的调过write_file/edit_file/task/memory再聚合),不是手填的假 payload -
右侧「任务监控」栏(v0.9.37):上面那一栏升级成可随时收起、并且记住你上次怎么摆的监控栏——顶栏「🛰 监控」或
Ctrl+Shift+M开合,默认收起(不占地方,也不在你没要的时候敲后端)。栏里四段,自上而下是「⏱ 此刻」「🗂 计划」「🧾 时间线」「📦 产出与来源」(后三段就是上一条那五类)。①此刻 = 现在正在跑的那一步 + 它已经跑了多少秒。秒数是后端给的基值在前端每秒 +1,后端没给数字时那一行压根不出现,不是显示 0 秒装忙;回合已经停了却还挂着没回话的那一步会改口「已中断」(抬头统计里也这么写),不转圈骗人。②计划 = 工作区那份计划的进度条 + 每步一行(完成/失败/进行中/被卡住/待办五种样子),点任意一行打开完整的计划面板看依赖与备注——栏里不打勾,打勾仍归 plan 工具,两处都能改就会互相盖。③时间线 = 按真实先后排的工具调用,一轮一段、默认只展开最新一段,抬头写「执行工具 N 次,其中 M 次失败」;时刻与用时来自 GUI 层那张实时表(minicode/gui_ui在tool_start/tool_done两处记的),所以子代理内部那些被静默吞掉的调用宁可不显示时间,也不给它编一个。④产出与来源 = 上一条那五类,一行都没变。哪一步对应哪一行靠minicode/toolsum.summarize这一份口径配对(聊天卡片、右侧栏、实时表三处调同一个函数;三处各自措辞早就对不上了,所以这一轮把动词收口成一份)。四段各自可折,折了哪几段落盘monitor-pref.json(连同"上次是开还是关"),它是个人数据,已同时进.gitignore、打包清理清单和「我的数据」面板——不随包外发;轮次的展开是一次性的,不记到磁盘(轮次每跑一步都在变,记下来明天就对不上)。验证在scripts/e2e_ui_v0937.py:13 组断言跑真 Chromium,payload 出自真Session+ 真GuiUI.tool_start/tool_done+ 真plan工具,连"等 0.6 秒那一步的用时该显示 1 秒"“收起后localStorage里必须写进open:false”"关掉再刷新回来折叠还在"都是实测出来的,不是照着界面手抄 -
子代理留话(
notify_parent,v0.9.154):子代理没有可以问的人(它跑在静默通道里,ask_user与task都摘掉了),以前它碰到"这里有个岔路没定"只能写进最后那份报告 —— 而你可能是三五分钟后才看到。现在它可以在半路留一句话:notify_parent落在主会话下一次请求里的一条系统侧注记上,你在聊天区随后就能看见它、也来得及改方向。三条写死的口径:①它绝不会变成「你说的话」 —— 走的是系统侧注记那条通道,不是插话信箱(queue_interjection那条落进留档时是role: user,那是给你自己补话用的;子代理的提醒走那条路会变成"你刚提的要求");②它不打断、也拦不住任何东西 —— 只加一句话,主会话照旧等子代理跑完(所以它不是提问通道,问不到回答);③收不下会直说 —— 超过 500 字会截断并说明,排队满了会回它一句"没送到,要紧的事写进最终报告",不让它以为自己提醒过了。这一只是只读的(提醒一下不该点一次头),网页版跟着task一起关掉(访客没有子代理)。 -
影子 git 检查点(v0.9.157):
/undo那本账只记得住学长亲手写的那些文件,所以bash/py_script间接改过的东西它回滚不了 —— 这一版补上了那一半:每次要动文件之前,把整个工作区快照进数据目录里的一个影子 git 库(shadow-git/)。四条写死的:①绝不碰你仓库的.git(你的git log一条都不会多出来);②回滚只还原、绝不删 ——/restore只写回快照里有的那些文件,快照之后新建的文件原样留在原处;③一轮只做一次,只读的回合不为它付钱,子代理不进这张网;④一个工作区一本账。用法:/snapshots列出最近几次、/restore还原;config.json里shadow_git默认开,置false即关。 -
子代理的并发边界与嵌套开关(v0.9.155):这一版把子代理那套并发边界补严了,并给「嵌套」(子代理再派子代理)留了个开关
config.subagent_nesting,默认 false = 今天的样子(子代理不能派活,深度只有一层)。为什么要这么谨慎:派活能嵌套之后有三件事必须同时成立,少一件都比不开更坏 —— ①父批与子批要共用同一张文件占用表(各建一张的话,同一个文件可以跨层同时被写、两边都不报错,上面那道「同一批里两路写同一个文件当场拦下」的程序闸就漏了);②并发上限必须有全局那一道(批次上限只管一次派活,管不到嵌套,也管不到「后台会话各建各的 Agent」那一层;现在全机在飞的上限是 24,满了不排队,直接如实回一句「这一路完全没有执行」);③超时不覆盖后代——父级到点不再等,而孙辈仍会把当前那一步跑完。打开之后:task只留给写档(侦察/复核/审计这几只只读档永远拿不到它 —— 否则「派一路只读侦察」就成了绕开只读限制去写文件的入口),深度最多 3 层(到顶那层里连工具都不出现,而不是出现了再回一句「不许派」)。没做前端嵌套树:机制默认关时它没有可展示的东西。 -
子代理并行派发:一次要查/做多件互不相干的事时,
task的type与task都传数组就能并发(上限 6 个,报告按请求顺序合并)。写类型也开放(v0.9.60 起)——确认模式下每一路的确认框标题带「第 N 路[类型] 任务摘要」,一次答一个;accept_edits/accept_all档下各路直接并行跑完。硬规矩:并行写各路负责不同文件——这条 v0.9.98 起是程序闸不只是口头规矩:同一批里两路都写同一个文件时,后到的那路当场被拦下并指名是谁占着(write_file/edit_file 的显式路径;bash/py_script 里间接写的文件闸管不住,划地盘的规矩对它们仍然适用)。并发时子代理的流式输出与工具卡片被静默(toast 与错误照常透传),避免几路text_delta在同一聊天区里互相穿插 -
多 Agent 领域路由(v0.9.39 起,
minicode/router.py):task的type除了 explore / implement / review,以及 v0.9.81 加的两档只读角色档audit(代码与文档/配置口径对账)/testaudit(测试假闸自检)—— 角色档不靠 SKILL.md,auto永远不会选中它们,要显式点名 ——,还能填八个领域档code(写改代码)/writing(论文、提纲、参考文献)/data(表格、统计、图表)/english(四六级与考研英语类,只读)/campus(校园办事:学校问题、馆藏借阅、校历通知、停车领车)/material(文档材料:PDF 合并拆分、证件照排版、经验帖链接归集)/career(就业求职:实习、校招、考公考编的时间线、投递记录、岗位对照与面试准备,引用 resume 技能但简历文书仍归 writing)/study(备考复习:按考试日期倒排复习计划、错题归集、背诵与预习节奏,引用 question-bank 技能但题库导出仍归 data),或直接type="auto"让它按任务描述自己判。这一层只登记"哪个领域用哪几份已有技能"的引用关系,不另写第二套提示词 —— 知识本体仍在skills/*.md,所以路由表里写的技能名必须真在skills/里、引用的工具名必须真在注册表里(有测试逐条钉着,写了不存在的名字当场红);只读档还多一条:它登记的常用工具必须真的read_only,否则该档根本拿不到这个工具,提示词却会空许诺(同样有测试钉)。v0.9.68 把原本无人认领的 7 份技能(school-qa/library-guide/kb-fallback/bike-parking-guide/pdf/photo-print/koubei-extract)收进campus与material两档。选中的理由会回显在报告抬头:派哪档、命中哪些词、计几分、会先加载哪几份技能;加载不到就明说"本机技能库里加载不到",不凭名字猜一份不存在的技能。一个词没命中时auto退回 explore 并在理由里承认,不假装路由很准。 -
进程树约束(v0.9.135):Windows 上每一条
bash/py_script起出来的进程都被挂进一个自己的 Job Object(操作系统记着这棵树)。于是三件事从"尽力而为"变成"有保证":①bash_kill与前台超时连孙子进程一起回收,不再是"只杀了 bash,下面的可能还在跑"那句道歉;② 命令自己退了之后,它在 job 里留下的后代也一起没(不漏进程);③ 单进程内存 2 GB、树内进程数 512 的兜底上限(防的是"模型写了一段递归把这台机器填满",默认给得很宽,正常活儿都装得下)。这一层不管网络 —— 禁网要 AppContainer 或防火墙规则,那是另一轮的事,回话里也永远这么写。起不来就照跑、照说:非 Windows、API 失败、父进程已被关进不许嵌套的 job,一律降级成"进程约束:未启用(原因)",命令照常执行、界面上看得见这一层在不在 —— 假装有沙箱比没有沙箱更糟,这是这个项目的红线。已知限界也写在话里:进程是Popen之后才挂进 job 的,那几十微秒里它已经 spawn 的下一代可能漏在外面(有一条反证测试专门复现这件事,所以那句"启动那一瞬在 job 之外起来的进程不在此列"不是客套) -
长命令放后台(v0.9.84):
bash多一个background=true—— 预计要跑超过 300 秒的活儿(全量测试、装依赖、构建、批量转换)不再硬等:命令放后台、立刻返回一个 job 编号,之后bash_status看状态与输出尾部(只读,不弹确认框)、bash_kill终止(Windows 上走taskkill /T连子进程一起杀 —— Git Bash 那条命令真正干活的是它下面的 python/pytest,只杀 bash 会留一堆孤儿)。四条边界写在回话与确认框里,不许模型糊过去:①后台不受 timeout 收手,也不会随这一轮结束而停止,要停必须显式 kill;②输出只存在内存缓冲里、只留尾部(丢掉多少字bash_status照实报),学长退出或重启就没了 —— 要留档请重定向到工作区文件;v0.9.85 起只要还有后台任务,学长会把它们的真实状态(poll 到的)附在下一次请求末尾的一行里,模型不必自己想起来轮询,也不许看到那行就替用户宣布「跑完了」;③学长退出时atexit会尝试把还在跑的一起收掉,收不掉会照实说;④没有 taskkill 的机器上只能杀直接子进程,回话就写「子进程可能还活着」,不假装杀干净。同时在跑的后台任务上限 12:超了是拒绝新任务而不是静默挤掉旧的(挤掉等于偷偷杀用户正在等的活儿) -
长命令跑到一半要看得见(v0.9.91):前台
bash不再等命令结束才一次给全 —— 它自己起进程、两条管道各一个读线程(只读一条或先等再读,都会在另一条写满时把子进程卡死),每 15 秒向界面报一行「已跑多久 · 已输出多少字 · 最后一行」,写在「任务监控 → ⏱ 此刻」那一行上。三条口径:①模型看到的回话一个字没变 —— 进度只走 UI 通道,不进会话消息(往每步塞变化的文字等于把旧闻留在留档里,与 v0.9.85 后台状态「搭在请求末尾、不进留档」同一条取舍);②两路输出仍然各自成段,--- stdout ---/--- stderr ---都在,失败排查靠「这句是 stderr 说的」,合流就没了(有一条两路各写 300 KB 的防死锁用例钉着);③进度是「尽力看见它在动」,不是逐字符转播 —— 只能读到子进程已经吐出来的那些字,它自己攒着不 flush(或干脆拿刷进度条)就看不见中间那一段,这句话同时写进代码注释和包内《使用说明》。终端那一侧是同一条信息追加一行(节流只在一处判);子代理的进度_QuietUI吞掉(几路并发一起报会盖住同一行)。顺带补两条:超时改走进程树那同一份杀法(不留第二份杀法,没有 taskkill 时照实说子进程可能还活着)并带回已经产出的那截;stdin改成 DEVNULL —— GUI 那边等于永远没人输入,命令会干等。验证:后端侧tests/test_bash_progress.py15 项,界面侧scripts/e2e_ui_v0991.py7 项真 Chromium(载荷出自真GuiUI.tool_start/tool_progress/tool_done,不是手填的假字典)。 -
计划 ↔ 子代理对上号 + 子代理的联网动作可见(v0.9.81):派子代理去做计划里的某一步时,
task带上step=编号—— 那一步立刻标成「进行中」、备注写下派了哪几路,子代理回来后把每路的报告字数与超时如实写回计划(计划面板与「🛰 监控」里都看得见);它不会替你把那一步标成完成 —— 子代理回来的是转述不是证据,成没成仍由模型按报告判断后再标。步号写错(没这一步、或那步已失败/已完成)时直接报错、一路都不派,不白花额度;上游已failed的步拒绝派活,守住「不跳过失败的上游」。同一轮补上了 v0.9.76「产出可见性」的姊妹盲区:子代理读过哪些网页、查过哪些库现在也进「任务监控 → 网页查阅」,每行标着是哪一档子代理读的、失败的那一路标失败(以前只算主对话自己发起的联网动作,派几路去查资料时那一栏就是一片空)。「来源」栏刻意不收这些网址 —— 那一栏的口径是「真进过主对话的外部内容」,子代理读的页面只在它自己那一程里,主对话拿到的是转述,混进去等于骗你说依据是那些页面。另加两档只读角色档:audit(查代码里的枚举/上限数字/工具名/默认值,与 README、system_prompt、HANDOFF、config.example.json、《使用说明》是否各说一套;只报两侧都真读到的差异,措辞不同不算漂移)与testaudit(扫恒真断言or True、只断言没抛异常的空壳、被 skip 掉的关键路径;它不跑测试 —— 只读档拿不到 bash/py_script,要真跑改派 code 档)。两档都不是领域档,auto不会选中,要显式点名 -
项目级权限白名单(v0.9.87):项目根放一份
permissions.json,把「每次都要问一遍」的动作预先批下来—— 但它只替换权限档位那一步确认,红线链一条都越不过:白名单里写「允许读.env」照样弹确认框、写绝对路径或..上跳在装载时就被拒收、首词命中白名单而命令里混了一段rm -rf /照样整条硬拒。三条刻意的设计:①写了不等于生效 —— 批准记在本机perms-trust.json里、记的是那份文件的内容指纹,改一个字整份失效;因为「clone 别人的仓库带进来一份」和「网页内容鼓动模型自己写一份来发通行证」这两条路在文件层面与用户真想批权限一模一样,不能靠文件自证;②能预授权的只有构建类命令(首词名单与accept_edits档共用同一份),rm/del/git push进不来;③每次免确认放行都留痕(安全日志一行 + 界面一句「这一步没问你:第 N 条…」),静默放行等于没有审计。两只新工具:permissions(只读,看现状与为什么没生效)/permissions_trust(要确认,批准与撤销) -
确认框那颗「以后都允许」(v0.9.133):以前用户点完「这次允许」,想让它下次别再问,得自己手写一份
permissions.json。现在确认框多第四颗按钮(图形版那颗 / 命令行按r),它落的是本机信任表里这个工作区名下的granted数组 —— 工作区里一个字节都不写。这是这一条最要紧的取舍:记进permissions.json等于 clone 一份别人的仓库就替这台机器决定什么不用问,与「钩子只从安装目录 config.json 读」是同一条根。三条规矩:只收窄(记的是"这一个文件"或"这一类命令首词",「允许改 notes.txt」永远不等于「允许改这个目录」;命令首词还得在可预授权名单里,rm/git push点十次头也记不进)、七类永不记住(凭据文件、仓库.git、接触过外部内容后升格的敏感动作、你自己写的 ask 规则、工作区外的路径、沙箱里可配的危险命令、以及「这份没读过」那一句 —— 前四类连钩子都不许代答,更不会由一次点头变成永久免确认)、可撤销(permissions_trust action=revoke一句"这个项目的免确认动作都收回去"会把文件那半截与记住的那半截一起带走,AGENTS.md的采纳不动,因为那是另一次独立的点头)。界面上看得见两处:那颗按钮只在收窄得成一条规则时才出现(给一颗点不成的按钮是样子货),它与「本轮总是允许」长得不一样(虚线边框 —— 误点一次就把一次性的点头变成长期授权);点完当场把这条规则读回这道门,所以"以后"不是下次开程序,是同一轮的下一步。permissions那一屏现在两本账分开列:「项目白名单 N 条(要核对指纹)」与「本机记住的 M 条(换台机器就没了)」 -
并行子代理的每一步都看得见(v0.9.93):
task一次派几路,以前界面上只有一条task加最后那份合并报告 —— 批量模式为了不让几路的流式文字在同一个聊天区里穿插成乱码,把每路的工具卡片整个吞了,顺手把「这一路先查了什么、哪一步挂了、现在跑到哪」也吞了。现在开的是一条只记账不刷屏的通道:每一步挂在task那一行下面(GuiUI.live_child_begin),带「第 N 路[档位]」标签、真实时刻与用时,失败那一路当场标出失败,仍在跑的那一路显示进行中并带着它自己的长命令进度;「此刻」下钻到真正最深那一层。五条不许做假的口径都有针:子步不掺进「执行工具 N 次」(那个数的定义就是会话消息里的调用数)、父行没开就什么都不记、收行只收自己那一路的、溢出如实写「另有 N 步没列出」、子步一律不可点(那一步的原文留在子代理自己的会话里,点开是空的行比不给更坏)。聊天区仍然只有一条task卡片 —— 安静这条规矩没被弄松,只是不再等于黑箱。 -
按档位分模型(v0.9.95,
config.json的subagent_models):「分别处理问题」以前只分工不分本钱——通用五档加八个领域档跑的永远是同一个模型,而大范围侦察和动手改代码根本不是一回事。现在可以写成{"explore": "便宜的", "code": "硬的"},一条规矩管到底:只换模型名,不换供应商(跨供应商是另一把 Key,那条路在「模型管理」里)。三条不许做假的口径:①换不出去必须说出来 —— 名字不在当前供应商的启用模型里(打错字、别的供应商的模型、界面上勾掉了的)就退回主模型,并把「退了、为什么退、现在用什么在跑」写进那一档的报告抬头与合并报告,单发/批量两条路同一个说法;②换成功也要说出来 —— 抬头写「本档模型 X」,计划备注里跟着记(模型 X),并行批次那条「已并行派出 N 路」写explore→X,免得「这一路结论为什么明显比另一路粗」变成事后无从查起的悬案;③没换就不喊 —— 留空或与主模型同名,报告一个字不多嘴。客户端按模型名复用(一个模型名一条连接),且不继承主模型的思考档位(档位能力是按模型算的,搬过去就是"这个模型根本没这个档")。构造规则收在LLMClient.scoped一处,会话内切模型走同一条 —— 两处各抄一遍总有一天漏带active_provider_id,表现是 401 看着像 Key 坏了。同一轮顺手修掉一处只有并行才暴露的老 bug:缓存里那条馆藏 SQLite 连接是跨线程共用的,而锁只在取连接那一瞬间握过,几条线程各自execute完再各自fetch—— 拿回来的是别人那条语句的结果,表现为某一路子代理随机报「执行出错」(报错文本与模型无关,最难倒推)。现在每一条读语句都在同一次持锁里跑完(library._read),六处调用点全部走它,取不到结果行就按「读不出来」降级,不报一个猜出来的数。 -
本地档位定义(
agents/*.md,v0.9.129):档位以前只有代码里那五个加八个领域档,想给"侦察"这一档换一句自己学校的输出规矩只能改源码。现在工作区(或应用数据目录)放一份agents/scout.md,frontmatter 写name/base/ 可选label/description/tools/read_only/max_steps,正文就是那一档多出来的角色规矩。四条红线全部在装载与派发两层核死,而且都不静默:①只能收窄 ——tools:只能是 base 那一档本来就拿得到的工具的子集(核对发生在sub_tool_registry,因为只有那里知道真注册表里有什么;写了拿不到的名字会在派发回话里点名),read_only只能 false→true、max_steps只能比内置上限小(超了夹回来并说);②不许覆盖内置档与领域档 ——name: explore或name: campus这种整份丢掉并说明理由(同名两套权限,谁生效变成看装载顺序),要改就base:指向它再换个名字;③提权字段一律剥掉 ——permission_mode/allow_tools/deny_tools/model/provider/api_key/sandbox这些从 frontmatter 上撕掉并逐条说给用户听(权限看config.permission_mode,换档模型看config.subagent_models,不由仓库里一份 markdown 决定;抄的是 ZCode 把项目级 profile 的permissionMode在运行时剥掉那一半);④丢掉要有声音 —— 读不出来、没写base、base不存在、档名撞内置、两份同名文件后一份、剥掉了哪些键,全部汇成[档位定义注记]打在派发回话开头,不"配了不生效还以为生效"。这类档不进auto路由(不在router.DOMAINS里,与audit/testaudit同一口径:角色要显式点名)。一处边界要说清:task给模型那份清单是装配时的快照,中途新加的定义要重开会话才出现在里面 —— 但派发那一层每次都重读盘,所以名字叫得出就派得出去。v0.9.152 起还会认别的工具放在仓库里的档位目录(v0.9.152,E「子代理外部目录兼容」):.cursor/agents/、.claude/agents/、.codex/agents/—— 你从 Cursor / Claude Code / Codex 带过来的子代理定义不用重写一遍。只认工作区里的那几个,不去翻你本机的~/.claude/agents(这一层的语义是"仓库自带的定义跟着仓库走",读工作区外面是另一笔账)。顺序即优先级:本项目自己的agents/排在前面,同名时它赢;认到的每一份都会在[档位定义注记]里说清"是从哪个目录认来的",免得你看见自己多了一档却不知道它哪来的。上面那四条红线对它们一样适用 —— 这一层多开了一个"读 markdown"的口子,而那个口子里的文件是别人写的(仓库自带的.cursor/agents/会跟着 clone 走),所以提权字段照剥、只读照不许放开、步数照只能往下收,有一条针专门钉这件事。 -
工具钩子(v0.9.100):config.json 的 hooks 字段配 pre_tool/post_tool 两条命令 —— 每次工具调用前后各跑一次,pre 非零退出=拦截该步(输出作为拒绝理由),post 失败只在结果尾附一行;参数与结果经临时文件交付不进命令行。只认 config.json:工作区文件长不出钩子(那是任意命令执行口子)。
-
工作区 AGENTS.md(v0.9.100):仓库根放一份 AGENTS.md(或 .agents.md)写项目约定,进系统提示词,子代理也带 —— Codex/ZCode 同款约定。v0.9.127 起第一次要你点一次头:这份文件可能是别人 clone 带来的,而"文件里写了规矩"与"你同意它对你说话"是两件事。问的是内容指纹(记在本机
perms-trust.json那一行):采纳过就不再问,文件改一个字会重新问;没答、点「按推荐」、点「不采纳」都算没采纳 ——那一段一个字都不进提示词,侧栏与/instructions会写「未采纳」。用户级那份是你自己写的,照旧不问。 -
自定义斜杠命令(v0.9.100):工作区
.commands/.md(frontmatter 一句说明 + $ARGS 模板),/ 菜单与终端 /命令 都能用,同名覆盖内置 —— 社团可以预置「周报模板」这类高频请求。 -
留档版本记账(v0.9.100):会话留档带 schema 版本号,格式再变时有明确的迁移路径。
-
删体检(v0.9.100):左栏 🩺 与 CLI /health 按用户要求移除;机器哪里不对直接跟学长说现象,要发反馈用「生成反馈文件」(它内部仍用体检的自检数据)。
-
反馈包(v0.9.99):说「生成反馈文件」,体检表 + 最近 7 天检索没接住的问法 + 技能使用统计就缝成一个 JSON 落在工作区(要带本次对话原文需明确说,默认不带)—— 报问题发给维护者这一个文件就够,不用截图;密钥/凭据/配置内容一个字节不进包,发之前自己过一眼。
-
工具钩子 matcher(v0.9.102):hooks 的值可用对象形态限定范围 —— {“command”: …, “tools”: […], “paths”: [“*.py”]},只有匹配的工具(带匹配路径)才跑;字符串形态=全量,老配置零改动。
-
工具钩子能改能问(v0.9.115,H1~H4):pre_tool 挪到权限门之前跑,认领这一步的钩子可以拒绝(exit 2 或
{"decision":"deny","reason":"…"})、改写这一步的参数({"updated_input":{…}})、附一句话({"context":"…"});改写后权限门重跑一遍,确认框画的也是改写后的那份 —— 门看的永远是真要执行的那份参数,"用户点过头的内容"与"被执行的内容"不许是两回事。硬拒红线根本不叫钩子(先只读跑一次门只为拿这个判断)。post_tool 可把 lint/测试的失败原文回灌进结果({"updated_output":"…"},是追加,原结果不吞)。退出码三种命运分开说:0=跑成、2=明确拒绝、其它非零/超时=钩子自己坏了(拦不拦看on_error,默认 block,连着三次没跑成会提醒你去修那条命令)。matcher 补command_prefix(bash 的参数叫 command,“只对 git 开头的命令审计"今天表达得出来了)与args_match;timeout可按条配(默认 10 秒、再长也只到 120 秒,被压回会说话)。钩子实测毫秒单列落档(hook_ms,不并进 handler 全程那把elapsed_ms),时间线还原显示成「用时 5s(钩子 0.4s)」。新增:permission_request(v0.9.115,H3)在弹确认框之前给一条钩子替用户答话的机会 —— 只有真跑成且明确表态(allow/deny)才算数,钩子没跑成一律照旧弹框(on_error在这一类上不适用:坏掉的策略钩子既不配替人拒绝、更不配替人放行);代答只这一条这一回合,不落盘、不升「本轮总是允许」,并且必留两处痕(安全日志 + 回给模型写明「用户没有点过头」)。三类问话永不叫钩子:工作区内凭据、仓库.git写入、本回合接触过外部内容后升格的敏感动作 —— 它们本就不接受档位/白名单/本轮总是允许,更不接受一条命令的 stdout。硬拒红线也不叫钩子(改写发生在门之前,门之前还有一次只读预检)。入口一个都没新增:仍只从 config.json 构造,工作区文件长不出钩子。H4 补三个非工具类事件(v0.9.115 的两个 + v0.9.151 的stop):session_start(每个会话叫一次)、user_prompt_submit(每问叫一次,「重新生成」不算又开口)、stop(每轮结束叫一次,正常答完、撞步数上限、被停止、报错都发 —— 而且拦不住这一轮结束,exit 2也不拦)。它们只能附一句话(走_pending_prior那条已有的一次性通道,与差评避让并列不互相覆盖),不改写用户原话、不拦发言(deny在这三类上不生效,而且当场说出来),子代理不叫这三个事件。stop那句落在下一轮的第一条请求上 —— 它跑的时候这一轮的请求早发完了,这是这一格唯一说得通的去处(给下一轮留句话);session_start/user_prompt_submit则附在这一次请求里。附的那句只到下一次请求为止,不是常驻上下文 —— 与 Claude 的 SessionStart 不等价,想常驻得先解决"谁能往 system prompt 里说话”。这三类钩子没有"哪只工具"这一维:配了tools/paths也不会被筛成永不触发。H6 编辑后自动检查闭环(v0.9.115,靠 H1 拼出来的第一个真用例):post_tool的{result_file}载荷现在带着args(旧形状只有tool/result,而"写完 .py 顺手 lint 一遍"要是拿不到路径就只能去解析那句给人看的结果)—— 于是这样一条就能跑通:{"post_tool": {"command": "python lint.py \"{result_file}\"", "tools": ["write_file","edit_file"], "paths": ["*.py"], "timeout": 60, "on_error": "continue"}},脚本读d["args"]["path"]、把失败原文以{"updated_output": "…"}回灌,模型当场修而不是留着"文件已写好"的假象;updated_output是追加,原结果不吞。没做也照实说:pre_compact(把压缩当策略点)、子代理事件、D5 只读诊断工具仍未开工 —— 压缩那条路最脆(KV Cache 前缀 + 配对修复 + 协议合法),不在出包这一轮往上面插管子。 -
行尾·编码保真 / 项目规则可写拒绝 / 钩子配方(v0.9.116):①学长改你文件时沿用原文件的行尾与编码(旧版把 CRLF 整份转成 LF、把 GBK 中文稿整份转成 UTF-8 —— 前者让你的 git diff 看着像每行都改过,后者让记事本打开变乱码),并在回话里说清沿用了什么;读不懂的字节直接拒写并说明,不把猜出来的字写进文件。顺带修了一面更糟的:CRLF 文件上多行 old_string 逐字匹配根本匹配不上,以前只报「未在文件中找到」。②项目根 permissions.json 的条目可带 decision:
allow(免确认,原形状不变)/ask(再自动的档位也要问我)/deny(直接不许做),求值 deny > ask > allow,且位置不同 —— deny 排在只读放行之前、ask 排在红线之后档位之前,否则这两种决定都是装饰品;三道老闸一条没松:没核对批准过整份不生效、改一个字批准作废、红线类路径不许写进规则(对 deny 同样拒收:那些本来进不去,留着只会让人以为是这条规则在拦)。③「看看有哪些钩子配方」有两条现成的(git 命令审计零执行 / 改完 Python 跑一次测试,后者会执行工作区代码),默认一条都不挂:preview 摊开命令、范围与风险并给十分钟一次性凭据,用户点头才写进 config.json(写前备份、写盘失败回滚内存那一份),挂上即时生效不用重启。钩子命令另有{workspace}占位符 —— 它继承的是本进程 cwd,而打包版 GUI 的 cwd 是安装目录,没这个占位符「跑测试」会在错误目录里跑且只在装好的包里发作。 -
/init 生成 AGENTS.md(v0.9.100):说 /init,学长扫一遍工作区起草项目指令文件(先给草稿,同意才写盘;已有文件在旧基础上补充)—— 与自动注入形成闭环。写完那一问会请你点一次头采纳(v0.9.127):写盘与"我同意照它干活"是两件事,这条与
permissions.json那句「写了不等于生效,核对过才生效」同一条根。 -
skill-creator / repo-wiki(v0.9.102):两份新技能 —— 把重复流程沉淀成 SKILL.md(含边界与模板验证),给工作区生成/更新一份带出处的仓库 Wiki(wiki/ 目录普通文件,不建第二套索引)。
-
压缩带记忆候选(v0.9.102):上下文压缩时顺手在摘要末尾列「记忆候选」—— 存不存由你与学长确认,不自动写。
-
看板跨工作区(v0.9.102):多副本并行时,看板每行标注在哪个工作区/副本跑(单一工作区不添噪)。
-
MCP resources(v0.9.102):读 MCP 服务器提供的资源(list 列清单/read 过确认框取内容,二进制不内联)—— P7 方案实施。
-
验收真跑(v0.9.102):计划步骤的验收判据跑完自动把 ✓/✗ + 时刻写进计划备注 —— 计划文件/计划卡/监控三处同源。
-
会话分支(v0.9.100→102):用户消息上的「⑂」从那一问分叉出新会话(原会话原样保留),换个思路再走一遍。
-
差评账上卡(v0.9.99):检索命中的知识条目若带着差评记录,回话会如实标注(差评是对当时那次回答的,不是判知识错),引用时会多核对来源 —— 有账就用,不再让「这条被差评过」没人看见。
-
终端 /health(v0.9.99):REPL 里一句 /health 出全表(数据目录/模型/权限/馆藏/MCP),与 GUI 体检共用 mcp.summary_rows 一份真相;深检仍走 python -m minicode.health --deep。
-
情绪标签回读(v0.9.99):记心情时可给标签(如「实习」),回看时按标签筛「实习那些天」;标签不进系统提示词、不进迁移包,只有你主动问才看得到。
-
数据归属上卡(v0.9.99):「💾 数据」面板逐行标注这条数据是「全局一份」还是「各工作区一份」—— 开了工作副本后课表/成绩不跟着走这件事写在明面上。
-
访客留档保留(v0.9.99):网页版的 session_keep_last 每个访客各自留最近 N 份(只在启动清),访客跑多了不再把服务器盘写满;0=全保留。
-
本轮改动逐个看、逐个退(v0.9.101):右侧「任务监控 → 本轮改动」列出学长这一程用 write_file / edit_file 改过的每一处(改 / 新建、几点、这之后还有几处没退、被别的工具动过没有)。点一行只退那一处并从栈里摘掉它,比它更新的改动原样留着;新建的那一处是删掉它不是恢复。每行那颗「看改了什么」展开的是后端算好的 diff:左边是学长最后一次改它之前的内容,右边是磁盘上的现在这份;加减几行、被截掉多少行、这一处后来有没有让别的工具动过,都写在那一块上。二进制或超过 512 KB 的文件明说算不出,不给一份「看起来没有变化」的空 diff。编辑某一句旧提问重发时会问一句「文件怎么办」:「退回文件并重发」把那一问之后学长改过的文件改回当时的样子(新建的那一处就是删掉),「保留文件,只重发」什么都不动 —— 两边都是一次点头,不会静默改你的盘。命令与外部程序改的从来不在账里,所以也退不掉;这中间压过一次历史时回合坐标会错位,那一次会拒绝回退并说明一个字都没动,让你改用逐处回退。原来的「↶ 撤销」按钮行为一字未变(还是后进先出退最近一步)。这一栏只列写文件工具改的 —— bash / py_script 改出来的东西不在快照里,「全部回退」也退不掉它们,抬头那句就写着这条边界,不让你以为一键就回到本轮开始前。v0.9.128 把这一屏三处说不准的地方说准了:① 这本栈是按会话攒的,所以现在按「第 N 问」分组、段标题带「跨 N 问」、当前那一问单独标「这一轮」,「全部回退」那行也从「退回本轮开始前」改成「退回这一场会话的开始」(旧那句在长会话里是假话);② 账外那片列出来了 —— 环境栏那份 git 清单里撤销账没有的文件,逐行标着「退不掉」跟在下面(不为此多敲一次 git,所以它随环境栏的节奏刷新,抬头写明);③ 回合结束时如果这一问真改过文件而监控栏关着,聊天区落一条「这一轮改了 N 个文件 · 看改了什么」,点一下开栏并展开那一段 —— 以前
activitySchedule在关着时直接 return(没人看就不敲桥,这条是对的),结果关着栏的人永远不知道该去开。 -
计划里的某一步可以带验收判据(v0.9.101):写计划时给这一步填
verify:(跑测试 / 跑构建 /--check这类一眼判得成的命令)。带它的步骤,在学长用 bash 原样把那条命令跑完之前,标 done 会被直接拒绝;跑不过也一样不收,回话里带着退出码与输出尾巴。填不出判据就留空 —— 留空是正常态,不许为了面板好看编一条空跑的命令。验收命令走的就是用户自己也能敲的那条 bash 路,权限门、沙箱、确认框一个都不绕过。判据本身跑得慢(>300 秒)就让它走background=true:那条命令跑完的那一刻这一步自己会认出来,不会因为前台超时而被锁在「永远标不了 done」外面。 -
跨会话看板(v0.9.101):侧栏「📋 看板」把四处现成的账拼成「在跑 / 等你 / 完成」三态 —— 哪几个会话在跑、哪些后台命令还在动、计划里哪一步卡住等你决定、定时任务上次跑出什么结论。只读、不新增一份任务状态落盘;只列最近 20 个会话(界面上写明,不悄悄截),读不到的那一处改口「没读到」并带原因,不会被画成「没有任务」。「在跑」认的是这个程序开着期间的事(那份标记在桥内存里),退出重开后就看不见谁在跑了 —— 这句边界跟着数据一起显示。
-
别的工具的规则文件也认(v0.9.153):仓库把规矩写在 Cursor / Cline 认的那几个名字底下时,学长一样读得到 ——
.cursorrules、.clinerules(这两份与工作区根的AGENTS.md进的是同一层,共用一次采纳点头:它们都是"这个仓库自带的规矩",拆成两次点头只会让你把同一件事点两遍),以及 Cursor 现在那种.cursor/rules/*.mdc。两条写死的口径:①.mdc里带globs的一律不读,而且会在「📐 指令」那一行与/instructions里点名说清为什么 —— 本项目刻意不做规则引擎,假装按 glob 生效就会做出"我明明只在.py上要这条,它却对所有文件都说";不带条件的(alwaysApply: true或什么都没写)才读。frontmatter 本身不进正文,那是给别的工具看的元数据,混进提示词等于让description:冒充你写的规矩。②采纳记的是这一组合并内容的指纹 —— 改.cursorrules里一个字、或者往仓库里再加一份,都会回到"没采纳",不会因为AGENTS.md没动就算数。AGENTS.md与.agents.md互为别名,只读第一个。 -
子目录就近
AGENTS.md(第三级,v0.9.149):前两级之外,仓库里任意子目录都可以放一份AGENTS.md(或.agents.md)。取层的锚点是你正在读/改的那个文件,不是命令行的工作目录 —— 改backend/api/x.py就按backend/api/→backend/→ 仓库根这条链逐层找,越靠近那个文件的越具体(与更外层冲突时按更近的那份来)。只在碰到时才进上下文:某个目录第一次被读/被改时,那一层的正文附在那一次工具结果后面,并且只附一次 —— 系统提示词那段固定前缀不为没碰过的目录付钱。每一层各自采纳一次:别人 clone 一个仓库等于把它自带的每一份都递到你面前,所以一层一次点头(与工作区根那份同一个口径),没点过头的那层不注入,但会在那一步结果里说一句"这里有一层、你还没采纳",下一问开头弹卡问它 —— 一次只问一层(一张卡里列 N 层要你逐条对齐,对齐错了等于替你点了头)。侧栏「📐 指令」那一行会把碰到过的目录层一起报出来(目录级 /(N 行)),没采纳的缀「、未采纳」。红线照旧:沙箱边界、敏感路径硬禁、确认门、「没答当没同意」哪一层都改不动。 -
两级指令文件(v0.9.101):项目级是工作区根的
AGENTS.md(v0.9.100 起),这轮补上用户级/AGENTS.md—— 一个词两个位置:仓库的规矩跟着仓库走,你本人的习惯跟着这台机器走(随「我的数据」迁移包一起带走)。存在才注入、不存在什么都不做(不创建模板也不提示「你该写一份」),过长被截会写明截了几字。侧栏「📐 指令:内置 + 用户级(N 行) + 项目级(M 行)」报的是真读到的份数与行数;项目级那份没点过头采纳时后面缀「、未采纳」(v0.9.127)—— 这一行不能让人以为它已经在起作用。管的是风格与流程:沙箱边界、敏感路径硬禁、动手前的确认框、「没答当没同意」这几类由代码把守,任何一份指令文件都改不动它们,注入时那句话也原样带给模型。 -
并行写的程序闸(v0.9.98):见「并行子代理派发」那条 —— 同一批两路子代理都写同一个文件时,后到的当场被拦下并指名谁占着,不再靠"各路负责不同文件"的口头规矩。
-
周期自动备份(v0.9.98):config.json 里填
backup_dir,每周六上午把可打包的本机数据(含聊天记录、不含密钥)自动打成一份 zip 放进去,保留最近 4 份 —— 「丢电脑/换机」时不用想起手动导出;没配置就如实跳过,绝不自选目录往你盘上写;跑没跑问学长「定时任务跑没跑」能查到。 -
Git 工作副本(v0.9.98):同一个仓库要同时做两件事,说一声就能在仓库同级开一份
__/的工作副本(命令走确认框执行,学长绝不偷偷建目录),它就是一个普通工作区 —— 沙箱与项目白名单照用(白名单默认要重批);长期记忆各一份、课表/待办/心情全局一份;删除永远不代做。 -
运行轨迹导出(v0.9.98):说「导出这次运行的轨迹」,当前会话的完整对话原文 + 每步工具调用的名称/参数/结果/时刻就落成一份 JSON(工作区根目录)—— 报 bug 时把它交给维护者就能复现,不用再截图;文件是原文,交人前自己过一眼。
-
会话自动起名(v0.9.98):侧栏会话的标题取自第一条提问(最后一句会漂,题目不该漂),不调模型零成本;老会话没有标题字段时照旧显示最后一句。手动改名刻意不做,等真实使用反馈。
-
两条时限(v0.9.39,
config.json):turn_time_limit_seconds(默认 1800)= 一轮最多跑多久,只在两步之间收手;subagent_time_limit_seconds(默认 600)= 单个子代理最多等多久报告,超时只是不再等它,那一档仍在后台跑完。所以它说的话里没有"我已经停止了它"这种吹牛,迟到的结果也不回填成准时的。设成 0 = 不限。 -
信号回灌(v0.9.39,
config.json的feedback_recall,默认开):已经记下来的东西回头要真的改变行为。①反复搜空——同一个查询词在可见对话里连着空手,第 3 次起工具回话末尾附一行「×3 未命中 + 下一步怎么办」,右侧监控栏那一行从第 2 次起标「×N 未命中」(两处数字出自同一次扫描,不会各说各话);一次任务里换关键词补搜不算,那是正常检索。②差评避让——这次的问题若与最近 30 天里某条 👎 属同一类(判定接长期记忆去重那份 2-gram 口径:整体 ≥0.75 或较短一条被覆盖 ≥0.85,够不到就当没这回事),下一次请求里会给模型一句系统侧先验:换种方式答、先给依据与来源。它不会跟你说"你上次点了不满意"(那是把私下的一次点击当众复述),先验也不进会话留档,只在那一次请求里存在、用完即清。关掉开关,发给模型的消息与工具回话与开之前逐字一致(有测试钉着)。数据都在已有的message-feedback.jsonl与kb-gaps.jsonl里,这一轮没新增任何落盘文件。③评价落到条目上(v0.9.80)——每次回答引用了哪些知识库条目,在检索那一刻记进kb-hits.jsonl(结果文本与会话留档里都没有条目 id,只有这一刻知道),你点 👍/👎 时按"最后一条提问之后"的窗口把条目绑进反馈记录;维护者脚本scripts/review_kb_growth.py的第四节从此能报逐条命中率(每条被引用几次、关联几次差评)。口径写死:差评数是"引用过这条的那次回答被点了 👎",不是"这条知识是错的"——它是线索不是判决 -
模型层收口(v0.9.40):模型"看到的东西"这一层补了四个口子。①时钟——日期与课表是建会话时烧进 system prompt 的,而本应用是托盘常驻的:进程连着开三天,它会照第一天的日子念三天。现在每个回合开始前对一次表,跨天了才把提示词重算一遍(走
build_system_prompt同一个函数,不出现第二份时间来源;一天至多破一次 KV Cache),并说一句「已跨天,日期与课表已刷新」。②压缩——超长历史折叠成摘要时从「保尾丢头」改成留头 + 留尾(总预算 40000 字不变),摘要提示词按校园场景重写:任务目标 / 改过哪些文件 / 日期·课名·地点·待办·来源网址 / 关键决定 / 下一步。③尺子——压缩阈值以前只数消息,而每次请求实际还带着 40 来个工具的 JSON Schema(几千 token),于是面板说"还早"它却突然压;现在Agent.context_tokens()一处算清,任务面板、/history、触发器三处同一个数。④步数——max_steps进 config(默认 40,老 config 行为不变),撞上限后不再戛然而止:补一次不带工具的调用,让模型就着已经跑完的那些步骤写「已完成 / 未完成 / 下一步」,那一句「工具用完了」只活在这次请求里、不进留档;这次调用失败就静默退回旧行为 -
记起上次 + 就地改答(v0.9.41):
search_history工具 / CLI/find/ 侧栏搜索框是同一份算法的三个消费者,而留档在APP_DIR/sessions(工作区围栏之外),所以模型侧走的是受控出口session.history_hits——只取用户与助手正文(工具往返不进结果)、只给会话时间与工作区目录名、绝对路径不下发,网页版明确排除并写了理由。回答下面 👍/👎 旁多一颗 ↻ 重新生成:撤掉这段答复、照原样重跑那句提问(不复用「编辑重发」那条路,因为它会丢掉当时那张图);点过的 👎 仍留着,那是差评回灌要的信号。 -
四处静默失效补闸(v0.9.41):悬空工具调用——
add_assistant(带tool_calls)与逐条add_tool_result不在一个事务里,断电/强关/压缩"保头+尾"任一种切断都会留下"喊了工具没结果"的序列,端点对它回 400 且往后每轮都 400,用户只剩/clear;现在在恢复时、工具循环异常时、以及贴着出口_messages_for_request三处补齐,原始留档不回写只补一行repaired标记。技能引用的工具名钉成清单(改名/删除红,技能新依赖一个工具也红)。技能要用的库(pptx/docx/openpyxl/pypdf)以前只在打包清单里、requirements.txt一个没声明,源码用户跑论文/课件技能第一步就ModuleNotFoundError而所有测试全绿;现在两头都钉。模型连不上从前是死胡同(一句「模型调用失败」之后没有任何恢复信号),现在失败起一条只问GET /models的探活(60 s × 最多 10 次,不动 Key 额度),通了在聊天里说一句并尽力弹一条桌面通知,同时那句没送出去的话回到输入框——绝不自动重发。 -
首页会看进度 + 能发群的卡片(v0.9.42):「接着做」那一行读的是真状态(逾期/今天要交的待办、计划里标「进行中」或现在能动的那一步),三样都没有就整行不出现,点一下只把话填进输入框不自动发。🖼 分享图把一段回答排成能直接发群的竖版卡片 PNG 存进
images/,回答里出现过的链接自动写进卡片尾部「来源(可点开核实)」,没有链接就不放这一段、超长会明说"只排到这里"。Ctrl+F 会话内搜索:两个以上字起搜,报"第几条 / 共几条",命中在收起的「工作过程」里会自动展开;高亮走 CSS Custom Highlight API,不改 DOM(重写 innerHTML 会把消息上的复制/编辑/↻ 按钮事件全弄丢)。快捷键补齐:Ctrl+Shift+K聚焦输入框、Ctrl+Shift+[ / ]切会话。工作区弹窗里三个"只进不出"的目录(uploads/、images/、charts/)看得见大小也删得掉。 -
网页抓取:
web_crawl抓网页/整站为 markdown(同域 BFS 跟链、限页限速),入库前自动去掉每页重复的导航/页脚;可选 to_kb 一键写入本地知识库kb/crawl-.json,用kb_category/kb_tags打主题标签(检索时标签权重×2),由 search_knowledge 带来源网址检索。源码环境用 crawl4ai(真浏览器,能渲染 JS);打包版自动切到内置轻量抓取器(httpx + BeautifulSoup),不带浏览器内核(否则 79MB 的包会涨到约 500MB),静态站点效果一致,需要 JS 的页面会明确提示(或改用下面的浏览器能力) -
浏览器能力(CDP 直连,不背浏览器内核):给 agent 装上"眼睛"——它能真的开一个浏览器看页面,而不只能抓静态 HTML。
browser_open返回 JS 渲染完成后的标题与正文(教务/通知页这类靠 JS 渲染的站点终于是真内容);browser_eval在页面里跑一段 JS 精确取数(价格/表格/链接列表)或点按钮、滚动;页面交互三件套:browser_snapshot列出页面上所有可见可交互元素(链接/按钮/输入框/下拉框,带序号与字段名,只读不弹确认),browser_click按快照序号/按钮文字/CSS 选择器点击并自动回报点击后的页面状态(序号是 snapshot 在页面元素上打的临时标记——页面一变标记就失效,永远不会点错元素;页面上有多个同名按钮时拒绝盲点),browser_fill按字段名批量填表单(name/id/占位符/aria/标签文字都认,下拉框按选项文字匹配、勾选框接受 true/false),文本框用「原生 setter + input/change 事件」写入——React/Vue 的受控组件也能感知到变化;可选submit=true全部填好后自动点提交,任何字段失败都不会提交半张表单;browser_screenshot把页面截成 PNG 存进工作区,图直接出现在对话里(点图可放大);browser_close收标签页。两条接入路线:launch(默认,零配置:自己找 Edge/Chrome 用独立 profile 起一个无窗口实例)与 attach(连用户自己开了远程调试的浏览器,带他的登录态,能看只看得到登录用户的页面)。attach 只在显式mode="attach"或设了YINLUXS_CDP_URL时才用——默认不动用户那个有几十个标签页和真实登录态的浏览器,对分发型程序太侵入,实测也更容易卡住(所以 auto 探到调试端口也会先走 launch,只有本机起不了浏览器时才拿 attach 兜底)。attach 的探测要三级兜底:127.0.0.1:/json/version→localhost:→ 直接读用户目录里的DevToolsActivePort文件第二行;实测本机 Edge 153 对/json/*一律返回 404,只有文件里那条 ws 路径连得上,只依赖 HTTP 探测就会永远报"没找到开着远程调试的浏览器"。且探到端口不等于能用(残留文件/端口被别的程序占),要真跑一次Browser.getVersion握手才算成立。靠纯 Python 的websockets说 CDP,所以轻量版安装包不需要 playwright 与 270MB 内核。安全三条:只允许 http/https(file://、javascript:、chrome://一律拒);每个线程/会话/子代理各自一个标签页,并发不串台,已结束线程留下的页会被回收;网页版(对外只读)不给浏览器工具(可被用来打内网 + 在服务器上起浏览器)。终端/browser看当前能不能用、走的哪条路线。标签页可见可管(v0.9.98):browser_status会列出现在开着哪些页(标题/网址/归属/编号),browser_close带 target=编号能关任意一路的页(用户自己开着的页只脱手不关)。配置被占用不再是死结(v0.9.139):上一次导入留下的浏览器还占着browser-profile时,再点「打开登录页」以前只会报一句「Edge 启动后立刻退出(退出码 0),无法启用浏览器能力」,点多少次「再读一次」都是同一句 —— 现在先复用那个活着且端口答得上来的实例(一个进程都不起),要窗口(教务登录必须有)而复用的那个是无窗口的就换一份兄弟配置继续并明说「教务要重新登录一次,登录态不会跟过来」,全起不来才报错、且那句话带着退出码与三条出路。四条保守口径:没有我们的实例标记就不复用(不知道那个实例有没有窗口,拿它做必须看得见的登录是在赌)、YINLUXS_BROWSER_PROFILE点名的目录绝不换(换目录等于绕过用户显式挑的那本登录态)、绝不 taskkill 不是自己起的进程(要关一个复用来的实例走它自己的Browser.close)、收工时只清自己那一份标记(删掉别人刚写的等于骗下一个人「这份配置没人用」) -
校园主题语料库:
scripts/crawl_school_topics.py按"用户会问什么"分主题爬官网(奖助学金 / 入党党建 / 团学推优 / 学科竞赛 / 证书与等级考试 / 考研升学 / 转专业与专业选择 / 选课与学分 / 教务考试 / 就业与考公考编 / 榜样风采 / 心理与情绪 / 学风与学习方法 / 招生专升本 / 校园活动与文体 / 宿舍与生活服务 / 社团与学生组织 / 军训与国防教育 / 校园新闻动态 / 学生故事与风采 / 学生事务办理 / 校园讲座与专题 / 视频与图文校园 / 服务大厅与办事入口,共 24 个),关键词过滤 + 翻页 + 发布日期提取 + 去导航,产出kb/school-gzasc.json(每条都带原文链接与发布日期;视频页与图文指引页也建条目,正文里给出观看/查看链接),换学校只改scripts/school_topics.json,不用改代码 -
OpenAI 兼容内核:底层走 OpenAI 协议(流式 + 工具调用),所以默认的校园模型之外,任何 OpenAI 兼容服务(DeepSeek / Kimi / Qwen / 智谱)都能在源码层接;本地服务(127.0.0.1)与校园内网(10.x)自动绕过系统代理
-
网页版(校园助手):一条命令把同一套前端搬到浏览器(
python web_main.py)——同学打开网址就能用,只读白名单(校园知识库/图书馆/校园地图),每访客独立会话与留档、限流与并发上限、同源校验(详见「网页版」一节)
快速开始(源码运行)
cd yinlu-xuezhang
py -3.12 -m venv .venv # Python 3.10+
.venv\Scripts\activate
pip install -r requirements.txt
crawl4ai-setup # web_crawl 首次使用前执行,下载浏览器内核
copy config.example.json config.json # 一般不用改:默认就用内置校园模型
python gui_main.py # 图形界面
python main.py # 终端 REPL
常见模型的 base_url(仅源码层自定义时参考)
校内分发版固定用内置校园模型,下面这些只在你要自己改造源码、替换默认模型时才用得上 (
config.json里的其他供应商配置会被保留但不会激活)。
| 供应商 | base_url | model 示例 |
|---|---|---|
| 智谱 GLM | https://open.bigmodel.cn/api/paas/v4 |
glm-4.6 |
| DeepSeek | https://api.deepseek.com/v1 |
deepseek-chat |
| Kimi | https://api.moonshot.cn/v1 |
kimi-k2-0905-preview |
| Qwen | https://dashscope.aliyuncs.com/compatible-mode/v1 |
qwen3-coder-plus |
用法
python gui_main.py # 图形界面
python main.py # 交互式 REPL
python main.py "修复 pytest 报错" # 一次性执行
echo "列出 TODO" | python main.py # 管道输入
python main.py --json "任务" # 无头:stdout 只有一份 JSON,退出码说清结局
python main.py --output-format stream-json "任务" # 无头:stdout 是 NDJSON 事件流(最后一行 result)
python main.py --output-schema s.json "任务" # 同上,另按 schema 要一份结构化结果(不合 → 退出码 6)
python main.py --mcp-serve # 作 MCP 服务端(stdio):把校园只读能力暴露给外部 MCP 客户端
python main.py --workspace "D:\我的资料" # 指定工作区启动(路径不合法直接报错退出)
python main.py --version # 打印名字与版本就退出(不发请求、不读配置)
无头模式那条是给脚本用的,不是给人看的:--json(等价 --output-format json)把横幅、
进度、工具卡片全部改道 stderr,stdout 只留一份能 json.loads 的结果(response / tool_calls
/ asks_refused / turn_tokens / session_file / status …)。退出码
0 做成 · 1 模型报错 · 2 参数不对 · 3 该问人却没人可问 · 4 被上限收尾 · 5 中断。
第 3 码是这条路上的安全边界:换入口不换权限 —— confirm 档该弹框的步骤,无头模式一律
按"不点头"处理并把它说出来(文件不会被写出来),而不是替你批一次从此不问。
--output-format 认不出的值直接报错,不静默退回纯文本。
-
要过程可判就上事件流(v0.9.144):
--output-format stream-json让 stdout 变成一行一条的 NDJSON:第一行stream_start、中间是text_delta/reasoning_delta/tool_start/tool_done/hard_reject/compacted/retry,最后一行是与--json同构的result。每条都带从 1 起严格递增的seq,每行立刻 flush;人读的话(info/error/ 进度)仍旧只走 stderr。它面向的读者是把学长当子进程驱动的编排层(CI、外层 agent), 不是盯着日志看的人,所以不新增退出码、结局仍以最后那份结果对象为准。--json与它 互斥(两个一起给报参数错,靠位置决定形状是这类旗标最贵的坏法);--output-schema与它可以一起用,那时格式仍是事件流,structured_output只出现在result行里。 stdout 被下游关掉(管道关闭)按中断处理,退出码 5,且停发后续事件。 -
要一份结构化结果(v0.9.136):
--output-schema让模型按你给的 JSON Schema 只输出一个 JSON 对象,结果里多两个固定字段:structured_output(按 schema 验 过了的值,不合就是 null)与schema_violations(人话清单,每条带路径如notes[1]:类型应是 string)。给了这个旗标就自动按 JSON 出(那份结果本来就是给机器读的)。这一条做的是"问过 它 + 验回来",不是网关侧的受约束解码 —— 后者能保证模型只能吐出合 schema 的字节,我们 不知道接的这家端点支不支持,所以只保证"不合就明说"(退出码 6,与status: schema_violation同一条)。把前者说成后者,就是这一路最容易犯的"界面上说安全、实际没拦"。schema 里影响 合法性判定的关键字这一版验不了就当场拒收(anyOf有、$ref/pattern/patternProperties/minimum/minItems/not无),而不是默默忽略 —— 忽略一条 = “我按 schema 验过了"成了假话;description/title/default这些不影响判定的元数据可以随便写。schema 读不出来就在进 Agent 之前以退出码 2 退,不花那一轮额度。那句输出要求走系统侧、只活这一回合,不并进 用户原话(否则它会进留档、被「编辑重发」原样带回、被/history念出来 —— 机器加的 东西不该冒充人话)。 第一次运行例外:全新安装还没有config.json时,CLI 会先从模板生成它并以退出码 1 结束 (就是那句"直接重新启动即可”)—— 这是 CLI 一直以来的首启行为,无头模式不绕过它;第二次起才是上面那套契约。 -
模型自带一份配置(v0.9.130):模型管理里每个模型有一颗「配置」,能填上下文窗口、最大输出 Token、图片输入(支持/不支持/跟随探测)、推理等级清单与参数映射。填了的数真的生效 —— 窗口决定什么时候压缩、最大输出决定请求里的
max_tokens、等级决定 🧠 按钮那几个选项怎么编码进请求;留空的项一个字都不覆盖(探测与内置目录照旧)。优先级是声明 > 探测 > 内置目录,所以「我这家的模型明明支持图、探测说没有」这种情况可以自己定。只填了等级没写映射会被拒绝保存 —— 那几档会显示在按钮上却一个参数都发不出去,那是摆设。 -
改动前像落盘(v0.9.131):
/undo、/rewind、「本轮改动」逐文件回退那本账以前只在内存里,所以「改完三个文件、程序崩了或重启,回来清单是空的、磁盘却还是改过的样子」会真发生。现在每处改动的改之前原文按会话落在本机checkpoints/(工具还没跑就先写,所以写到一半崩了也在)。一条硬规矩:存不下的就整条不记 —— 因为「没有前像」在回退端的含义是「这文件当时不存在」,按那个含义退会删掉你现在的文件,所以宁可清单少一条,也不留一条假前像。这份账本不进安装包、不进迁移包(里面是别人文件改之前的原文),会话留档被删时它跟着被扫掉。
CLI 命令:/help /clear /model(供应商列表)/history /resume [] /find、/rename、/archive、/unarchive、/fork [](搜自己的历史会话)/undo(清单;diff 看改动、``·last·all 才动手,动手都要点头)/compact
/sandbox /permission [档位](四档权限 + 项目白名单生不生效)/think [档位](思考档位)/instructions(这一轮读到了哪几层指令:内置 + 用户级 + 项目级,各几行、有没有被截)/rewind [files|talk|both](退到那一问之前:文件与对话一起退,默认 both;留档不删)/snapshots(影子库里有哪几次整树检查点)/restore (还原到那次快照,只还原、绝不删 —— H,v0.9.157)/workspace [路径|default] /memory /remember /dream /skills /kb(知识库统计)/plan
/library [书名](不带参数=馆藏库状态;带书名=直接在 133 万条书目里搜,与 library_search 工具同一个 handler)/style [normal|guide](回复风格,guide=讲解模式)、/usage [1|7|30](token 用量)/browser(浏览器能力状态)/review (审查一个分支相对分叉点的改动:文件账+提交清单+逐文件 diff,只审不改)/exit;
Ctrl+C 中断当前回合。
网页版(校园助手)
同学打开网址就能用,不用装任何东西。只读问答:校园知识库 / 图书馆馆藏 / 校园地图 / 技能说明,没有文件与命令能力。
python web_main.py # 默认监听 0.0.0.0:8480,同学从校园网访问
python web_main.py --open # 顺带用本机浏览器打开
python web_main.py --host 127.0.0.1 # 只给自己用
python main.py --web # 等价入口
- 同一套前端:
frontend/index.html一行不改 —— 桥接 shimfrontend/bridge-web.js在服务时注入,把pywebview.api换成POST /api/,把引擎事件用 SSE(GET /api/events)送到页面。 - 引擎零改动:
agent.py/llm.py/tools/*/sandbox.py/session.py全部原样复用;新增的只有web_ui.py(队列推送)、web_profile.py(白名单与门面)、web_server.py(HTTP/SSE)。 - 只读白名单:
web_profile.PUBLIC_TOOLS显式列举(frozenset),不用Tool.read_only过滤 —— 那个标志的语义是"执行前不需要确认",不是"读不到敏感数据"(read_file/grep都是read_only=True,而工作区里就有含内置 Key 的config.local.json)。 - 多访客隔离:每个浏览器一个 cookie 身份,各自的会话、Agent、事件队列与留档目录(
web-sessions//),互相看不到对方的对话。 - 滥用控制:每访客 12 次/分钟、全局同时 3 个回合(超了回"前面还有 N 位同学")、每日 2000 次上限;发问与来源 IP 记在
web-usage.log。 - 跨站防护:校验
Origin/Referer与Host同源 —— 否则你浏览器里任意网站都能朝这台服务器发请求。 - 部署注意:服务必须跑在能访问校园内网模型端点的机器上(公网云主机连不通
10.x);监听非本机地址时,同网段任何人都能用本服务并消耗学校模型额度。只读白名单下没有 shell,但请勿把非只读版本开到公网。
更完整的设计与安全取舍见 D:\game\agent网页版-实施方案.md;开发时看效果可用 py -3.12 _tmp_dev_check/serve_web_e2e.py --port 8481(带一个本地假模型,不连校园网)。
技能(SKILL.md)
把技能放进程序目录的 skills/(每个技能一个文件夹,内含 SKILL.md):
---
name: git-commit
description: 生成符合规范的 git 提交信息
---
(给模型的指导正文……)
系统提示词会列出可用技能,模型接到相关任务时自动用 use_skill 读取全文后再行动。CLI 用 /skills 查看已装技能。
「⭐ 技能」面板(浏览 / 渠道 / 添加)里,真用过的技能卡片会显示「用过 N 次 · 最近日期」(v0.9.69;成功调用才记、不去重)—— 哪几个技能真在被用,一眼可见;没用过的保持安静。依赖声明与真核对(v0.9.98):SKILL.md 的 frontmatter 可以声明 tools:(依赖的内置工具)与 libs:(依赖的 Python 库,如 libs: pptx, pypdf)——声明了才会核对:use_skill 读取时真查一遍,缺了就把「缺什么、别硬跑」摆在技能正文之前,而不是等模型把模板抄进脚本跑到一半才报错;CLI /skills 每行也带「缺库/缺工具」标记。没声明的技能不查也不警告——声明是承诺,程序不猜。
校园场景里最常用的是这四份带边界的内容技能(v0.9.31):paper-writing(选题收窄、提纲、GB/T 7714 顺序编码制渲染、降重自查——不代写正文、缺的文献字段一律标【待补】不替他编)、question-bank(只整理他自己给的那份题 → Anki TSV / GIFT / Aiken,不去抓别人的真题,导之前先跑一遍校验挡"答案错位")、lecture-notes(课件 → 带页码锚点的结构化笔记,扫描版 PDF 直说抽不到文字,不靠页码脑补一章)、resume(一份简历只投一类岗位,技术岗/非技术岗两套改法,只重排与换重点、不加经历)。
沙箱
Agent 能碰到什么,由四层边界决定:
| 边界 | 行为 |
|---|---|
敏感路径(~/.yinluxs、~/.ssh、~/.aws、~/.gnupg …) |
永远拒绝,任何权限模式、任何用户授权都不能越过 |
| 工作区内路径 | 直接放行 |
| 工作区外路径 | 默认逐次确认;用户放行后本回合内有效;allow_outside_workspace: true 则直接放行 |
| 脚本内容(v0.9.39 起) | py_script / bash python x.py 要跑的文件先按行扫一遍(只扫前 200KB),把命中的那几行原文 + 行号摆进确认框,分「碰密钥位置 / 走出工作区 / 要联网或再起子进程」三类 |
命令侧:灾难命令照旧硬拒绝(rm -rf /、format c:、fork 炸弹…);沙箱还支持
allow_network: false 禁掉 curl/wget/ssh 等联网命令、deny_patterns 加自定义正则
(如 git push)、timeout_seconds 收紧命令执行超时上限。
子进程这边另有一层:环境变量里名字像凭据的(*_API_KEY、TOKEN、SECRET …)默认摘掉,
摘了哪几个会在输出末尾告诉你;不想摘就设 sandbox.strip_env_secrets: false。
Windows 还可打开 sandbox.app_container: true: bash / py_script 会改用
AppContainer token,工作区可写、Python 运行时只读、allow_network 决定是否注入
internetClient capability。它是实验性的 OS 执行层,首次准备运行时 ACL 会慢一些;
启动失败会拒绝执行并说明原因,不会静默退回普通进程。
边界要说得出自己拦不住什么:脚本内容级扫描只负责"把可疑行摆到你面前",不给子进程做隔离;
allow_network 是按命令名 / 脚本导入扫的门禁,不是操作系统防火墙 —— 真要断网得用虚拟机级隔离。
GUI 顶栏的「🛡 沙箱开/关」可随时切换(写回 config.json);CLI 用 /sandbox [on|off] 查看或临时切换。
注意:沙箱边界优先于权限模式——accept_all 也不能让 Agent 在没有确认的情况下访问工作区外。
档位越高越信任你,不是越信任外面来的东西:要密钥的脚本、访问凭据目录的脚本、扫出外传出口的脚本,
在 full 档也一样弹确认。
沙箱判的「工作区」就是「工作区」那一节选定的文件夹:换工作区,围栏跟着换,
且切换时会清掉本回合已放行的工作区外路径(不把旧授权带到新工作区)。
工作区
Agent 在哪个文件夹里干活,由你定。
| 入口 | 说明 |
|---|---|
| GUI 顶栏「📁 工作区」 | 弹窗里选:当前 / 默认 / 最近用过;点一行即切过去 |
CLI /workspace |
无参=查看当前与最近;/workspace =切换;/workspace default=回默认 |
| CLI 启动参数 | --workspace "D:\我的资料" / -w(也可写 --workspace=...) |
- 默认工作区 = 程序目录(exe 旁 / 开发态仓库根),也就是改造前写死的那个,老用户无感。
- 只接受已存在的文件夹:不做隐式创建(免得在用户盘上凭空长出目录);
~/.yinluxs、~/.ssh、系统凭据目录这类放钥匙的地方永远不能当工作区。 - 切换的代价说清楚:旧会话运行器一律停掉(它的工具上下文与 system prompt 都是按旧工作区装的),
从新会话开始;有任务在跑时直接拒绝,不偷偷换掉正在运行的围栏。会话留档不丢,
侧栏里不属于当前工作区的历史会话会标出
📁 目录名,提醒你那些文件不在当前文件夹里。 - 记忆是全局一份(
workspaces.json,跟 exe 走):GUI 与 CLI 读到的是同一个「上次在哪干活」; 记录的文件夹被删/改名时静默回退默认工作区,绝不因为一个失效设置拦启动。 - 网页版(对外形态)不开放工作区管理:访客按 POST 调那四个方法一律被拒,前端也会把胶囊整个藏掉。
附件(文件 / 图片)
聊天框左侧 📎 打开系统文件选择框,可以多选:
- 文件先复制进工作区
uploads/(重名自动加-1/-2),消息里注入相对路径清单, 模型用read_file/bash等工具自行处理 —— PDF 这类二进制不会被硬塞进上下文; - 图片另做压缩:长边超过 1536 等比缩小,JPEG/WebP 逐级降质量到 1MB 以内, 带透明的 PNG 保持 PNG,GIF 保留动画;单文件上限 20MiB、解码后不超过 4000 万像素;
config.json里vision: true(且模型确实支持看图)时,图片会以 base64 data URL 随消息直接发给模型;否则只给路径并在消息里注明「当前模型不支持看图」。- 恢复旧会话时附件以标签复原(v0.9.69):图片带缩略图、文件显示名字与真实大小; 附件文件后来被删了的,标签变灰并写明「已不在工作区」—— 不装作还能打开, 也不补一张假的缩略图。
外接能力(OCR / 图表 / 图片生成 / 向量档)
这一节的规矩与其他能力同源:"能用什么"由探测函数自己说,缺了只报缺什么 —— 每一句能力描述都要能追到一次真的执行分支,不许按模型名猜、不许静默换成"看起来成功了"。
| 工具 | 后端 | 缺了 / 不准的时候 |
|---|---|---|
ocr_image |
system = Windows 自带的 Windows.Media.Ocr(不联网、不含模型权重,用的系统语言包,但要一组可选 winrt-* 绑定);vision = 配置里的视觉模型(能不能看图只认 model_probe 的实测缓存结论) |
没装绑定就照实说没装 + 给可照抄的安装命令;认出来的字只当待核对草稿(本机实测:f(x)→f 冈、x^2→x ^ 2、减号 −→汉字 一),每条出口都带"后端 + 告警"两行 |
render_chart |
只用标准库手写自包含 SVG(bar/line/pie,MAX_POINTS = 200) |
数据必须由调用方真给出来:少一个数就报错,不把空缺插成 0;source 印在脚注,没写就是空的;产物落 工作区/charts/,「撤销」不跟踪它 |
generate_image |
api = OpenAI 兼容 /images/generations(Key 借 providers 那份,不落 config.json);card = Pillow 把文字排成 PNG |
没配接口就只出文字卡片并写明「这是排版,不是 AI 绘图」,绝不凭描述假装出图;返回超过 12MB 拒绝落盘;产物落 工作区/images/ |
| 知识库向量档 | api(/v1/embeddings,借已有供应商的 Key)/ local(ONNX 小模型 + 自带 WordPiece,池化按模型口径选 cls/mean) |
两档都不可用时只跑关键词(BM25F),并在检索结果里写「向量档未跑:」——把字面匹配说成语义检索就是装饰 |
开语义档的两条路:①在 config.json 写
"capabilities": {"embeddings": {"backend": "api", "provider_id": "", "model": ""}};
②{"backend": "local", "model": "", "pooling": "cls"} + 把 model.onnx、vocab.txt 放进
数据目录的 models//(两个文件名必须一模一样)。源码运行也可以用
python scripts/fetch_embed_model.py --repo / 下(先写 .part 再改名;
--sha256 文件=十六进制 钉过才会报"已核对",没钉只报指纹)。
模型权重不进安装包(bge-small-zh-v1.5 那份实测 94,835,369 B),但 v0.9.123 起
onnxruntime + numpy 已经在包里,装好的便携版 / 安装版同样能跑本地档 —— 差别只剩
包里没有 scripts/,那一步要手工放文件。
向量索引落在数据目录 kb-vectors/(同样不进包),以条目正文 sha1 为键;缓存文件名带着
会改变向量数值的那几个口径(local 档:池化与截断宽度),换了口径就是一套新缓存,
不拿旧向量当真值。索引第一次要明确点一次头才建 —— 那是几百次向量调用,不顺手替使用者做。
查询侧的检索指令默认不加:2026-10-06 用那份 ONNX 在 200 条真馆藏上实测,加上
「为这个句子生成表示以用于检索相关文章:」把自召回 Top-1 从 200/200 打到 130/200,
要加就在 capabilities.embeddings.query_prefix 里显式写;这次跑的池化与带没带指令
都会印在检索口径那一行里。
capabilities 里手写的 api_key 会在 save_config 落盘前被洗掉 —— 密钥只有 credentials 那一条路。
长期记忆
跨会话记住四类事实:用户偏好(user)/反馈纠正(feedback)/项目约定(project)/ 参考资料(reference)。分两级作用域:
| 作用域 | 存放位置 | 适用 |
|---|---|---|
| 项目级(默认) | 工作区 memory/MEMORY.md |
只跟这个项目有关:技术选型、目录约定、踩过的坑 |
用户级(scope=user) |
~/.yinluxs/memory/MEMORY.md |
跨项目通用:个人偏好、沟通习惯、常用环境 |
两个文件都是一条一行、人工可直接编辑的 Markdown:
- [2026-09-13][user] 喜欢先给结论再给理由
- [2026-09-13][project] 打包前必须先关掉运行中的实例
模型通过 memory 工具增删查(save / list / search / forget),系统提示词会自动
注入两级记忆(用户级在前、项目级在后,合计约 4000 字的预算)。装不下时按条让位而不是切半句:
两级各自从最旧的那条开始退,最新的一定在,界面上会说「本次注入最近 N 条,另有 M 条没列出」,
要翻旧账就 list、按词找就 search(v0.9.121;此前是按字符硬切,既会把一条记忆切成半句,
又必定整块丢掉项目级那一批)。
整理去重(Dream action=dream) —— 对齐星瑶 Y-Code 的 /dream 思路,分两步:
- 确定性去重:同类别内按中文 2-gram 相似度聚类(整体相似 ≥0.75,或短的一条被 覆盖 ≥0.85 视为同一条),合并时保留信息最全的正文 + 较新的日期,完全重复直接丢弃;
- 模型归纳(有 LLM 时):让模型合并同义、删掉被后续条目推翻的,每条压成一句话, 输出严格 JSON;解析失败或返回空就退回第 1 步的结果,绝不把记忆整理没了。
覆盖前会把原文件备份到同目录 history/MEMORY-.md,所以整理永远可回溯。
入口:GUI 顶栏「🧠 记忆」(点击整理两级)、CLI /dream [project|user|all]、
模型在用户说「整理记忆」时自行调用 memory action=dream。
MCP 服务器
支持接入任意MCP服务器,外部工具会以
mcp__ 的名字挂进工具集,和内置工具一样被模型调用。三种传输都支持:
stdio(给 command,子进程按行收发)、http(Streamable HTTP:给 url,POST 过去,
响应可能是 JSON 也可能是 text/event-stream,Mcp-Session-Id 会自动带上)、
sse(老式 HTTP+SSE:GET 一条长流拿到 endpoint 事件后再 POST 到那条地址)。
只有网址、没有启动命令的服务器从此也能连,而且不额外依赖任何第三方库(走标准库 urllib)。
能力协商照实说(v0.9.82):握手时学长声明的 capabilities 是空的 —— 它只实现了 MCP 的 tools 这一个原语,resources / prompts / sampling / logging 都没接,所以不假装支持。对端在握手里声明了什么则原样留着并说给你听:添加服务器成功那句话会带上「对端声明: prompts、resources、tools;学长只接了 tools(prompts、resources 没实现,不会去调)」,侧栏 🔌 MCP 健康行悬停是同一句;没连上(没握过手)的服务器不编能力表,直说拿不到。mcp action=list 仍是配置层口径(它不去连服务器),活状态与能力在这两处。
本 agent 反过来也能当服务器(v0.9.144):引路学长-CLI.exe --mcp-serve(源码态 python main.py --mcp-serve)在本机起一个 stdio MCP 服务端,把校园只读能力暴露给 Claude Code / Cursor / Qoder 一类 MCP 客户端 —— library_search / library_guide / campus_calendar / gpa_calc / search_knowledge / campus_notices / get_weather 与地图五件,共 12 只,清单显式列举(绝不用 read_only 标志过滤:read_file/glob/grep 也是只读,而工作区根就有含内置 Key 的 config.local.json)。两条硬边界:① 外部来的每一步都走同一道权限门,需要人点头的一律拒绝 —— 没有人能替这台机器的主人点头,也没有 --mcp-yolo 这种例外档;② stdout 只走协议报文,人读的话全走 stderr。写盘 / 执行命令 / 读文件 / 私有数据(成绩、情绪、记忆、课表)一律不在名单里;被拒的那一次会在本机 injection-events.log 留一行(带客户端自述标签,clientInfo 只进日志、不进判定)。只做 stdio、一个进程一个客户端:不开端口、不做 http/sse、不连出站 MCP。
在 config.json 里配置(完整示例见 config.example.json):
"mcp_servers": [
{
"id": "filesystem",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "D:/data"],
"enabled": true,
"read_only": false,
"description": "文件系统"
},
{
"id": "remote-demo",
"transport": "http",
"url": "https://example.com/mcp",
"headers": { "Authorization": "${MY_MCP_TOKEN}" },
"enabled": true,
"read_only": true,
"description": "只有网址的服务器;密钥留在环境变量里,不写进 config.json"
}
]
headers 里的 ${VAR} 在发请求时才展开(MY_MCP_TOKEN 从环境变量取),配置文件中不落明文;
日志与报错里的 URL 一律剥掉 query,所以 token 不会顺着错误文案漏进对话。
transport 留空即按 command 走 stdio;url 缺失、file: 协议、不认识的 transport 会被跳过并说明。
| 字段 | 说明 | 默认 |
|---|---|---|
id |
服务器标识,用于拼工具名(会规范化成字母数字下划线) | 必填 |
transport |
stdio(按 command 起子进程)/ http / sse;写 streamable-http、http+sse 等别名也认 |
stdio |
command / args |
启动命令,支持 npx / uvx / python 等(stdio 时必填) |
空 |
url |
服务器地址(http / sse 时必填,只认 http/https) |
空 |
headers |
附加请求头(值支持 ${VAR} 展开,发请求时才代入) |
空 |
env |
追加的环境变量(值支持 %VAR% / $VAR 展开) |
空 |
enabled |
关掉可保留配置不启动 | true |
read_only |
标记为只读 → 免确认直接执行;默认需要用户确认 | false |
allow_tools |
非空时只挂列出的那几只(精确名或末尾 * 前缀);留空 = 全挂 |
空 |
deny_tools |
列出的那些一律不挂,优先级高于 allow_tools;写错一个字母会在侧栏/体检与添加回话里点名"没匹配到任何工具" |
空 |
start_timeout / call_timeout |
握手 / 调用超时(秒) | 10 / 60 |
description |
显示名与工具描述前缀 | 空 |
行为约定:
- 名单只收窄、不扩权:
allow_tools/deny_tools只能让服务器声明过的工具挂不上注册表,不能变出一只它没声明的工具;被挡掉的只数与原因写在侧栏、体检与「已添加」那句回话里,报的只数是真挂上来的那只数(不是服务器自己声明的数)。 - 连不上不崩应用:命令不存在、握手超时、协议错误都只在日志里提示并跳过该服务器;
- 进程级长连接 + 退出回收:窗口关闭 / CLI 退出时统一终止子进程,不留孤儿;
- 工具自带 JSON Schema,权限门按
read_only决定免确认还是逐个确认; - 侧栏底部的 MCP 健康行(v0.9.70):配置了的都在 —— 连上的显示
服务器名(工具数),没连上的写「未连上」,停用的写「停用」; 对话里增删后当场刷新。
预设模板库(v0.9.70,对话里说「看看有哪些 MCP 预设」):mcp 工具的
action=list_presets 摆出内置模板 —— everything(官方演示,试水用)、
sequential-thinking(分步思考)、filesystem(开放工作区之外的某个文件夹,
要给 path)、time(时间与时区)、fetch(网页转 Markdown),每条都写清
本机需要什么(npx 要 Node.js,uvx 要 uv)。加的时候 action=add 传
{"preset": "", "path": "D:/课件"}(要参数的预设才需要 path)——
命令与参数以模板为准,raw 改不动(raw 能改 command,预设就成了任意命令
执行口子);探测闸照旧真连一次,连不上不写入,并如实说本机缺什么。
配置项(config.json)
| 字段 | 说明 | 默认 |
|---|---|---|
providers |
供应商数组:{id, name, base_url, api_key, model}(保留字段:校内分发版固定用内置校园模型) |
内置校园模型 |
active_provider |
同上,不参与切换;启动时一律指向内置校园模型 | gzasc |
permission_mode |
confirm 变更逐次确认;accept_all 自动放行 |
confirm |
shell |
auto 自动选 Git Bash→cmd;可指定 bash / cmd / powershell |
auto |
max_output_chars |
工具输出回填给模型前的截断长度(超过的部分不再"凭空消失",转存进工作区 tool-outputs/ 并给出路径,见 v0.9.126) |
20000 |
capabilities.embeddings.min_sim |
向量档的病态下限:整档都够不到它就退回关键词。它不是"算不算命中"的判据(实测单一绝对阈值没有判别力:0.35 放过 98.6% 的不相关配对) | 0.45 |
capabilities.embeddings.rel_margin |
真正在做事的那道:只收与第一名相似度相差不到这么多的条目(不受问句长短影响) | 0.15 |
max_steps |
一个回合最多转几圈"请求模型→执行工具→回填";撞上限后停止调用工具,但会让模型把已经跑完的那些步骤收一段尾(那一次不带工具)。调大 = 一轮烧的 token 更多 | 40 |
request_timeout_seconds |
单次 LLM 请求超时 | 300 |
turn_time_limit_seconds |
一轮最多跑多久(秒);只在两步之间收手,不强杀在跑的那一步。0 = 不限 |
1800 |
backup_dir |
周期自动备份目录:填了路径,每周六上午自动把可打包数据(含聊天记录、不含密钥)备份成 zip 保留最近 4 份;留空 = 不备份 | 空 |
daily_token_budget |
日预算:今天全供应商累计 token 的上限,接近 80%/达到 100% 各提醒一次;0 = 不启用。与 session_token_limit 分工:那个管会话,这个管今天 | 0 |
session_token_limit |
本会话累计 token 消耗上限(v0.9.78 成本闸门);只认服务端返回的真实用量(不给 usage 的端点这道闸不起作用)。触顶与两条时限同一口径:两步之间收手,让模型交代进度,可提高上限或新开会话继续。0 = 不限 |
0 |
session_keep_last |
会话留档保留个数:启动时按时间删旧的(当前会话永不删)。0 = 全部保留(默认) —— 想开清理再写个数(如 200) | 0 |
subagent_time_limit_seconds |
单个子代理最多等多久报告(秒);超时只到"不再等",那一档仍在后台跑完。0 = 不限 |
600 |
subagent_models |
按档位分模型(v0.9.95):{"explore": "glm-4.5-air", "code": "glm-4.6"} —— 侦察用便宜的、实现用硬的。只换模型名,不换供应商(跨供应商是另一把 Key,走「模型管理」那个对话框)。名字必须写在当前供应商的启用模型里,对不上就退回主模型,并把"退了、为什么退"印在那一路的报告里(静默换个模型跑比不换更难查);留空或与主模型同名就当没配,报告不多嘴 |
{}(= 全部用主模型) |
feedback_recall |
信号回灌开关:同一个词连着搜空就在工具回话末尾点一句(监控栏那一行标「×N 未命中」)、这次的问题与最近 30 天某条 👎 属同一类就给本轮一条系统侧先验(不进留档、不当众复述)。设 false 时发给模型的消息与工具回话与开之前逐字一致 |
true |
capabilities |
外接能力的后端开关:embeddings(向量档)与 images(文生图)。这里只写 provider_id 借已有供应商的 Key,别写 api_key(save_config 落盘前会洗掉) |
{}(=只有关键词检索 + 只出本地文字卡片) |
context_window |
模型上下文窗口(token),用于压缩触发判断 | 131072 |
compact_at_ratio |
估算 token 达窗口该比例时自动压缩 | 0.7 |
mcp_servers |
MCP 服务器数组(见上一节) | [] |
vision |
当前模型是否支持看图:开启后上传的图片以 base64 随消息发送 | false |
sandbox |
沙箱策略:enabled / allow_outside_workspace / allow_network / app_container / timeout_seconds / deny_patterns |
见「沙箱」一节 |
模型固定:面向校内分发的版本只使用内置的广州应用科技学院模型 (
gzasc/deepseek-v4-flash),界面不提供切换入口。config.json里若残留其他供应商配置会被保留(不删用户数据),但不会被激活; 顶栏模型标识是纯展示,不可点选。内网地址不面向用户展示:模型管理弹窗与顶栏对内置项只显示模型名,
base_url一律留空下发(见Bridge.get_providers/get_info)。能力自动探测:上下文窗口与「是否支持视觉」由
minicode/model_probe.py在启动时问一次模型服务 —— 窗口靠发一条max_tokens超限的请求、从服务端 拒绝文本里读真实上限(请求被拒=没生成 token,几乎不花钱);视觉靠发一张 1×1 图片看是否被回「not a multimodal model」。结论落model_caps.json(缓存一周) 并发布给model_catalog,任务面板的能力标签、窗口上限,以及压缩触发阈值 都会自动跟上,学校换模型/换网关不必改代码。探测走后台线程,失败只是"这次没 测出来",不阻塞启动。内置模型的 Key 不随仓库分发(本仓库公开):放在本地未跟踪的
config.local.json的builtin_api_key字段,或用环境变量YINLUXS_BUILTIN_API_KEY临时覆盖。两者都没有时应用照常启动,只是内置模型 不可用;打包脚本会把config.local.json一并打进 exe,所以发给用户的包仍是开箱即用。{"builtin_api_key": "sk-在这里填入内网模型的 Key"}离线测试/调试可以用环境变量把当前端点临时指到别处(不写回 config.json, 普通用户无需设置),冻结版 e2e 脚本就是靠它把 exe 指到本地假 LLM:
YINLUXS_LLM_BASE_URL=http://127.0.0.1:8000/v1 YINLUXS_LLM_MODEL=fake 引路学长-CLI.exe "任务"
项目结构
minicode/
├── agent.py # Agent 主循环(回合内 模型↔工具 迭代)+ 快照回滚 + 压缩触发
├── app_setup.py # CLI/GUI 共享装配:system prompt(含技能注入)+ Agent 构建
├── llm.py # OpenAI 兼容流式调用 + 工具调用增量聚合 + 重试 + 本地代理绕行
├── skills.py # SKILL.md 技能加载 + use_skill 工具处理器
├── mcp.py # MCP 客户端:stdio / Streamable HTTP / HTTP+SSE 三种传输 + 工具发现 / 调用 / 进程回收
├── mcp_server.py # MCP 服务端(--mcp-serve):stdio,把校园只读能力接给外部 MCP 客户端
├── sandbox.py # 沙箱策略:路径分级(工作区/外部/敏感)+ 命令管控 + 超时
├── workspace.py # 工作区:选择校验(拒敏感目录)+ 最近列表持久化 + 启动回退
├── attachments.py # 附件:落盘去重 / 图片压缩 / 多模态消息构造
├── suggestions.py # 首页建议 chips:按聊天记录给校园主题打分
├── kb.py # 本地知识库:异构 JSON 加载 + 2-gram 检索 + 来源网址输出
├── compaction.py # token 估算 + 按完整轮切分的上下文压缩
├── campus.py # 校园地图:建筑索引加载 + 地名解析(四态)+ map_* 工具
├── explain.py # 权限确认框的"为什么要做这一步":命令人话解读 + 影响面提示
├── permission.py # 权限门 + 灾难命令黑名单
├── session.py # 消息历史 + JSONL 留档 + 会话恢复
├── paths.py # 源码/打包双形态路径解析
├── ui.py # 终端 UI:rich 流式 Markdown / 工具卡片 / 确认
├── gui_ui.py # GUI 适配器:引擎事件 → webview 推送,停止=中断
├── gui_bridge.py # pywebview js_api(门面对象)+ 供应商/密钥管理
├── config.py # 多供应商配置:解析/迁移/保存
└── tools/ # base(Tool 定义与路径安全)+ fs / shell / search / crawl / registry
main.py # CLI 入口与 REPL
gui_main.py # GUI 入口(pywebview 窗口)
frontend/ # 免构建单页前端(暮色玻璃风,深浅双色;img/campus_dusk.jpg 为背景图)
frontend/map.js # 校园地图面板:手绘底图 + 标注框/图钉/列表 + 标注图裁切窗与灯箱(零依赖)
frontend/vendor/ # 随包离线的第三方渲染件(全部本地引用,不连 CDN):
# marked.min.js(Markdown)、mermaid.min.js(流程图,出现 ```mermaid 才懒加载)、
# katex/(数学公式,v0.9.138 起,出现 $…$ 才懒加载)——
# KaTeX 0.16.11 取自 npm registry,katex.min.js sha256 `e6bfe5deebd4c7cc…`、
# katex.min.css sha256 `717bc9ae7853b61f…`,只带 woff2 字体(20 个),整目录 596KB
frontend/campus-index.json # 交付包索引副本(36 处建筑 + 203 条别名 + 20 条歧义 + 10 处非建筑)
frontend/img/campus/ # map.jpg(手绘底图原图) + 1280/NN.webp(36 张单栋标注图,约 3.8MB)
skills/ # 内置技能(git-commit / python-testing / code-review / school-qa)
kb/ # 本地知识库 JSON(notices / knowledge / school-gzasc,带来源网址与可信度)
packaging/gcode.spec # PyInstaller 双 exe 配置
scripts/ # 打包与端到端验证脚本 + 校园主题爬虫 + build_campus_assets.py(生成本地地图资源)
校园主题语料库
python scripts/crawl_school_topics.py --dry-run # 只看会抓哪些链接
python scripts/crawl_school_topics.py --only 奖助学金 # 只刷新一个主题
python scripts/crawl_school_topics.py # 全量刷新(24 个主题,约 8 分钟)
python scripts/crawl_school_topics.py --prune # 清理已入库、但被 exclude 关键词排除的条目(离线)
爬取结果:正文归档到 crawled/www.gzasc.edu.cn/school-qa/(文件名带主题前缀,附
index.json 清单),知识库条目写入 kb/school-gzasc.json(按 url 合并,重爬只更新
不丢旧数据)。学生问校园问题时,search_knowledge 会直接命中这些带原文链接的条目;
问细节时可加大 snippet_chars 一次取回更多原文。
栏目按"学生会问什么"划分:奖助学金 / 入党党建 / 团学推优 / 学科竞赛 / 证书与等级考试 / 考研升学 / 转专业与专业选择 / 选课与学分 / 教务考试 / 就业与考公考编 / 榜样风采 / 心理与情绪 / 学风与学习方法 / 招生专升本 / 校园活动与文体 / 宿舍与生活服务 / 社团与学生组织 / 军训与国防教育 / 校园新闻动态 / 学生故事与风采 / 学生事务办理 / 校园讲座与专题 / 视频与图文校园 / 服务大厅与办事入口。
正文不在文字里的页面也建成条目,保证链接能送到学生手上:
| 页面类型 | 抓到的文字 | 条目正文 |
|---|---|---|
| 正文全在视频播放器 | 0 字 | 标题 + 发布日期 + 观看地址: 原页链接 |
| 二维码/图文操作指引(热水充值、报修、校园服务公众号) | 0 字 | 标题 + 发布日期 + 查看地址: 原页链接 |
| 只有附件的管理办法/培养方案 | 附件名 | 标题 + 发布日期 + 附件名清单 + 原页链接 |
| 失效链接(官网把 404 也渲染成 200) | 提示文字 | 不入库(靠标题识别拦掉) |
两个便携版(轻量版 / 完整版)
打包版联网抓取有两个引擎:轻量版不带 crawl4ai,走内置抓取器(httpx + BeautifulSoup); 完整版把 crawl4ai 与浏览器内核一起打进去,能抓需要 JS 渲染的页面。运行时自动选择, 降级时会在工具输出里说明原因。
python scripts/build_exe.py # 轻量版:文件夹 + zip + 单文件版 + 安装包
python scripts/build_crawl4ai_exe.py # 完整版:文件夹 + zip + 安装包(需本机有浏览器内核)
| 轻量版 | 完整版 | |
|---|---|---|
| 产物 | 引路学长--win64.zip(便携)引路学长--setup.exe(安装包)引路学长-单文件版.exe |
引路学长--crawl4ai-win64.zip(便携)引路学长--crawl4ai-setup.exe(安装包) |
| 抓取引擎 | 内置抓取器(无浏览器) | crawl4ai(真浏览器,可渲染 JS) |
| 解压后体积 / zip | 约 110MB / 76MB | 约 660MB / 281MB |
| 浏览器内核 | 无 | ms-playwright/chromium_headless_shell-*(272MB,放在 exe 同级,不塞进 exe) |
| 适用 | 日常分发、静态站点抓取 | 需要抓 JS 页面时 |
两个安装包用不同的 AppId,可以同时装在一台电脑上互不覆盖(完整版装到
%LOCALAPPDATA%\Programs\引路学长-完整版);便携版则是把整个文件夹拷走就能用,
配置与会话都在 exe 同目录。
完整版的浏览器内核目录可以单独拷进轻量版目录(与 exe 同级),即把轻量版升级成完整版;
反过来删掉 ms-playwright/ 就会自动降级,不会报错。
验收(两版都可以用同一个脚本验,断言期望的引擎):
python scripts/e2e_frozen_crawl.py
python scripts/e2e_frozen_crawl.py --exe dist/引路学长-crawl4ai/引路学长-CLI.exe --expect-engine crawl4ai
测试
python -m pytest # 单元测试,不依赖网络
python scripts/e2e_bg_jobs.py # 后台命令端到端(真进程:杀透整棵树 / 学长退出收口 / 状态只搭请求不进留档)
python scripts/e2e_ui_v0991.py # 前端:长命令跑到一半,「此刻」那一行真写着它跑到哪了(真 Chromium 7 项,载荷出自真 GuiUI 而不是手填)
python scripts/e2e_ui_v0996.py # 前端:动手前问一句那张卡(真 Chromium 31 项,卡片上每个字都出自后端、回传的是用户点的 label 原话、没等到回答也要收卡)
python scripts/e2e_ui_v0997.py # 前端:顶栏「🧠 记忆」现在能记一条(真 Chromium 21 项,那行计数必须是桥返回的数 —— 前端自己 +1 就红)
python scripts/e2e_ui_v09101.py # 前端:本轮改动逐处回退 + 跨会话看板 + 指令层那一行(真 Chromium 36 项:回退只敲那一行的 seq、drift 与 newer 两句警告要在点头之前念出来、空清单整段不出现、看板三态计数与「没读到」都出自桥、没真动作的行一次都不敲桥)
python scripts/e2e_ui_v0993.py # 前端:并行子代理的每一步挂在「任务监控」的父行下面(真 Chromium 13 项,载荷出自真 GuiUI + 真 Session)
python scripts/e2e_fake_server.py # CLI 端到端冒烟(假服务器,不花 token)
python scripts/e2e_frozen.py # 打包后验证:CLI 全链路 + GUI 启动
python scripts/e2e_frozen_crawl.py # 打包后验证:联网爬取 → 自动入库 → 下次提问命中
python scripts/e2e_frozen_mcp.py # 打包后验证:MCP 服务器连上 → 调工具 → 结果回填模型
python scripts/e2e_frozen_mcp.py --exe dist/引路学长-crawl4ai/引路学长-CLI.exe
python scripts/e2e_frozen_sandbox.py # 打包后验证:工作区外访问触发确认且拒绝后不泄露内容
python scripts/e2e_web.py # 网页版:静态/shim/越权拒绝/跨站拦截/SSE 回合全链路
python scripts/e2e_map_reset.py # 前端:切会话后地图状态是否清零(B12 回归,真实浏览器)
python scripts/e2e_browser.py # 浏览器能力:真 Edge/Chrome 全链路(渲染后取正文/取数/截图/并发隔离/file 拒绝)
python scripts/e2e_browser.py --attach # 同上,但改用已开远程调试的浏览器(带登录态那条路线)
python scripts/e2e_browser_shot.py # 前端:Agent 截的图是否真的画进对话(取图/放大/后台会话不串台)
python scripts/e2e_workspace.py # 前端:工作区胶囊/弹窗/切换/恢复默认/选文件夹/移除/网页版隐藏
python scripts/e2e_frozen_library.py # 打包后验证:用包内 1.3 GB 真库查书(书名号/版次标注都能命中)
python scripts/eval_behavior.py # 行为评测:列出五类"诚实边界"用例(不连模型、不写文件)
python scripts/eval_behavior.py --live # 发版前手动跑:连真模型逐条验规矩,有红即退出码非零
打包发布
pip install -r requirements-dev.txt
python scripts/build_exe.py # 构建 dist/引路学长/ 并生成 引路学长--win64.zip
python scripts/e2e_frozen.py # 对 exe 做端到端验证
产物三件套(dist/ 下):
- 引路学长–setup.exe —— Windows 安装包(推荐分享):中文向导、 仅当前用户安装(无需管理员)、自动创建桌面/开始菜单快捷方式、带卸载器
- 引路学长-单文件版.exe —— 免安装单文件,双击直接用(启动稍慢)
- 引路学长-0.x-win64.zip —— 绿色便携 zip,解压即用
安装包内置全部三种 exe 形态对应的 GUI 版;config.json 首次启动生成在安装目录;
用户数据(config/sessions/memory)卸载时保留。
config.json 在 exe 旁自动生成;图标、system_prompt、前端页面、内置技能已打包。
路线图(下一阶段)
- [x] MCP 客户端(配置即用,连不上不阻塞启动);传输三种齐了(stdio / Streamable HTTP / HTTP+SSE,v0.9.24)
- [x] MCP 增强:对话里自助管理(list/add/remove/enable/disable,add 先真连一次探测、通过才落盘热重载)与断线自动重连(v0.9.61) - 待做:预设模板库、服务器健康看板
- [x] 长期记忆(用户偏好/项目约定,
memory/MEMORY.md) - [x] 长期记忆整理:去重 / Dream 式归并,用户级全局记忆(
~/.yinluxs/memory/) - [x] 子代理(
task工具):explore / implement / review + audit / testaudit 两档只读角色档(v0.9.81)+ 八个领域档分工(career 就业求职、study 备考复习分别于 v0.9.90/92 起),并行派发(上限 6 个,v0.9.60 起含写类型);v0.9.81 起可带step=编号与计划对上号 - [x] 计划模式:复杂任务先建计划,再按
depends_on依赖图执行(含进行中/可执行/卡住调度视图;v0.9.33 起进度还会以一张内联卡片出现在对话流里;v0.9.34 起右侧那栏把本轮真做过的子代理/产出/网页/来源/记忆列成一张表,v0.9.37 改版成「任务监控」——此刻/计划/时间线/产出与来源,入口自 v0.9.39 起在最左边的入口栏里,标着「🛰 监控」;v0.9.81 起task step=编号会把那一步标成进行中、备注记下派了哪几路与每路报告字数,但不替模型标 done) - [x] 工作区:自己选文件夹当工作台(GUI 胶囊 / CLI
/workspace/--workspace),围栏与会话跟着走 - [x] 写子代理并行(v0.9.60):每个子代理独立的带标签确认队列(「第 N 路[类型] 任务摘要」),
accept_edits/accept_all档各路直接并行跑完;并行写各路负责不同文件 - [ ] 工作区进阶:随会话自动切回它的工作区(按工作区分组的会话视图已于 v0.9.10 完成)
相关文档
CHANGELOG.md—— 各版本做了什么。由scripts/gen_changelog.py从 git log 生成, 别手改(手抄的那一份一定会和提交历史分家)。SECURITY.md—— 权限四档与沙箱四层具体拦什么、不拦什么;密钥、本机数据、 分享安装包之前该做的检查。CONTRIBUTING.md—— 改完之后要跑的四件事,以及"一件事只允许一处真相"的规矩表。HANDOFF.md—— 交接文档:当前状态、测试基线、每一轮的取舍与踩过的坑 (docs/handoff/milestones.md是它的里程碑归档)。
License
Recommended Tools
Try a different keyword or remove a filter.
Install
npx skillfish add moko-tb/yinlu-xuezhang