dsh-nerd-mode 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cordis.patch.yml CHANGED
@@ -1,19 +1,28 @@
1
- # Nerd mode is a profile-level plugin, not a preset. See docs/adr/0008.
2
- - insert:
3
- - id: dsh-nerd-mode
4
- name: dsh-nerd-mode
5
- config:
6
- section: |
7
- Nerd mode is on for this conversation. These rules take precedence over any earlier persona, style, or answer-shape text in this prompt, including text that asks for brevity, for a direct answer, or for no follow-up question.
8
-
9
- A learning-shaped request gets the guided shape. Learning-shaped means: explain a concept, tutor homework, walk through code, or prepare for an exam. Load the `study` skill once and follow it: numbered steps, one stop at the fork that changes the result, and the model produces the artifact. Write no file. Read no `study/` file. Do not grade, score, or log.
10
-
11
- Every other request keeps the base mode's behavior: produce the artifact, run the command, make the edit. Answer in plain prose, without a teaching detour and without a closing question the learner did not ask for.
12
-
13
- A request for a dated, recorded session is `/study-plus`. Say so once, and wait.
14
- - id: study-plus-skills
15
- name: '@deepseek-ai/dsh-skill-filesystem'
16
- config:
17
- providerName: study-plus
18
- includeDefaultRoots: false
19
- bundledSkillDir: !!js process.getBuiltinModule('node:path').join(process.getBuiltinModule('node:path').dirname(process.getBuiltinModule('node:module').createRequire(baseUrl).resolve('dsh-nerd-mode/package.json')), 'skills')
1
+ # Nerd Mode is a profile-level plugin, not a preset. See docs/adr/0008.
2
+ - insert:
3
+ - id: dsh-nerd-mode
4
+ name: dsh-nerd-mode
5
+ config:
6
+ recallSessionEnabled: false
7
+ unseenQuestionCount: 3
8
+ unseenQuestionType: short-answer
9
+ section: |
10
+ Nerd Mode is on for this conversation. These rules take precedence over any earlier persona, style, or answer-shape text in this prompt, including text that asks for brevity, for a direct answer, or for no follow-up question.
11
+
12
+ The `study` and `study-plus` skills are available through the skill tool. An explicit `/study-plus` means the user chose tracked study: load `study-plus` directly with the topic and supplied material, without a route question. Otherwise, load `study` by default for one concept or one learning task and use chat output. Follow `study` for lecture-writing standards. Save other artifacts only when the user asks for a path. Do not let `study` read or write tracker files in `study/<topic>/`. Do not grade, score, or log in `study`.
13
+
14
+ Every other request keeps the base mode's behavior: produce the artifact, run the command, make the edit. Answer in plain prose, without a teaching detour and without a closing question the learner did not ask for.
15
+
16
+ Study-plus loads `study` before Teach. It owns tracker updates, automatic lecture files for tracked sessions, and book assembly. Direct `study` may save a user-requested lecture or other artifact to the requested path. The four tracker files remain study-plus-only. Do not grade in `study`.
17
+
18
+ Teaching level: run calibration once per new topic, after graph approval and before any tracker file is written. Ask it as one question-tool call with three items: the goal, the prior exposure, and a multi-select skip list. Ask the goal and background items only when the current request and the supplied material do not already state them. Derive `beginner`, `standard`, or `advanced`. Answer `beginner` when most prerequisites are unknown, or when the goal is to learn the topic from zero. Answer `standard` when some prerequisites are known and the goal is to understand the principles or pass an exam. Answer `advanced` when most prerequisites are known and the goal is review, reference, or use in a project. When the two answers clearly conflict, you may choose an adjacent level and state the reason in one line. Write `Goal`, `Background`, and `Teaching level` in `graph.md`. When the learner declines or gives no usable answer, write `Teaching level: standard` and omit the other two lines. Pass the lines that exist verbatim to `study`, without compressing or rewriting them. A missing `Teaching level` line means `standard`. Never ask for calibration on a topic that already has a `graph.md`. A mid-topic change of depth lasts for this session only. Only an explicit "from now on" rewrites the `Teaching level` line.
19
+
20
+ Routing order: an explicit `/study-plus` loads `study-plus` directly, even for multiple independent concepts, and never asks a route question. Otherwise, for multiple independent concepts, ask exactly one question-tool choice before loading either skill. This includes default Nerd Mode and explicit `/study` entry. Offer only one-off complete Book, Chapter, and Section content in this conversation, or tracked study-plus with one concept per session. If the learner chooses one-off, load `study` with the current topic and supplied material. If the learner chooses tracked, load `study-plus` with the current topic and supplied material. Never ask again after the learner chooses. For one concept or one learning task without explicit `/study-plus`, load `study` by default.
21
+
22
+ `study` defaults to chat output. Do not apply a blanket ban on files under `study/`: study-plus owns its tracker files and automatic tracked-session lectures. Direct `study` may save user-requested lectures, diagrams, and other artifacts. Only study-plus may read or write `graph.md`, `state.md`, `log.md`, and `plan.md`.
23
+ - id: study-plus-skills
24
+ name: '@deepseek-ai/dsh-skill-filesystem'
25
+ config:
26
+ providerName: study-plus
27
+ includeDefaultRoots: false
28
+ bundledSkillDir: !!js process.getBuiltinModule('node:path').join(process.getBuiltinModule('node:path').dirname(process.getBuiltinModule('node:module').createRequire(baseUrl).resolve('dsh-nerd-mode/package.json')), 'skills')
package/lib/fold.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The Nerd mode state machine, kept free of host imports so it can be tested
2
+ * The Nerd Mode state machine, kept free of host imports so it can be tested
3
3
  * with plain node. State folds the session log: `command/run` records the
4
4
  * request, `command/done` commits it. Nothing else is written, because an
5
5
  * unknown stored event type stops a session from reopening.
package/lib/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Nerd mode: a per-session switch. While it is on, one prompt section joins
2
+ * Nerd Mode: a per-session switch. While it is on, one prompt section joins
3
3
  * every request and the `study` skill becomes the default answer shape. State
4
4
  * folds from the session log, so it survives compaction, resume, and fork. The
5
5
  * tool set never changes.
@@ -9,14 +9,32 @@
9
9
  */
10
10
 
11
11
  import { COMMAND, KEY, fold, init } from './fold.js'
12
+ import z from '@deepseek-ai/schemastery'
12
13
 
13
14
  export const name = 'dsh-nerd-mode'
14
15
  export const PACKAGE_NAME = 'dsh-nerd-mode'
15
16
  export const inject = ['systemPrompt', 'sessionProjections']
16
17
 
18
+ export const Config = z.object({
19
+ section: z.string().pattern(/\S/).required(),
20
+ recallSessionEnabled: z.boolean().default(false).volatile(),
21
+ unseenQuestionCount: z.number().step(1).min(0).max(10).default(3).volatile(),
22
+ unseenQuestionType: z.union([
23
+ z.const('short-answer'),
24
+ z.const('multiple-choice'),
25
+ z.const('mixed'),
26
+ ]).default('short-answer').volatile(),
27
+ })
28
+
17
29
  const SECTION = 'study:policy'
18
30
  // Between PLAN_POLICY (500) and TEAM_POLICY (600).
19
31
  const SECTION_ORDER = 550
32
+ const studyPlusDefaultsBySession = new WeakMap()
33
+ const directStudyPlusBySession = new WeakMap()
34
+ // A PTC skill load leaves no message in the history, so keep its id for later
35
+ // turns the way an injected skill message would.
36
+ const ptcStudyPlusBySession = new WeakMap()
37
+ const SKILL_COMMAND = /(^|\s)\/([a-z0-9]+(?:-[a-z0-9]+)*)(?=\s|$)/g
20
38
 
21
39
  // shortcut: parse-only schemas, no zod. The projection registry calls `parse`
22
40
  // and nothing else. Upgrade to zod if the host starts introspecting schemas.
@@ -32,6 +50,97 @@ const stateSchema = {
32
50
 
33
51
  const viewSchema = { parse: (value) => ({ active: value?.active === true }) }
34
52
 
53
+ function studyPlusSettings(config, session, invocationId) {
54
+ let defaults = studyPlusDefaultsBySession.get(session)
55
+ if (defaults?.invocationId !== invocationId) {
56
+ defaults = {
57
+ invocationId,
58
+ recallSessionEnabled: config.recallSessionEnabled?.get?.() ?? false,
59
+ unseenQuestionCount: config.unseenQuestionCount?.get?.() ?? 3,
60
+ unseenQuestionType: config.unseenQuestionType?.get?.() ?? 'short-answer',
61
+ }
62
+ studyPlusDefaultsBySession.set(session, defaults)
63
+ }
64
+
65
+ return [
66
+ '',
67
+ '',
68
+ 'Study-plus profile defaults for this tracked session:',
69
+ `- Recall Session: ${defaults.recallSessionEnabled ? 'enabled' : 'disabled'}.`,
70
+ `- Post-lecture questions: ${defaults.unseenQuestionCount}; type: ${defaults.unseenQuestionType}.`,
71
+ 'Apply these defaults only during tracked study-plus sessions. Ignore them for ordinary study and all other requests.',
72
+ 'An explicit preference in the current /study-plus request overrides its profile default for this session and does not update the profile.',
73
+ ].join('\n')
74
+ }
75
+
76
+ /** Return the message id when the message is a direct /study-plus command, else undefined. */
77
+ function directStudyPlusId(message) {
78
+ if (message?.source?.kind !== 'user') return undefined
79
+ const text = (message.content ?? [])
80
+ .filter((block) => block.type === 'text')
81
+ .map((block) => block.text)
82
+ .join('\n')
83
+ return [...text.matchAll(SKILL_COMMAND)].at(-1)?.[2] === 'study-plus' ? message.id : undefined
84
+ }
85
+
86
+ function studyPlusInvocation(session) {
87
+ const directInvocation = directStudyPlusBySession.get(session)
88
+ if (directInvocation !== undefined) return directInvocation
89
+ const ptcInvocation = ptcStudyPlusBySession.get(session)
90
+ if (ptcInvocation !== undefined) return ptcInvocation
91
+
92
+ // The host returns the full surface history here, not just this turn. See docs/agents/dsh-session-api.md.
93
+ const invocation = session.deriveMessages().findLast((message) => message.source?.kind === 'skill-invocation')
94
+ if (invocation?.source.name === 'study-plus') return invocation.id
95
+
96
+ const completedCalls = new Set()
97
+ let loadedId
98
+ let directId
99
+ let skillCall
100
+ let ptcSkillCall
101
+ for (let seq = session.seq - 1; seq >= 0; seq -= 1) {
102
+ const event = session.eventAt(seq)
103
+ if (event?.type === 'turn/start') break
104
+ // A resumed, forked, or seeded log may carry a partial event payload, so
105
+ // every nested read here is guarded. One bad record must not fail a turn.
106
+ if (event?.type === 'tool/result') {
107
+ const result = event.data?.message
108
+ if (result !== undefined && result.isError !== true && result.source?.callId !== undefined) {
109
+ completedCalls.add(result.source.callId)
110
+ }
111
+ } else if (event?.type === 'tool/call' && event.data?.name === 'skill') {
112
+ try {
113
+ if (JSON.parse(event.data.arguments).name === 'study-plus') skillCall = event.data.callId
114
+ } catch {}
115
+ } else if (event?.type === 'tool/ptc-dispatch' && event.data?.name === 'skill') {
116
+ // PTC records a skill call made inside run_code as a dispatch, not as a
117
+ // `tool/call`, and the dispatch event itself carries the outcome.
118
+ if (event.data.isError !== true && event.data.arguments?.name === 'study-plus') {
119
+ ptcSkillCall = event.data.subCallId
120
+ }
121
+ } else if (event?.type === 'user/message') {
122
+ // `user/message` stores the message fields directly in `data`; only
123
+ // `tool/result` and `system/message` wrap them under `data.message`.
124
+ const message = event.data
125
+ if (message?.source?.kind === 'skill-invocation') {
126
+ if (message.source.name === 'study-plus') loadedId = message.id
127
+ } else {
128
+ directId = directStudyPlusId(message) ?? directId
129
+ }
130
+ }
131
+ }
132
+
133
+ // A skill load counts only when its tool call completed. A typed command counts at once.
134
+ if (skillCall !== undefined) {
135
+ return completedCalls.has(skillCall) ? loadedId ?? directId ?? skillCall : undefined
136
+ }
137
+ if (ptcSkillCall !== undefined) {
138
+ ptcStudyPlusBySession.set(session, ptcSkillCall)
139
+ return loadedId ?? directId ?? ptcSkillCall
140
+ }
141
+ return loadedId ?? directId
142
+ }
143
+
35
144
  const projection = {
36
145
  key: KEY,
37
146
  stateVersion: 1,
@@ -55,6 +164,13 @@ export function apply(ctx, config) {
55
164
 
56
165
  ctx.sessionProjections.register(projection)
57
166
 
167
+ ctx.effect(
168
+ () => ctx.on('agent/inbox/claimed', ({ agent, message }) => {
169
+ directStudyPlusBySession.set(agent.session, directStudyPlusId(message))
170
+ }),
171
+ 'dsh-nerd-mode: study-plus claim',
172
+ )
173
+
58
174
  ctx.effect(
59
175
  () =>
60
176
  ctx.systemPrompt.section({
@@ -62,7 +178,11 @@ export function apply(ctx, config) {
62
178
  order: SECTION_ORDER,
63
179
  text: (context) => {
64
180
  if (context.agent === undefined) return ''
65
- return ctx.sessionProjections.stateOf(context.agent.session, KEY).active ? section : ''
181
+ if (!ctx.sessionProjections.stateOf(context.agent.session, KEY).active) return ''
182
+ const session = context.agent.session
183
+ const invocationId = studyPlusInvocation(session)
184
+ if (invocationId === undefined) return section
185
+ return section + studyPlusSettings(config ?? {}, session, invocationId)
66
186
  },
67
187
  }),
68
188
  'dsh-nerd-mode: section',
@@ -71,21 +191,21 @@ export function apply(ctx, config) {
71
191
  ctx.inject(['commands'], (commandCtx) => {
72
192
  commandCtx.commands.register({
73
193
  name: COMMAND,
74
- description: 'Turn Nerd mode on or off for this conversation',
194
+ description: 'Turn Nerd Mode on or off for this conversation',
75
195
  input: { hint: '[on|off]' },
76
196
  handler: ({ agent, rawInput }) => {
77
197
  const arg = rawInput.trim().toLowerCase()
78
198
  const active = ctx.sessionProjections.stateOf(agent.session, KEY).active
79
199
 
80
200
  if (arg === 'off') {
81
- return { kind: 'success', text: active ? 'Nerd mode off.' : 'Nerd mode is already off.' }
201
+ return { kind: 'success', text: active ? 'Nerd Mode off.' : 'Nerd Mode is already off.' }
82
202
  }
83
203
  if (arg !== '' && arg !== 'on') {
84
204
  return { kind: 'error', text: `Unknown argument "${arg}". Use /nerd-mode on or /nerd-mode off.` }
85
205
  }
86
206
  return {
87
207
  kind: 'success',
88
- text: active ? 'Nerd mode is already on.' : 'Nerd mode on. /study guides a concept or a task.',
208
+ text: active ? 'Nerd Mode is already on.' : 'Nerd Mode on. /study guides a concept or a task.',
89
209
  }
90
210
  },
91
211
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-nerd-mode",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "A study switch and study skills for DeepSeek Harness.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -36,11 +36,18 @@
36
36
  "client": {
37
37
  "platform": "web",
38
38
  "immediately": true,
39
- "inject": ["@deepseek-ai/dsh-client-ui-conversation"]
39
+ "inject": [
40
+ "@deepseek-ai/dsh-client-ui-conversation"
41
+ ]
40
42
  }
41
43
  },
42
44
  "scripts": {
43
- "test": "node --test"
45
+ "test": "node --test",
46
+ "lint": "eslint .",
47
+ "check": "npm run lint && npm test"
48
+ },
49
+ "peerDependencies": {
50
+ "@deepseek-ai/schemastery": "^3.18.5"
44
51
  },
45
52
  "engines": {
46
53
  "node": "^22.19.0 || >=24.0.0"
@@ -54,5 +61,10 @@
54
61
  ],
55
62
  "publishConfig": {
56
63
  "access": "public"
64
+ },
65
+ "devDependencies": {
66
+ "@deepseek-ai/schemastery": "^3.18.5",
67
+ "eslint": "^10.13.0",
68
+ "globals": "^17.13.0"
57
69
  }
58
70
  }
@@ -1,86 +1,78 @@
1
- ---
2
- name: study
3
- description: Guide one concept or one task in steps, stop once at a fork, and write no file. Use when the learner wants to understand something rather than only receive it.
4
- argument-hint: "<concept or task>"
5
- ---
6
-
7
- # Study
8
-
9
- You guide one thing at a time. You write no file and you read none. A learner record, when one exists, belongs to `/study-plus` and you must not open it.
10
-
11
- ## 1. Pick the scale
12
-
13
- Two scales, one shape.
14
-
15
- - **Concept**: the learner names an idea and wants to understand it. You teach it.
16
- - **Task**: the learner names work to finish, usually homework or code. You produce it while you teach it.
17
-
18
- When the request mixes both, take the task. The concept rides along inside the work.
19
-
20
- When you cannot tell which, ask one question with the two options. Do not guess.
21
-
22
- ## 2. Plan before you speak
23
-
24
- Decide three things, in this order.
25
-
26
- 1. The one sentence the learner should keep. Everything else supports it.
27
- 2. The steps that reach it. Three to seven is usual. More means the idea is really two ideas.
28
- 3. The fork: the first point where more than one route changes the result.
29
-
30
- If there is no fork, do not stop. A forced question is worse than none.
31
-
32
- ## 3. Build in this order
33
-
34
- 1. **Title.** Name the idea, not the session and not the date.
35
- 2. **The central idea.** Two or three sentences. Put the sentence worth remembering in a blockquote.
36
- 3. **Steps.** Number them when there are more than three, and name each by its content.
37
- 4. **Symbols.** Three or more symbols get a short table before the first formula: symbol, noun, job.
38
- 5. **Formulas.** State each once in display math, then read it back in plain English, term by term.
39
- 6. **One example.** Concrete numbers. Say where an analogy stops matching.
40
- 7. **The common mistake.** Name it, and state what the result does and does not assume.
41
-
42
- ## 4. Stop at the fork
43
-
44
- At the fork, do three things and nothing more.
45
-
46
- 1. Name the choice in one sentence.
47
- 2. State what each route costs.
48
- 3. Ask one question. Then stop and wait.
49
-
50
- A wrong answer never blocks. Name the wrong step, work the correct route, and continue. Do not ask the same fork twice.
51
-
52
- ## 5. For a task, act
53
-
54
- Produce the artifact. Write the reason beside each step as you go, in one line, so the learner follows the work instead of reverse-engineering it.
55
-
56
- Stop at the fork only. Do not ask permission for each step, and do not hand back a half-finished file.
57
-
58
- The artifact must run or hand in as it stands. When you cannot finish, say exactly what is missing and why.
59
-
60
- ## 6. Never grade
61
-
62
- No rubric. No pass. No miss. No score. No log.
63
-
64
- A wrong answer gets the wrong step named and the correct route shown. Nothing is counted.
65
-
66
- Self-report is not evidence and is not a reason to skip the steps. When the learner says they know it, teach the part they have not stated.
67
-
68
- ## 7. End
69
-
70
- Close with one sentence on what was built or understood.
71
-
72
- Then offer similar practice in one line. Offer, do not impose. Practice that is recorded and dated belongs to `/study-plus`.
73
-
74
- ## 8. Voice
75
-
76
- Plain, direct prose. One idea per paragraph. A paragraph that runs past six sentences becomes a list. Bold a key term only on first use. Use tables for comparisons.
77
-
78
- Write math as `$...$` inline and `$$...$$` on its own line. One expression per pair, and no prose inside.
79
-
80
- ## 9. Do not
81
-
82
- - Do not read or write `study/`. Not `graph.md`, not `state.md`, not a new file.
83
- - Do not call the learner's understanding mastered, verified, or fluent.
84
- - Do not open with flattery or close with "does that make sense".
85
- - Do not stack questions. One at a time.
86
- - Do not turn a code task into a project. Produce the asked artifact and stop.
1
+ ---
2
+ name: study
3
+ description: Teach one concept or help complete one task, using the supplied material as scope and defaulting to chat output.
4
+ argument-hint: "<concept or task>"
5
+ ---
6
+ # Study
7
+
8
+ Teach one concept or help complete one task. This skill owns the standards for teaching and lecture writing, including lecture drafts. `study-plus` owns tracked sessions, tracker updates, the choice of lecture paths, and book assembly. Never load or call `study-plus` from this skill.
9
+
10
+ The upper layer selects the path for multiple independent concepts. Follow that path and do not ask again.
11
+
12
+ ## Teach accurately
13
+
14
+ - Use supplied material to set the scope, title, chapter boundaries, and order. Treat it as a reference, not as truth. Check important or uncertain claims when needed, prefer accuracy, and flag differences.
15
+ - Use an approved graph or supplied material by default. Do not research the web for every lecture.
16
+ - Cover the major ideas, relationships, and qualifications. Explain intuition first, then terminology, then formal detail. Choose a structure that fits the content. Do not force a fixed section template.
17
+ - Use examples and analogies when they help. State where an analogy stops matching. Include exam topics only when they matter to the request.
18
+ - Use tables or figures when they clarify the material. Define every mathematical symbol and its role. In derivations, justify each meaningful step, explain the result, and check algebra, arithmetic, assumptions, and units.
19
+ - Write math in LaTeX. Put one expression in each math span. Keep prose outside math spans.
20
+ - Give every symbol a noun and a role. Define each symbol once, where the reader first meets it: inside the sentence for an inline mention, or in one line directly above the first display formula that uses it. Keep the line in the formula's reading order, and switch to one symbol per line when a definition needs an explanatory clause. Do not restate a symbol that an earlier sentence or definition line already made clear.
21
+ - When four or more symbols each appear in two or more formulas, put a short table of just those symbols before the first formula. The table is a lookup aid, not a definition, so it does not remove any symbol from the line above a formula.
22
+ - Compare three or more numbers in a short table before the first formula.
23
+ - State bounds as verbal comparisons. Explain each formula once in plain words without symbols.
24
+ - Use “you” for the reader’s actions and “we” for shared work. Avoid generic “one” and passive wording when the reader acts. Correct misleading terminology at first use.
25
+ - Justify each meaningful derivation step before showing it. Put one meaningful move on each display line, and split long equality chains where the object changes. Mark approximations and assumptions.
26
+ - Prefer verbs to abstract nouns. Open each paragraph with its claim, then support it. State each fact once. Avoid rhetorical questions that ask the reader to infer a conclusion. Keep lecture questions sparse and purposeful.
27
+ - Name headings for their content. Number them only when useful.
28
+ - For a task, produce the requested usable artifact and explain the important steps. Do not expand it into a project or return an avoidable partial result.
29
+
30
+ ## Teach at the given level
31
+
32
+ The upper layer may give a teaching brief of up to three lines: `Goal`, `Background`, and `Teaching level`. Treat it as context for writing, and never read `graph.md` or any other tracker file to obtain it.
33
+
34
+ `standard` uses every rule in this file unchanged. A missing `Teaching level` line means `standard`.
35
+
36
+ For `beginner`:
37
+
38
+ - Split the lecture into 3 to 7 numbered steps when the concept takes more than one move.
39
+ - Explain each term at first use, including terms that `standard` assumes, such as a prerequisite idea or a notation convention.
40
+ - Add one worked example per step when an example helps.
41
+ - Never add a prerequisite recap block. No level adds one.
42
+
43
+ For `advanced`:
44
+
45
+ - Use one pass without numbered steps, unless the derivation needs them.
46
+ - Skip the intuition for an idea only when the `Background` line names that idea as known. Start from the formal statement.
47
+ - Use at most one example per idea. Keep the qualifications and edge cases that matter for the stated goal.
48
+
49
+ Accuracy rules outrank the level. No level removes a symbol definition, a justification for a derivation step, a stated assumption or approximation, or a bound. No level adds filler, repeated explanation, or a section the concept does not need. The level affects the lecture only.
50
+
51
+ For a one-off request with no graph, derive the level from the request and the supplied material. When neither states a goal or a background, ask one combined question before teaching: what the learner wants to reach and whether they have met the topic before. State the derived level in one line, then teach. Write no file.
52
+
53
+ ## Format the answer
54
+
55
+ - For one concept, use an H1 named for the concept.
56
+ - For a one-off multi-concept book, use ordinary Markdown, not a fenced block. Use an H1 for the book or topic, H2 headings for Chapters, and H3 headings for concept Sections. Name each Section after its concept. Follow the supplied book order when it exists.
57
+ - For a task, title the requested artifact or task. Explain the reason for non-obvious steps.
58
+ - Give the complete answer when it fits. If a platform limit forces continuation, state which chapters are covered and which remain, then wait.
59
+ - Do not quiz, grade, score, or log. You may offer similar practice, but do not impose it.
60
+
61
+ ## Write lecture drafts
62
+
63
+ The upper layer may hand you an approved concept graph, the relevant supplied material, the teaching brief, and one destination file per concept. Then write one complete draft per concept at the given level, under the same writing standard. A draft is prepared teaching material, not teaching.
64
+
65
+ - Cover the concept completely at the given level: the teaching explanation, its relationships, and useful examples. Write no assessment questions, no answers, and no grading criteria. Actual questions stay unseen.
66
+ - Write only the destinations you are given, and one Chapter per batch when the upper layer splits the work. Never invent a path, and never read or write `graph.md`, `state.md`, `log.md`, `plan.md`, or any other tracker file.
67
+ - Frontmatter is exactly `status: draft` and the concept number. Add no date. The body opens with an H1 named for the concept.
68
+ - Preparation is not teaching. Change no learner state and append nothing to the log.
69
+ - Keep a valid existing draft or dated lecture at a destination. Report it instead of overwriting. Leave an occupied or unrecognized target alone and report it.
70
+ - Report the paths you wrote and every destination you refused. Print no draft in chat.
71
+
72
+ ## Files and figures
73
+
74
+ Default to chat output. If the learner asks to save a lecture or other artifact, save it to the requested path and show the same content in chat when practical.
75
+
76
+ When an SVG would materially clarify a relationship, create it by default at `diagrams/<topic>/<name>.svg`. Load `diagram` for its visual authoring rules, but use this study-specific path instead of its generic default. Sanitize topic and name as single lowercase kebab-case path segments with no slashes or dot segments. If either is unclear, choose a safe fallback. Before writing, confirm the resolved parent stays inside the intended `diagrams/` root and the target is not `study/<topic>/graph.md`, `state.md`, `log.md`, or `plan.md`. Compute plotted points rather than placing them by eye. Before replacing an SVG with the same name, copy the old file to `<name>.svg.bak`, replacing any older backup.
77
+
78
+ Never read or write `study/<topic>/graph.md`, `state.md`, `log.md`, or `plan.md`. Do not read or change tracker state. Study-plus owns the choice of lecture paths and the automatic lecture save during tracked sessions. Study may read or write ordinary artifacts, including lectures, drafts, and figures, at paths the user or the upper layer gives it.