"pitfalls":["Assuming every shell opens in the same place","Running a file command before checking the path"],
"scenarios":["Verify where you are before editing a file","Confirm location before launching a script"],
"troubleshooting_flow":["Confirm the working context","Run pwd","Use the output to choose the next command"],
"related_commands":["pwd","cd","ls"],
"classic_view":"Treat pwd as the command that restores orientation before every other action.",
"takeaways":["Know your location before acting","Read the full path instead of guessing","Use location to decide the next safe step"],
"after_class":"Repeat pwd before every directory-changing command until it becomes automatic.",
"exercises":[
{"id":"m1_l1_e1","type":"understanding","question":"Which command prints the full current working directory?","answer":"pwd"},
{"id":"m1_l1_e2","type":"operation","title":"Print the current working directory","hint":"Run pwd directly.","success_test":"cmd == 'pwd'","solution":["pwd"],"success_msg":"You verified the shell location correctly."},
{"id":"m1_l1_e3","type":"scenario","question":"If a script fails with 'file not found', what should you check first?","answer":"Run pwd and verify the current path before anything else."}
"pitfalls":["Thinking a hidden file does not exist because plain ls missed it","Reading long output without understanding permissions or size"],
"scenarios":["Check what files exist before deleting anything","Inspect a config directory for hidden dotfiles"],
"troubleshooting_flow":["List the directory first","Switch to ls -la if details matter","Use the listing to choose the next file command"],
"related_commands":["ls","find","stat"],
"classic_view":"Observation comes before diagnosis, and ls is usually the first observation tool.",
"takeaways":["Use ls for broad visibility","Use ls -la for hidden files and metadata","Treat the listing as evidence"],
"after_class":"Practice comparing ls and ls -la until you can explain why the outputs differ.",
"exercises":[
{"id":"m1_l2_e1","type":"understanding","question":"Why does ls -a reveal more than plain ls?","answer":"Because it includes hidden dotfiles."},
{"id":"m1_l2_e2","type":"operation","title":"List the current directory","hint":"Start with ls.","success_test":"cmd == 'ls'","solution":["ls"],"success_msg":"You listed the current directory."},
{"id":"m1_l2_e3","type":"operation","title":"Show hidden files and details","hint":"Use ls -la.","success_test":"cmd == 'ls -la' or cmd == 'ls -al'","solution":["ls -la","ls -al"],"success_msg":"You switched from a simple listing to a full inspection view."}
"pitfalls":["Forgetting -p for nested paths","Trying to touch a file under a missing directory"],
"scenarios":["Prepare a clean lab directory","Create a placeholder log or notes file"],
"troubleshooting_flow":["Check the target path","Create directories first","Create files after the path exists"],
"related_commands":["mkdir","touch","ls"],
"classic_view":"File-system work is safer when you change one layer at a time: path first, file second.",
"takeaways":["Use mkdir for structure","Use touch for placeholders","Think about parent directories before file creation"],
"after_class":"Rebuild the same directory tree twice until the path feels natural.",
"exercises":[
{"id":"m2_l1_e1","type":"operation","title":"Create a lab directory","hint":"Run mkdir /tmp/lab.","success_test":"cmd == 'mkdir /tmp/lab' and exists('/tmp/lab')","solution":["mkdir /tmp/lab"],"success_msg":"Your lab directory now exists."},
{"id":"m2_l1_e2","type":"operation","title":"Create a nested directory tree","hint":"Run mkdir -p /tmp/lab/data/raw.","success_test":"cmd == 'mkdir -p /tmp/lab/data/raw' and exists('/tmp/lab/data/raw')","solution":["mkdir -p /tmp/lab/data/raw"],"success_msg":"You created the nested path correctly."},
{"id":"m2_l1_e3","type":"operation","title":"Create a note file","hint":"Run touch /tmp/lab/notes.txt.","success_test":"cmd == 'touch /tmp/lab/notes.txt' and exists('/tmp/lab/notes.txt')","solution":["touch /tmp/lab/notes.txt"],"success_msg":"You created a new empty file in the lab path."}
"pitfalls":["Deleting before backing up","Changing permissions without checking metadata first"],
"scenarios":["Back up a config before editing","Make a script or directory executable when needed"],
"troubleshooting_flow":["Copy before editing","Rename with a purpose","Inspect metadata before permission changes"],
"related_commands":["cp","mv","chmod","stat"],
"classic_view":"File operations are safe when you can clearly name the step: backup, rename, inspect, or permission change.",
"takeaways":["Back up first","Rename with purpose","Inspect before changing permissions"],
"after_class":"Repeat the flow copy -> rename -> stat -> chmod on a temporary file until the sequence feels obvious.",
"exercises":[
{"id":"m2_l2_e1","type":"operation","title":"Back up the hosts file","hint":"Run cp /etc/hosts /tmp/hosts.bak.","success_test":"cmd == 'cp /etc/hosts /tmp/hosts.bak' and exists('/tmp/hosts.bak')","solution":["cp /etc/hosts /tmp/hosts.bak"],"success_msg":"You created a backup copy before any change."},
{"id":"m2_l2_e2","type":"operation","title":"Rename the backup file","hint":"Run mv /tmp/hosts.bak /tmp/hosts.backup.","success_test":"cmd == 'mv /tmp/hosts.bak /tmp/hosts.backup' and exists('/tmp/hosts.backup')","solution":["mv /tmp/hosts.bak /tmp/hosts.backup"],"success_msg":"You renamed the file successfully."},
{"id":"m2_l2_e3","type":"operation","title":"Inspect hosts metadata","hint":"Run stat /etc/hosts.","success_test":"cmd == 'stat /etc/hosts' and 'File:' in output","solution":["stat /etc/hosts"],"success_msg":"You inspected the file metadata successfully."}
"pitfalls":["Searching too broadly and ignoring context","Forgetting case-insensitive mode"],
"scenarios":["Find one user entry in passwd","Locate error lines in a log"],
"troubleshooting_flow":["Choose the right file first","Search for the smallest useful keyword","Use the matched lines to decide the next command"],
"related_commands":["grep","cat","tail"],
"classic_view":"grep turns a large text space into a small set of signals you can reason about.",
"takeaways":["Search deliberately","Narrow the signal before changing anything","Use matched lines as evidence"],
"after_class":"Practice moving from a broad keyword to a more precise keyword in the same file.",
"exercises":[
{"id":"m3_l1_e1","type":"operation","title":"Find sandbox_user in passwd","hint":"Run grep sandbox_user /etc/passwd.","success_test":"cmd == 'grep sandbox_user /etc/passwd' and 'sandbox_user' in output","solution":["grep sandbox_user /etc/passwd"],"success_msg":"You extracted the relevant passwd line."},
{"id":"m3_l1_e2","type":"operation","title":"Find error lines in syslog","hint":"Run grep -i error /var/log/syslog.","success_test":"cmd == 'grep -i error /var/log/syslog' and 'error' in output.lower()","solution":["grep -i error /var/log/syslog"],"success_msg":"You filtered the log down to the error lines."},
{"id":"m3_l1_e3","type":"scenario","question":"Why is grep usually faster than reading the whole log manually?","answer":"Because it narrows the file to only the lines that match the signal you care about."}
"pitfalls":["Searching from too high in the tree","Using cat on a large file when tail would answer faster"],
"scenarios":["Find config files under /etc","Inspect the newest auth log line"],
"troubleshooting_flow":["Pick the smallest reasonable root","Add a filter","Preview the most relevant file segment"],
"related_commands":["find","tail","head"],
"classic_view":"A good search ends with an exact path and a small, readable preview.",
"takeaways":["Use find for precise location","Use tail for fresh log evidence","Reduce noise early"],
"after_class":"Practice explaining the root path and every filter before you run find.",
"exercises":[
{"id":"m3_l2_e1","type":"operation","title":"Find configuration files under /etc","hint":"Run find /etc -name '*.conf'.","success_test":"cmd == \"find /etc -name '*.conf'\" and '.conf' in output","solution":["find /etc -name '*.conf'"],"success_msg":"You located configuration files recursively."},
{"id":"m3_l2_e2","type":"operation","title":"Find log files under /var/log","hint":"Run find /var/log -type f.","success_test":"cmd == 'find /var/log -type f' and '/var/log' in output","solution":["find /var/log -type f"],"success_msg":"You filtered the search to files under the log tree."},
{"id":"m3_l2_e3","type":"operation","title":"Read the newest auth log line","hint":"Run tail -n 1 /var/log/auth.log.","success_test":"cmd == 'tail -n 1 /var/log/auth.log' and 'sandbox_user' in output","solution":["tail -n 1 /var/log/auth.log"],"success_msg":"You previewed the most recent auth log line."}
"goal":"Spot busy processes and connect process views to system pressure.",
"why_it_matters":"Incidents often begin with 'the system feels slow', and process views turn that feeling into evidence.",
"concepts":["Process snapshots","CPU-heavy processes","Live system views"],
"command":"top / ps",
"examples":["top","ps aux --sort=-%cpu | head"],
"pitfalls":["Jumping straight to kill before understanding the process role","Looking at one snapshot without connecting it to symptoms"],
"scenarios":["Find the hottest process when CPU looks high","Explain which command gives the faster broad view"],
"troubleshooting_flow":["Look at top for the broad picture","Use ps sorting to confirm the hottest process","Only then decide the next action"],
"related_commands":["top","ps","kill"],
"classic_view":"System pressure is easier to reason about when you move from a broad live view to a specific process list.",
"takeaways":["Use top for the live picture","Use ps for a sortable snapshot","Diagnose before you terminate anything"],
"after_class":"Compare top and ps side by side and explain what each one is better at.",
"exercises":[
{"id":"m4_l1_e1","type":"operation","title":"Show a live overview","hint":"Run top.","success_test":"cmd == 'top' and 'load average' in output","solution":["top"],"success_msg":"You captured a live system overview."},
{"id":"m4_l1_e2","type":"operation","title":"List processes by CPU usage","hint":"Run ps aux --sort=-%cpu | head.","success_test":"cmd == 'ps aux --sort=-%cpu | head' and '%CPU' in output","solution":["ps aux --sort=-%cpu | head"],"success_msg":"You ranked processes by CPU usage."},
{"id":"m4_l1_e3","type":"understanding","question":"Why should kill come after observation rather than before it?","answer":"Because you need evidence about what the process is doing and whether it is safe to stop."}
"pitfalls":["Treating DNS, port, and app failures as one category","Checking a port without making a real request"],
"scenarios":["A local service looks up but the app still feels unavailable","You need to confirm whether the issue is address, reachability, port, or HTTP behavior"],
"troubleshooting_flow":["Check interface state with ip addr","Test connectivity with ping","Check sockets with ss","Validate the app layer with curl"],
"classic_view":"The cleanest network diagnosis moves from low-level reachability to the final application response.",
"takeaways":["Do not skip layers","Confirm a port before blaming the app","Use curl to verify user-facing behavior"],
"after_class":"Repeat the sequence ip -> ping -> ss -> curl until the layer transitions feel natural.",
"exercises":[
{"id":"m4_l2_e1","type":"operation","title":"Inspect interface addresses","hint":"Run ip addr.","success_test":"cmd == 'ip addr' and 'inet' in output","solution":["ip addr"],"success_msg":"You confirmed interface and address information."},
{"id":"m4_l2_e2","type":"operation","title":"Test local connectivity","hint":"Run ping 127.0.0.1.","success_test":"cmd == 'ping 127.0.0.1' and 'packet loss' in output","solution":["ping 127.0.0.1"],"success_msg":"You verified the local connectivity layer."},
{"id":"m4_l2_e3","type":"operation","title":"Validate the application response","hint":"Run curl http://127.0.0.1.","success_test":"cmd == 'curl http://127.0.0.1' and 'hello localhost' in output","solution":["curl http://127.0.0.1"],"success_msg":"You completed the network path all the way to the application layer."}