This is a submission for the GitHub Copilot CLI Challenge
What I Built
Quick question: what does find . -name "*.log" -mtime +7 -exec rm {} \; do?
If you had to think about it for more than two seconds, shelltutor is for you.
When I was 15, I taught myself to code by writing C++ and Python on paper, no laptop, no terminal, just notebooks. I'd mentally trace through loops and debug with a pencil. When I finally got access to a computer, the terminal was the first real interface I had. But even after years of building (I launched my first AI company at 17, and recently scaled a project to a 50GB data moat all bootstrapped from Addis Ababa), I still find myself googling the same shell commands. tar flags? Every single time.
shelltutor fixes this. It's an interactive CLI that teaches shell commands through hands-on challenges but with a twist that only became possible with Copilot CLI.
You get a task. You type a real command. And GitHub Copilot CLI evaluates whether your answer is functionally correct not just whether it's an exact string match.
If a challenge asks "find all files larger than 100MB" and the expected answer is find . -size +100M, but you type find . -type f -size +100M shelltutor marks you correct, because Copilot CLI understands your answer is actually more precise (it excludes directories). You don't get penalized for writing a better answer. That's impossible with traditional quiz apps.
The Aha Moment
I had the idea for a shell quiz app months ago. I even prototyped one. But I abandoned it because the answer checking was garbage ls -al would fail when the expected answer was ls -la. Same command, different flag order. I couldn't hard-code every valid permutation.
When I started exploring Copilot CLI for this challenge, I was using it as a development tool asking it to help me structure the project. Then I thought: what if the user's answer goes through Copilot CLI too?
I sent this prompt:
A student was asked: "List all files including hidden ones."
They answered: "ls -al". Expected: "ls -la".
Is this functionally correct?
Copilot CLI came back: CORRECT — flag order doesn't matter for ls.
That was the moment. The tool I couldn't build before suddenly became possible. Copilot CLI isn't a feature in shelltutor — it's the reason shelltutor can exist.
What's Inside
- 26 challenges across 8 topics: files, text processing, permissions, processes, networking, git, pipes, search
- 3 difficulty levels: beginner, intermediate, advanced
- Practice mode with 3 attempts per question, AI hints, and AI explanations
- Quiz mode — timed, one-shot, no hints
-
shelltutor explain— ask Copilot CLI to break down any command, anytime - Progress tracking with accuracy stats, streaks, and per-topic breakdown
Demo
GitHub Repository: https://github.com/Garinmckayl/shelltutor
Video Walkthrough
Explain any command in plain English:
Explain complex commands (tar, rsync, awk...):
Browse all 26 challenges:
The Explain Command — Better Than Man Pages
This is the gateway feature. Ask about any command and Copilot CLI breaks it down:
$ shelltutor explain "find . -name '*.log' -mtime +7 -delete"
╭──────────────────────────────────────────────────────────────╮
│ │
│ shelltutor — Learn the terminal, one challenge at a time │
│ Powered by GitHub Copilot CLI 🧠 │
│ │
╰──────────────────────────────────────────────────────────────╯
Command: $ find . -name '*.log' -mtime +7 -delete
╭ Explanation ──────────────────────────────────────────────────────────────╮
│ This command searches for and deletes old log files: │
│ │
│ **Breaking it down:** │
│ - `find .` - Search starting from the current directory (`.`) │
│ - `-name '*.log'` - Find files whose names end with `.log` │
│ - `-mtime +7` - That were modified more than 7 days ago │
│ - `-delete` - Delete those files │
│ │
│ **In plain English:** "Find all `.log` files in this directory and │
│ subdirectories that haven't been modified in over 7 days, and delete │
│ them." │
╰───────────────────────────────────────────────────────────────────────────╯
Powered by shelltutor + GitHub Copilot CLI
Compare that to man find. No contest.
Practice Mode — Learn by Doing
✓ GitHub Copilot CLI detected — AI-powered evaluation enabled 🧠
◎ Challenge #1
✨ [beginner] • Search & Find
┌───────────────────────────────────────────────────────────────────────────┐
│ Search for the word "ERROR" in all `.log` files in the current directory. │
└───────────────────────────────────────────────────────────────────────────┘
Your command: ls -la
✗ Not quite.
The command `ls -la` only lists files and directories with detailed
information. It does not search for text content within files. To search
for the word "ERROR" inside `.log` files, you need to use `grep`
(e.g., `grep "ERROR" *.log`), which searches file contents for the
specified pattern.
2 attempt(s) remaining. Type "hint" for help or "skip" to move on.
Your command: grep "ERROR" *.log
✓ Correct! ✨
Score: 1/1 (100%) 🔥 1 streak!
Notice how Copilot CLI doesn't just say "wrong" — it explains why ls -la doesn't solve the problem and points you toward grep. That's teaching, not testing.
Type hint when stuck — Copilot CLI generates a contextual hint without revealing the answer:
Your command: hint
╭ Hint ────────────────────────────────────────────────────────────────╮
│ Think about the `sed` command — it's a stream editor. The `-i` │
│ flag lets you edit files in-place. For the substitution pattern, │
│ you'll want the `s/old/new/g` syntax where `g` means global. │
╰──────────────────────────────────────────────────────────────────────╯
Quiz Mode — Test Under Pressure
$ shelltutor quiz -d intermediate -n 10
One attempt per question. No hints. Timer running. At the end:
╭──────────────────────────────────────────╮
│ │
│ Session Complete │
│ │
│ Score: 8/10 ████████████████░░░░ 80% │
│ Best streak: 5 🔥 │
│ │
│ ★ Excellent! │
│ │
╰──────────────────────────────────────────╯
Progress Tracking
$ shelltutor stats
♛ Your Progress
Total attempted: 47
Total correct: 38
Accuracy: ████████████████████████░░░░░░ 81%
Best streak: 12
Challenges done: 22
Topic Breakdown:
File Management ████████████████████ 6/7 (86%)
Text Processing ██████████████░░░░░░ 5/7 (71%)
Permissions & Ownership ████████████████████ 3/3 (100%)
Process Management ████████████░░░░░░░░ 4/6 (67%)
Networking ██████████████████░░ 4/5 (80%)
Git ████████████████████ 5/5 (100%)
Pipes & Redirection not started
Search & Find ████████████████░░░░ 5/7 (71%)
Try It Yourself
git clone https://github.com/Garinmckayl/shelltutor.git
cd shelltutor
npm install && npm run build
node dist/index.js practice -n 5
Works without Copilot CLI too (falls back to exact matching), but the experience is dramatically better with it.
My Experience with GitHub Copilot CLI
Copilot CLI Isn't a Feature — It's the Teacher
Most tools use AI as a nice-to-have. In shelltutor, removing Copilot CLI would fundamentally break the product. Here are the 5 distinct ways it powers the core experience:
1. Semantic Answer Evaluation
This is the feature I'm most proud of. Here's exactly what happens when you submit an answer:
// I don't do this:
userAnswer === expectedAnswer // ❌ Too brittle
// I send this to Copilot CLI:
const prompt = `A student was asked: "${challenge.description}".
They answered: "${userAnswer}".
The expected answer was: "${expectedAnswers.join(', ')}".
Is the student's answer functionally correct or equivalent?
Reply with CORRECT or INCORRECT, then explain why.`;
Copilot CLI then reasons about shell semantics:
-
ls -alvsls -la→ CORRECT (flag order doesn't matter) -
find . -type f -size +100Mvsfind . -size +100M→ CORRECT (more specific is still correct) -
grep -rn "TODO" src/vsgrep "TODO" src/→ INCORRECT (missing recursive flag changes behavior)
No regex or heuristic system can do this. It requires understanding what the commands actually do.
2. Dynamic Hints
Static hints get memorized and stop being useful. Copilot CLI generates fresh hints each time, calibrated to the specific challenge — without revealing the answer.
3. Post-Challenge Explanations
After every challenge, Copilot CLI provides a plain-English breakdown. One time it told me "the order of flags matters for find -delete" — exactly the kind of insight that separates understanding from memorization.
4. Freeform Command Explainer
shelltutor explain works on any command, not just challenges. It's a man replacement that speaks English:
shelltutor explain "tar -xzf archive.tar.gz -C /opt --strip-components=1"
shelltutor explain "awk -F: '{print $1}' /etc/passwd"
shelltutor explain "rsync -avz --exclude='node_modules' src/ backup/"
5. Personalized Learning Recommendations
After a session where you got questions wrong, Copilot CLI analyzes your weak areas and suggests what to practice next — specific techniques, not generic advice.
How Copilot CLI Helped Me Build It
Building a teaching tool requires getting the content right. I used Copilot CLI throughout the process:
Verifying challenge answers — Shell commands have many valid forms. For every challenge, I asked Copilot CLI "what are all the valid ways to accomplish X?" and added alternatives I'd missed.
Refining evaluation prompts — The semantic evaluation prompt took several iterations. Copilot CLI helped me tune the wording so it reliably distinguishes between functionally equivalent commands and genuinely wrong answers.
Catching edge cases — Copilot CLI pointed out I needed to handle re-attempts on previously failed challenges (remove from the
incorrectChallengeslist when the user finally solves them).
The Fallback Design
Without Copilot CLI, shelltutor still works:
- Answer checking falls back to exact string matching
- Hints use pre-written static text
- Explanations use built-in descriptions
But the gap is enormous. Exact matching means ls -al fails when the expected answer is ls -la. Static hints don't adapt. The AI version is what makes this a teaching tool instead of a trivia game.
Tech Stack
- TypeScript + Node.js
-
commander— CLI commands -
inquirer— interactive prompts -
chalk+boxen+ora— terminal UI - GitHub Copilot CLI (
gh copilot -- -p) — answer evaluation, hint generation, explanations, command explainer, learning recommendations - JSON file-based progress persistence
Top comments (0)