dsh-nerd-mode 0.4.6 → 0.5.2

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.
Files changed (34) hide show
  1. package/README.md +11 -6
  2. package/README.zh.md +11 -6
  3. package/assets/calibration.svg +69 -69
  4. package/assets/nerd.svg +22 -22
  5. package/assets/section.md +15 -15
  6. package/client.js +2170 -1806
  7. package/cordis.patch.yml +24 -24
  8. package/lib/index.js +838 -223
  9. package/lib/study-sessions.js +283 -0
  10. package/package.json +2 -2
  11. package/skills/convert-documents-to-markdown/SKILL.md +26 -26
  12. package/skills/diagram/SKILL.md +43 -19
  13. package/skills/diagram/scripts/check-svg.mjs +184 -0
  14. package/skills/humanizer/.claude-plugin/marketplace.json +18 -18
  15. package/skills/humanizer/.claude-plugin/plugin.json +15 -15
  16. package/skills/humanizer/.cursor-plugin/plugin.json +12 -12
  17. package/skills/humanizer/.github/ISSUE_TEMPLATE/config.yml +8 -8
  18. package/skills/humanizer/.github/ISSUE_TEMPLATE/new-pattern.yml +24 -24
  19. package/skills/humanizer/.github/ISSUE_TEMPLATE/rewrite-problem.yml +44 -44
  20. package/skills/humanizer/.github/workflows/validate.yml +29 -29
  21. package/skills/humanizer/AGENTS.md +54 -54
  22. package/skills/humanizer/CHANGELOG.md +116 -116
  23. package/skills/humanizer/LICENSE +21 -21
  24. package/skills/humanizer/README.md +206 -206
  25. package/skills/humanizer/SKILL.md +397 -397
  26. package/skills/humanizer/agents/openai.yaml +4 -4
  27. package/skills/humanizer/scripts/validate-package.py +146 -146
  28. package/skills/study/SKILL.md +81 -78
  29. package/skills/study-plus/SKILL.md +246 -246
  30. package/skills/study-plus/scripts/book-client.js +284 -284
  31. package/skills/study-plus/scripts/book-data.mjs +289 -289
  32. package/skills/study-plus/scripts/build-book.mjs +155 -155
  33. package/skills/writing-beats/SKILL.md +66 -66
  34. package/skills/writing-beats/agents/openai.yaml +5 -5
@@ -1,4 +1,4 @@
1
- interface:
2
- display_name: "Humanizer"
3
- short_description: "Make AI-written text sound like the writer"
4
- default_prompt: "Use $humanizer to rewrite this text in my voice without changing its facts."
1
+ interface:
2
+ display_name: "Humanizer"
3
+ short_description: "Make AI-written text sound like the writer"
4
+ default_prompt: "Use $humanizer to rewrite this text in my voice without changing its facts."
@@ -1,146 +1,146 @@
1
- #!/usr/bin/env python3
2
- """Check Humanizer's package files without external dependencies."""
3
-
4
- from __future__ import annotations
5
-
6
- import json
7
- import re
8
- from pathlib import Path
9
-
10
-
11
- ROOT = Path(__file__).resolve().parent.parent
12
-
13
-
14
- def read_package_file(path: Path) -> str:
15
- try:
16
- return path.read_text(encoding="utf-8")
17
- except OSError as error:
18
- raise SystemExit(f"Cannot read {path.relative_to(ROOT)}: {error}")
19
-
20
-
21
- SKILL_PATH = ROOT / "SKILL.md"
22
- SKILL = read_package_file(SKILL_PATH)
23
- README = read_package_file(ROOT / "README.md")
24
- CHANGELOG = read_package_file(ROOT / "CHANGELOG.md")
25
- try:
26
- PLUGIN = json.loads(read_package_file(ROOT / ".claude-plugin" / "plugin.json"))
27
- except json.JSONDecodeError as error:
28
- raise SystemExit(f"Fix the JSON in .claude-plugin/plugin.json: {error}")
29
- try:
30
- CURSOR_PLUGIN = json.loads(
31
- read_package_file(ROOT / ".cursor-plugin" / "plugin.json")
32
- )
33
- except json.JSONDecodeError as error:
34
- raise SystemExit(f"Fix the JSON in .cursor-plugin/plugin.json: {error}")
35
-
36
-
37
- def require_match(match: re.Match[str] | None, message: str) -> re.Match[str]:
38
- if match is None:
39
- raise SystemExit(message)
40
- return match
41
-
42
-
43
- yaml_metadata = require_match(
44
- re.match(r"\A---\n(.*?)\n---\n", SKILL, re.DOTALL),
45
- "SKILL.md must begin with YAML metadata",
46
- ).group(1)
47
-
48
- for unsupported_field in ("version:", "compatibility:", "allowed-tools:"):
49
- if re.search(rf"(?m)^{re.escape(unsupported_field)}", yaml_metadata):
50
- raise SystemExit(f"Remove unsupported YAML field: {unsupported_field[:-1]}")
51
-
52
- skill_version = require_match(
53
- re.search(r'(?m)^\s+version:\s*["\']?([0-9]+\.[0-9]+\.[0-9]+)["\']?\s*$', yaml_metadata),
54
- "Add metadata.version to SKILL.md as a three-part version",
55
- ).group(1)
56
- changelog_version = require_match(
57
- re.search(r"(?m)^## ([0-9]+\.[0-9]+\.[0-9]+)$", CHANGELOG),
58
- "Add a version heading to CHANGELOG.md",
59
- ).group(1)
60
-
61
- package_versions = {
62
- skill_version,
63
- changelog_version,
64
- str(PLUGIN.get("version", "")),
65
- str(CURSOR_PLUGIN.get("version", "")),
66
- }
67
- if len(package_versions) != 1:
68
- raise SystemExit(
69
- f"Use one package version in all files: {sorted(package_versions)}"
70
- )
71
-
72
- skill_files = {path.relative_to(ROOT) for path in ROOT.rglob("SKILL.md")}
73
- if SKILL_PATH.is_symlink() or skill_files != {Path("SKILL.md")}:
74
- raise SystemExit("Keep one regular SKILL.md at the repo root")
75
- if PLUGIN.get("skills") != ["./"]:
76
- raise SystemExit("Point the Claude plugin skill loader at the repo root")
77
- if CURSOR_PLUGIN.get("name") != "humanizer":
78
- raise SystemExit("Set the Cursor plugin name to humanizer")
79
- if "skills" in CURSOR_PLUGIN:
80
- raise SystemExit("Omit skills from the Cursor plugin so it loads the root SKILL.md")
81
-
82
- skill_description = " ".join(
83
- require_match(
84
- re.search(r"(?m)^description: \|\n((?: .*\n)+)", yaml_metadata + "\n"),
85
- "Write the SKILL.md description as an indented block",
86
- ).group(1).split()
87
- )
88
- MARKETPLACE = json.loads(read_package_file(ROOT / ".claude-plugin" / "marketplace.json"))
89
- package_descriptions = {
90
- str(PLUGIN.get("description", "")),
91
- str(CURSOR_PLUGIN.get("description", "")),
92
- *(str(plugin.get("description", "")) for plugin in MARKETPLACE.get("plugins", [])),
93
- }
94
- if len(package_descriptions) != 1 or not skill_description.startswith(
95
- next(iter(package_descriptions))
96
- ):
97
- raise SystemExit(
98
- "Use the first sentence of the SKILL.md description in every plugin manifest: "
99
- f"{sorted(package_descriptions)}"
100
- )
101
-
102
- skill_patterns = dict(
103
- (int(number), name)
104
- for number, name in re.findall(r"(?m)^### ([0-9]+)\. (.+)$", SKILL)
105
- )
106
- pattern_numbers = list(skill_patterns)
107
- pattern_count = len(pattern_numbers)
108
- if pattern_count == 0 or pattern_numbers != list(range(1, pattern_count + 1)):
109
- raise SystemExit(f"Number SKILL.md patterns from 1 upward without gaps: {pattern_numbers}")
110
-
111
- readme_patterns = dict(
112
- (int(number), name)
113
- for number, name in re.findall(r"(?m)^\| ([0-9]+) \| \*\*(.+?)\*\*", README)
114
- )
115
- if sorted(readme_patterns) != pattern_numbers:
116
- raise SystemExit(
117
- f"List patterns 1 through {pattern_count} once each in the README tables: {sorted(readme_patterns)}"
118
- )
119
- renamed = [
120
- f"{number}: {readme_patterns[number]!r} should be {name!r}"
121
- for number, name in skill_patterns.items()
122
- if readme_patterns[number] != name
123
- ]
124
- if renamed:
125
- raise SystemExit("Match the README pattern names to SKILL.md: " + "; ".join(renamed))
126
- if f"## The {pattern_count} patterns" not in README:
127
- raise SystemExit(f"Title the README pattern section 'The {pattern_count} patterns'")
128
-
129
- # A renumber can leave a section reference pointing at the wrong pattern or at
130
- # nothing. CHANGELOG.md keeps the numbers each release used, so read SKILL.md only.
131
- skill_references = sorted({int(number) for number in re.findall(r"§([0-9]+)", SKILL)})
132
- missing_patterns = [
133
- number for number in skill_references if not 1 <= number <= pattern_count
134
- ]
135
- if missing_patterns:
136
- raise SystemExit(
137
- f"Point every SKILL.md section reference at a pattern from 1 to "
138
- f"{pattern_count}: {missing_patterns}"
139
- )
140
-
141
- # Every word of SKILL.md is read on each use, so the budget is in words.
142
- skill_words = len(SKILL.split())
143
- if skill_words > 5500:
144
- raise SystemExit(f"Keep SKILL.md at 5,500 words or fewer; it has {skill_words}")
145
-
146
- print(f"Humanizer package v{skill_version} is valid")
1
+ #!/usr/bin/env python3
2
+ """Check Humanizer's package files without external dependencies."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import json
7
+ import re
8
+ from pathlib import Path
9
+
10
+
11
+ ROOT = Path(__file__).resolve().parent.parent
12
+
13
+
14
+ def read_package_file(path: Path) -> str:
15
+ try:
16
+ return path.read_text(encoding="utf-8")
17
+ except OSError as error:
18
+ raise SystemExit(f"Cannot read {path.relative_to(ROOT)}: {error}")
19
+
20
+
21
+ SKILL_PATH = ROOT / "SKILL.md"
22
+ SKILL = read_package_file(SKILL_PATH)
23
+ README = read_package_file(ROOT / "README.md")
24
+ CHANGELOG = read_package_file(ROOT / "CHANGELOG.md")
25
+ try:
26
+ PLUGIN = json.loads(read_package_file(ROOT / ".claude-plugin" / "plugin.json"))
27
+ except json.JSONDecodeError as error:
28
+ raise SystemExit(f"Fix the JSON in .claude-plugin/plugin.json: {error}")
29
+ try:
30
+ CURSOR_PLUGIN = json.loads(
31
+ read_package_file(ROOT / ".cursor-plugin" / "plugin.json")
32
+ )
33
+ except json.JSONDecodeError as error:
34
+ raise SystemExit(f"Fix the JSON in .cursor-plugin/plugin.json: {error}")
35
+
36
+
37
+ def require_match(match: re.Match[str] | None, message: str) -> re.Match[str]:
38
+ if match is None:
39
+ raise SystemExit(message)
40
+ return match
41
+
42
+
43
+ yaml_metadata = require_match(
44
+ re.match(r"\A---\n(.*?)\n---\n", SKILL, re.DOTALL),
45
+ "SKILL.md must begin with YAML metadata",
46
+ ).group(1)
47
+
48
+ for unsupported_field in ("version:", "compatibility:", "allowed-tools:"):
49
+ if re.search(rf"(?m)^{re.escape(unsupported_field)}", yaml_metadata):
50
+ raise SystemExit(f"Remove unsupported YAML field: {unsupported_field[:-1]}")
51
+
52
+ skill_version = require_match(
53
+ re.search(r'(?m)^\s+version:\s*["\']?([0-9]+\.[0-9]+\.[0-9]+)["\']?\s*$', yaml_metadata),
54
+ "Add metadata.version to SKILL.md as a three-part version",
55
+ ).group(1)
56
+ changelog_version = require_match(
57
+ re.search(r"(?m)^## ([0-9]+\.[0-9]+\.[0-9]+)$", CHANGELOG),
58
+ "Add a version heading to CHANGELOG.md",
59
+ ).group(1)
60
+
61
+ package_versions = {
62
+ skill_version,
63
+ changelog_version,
64
+ str(PLUGIN.get("version", "")),
65
+ str(CURSOR_PLUGIN.get("version", "")),
66
+ }
67
+ if len(package_versions) != 1:
68
+ raise SystemExit(
69
+ f"Use one package version in all files: {sorted(package_versions)}"
70
+ )
71
+
72
+ skill_files = {path.relative_to(ROOT) for path in ROOT.rglob("SKILL.md")}
73
+ if SKILL_PATH.is_symlink() or skill_files != {Path("SKILL.md")}:
74
+ raise SystemExit("Keep one regular SKILL.md at the repo root")
75
+ if PLUGIN.get("skills") != ["./"]:
76
+ raise SystemExit("Point the Claude plugin skill loader at the repo root")
77
+ if CURSOR_PLUGIN.get("name") != "humanizer":
78
+ raise SystemExit("Set the Cursor plugin name to humanizer")
79
+ if "skills" in CURSOR_PLUGIN:
80
+ raise SystemExit("Omit skills from the Cursor plugin so it loads the root SKILL.md")
81
+
82
+ skill_description = " ".join(
83
+ require_match(
84
+ re.search(r"(?m)^description: \|\n((?: .*\n)+)", yaml_metadata + "\n"),
85
+ "Write the SKILL.md description as an indented block",
86
+ ).group(1).split()
87
+ )
88
+ MARKETPLACE = json.loads(read_package_file(ROOT / ".claude-plugin" / "marketplace.json"))
89
+ package_descriptions = {
90
+ str(PLUGIN.get("description", "")),
91
+ str(CURSOR_PLUGIN.get("description", "")),
92
+ *(str(plugin.get("description", "")) for plugin in MARKETPLACE.get("plugins", [])),
93
+ }
94
+ if len(package_descriptions) != 1 or not skill_description.startswith(
95
+ next(iter(package_descriptions))
96
+ ):
97
+ raise SystemExit(
98
+ "Use the first sentence of the SKILL.md description in every plugin manifest: "
99
+ f"{sorted(package_descriptions)}"
100
+ )
101
+
102
+ skill_patterns = dict(
103
+ (int(number), name)
104
+ for number, name in re.findall(r"(?m)^### ([0-9]+)\. (.+)$", SKILL)
105
+ )
106
+ pattern_numbers = list(skill_patterns)
107
+ pattern_count = len(pattern_numbers)
108
+ if pattern_count == 0 or pattern_numbers != list(range(1, pattern_count + 1)):
109
+ raise SystemExit(f"Number SKILL.md patterns from 1 upward without gaps: {pattern_numbers}")
110
+
111
+ readme_patterns = dict(
112
+ (int(number), name)
113
+ for number, name in re.findall(r"(?m)^\| ([0-9]+) \| \*\*(.+?)\*\*", README)
114
+ )
115
+ if sorted(readme_patterns) != pattern_numbers:
116
+ raise SystemExit(
117
+ f"List patterns 1 through {pattern_count} once each in the README tables: {sorted(readme_patterns)}"
118
+ )
119
+ renamed = [
120
+ f"{number}: {readme_patterns[number]!r} should be {name!r}"
121
+ for number, name in skill_patterns.items()
122
+ if readme_patterns[number] != name
123
+ ]
124
+ if renamed:
125
+ raise SystemExit("Match the README pattern names to SKILL.md: " + "; ".join(renamed))
126
+ if f"## The {pattern_count} patterns" not in README:
127
+ raise SystemExit(f"Title the README pattern section 'The {pattern_count} patterns'")
128
+
129
+ # A renumber can leave a section reference pointing at the wrong pattern or at
130
+ # nothing. CHANGELOG.md keeps the numbers each release used, so read SKILL.md only.
131
+ skill_references = sorted({int(number) for number in re.findall(r"§([0-9]+)", SKILL)})
132
+ missing_patterns = [
133
+ number for number in skill_references if not 1 <= number <= pattern_count
134
+ ]
135
+ if missing_patterns:
136
+ raise SystemExit(
137
+ f"Point every SKILL.md section reference at a pattern from 1 to "
138
+ f"{pattern_count}: {missing_patterns}"
139
+ )
140
+
141
+ # Every word of SKILL.md is read on each use, so the budget is in words.
142
+ skill_words = len(SKILL.split())
143
+ if skill_words > 5500:
144
+ raise SystemExit(f"Keep SKILL.md at 5,500 words or fewer; it has {skill_words}")
145
+
146
+ print(f"Humanizer package v{skill_version} is valid")
@@ -1,78 +1,81 @@
1
- ---
2
- name: study
3
- description: "[v0.4.6] 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 brief the upper layer supplies and from the request and the supplied material. A brief from an upper layer is final: never ask again for a goal or a background it leaves out. A bare topic, or "I want to learn X", states no goal. When no brief arrives and neither the request nor the supplied material 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. When the upper layer scopes a Course, write `study/<course>/diagrams/<name>.svg`. When the guide runs alone, write `diagrams/<name>.svg` and create no folder under `study/`. Load `diagram` for its visual authoring rules, but use this study-specific path instead of its generic default. Sanitize `course` 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/<course>/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/<course>/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.
1
+ ---
2
+ name: study
3
+ description: "[v0.5.2] 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. Start from one concrete instance when the concept has one, then explain the intuition, the terminology, and the 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 a figure when the concept has a process, a flow, or a relation between parts; use a table when the reader must compare values. Put the figure next to the paragraph it explains, with one caption sentence that states the point, and do not restate the figure in prose. When no honest figure exists, stay with prose and do not invent one. 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. Number the moves when the concept takes more than one; the level may drop the numbers. Delete asides, restatements, and footnotes that only decorate. 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 and the concrete opening 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
+ - Keep the figures. A position figure or a relation figure locates the idea; it does not count as an example.
49
+
50
+ 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.
51
+
52
+ For a one-off request with no graph, derive the level from the brief the upper layer supplies and from the request and the supplied material. A brief from an upper layer is final: never ask again for a goal or a background it leaves out. A bare topic, or "I want to learn X", states no goal. When no brief arrives and neither the request nor the supplied material 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.
53
+
54
+ ## Format the answer
55
+
56
+ - For one concept, use an H1 named for the concept.
57
+ - 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.
58
+ - When the answer has chapters, open each chapter with one figure that shows its concepts and how they connect. Place it in the first section of the chapter. A single-concept answer gets no chapter figure.
59
+ - For a task, title the requested artifact or task. Explain the reason for non-obvious steps.
60
+ - Give the complete answer when it fits. If a platform limit forces continuation, state which chapters are covered and which remain, then wait.
61
+ - Do not quiz, grade, score, or log. You may offer similar practice, but do not impose it.
62
+
63
+ ## Write lecture drafts
64
+
65
+ 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.
66
+
67
+ - 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.
68
+ - In a chapter batch, the first draft of the chapter opens with the chapter figure, written under the Course's `diagrams/`; the destination list covers lectures only. Later drafts in the chapter do not repeat it.
69
+ - 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.
70
+ - Frontmatter is exactly `status: draft` and the concept number. Add no date. The body opens with an H1 named for the concept.
71
+ - Preparation is not teaching. Change no learner state and append nothing to the log.
72
+ - 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.
73
+ - Report the paths you wrote and every destination you refused. Print no draft in chat.
74
+
75
+ ## Files and figures
76
+
77
+ 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.
78
+
79
+ When the upper layer scopes a Course, write a figure to `study/<course>/diagrams/<name>.svg`. When the guide runs alone, write `diagrams/<name>.svg` and create no folder under `study/`. Load `diagram` for its visual authoring rules, but use this study-specific path instead of its generic default. Sanitize `course` 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/<course>/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.
80
+
81
+ Never read or write `study/<course>/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.