# Tutorial Creator

> Generate annotated code reading tutorials from your own codebase. Three surfaces - tutorial generation, vocabulary management, and learning-state inspection. Tracks vocabulary with status state machine, supports six writing-to-learn entry points and five audience-facing entry points.

- **Type:** Skill
- **Install:** `agentstack add skill-terryc21-tutorial-creator-tutorial-creator`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [Terryc21](https://agentstack.voostack.com/s/terryc21)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** Apache-2.0
- **Upstream author:** [Terryc21](https://github.com/Terryc21)
- **Source:** https://github.com/Terryc21/tutorial-creator/tree/main/skills/tutorial-creator
- **Website:** https://github.com/Terryc21/tutorial-creator

## Install

```sh
agentstack add skill-terryc21-tutorial-creator-tutorial-creator
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# tutorial-creator

Three surfaces, gateway-mediated:

- **`tutorial`** — generate a lesson (six writing-to-learn entries, five audience-facing entries)
- **`vocab`** — manage vocabulary independent of lesson generation
- **`status`** — inspect your learning state (read-only dashboard)

The legacy v1.1 invocation (`/skill tutorial-creator  `) still works; it routes to writing-to-learn entry [b] (topic + file).

## Usage

```
/skill tutorial-creator                         # opens gateway question
/skill tutorial-creator          # legacy v1.1 path → entry [b]
/skill tutorial-creator tutorial          # tutorial surface
/skill tutorial-creator vocab       # vocab surface
/skill tutorial-creator status                  # status surface
/skill tutorial-creator undo                    # revert last generation
/skill tutorial-creator undo --session      # revert a specific session (rare)
/skill tutorial-creator renumber      # rename Day-N + rewrite cross-references
/skill tutorial-creator --mode learn|audience|both|vocab|status [args]
                                                 # skip gateway, route directly
/skill tutorial-creator open              # register a tutorial-creator project
                                                 #  in ~/.claude/tutorial-creator/registry.yaml
                                                 #  so future invocations from any cwd find it
/skill tutorial-creator open                    # list registered projects + pick one
                                                 #  (sets it as the registry default)
/skill tutorial-creator forget            # remove a project from the registry
                                                 #  (no filesystem changes; project files stay)
/skill tutorial-creator --project-dir  [args]
                                                 # one-shot override; resolves config
                                                 #  from /.claude/tutorial-config.yaml
                                                 #  instead of the default discovery rule
```

**Where the project lives.** `.claude/tutorial-config.yaml` and `.claude/tutorial-sessions/` live in the **resolved project root**, not necessarily cwd. The skill walks a discovery chain on every invocation; see `## Project resolution`. This means you can keep a tutorial-creator project at `/Volumes/.../Tutorials/` and invoke `/skill tutorial-creator status` from any working directory and it Just Works — same mental model as `git status` walking up from cwd to find `.git/`.

## Routing logic

Every invocation runs through this dispatch:

0. **Resolve the project root** (NEW in this revision). Run `## Project resolution` first to determine which `.claude/tutorial-config.yaml` this invocation should read or write to. The resolved path becomes `$PROJECT_ROOT` for the rest of the invocation; all subsequent file operations described in this document use `$PROJECT_ROOT/.claude/`, `$PROJECT_ROOT/{tutorials_dir}/`, etc. Steps 1–4 below assume this has run.
1. **Read `--mode` flag if present.** If set, echo it back to the user as a one-line confirmation, then jump directly to that surface or path. Skip the gateway question. Mode values: `learn`, `audience`, `both`, `vocab`, `status`.
2. **Else, recognize first-positional subcommand keywords.** If the first positional arg is one of:
   - `tutorial` → tutorial surface (Path 1 unless `--mode audience` follows)
   - `vocab` → vocab surface; the second positional is the subcommand (`add`, `list`, `show`, `edit`, `merge`, `review`, `gap`, `regen-md`, `undo`)
   - `status` → status surface (`STATUS.md`)
   - `undo` → recovery `undo` route (see `## Recovery` § `undo` command). May be followed by `--session `
   - `renumber` → recovery `renumber` route (see `## Recovery` § `renumber`). Requires two more positional args: ` ` (e.g., `renumber 8 7.5`)
   - `open` → registry route (see `## Project resolution` § `open` command). May be followed by an optional `` positional
   - `forget` → registry route (see `## Project resolution` § `forget` command). Requires one positional arg: ``
   Route directly. Skip the gateway question.
3. **Else, parse two-positional legacy form.** If the user invoked with two positional args matching ` ` AND the source is an existing file in the project, treat as **entry [b] legacy path** — produce a v1.1-shaped tutorial. This preserves the v1.1 invocation contract for users who haven't seen the v2 changes.
4. **Else, ask the gateway question.** Present the four-option menu (below). Route based on answer.

### Gateway question

Use AskUserQuestion (or plain-text prompt if AskUserQuestion is unavailable):

```
What do you want to do?

[1] Write a tutorial for myself      (for my own learning)
[2] Write a tutorial for others      (preparing a lesson for others to learn)
[3] Manage vocabulary                 (edit vocabulary)
[4] Inspect my learning state         (see my progress and what I'm forgetting)
```

- **Answer [1]** → tutorial surface, Path 1 (writing-to-learn). Ask the entry-point question (six options; see `## Tutorial surface — entry points`).
- **Answer [2]** → tutorial surface, Path 2 (audience-facing). Load `AUDIENCE.md` and run the Path 2 routing flow (entry-point question, audience question, honest-machine opt-in, length budget, venue selection, then handoff to the chosen `venues/.md`).
- **Answer [3]** → vocab surface (load `VOCAB.md`).
- **Answer [4]** → status surface (load `STATUS.md`).

### Mode-mismatch detection

If the user picked Path 2 (audience-facing) AND their topic phrasing matches one of these patterns, soft-nudge once:

- starts with `I want to understand`
- starts with `I'm confused about`
- starts with `why does my`
- starts with `what is`

Nudge text:

> This phrasing reads like writing-to-learn. Confirm audience-facing, or switch to writing-to-learn?

**Single-fire per session.** A session-scoped flag (`mode_mismatch_nudge_fired: true`) flips after the first surface. Subsequent matching topics in the same session do NOT re-nudge. The user has demonstrated awareness.

Not blocking. The user always has final say. The nudge is purely advisory; either answer proceeds without delay.

## Tutorial surface — entry points

After gateway answer = [1] (writing-to-learn), ask:

```
Where does the lesson start?

[a] Daily progression       — pick what's next based on my progress
[b] Topic + file            — I have both a topic and a source file
[c] Topic only              — I have a topic, find the best file
[d] Question                — I'm stuck on something specific
[e] Gap-driven              — show me my "confused" vocabulary, pick from there
[f] Notes & synthesis       — from a doc, post, video, or past session
```

After gateway answer = [2] (audience-facing), ask:

```
Where does the tutorial start?

[a] Annotated source         — file in my codebase that demonstrates the pattern
[b] Incident-grounded        — a real failure or decision I want to write about
[c] Synthesized example      — contrived minimal example for the concept
[d] External source          — public repo, Apple sample, blog post
[e] Documentation-grounded   — Apple Developer docs, RFCs, etc.
```

After the entry letter is picked, the Path 2 flow runs four more AskUserQuestion prompts in this order, then hands off to a venue template:

1. **Audience question.** Options: `beginner` / `intermediate` / `senior` / `mixed`. Drives in-voice content shifts (definitions vs. tradeoffs).
2. **Honest-machine opt-in.** Y / N. When Y, the venue template appends a section on what the article does NOT cover (section name varies by venue; resolved from `venues/_schema.yaml#venues..honest_machine_section_name`).
3. **Length budget.** Options: `S` / `M` / `L` / `X`. Each option label includes the venue's word target and ceiling, looked up from `venues/_schema.yaml#venues..length_budget`.
4. **Venue selection.** Options: `reddit` / `book-chapter` / `apple-developer-article` / `medium` / `blog` / `repo-doc`. All six venues are shipped as of `v2.0.0`; the runtime loads `venues/.md` and renders the article using that venue's voice signature.

The full procedure for each Path 2 entry, the venue handoff payload schema, the audience × budget interaction rules, and the recovery-asymmetry rationale all live in `AUDIENCE.md`. SKILL.md is the routing surface; AUDIENCE.md is the procedure surface.

### Implementation status

**All six writing-to-learn entries are implemented** (Phases 3abc + 3def):

- **[a] daily progression** — see `## Entry [a] — Daily progression`
- **[b] topic + file** — see `## Entry [b] — Tutorial Format (topic + file)` (this is also the legacy v1.1 path)
- **[c] topic only** — see `## Entry [c] — Topic only (skill finds the file)`
- **[d] question-led** — see `## Entry [d] — Question-led`
- **[e] gap-driven** — see `## Entry [e] — Gap-driven`
- **[f] external source** — see `## Entry [f] — External source`

**All five audience-facing entries are implemented** (Phase 7); all six venue templates are shipped:

- **[a] annotated source** — see `AUDIENCE.md` § Entry [a]
- **[b] incident-grounded** — see `AUDIENCE.md` § Entry [b]
- **[c] synthesized example** — see `AUDIENCE.md` § Entry [c]
- **[d] external source** — see `AUDIENCE.md` § Entry [d]
- **[e] documentation-grounded** — see `AUDIENCE.md` § Entry [e]

**Venue templates available right now:**

| Venue | File | Status |
|---|---|---|
| `reddit` | `venues/reddit.md` | ✅ shipped |
| `book-chapter` | `venues/book-chapter.md` | ✅ shipped |
| `apple-developer-article` | `venues/apple-developer-article.md` | ✅ shipped |
| `medium` | `venues/medium.md` | ✅ shipped |
| `blog` | `venues/blog.md` | ✅ shipped |
| `repo-doc` | `venues/repo-doc.md` | ✅ shipped |

The five Path 2 entries `[a]`-`[e]` share letters with the Path 1 entries but are different procedures; do not conflate them. Path 1 produces artifacts for the user (writing-to-learn); Path 2 produces artifacts for an audience (Reddit posts, book chapters, articles, blog posts, repo docs). After the entry is chosen, Path 2 hands off to one of the 6 venue templates in `venues/`.

## Entry [a] — Daily progression

Use when the user wants the next concept in their learning sequence and doesn't have a specific topic or file in mind.

### Procedure

1. **Read config.** `.claude/tutorial-config.yaml`. Required fields for entry [a]: `language`, `next_day`, `experience_level`, `tutorials_dir`. If `progression_override` is set, use that path; otherwise load `progressions/.yaml` from the skill bundle.
2. **Determine current phase.** Read `PROGRESS.md`. Look for the most recent Score Log row to find the last-shipped phase number. If PROGRESS.md is empty (first day), current phase = 1.
3. **Read the active progression.** Parse the matching `progressions/*.yaml`. Extract the current phase's `concepts` list.
4. **Identify uncovered concepts in this phase.** Cross-reference `concepts` against the Concepts Mastery Checklist in PROGRESS.md (entries marked `- [ ]` or `- [x]`). Concepts NOT yet appearing in the checklist are the candidates.
5. **Recommend the next concept.** Pick the first uncovered concept in the phase's list (the list order is teaching order). Show the user one candidate with brief reasoning:
   ```
   Next in your progression:
     Concept: 
     Phase:   . 
     Reason:  First uncovered concept in this phase. / concepts done.
   Generate a tutorial for this? [yes / pick different concept / advance to next phase / cancel]
   ```
6. **Handle user response.**
   - `yes`: proceed to step 7
   - `pick different concept`: list all uncovered concepts in current phase, let user choose
   - `advance to next phase`: increment phase number; re-run from step 4 with the next phase. If the user is already in the last phase (phase 6 in built-in progressions), say: "You're in the last built-in phase. Use entry [c] (topic only) for advanced topics, or define a custom progression in `tutorial-config.yaml#progression_override`." Stop.
   - `cancel`: stop without generating
7. **Find a source file.** With concept chosen, scan the project for files demonstrating it. Use the same ranking heuristic as Entry [c] below ("pedagogical fit beats density"). Show 1-3 candidates; user picks one.
8. **Generate the tutorial.** Follow the tutorial format in `## Entry [b] — Tutorial Format`. The chosen concept becomes the topic; the chosen file becomes the source.

### Cold-start handling

If `next_day == 1` AND PROGRESS.md doesn't exist yet AND no tutorials have been written:

- The user has just completed first-run setup
- Phase = 1; pick the first concept of phase 1 ("optionals" for Swift, "basic types" for TypeScript, etc.)
- Note in the recommendation: "First lesson — picking the foundational concept for your language."

### Honesty rule

If no source file in the project demonstrates the recommended concept (scan returns zero candidates above the quality threshold defined in Entry [c]), say so explicitly:

> No good example of `` in your codebase. Two options:
>   1. Pick a different concept from this phase (I can list them)
>   2. Use audience-facing path [c] (synthesized minimal example) if you want a contrived example

Do not silently fall back to a synthesized example or pick a marginal file. The user's confidence in the recommendation is load-bearing.

## Project resolution

Runs as step 0 of every invocation, before routing. Determines `$PROJECT_ROOT` — the directory whose `.claude/tutorial-config.yaml` this invocation reads from and writes to. Resolution must succeed before any other step runs; if it doesn't, the skill either runs first-run setup (if no project anywhere) or refuses (if multiple registered projects can't be disambiguated).

### Discovery chain (highest precedence first)

1. **`--project-dir ` flag.** If set on the invocation, treat `` as `$PROJECT_ROOT` and stop. The path must be absolute or resolvable relative to cwd. If `/.claude/tutorial-config.yaml` does not exist, the skill **does not** auto-create it from this flag — say `--project-dir  has no tutorial-creator config. Run "/skill tutorial-creator open " first, or invoke from  to trigger first-run setup.` and stop. The `--project-dir` flag is for picking among already-set-up projects, not for bootstrapping new ones in unusual locations.
2. **Environment variable `TUTORIAL_CREATOR_PROJECT_DIR`.** If set and points to a directory with `.claude/tutorial-config.yaml`, use it as `$PROJECT_ROOT`. If the env var is set but the path is invalid, warn (`TUTORIAL_CREATOR_PROJECT_DIR= doesn't have a tutorial-creator config; ignoring`) and fall through to the next step.
3. **Cwd's `.claude/tutorial-config.yaml`.** If `./.claude/tutorial-config.yaml` exists in the current working directory, use cwd as `$PROJECT_ROOT`. This preserves backward compatibility with v1.1 / v2.0-pre-resolution behavior — if you're already in your project, nothing changes.
4. **Ancestor walk from cwd.** Walk up from cwd one directory at a time until either: (a) a `.claude/tutorial-config.yaml` exists at that level — use that directory as `$PROJECT_ROOT`; (b) the filesystem root is reached — fall through to the next step. Stop at filesystem root, do NOT cross into another user's home directory or into `/`.
5. **Registry lookup.** Read `~/.claude/tutorial-creator/registry.yaml` (per SCHEMAS.md Schema 5). If the file exists and:
   - has exactly one project entry → use it as `$PROJECT_ROOT`
   - has a `default` field pointing at a registered project → use it
   - has multiple projects with no default → prompt the user to pick one (and offer to set it as default for next time):
     ```
     Multiple tutorial-creator projects registered. Pick one for this invocation:
       [1] /Volumes/.../Tutorials      (last invoked: 2026-05-10)
       [2] /Users/me/Code/learn-rust   (last invoked: 2026-04-15)
       [3] /Users/me/code-smarter      (last invoked: 2026-03-22)
     Choose [1-3]; add `--default` to also set this as the

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [Terryc21](https://github.com/Terryc21)
- **Source:** [Terryc21/tutorial-creator](https://github.com/Terryc21/tutorial-creator)
- **License:** Apache-2.0
- **Homepage:** https://github.com/Terryc21/tutorial-creator

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-terryc21-tutorial-creator-tutorial-creator
- Seller: https://agentstack.voostack.com/s/terryc21
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
