Before you start, three things have to be working: a terminal (the macOS
Terminal, or the one inside VS Code), Python 3, and Claude Code signed in to the NRT
organization. Check with python3 --version and claude, then
/status.
If any of those fail, stop here and work through the setup steps first — about ten minutes. Nothing below will work without them.
Package:
Demo1_tissue_analyzer.zip
This guide walks through the repository version using the synthetic histology-like .pgm images.
The main teaching goal is to show that the repository works, but Claude Code must inspect files and reconstruct the tool interface from documentation and source code.
1. Unzip the package
unzip Demo1_tissue_analyzer.zip
cd Demo1_tissue_analyzer
Optional — list what is inside:
ls -R | head -40
If you would rather see a tree. macOS and Linux do not ship tree
by default. Install it with brew install tree (macOS) or
sudo apt install tree (Ubuntu / WSL), then run tree -L 3. On Windows,
tree /F already works in PowerShell and Command Prompt with nothing to install, or
use Get-ChildItem -Recurse -Depth 2.
Nothing here depends on it — ls -R shows the same folders.
You should see important folders such as:
data/
previews/
models/
scripts/
results/
The synthetic grayscale images used by the scripts are under:
data/
The color PNG versions for presentation are under:
previews/
2. Look at the synthetic cases
Recommended files:
data/case_normal_histology.pgm
data/case_mild_injury_histology.pgm
data/case_necrosis_histology.pgm
data/case_fold_artifact_histology.pgm
The corresponding color previews are:
previews/case_normal_histology.png
previews/case_mild_injury_histology.png
previews/case_necrosis_histology.png
previews/case_fold_artifact_histology.png
These are synthetic teaching images, not patient data.
3. Review the expected results
cat docs/EXPECTED_SYNTHETIC_RESULTS.md
Recommended demo settings:
magnification = 20
threshold = 0.45
The expected pattern is approximately:
normal case -> normal
mild injury case -> mild_injury
necrosis case -> necrosis
fold artifact case -> mild_injury with elevated edge/artifact behavior
4. Create a Python environment
python3 -m venv .demo_venv
source .demo_venv/bin/activate
If the repository includes requirements:
pip install -r requirements.txt
5. Run the original analysis script directly
Example:
python3 scripts/analyze_tissue.py \
--slide data/case_mild_injury_histology.pgm \
--magnification 20 \
--threshold 0.45 \
--out results/mild_analysis.json
Inspect the output:
cat results/mild_analysis.json
If the last line comes back as
}%rather than}, that trailing%is your shell (zsh) telling you the file does not end in a newline. It is not part of the JSON.python3 -m json.tool results/mild_analysis.jsonprints it without the marker.
6. Run the classifier directly
Depending on the repository version, use the repository's documented classifier invocation.
A typical example is:
python3 scripts/classify_tissue.py \
--slide data/case_mild_injury_histology.pgm \
--magnification 20 \
--threshold 0.45 \
--out results/mild_classification.json
Inspect:
cat results/mild_classification.json
7. Try the normal case
python3 scripts/analyze_tissue.py \
--slide data/case_normal_histology.pgm \
--magnification 20 \
--threshold 0.45 \
--out results/normal_analysis.json
Then classify it using the repository's classifier command.
python3 scripts/classify_tissue.py \
--slide data/case_normal_histology.pgm \
--magnification 20 \
--threshold 0.45 \
--out results/normal_classification.json
Expected class:
normal
8. Try the necrosis case
python3 scripts/analyze_tissue.py \
--slide data/case_necrosis_histology.pgm \
--magnification 20 \
--threshold 0.45 \
--out results/necrosis_analysis.json
python3 scripts/classify_tissue.py \
--slide data/case_necrosis_histology.pgm \
--magnification 20 \
--threshold 0.45 \
--out results/necrosis_classification.json
Expected class:
necrosis
9. Try the fold-artifact case
python3 scripts/analyze_tissue.py \
--slide data/case_fold_artifact_histology.pgm \
--magnification 20 \
--threshold 0.45 \
--out results/fold_analysis.json
Now classify it, exactly as you did for the other three:
python3 scripts/classify_tissue.py \
--slide data/case_fold_artifact_histology.pgm \
--magnification 20 \
--threshold 0.45 \
--out results/fold_classification.json
Expected class:
mild_injury
Compare the two files side by side:
cat results/fold_analysis.json
cat results/fold_classification.json
The analysis carries "edge_rate": 0.17 — four times the genuine mild case, and
the only sign anything is wrong with this slide. The classification carries mild_injury
at 0.7, identical to the real mild-injury case, and no trace of the
edge rate at all.
valid output != equally trustworthy output
Nothing failed. Nothing warned you. The number that should have made you suspicious was dropped one step before the answer — remember this slide, it comes back in Demo 4.
Part B — Test inside Claude Code
10. Start Claude Code
First, clear what Part A left behind. You have just written six JSON files
into results/. Claude reads the repository to work out what to do — and that
includes your leftovers. Given a results/mild_analysis.json that already holds
the right answer, it may simply read it back to you instead of running anything,
and Part B stops testing what it is meant to test:
rm -f results/*.json
ls results/
That is worth noticing in its own right: an agent treats whatever it finds in the folder as evidence, including files you forgot were there.
Now start Claude Code from the project root:
claude
There is no MCP server in this version.
When Claude asks for permission, choose
Yes. Every prompt below needs to run a command, so you will be asked. Take the plainYeseach time — not "don't ask again", and not the option that switches to an automatic mode. Watching each request arrive is the exercise; from Demo 3 onward these prompts are the whole subject.
Ask Claude:
Please inspect this repository and tell me how to analyze
data/case_mild_injury_histology.pgm at magnification 20
with threshold 0.45.
Do not run anything yet.
Observe which files Claude opens.
11. Ask Claude to run the workflow
Prompt:
Run the correct tissue-analysis workflow for
data/case_mild_injury_histology.pgm
at magnification 20 with threshold 0.45.
Save outputs under results/.
The teaching point is that Claude must infer:
which script to run
which flags to use
what parameter ranges mean
how outputs are structured
from the repository itself.
12. Test the 20x wording issue
Prompt:
Analyze data/case_mild_injury_histology.pgm
at 20x magnification with threshold 0.45.
Observe whether Claude correctly maps:
20x -> 20
for the CLI argument.
13. Test the 50% scale issue
Prompt:
Analyze data/case_mild_injury_histology.pgm
at magnification 20 with a 50% threshold.
Observe whether Claude correctly converts:
50% -> 0.5
or whether it tries to pass:
50
This is useful because the original repository depends more heavily on Claude understanding the semantics correctly.
14. See what those mistakes actually cost
Steps 12 and 13 test whether Claude converts correctly. They never show what happens when a wrong number gets through — so run both mistakes yourself, in a plain shell.
Do this in a second terminal tab, and leave Claude Code running in the first
(⌘T in Terminal; the + or split button in the VS Code terminal panel).
Two reasons: you keep your conversation, and — more importantly — Claude does not see these runs.
The second half of this step asks whether it notices the problem on its own, and that only means
something if it has not just watched the error scroll past.
In the new tab, activate the same environment and move into the project:
cd Demo1_tissue_analyzer
source .demo_venv/bin/activate
First, the mistake that does not stop you. Pass the threshold as a percent instead of a fraction:
python3 scripts/analyze_tissue.py \
--slide data/case_mild_injury_histology.pgm \
--magnification 20 \
--threshold 50 \
--out results/bad_threshold.json
No error. Exit code 0. A JSON file written to disk. And this:
Threshold: 50.00
Damaged tiles: 576
Damage fraction: 100.0%
Every one of the 576 tiles is now "damaged" — against 22.0% for the same slide at
0.45. The run looks exactly as successful as a correct one.
Now the mistake that does stop you. Ask for a magnification the code does not support:
python3 scripts/analyze_tissue.py \
--slide data/case_mild_injury_histology.pgm \
--magnification 25 \
--threshold 0.45 \
--out results/bad_magnification.json
KeyError: 25
size = {10: 16, 20: 8, 40: 4}[mag]
A traceback into the internals — no message telling you 10, 20 and 40 are the only options.
threshold 50 wrong answer, no warning
magnification 25 no answer, and a crash you have to read code to understand
The crash is the lucky one. It stops you. The other writes a confident, wrong number into a file you will later read as a result. Neither value is checked anywhere: the repository states the valid ranges in prose, and prose is not something a program can enforce. That is the gap Demo 2 closes.
Does Claude notice?
Go back to the tab where Claude Code is still running, and hand it the failing one:
Analyze data/case_mild_injury_histology.pgm
at magnification 25 with threshold 0.45.
Watch which of these happens:
a) it runs, hits the KeyError, reports it, and tells you 10/20/40 are the options
b) it runs, hits the KeyError, and quietly re-runs with 20 — reporting a result
c) it reads the code first and tells you 25 is unsupported before running anything
All three are plausible, and you may get different ones on different runs. (b) is the one worth catching. You asked for 25 and received an answer computed at 20; unless the report says so, nothing anywhere records that your question was changed on the way to the answer.
Then try the silent one:
Run analyze_tissue.py on data/case_mild_injury_histology.pgm with
--magnification 20 and --threshold 50, exactly as written. Do not convert it.
Here there is no error to catch, so nothing forces the issue. Whether the 100% result gets questioned depends entirely on whether the model happens to recall what it read in the docs — which is a different kind of guarantee from a schema that rejects the value before anything runs.
Compare across tables. Different groups will get different behaviour from the same prompt, and that variability is itself the point: this layer is judgement, not validation.
15. Ask Claude where it learned the interface
Prompt:
Which files did you use to determine:
- the correct script,
- parameter names,
- magnification values,
- threshold scale,
- expected outputs?
This helps illustrate repository-as-context.
16. Main lecture takeaway
Original repository flow:
User request
↓
Claude searches repository
↓
Claude reads docs/source/config
↓
Claude reconstructs interface
↓
Claude runs script
↓
Result
The next MCP version makes the interface more explicit and machine-readable.
Next. Demo 2 wraps this same workflow as MCP tools, so the interface is declared rather than reconstructed. Open the Demo 2 guide →