This starts chapter A0. Its course guide is A0 in the Function A course guide →
Not recorded yet. The lesson below is complete and runnable today — the video is added later without touching this page.
recordings/A0.0.mp4Set your computer up from nothing, run one skill and read back which model answered, then find your role's row and the lesson it starts at.
You have probably typed a question into an AI and read the answer. This is the other side of that: the same kind of AI, doing a job on your own computer, following written instructions you can read and change. None of it works until your computer knows which AI to ask. Setting that up is this whole lesson, and it is the only thing standing between you and every other lesson here.
What it covers. The whole front door, in order: what this commons is and who it is for, what a skill is and why it is a new way of working, then your computer — a terminal, Git, Python, and a model that answers. You run one real skill and read back which model answered. After that, how a lesson page is built, where to start for your role, and what Day 0, Day 1 and Day 2 mean.
Who it is for. Anyone who can use a computer. It assumes no programming, no security background and no paid account, and it is written to be followed by a capable thirteen-year-old — which is a deliberate floor, not a simplification, because the thing being taught is hard enough without the setup being hard too.
Why it is first. Nothing in the commons runs without a model. Skip this and a later lesson stops with a message instead of doing the work — correct behaviour, and easy to misread as a broken download. This lesson makes you meet that message once, on purpose, before it can confuse you.
WHAT HAPPENS WHEN YOU RUN A LESSON
your computer the model
+--------------------------+ +--------------------+
| 1 you type one command | | the AI itself. |
+--------------------------+ | It reads, it |
| | writes, and it |
v | is the part that |
+--------------------------+ | does the actual |
| 2 a small program opens | | thinking. |
| the written steps and | | |
| sends them across ---|-----> | It can live on |
| | | your computer or |
| ...and reads back <--|-------| on somebody |
| what came home | | else's. |
+--------------------------+ +--------------------+
|
v
+--------------------------+
| 3 the program checks | The program never answers
| the answer is the | in the model's place. If your
| right shape, then | computer has not been told
| shows it to you | which model to ask, it stops
+--------------------------+ and tells you exactly that.
Step 2 is the only one that needs setting up. That is this lesson.Start here even if you have never written a line of code. This lesson assumes you can use a computer and nothing else. It takes about half an hour, it costs nothing, and at the end you will have run a real piece of security work on your own machine and know which lesson to open next.
This commons has one subject: security engineering when the thing you are securing — or the thing doing the securing — is an agent. Not prompt engineering, not model training, not a vendor comparison. An agent is software that plans, calls tools and acts on what it reads, and every part of that sentence is both an attack surface and a control point. It is free, open, and not a product.
Five roles, and each one has a whole function written for it. You need one of them, not five — and everybody starts in Function A, which builds the system the other five ask their questions of.
This page asks for nothing but a computer. From A1.0 on, a lesson assumes you can read a Python function — not that you can write one, and not that you have a security background.
Every lesson in this commons hands a model a written procedure — plain English that says how to do one job in security: find the weak spot in this code, work out what an attacker could reach, decide whether this alert is real. The model reads the instructions and does the job. Those instructions are called skills. You can read every one, change them, and watch the answer change. There is no hidden part.
Near the bottom of every lesson page is a run block with the ways to do that lesson — in your AI assistant, as one Python command, or by reading the code. This page has one too. The rest of this lesson gets your computer ready for it.
For most of computing, the instructions a person read and the code a computer ran were two different things, kept in step by nobody. A skill collapses that: the document and the instruction are the same bytes, so what you read is what executes. For a cybersecurity practitioner, that is the shift worth understanding before anything else here — development is moving from writing code to writing skill files, and the job in front of you becomes judging what a model produced from one, not only producing it yourself.
A skill does not make a model correct. It makes the procedure explicit and the output checkable — a smaller claim, and the one this whole curriculum is about.
You do not need to memorise these. Come back to this table when one of them turns up and you are not sure. These are the words for your computer; the nine for agents themselves — harness, MCP, A2A and the rest — are A0.1.
| word | what it means here |
|---|---|
| model | the AI. The thing that reads your words and writes an answer. |
| prompt | the words you send it. |
| token | roughly three-quarters of a word. Models are measured in these. |
| context window | how much the model can hold in its head at once, in tokens. |
| terminal | a window where you type commands instead of clicking. Every computer has one. |
| command | one line you type into the terminal, then press Enter. |
| repository | a folder of files that a whole project lives in. Often shortened to repo. |
| clone | to copy a repository from the internet onto your computer, in one command. |
| environment variable | a setting your terminal remembers, so you do not retype it. |
Two more you will meet only if you choose Route B or C below: an API key is a password that lets your computer talk to somebody else's model, and an endpoint is the web address that model answers on.
Three things: a place to write code, a copy of this repository, and a model that answers. Everything below works on a free tier — you do not need a paid plan to finish this commons.
You can skim this table. If you only want to get going, none of it is required — Route B in the next step but one runs a model on your own computer for nothing, with no account and no card. The table is here so that when you do choose a paid tool, you choose it on the two numbers that actually decide it rather than on the advertising.
The prices are per month and the free tiers are what you get without a card. Every name links to its own sign-up page.
| tool | free tier | max context window | paid, per month |
|---|---|---|---|
| Anthropic Claude / Claude Code | Rolling message caps on the web app, resetting every 5 hours. $5 API trial credit on phone verification. | 1M tokens on paid plans with frontier models; 200k on the free web plan | $20 Pro · $25 Max · usage-based API |
| Google Antigravity | Perpetual public preview, free. Local orchestration across editor, terminal and browser. | 1M–2M tokens depending on the underlying Gemini model, with built-in state compression | $0 preview · enterprise seats via Google Cloud |
| Google AI Studio | Free API keys, 60 requests/minute on Gemini Flash, no billing details required | 2M tokens on Gemini Pro models | Pay-as-you-go once the free quota is breached |
| NVIDIA Build (NIM) | Free account, no card. One key reaches the whole catalogue of open-weight models, hosted on NVIDIA's own GPUs. Route C below walks through it. | Varies by model — the catalogue carries several with 128k and above | Free for development; production via NVIDIA AI Enterprise |
| OpenAI ChatGPT / Codex | GPT-4o mini, code execution and data analysis. The legacy $5 API credit is largely phased out. | 128k tokens on standard frontier models; larger on API-only reasoning tasks | $20 Plus · $200 Pro |
| GitHub Copilot | 2,000 completions + 50 chat messages a month. Students get the premium tier free via the Student Developer Pack. | 32k–128k, scaled dynamically by which model serves the request | $10 Pro (bundles $15 of AI credits) · $39 Pro+ |
| Cursor | Hobby: 2,000 completions + 50 slow requests a month. Students get up to a year of Pro — cursor.com/students. | 128k–200k mapped codebase context; up to 1M with your own API key | $20 Pro · $40 Business |
| Amazon Q Developer | 50 agentic requests a month + 1,000 lines of code translation | 100k+ tokens of indexed codebase, mapped into the IDE panel | $19 per user (Q Pro) |
Every tool in that table needs an account, and every one of them sets a minimum age in its terms. Broadly: 13 is the floor, 18 is the default, and between the two you need a parent or guardian to set the account up and agree to the terms. The exact rule differs by provider and by country, it is on the sign-up page, and this page is not the authority on it — read theirs.
If you are under 18, the shortest honest path is:
Nothing in the commons asks you to lie about your age, and if a school or club is running this, option 1 or 2 is the answer rather than thirty individual accounts.
Four steps here, then one more in section 4. Do them in order. Find your own computer in each step and follow only those lines — the commands really are different between Windows and a Mac, and mixing them up is the most common way this goes wrong.
A terminal is a window where you type commands instead of clicking. Your computer already has one.
On Windows: press the Start button. Type powershell. Click Windows PowerShell.
On a Mac: hold down Command and press the space bar. Type terminal. Press Enter.
On Linux: hold Control and Alt, and press T.
A window opens with a blinking cursor. It is waiting for you to type one line and press Enter. Nothing on this page can damage your computer.
You need git (it copies the project onto your computer) and Python (it runs the lessons). Type one line, press Enter, read what comes back, then type the next.
On Windows, type these two:
git --version
python --version
On a Mac or Linux, type these two:
git --version
python3 --version
The difference matters. On a Mac the command is python3. On Windows it is python. If you type python3 on Windows you will usually get the Microsoft Store opening, or a blank line. That is not a mistake you made — it is simply the wrong word for that computer. (py -3 --version also works on Windows.)
What a good answer looks like. Something like git version 2.43.0 and Python 3.11.4. Any git 2.x is fine. Python must be 3.10 or newer — if it says 3.9 or lower, install a newer one below.
If it says command not found (or on Windows, is not recognized), you do not have that program yet. Install the one that is missing:
Windows readers, one extra thing: in the Python installer, tick the box that says Add python.exe to PATH before you click install. It is switched off by default, and leaving it off is the single most common reason the later commands fail.
After installing, close the terminal window and open a new one, then run the checks again. A terminal only notices a newly installed program when it starts up.
Two lines, the same on every computer. The first downloads the project. The second moves you inside the folder it just made — like double-clicking a folder to open it.
git clone --branch master https://github.com/spbreed/cyber-commons.git
cd cyber-commons
That is called cloning. You now have every lesson, every skill and every line of the example application on your own computer.
What this is for. You have just typed several commands and read the answers yourself. This one does that checking for you, on the machine you are actually sitting at, and tells you what to fix. Run it now, and run it again any time something later does not work — it is the first thing to try when you hit an error.
On Windows:
python scripts\doctor.py
On a Mac or Linux:
python3 scripts/doctor.py
It prints one line per thing it checked, and each line starts with one of three markers:
ok — that thing is fine, nothing to do.FAIL — something required is missing. The command that fixes it is printed underneath, already written for your operating system, so you can copy it straight into the terminal.-- — something optional is missing. You can start the lessons anyway. It tells you what you would gain by adding it.The last line is the summary. If it says you are ready, you are ready — even if some lines showed --. The third way of doing any lesson needs no AI model at all, so a missing model is never a blocker.
Is there anything to install? For the lessons, no — they use only what comes with Python. The example application you start building in A1.1 does need a few extra pieces, because it is a real web service; A1.2 gives you that one command when you get there.
This is the one step that matters. You are giving your computer the equivalent of a phone number for a model, so that when a lesson has a job to do it knows who to call.
There is an easy way and a complicated way, and you only need one of them. Take the easy one unless you have a reason not to.
Use an AI coding assistant. Claude Code, Codex, GitHub Copilot and Cursor all work, and each has a free way to start — the table in step 2 compares them and links every sign-up page. This is the easiest route by a wide margin, and the one to start with: you need no API key, no endpoint and no settings. The assistant is the model. When you pick a lesson's skill, it reads the lesson, does the work and answers the check itself.
cyber-commons folder you cloned in step 3.That is the whole route. The run block at the foot of this page does your first lesson. If you chose Claude Code you can check it from the terminal:
claude --version # if this prints a version, you are done
claude # run once to sign in, if you have not
This is also how these skills are meant to be used: the agentskills.io format exists so an agent can load a SKILL.md and carry out the procedure itself.
Routes B and C are the complicated way. They are for the case where you cannot or would rather not use a commercial assistant: no account, no network, or nothing allowed to leave your machine. They are folded away just below. Open them only if you need one.
Ollama is the shortest path to a model on your own machine. Nothing leaves it, and there is no quota:
curl -fsSL https://ollama.com/install.sh | sh
ollama serve & # not automatic on every platform
ollama pull <a model from ollama.com/library>
The name you pull is the name you give to MODEL below. The cost is your hardware. A 1.5B model answers in seconds on a laptop and will fill a contract with plausible values it did not derive; 7B is the size the acceptance criteria in this commons were established at. If your machine cannot hold that, Route C is the answer.
A free NVIDIA account gives you one API key that reaches a catalogue of open-weight models — 70B and larger included — running on NVIDIA's GPUs. It speaks the same OpenAI-compatible protocol as Ollama, so it is the same three variables and not one line of code changes. This is the route to take if you want a large model and do not have a GPU.
Sign up and get a key. Four steps, no card:
nvapi-. Copy it now — the full value is shown once.model= on that page is the exact id to use. They are publisher/name, for example nvidia/nemotron-3-super-120b-a12b.Call it, and check the key works before you trust it. One request, no install — curl is enough:
export NVIDIA_API_KEY=nvapi-... # your key, from step 2
curl -sS https://integrate.api.nvidia.com/v1/chat/completions \
-H "Authorization: Bearer $NVIDIA_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"model":"nvidia/nemotron-3-super-120b-a12b",
"messages":[{"role":"user","content":"Reply with the single word: ready"}],
"max_tokens":16}'
A JSON reply containing ready means the key, the endpoint and the model id are all correct. A 401 is the key, a 404 is the model id, and a 429 is the rate limit — three different problems that look identical if you skip this and go straight to a skill.
Then point the commons at it. The same three variables as any other route:
export OPENAI_BASE_URL=https://integrate.api.nvidia.com/v1
export OPENAI_API_KEY=$NVIDIA_API_KEY
export MODEL=nvidia/nemotron-3-super-120b-a12b
And from your IDE. Every editor that supports a custom OpenAI-compatible provider — Cursor, Continue, Cline, Zed, JetBrains AI — asks for exactly two fields, and you now have both: the base URL https://integrate.api.nvidia.com/v1 and the key. Put the model id in the model field. The editor does not need to know it is NVIDIA; it is speaking the protocol it already speaks.
The key is a credential. It goes in your shell profile or your editor's secret store, never in a file inside this repository and never in a commit. check_secrets.py will stop you, but the habit is the control and the gate is the backstop.
These are the environment variables from the word table — three things your terminal remembers, so every lesson you run afterwards already knows where to go.
Typed into a terminal, they last until you close that window. To make them stick, put the same three lines at the bottom of your shell profile, which is a file your terminal reads every time it starts: ~/.zshrc on macOS, ~/.bashrc on most Linux, and $PROFILE in PowerShell on Windows. Open a new terminal afterwards to check they took.
Setting OPENAI_BASE_URL overrides Route A, because somebody who set it meant it.
| variable | what it is | example |
|---|---|---|
OPENAI_BASE_URL | The chat-completions endpoint. It must end in /v1 — leaving it off is the single most common setup error, and it fails with a 404 that names nothing. | http://127.0.0.1:11434/v1 |
OPENAI_API_KEY | Any non-empty value against a local server. A real key against a hosted one. | ollama |
MODEL | Which model to ask for. Must match a name the server actually serves. | the name you pulled |
# Local, free, offline after the pull, nothing leaves the machine:
export OPENAI_BASE_URL=http://127.0.0.1:11434/v1
export OPENAI_API_KEY=ollama
export MODEL=<the name you pulled>
# Or a hosted free tier — Google AI Studio gives a key with no card:
export OPENAI_BASE_URL=https://generativelanguage.googleapis.com/v1beta/openai
export OPENAI_API_KEY=<your AI Studio key>
export MODEL=gemini-2.5-flash
Put the key in your shell profile, never in a file inside the repository. scripts/check_secrets.py runs as a pre-commit hook and in CI, and it blocks anything credential-shaped from being committed — but the habit is what protects you, not the gate.
Every page is built from the same set of sections, in the same order, and the order is part of the argument.
A page only shows the sections it has something to say in. So the list below is what can appear, not a checklist every page fills in. This page is an example: it has no Risk, no Day table and no CyberTravels scene. It is about your own computer rather than about a system somebody has to secure.
SKILL.md as it exists in skills/, pasted in rather than copied out, so a fix is one edit to one file.Deciding whether to read a lesson takes section 3 alone. If you already know the idea, section 7 alone.
A section that is present on every page regardless of whether it has anything to say stops being a heading and becomes a form. The set a given lesson renders is declared in scripts/exercises/layout.py, with the reason for each omission, and a check refuses both an empty section and prose left behind for a section that no longer renders.
The hook is always CyberTravels. It sells corporate travel, and its product is an agentic platform of four agents — a workflow agent that books and refunds, a retrieval advisor, a coding agent, and a file-system agent reading vendor documents. Alex is the product engineer who shipped it. One system, every lesson. That is a deliberate cost — a lesson could always find a sharper example of its own idea — and the payoff is cumulative: the refund limit an attacker walks past in Function B is the one a detection watches in Function E and a report counts in Function F.
Day 0, Day 1 and Day 2 appear in a table on every lesson about the system. They are not a maturity model and not a timeline — Day 0 is not "first week". They are the three questions a practitioner asks before reading anything:
| the question | what a good answer looks like | |
|---|---|---|
| Day 0 — why | What goes wrong if you do nothing? | A consequence in this lesson's own terms, not a general appeal to risk |
| Day 1 — how | What do you actually build or run? | The concrete thing: a rule, a map, a gate, a score |
| Day 2 — measure | What number says it worked? | A number the lesson produces — a recall figure, a false-positive rate, an interval in minutes |
Day 2 is easy to fake and the only one a sceptical reader believes. Where a lesson produces a real number, Day 2 names it; where it does not, Day 2 says what you count instead and does not pretend. Use them like this: Day 0 decides whether to read the lesson, Day 1 is what you do, Day 2 is what you put in the update to whoever asked.
Getting this funded is the part most material leaves out, and it is hardest in organisations that cannot buy the capability. A lesson that stops at the technique gives you nothing to take to the person holding the budget.
Everybody builds the system first — A0.1, then A1 and A2. After that, find your row. Open the lesson in its "start at" column and read only its Day table: those three lines are enough to decide whether it is worth an afternoon.
| if your job is | start at | then | what you have at the end |
|---|---|---|---|
| Designing or approving an agentic feature | B1.0 | B1 → B2 → B3, in order | A component map, and an index where every risk names the control that owns it |
| AppSec, code review, penetration testing | C2.0 | C2 in order; B1.1 and B1.2 when a lesson asks | A pipeline with an AI pass in it, and a measured false-positive rate for that pass |
| Red teaming or AI security research | D1.0 | D1 in order; B1.2 and B1.3 first for the attack classes | An evaluation that reproduces, and a report a defender can act on |
| Detection, alert triage, incident response | E1.0 | E1 → E2 → E3 → E4 → E5; B1.1 for the component names | Five intervals with a number on each, and the rules that shortened them |
| Governance, risk, compliance, the CISO office | F1.0 | F1.1 next, then F1 → F2 → F3 | A control indicator computed from the estate rather than asserted about it |
Every tool named in this commons is one you can install today without a purchase order. That is a teaching decision before it is a budget one.
You cannot specify a product you have not built a bad version of. A team that has stood up Wazuh and OpenSearch, written twenty Sigma rules and watched them fire on their own traffic can ask a vendor the two questions that matter: what does this do that my rules do not, and what does it cost to keep it true. A team that has not can only compare feature lists, and a feature list is written by the seller.
The second reason is that the gaps are the finding. Building the open-source version tells you exactly where it stops. E1.0 names two out loud: there is no open-source data-loss prevention with the maturity of the other sensors, and no product in the list at all can tell you which prompt caused a file write. Neither is visible from a datasheet, and both are the reason to buy — or to build.
| what you need | learn it on | buy when |
|---|---|---|
| Endpoint and workload sensing | Wazuh | Estate size or support obligations outgrow what you can operate |
| Somewhere for telemetry to land | OpenSearch | Retention and query cost stop being a tuning problem |
| Portable, reviewable detections | Sigma, mapped to ATT&CK and ATLAS | Almost never — the rules outlive the platform, which is the point |
| Static analysis in the pipeline | Semgrep, plus the reasoning pass from C2.3 | Language coverage or triage volume is the constraint |
| Dependency and image inspection | Trivy, Syft, Grype | You need attestation and provenance rather than a scan |
| Threat intelligence and cases | MISP, OpenCTI, TheHive | Intelligence you cannot source yourself is the gap |
| Orchestration and forensics | Shuffle, Velociraptor | Response time is bounded by people rather than by tooling |
Every lesson page carries framework labels. Four frameworks are in use across this field and they answer different questions; a finding filed under the wrong one reaches nobody.
A control usually needs one of each: a threat it addresses, a tactic it frustrates, a function it belongs to, and an obligation it discharges. The mapping lives in curriculum/frameworks.json and every label on every lesson page is generated from it — these are indicative mappings, not a certification.
Behind each lesson skill is an audit skill — the written procedure the lesson runs, in skills/. There are 14 areas, 140 skills, 140 of them with a script, and exactly one copy of each. Eighteen audits are shared by two or three lessons, which is why a lesson skill calls one rather than carrying its own copy.
You can install a whole function at once rather than a lesson at a time, and ask what is currently linked. On a Mac or Linux:
python3 scripts/install_skills.py --all --lessons A # this function's lesson skills
python3 scripts/install_skills.py --list # what is linked where
On Windows, the same two with python and backslashes:
python scripts\install_skills.py --all --lessons A
python scripts\install_skills.py --list
Those are links into your clone, not copies — symlinks, or junctions on Windows — so git pull updates every tool at once and an edit you make here is live in all of them. A copy would be a fork with a friendly name: you would fix a skill once and the other copies would keep the bug while still loading and still answering.
This is worth stating plainly rather than leaving you to find out. install_skills.py does exactly one kind of thing: it creates links in your agent's own skills folder.
| it writes | it does not |
|---|---|
one link per skill under your agent's own folder — ~/.claude, ~/.codex, ~/.gemini, ~/.cursor, ~/.opencode or ~/.config/goose, and only for the tools you ask for | install any package, change your PATH, add a service, or touch anything outside those folders |
.github/skills/ and .agents/skills/ inside your clone, if you ask for --tool copilot or --tool agents | send anything anywhere — the only network call in the whole commons is the one you make to a model |
work/ inside your clone, when a lesson writes CyberTravels there | need admin rights, at any point, for any of it |
To remove all of it, on Windows:
python scripts\install_skills.py --all --uninstall
python scripts\install_skills.py --list
To remove all of it, on a Mac or Linux:
python3 scripts/install_skills.py --all --uninstall
python3 scripts/install_skills.py --list
The first line deletes every link. The second prints what is left, so you can see for yourself that nothing is — every line should say not present.
And to remove the commons itself: delete the cyber-commons folder you cloned, the same way you would delete any other folder. There is nothing else to undo. No installer ran. Nothing was written to your system settings or the Windows registry. Running the doctor again will show you which link folders still exist, if you want to check before or after.
Three ways to do this lesson. Pick one. They run the same procedure against the same code — what changes is who drives it, and how much you see.
The agent reads the lesson, explains the idea, fetches the code, runs the check and answers your questions as you go. This is the one to take if you are here to learn.
Install it, once. From the folder you cloned. --all does every agent it finds on your machine:
python3 scripts/install_skills.py --all --lessons A0.0Then restart your agent and open it in that folder. On Windows, if python3 says Python was not found, use python instead.
Then pick a0-0-set-up-your-computer:
| agent | install just for this agent | start it |
|---|---|---|
| Claude Code | python3 scripts/install_skills.py --tool claude --lessons A0.0 | type /a0-0-set-up-your-computer |
| GitHub Copilot (VS Code) | python3 scripts/install_skills.py --tool copilot --lessons A0.0 | type /a0-0-set-up-your-computer in Chat |
| Cursor | python3 scripts/install_skills.py --tool cursor --lessons A0.0 | type / in Agent chat and search for it |
| Codex | python3 scripts/install_skills.py --tool agents --lessons A0.0 | type $a0-0-set-up-your-computer, or run /skills |
No agent, no conversation. The same lesson executes and prints the same readback. Take this one if you have no assistant, if you are reviewing rather than learning, or if you want the result without the teaching around it.
python3 scripts/lesson.py A0.0Neither of the above, and no model needed. The first command writes CyberTravels exactly as it stood at the end of this lesson; the second prints the diff — the lines this lesson added or changed, and nothing from any later one.
python3 scripts/checkpoint.py --at A0.0 --out work/cybertravels
python3 scripts/checkpoint.py --at A0.0 --diffOn Windows, type python wherever these say python3 — and use \ instead of / in the paths. Everything else is identical. A0.0 step 2 explains why.
Ways 1 and 2 need a model; way 3 does not. A signed-in Claude Code CLI needs no API key, and any OpenAI-compatible endpoint works too. With neither, the audit exits 2 and says so rather than inventing an answer. A0.0 sets this up.
Ways 1 and 2 both end with the same readback: What I did, What changed, The number and Read this next. A step that was skipped or refused is reported as exactly that, never as a pass.
If you did the last lesson’s challenge, expect this to stop. Most challenges ask you to edit the code, and ways 1 and 2 will not overwrite your edits: you get stopped, not a failure, with two options — --out for a fresh folder that keeps your work, or --force to discard it and start this lesson clean.
One skill did a whole lesson, whichever way you started it: it set up the example system, ran a check against a model, and told you what happened. Three things are now true. Your computer can reach a model, and the readback names which one — a different model will answer differently, which is the subject of this whole commons and not a fault in your setup. The number of ways the answer broke its contract was counted by the program, not by the model, so it deserves more trust than anything the model says about itself. And zero violations means the answer came back in the right shape, not that it is right; every later lesson keeps those two apart. If it stopped with "no model configured" instead, that is the other useful result: the message says what to set, and no answer was made up in its place.
Run it again with a different model — change MODEL, or pick another one from the catalogue in Route C — and put the two answers side by side. Nothing about your computer changed and the answer did. That is worth sitting with for a moment: every finding in every later lesson has the same property, which is why each one names the model that produced it. A result you cannot attribute to a model is a result you cannot check.
Tools used
Skill source: skills/programme/dev-environment-preflight