# StudyMate 使用说明 日常怎么用、东西放在哪、规则由谁说了算。项目介绍见 [README](../../README.md),安装与更新见 [安装说明](安装.md)。 **相关文档**:[课件内容格式](../规范/课件内容格式.md)(内容文件与题目位置的语法——阅读端的唯一输入规格)· [文件归属](../规范/文件归属.md)(每份文件干什么、归谁维护)· [目标态规格](../设计/目标态规格.md)(系统形状)· [工程约束](../规范/工程约束.md)(目录约定、规则归属、工具指针)· [工作区数据骨架](../../templates/README.md) --- ## 一、一次学习会话长什么样 ### 开场 1. 主教练开场**只调一次** `studymate_workspace_context`:它回报工作区路径、今天、各科目现状、最近学习记录与共享记忆 2. 报告你上次学到哪、这次建议学什么;要接着读就从侧边栏切到阅读端 3. 每一轮回复的最后一行都是「**下一步**:谁做什么 —— 怎么触发」;科目前的探索明确退出时只简短收尾,不再追问 ### 可选:先探索学习方向 首次试用开发分支,先看 [学习方向探索使用指南](../设计/learning-discovery-guide.md) 中的安装、启动和对话示例。 在「学习模式」对话里说「**我不知道学什么,帮我选方向**」,或主动选择探索,主教练才会开启这一步。说「我想学 Python」等明确科目,或恢复已有科目,直接走原流程。入口是学习对话中的自然语言,静态 HTML 主页不负责启动代理。 探索一次只问一个实质问题,选项不标「推荐」,可回答「不确定」或自由补充。主教练复用你本轮已说的信息和允许读取的共享记忆,通常围绕目标、感兴趣的活动、基础、时间与讲法偏好收集五项信息,五问后给阶段建议;必要的追问也计数,默认探索最多八个实质问题。你说「先给建议」时会立即停止追问,缺项标为未知。讲法偏好随时可调,不代表固定人格或能力。 - **「跳过这题」**:该项记为未知,已问的问题仍计数,继续必要问题。 - **「跳过整个探索」**:结束探索,按已有信息回到科目选择或原流程,不自动建课。 - **「今天到这/退出」**:只简短收尾,不强制报告或继续提问。只有你主动要求更深入,才会明确进入追加探索。 阶段建议通常给二至三个可组合的方向(证据只支持一个时说明原因),简述能做出的成果、对应你回答的理由、已知基础与未知项、先修和学习路径。你可直接选一个、比较、修改答案或暂不决定,不必读长报告才能继续;这份路径概览不是正式课程大纲。 探索只保留会话内状态:确认前不建科目、不写探索档案或 `MEMORY.yaml`、不改学习进度,也不做知识小测。选定方向后会明确告知「进入开课准备」,复用答案,只补目标深度、基础、项目、实验载体等必要缺项;选方向不等于同意所有项目或开始上课。开课准备仍按原来的 `frontier 空` 规则完成,保留项目/载体选择和最后的「下一步/开始吗」确认。共享记忆的更新不走确认这一步——两份记忆都由干活的人在收尾时直接追加(口径见 `record-keeping` 的「共享记忆」节)。详细规则见 [learning-discovery 协议](../../preset/skills/learning-discovery/SKILL.md)。 ### 开一门新课 4. 主教练亲自盘问(这是硬流程,不是客套),必问五项:**学它的目的**(追问到具体,写进 `MISSION.md`)、**想学到什么程度**、**前置知识基础**(这门课要用的数学/编程/工具,按"能独立用 / 学过但忘了 / 没学过"三档问,写进 `MISSION.md` 的 `## Constraints` 与共享记忆)、**配套项目**(给你 3 个以上候选让你挑)、**实验用什么载体**(先随派工 prompt 交给 `practice-evaluator`,写盘时机见 `record-keeping` 的「科目文件夹」——首个实操/实验节点才建 `lab/`)。记忆里已经有的信息不会再问你 5. 盘问完成后,主教练主动询问是否有准备好的本地教材或讲义路径(留空则全网检索);要转换工具时先问过你、装好,再派 `resource-scout` 收集资料——本地教材转成 Markdown 进 `reference/`(学生能在科目页点开),它收集到的在线来源转成 Markdown 进 `sources/`(只给写课对齐用);随后派课程设计角色产出大纲(知识点 DAG + 每节点的课型 `kind` + `objective`),其中会插入 3~5 个 `kind: 实验` 的验收课 6. 建科目文件夹、写进度文件 —— 你在**阅读端**看到这门课的全貌(大纲路线图、资源清单、术语表与学习记录;`sources/` 的在线来源原文只在写课时被读);报告第一课安排,问「开始吗」,确认后开始首课 ### 学一个知识点 7. 节点状态置为「学习中」,然后按课型产材料(见 §三):讲解角色先写**内容**(正文里带题目位置锚点),出题角色再按锚点交题(不出题的锚点交回一行 `empty_reason`,总控调 `studymate_apply_empty_reasons` 打进内容文件),出题角色把题库写成 `deliver/lessons/<序号>-<节点id>.quiz.json`,总控过交接门禁后**原样搬入**科目目录 8. 搬入后跑一次**内容层校验**(`studymate_validate_lesson`,见 §五),阻断项按归属打回对应角色修,非阻断提醒不拦 9. 通过后总控告诉你从侧边栏切到阅读端读这一课(**页面由阅读端实时渲染,没有页面文件**) ### 学完与评估 10. 只在**评估点**派评估角色:① `kind: 实验` 的课 ② 你自己说「考考我」。**阶段评估已删**——没有"每 3~5 个节点考一次"的节拍;不是评估点就按保守标准更新(读了 + 页内自测做了 + 实操断言全绿 → 状态最多到「学习中」) 11. 通过 → 更新进度(三档:未开始/学习中/已学完)、写学习记录;实验课通过 → 它和它 `prerequisites` 里被验收的节点一起置「已学完」 12. 部分通过 / 不通过 → 指出具体缺口、把误解记进 `misconceptions.yaml`(唯一落点)、安排补练 ### 结束 13. 把这次真正学会的东西写进学习记录(`learning-records/`)+ 把这一轮值得留的做法与事实**直接追加**进共享记忆的「积累」(`MEMORY.yaml`;换一门课还成立的那一类,只对这门课成立写科目记忆)——两份记忆都是干活的人在收尾时直写,中间没有「先给建议、等你确认」这一步(口径见 `record-keeping` 的「共享记忆」节)。`sessions/` 与 `assessments/` 已退役:不再写会话摘要与评估记录,旧文件保留可读 以上结束记录适用于已有正式科目的学习会话;科目前的方向探索没有正式 subject/node,不套用科目摘要落盘规则。 ## 二、读课件时随时提问 在**阅读端里选中看不懂的文本或代码**,右栏的问答面板就地回答——面板独立调模型(只带当前课件、选中文本与共享记忆),不经过总控,也不占用学习会话的上下文。 - 回答无痕,但会往 `misconceptions.yaml` 写**一条误解记录**(提问原文 + 回答摘要 + 位置);总控下次开场读得到,据此决定要不要补讲或补练 - 记的是"卡在哪",不是"答过什么"——它只服务教学 - 问题超出片段范围(变成"整块知识都没懂")→ 回到会话里说,那才是学习循环的事(值得单独讲的安排一次讲解) - 也可以把文本原样贴回会话:主教练就地答一小段并记一条误解记录,答完把你送回原位 ## 三、课型与材料(产出什么) `curriculum.yaml` 里每个节点都有必填的 `kind`: | `kind` | 是什么 | 产出 | |---|---|---| | `概念` | 只讲不落 lab | 课件(讲解 + 轻量练习) | | `实操` | 学一点练一点 | 课件 + 自己的小 lab | | `实验` | **里程碑验收课**:验收"学到目前的知识能做出什么" | 实验说明页(任务书)+ 验收任务 | **课型只决定产不产 lab 材料**:题的深度由节点的 `objective` 决定,不由课型定上限。 **一个知识点一节课,写成两份源文件**(都在 `lessons/` 下、同名不同后缀,`<序号>` = 节点在 `nodes:` 里的序号,一个节点一节课)——**谁写哪一件、里面是什么**见 `record-keeping` 的「课件的两份产物与作答数据」,这里不重抄。要记住的动作只有两条: - **改课件改源文件**(内容改 `.md`、题目改 `.quiz.json`);**没有页面文件要改**——阅读端下次打开就是新的。旧工作区里的 `*.html` 是退役产物,保留可读、不再生成 - **`empty_reason` 不进正文**:出题角色对无题锚点交回一行,总控调 `studymate_apply_empty_reasons` 打进内容文件(别手工开内容文件改) **`kind: 实验` 的说明页**也是内容格式正文(归属见 `record-keeping`),但它是任务书、**不出题**。阅读端里的课件页有什么: - 教材级深度(讲透前提、推导、边界、反例,不做速成课;目标是深入浅出)→ 晦涩难懂的术语先讲来历再给定义,简单的术语不过度解释 - 页内检索练习(选择题当场判分;开放题展开参考答案与判分要点,自评) - 数学公式用 TeX 写(`$…$` 行内、`$$…$$` 块级),由阅读端自带的**离线 KaTeX** 排版——不联网、不依赖 CDN - 侧边栏目录 + 上/下节课入口(阅读端按 `curriculum.yaml` 的邻居现算,不用回填) - 亮/暗主题跟随阅读端 **配图从哪来**(按"这张图要证明什么"定来源):讲解角色自己产——效果对照图、数据图表、结构示意图都归它,**具体用什么方式画由它按内容定**(不限定工具或库);真实照片/界面这类只能**采集**,由 `image-scout` 沿 `RESOURCES.md` 的链接抓网页里现成的位图。**配图规范(来源怎么定、怎么产、尺寸与写法)的唯一 owner 是讲解角色**(见 `learning-coach` 的「配图」);课件规范(`lesson-design`)只管**该配图的地方别只用文字带过**——配几张、怎么画由内容定,某节没图要能说出为什么。自己产的图与采集来的图都落 `assets/img/pool/`、都进 `pool.md`(自己产的:`来源 URL` 写「本机生成」、`许可` 写「本项目自产」),生成脚本另存 `assets/img/gen/<同名>.py` 以便复现。采集来的图只记来源与许可**备查**——个人学习用途,许可未知/未标注(填「未标注」)不影响采用,采图角色不为许可做额外核查。新科目开课时,主教练派 `image-scout` 沿 `RESOURCES.md` 的链接抓网页里**现成的**位图——清单里的链接圈出可抓的**站点**,站内允许沿同站链接下钻**最多两跳**(资料入口页 → 分类/条目页 → 具体图所在页),**每站最多访问 8 个页面、最多下载 6 张**,同站低频串行(≤1 请求/秒)、尊重 robots,不抓 PDF 与动态加载内容。抓到的先过滤:图标/头像/装饰/广告、宽度 <400px、单张 >500 KB 的一律不要;留下的按 `<主题>-<子主题>-<要点>-<来源缩写>-.` 命名(主题词必须与科目 `GLOSSARY.md` 的术语一致),落进科目图片库 `/assets/img/pool/`;每张的来源 URL(图片所在**页面**的地址)、页面标注的许可(没标注就写「未标注」)、尺寸、抓取日期写进索引 `/assets/img/pool.md`,末尾 `## Gaps` 记抓不到的。讲解角色写课件前**先读这份索引**、按主题标签检索:挑到就写 `::: figure ../assets/img/pool/<文件>`(`alt:` 必填;来源与许可由阅读端按 `pool.md` 自动补进题注);挑不到就自己产一张(内联 `::: svg` 或脚本出图都行,画法自己挑);再没有就纯文字——**图片库为空不阻塞**大纲与课件产出。 **lab(引导式实操)**:载体在开课时跟你确认,可选 notebook / 源码+测试 / 页面 / SQL / 命令行 / 练习页 / 清单。五条内核固定:分步引导 · 任务留白(亲手写)· 可验证 · 即时反馈 · 卡壳先引导不给答案。结构是 `lab/NNNN-主题/`(与课件编号同源)+ `lab/solutions/NNNN-主题/`(答案,做完再对照)+ `lab/README.md`(载体与环境、怎么跑、任务表)。 > 概念课**不该**有 lab;实操课与实验课**必须**有——这是检查的阻断项之一。 ## 四、题目:四种题型与四层 **题只有一个 owner**:`practice-evaluator`。题面、答案、判分要点、`lab/` 实操题、实验课验收任务全由它出。题放哪由讲解角色在内容文件里留**题目位置**(`::: quiz <层级> 锚点:<锚点文本>`)决定,题本身由出题角色按同一串锚点交付——**题不是抄进正文的**:渲染器按锚点从 `.quiz.json` 取题合进页面,题面与答案一个字不改。主教练不出题。 | 题型 | 长什么样 | 判分 | |---|---|---| | 客观题 | 页内点选项即时反馈 + 一句解释 | 阅读端自动判 | | 预测 + 验证 | 先写下预测,再跑起来对照 | 学生自评(对照真实输出) | | 开放题 | 页内出题,**参考答案 + 判分要点点击展开**(不贴回会话) | 学生自评 | | 交付物 | 交付物 + 可运行证据(测试/断言/期望输出) | 真实运行结果 | 数据字段的唯一出处是 `schemas/question.schema.json` 与 `lib/core/questions.ts`(题型与必备字段)。题面里的多行代码写进 ` ``` ` 围栏(起止各占一整行),页面上会渲染成带高亮、保留缩进的代码块——排错题的代码缩进是题的一部分,不进围栏就会被浏览器折叠掉。 **四层**是题的层级词汇:**读懂**(能解释为什么)→ **改对**(改一处并先预测再验证)→ **查错**(定位真实 bug 的根因)→ **造出**(从零做出能跑通的东西)。这是默认进阶路径,不是必须逐级走的台阶:项目里用过某知识点可以从高层起步,某层反复卡住可以退回来补。层级是 `::: quiz` 的**元信息**,不进页面。 **证据 > 口头确认**:判"会不会"看的是 ① 运行结果 ② 你自己写的测试 ③ 解释能力 ④ 口头确认(单独出现不足以判过)。核验时拿产物去对节点的 `objective`(这一课要做到什么),加上每道题自己的判分要点。 ## 五、质量检查 **门禁三层**([目标态规格 §10](../设计/目标态规格.md)),每一层都由工具或套件承担: | 层 | 查什么 | 什么时候跑 | |---|---|---| | **数据层** | `schemas/*.json` 校验、引用完整性、大纲 DAG 无环与位次不倒挂、实验课前置非空 | 写完大纲/进度/科目档案:`studymate_validate_curriculum` | | **内容层** | 内容格式、锚点与题库逐字对账、图片存在性、公式标记 | 搬入内容与题库后:`studymate_validate_lesson`;采图后:`studymate_validate_pool`;合盘前:`studymate_validate_handoff` | | **渲染冒烟** | 阅读端与导出的产物在真浏览器里真渲染一遍 | 门禁里跑(`npm run test:browser`),不是会话步骤 | 工具回报的是**逐条问题**(文件 + 行号 + 是否阻断)与一句放行结论,**不是退出码**:`blocking: true` 的 按归属打回(内容 → 讲解,题库与锚点 → 出题评估),非阻断提醒不拦。工具的完整清单与参数只在 [原生工具契约](../../preset/skills/learning-system/references/tools.md)(人读)与 [`lib/tools/index.ts`](../../lib/tools/index.ts)(代码)里,这里不重抄。 日常要跑的命令只有一条自检: ```bash npm test ``` ## 六、学习数据存在哪 三个区域互不混用:**引擎项目**(本目录,源码)、**用户级安装**(DSH 安装器管理 `~/.dsh/` 下的预设与配置;Codex 管理导入的插件)、**学习工作区**(你的学习数据,DSH 首次安装默认 `~/StudyMate`,无头宿主在对话中指定)。 ```text / ├── export/ # 导出产物:一份能离线打开的自包含页面(入口 index.html) └── .learning/ ├── MEMORY.yaml # 跨科目共享记忆(我是谁 / 教学偏好 / 学习习惯 / 积累;只有画像三节会进上下文) └── subjects// # 每门科目独立,互不读取 ├── subject.yaml MISSION.md RESOURCES.md GLOSSARY.md # 四份元数据 ├── MEMORY.yaml # 科目记忆:只对这门课成立的做法与事实(只有「积累」一节,不进上下文) ├── curriculum.yaml # 大纲(知识点 DAG + kind + objective) ├── progress.yaml misconceptions.yaml # 三档进度(未开始/学习中/已学完)/误解记录的唯一落点 ├── lessons/ # 一节课两份源文件:<序号>-<节点id>.md(内容)+ .quiz.json(题,逐字纯净) ├── attempts/ # 作答数据(与课件一一对应;作答绝不写回题库) ├── lab/ # 实操 + solutions/ + README.md(概念课没有) ├── reference/ sources/ assets/ # 学生自加与 agent 收的资料(阅读端可写 reference/)/在线来源原文(写课对齐用,按需建)/图片库 ├── learning-records/ # 学习记录(记"真的学会了什么";实验课验收结论也写这里) ├── assessments/ sessions/ # 已退役:不再产生新文件,旧文件保留可读 ``` 每份文件干什么、归谁维护、在哪些角色手里流转,见 [文件归属](../规范/文件归属.md)——这里是日常视角的树,那份是权威清单。 规则要点: - **跨科目只共享工作区根那份 `MEMORY.yaml`**(科目目录里那份只对本科目成立),科目文件之间不互相引用 - **没有"成品放哪"这一步**:学习数据直接写进配置好的学习工作区(暂存模式已删)。会话目录不在工作区里时,把会话工作目录设成 `` 最省事 - **两条写入路径,范围不重叠**:学习内容(大纲、课件、题库、进度、档案)**只有 agent 写**;学生自加的资料(`reference/`)与作答数据(`attempts/`)**只有阅读端写** - **学习记录**只在出现可观察证据时写(正确用出概念、主动说明已知、误解被纠正);覆盖了但没证据的不记,纯进度日志不记 - **误解只记一处**:`misconceptions.yaml`(追加日志;字段 topic/source/evidence/status/at) - **课件页不再预生成**:阅读端实时渲染;要离线副本就导出到 `export/` - 换机器:复制整个学习工作区(包括隐藏的 `.learning/`),按 [安装说明](安装.md) 重新安装,并指定复制后的工作区路径。 ## 七、谁负责什么(12 个技能) 技能的范围由「学习模式」自己定,两头都封死:技能源在 `preset/skills/`,预设用 `customSkillDirs` 显式指过去并设了 `includeDefaultRoots: false`——**学习会话**只加载 StudyMate 自己的这 12 个技能,不读 `~/.dsh/skills/` 里你装的其他技能;反过来,**别的预设的会话**也看不到它们,不管你那个会话的工作目录开在哪(它们不在宿主默认会扫的项目本地技能目录里)。 | 角色 | 职责 | |---|---| | `learning-system`(总控 / 主教练) | 调度中枢:开场、盘问、学习循环、档案维护;**唯一跟你对话的人** | | `resource-scout` | 收集资料:按科目目标找权威教材与官方文档,产出资源清单 | | `image-scout` | 采图:沿资源清单抓网页里现成的位图,按可检索规则命名落进科目图片库 `/assets/img/pool/`,并把来源与许可写进索引 `/assets/img/pool.md`;**站内可以搜索/画廊找图**(维基条目页、Commons 分类页、官方示例画廊都算),可另给"额外允许站点",站外仍不碰,每站最多 8 页/6 张 | | `curriculum-designer` | 课程设计:大纲与实验课节点、知识依赖 | | `learning-coach` | 讲解:写课件**内容**(正文 + 题目位置锚点),一次交稿;不出题、不产 lab、不渲染 | | `practice-evaluator` | 题目唯一 owner:按锚点出题、批改、证据核验;产出交总控写盘 | 六个协议(按需加载):`learning-discovery`(总控亲自执行的可选方向探索,不新增角色)、`lesson-design`(课件内核的唯一约束来源;**配图规范在 `learning-coach` 的「配图」**)、`layered-practice`(题目唯一规范)、`evidence-check`(证据核验标准)、`local-qa`(局部提问怎么答)、`record-keeping`(状态读写规则)。 **只派五类活**:收集资料(`resource-scout`)、采图(`image-scout`)、拟大纲与实验课、做课件(**串行两段**:讲解先交正文与锚点 → 出题人再按锚点交题;中间不并发——锚点是讲解的产物,渲染与过检查归总控)、出题与评估(两个时机)。答疑、盘问、使命确认、四份元数据、全部档案记录 —— 信息源在主教练上下文里,它自己干。派出去的活不过检查就带证据打回**同一个** agent 重做,不代改。 **派工只写三样**:角色规格的绝对路径(`preset/skills/<角色>/SKILL.md`,明说"先读它、照它执行")+ **值**(按 [文件归属](../规范/文件归属.md) 的角色表给:`subject_path`、节点 id、载体、点名条目、盘问结果摘要…)+ **三条边界**一句(派工边界按角色规格:默认不派子 agent/不用 `ask_user_question`/不建环境)。要它加载哪些协议、交付与返回格式、怎么写盘、角色的做法与判据,都在角色 SKILL.md 里——**派工 prompt 不复述**(角色规格是权威,主教练只给值)。 ## 八、常见问题
为什么学习时老是弹「授权写入工作区外的目录」? 以前会:工作区不在会话启动目录里(比如你在某个代码仓里开会话,而工作区在 `~/StudyMate`),每写一步都要授权一次。现在不会了——**学习数据由插件 Host 半直接写进配置好的工作区**(暂存模式已删),agent 沙箱的可写集不再是前提。想彻底零弹窗:把会话工作目录设成 `` 重开会话。顺带一条容易踩的坑:**不要拿 `/tmp` 当学习数据的中转站**——bash 看到的 `/tmp` 每次调用都是新的空的,而文件工具写的是另一个 `/tmp`,两边互不可见。
课件里的题是怎么放进去的?<!-- 题目位置:… --> 标记还有吗? 题放哪由内容文件里的 `::: quiz <层级> 锚点:<锚点文本>` 决定:出题角色按同一串锚点交题(写成 `lessons/<序号>-<节点id>.quiz.json`),阅读端按锚点把题合进页面。锚点文本与指令名都不进页面。某个锚点这轮不出题,就在它的 `:::` quiz 块里写一行 `empty_reason: <理由>`(它进 `.md`、不进 `quiz.json`;锚点有题却写理由同样报错)。老课件里那种 `` 注释是手写时代的遗留,校验仍把残留当阻断项拦下,只为照看已交付的那几份手写课件。
大纲里插了/删了节点,位次和指针为什么会错? 课件文件名里的序号与上/下节课指针都按「节点在 `nodes:` 里的序号」定。阅读端在渲染时按大纲的**当前邻居**现算指针,不预写;大纲一改就调 `studymate_renumber_lessons` 重排文件序号(先 `dryRun` 看清单)。另外"一个节点只能一节课"是当前的设计约束。
离线能用吗? 学习数据全是本地纯文本,导出的页面自包含(无网络字体、无 CDN 依赖),`file://` 打开即用。只有需要核对易变内容/查一手资料时才联网。
手改 YAML 时要注意什么? 列表项以 `&` 或 `*` 开头**必须加引号**:`["& 取地址", "* 解引用"]` —— 裸写会被当成 YAML 锚点/别名,block 与 flow 列表都会解析失败(C++ 科目踩过这个坑)。另外:写前先读、增量修改,不要整文件覆盖;任何字段都别写 `null`(没有内容就写「无」或省略可选行);改完调一次 `studymate_validate_curriculum`。