@mulmoclaude/core 0.1.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.
Files changed (122) hide show
  1. package/assets/helps/billing-clients-worklog.md +215 -0
  2. package/assets/helps/billing-invoice.md +458 -0
  3. package/assets/helps/business.md +104 -0
  4. package/assets/helps/collection-skills.md +810 -0
  5. package/assets/helps/custom-view.md +433 -0
  6. package/assets/helps/feeds.md +114 -0
  7. package/assets/helps/gemini.md +57 -0
  8. package/assets/helps/github.md +23 -0
  9. package/assets/helps/guide.md +61 -0
  10. package/assets/helps/index.md +89 -0
  11. package/assets/helps/lessons-collection.md +400 -0
  12. package/assets/helps/mulmoscript.md +249 -0
  13. package/assets/helps/portfolio-tracker.md +211 -0
  14. package/assets/helps/presentation-deck.md +828 -0
  15. package/assets/helps/presenthtml.md +89 -0
  16. package/assets/helps/sandbox.md +97 -0
  17. package/assets/helps/spreadsheet.md +43 -0
  18. package/assets/helps/storyteller.md +101 -0
  19. package/assets/helps/telegram.md +136 -0
  20. package/assets/helps/todo-collection.md +140 -0
  21. package/assets/helps/vocabulary.md +109 -0
  22. package/assets/helps/wiki.md +168 -0
  23. package/assets/skills-preset/mc-cooking-coach/SKILL.md +217 -0
  24. package/assets/skills-preset/mc-library/SKILL.md +188 -0
  25. package/assets/skills-preset/mc-manage-automations/SKILL.md +119 -0
  26. package/assets/skills-preset/mc-manage-skills/SKILL.md +141 -0
  27. package/assets/skills-preset/mc-wiki-deep-lint/SKILL.md +108 -0
  28. package/assets/skills-preset/mc-wiki-health-check/SKILL.md +61 -0
  29. package/assets/skills-preset/mc-wiki-ingest/SKILL.md +182 -0
  30. package/assets/skills-preset/mc-wiki-promote/SKILL.md +175 -0
  31. package/assets/skills-preset/mc-zenn/SKILL.md +136 -0
  32. package/dist/chunk-CKQMccvm.cjs +28 -0
  33. package/dist/collection/core/actionVisible.d.ts +34 -0
  34. package/dist/collection/core/calendarGrid.d.ts +120 -0
  35. package/dist/collection/core/deriveAll.d.ts +38 -0
  36. package/dist/collection/core/derivedFormula.d.ts +18 -0
  37. package/dist/collection/core/draft.d.ts +18 -0
  38. package/dist/collection/core/enumColors.d.ts +33 -0
  39. package/dist/collection/core/errorMessage.d.ts +4 -0
  40. package/dist/collection/core/itemLabel.d.ts +12 -0
  41. package/dist/collection/core/presentCollection.d.ts +13 -0
  42. package/dist/collection/core/promptSafety.d.ts +1 -0
  43. package/dist/collection/core/schema.d.ts +355 -0
  44. package/dist/collection/core/shortHexId.d.ts +8 -0
  45. package/dist/collection/core/sortItems.d.ts +29 -0
  46. package/dist/collection/core/uiTypes.d.ts +106 -0
  47. package/dist/collection/index.cjs +793 -0
  48. package/dist/collection/index.cjs.map +1 -0
  49. package/dist/collection/index.d.ts +14 -0
  50. package/dist/collection/index.js +740 -0
  51. package/dist/collection/index.js.map +1 -0
  52. package/dist/collection/paths.cjs +44 -0
  53. package/dist/collection/paths.cjs.map +1 -0
  54. package/dist/collection/paths.js +41 -0
  55. package/dist/collection/paths.js.map +1 -0
  56. package/dist/collection/server/atomic.d.ts +1 -0
  57. package/dist/collection/server/delete.d.ts +38 -0
  58. package/dist/collection/server/derive.d.ts +8 -0
  59. package/dist/collection/server/discoveredCollection.d.ts +18 -0
  60. package/dist/collection/server/discovery.d.ts +227 -0
  61. package/dist/collection/server/host.d.ts +77 -0
  62. package/dist/collection/server/index.cjs +1721 -0
  63. package/dist/collection/server/index.cjs.map +1 -0
  64. package/dist/collection/server/index.d.ts +11 -0
  65. package/dist/collection/server/index.js +1671 -0
  66. package/dist/collection/server/index.js.map +1 -0
  67. package/dist/collection/server/io.d.ts +114 -0
  68. package/dist/collection/server/paths.d.ts +52 -0
  69. package/dist/collection/server/spawn.d.ts +55 -0
  70. package/dist/collection/server/templatePath.d.ts +25 -0
  71. package/dist/collection/server/util.d.ts +3 -0
  72. package/dist/collection/server/validate.d.ts +19 -0
  73. package/dist/collection/server/views.d.ts +20 -0
  74. package/dist/deriveAll-C15OpM3K.cjs +399 -0
  75. package/dist/deriveAll-C15OpM3K.cjs.map +1 -0
  76. package/dist/deriveAll-C6BYnpBL.js +364 -0
  77. package/dist/deriveAll-C6BYnpBL.js.map +1 -0
  78. package/dist/file-change/index.cjs +72 -0
  79. package/dist/file-change/index.cjs.map +1 -0
  80. package/dist/file-change/index.d.ts +43 -0
  81. package/dist/file-change/index.js +66 -0
  82. package/dist/file-change/index.js.map +1 -0
  83. package/dist/notifier/engine.d.ts +72 -0
  84. package/dist/notifier/index.cjs +484 -0
  85. package/dist/notifier/index.cjs.map +1 -0
  86. package/dist/notifier/index.d.ts +3 -0
  87. package/dist/notifier/index.js +464 -0
  88. package/dist/notifier/index.js.map +1 -0
  89. package/dist/notifier/store.d.ts +18 -0
  90. package/dist/notifier/types.d.ts +118 -0
  91. package/dist/notifier/validate.d.ts +17 -0
  92. package/dist/scheduler/adapter.d.ts +48 -0
  93. package/dist/scheduler/index.cjs +352 -0
  94. package/dist/scheduler/index.cjs.map +1 -0
  95. package/dist/scheduler/index.d.ts +2 -0
  96. package/dist/scheduler/index.js +343 -0
  97. package/dist/scheduler/index.js.map +1 -0
  98. package/dist/scheduler/task-manager.d.ts +51 -0
  99. package/dist/whisper/client.cjs +241 -0
  100. package/dist/whisper/client.cjs.map +1 -0
  101. package/dist/whisper/client.d.ts +35 -0
  102. package/dist/whisper/client.js +239 -0
  103. package/dist/whisper/client.js.map +1 -0
  104. package/dist/whisper/ffmpeg.d.ts +6 -0
  105. package/dist/whisper/index.cjs +433 -0
  106. package/dist/whisper/index.cjs.map +1 -0
  107. package/dist/whisper/index.d.ts +5 -0
  108. package/dist/whisper/index.js +425 -0
  109. package/dist/whisper/index.js.map +1 -0
  110. package/dist/whisper/internal.d.ts +11 -0
  111. package/dist/whisper/models.d.ts +49 -0
  112. package/dist/whisper/sidecar.d.ts +8 -0
  113. package/dist/whisper/whisper.d.ts +28 -0
  114. package/dist/workspace-setup/assets.d.ts +10 -0
  115. package/dist/workspace-setup/index.d.ts +3 -0
  116. package/dist/workspace-setup/index.js +556 -0
  117. package/dist/workspace-setup/index.js.map +1 -0
  118. package/dist/workspace-setup/slug.d.ts +6 -0
  119. package/dist/workspace-setup/slug.js +13 -0
  120. package/dist/workspace-setup/slug.js.map +1 -0
  121. package/dist/workspace-setup/sync.d.ts +94 -0
  122. package/package.json +95 -0
@@ -0,0 +1,61 @@
1
+ # Guide & Planner Templates
2
+
3
+ Reference templates for the Guide & Planner role. Use these structures when authoring documents with `presentDocument` for any of the supported guide types.
4
+
5
+ ## Document Conventions (all types)
6
+
7
+ Every guide should:
8
+
9
+ - **Overview**: open with a summary of the key parameters (servings, days, level, budget, etc.)
10
+ - **Numbered steps OR structured sections**: use one or the other consistently across the document
11
+ - **Anchors**: add `<a id="step-1"></a>` (or `step-N`, `day-N`, `section-name`) to each major heading for `scrollToAnchor` navigation
12
+ - **Images**: embed via `![Detailed image prompt](__too_be_replaced_image_path__)` — make the alt-text prompt specific enough to generate a useful illustration on its own
13
+ - **Close**: end with tips, variations, troubleshooting, or follow-up recommendations
14
+ - **Tone**: warm and encouraging; adapt vocabulary to the user's stated experience level
15
+
16
+ ## Form-First Workflow
17
+
18
+ Always call `presentForm` before producing the document. Tailor fields to the request type:
19
+
20
+ - **Recipe**: servings, dietary restrictions, skill level, available time, equipment
21
+ - **Travel**: destination, dates, traveler count, interests, budget tier, accommodation type
22
+ - **Fitness**: goal (weight loss / strength / endurance), starting level, days per week, equipment access
23
+ - **Event**: occasion, guest count, budget, venue type, dietary needs
24
+ - **Study guide**: topic, current level, time available, learning goal
25
+ - **DIY / home project**: project type, skill level, tools available, budget
26
+
27
+ Pre-fill any field the user already provided via `defaultValue`. Mark fields the user must answer as `required: true`. Keep forms concise — ask only for what is needed to produce a great result.
28
+
29
+ ## Per-Type Document Structures
30
+
31
+ ### Recipe
32
+
33
+ overview → ingredients (scaled to the chosen servings) → equipment → prep work → numbered cooking steps (each with an image) → chef's tips → storage notes
34
+
35
+ ### Travel
36
+
37
+ overview → day-by-day itinerary (morning / afternoon / evening) → accommodation & dining → transport between stops → budget breakdown → packing tips → local culture tips
38
+
39
+ ### Fitness
40
+
41
+ overview → weekly schedule → per-workout breakdown (warm-up, main exercises with sets / reps / form notes, cool-down) → progression plan over weeks → nutrition tips
42
+
43
+ ### Event
44
+
45
+ overview → timeline & checklist (T-minus weeks) → venue & catering → guest list & invitations → décor & entertainment → budget tracker
46
+
47
+ ### Study Guide
48
+
49
+ overview → topic breakdown → key concepts per section → worked examples → practice questions → resources & references
50
+
51
+ ### DIY / Home Project
52
+
53
+ overview → required tools & materials → safety notes → numbered steps (each with an image) → finishing & cleanup → maintenance & care
54
+
55
+ ## Follow-up Pattern
56
+
57
+ After presenting the document:
58
+
59
+ - Offer to read any step aloud (scroll to it first with `scrollToAnchor`, then narrate the step)
60
+ - Invite follow-up questions
61
+ - Offer to adjust the plan based on feedback (regenerate the form, add steps, change scope)
@@ -0,0 +1,89 @@
1
+ # About MulmoClaude
2
+
3
+ MulmoClaude is a GUI front-end for Claude Code. It lets you talk to Claude Code through a chat interface with rich visual output, powered by the **GUI Chat Protocol** — a plugin layer that allows Claude to render structured results (documents, spreadsheets, mind maps, images, and more) directly in the canvas alongside the conversation.
4
+
5
+ Under the hood it uses the Claude Code Agent SDK as its LLM core. Claude has full access to your workspace files and can use built-in tools (read, write, bash, search) as well as GUI Chat Protocol plugins registered as MCP servers.
6
+
7
+ **Core philosophy**: The workspace is the database. Files are the source of truth. Claude is the intelligent interface.
8
+
9
+ ## Roles
10
+
11
+ - **General** — Everyday assistant: task management, scheduling, wiki, mind maps, and general Q&A.
12
+ - **Office** — Creates documents, spreadsheets, presentations, and MulmoScript slideshows.
13
+ - **Guide & Planner** — Collects your needs via a form, then produces a rich illustrated guide or plan. Works for recipes, travel itineraries, fitness programs, event planning, study guides, DIY projects, and more.
14
+ - **Artist** — Generates and edits images, opens a drawing canvas, and creates 3D scenes.
15
+ - **Tutor** — Assesses your knowledge level, then teaches any topic with structured documents and visuals.
16
+ - **Storyteller** — Crafts illustrated narrative stories as a MulmoScript storyboard.
17
+ - **Storyteller Plus** — Like Storyteller, with consistent character images across beats.
18
+ - **Settings** — Manages information sources, skills, and scheduled automations for the workspace.
19
+ - _(Additional roles may be defined by the user in the workspace.)_
20
+
21
+ ## Key Capabilities
22
+
23
+ - Build **collections** — schema-driven data apps (todo lists, trackers, ledgers, decks) with table / calendar / kanban / dashboard views, plus LLM-authored **custom views**; manage a calendar scheduler
24
+ - Present documents and spreadsheets with rich formatting
25
+ - Generate and edit images
26
+ - Create interactive mind maps
27
+ - Generate and edit HTML pages / 3D scenes
28
+ - Present MulmoScript multimedia stories
29
+ - Manage a personal knowledge wiki
30
+ - Switch between roles mid-conversation
31
+ - Ask clarifying questions via interactive forms
32
+ - Play browser games
33
+
34
+ ## Collections — Apps from Data
35
+
36
+ Collections are MulmoClaude's most distinctive capability: a **schema-driven data app declared in a single small JSON file**, with no database, ORM, or migration tool. You describe a data model, cross-record relations, computed fields, and per-record action buttons in a `schema.json`; the host reads that DSL and renders a full app — table, calendar, kanban board, and dashboard views — over a folder of plain `<id>.json` records. The same primitives power todo lists, recipe boxes, stock portfolios, invoice ledgers, vocabulary decks, and curricula, all without any app-specific host code. This is the core philosophy made concrete: a `schema.json` plus a folder of records **is** the app.
37
+
38
+ Because Claude authors and edits the schema for you in conversation, you build and reshape these apps just by talking — "add a priority field," "track this as a kanban," "make rent recur monthly" — and the collection updates live. We call this **vibe crafting**: the end-user counterpart of a developer's "vibe coding" — you describe the app you want and Claude builds it, with the schema validated and custom views sandboxed so you get the power without the pitfalls. Records stay validated, computed fields (totals, cross-collection lookups) recompute on every render, and completion bells / recurring obligations are declared in the same schema.
39
+
40
+ See [Collection skills](config/helps/collection-skills.md) for the full schema DSL.
41
+
42
+ ## Custom Views — Views the Built-ins Don't Cover
43
+
44
+ When the built-in table / calendar / kanban / dashboard views don't fit what you want to _see_ — a year-at-a-glance planner, a Gantt bar, a heat-map, a printable report — Claude authors a **custom view**: a single HTML file rendered in a sandboxed iframe over the collection's records. It reads (and optionally writes) records through a scoped token, stays live as the data changes, and can hand work back to a chat — all without any view-specific host code. The view is data, just like the rest of the collection, so you can ask for an entirely new way to look at your data in plain language and get it.
45
+
46
+ See [Custom views](config/helps/custom-view.md) for the authoring contract.
47
+
48
+ ## Wiki — Long-Term Memory
49
+
50
+ The wiki (`wiki/` in the workspace) acts as Claude's long-term memory. Unlike the conversation history which resets each session, the wiki is a persistent, compounding knowledge base that Claude builds and maintains over time. You feed it sources — articles, URLs, notes — and Claude ingests them into structured, interlinked Markdown pages. The more you add, the smarter it gets.
51
+
52
+ See [Wiki](config/helps/wiki.md) for details on how it works.
53
+
54
+ ## Help Pages
55
+
56
+ - [Wiki](config/helps/wiki.md) — how the personal knowledge wiki works, its folder layout, page format, and operations
57
+ - [Gemini API Key](config/helps/gemini.md) — why `GEMINI_API_KEY` is strongly recommended (images, audio, video) and how to get one from Google AI Studio
58
+ - [MulmoScript](config/helps/mulmoscript.md) — format reference for authoring multimedia stories: beats, image types, speech, audio, and a minimal example
59
+ - [Business Presentation Template](config/helps/business.md) — MulmoScript template and rules for business presentations in the Office role
60
+ - [Presentation Deck](config/helps/presentation-deck.md) — authoring business decks two ways: structured `slide` layouts (title/stats/table/timeline/…) or animated `html_tailwind` + `animation: true`, with full worked samples
61
+ - [Storyteller Template](config/helps/storyteller.md) — MulmoScript template and rules for character-driven narrated stories in the Storyteller role
62
+ - [Guide & Planner Templates](config/helps/guide.md) — document structures and form-field hints per guide type for the Guide & Planner role
63
+ - [Spreadsheet](config/helps/spreadsheet.md) — cell format, formulas, date handling, and format codes for the presentSpreadsheet plugin
64
+ - [presentHtml](config/helps/presenthtml.md) — self-contained HTML rules and the three-`../` relative-path convention used by the presentHtml plugin to keep generated files portable under `file://`
65
+ - [Sandbox](config/helps/sandbox.md) — how the Docker sandbox isolates the agent, what it can access, and how to disable it
66
+ - [Telegram Bridge](config/helps/telegram.md) — how to talk to MulmoClaude from the Telegram app: creating a bot, starting the bridge, allowlisting chat IDs, commands, and troubleshooting
67
+ - [Feeds](config/helps/feeds.md) — register a self-refreshing data feed (RSS/Atom/JSON) by authoring `feeds/<slug>/schema.json`: schema shape, the `ingest` block, raw-item field mapping, and `maxItems` retention
68
+ - [GitHub repositories in the workspace](config/helps/github.md) — clone-destination rules under `github/<name>/` and how to handle existing directories with matching or different remotes
69
+ - [Collection skills](config/helps/collection-skills.md) — build a data app (model + UI + relations + computed fields + action buttons) by authoring a `schema.json` collection skill: the DSL, field types, derived formulas, actions, records
70
+ - [Custom views](config/helps/custom-view.md) — give a collection a view the built-ins don't cover (year/quarter overview, Gantt): an HTML file under `views/`, registered in `schema.json`, rendered in a sandboxed iframe over the records
71
+ - [Todo list collection](config/helps/todo-collection.md) — the canonical recipe for building or migrating a todo / task list: full schema (status enum + `done` toggle + priority bells), `SKILL.md`, and legacy `todo-plugin` migration steps
72
+ - [Vocabulary collection](config/helps/vocabulary.md) — recipe for a language-learning word deck (any language): `proficiency` enum + `mastered` toggle + `meaning`/`example` fields, a kanban for drag-to-promote review, and bulk-add / quiz workflows
73
+ - [Lessons collection](config/helps/lessons-collection.md) — recipe for a multi-session **curriculum** (any topic): one lesson per record, a `status` kanban, a `file` link to each lesson's HTML, and per-lesson + course-level **Learn** actions run by the Tutor
74
+ - [Clients + Worklog](config/helps/billing-clients-worklog.md) — recipe for a client database and a per-client timesheet (Bundle A of the billing suite); set this up before invoicing
75
+ - [Invoicing](config/helps/billing-invoice.md) — recipe for an invoice ledger + business profile with line items, host-computed totals, and PDF / bookkeeping action buttons (Bundle B; references the clients + worklog from Bundle A)
76
+ - [Portfolio tracker](config/helps/portfolio-tracker.md) — recipe for a paired stock-quotes watchlist + holdings portfolio whose price/value are computed live from the quotes via a cross-collection derived ref
77
+
78
+ ## Workspace Layout
79
+
80
+ ```
81
+ ~/mulmoclaude/
82
+ chat/ ← session tool results (.jsonl per session)
83
+ todos/ ← todo items
84
+ calendar/ ← calendar events
85
+ contacts/ ← address book
86
+ wiki/ ← personal knowledge wiki (long-term memory)
87
+ config/helps/ ← help pages (synced from app on every start)
88
+ memory.md ← distilled facts loaded into every session
89
+ ```
@@ -0,0 +1,400 @@
1
+ # Lessons — a stateful-curriculum collection recipe
2
+
3
+ Read this whenever the user wants to **learn a topic over multiple sessions** and
4
+ have their **course tracked** — a sequence of lessons, where each lesson is taught
5
+ once, practiced, and revisited, with progress that survives across conversations.
6
+ It is the authoritative template for a lessons collection — copy it rather than
7
+ reinventing one from the generic DSL fragments in
8
+ `config/helps/collection-skills.md`. Read that file first for the general schema
9
+ rules; this one is the lessons-specific specialization. For a **flashcard / word
10
+ deck** (single-item drilling rather than a structured curriculum) use
11
+ `config/helps/vocabulary.md` instead.
12
+
13
+ The design in one line: **each lesson is one record, the `status` enum is the
14
+ single source of truth for where the learner is in the curriculum, and a kanban
15
+ board turns the whole course into a visible progress pipeline.** The lesson's
16
+ actual content lives as a self-contained HTML artifact that a `file` field links
17
+ to — so the collection is the *table of contents + progress board* over the
18
+ self-contained HTML lessons you author.
19
+
20
+ > **The `lesson` field points at a real HTML file on disk.** Each lesson's body
21
+ > is a self-contained HTML page saved under `artifacts/html/…`; the `file` field
22
+ > stores its **workspace-relative path**, and the row becomes a clickable link
23
+ > that re-opens the rendered page. The collection never stores the lesson body —
24
+ > it points at it. One concept per lesson, one HTML file per lesson, one record
25
+ > per lesson. **How and *when* that file gets written matters — see "Authoring the
26
+ > lesson HTML" and "Pre-generating lessons in the background" below: author ahead of
27
+ > time in a hidden background session so the learner never waits; `presentHtml`
28
+ > renders a single lesson to the learner but don't loop it to batch-create files.**
29
+
30
+ ## Ground it in the learner's goal first
31
+
32
+ A curriculum is only good if it serves a real goal. **Before** authoring lessons,
33
+ establish *why* the learner wants this and *where they already are* — the Tutor
34
+ role does this with `putQuestions`. Capture the answer (their goal + current
35
+ level) so later sessions can resume without re-asking: either in the SKILL.md, or
36
+ as a `singleton` companion collection (see "Extending it"). Then pitch each
37
+ lesson at the learner's **zone of proximal development** — challenging but
38
+ reachable — and prefer cited, external sources over unverified recall.
39
+
40
+ ## schema.json
41
+
42
+ Author it at `data/skills/lessons-<topic>/schema.json` — one collection per
43
+ course, so the slug carries the topic (`lessons-french-cooking`,
44
+ `lessons-linear-algebra`). The bridge mirrors it to `.claude/skills/<slug>/`; the
45
+ user opens it at `/collections/lessons-<topic>`:
46
+
47
+ ```json
48
+ {
49
+ "title": "Linear Algebra",
50
+ "icon": "school",
51
+ "dataPath": "data/lessons-linear-algebra/items",
52
+ "primaryKey": "id",
53
+ "fields": {
54
+ "id": { "type": "string", "label": "ID", "primary": true, "required": true },
55
+ "order": { "type": "number", "label": "#", "required": true },
56
+ "title": { "type": "string", "label": "Lesson", "required": true },
57
+ "status": { "type": "enum", "label": "Status", "values": ["planned", "learning", "practiced", "mastered"], "required": true },
58
+ "objective": { "type": "text", "label": "What this lesson teaches" },
59
+ "lesson": { "type": "file", "label": "Lesson" },
60
+ "resources": { "type": "markdown", "label": "Cited sources" },
61
+ "notes": { "type": "text", "label": "Where the learner is" }
62
+ },
63
+ "displayField": "title",
64
+ "kanbanField": "status",
65
+ "actions": [
66
+ { "id": "learn", "label": "Learn", "icon": "school", "kind": "chat", "role": "tutor", "template": "templates/learn.md" }
67
+ ],
68
+ "collectionActions": [
69
+ { "id": "continue", "label": "Learn", "icon": "play_arrow", "kind": "chat", "role": "tutor", "template": "templates/continue.md" }
70
+ ]
71
+ }
72
+ ```
73
+
74
+ Every key earns its place:
75
+
76
+ | Key | What it gives the user |
77
+ |---|---|
78
+ | `order` (`number`) | The curriculum sequence. Sort the table by it to read the course top-to-bottom. Cheap to renumber, unlike renaming files. |
79
+ | `title` (`string`) | The lesson name. It is the `displayField`, so it labels every table row and kanban card. |
80
+ | `status` (`enum`) | The four stages of mastery and the single source of truth for "where the learner is". Drives the kanban columns: `planned` → `learning` → `practiced` → `mastered`. |
81
+ | `objective` (`text`) | The **prompt the lesson's HTML page is generated from** (see the callout below). A paragraph covering the one concept this lesson teaches, the key points, and the takeaway — keep it to **one concept** (the cardinal rule of good lessons), but describe it *fully*. Not a one-line title. |
82
+ | `lesson` (`file`) | The clickable link to the lesson's HTML page on disk. Stores the bare workspace-relative path (`artifacts/html/lessons-<topic>/<id>.html`) — never an `/api/files/raw?...` URL. Written directly to disk when pre-authored, or set from the path `presentHtml` returns when taught live. Empty until the page exists. |
83
+ | `resources` (`markdown`) | Cited external sources for the lesson — links the learner can return to. Grounds teaching in verifiable material, not unverified recall. |
84
+ | `notes` (`text`) | Learner-specific observations: what they struggled with, what to revisit next time. The continuity that makes multi-session teaching work. |
85
+ | `kanbanField` | Pins the board to `status` (drag a card → writes `status`). |
86
+ | `displayField` | Card / table label (the lesson title, not the opaque id). |
87
+
88
+ > **`objective` is the lesson's generation prompt — write it like one.** Because
89
+ > lessons are authored just-in-time, when the page is finally written the LLM sees
90
+ > only this record: `title` + `objective` are the entire spec it generates the
91
+ > HTML from. So don't write a label — write a brief. Spell out the angle to take,
92
+ > the points that must be covered, a worked example or analogy to use, what to
93
+ > defer to other lessons, and the takeaway the learner should leave with. The
94
+ > richer the `objective`, the better the page and the less it drifts from the
95
+ > course you planned. Think of it as the prompt you're handing your future self.
96
+ >
97
+ > **Because it's a long prose field, mind the JSON:** an unescaped ASCII quote
98
+ > inside `objective` (e.g. `…もう"中心"ではなく…`) breaks the file, and a broken
99
+ > record is **silently skipped** — you'll quietly end up with fewer lessons than
100
+ > you wrote. In prose, use `「」`/`『』` (or escape as `\"`), never a raw `"`.
101
+
102
+ **Labels are localizable.** `title`, every `label`, and the enum `values` are free
103
+ text — translate them into the learner's language. Product/role names stay in
104
+ English. Keep the `status` `values` in lockstep with anything that references them
105
+ (`kanbanField`, action `when` predicates).
106
+
107
+ ## Action templates
108
+
109
+ There are just **two actions, both labeled "Learn"** — each picks the right mode
110
+ automatically, so the learner never has to choose "teach vs. review vs. extend".
111
+ Each needs a plain-English template inside the skill dir; the host starts a new
112
+ chat in the `tutor` role seeded with it.
113
+
114
+ - **Per-record action** (`actions`) — the **Learn** button on a lesson's detail
115
+ panel. The host prepends **that lesson's record JSON** as passive data; the
116
+ `learn` template teaches or reviews it depending on its `status` (the gating
117
+ that used to need a `when` predicate now lives inside the template).
118
+ - **Collection-level action** (`collectionActions`) — the **Learn** button in the
119
+ collection header. There's no single record, so the host prepends a **compact
120
+ progress summary of every lesson** (each one's `id`, `title`, and `status`); the
121
+ `continue` template reads how far the learner has got and picks the next lesson
122
+ to run. `when` predicates are not evaluated on collection-level actions.
123
+
124
+ Keep templates short — the role prompt already knows how to teach.
125
+
126
+ `data/skills/lessons-<topic>/templates/learn.md` (per-record):
127
+
128
+ ```markdown
129
+ Learn this lesson. The record above gives the lesson's `title`, its `objective`
130
+ (a paragraph describing what to teach — your authoring brief), `status`, and — if
131
+ already authored — its `lesson` HTML path. Pick the mode from `status`, and never
132
+ jump straight to a quiz — the HTML page IS the lesson, so deliver it first.
133
+
134
+ Deliver the page with `presentHtml`:
135
+ - `lesson` already set (often pre-authored in the background — see below) → present
136
+ it by passing its **path** to `presentHtml` (no duplicate save). Instant.
137
+ - `lesson` empty (the prefetch worker hasn't finished, or never ran) → author the
138
+ page **from the `objective` brief** and present it with `presentHtml` (passing the
139
+ `html`), then write the returned `data.filePath` into the record's `lesson` field.
140
+ This is the graceful fallback.
141
+
142
+ **The moment the page is on screen — _before_ you teach or quiz — prefetch the next
143
+ lesson** so its generation overlaps the whole time the learner spends here: call
144
+ `spawnBackgroundChat` (`hidden: true`, `role: "tutor"`) to author the next-by-`order`
145
+ lesson's HTML in the background (a self-contained message that reads that record and
146
+ `Write`s the page to `artifacts/html/lessons-<topic>/<id>.html`, sets its `lesson`
147
+ field, and presents nothing). Skip if it's already authored or this is the last
148
+ lesson. **Do this now, not at the end** — the learner often advances the instant they
149
+ finish, and a prefetch fired during the wrap-up is too late to hide the wait.
150
+
151
+ Then branch on `status`:
152
+ - `planned` / `learning` → teach the page, check understanding with a question or a
153
+ `presentForm` quiz, and set `status` to `learning` (or `practiced` if they nailed
154
+ it).
155
+ - `practiced` / `mastered` → run a short review quiz on the `objective` (include an
156
+ "explain it in your own words" item); set `status` to `mastered`, or back to
157
+ `learning` if they're shaky.
158
+
159
+ Cite real sources in the page and in `resources`, and record anything to revisit in
160
+ `notes`. Don't re-show the collection card after a single lesson — just keep the
161
+ conversation going; the board reflects the new `status` next time it's opened. (The
162
+ next lesson was already prefetched right after you showed this page — see above.)
163
+ ```
164
+
165
+ `data/skills/lessons-<topic>/templates/continue.md` (collection-level):
166
+
167
+ ```markdown
168
+ Continue the course. The summary above lists every lesson's `id`, `title`, and
169
+ `status`. Pick the next move, in order:
170
+
171
+ 1. a lesson with `status: learning` → resume it
172
+ 2. else the lowest-`order` `status: planned` lesson → start it
173
+ 3. else a `practiced` (not yet `mastered`) lesson → review it
174
+
175
+ In cases 1–3, run that one lesson exactly like the per-lesson Learn button: present
176
+ by `path` if `lesson` is set (else author from `objective`), and **immediately
177
+ prefetch the next lesson** with a hidden `spawnBackgroundChat` worker — _before_ you
178
+ teach or quiz, so it generates while the learner works. Then deliver the lesson, check
179
+ understanding, and update `status` + `notes`. Don't re-show the collection card
180
+ afterwards — just continue the conversation.
181
+
182
+ 4. only if **every** lesson is `mastered` → append the next batch as `planned`
183
+ records (a **paragraph `objective`** each — the authoring brief — continuing the
184
+ `order`), pitched at the learner's now-higher level; do NOT author the HTML yet.
185
+ When you write these records, use the language's quotation marks (`「」`/`『』`,
186
+ or `'…'`/`“…”`) — or escape as `\"` — in string values, never a raw `"`, or the
187
+ file breaks and the record is silently skipped. Then call
188
+ `presentCollection` once to show the expanded roadmap.
189
+ ```
190
+
191
+ ## Authoring the lesson HTML — two ways
192
+
193
+ `presentHtml` does two things: it saves the HTML *and* **renders it in the
194
+ learner's canvas**. The `Write` tool only saves. Choose by whether the learner
195
+ should see the page right now.
196
+
197
+ **Batch / scaffolding (no user involvement) — Write the file directly.** If you
198
+ pre-author several lessons at once, do NOT loop `presentHtml` over them — that
199
+ would flash every page into the canvas one after another, hijacking the
200
+ conversation. Instead:
201
+
202
+ 1. Author the self-contained HTML (see `config/helps/presenthtml.md` for the
203
+ document rules — full `<!DOCTYPE html>`, inline CSS/JS or an allowed CDN).
204
+ 2. **Write it straight to disk** at a stable, course-scoped path:
205
+ `artifacts/html/lessons-<topic>/<id>.html` (filename = the record id, so the
206
+ link is meaningful and stable). Use the `Write` tool — not `presentHtml`.
207
+ 3. Set that path as the lesson record's `lesson` field.
208
+
209
+ **Teaching one lesson live — use `presentHtml`.** This is the common case: most
210
+ lessons are authored **just-in-time**, the moment the learner reaches them (you
211
+ don't pre-generate the whole course up front). When you teach one and want it in
212
+ the canvas:
213
+
214
+ - **New lesson** (empty `lesson`): call `presentHtml` with the `html` — it saves
215
+ and renders in one step and returns the saved path in `data.filePath`. Write
216
+ *that* returned path into the record's `lesson` field (don't also `Write` it
217
+ yourself, or you'll create two copies).
218
+ - **Pre-authored lesson** (`lesson` already set): call `presentHtml` with the
219
+ **`path`** (the existing `lesson` value) instead of `html` — it presents the
220
+ file in place without saving a duplicate.
221
+
222
+ Either way, **`presentHtml` must actually run** — delivering the page is the heart
223
+ of teaching, not an optional step before the quiz.
224
+
225
+ Keep lesson pages **self-contained** (inline everything or an allowed CDN) so
226
+ they render correctly regardless of the directory they were saved in.
227
+
228
+ ## Pre-generating lessons in the background — no wait
229
+
230
+ Authoring a full HTML page takes the model tens of seconds, and `presentHtml` only
231
+ renders **after** the page is fully generated. So a lesson authored at the moment
232
+ the learner asks for it makes them **stare at a blank canvas** — worst of all on the
233
+ very first lesson of a brand-new course. The fix: author **ahead of time, in a
234
+ parallel background session**, so the page is already on disk (and the record's
235
+ `lesson` field set) by the time the learner opens it. Then you just present it by
236
+ `path`, instantly.
237
+
238
+ The tool is **`spawnBackgroundChat({ message, role, hidden })`** — it launches a
239
+ second, independent agent session that runs **concurrently** with this conversation
240
+ and returns immediately. To pre-author one lesson:
241
+
242
+ ```
243
+ spawnBackgroundChat({
244
+ role: "tutor",
245
+ hidden: true,
246
+ message: "<a fully self-contained instruction — see the rules below>"
247
+ })
248
+ ```
249
+
250
+ Rules for the worker:
251
+
252
+ - **`hidden: true`, always.** These are plumbing, not conversations — a visible
253
+ worker would clutter the learner's chat history. (`hidden: false` exists for other
254
+ uses where the user *should* see the spawned chat; a lesson worker is never that.)
255
+ - **The `message` must be fully self-contained** — the worker shares NONE of this
256
+ chat's context. Spell out: read the record at
257
+ `data/lessons-<topic>/items/<id>.json`; author a self-contained HTML page **from
258
+ its `objective`** (full `<!DOCTYPE html>`, inline CSS/JS or an allowed CDN — see
259
+ `config/helps/presenthtml.md`); **`Write`** it to
260
+ `artifacts/html/lessons-<topic>/<id>.html`; set that path as the record's `lesson`
261
+ field with `manageCollection` putItems `mode: "merge"` (`{ id, lesson }` — merge
262
+ keeps every other field); do **NOT** call `presentHtml` and do **NOT** present
263
+ anything — just write the files and stop. (No one is viewing the worker's canvas,
264
+ so presenting there is wasted.)
265
+ - **One lesson per call**, and don't spawn a fleet — the host caps concurrent hidden
266
+ workers and a worker can't spawn further workers.
267
+
268
+ **When to pre-author:**
269
+
270
+ 1. **At course creation — pre-author lesson 1 (optionally 2).** Right after
271
+ `presentCollection` shows the roadmap, fire a worker for lesson 1 and tell the
272
+ learner it's being prepared (e.g. "コースができました!最初のレッスンを準備中です。
273
+ 準備ができたら『始めて』と言ってください"). The learner reads the roadmap while the
274
+ page generates — the wait now **overlaps** with something useful instead of being
275
+ dead air. Do **not** also author lesson 1 inline in the same turn.
276
+ 2. **Prefetch the next lesson the moment you present the current one — not at the
277
+ end.** As soon as lesson N's page is on screen (*before* you teach or quiz it),
278
+ fire a worker for the next-by-`order` lesson, so its generation overlaps the
279
+ *whole* time the learner spends on N. Waiting until you update `status`/`notes` is
280
+ too late — the learner often advances the instant they finish, and the wait
281
+ reappears. By the time they reach N+1, it's already authored → instant.
282
+
283
+ **Presenting, and the fallback.** When the learner opens a lesson, check its `lesson`
284
+ field: **set** → `presentHtml` by `path` (instant); **still empty** (the worker
285
+ hasn't finished, or never ran) → author it inline from `objective` as usual. The
286
+ inline path is the graceful fallback — background pre-generation is a pure
287
+ optimization, never a dependency. Because workers write to the **stable**
288
+ `artifacts/html/lessons-<topic>/<id>.html` path, a rare double-author (learner races
289
+ ahead of the worker) just overwrites in place — never a duplicate.
290
+
291
+ ## SKILL.md
292
+
293
+ `data/skills/lessons-<topic>/SKILL.md` tells the agent when and how to operate the
294
+ collection. Keep it short — the schema and templates do the heavy lifting. Cover:
295
+
296
+ - **Trigger phrases** — "teach me <topic>", "what's my next lesson", "continue my
297
+ course", "I'm ready for the next one", plus the equivalents in the learner's
298
+ language.
299
+ - **Record shape** — point at the schema; note `id` is the filename
300
+ (`lesson-<order3>-<slug>`, e.g. `lesson-001-eigenvalues`), new lessons start at
301
+ `status: "planned"` with an empty `lesson`, `order` is the reading sequence, and
302
+ `objective` is a **full paragraph** (the authoring brief), not a one-liner.
303
+ - **The teaching loop** —
304
+ - **Plan the course**: once the goal/level is known, draft the full sequence of
305
+ lessons as `planned` records, in `order`, so the learner can see the road
306
+ ahead. Give each one a **paragraph `objective`** — what that lesson must teach,
307
+ its key points, the intended takeaway — not just a title. That paragraph is
308
+ what makes deferred authoring work: when you write the page later, the record's
309
+ `objective` is the prompt you generate it from, so write it that way. Once the
310
+ records are written, call `presentCollection` **once** to show the roadmap (this
311
+ also surfaces any malformed records right away). **Then immediately fire a hidden
312
+ `spawnBackgroundChat` worker to pre-author lesson 1** and tell the learner it's
313
+ being prepared — do NOT author lesson 1 inline in the same turn (see
314
+ "Pre-generating lessons in the background"). The learner reads the roadmap while
315
+ it generates.
316
+ - **Pre-author lesson 1 in the background** (then the rest just-in-time): the
317
+ worker above writes lesson 1's HTML to disk and sets its `lesson` path, so the
318
+ first open never waits. You *may* fire a second worker for lesson 2 as well.
319
+ Leaving the rest `planned` with an empty `lesson` and prefetching each next
320
+ lesson as you open the current one is the default — never pre-generate the
321
+ whole course up front.
322
+ - **Learn a lesson** (the per-lesson **Learn** button): always **deliver the page
323
+ with `presentHtml` first** — never jump straight to a quiz. Present by `path` if
324
+ `lesson` is set (usually it was pre-authored in the background), else author from
325
+ `objective` inline (store the returned `data.filePath`) as the fallback. **The
326
+ moment the page is shown — before teaching or quizzing — prefetch the next lesson**
327
+ with a hidden `spawnBackgroundChat` worker, so its generation overlaps this whole
328
+ lesson rather than starting at the end. Then branch on `status`:
329
+ `planned`/`learning` → teach + quiz (→ `learning`/`practiced`);
330
+ `practiced`/`mastered` → review quiz (→ `mastered`, or back to `learning` if
331
+ shaky). Record gaps in `notes`.
332
+ - **Continue the course** (the header **Learn** button, `continue` action): from
333
+ the progress summary, resume a `learning` lesson, else start the lowest-`order`
334
+ `planned` one, else review a `practiced` lesson; **prefetch the next lesson the
335
+ moment you present the current one** (not after running it) — and only once
336
+ everything is `mastered`, append the next batch of `planned` lessons (paragraph
337
+ `objective` each, HTML authored lazily later).
338
+ - **Operations** — record I/O via `manageCollection` (`getItems` to read;
339
+ `putItems` for schema-validated writes — `mode: "create"` for new lessons,
340
+ `mode: "merge"` with a partial row for status/notes/lesson updates so the
341
+ fields you omit survive; Delete removes the file at
342
+ `data/lessons-<topic>/items/<id>.json`; raw Read / Write / Edit is the
343
+ escape hatch). Rather than dumping the whole course into chat,
344
+ point the user at `/collections/lessons-<topic>`.
345
+ - **When to call `presentCollection`** — when the **course itself** changes: after
346
+ creating the collection or adding/extending lessons (it also surfaces malformed
347
+ records). Do **not** call it after each individual lesson's teach/review — a
348
+ single `status` update doesn't need the whole board re-rendered; that's just
349
+ noise mid-lesson.
350
+
351
+ ## A record on disk
352
+
353
+ One JSON per lesson — `lesson` is empty until the lesson is taught. Note the
354
+ `objective` is a full paragraph (the brief the page will be authored from), not a
355
+ one-liner:
356
+
357
+ ```json
358
+ { "id": "lesson-001-eigenvalues", "order": 1, "title": "What an eigenvalue is", "status": "planned", "objective": "Teach that an eigenvector is a direction a matrix only scales (never rotates), and its eigenvalue is the scale factor. Cover the geometric picture first (a transformation acting on a few vectors, most changing direction, a special one not), then the equation Av = λv. The takeaway: the learner can look at a 2x2 transformation and point to which directions are eigenvectors. Keep it geometric — defer the characteristic-polynomial algebra to a later lesson." }
359
+ ```
360
+
361
+ After teaching, the same record gains its artifact link:
362
+
363
+ ```json
364
+ { "id": "lesson-001-eigenvalues", "order": 1, "title": "What an eigenvalue is", "status": "learning", "objective": "Teach that an eigenvector is a direction a matrix only scales (never rotates), and its eigenvalue is the scale factor. Cover the geometric picture first, then Av = λv. Takeaway: spot eigenvectors of a 2x2 transformation by eye. Keep it geometric.", "lesson": "artifacts/html/lessons-linear-algebra/lesson-001-eigenvalues.html", "resources": "- [3Blue1Brown](https://www.3blue1brown.com/)", "notes": "Solid on the geometry; revisit the algebra next time." }
365
+ ```
366
+
367
+ ## What the learner gets, with zero host code
368
+
369
+ - **Table** — the whole course in `order`, each row showing its `status` and a
370
+ clickable link to the rendered lesson. The `status` dropdown edits inline.
371
+ - **Kanban** — columns from `status`; the course as a progress pipeline. Drag a
372
+ card to promote/demote a lesson, or run an entire review pass by dragging.
373
+ - **Learn button (per lesson)** — one tap starts a fresh Tutor chat seeded with
374
+ that lesson; it teaches or reviews based on the lesson's `status`, so there's
375
+ nothing to decide.
376
+ - **Learn button (header)** — seeds a Tutor chat with the whole course's progress
377
+ and resumes where you left off — picking the next lesson, or growing the course
378
+ once everything's mastered.
379
+ - Because each lesson is its own file, the course is fully diffable and portable;
380
+ the learner owns it as plain JSON plus the HTML artifacts.
381
+
382
+ ## Extending it
383
+
384
+ - **Spaced review reminders.** Add a `reviewBy` (`date`) field plus
385
+ `"completionField": "status"`, `"completionDoneValues": ["mastered"]`,
386
+ `"triggerField": "reviewBy"`, and a `"notifyWhen": { "field": "status", "in":
387
+ ["practiced", "mastered"] }`. The bell then nudges the learner to review a
388
+ taught lesson on its `reviewBy` date — without belling every `planned` lesson.
389
+ - **The mission / goal.** For a durable record of *why* the learner is studying,
390
+ add a `singleton` companion collection (`lessons-<topic>-goal`, `singleton:
391
+ "goal"`) with `goal`, `level`, and `target` fields — read it at the start of
392
+ every session to resume without re-interviewing.
393
+ - **A "mastered" checkbox.** Add a `toggle` projecting `status`
394
+ (`"field": "status", "onValue": "mastered", "offValue": "practiced"`) for a
395
+ one-click way to mark a reviewed lesson done.
396
+ - **Prerequisites.** Add a `ref` field pointing back into the same collection to
397
+ record which lesson must come first — useful for non-linear curricula.
398
+
399
+ Keep additions minimal — the core fields (`order`, `title`, `status`,
400
+ `objective`, `lesson`) are enough to start teaching a tracked course today.