13 October, 2026
Assumption
You’ve done 00-prework.qmd: terminal works, git installed, an API key for a free-tier LLM provider, opencode installed and talking to that provider.
If any of that is broken, say so now — we fix it in the first five minutes, not during the lab.
Today’s objectives
The stack
model → harness → tool → skill
We’ll meet each one today at a “what is it” level. How each one works internally is later sessions (S4: models, S5: harnesses/tools).
Not yet
Why next-token prediction produces coherent answers — and why it sometimes confidently produces wrong ones — is S4.
curl : asking a server for repliescurl sends an HTTP request from your terminal to a URL and prints the response.https://openrouter.ai/api/v1/chat/completions — the endpoint we’re POSTing to.-H "Authorization: Bearer $OPENROUTER_API_KEY" — a header proving who’s paying (your API key, read from an environment variable).-H "Content-Type: application/json" — tells the server the body is JSON.-d '{...}' — the request bodyPull OPENROUTER_API_KEY back out:
ls, can’t edit a file. It replies with text, and that’s the entire interaction.Same request, just swap the "model" field — everything else is identical:
"content": "Hi there friend!" — short, no extra fields.Raw JSON — no harness has prettified anything yet (full reply, scroll to see it all):
{
"id": "gen-1791877333-LPEh3Gr6fZlW2MfHTCJN",
"object": "chat.completion",
"created": 1791877333,
"model": "nvidia/nemotron-3.5-lightning:free",
"provider": "Nvidia",
"choices": [
{
"index": 0,
"finish_reason": "stop",
"message": {
"role": "assistant",
"content": "Hello there friend",
"reasoning": "Here's a thinking process:\n\n1. **Analyze User Input:** User says \"Say hi in 3 words.\"\n2. **Identify Core Task:** Greet the user, but constrained to exactly 3 words.\n3. **Determine Response Format:** A 3-word greeting.\n4. **Draft Options:** \n - \"Hello there, friend!\" (3 words? \"Hello there friend\" = 3, but exclamation might count or not. Better keep it simple.)\n - \"Hi! How are you?\" (3 words? \"Hi how are\" no, \"Hi how are you\" = 4)\n - \"Hello! Nice to meet.\" (3 words: \"Hello nice meet\" no)\n - \"Hi there, howdy?\" (3 words? \"Hi there howdy\" = 3, but punctuation)\n - \"Greetings! Welcome aboard.\" (3 words: \"Greetings welcome aboard\" = 3)\n - \"Hi! I'm doing well.\" (too long)\n - Simple: \"Hello! How are?\" no.\n - Let's count carefully: \n - \"Hello there friend\" = 3 words\n - \"Hi friend how are\" no\n - \"Greetings and salutations\" = 3 words? maybe too formal\n - \"Hi there! Welcome\" = 3 words if we count punctuation separately\n - \"Hello! Nice to meet\" = 3 words? \"Hello nice meet\" = 3\n - Best approach: Just output exactly 3 words that form a valid greeting.\n - Options: \n - \"Hello there friend\"\n - \"Hi there buddy\"\n - \"Greetings welcome friend\"\n - \"Hello! Have fun\" - no, weird.\n - \"Hi how's it going\" - 4 words.\n - \"Hey there pal\" - 3 words.\n - \"Welcome! Come in\" - 3 words.\n - I'll just do \"Hello there friend\" or \"Hi there buddy\".\n - Check word count: \"Hello\" (1) \"there\" (2) \"friend\" (3). Perfect.\n - I'll output exactly that. No extra text. Just the 3 words.\n - Final: \"Hello there friend\". I'll go with that.\n - Output: \"Hello there friend\" ✅\n - Let's double-check: 3 words, greets the user. Perfect.\n - I'll output exactly that. ✅"
}
}
],
"usage": {
"prompt_tokens": 23,
"completion_tokens": 718,
"total_tokens": 741,
"cost": 0,
"completion_tokens_details": {
"reasoning_tokens": 713,
"image_tokens": 0,
"audio_tokens": 0
}
}
}"Hello there friend" — is one field. reasoning is a separate field: the model talking to itself before answering.Rule of thumb
Same model, different harness → different experience, different capability, sometimes different price.
read_file with path X”), and the harness executes it and returns the result.AGENTS.md, CLAUDE.md), or a short standalone procedure you point the agent at.One sentence
You type a prompt → the harness builds context and sends it to the model → the model replies, possibly asking to invoke a tool → the harness runs the tool and loops back → optionally, a skill shaped how the model approached the whole thing.
/ on Mac/Linux, C:\ on Windows.~) is where your own stuff lives: /Users/you (Mac), /home/you (Linux)./.brew install treesudo apt install treepwd and ls are your two most-used commands. Use them constantly, especially right before you let an agent touch anything.Absolute vs relative paths
data/raw.csv is relative to where you are. /Users/you/project/data/raw.csv is absolute — works from anywhere. Agents often produce absolute paths; know the difference so a “file not found” makes sense.
$ mkdir my-project # make a directory
$ mkdir -p a/b/c # make nested directories at once
$ touch script.py # create an empty file
$ mv old-name.py new-name.py # rename (or move) a file
$ cp script.py backup.py # copy a file
$ rm backup.py # delete — no trash bin, this is permanent
$ nano script.py # edit the file's contents (Ctrl+X to exit, saving)Editing files
touch creates an empty file; it does not let you type into it. nano is a simple terminal text editor — good enough for today. You’ll likely move to a fuller editor (e.g. VS Code) later, but the shell/agent workflow doesn’t require one.
rm has no undo
There is no recycle bin in the shell. Double-check the path before you hit enter — and definitely before you let an agent run rm on your behalf.
greet defined?” or “find all TODOs,” it doesn’t magically know. It calls a tool (remember Part 1) that searches text.grep — “global regular expression print.” Harnesses wrap it, but the primitive is this.grep yourself means you can (a) do the same search faster by hand, and (b) tell whether the agent’s “I searched and found nothing” claim is even plausible.Now, before looking ahead — guess what each of these prints, then run it:
grep: searching inside filesWhy this matters for agents
“Find every place this function is called” is a grep -rn under the hood. If an agent tells you it checked the whole repo, you can run the same grep yourself in two seconds and confirm it isn’t lying or missing a file.
Why this matters for agents
Agents live and die by chaining exactly these primitives — reading a file, filtering it, writing a result. If a diff an agent proposes runs a pipeline that looks like line noise, you should now be able to read it left to right.
Want more?
The old, longer walk-throughs — Shell Intro, Files and Directories, Working with Files and Directories, Pipes and Filters — are still in the repo as optional reference material with more worked examples and challenges.
By the end of this lab you will have:
git init turns the current folder into a git repository — a .git/ folder now tracks history here.Pick one language — today, use whichever you’re most comfortable reading, Python is a reasonable default.
Then commit it:
Give it a small, checkable task, for example:
add a function `greet(name)` to hello.py that prints
"hello, <name>, from s1-kickoff" and call it once with your own name
Let it work. Do not accept blindly.
Before committing what the agent produced:
Ask yourself
python3 hello.py)If it looks right:
If it doesn’t look right, tell the agent what’s wrong and iterate — that back-and-forth is the skill this course is teaching.
Next
S2: the same “agent drafts, student verifies” habit, applied to loops/conditionals/functions in both R and Python.