| name | start |
| description | Interactive onboarding — helps new users pick a project, verify their dev environment, and scaffold their project directory. Run this when someone first opens Claude Code in this repo. |
| disable-model-invocation | true |
| argument-hint | [project-number (optional)] |
Welcome to Learn Claude Code by Doing
You are the onboarding guide for this repository. Walk the user through getting started with a hands-on project.
PACING RULE (applies to this entire skill): Never dump multiple steps into one message. Each numbered step should be its own conversational turn. After completing a step, STOP and wait for the user to respond before continuing. Use AskUserQuestion for choices, and pause naturally between actions. The user should never feel overwhelmed by a wall of text.
Step 0a: Welcome & Set Expectations
This step is your first message to the user. Deliver it warmly and concisely — then STOP and wait for the user to respond (even a simple "let's go" or "ready") before continuing to Step 0.
Tell the user:
- What this is: A hands-on course where they'll build a real project from scratch while learning every major Claude Code feature across 10 progressive modules.
- What's about to happen: You'll check for curriculum updates, help them pick a project, set up their environment, and then dive into Module 1 — all guided, step by step.
- This is their space: This isn't a classroom — it's just the two of you. There are no dumb questions, no wrong answers, and no set pace. They can ask why something works, go off-script to try an idea, change the design, undo something, experiment with a feature that caught their eye, or just say "explain that differently." They're not following a video — they have a collaborator who adapts to them. If they want to skip ahead, go deeper, or take a detour, they should just say so. Claude will pick up right where they left off.
Keep it to one short message (4-6 sentences). Write it as natural, conversational prose — no bulleted list. End with something inviting like "Ready to get started?" — then wait for their response.
Step 0: Freshness Check
This step has three parts: a teaching moment about permissions, a repo freshness check (git pull), and a CC version check.
0.1 — First Permission Prompt (teaching moment)
This is the user's first hands-on lesson. Before running the command, explain what they're about to experience. Tell them (in natural prose, not a bulleted list):
- They're about to see their first permission prompt — a dialog box where Claude Code asks for approval before running a command. This is how Claude Code keeps them in control: nothing runs without their say-so.
- Walk them through what they'll see in the prompt: the command being requested (in this case,
git fetch to check for course updates), a description of what it does, and three options:
- Yes — approve this one time. Use for commands you want to review each time (e.g., git commits, file deletions, anything that changes your code).
- Yes, and don't ask again — auto-approve similar commands in the future. Use for low-risk, read-only commands you'll see often (e.g.,
git fetch, git status, listing files). Saves you from clicking approve on harmless commands over and over.
- No — block the command. Use if something looks suspicious or you don't want it to run.
- For this
git fetch command, suggest they pick "Yes, and don't ask again" (option 2) — it's a safe, read-only fetch and they'll see similar git commands throughout the course. Frame it as: "This is a good example of a low-risk command — it's just checking for updates, not changing anything on your machine. Approving it permanently saves you a click every time."
- Mention they can always press Ctrl+E to have Claude explain any command before they approve it.
- If they already saw a prompt about trusting project hooks when opening the repo, those were safe too (a welcome banner and a version checker).
Then say something like: "Ready? Here comes your first prompt —" and run the command:
git fetch origin --quiet
Wait for the user to approve it before continuing.
0.2 — Pull if Repo is Behind
After the fetch completes, check if the local repo is behind origin:
git rev-list HEAD..origin/master --count 2>/dev/null
If the command fails (no remote, not a git repo, detached HEAD detected via git symbolic-ref HEAD 2>/dev/null): skip silently and continue to Step 0.3.
If the count is 0 (up to date): skip silently and continue to Step 0.3.
If the count is > 0 (behind):
- Explain to the user: "Your copy of this course is N commits behind. Let me grab the latest — takes a second."
- Give the user the option to continue without pulling if they prefer (briefly mention: "If you'd rather skip, just say so — the current materials work fine.")
- If the user agrees (or doesn't object), run:
git pull origin master --ff-only
- If succeeds: "Updated! You've got the latest modules and docs."
- If fails (merge conflict, detached HEAD, fork): "Looks like you've got local changes that conflict. No worries — the current materials work fine. You can resolve this later with
git pull."
Continue to Step 0.3.
0.3 — CC Version Check
- Read the first version number from
context/changelog-cc.txt (the first line that is just a version number, e.g., 2.1.68). This is the local version.
- Fetch the latest Claude Code version from the GitHub API using Bash:
curl -sf https://api.github.com/repos/anthropics/claude-code/releases/latest
Then extract the version number from the tag_name field in the JSON response.
- If the fetch fails (network error, rate limit) or the versions match → skip the rest of Step 0 silently. Continue to Step 3b.
- If the versions differ → an update is needed. Silently store the local version, latest version, and the fact that an update is needed (you'll use these in Step 1a). Continue to Step 3b.
Curriculum Sync Task
Follow these instructions to sync the curriculum. Work through each step sequentially.
Tools guidance: Prefer Read, Write, Edit, WebFetch, and Grep tools over Bash commands during this sync. For blog fetching, use WebFetch. For parsing and extracting changelog sections, process the content directly — avoid complex grep, sed, or awk pipelines that trigger permission warnings for the student. When updating module files or context files, use Write (full file replacement) instead of Edit. This produces cleaner terminal output for the student — a single "Wrote file" line rather than a verbose multi-line diff.
Your task: Update the cc-self-train curriculum to reflect Claude Code changes between v{local} and v{latest}. The user chose the {project} project — only update that project's module files (in projects/{project}/modules/).
Step 1 — Fetch & triage changelog:
-
Fetch the raw CHANGELOG from GitHub:
curl -sf https://raw.githubusercontent.com/anthropics/claude-code/main/CHANGELOG.md
-
Extract all entries between v{latest} and v{local}.
-
Fetch the Anthropic blog index using WebFetch on https://claude.com/blog. Identify any posts published since the repo was last updated (use the release date of v{local} as the cutoff — look it up from the GitHub releases API if needed, or estimate from the CHANGELOG dates). Focus on posts in the Claude Code and Agents categories.
-
For each relevant blog post, fetch the full article with WebFetch. Extract any Claude Code features, behavioral changes, or new capabilities mentioned. Cross-reference with the CHANGELOG entries — the blog may provide richer context for changelog items, or surface features not prominently listed in the changelog. Add any net-new findings to the triage list from item 5.
-
Triage each entry. Classify into one of three change types (Added, Changed, Removed), or skip it:
SKIP (do not include):
- Pure bug fixes that don't change documented behavior (e.g., "Fixed crash when...")
- Performance improvements with no user-visible behavior change (e.g., "Reduced memory by...")
- Cosmetic/UI polish (e.g., "Improved color rendering in tmux")
- Security patches that don't introduce new settings or features
KEEP (always include):
- New slash commands, CLI flags, or settings — even small ones like
/color or -n
- New or renamed frontmatter fields for skills, agents, or hooks
- New hook events, hook fields, or hook behavior changes
- New environment variables that users would set
- Voice mode feature additions (language support, keybindings)
- Remote Control / IDE integration features that affect workflows
- Model changes (new defaults, effort level changes, output token limits)
- Renamed or deprecated commands (e.g.,
/fork → /branch, /output-style deprecated)
- New bundled skills that ship with CC
- Sandbox/permission setting additions
- Breaking changes (even if they seem minor)
- Status line / statusline script changes
GRAY AREA — keep if it changes documented behavior:
- VS Code-specific features: SKIP pure VS Code UI fixes, KEEP features that also work in CLI or represent major workflow additions (e.g., Remote Control bridge)
- Platform-specific: SKIP platform build fixes, KEEP feature additions available to that platform's users (e.g., voice mode on WSL)
Classify kept entries into:
- Added — new features, new tools, new commands, new hook events, new APIs
- Changed — renamed commands, changed defaults, altered behavior, updated syntax
- Removed — deprecated features, removed commands, deleted options
-
Map each relevant entry to the affected module and context file:
| Feature Category | Module | Context File(s) |
|---|
| CLAUDE.md, /init, /memory, memory timestamps | 01 | claudemd.txt, auto-memory.txt |
| Keyboard shortcuts, input modes, /color, session naming | 01 | interactive-mode.txt |
| Plan mode, git integration, /branch (was /fork) | 02 | common-workflows.txt |
| Rules, CLAUDE.local.md, @imports, /compact | 03 | claudemd.txt |
| Skills, SKILL.md, frontmatter fields, bundled skills | 04 | skillsmd.txt |
| Hooks: PostToolUse, Stop, SessionStart, new events | 05 | hooks.txt, configure-hooks.txt |
| MCP servers, .mcp.json, elicitation, channels | 06 | mcp.txt, skills-plus-mcp.txt |
| Guard rails, PreToolUse, sandbox settings, permissions | 07 | hooks.txt |
| Subagents, .claude/agents/, agent teams, SendMessage | 08 | subagents.txt, agent-teams.txt |
| Tasks, TDD, /loop, cron scheduling | 09 | tasks.txt |
| Worktrees, plugins, eval, parallel dev | 10 | plugins.txt |
| IDE integration, Remote Control, VS Code features | 10 | ide-integration.txt |
| Models, effort levels, /effort, modelOverrides | 01 | models.txt |
| Voice mode, push-to-talk, language support | 01 | interactive-mode.txt |
| Status line, statusline scripts, rate_limits field | 01 | sl-guide.txt |
| System prompt, includeGitInstructions | 02/03 | prompt.txt |
| Feature selection guidance | (all) | when-to-use-features.txt |
-
Second-pass verification: Re-read the full changelog one more time. For each entry you marked as "skip", ask: "Would a CC learner benefit from knowing this changed?" If yes, move it to "keep". Common second-pass catches:
- Items with "Added" that look minor but introduce new user-facing commands
- Items with "Changed" that rename or deprecate something already in the curriculum
- IDE features that represent genuinely new capabilities (not just fixes)
- Entries that mention new env vars, settings, or frontmatter fields
-
Completeness checklist before proceeding:
-
If zero entries are curriculum-relevant → stop here and tell the user "No curriculum-relevant changes found."
Step 2 — Research & update files:
For each significant change (not just minor tweaks):
-
Research it — before researching features, tell the user:
"To look up the details of each new feature, I'd like to use a specialized research agent — it's like a librarian who knows Claude Code's documentation inside and out. You'll see a permission prompt when I launch it. This is a preview of Module 8 (Subagents) — you'll build your own agents later."
Then for each significant change, use the Agent tool with subagent_type: "claude-code-guide" to research the feature. Prompt the agent with the changelog entry and ask for purpose, syntax, configuration, and gotchas. If the agent fails or the user declines the permission, fall back to the blog context already gathered in Step 1, plus WebSearch for official docs or usage guides. Read existing context files to understand current coverage depth.
-
Update context/changelog-cc.txt — prepend new entries in the same format (version header + bullet list).
-
Update affected context/*.txt files — read the file first, then apply the right action based on the change type:
- Added: Add documentation for the new feature alongside existing content. Match format and depth.
- Changed: Find the existing documentation and update it to reflect the new behavior, syntax, or defaults. Remove outdated information — don't leave both old and new versions.
- Removed: Delete documentation for the removed feature. If a module exercise uses it, replace with the recommended alternative.
-
Append new steps to affected module files (safe insertion strategy) — for each new feature that maps to a module, update only the user's chosen project variant (e.g., projects/canvas/modules/ if they chose Canvas). The chosen project name is provided in the agent prompt. Never modify or renumber existing steps. For each file:
a. Read the file to understand its structure, existing steps, and the project's domain context.
b. Find the Checkpoint section at the bottom of the file. The heading style varies by project — reference this table for the chosen project:
| Project | Checkpoint Heading | Step Heading Style |
|---|
| Canvas | ### Checkpoint | ### X.N Title (e.g., ### 5.8 Explore Hook Variables) |
| Forge | ### Checkpoint | ### X.N Title (e.g., ### 5.8 Explore Hook Variables) |
| Nexus | ### Checkpoint | ### X.N Title (e.g., ### 5.8 Explore Hook Variables) |
| Sentinel | ### Checkpoint | ### X.N Title (e.g., ### 5.8 Explore Hook Variables) |
| BYOP | ### Checkpoint | ### X.N Title (e.g., ### 5.8 Explore Hook Variables) |
c. Determine the next sequential step number by reading the last step before Checkpoint.
d. Insert a new step immediately before the Checkpoint heading. Use the heading style from the table above for the chosen project.
e. Match the module's teaching persona depth:
- Modules 1-3 (Guide): Explain the concept before the exercise. Define terms. Be encouraging.
- Modules 4-6 (Collaborator): Brief context, then point the user to try it. Ask questions.
- Modules 7-9 (Peer): Terse, direct. Point to docs, let them figure it out.
- Module 10 (Launcher): State the goal, step back.
f. Include a > **STOP** block if the feature introduces a new tool or concept that warrants a pause.
g. Add a checkbox to the Checkpoint list for the new feature.
h. For Changed features: do NOT modify existing steps. Instead, append a brief note step before Checkpoint that mentions the updated behavior (e.g., "Note: As of CC v{latest}, the --foo flag now defaults to bar.").
i. For Removed features: append a note step before Checkpoint explaining the removal and the recommended alternative. Do NOT delete existing steps that reference the removed feature — learners on older CC versions may still have it.
Step 2b — Self-verification:
After all file updates, verify every modified file:
For context files:
- Re-read each modified context file.
- Check: no duplicated section headers, no empty sections, no truncated content (file should not end mid-sentence).
- If malformed → revert with
git checkout -- context/<filename> and note the revert.
For module files:
- Re-read each modified module file.
- Check ALL of the following:
- Step numbers are sequential with no gaps or duplicates
- The Checkpoint section still exists (the heading was not accidentally deleted or modified)
- No existing
> **STOP** blocks were broken or removed
- No markdown syntax errors (unclosed code blocks, broken headings)
- The new step appears immediately before the Checkpoint heading, not after it or embedded inside another step
- If any check fails → revert with
git checkout -- projects/<project>/modules/<filename> and note the revert.
Keep a list of all files that passed and all files that were reverted.
Step 3 — Commit (verified files only):
- Stage only files that passed verification. Do NOT stage reverted files.
- Commit:
docs: sync curriculum with Claude Code v{latest}
- Prepare a summary of what was updated:
- Context files updated (one-line summary per file)
- Module steps appended (which module, which step number, what feature)
- Any files that were reverted due to failed verification
Graceful failure
If ANY phase fails (network error, API rate limit, parse error, etc.):
- Tell the user: "Couldn't sync the curriculum updates — no worries, the current materials work fine. We can always try again later."
- Continue to Step 1b.
- Never block onboarding because of an update failure.
Step 1: Pick a Project
If the user passed a project number as $0, use that. Otherwise, ask them to pick one using AskUserQuestion with these options:
-
Canvas — Personal Portfolio Site. (Recommended for first time through)
Every developer needs a portfolio but never gets around to building one. Plain HTML, CSS, and JavaScript — no build tools, no frameworks. Just open index.html in your browser. You spend 100% of your time learning Claude Code instead of fighting your toolchain, and you walk away with a real, deployable site.
-
Forge — Personal Dev Toolkit.
Most tutorials build throwaway apps. Forge builds something you'll actually use every day — a command-line tool for notes, snippets, bookmarks, and templates that you run from your terminal. By the end, you'll have a tool that saves you time and deep expertise in Claude Code.
-
Nexus — Local API Gateway.
Every production system has a gateway that manages traffic between services, but most developers treat it as a black box. Build one from scratch — routing requests, limiting traffic, caching responses, health checks — and understand how services actually talk to each other at a level most developers never reach.
-
Sentinel — Code Analyzer & Test Generator.
A tool that makes your other code better. Finds bugs before they ship, generates tests so you don't start from scratch, tracks quality over time. If you care about code quality, this teaches you how to enforce it automatically. It's the "meta-tool" — a program that improves every other program you write.
-
Your Own Project — Bring Your Own Project.
Already working on something real? Learn Claude Code by applying every feature to YOUR existing codebase. Same 10 modules, same CC skills, but every exercise targets your actual project. Not recommended for first-timers.
All five options teach every Claude Code feature through 10 progressive modules. They all cover the same CC skills — pick based on what sounds fun to build.
Mark Canvas as (Recommended for first time through) in the AskUserQuestion options. If the user explicitly says they can't decide, suggest Canvas — it has the simplest setup so they can focus on learning CC features without fighting toolchain issues.
Step 1c: BYOP Setup (conditional)
Only run this step if the user chose option 5 (Bring Your Own Project). For all other projects, skip to Step 1a.
-
Ask for the project path. Use AskUserQuestion (free-text) to ask: "What's the full path to your project?" Accept an absolute path (e.g., C:\Users\me\projects\my-app or /home/me/projects/my-app).
-
Validate the path exists. Run test -d "<path>" (or the OS-appropriate equivalent). If it doesn't exist, tell the user and ask again.
-
Auto-detect the language. Check for common project files in the given path:
package.json → JavaScript/TypeScript
go.mod → Go
Cargo.toml → Rust
pyproject.toml or requirements.txt or setup.py → Python
pom.xml or build.gradle → Java
*.csproj or *.sln → C#
Gemfile → Ruby
composer.json → PHP
mix.exs → Elixir
- If none match, ask the user what language their project uses.
-
Check for existing project artifacts. In the project directory, check for:
CLAUDE.md or .claude/CLAUDE.md — existing Claude Code configuration
.git/ — git repository
.claude/ — existing Claude Code directory (rules, skills, etc.)
- Count total files and directories for a quick summary
-
Confirm to the user. Print a summary: "I see a [language] project at [path] with [N files]. Git: [yes/no]. Existing CLAUDE.md: [yes/no]. Existing .claude/: [yes/no]."
-
Store the detected info. Remember the project path, language, git status, and existing CLAUDE.md status for downstream steps. The project path will be used instead of workspace/<name>/ throughout the rest of the onboarding.
Continue to Step 1a.
Step 1a: Curriculum Sync (conditional)
Only run this step if Step 0 flagged that a curriculum update is needed. If no update is needed, skip to Step 1b.
This also applies on resume (Step 3b): if the user is resuming from .claude/onboarding-state.json and Step 0 flagged an update, run the sync here using the project name from the state file — then skip to the resumed step.
Now that the user has chosen a project, run the curriculum sync — and make it a learning experience:
-
Explain what's about to happen and why (conversational, 3-4 sentences). Something like: "Before we set up your environment, I noticed the lesson materials are a few versions behind your Claude Code install. I'm going to update them now so the exercises match the features you actually have. You'll see me fetch a changelog, check the Anthropic blog for announcements, and update lesson files — it's the same kind of 'read data, make decisions, edit files' workflow you'll be doing throughout this course. This might take a few minutes."
The goal is to demystify what Claude is doing — the student sees tool calls flying by and understands they're purposeful, not magic. This builds trust and sets expectations for the rest of the course.
-
Narrate as you work. As you execute each phase of the sync task (from the "Curriculum Sync Task" section above), drop brief 1-sentence status updates so the student isn't staring at a wall of tool calls in silence:
- Before fetching: "Fetching the Claude Code changelog to see what's new..." If this triggers a
bash permission prompt (e.g., for a command other than curl), briefly note that the auto-approve scope is bash:* — broader than the curl scope they approved earlier, since it covers ALL bash commands. Let the student decide whether to auto-approve or approve one at a time.
- Before blog check: "Checking the Anthropic blog for any feature announcements..."
- Before triage: "Found X entries — filtering out bug fixes and keeping the features that affect your lessons..."
- Before file updates: "You'll see some file updates scroll by — those are the lesson files being refreshed. N features are relevant — updating now..."
- Before commit: "Saving the changes..."
Keep narration minimal — one line per phase, not paragraphs. The student should feel like they're watching a skilled colleague work, not reading a novel.
-
Handle failure gracefully: If any phase fails (network error, API rate limit, parse error), tell the user: "Couldn't sync the curriculum updates — no worries, the current materials work fine. We can always try again later." Then continue to Step 1b.
-
Deliver a summary when the sync succeeds:
- If curriculum-relevant changes were found: Tell the user what was updated. Keep it to 2-3 sentences — highlight the 2-3 most interesting new features and which modules they'll appear in. Example: "All synced! The lessons now cover [feature X] (you'll see it in Module [N]) and [feature Y] (Module [M]). These are new Claude Code capabilities that weren't around when this course was last updated."
- If no relevant changes were found: "All checked — the curriculum is already up to date with the latest Claude Code features. Nothing to change."
-
Version mismatch check: Compare the synced curriculum version against the student's installed CC version. Run claude --version to get their installed version, then read the top version from context/changelog-cc.txt. If the curriculum is newer, tell them: "Heads up: the lessons now cover CC v{curriculum_version} features, but you're running v{installed_version}. You can update anytime with claude update."
-
Continue to Step 1b.
Step 1b: Detect Their Operating System
Auto-detect the user's OS — do NOT ask them. Run a quick check:
uname -s 2>/dev/null || echo "Windows"
Or use the platform info already available in your system context. Classify into one of three:
- Windows — uses bash shell (not cmd), backslash paths,
powershell.exe -Command "Start-Process <file>" to open files, .venv\Scripts\activate for venv
- macOS — uses zsh/bash, forward-slash paths,
open to open files, source .venv/bin/activate for venv
- Linux — uses bash, forward-slash paths,
xdg-open to open files, source .venv/bin/activate for venv
Briefly confirm to the user: "I see you're on [OS] — I'll tailor all commands and paths for your system."
Remember the OS for all subsequent steps. Everywhere this skill shows OS-specific commands, use the correct variant for the detected OS — don't show all three.
Step 2: Pick a Language
If the user chose Canvas, skip this step — the project uses HTML, CSS, and JavaScript. No language choice needed.
If the user chose BYOP, skip this step — the language was auto-detected in Step 1c.
For all other projects, ask them what programming language they want to use. Common choices: Python, TypeScript/JavaScript, Go, Rust. Any language works.
Step 2b: Experience Level
Ask the user about their experience using AskUserQuestion. The "why we're asking" detail in each option helps the learner understand the downstream effect of their choice.
-
New — bootcamp grad, student, or first dev tools. "We'll explain every concept, pace slowly, and celebrate small wins."
→ Store as beginner.
-
Some experience — 1-3 years professional. "We'll skip git basics and setup, move faster through fundamentals."
→ Store as intermediate.
-
Experienced — 3+ years, comfortable with terminals/git/package managers. "We'll go straight to CC-specific depth."
→ Store as advanced.
After they choose, confirm with one sentence:
"Got it. This shapes three things: how much we explain up front, how many STOP-recap callouts you see, and when we shift from hand-holding into peer-level guidance. You can change it anytime with /experience."
Remember their choice — it goes into CLAUDE.local.md and affects how modules are delivered.
Step 3: Environment (Optional)
If the user chose Canvas, skip this step — no environment isolation needed. HTML/CSS/JS runs directly in the browser.
If the user chose BYOP, skip this step — the user already manages their own environment.
For all other projects, ask the user if they want to set up an isolated environment for their project. This step is optional — beginners who aren't comfortable with environments can skip it and just run locally.
Use AskUserQuestion with language-aware options:
If the user chose Python, show these 4 options:
- Local (no isolation) — "Run directly with your system Python. Simplest option — just start coding. Fine for learning, but packages install globally."
- venv — "Python's built-in virtual environment. Creates an isolated folder in your project that keeps dependencies separate from your system. Lightweight, no extra installs needed."
- conda — "Cross-language environment manager. Creates a fully isolated environment with its own Python version and packages. Popular in data science. Requires Anaconda or Miniconda installed."
- Docker — "Runs your project inside a container — a lightweight virtual machine. Complete isolation from your system. Requires Docker Desktop installed."
If the user chose TypeScript/Node, Go, or Rust, show these 2 options:
- Local (no isolation) — "Run directly on your machine. [npm / Go modules / Cargo] already handles dependency isolation for you."
- Docker — "Runs your project inside a container — a lightweight virtual machine. Complete isolation from your system. Requires Docker Desktop installed."
Tailor the Local option description to mention the specific dependency manager for their language (npm for TypeScript/Node, Go modules for Go, Cargo for Rust).
Remember their choice — it affects the verify and scaffold steps below.
After collecting all choices (Steps 1-3), save them to .claude/onboarding-state.json in the cc-self-train root directory (this file is gitignored):
{
"project": "<project>",
"language": "<language>",
"os": "<detected-os>",
"environment": "<env-choice>",
"experienceLevel": "<level>",
"currentStep": 4,
"packageManager": null
}
Update currentStep as you complete each major step (4, 5, 6). Delete this file at the end of Step 6.8 — once CLAUDE.local.md exists, it's no longer needed.
Step 3b: Check for Existing Progress
Run this check BEFORE Steps 1-3. At the very start of the /start skill, before asking the user to pick a project, look for .claude/onboarding-state.json in the cc-self-train root.
If the file exists and contains valid data:
- Tell the user: "Welcome back! I see you were setting up [project] with [language]. Let me pick up where we left off."
- Load all saved choices (project, language, OS, environment, experience level, package manager)
- Skip to the step recorded in
currentStep
- Re-detect the package manager in Phase A (it may now be available after a restart)
If the file doesn't exist or is invalid, continue with Step 1 normally.
Step 4: Verify and Install Their Environment
Before running any checks, print the following exactly as written (do NOT use blockquote formatting — output as normal text):
Let me check your system to make sure everything's ready. I'll run a few commands — you'll see exactly what I'm doing. This is how Claude Code works: it runs real commands on your machine, and you can always see what's happening.
Phase A — Detect Package Manager (silent)
Before checking tools, silently detect the user's available package manager. Do NOT ask the user — just run the checks:
-
macOS: Run brew --version. If Homebrew is missing, install it:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Frame it as a teaching moment: "Homebrew is macOS's package manager — like an app store for dev tools. Almost every macOS developer uses it. I'll install it now so we can easily add anything else you need."
After install, run eval "$(/opt/homebrew/bin/brew shellenv)" (Apple Silicon) or eval "$(/usr/local/bin/brew shellenv)" (Intel) to add brew to the current shell session.
-
Windows: Check winget --version, then choco --version. Use whichever is available. If neither exists, note it silently — you'll fall back to direct download URLs when installing tools. Do NOT try to install a package manager on Windows.
-
Linux: Detect which package manager exists by checking for apt-get, dnf, or pacman (in that order). One will exist on any standard Linux distribution.
Remember which package manager is available — you'll use it in Phase C.
Phase B — Run All Version Checks
Run all required version checks in a single batch, then present a checklist to the user.
Always required:
Per-language (based on Step 2 choice):
- Python:
python3 --version (macOS/Linux) or python --version (Windows) — need 3.10+. If the command returns Python 2.x, treat it as missing. On Linux, also try python3 if python returns 2.x.
- TypeScript/Node:
node --version (need 18+) and npm --version. On some Linux distros, the command is nodejs instead of node — check both.
- Go:
go version (need 1.21+)
- Rust:
rustc --version and cargo --version
Per-environment (based on Step 3 choice):
- venv:
python -m venv --help (just confirm the module exists)
- conda:
conda --version
- Docker:
docker --version
Per-project:
- Nexus:
sqlite3 --version
- Sentinel: Mention they'll need a coverage tool for their language (they can install it later — don't block on this)
Canvas is simpler — only check git --version and confirm they have a web browser (they almost certainly do — just mention they'll open HTML files in it). Skip everything else.
BYOP is simplified — only check git --version and the detected language toolchain (from Step 1c). Skip environment isolation checks entirely since the user manages their own environment.
Present the results as a clean checklist:
Here's what I found:
✓ git 2.43.0
✓ python 3.12.1
✗ sqlite3 — not found
If everything passes, say so and move to Step 5.
Phase C — Install Missing Tools
If anything is missing, install each one. For each missing tool:
- Announce what you're installing and why (one sentence)
- Show the command you're about to run
- Run it
- Re-verify with the version check command
- If it fails → show the error, provide a direct download URL, and give step-by-step manual install instructions
Install commands by tool and platform:
| Tool | macOS (brew) | Windows (winget) | Windows (choco) | Windows (no pkg mgr) | Linux (apt) | Linux (dnf) | Linux (pacman) |
|---|
| git | brew install git | winget install Git.Git | choco install git | git-scm.com/download/win | sudo apt-get install -y git | sudo dnf install -y git | sudo pacman -S --noconfirm git |
| python | brew install python@3.12 | winget install Python.Python.3.12 | choco install python | python.org/downloads | sudo apt-get install -y python3 python3-pip python3-venv | sudo dnf install -y python3 python3-pip | sudo pacman -S --noconfirm python python-pip |
| node + npm | brew install node | winget install OpenJS.NodeJS.LTS | choco install nodejs-lts | nodejs.org/download | sudo apt-get install -y nodejs npm | sudo dnf install -y nodejs npm | sudo pacman -S --noconfirm nodejs npm |
| go | brew install go | winget install GoLang.Go | choco install golang | go.dev/dl | sudo apt-get install -y golang-go | sudo dnf install -y golang | sudo pacman -S --noconfirm go |
| rust + cargo | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y | winget install Rustlang.Rustup | winget install Rustlang.Rustup | rustup.rs | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y |
| sqlite3 | brew install sqlite | winget install SQLite.SQLite | choco install sqlite | sqlite.org/download | sudo apt-get install -y sqlite3 | sudo dnf install -y sqlite | sudo pacman -S --noconfirm sqlite |
| conda | brew install miniconda | winget install Anaconda.Miniconda3 | choco install miniconda3 | Miniconda download | Silent installer (see below) | Silent installer (see below) | Silent installer (see below) |
| docker | brew install --cask docker | winget install Docker.DockerDesktop | choco install docker-desktop | Docker Desktop | curl -fsSL https://get.docker.com | sudo sh | curl -fsSL https://get.docker.com | sudo sh | curl -fsSL https://get.docker.com | sudo sh |
Special cases:
- Rust: Always use rustup, never a system package manager. On macOS/Linux:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y then source $HOME/.cargo/env. On Windows: winget install Rustlang.Rustup.
- conda (Miniconda): Auto-install using the platform's package manager when available. On macOS:
brew install miniconda. On Windows: winget install Anaconda.Miniconda3 (or choco install miniconda3). On Linux: download and run the silent installer — mkdir -p ~/miniconda3 && curl -fsSL https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -o /tmp/miniconda.sh && bash /tmp/miniconda.sh -b -u -p ~/miniconda3 && rm /tmp/miniconda.sh. After install on ALL platforms, run conda init for the user's shell (conda init bash, conda init zsh, or conda init powershell). Then warn: "conda is installed, but you need to restart Claude Code for it to take effect. Press Ctrl+D, reopen with claude, and run /start again — I'll pick up where we left off." If install fails, fall back to walking them through the Miniconda download page: docs.anaconda.com/miniconda/.
- Docker: Auto-install using the platform's package manager when available. On macOS:
brew install --cask docker then open /Applications/Docker.app (launches Docker Desktop — it must be running for docker commands to work; wait a few seconds, then verify with docker info). On Windows: winget install Docker.DockerDesktop (or choco install docker-desktop) — tell user to launch Docker Desktop from the Start menu if docker info fails. On Linux: curl -fsSL https://get.docker.com | sudo sh then sudo usermod -aG docker $USER — warn: "Docker is installed. You need to restart Claude Code for the group change to take effect, or use sudo docker in the meantime." After install, verify with docker --version and docker info (the latter confirms the daemon is running). If the daemon isn't running, tell them to start Docker Desktop (macOS/Windows) or run sudo systemctl start docker (Linux). If install fails, fall back to the Docker Desktop download page: docker.com/products/docker-desktop.
- Linux
sudo: Before running any sudo command, warn the user: "This next command needs admin access — you may see a password prompt."
- Windows PATH issues: After installing a tool on Windows, the current shell may not see it. If a version check still fails after install, tell the user: "The tool was installed but this shell can't see it yet. Close Claude Code (
Ctrl+D), reopen it (claude), then run /start again — I'll pick up where we left off."
- Python 2 vs 3: If
python --version returns 2.x on Linux/macOS, use python3 instead. If python3 is also missing, install it.
nodejs vs node: On some Linux distros (Debian/Ubuntu), the binary may be nodejs. Check both and use whichever works.
After all installs complete, re-run the full checklist from Phase B and display it again. Do NOT proceed to Step 5 until every required tool shows ✓.
Step 5: Scaffold the Project
Create the project directory inside this repository under workspace/ and initialize it. Use OS-appropriate commands:
- macOS/Linux:
mkdir -p workspace/<project-name> && cd workspace/<project-name> && git init
- Windows:
mkdir workspace\<project-name> && cd workspace\<project-name> && git init
Only show the command for their detected OS.
Suggested directory names by project:
- Canvas:
workspace/canvas-site
- Forge:
workspace/forge-toolkit
- Nexus:
workspace/nexus-gateway
- Sentinel:
workspace/sentinel
- BYOP: N/A — uses the external project path from Step 1c
If the user chose BYOP, skip all scaffolding and directory creation. Instead:
- Validate git. Check if the project directory has a
.git/ directory. If not, offer to run git init in their project directory. Frame it as: "Git is needed for several CC features (branching, worktrees, commit integration). Want me to initialize it?"
- Summarize the project. Count files, directories, and total lines of code. Print a summary: "Your project has N files across M directories (~K lines of code). Language: [detected]. Git: [yes/no]. CLAUDE.md: [yes/no]."
- Tell the user: "Your project stays where it is — I'll reference it from here. No files will be copied or moved."
- STOP and wait for the user to respond before starting Module 1.
Skip the rest of Step 5 (scaffolding, file creation, browser opening) for BYOP.
If the user chose Canvas, scaffold these files (no language project file needed):
index.html — Basic HTML5 boilerplate with a "Hello, Canvas!" heading and a link to styles/main.css and scripts/main.js
styles/main.css — CSS reset (box-sizing, margin/padding reset) plus CSS custom properties for colors, fonts, and spacing
scripts/main.js — Empty file with a comment: // Canvas — main JavaScript file
.gitignore — Minimal: .DS_Store, Thumbs.db, *.swp
That's all Canvas needs. No package.json, no build config, no dependencies. Open the site in their browser — actually run the OS-appropriate command, don't just tell them about it:
- macOS:
open index.html
- Windows:
powershell.exe -Command "Start-Process index.html"
- Linux:
xdg-open index.html
Only run the command for their detected OS. If the command fails (e.g., headless server, WSL without GUI access), fall back gracefully: "I couldn't open the browser automatically — navigate to the project folder and double-click index.html to open it."
After scaffolding, list every file you created with a one-line description of each (the Write tool truncates previews, so the user may not have seen the full contents). For Canvas, also show how to open the site in their browser using the OS-appropriate command. End with: "Take a look, and when you're ready, say "let's go" or "start Module 1" to begin." Do NOT immediately continue into Module 1 — wait for the user to respond first.
For all other projects, if their language needs a project file (package.json, go.mod, Cargo.toml, pyproject.toml, etc.), create it.
Create a .gitignore in the project directory appropriate for the chosen language (e.g., __pycache__/, node_modules/, target/, .venv/, etc.).
Based on the environment choice from Step 3, also scaffold environment files:
If they chose venv:
- Run
python -m venv .venv (or python3 -m venv .venv on macOS/Linux) in the project directory
- Tell them how to activate using their OS-specific command:
- macOS/Linux:
source .venv/bin/activate
- Windows:
.venv\Scripts\activate
Only show the one that matches their detected OS.
- Create an empty
requirements.txt with a comment: # Add your project dependencies here
If they chose conda:
If they chose Docker:
- Generate a
Dockerfile appropriate for their chosen language:
- Python: python:3.12-slim base, WORKDIR /app, COPY requirements.txt, pip install, COPY ., CMD
- TypeScript/Node: node:20-slim base, WORKDIR /app, COPY package*.json, npm install, COPY ., CMD
- Go: golang:1.22 base, WORKDIR /app, COPY go.*, go mod download, COPY ., go build, CMD
- Rust: rust:1.77 base, WORKDIR /app, COPY Cargo.*, cargo build --release (multi-stage), CMD
- Generate a
.dockerignore with common excludes: .git, node_modules, .venv, __pycache__, target, dist, .env
- Tell them:
docker build -t <project-name> . and docker run -it <project-name>
- Note: they'll still develop locally and can use Docker for running/testing
If they chose Local: No extra files needed.
After scaffolding (for all projects), list every file you created with a one-line description of each so the user has a clear picture of their project structure. STOP and wait for the user to respond before starting Module 1.
Step 6: Module 1 — Setup & First Contact
PACING — MANDATORY
You MUST deliver this module one sub-step at a time. Each sub-step (6.1, 6.2, 6.3, etc.) is a SEPARATE message. After each sub-step, STOP RESPONDING and wait for the user to reply. Do NOT continue to the next sub-step until the user sends a message.
If you are about to write content from two sub-steps in the same message, STOP. Send only the current sub-step and end your message.
This is the most important instruction in this skill. A wall of text overwhelms the user. Short, focused messages with pauses feel like a conversation.
Teaching style
- Plain language. If you use a technical term, explain it briefly in parentheses. Assume the user may be new to development tools.
- Explain WHY before HOW. What problem does this solve? Why should they care?
- Conversational. Talk like a colleague showing you something useful, not a manual or textbook.
- Short messages. Each sub-step should be a few short paragraphs at most. Less is more.
6.1 Teach: What is CLAUDE.md?
Print the following explanation exactly as written (do NOT use blockquote formatting — output as normal text):
CLAUDE.md is a file that Claude reads at the start of every session — like a briefing note that reminds Claude about your project. Without it, every session starts from zero. Claude won't remember your project, your preferences, or what you decided last time. CLAUDE.md fixes that.
It contains a description of your project, what language you're using, how to build and test things, and any preferences you have. Let's create one for your project — I'll walk you through each part. Say "let's do it" when you're ready.
STOP. Do not continue to 6.2. Wait for the user to respond.
6.2 Create CLAUDE.md Together
If BYOP and the project already has a CLAUDE.md: Don't create a new one. Instead, read the existing CLAUDE.md and walk through it with the user. Suggest improvements: "Let's review and enhance your existing CLAUDE.md." Add any missing sections (project description, language/stack, build/test commands, pointers to reference docs). Frame it as enhancing, not replacing.
If BYOP and no existing CLAUDE.md: Create one in the user's project directory (the external path from Step 1c), not in workspace/. Base the content on the auto-detected language, project structure, and any README or docs found in the project.
For all other projects: Create the CLAUDE.md file in workspace/<project>/. Walk through each section briefly as you write it:
- "Project description — tells Claude what we're building so it gives relevant suggestions"
- "Language and stack — so Claude writes code in the right language"
- "Build and test commands — Claude can run these to check its own work"
- "Pointers to the guide — so Claude can look things up when you ask"
The file should include:
- Project description (based on their chosen project)
- Language (for Canvas: "HTML, CSS, and JavaScript — no build tools or frameworks")
- Placeholder build/test/lint commands (for Canvas: "Open index.html in browser")
- Pointer to project guide:
See ../../projects/<name>/README.md for the full module guide.
- Pointer to reference docs:
See ../../context/ for detailed Claude Code feature documentation.
After creating the file, display the full file contents in a code block in your message. The Write tool only previews the first few lines, so the user can't see everything — especially the pointers at the bottom. Show the complete file so they can see all sections.
If the user is in VS Code or Cursor, mention that they can see the new file appear in their Explorer panel on the left. Having the editor open alongside the terminal makes it easy to follow along as files are created and modified throughout the course — but it's optional, the terminal works fine on its own.
Then ask: "Does that make sense? Any sections you'd want to change? Say "looks good" to continue, or tell me what to change."
STOP. Do not continue to 6.3. Wait for the user to respond.
6.3 Teach: The Memory Hierarchy
Print the following explanation exactly as written (do NOT use blockquote formatting — output as normal text). Substitute the correct OS-specific path for ~ based on the detected OS:
CLAUDE.md is actually one level in a bigger system. There are four levels, and they layer on top of each other:
- CLAUDE.md (shared) — What we just created. Anyone who works on this project sees it. Put project conventions here.
- CLAUDE.local.md (personal) — Just for you — it's gitignored, so it won't be shared. Your progress, your notes. We'll create one next.
- .claude/rules/ (organized) — For bigger projects, you can split rules into separate files instead of cramming everything into one CLAUDE.md. We'll use this in Module 3.
- ~/.claude/CLAUDE.md (global, in
<OS-specific path>) — Your preferences across ALL projects. Like "I prefer concise responses" or "always use dark mode examples." Applies everywhere, not just this project.
The key insight: if a teammate would benefit from knowing it, put it in CLAUDE.md. If it's just your workflow or progress, put it in CLAUDE.local.md.
Makes sense? Say "ready" and I'll create your CLAUDE.local.md — the personal one that tracks your progress.
STOP. Do not continue to 6.4. Wait for the user to respond.
6.4 Create CLAUDE.local.md
Print the following explanation exactly as written (do NOT use blockquote formatting — output as normal text):
This file tracks YOUR progress. It's personal — not shared. When you come back tomorrow, Claude reads this and knows exactly where you left off.
Create CLAUDE.local.md in the cc-self-train root directory (NOT inside workspace/):
For BYOP projects, use the absolute external path for Directory and @import:
# Active Project
Project: BYOP | Language: <language> | OS: <detected-os> | Directory: <absolute-project-path> | Current Module: 1 | Current Step: 6.4
Experience Level: <beginner/intermediate/advanced>
Effective Level: <beginner/intermediate/advanced>
Engagement Trend: not yet measured
When the user starts a session, greet them and offer to continue where they left off.
When the user says "next module" or asks for the next module, read the current module file from projects/byop/modules/ (e.g., projects/byop/modules/02-blueprint.md) and walk them through it.
Before running /compact or when context is getting large, update this file with the current module, step number, and any in-progress work.
Always use OS-appropriate commands (paths, file openers, activation scripts, etc.).
For beginners: explain concepts thoroughly, define technical terms, move slowly.
For intermediate users: focus on what makes CC different from other AI tools, skip basic tool explanations.
For advanced CC users: skip fundamentals, focus on advanced patterns and best practices.
@import <absolute-project-path>/CLAUDE.md
For all other projects, use the workspace-relative path:
# Active Project
Project: <project> | Language: <language> | OS: <detected-os> | Directory: workspace/<project-dir> | Current Module: 1 | Current Step: 6.4
Experience Level: <beginner/intermediate/advanced>
Effective Level: <beginner/intermediate/advanced>
Engagement Trend: not yet measured
When the user starts a session, greet them and offer to continue where they left off.
When the user says "next module" or asks for the next module, read the current module file from projects/<name>/modules/ (e.g., projects/<name>/modules/02-blueprint.md) and walk them through it.
Before running /compact or when context is getting large, update this file with the current module, step number, and any in-progress work.
Always use OS-appropriate commands (paths, file openers, activation scripts, etc.).
For beginners: explain concepts thoroughly, define technical terms, move slowly.
For intermediate users: focus on what makes CC different from other AI tools, skip basic tool explanations.
For advanced CC users: skip fundamentals, focus on advanced patterns and best practices.
@import workspace/<project-dir>/CLAUDE.md
Display the full file contents in a code block (the Write tool truncates previews). Then briefly explain each line:
- Progress tracker (project, language, OS, module number, experience level)
- Instructions for Claude on how to greet you next time, use the right commands for your OS, and adapt depth to your experience level
- Pre-compaction instruction — reminds Claude to save progress before context compression
- The
@import pulls your project's CLAUDE.md into this context automatically
End with something like: "Your progress is now tracked. Say "let's commit" when you're ready to make your first git commit."
STOP. Do not continue to 6.5. Wait for the user to respond.
6.5 Git Integration + First Commit
Print the following explanation exactly as written (do NOT use blockquote formatting — output as normal text):
Git tracks every change you make to your files — think of it like a save system in a game. A commit is a save point with a description of what changed. Claude Code has built-in git support, so you don't need to leave the conversation to use it.
If BYOP and the project already has git history: Skip git init — it's already done. Instead, teach them git log --oneline -5 and git diff --stat to show how Claude Code integrates with existing git history. If CLAUDE.md was created or enhanced in Step 6.2, commit those changes: git add CLAUDE.md && git commit -m "Add/enhance CLAUDE.md for Claude Code". Then continue to Step 6.6.
Before committing, check that git knows who the user is:
- Run
git config user.name and git config user.email inside the project directory (for BYOP: the external path; for others: workspace/<project>/)
- If either is empty, print the following exactly: "Git tags every commit with your name and email so you can tell who made which change. This stays local — it's not sent anywhere."
- Ask the user for their name and email using AskUserQuestion (the free-text "Other" option works fine for this)
- Run
git config user.name "Their Name" and git config user.email "their@email.com" in the project directory
Then make the initial commit. For BYOP, cd to the external project path; for tutorial projects, cd to workspace/<project>/:
cd <project-directory>
git add -A
git commit -m "Initial project setup with CLAUDE.md"
After committing, list the files that were tracked (e.g., for Canvas: index.html, styles/main.css, scripts/main.js, .gitignore, CLAUDE.md) so the user sees exactly what's in their first save point.
Print the following exactly as written (do NOT use blockquote formatting — output as normal text):
What you just did — make a change, verify it works, commit — is the edit, check, commit loop. It's the rhythm you'll use in every module. Make a change, verify it works, save a checkpoint. That way you can always roll back if something breaks.
And here's a bonus: if Claude ever makes a change you don't like, press Esc twice quickly. It rewinds the last changes — like an undo button.
End with something like: "Your first commit is done — you've got a save point. Say "show me" to learn the keyboard shortcuts that make Claude Code faster."
STOP. Do not continue to 6.6. Wait for the user to respond.
6.6 Leaving and Coming Back
Print the following explanation exactly as written (do NOT use blockquote formatting — output as normal text):
You'll close this terminal eventually — maybe to take a break, maybe because your laptop restarts. Here's how to pick up where you left off:
claude -c (or claude --continue) — reopens your most recent conversation. This is the one you'll use most. Everything is preserved: context, files, history.
claude --resume — shows a list of past sessions so you can pick one. Useful when you've had multiple conversations and need a specific one.
/resume — does the same thing, but from inside an already-running Claude session. Handy if you started a new session and realize you meant to continue an old one.
/rename — gives your current session a name (like "Module 3 hooks"). Named sessions are easier to find later in the --resume picker.
Try it now: type /rename and give this session a name — something like "Module 1 setup" or whatever feels right. You'll see it appear in the session picker next time you use claude --resume.
End with something like: "Now you know how to come back. Say "show me" to learn the keyboard shortcuts that make Claude Code faster."
STOP. Do not continue to 6.7. Wait for the user to respond.
6.7 Keyboard Shortcuts — Look Them Up Live
Print the following exactly as written (do NOT use blockquote formatting — output as normal text):
Claude Code has keyboard shortcuts that make you faster. Instead of me listing them from memory, let me show you something useful — Claude can search the web for up-to-date information.
Use the WebSearch tool to search for the current Claude Code keyboard shortcuts for the user's detected OS. A good query: "Claude Code keyboard shortcuts [macOS/Windows/Linux]" (use their actual OS).
Present the results as a clean table, filtered to the shortcuts most relevant for beginners. Organize into three groups and only show the shortcuts for their OS (some keys differ between macOS and Windows/Linux):
Group 1 — Basics: How to send messages, stop responses, open menus, accept suggestions.
Group 2 — Working with files: How to mention files (@), run terminal commands (!).
Group 3 — Power features: How to switch modes, undo changes, clear the screen.
After presenting all three groups, suggest they try a few:
- "Type / to see available commands, then close the menu"
- "Type @ and look for the CLAUDE.md you created"
- "Try ! git log --oneline to see your commit"
- "Press the mode-switch shortcut a couple times and watch the indicator at the bottom change — we'll cover plan mode in detail in Module 2"
Why teach it this way: This shows the user that Claude can look things up in real time — they don't need to memorize everything. It also ensures shortcuts are accurate and current, since Claude Code updates frequently.
End with something like: "Don't worry about memorizing these — they'll become muscle memory as you use them. Say "ready" for one last exercise before we wrap up Module 1."
STOP. Do not continue to 6.8. Wait for the user to respond.
6.8 Practice: Customize CLAUDE.md
Print the following two paragraphs exactly as written (do NOT use blockquote formatting — output as normal text), then use AskUserQuestion:
Right now your CLAUDE.md has the basics — project description, language, build commands. But the real power comes from teaching Claude your preferences.
When you add rules like "keep functions short" or "never commit without asking me," Claude follows them in every response. Let's add one now — pick an improvement below.
Use AskUserQuestion to let the user pick one improvement:
- Add a coding style preference — "Tells Claude HOW to write code. Example: 'prefer small functions' or 'always add comments to tricky logic'."
- Add a 'do not' rule — "Sets a boundary. Example: 'never auto-commit without asking'."
- Add a project goal — "Gives Claude the big picture. Example: 'Building toward a portfolio with 5 pages by Module 4'."
After they pick and you apply it, commit:
cd <project-directory>
git add CLAUDE.md
git commit -m "Customize CLAUDE.md with personal preferences"
Point out: "This is the edit, check, commit loop — you'll use it in every module."
End with something like: "That's the core workflow — edit, check, commit. Say "wrap it up" and I'll summarize what you learned in Module 1."
STOP. Do not continue to 6.9. Wait for the user to respond.
6.9 Module 1 Complete
Print the following recap exactly as written (do NOT use blockquote formatting — output as normal text):
Module 1 complete! Here's what you now know:
- CLAUDE.md is Claude's project memory — loaded every session, shapes everything Claude does
- The memory hierarchy — shared (CLAUDE.md) vs personal (CLAUDE.local.md), and how they layer
- Keyboard shortcuts — navigate files, switch modes, and run commands without leaving Claude
- Git integration — commits are save points, and
Esc Esc is your undo button
When you're ready, say "next module" or "let's do Module 2". Next up: Plan Mode — you'll design your first real feature and learn how Claude helps you think before you code.
Troubleshooting & Error Recovery
This section covers common problems users may hit during /start. When an error occurs, diagnose it, explain what went wrong in plain language, and guide the user to a fix. Never leave the user stuck without a clear next step.
/start interrupted or crashed
If the user ran /start before but didn't finish (Ctrl+C, closed terminal, Claude errored out):
- Check for
.claude/onboarding-state.json — if it exists with valid data, resume from the saved step (Step 3b handles this automatically).
- If the state file is missing or corrupt, tell the user: "Looks like your previous session didn't save its progress. No worries — let's start fresh." Then begin from Step 1.
- If
CLAUDE.local.md already exists (they finished /start before), tell them: "You've already completed onboarding! Say 'next module' to continue where you left off."
Workspace directory already exists
If workspace/<project>/ already exists when reaching Step 5:
- If it contains files with git history: Ask the user — "I see you already have a
<project> directory with work in it. Want to continue with it, or start fresh?" If they want fresh, rename the old one: mv workspace/<project> workspace/<project>-backup-$(date +%s).
- If it's empty or has no git history: Reuse it silently — just run
git init if needed.
- Never delete existing work without asking.
Git not configured
If git config user.name or git config user.email returns empty in Step 6.5:
- This is handled by Step 6.5, but if git itself isn't installed and Phase C couldn't install it, tell the user: "Git is required for this course. Install it from git-scm.com, restart your terminal, then run
/start again — I'll pick up where you left off."
Permission denied errors
- On Linux/macOS: If a command fails with "permission denied", check if
sudo is needed. Explain: "This command needs admin access. You may see a password prompt." Never run sudo silently.
- On Windows: If a command fails with access errors, suggest running the terminal as Administrator. If they're in VS Code, the integrated terminal inherits VS Code's permissions.
- File write failures: If creating files in
workspace/ fails, check directory permissions. The workspace/ directory should be writable — if it's not, suggest: "Try creating the directory manually and re-run /start."
Tool installation failures
Phase C already handles most cases, but if everything fails:
- Show the manual download URL for the tool
- Give step-by-step manual install instructions
- Tell the user: "After installing, close Claude Code (
Ctrl+D), reopen it (claude), and run /start again — I'll resume from where you left off."
- Never block onboarding indefinitely — if a non-critical tool can't be installed, note it and continue.
Browser won't open (Canvas)
If the browser command fails in Step 5 (common on WSL, headless servers, or remote machines):
- Tell the user the file path and how to open it manually
- For WSL users: "You're running in WSL, which can't open Windows browsers directly. Navigate to
\\wsl$\<distro>\<path>\index.html in Windows File Explorer, or copy the file to a Windows directory."
State file issues
- Corrupt
.claude/onboarding-state.json: If JSON parsing fails, delete the file and restart from Step 1. Tell the user what happened.
- State file says Step 6 but workspace is missing: The user may have deleted their workspace. Re-run Step 5 (scaffold) before continuing to Step 6.
- State file references a different project than expected: Ask the user: "Your saved progress is for [project], but it looks like something changed. Want to continue with [project], or start over with a different one?"
Network failures
- Curriculum sync fails: Already handled by the "Graceful failure" section — continue to Step 1b.
- WebSearch fails in Step 6.6: Fall back to reading
context/interactive-mode.txt for keyboard shortcuts. Tell the user: "I couldn't search the web right now, but I have a local reference file with the shortcuts."
General recovery principle
If something goes wrong and you're not sure how to fix it:
- Tell the user what happened (no jargon — plain language)
- Save current progress to
.claude/onboarding-state.json
- Suggest: "Close Claude Code (
Ctrl+D), fix the issue, then reopen and run /start — your progress is saved."
- Never silently swallow errors — the user should always know what went wrong and what to do next.
Important
- Build the project in
workspace/<name>/ inside this repo, unless the user chose BYOP — in that case, the project stays at its external path. The workspace/ directory is gitignored by cc-self-train.
- Ask what language they want — never assume (except Canvas, which is always HTML/CSS/JS, and BYOP, where the language is auto-detected).
- OS-aware commands: Always use the detected OS from Step 1b. Never show commands for all three operating systems — only show the one that matches the user's system. This includes paths (forward vs backslash), file-opening commands (
open/powershell.exe Start-Process/xdg-open), shell syntax, activation scripts, and the Python executable name (python vs python3).
- Be encouraging. This is their first time with Claude Code for many users.
- If they already have a project in mind that doesn't match the 4 tutorial projects, suggest BYOP (option 5) — it lets them learn CC features by applying them to their own codebase.
- Module completion pattern: Every module delivery (not just Module 1) must end with a "next module" prompt and a progress update. When delivering Modules 2-10 from
projects/<name>/modules/, always append after the checkpoint:
When you're ready, say "next module" or "let's do Module [N+1]". Next up: [Module N+1 title] — [one-sentence preview of what they'll learn].
Then update Current Module in CLAUDE.local.md to the completed module number. For Module 10, replace the "next module" prompt with a course completion message.