Gamified, story-driven CLI trainer β learn by doing, in your real terminal or your browser.
Terminal Tutor replaces sprawling docs and copy-paste tutorials with quests β short, narrative missions where every beat of the story maps to a real command you run in your shell (or in the browser). It watches what you run, verifies it worked, and unlocks the next beat.
The web version runs entirely in your browser. No install, no setup. Looks and feels exactly like a real terminal.
π terminal-tutor.vercel.app
Features:
- xterm.js terminal emulator β real keyboard input, cursor, scrollback
- Simulated shell responds to
ls,cd,cat,git,gh,npm, and more - Saves progress to
localStorageβ quit any time, resume later
- Language: TypeScript
- CLI: Node.js with custom game engine
- Web: Next.js 14 (App Router) + xterm.js terminal emulator
- Storage: localStorage for progress persistence
π terminal-tutor.vercel.app
No installation required β just open and play!
# Requires Node 18+
git clone https://github.com/carlosfranzetti/terminal-tutor.git
cd terminal-tutor
npm install
node bin/tt.jsOr install globally:
gnpm link
# Now run 'tt' from anywhere
tt| Pack | Tool | Stories | Steps | Total XP |
|---|---|---|---|---|
| Ghost in the Shell | gh copilot |
3 | 25 | ~430 |
Three branching stories about using gh copilot explain and gh copilot suggest when you're stuck in the terminal.
| Story | Setting |
|---|---|
| Summon the Copilot | Standup in 20 minutes. Learn gh copilot before the sprint starts. |
| Debug at 3am | Production down. Cryptic error. Stack Overflow has nothing. You have Copilot. |
| The New Hire's Secret Weapon | Week 1. Impossible ticket. gh copilot suggest writes the commands you don't know yet. |
Each story has a branching decision point β your choice shapes the path through the quest.
| Key | Action |
|---|---|
Enter |
Run the command |
h |
Request a hint (β25% XP penalty) |
s |
Skip current step (no XP) |
q |
Quit and save progress |
A pack is a single .js file in quests/. Drop it in and it auto-loads at next launch.
// quests/my-pack.js
export default {
id: 'my-pack',
title: 'The Pack Title',
synopsis: 'One-line pitch.',
tool: 'my-cli',
stories: [
{
id: 'story-1',
title: 'Story One',
setting: 'One-liner shown in the story picker.',
steps: [
{
id: 'step-1',
narration: 'The story beat β second person, present tense.',
objective: 'What the player must do.',
verify: { mode: 'shell', stdoutContains: 'expected output', exitCode: 0 },
hints: ['Vague hint', 'More specific', 'Nearly explicit β try: `command`'],
xp: 30,
},
],
},
],
};steps: [
{
id: 'bp-1',
type: 'branch',
narration: 'Two paths appear before you.',
branches: [
{
label: 'Path A',
flavor: 'One-line description shown in picker.',
steps: [/* normal steps */],
},
{
label: 'Path B',
flavor: 'Alternative route.',
steps: [/* normal steps */],
},
],
},
],| Mode | What it checks |
|---|---|
shell |
Runs the command; evaluates exitCode, stdoutContains, stdoutMatches (regex), stderrContains, custom(result, input) |
which |
Checks a binary is on PATH (verify.binary) |
prompt |
Multiple-choice question (verify.choices, verify.answer or verify.answers[]) |
See CONTRIBUTING.md for the full authoring guide.
The web version lives in web/ β a Next.js 14 app with App Router and TypeScript.
web/
app/ Next.js app router
components/
TerminalGame.tsx xterm.js terminal + full game loop
lib/
quests/ Quest pack definitions (TypeScript mirrors of quests/)
shell-sim.ts Simulated shell (ls, git, gh, npm, β¦)
verifier.ts Predicate evaluation (same logic as CLI verifier.js)
xp.ts XP / level math
hints.ts Hint ladder + XP penalty
progress.ts localStorage progress store
types.ts Shared TypeScript types
cd web
npm install
npm run dev # http://localhost:3000
npm run build # production buildcd web
npx vercel --prodbin/tt.js CLI entrypoint
src/app.js CLI screens and flow
src/engine/ loader, runner, verifier, hints, progress, xp
src/ui/ theme, splash, browser, player, components
quests/ CLI quest packs (.js)
web/ Browser version (Next.js 14, TypeScript)
test/ Unit and integration tests
CLAUDE.md Repo guide for AI assistants
TDD.md Full technical design document
CONTRIBUTING.md How to add quest packs and contribute code
Contributions are welcome β bug fixes, new quest packs, and web improvements all appreciated.
The highest-leverage contribution is a new quest pack. A single well-written pack can teach an entire CLI tool to someone who's never touched it. See the Adding a quest pack section above for the format.
- Fork the repo and create a branch (
git checkout -b feat/my-quest) - Make your changes β quest packs go in
quests/, web mirrors inweb/lib/quests/ - Run the tests β all 27 must be green before you open a PR:
npm test - Play through your changes β launch
node bin/tt.jsand complete the quest end-to-end - Open a pull request with a short description of what the pack teaches and why it fits
- Quest narration is written in second person, present tense ("You stand at the gates...")
- Hints follow a three-tier ladder: vague concept β direction β near-explicit command
- Verification should be lenient β prefer
stdoutContainsand regex over exact matches - Keep quest packs under 200 lines; split into multiple stories if the scope grows
- Every new quest pack must have an
orderfield so it sorts correctly in the menu
Open a GitHub issue with:
- What you ran and what you expected
- What actually happened (paste the terminal output)
- Your OS and Node.js version (
node --version)
MIT β Carlos Franzetti

