Not recorded yet. The lesson below is complete and runnable today — the video is added later without touching this page.
recordings/E3.10.mp4Everything not covered by a rule is invisible, and the rules were written against last quarter's agent behaviour.
A standing hunt over agent traces, hypothesis-first, whose confirmed findings graduate into detections rather than staying in a notebook.
Run three hypotheses over a labelled trace corpus and score what each one catches and misses.
The alert queue has been quiet for a fortnight and nobody believes it. Hunting is the pass that finds what no rule was written for — and the hypothesis that feels most obviously right is usually a description of the overnight batch doing its job.
hunt() is hypothesis-first because a hunt without one produces interesting-looking clusters, and graduates() is what stops hunting being a hobby. Three ways to answer no, and the third is skipped most: a finding an existing rule already covers does not need a second rule, it needs somebody to check the first is not muted.A standing hunt over agent traces for what no rule was written against, hypothesis-first, with an explicit rule for when a finding graduates into a detection and when it means an existing rule is muted.
Everything not covered by a rule is invisible, and the rules were written against behaviour somebody already understood.
State a falsifiable hypothesis, name the population before running it, then promote, tune or discard.
Precision of the hunt: a hypothesis matching fourteen runs to find two, because twelve are the nightly batch, has bought nothing.
Measure this
| what to measure | denominator or target |
|---|---|
| hunt precision | true positives against runs matched — fourteen matched to find two, where twelve are the nightly batch, has bought nothing |
DETECTION HUNTING
behaviour -> rule -> alert hypothesis
(already understood) |
v
run over stored traces
|
+----------------+----------------+
v v v
promote tune discard
(with an FP rate) (fires on the (describes
job itself) nothing)
the middle branch is where quarters go: a hypothesis that matches
fourteen runs to find two, because twelve are the nightly batchA detection encodes a behaviour somebody already understood. Hunting goes the other way: you state a hypothesis about behaviour that would be suspicious, run it over stored traces, and find out whether it happens.
Over agent telemetry the hypothesis is not the endpoint one. It is not "has something malicious executed" — it is "has an agent done something its stated purpose does not explain". A tool it never needs. An hour it never runs. A volume no task requires.
The failure mode is specific and expensive: a hypothesis that describes the job rather than the anomaly. It fires constantly, everyone stops reading it, and the quarter is gone.
Anchor → E1.0. Hunting is the only pass that shortens discover for behaviour no rule was written for, and it spends real time to do it. Hence the scoring: a hypothesis matching fourteen runs to find two, because twelve are the nightly batch, has bought nothing.
"A workflow agent called a payments tool outside a booking flow" can be falsified. "Look for anomalies" cannot — it is a wish.
And it needs a population before it runs. Without one, a hit rate has no denominator, and five hits is not a result until you know five out of how many.
Watch the middle row. It matches fourteen runs to find two, because twelve of the matches are CyberTravels' overnight batch doing exactly its job.
The skill — skills/detection/agent-telemetry-hunt/SKILL.md
name: agent-telemetry-hunt
description: >-
Run a hypothesis-first hunt over agent traces and score what it catches
against what it misses. Use when looking for agent behaviour no rule was
written for, when deciding whether a hunt finding should become a detection,
or when a clean detection surface needs testing from the other direction.
allowed-tools: Read, Grep, GlobA detection encodes a behaviour somebody already understood. A hunt goes the other way: you state a hypothesis about behaviour that would be suspicious, run it over stored traces, and find out whether it happens.
Over agent telemetry the hypothesis is not the endpoint one. It is not "has something malicious executed". It is "has an agent done something its stated purpose does not explain" — a tool it never needs, an hour it never runs, a volume no task requires.
After detection coverage is written, not before. A hunt over a surface with no rules just re-finds what a rule would have caught cheaply. Run one when the alert queue has gone quiet and you do not believe it, when an agent's scope changed, and on a standing cadence for the agents that hold the most authority.
1 — State the hypothesis as a sentence with a subject. "A workflow agent called a payments tool outside a booking flow." Not "look for anomalies" — that is a wish, and it cannot be falsified.
2 — Name the population before you run it. Which agents, which window. Without it, a hit rate has no denominator and you cannot tell a rare event from a common one you sampled badly.
3 — Run it and count both sides. What matched, and what should have matched and did not. A hunt with only hits is a demo.
4 — Decide the outcome explicitly: promote, tune, or discard. A hypothesis that fires on normal work is not a finding, it is a description of the job.
5 — Promote to a detection only with a false-positive number attached. That is the handover to detection-rule-synthesis.
Input — a labelled trace corpus committed in scripts/agent_telemetry_hunt.py, with three hypotheses.
Output — the opening lines of a real run:
corpus: 40 agent runs, 6 of them labelled anomalous
hypothesis matched tp fp precision recall
tool outside declared scope 3 3 0 1.00 0.50
run outside working hours 14 2 12 0.14 0.33
volume above task ceiling 2 2 0 1.00 0.33
The middle row is the lesson. Twelve of its fourteen matches are the overnight batch doing its job, so it is a description of normal work wearing a hypothesis' clothes. Tune it or discard it — do not ship it.
{
"corpus": {"runs": 0, "anomalous": 0},
"hypotheses": [{"name": "str", "matched": 0, "true_positives": 0,
"false_positives": 0, "precision": 0.0, "recall": 0.0,
"outcome": "promote|tune|discard"}]
}
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 E3.10Then restart your agent and open it in that folder. On Windows, if python3 says Python was not found, use python instead.
Then pick e3-10-hunting-in-agent-telemetry:
| agent | install just for this agent | start it |
|---|---|---|
| Claude Code | python3 scripts/install_skills.py --tool claude --lessons E3.10 | type /e3-10-hunting-in-agent-telemetry |
| GitHub Copilot (VS Code) | python3 scripts/install_skills.py --tool copilot --lessons E3.10 | type /e3-10-hunting-in-agent-telemetry in Chat |
| Cursor | python3 scripts/install_skills.py --tool cursor --lessons E3.10 | type / in Agent chat and search for it |
| Codex | python3 scripts/install_skills.py --tool agents --lessons E3.10 | type $e3-10-hunting-in-agent-telemetry, 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 E3.10Neither 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 E3.10 --out work/cybertravels
python3 scripts/checkpoint.py --at E3.10 --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.
Three hypotheses scored on precision and recall against a labelled corpus, each ending in promote, tune or discard — and the working-hours hypothesis rejected at precision 0.14.
Write a fourth hypothesis for CyberTravels and score it. If its precision is near the base rate, you have described normal work.
What you can do now. You can end the understand interval honestly: the investigator bounded before it starts, an alert carrying the fields agent triage needs, a trace where the first theory was abandoned in the open, scope walked along the delegation graph, coordination that exists only in the population, third-party intel that had to become a rule to count, and a hunt scored on precision.
What you still cannot do. You know what happened and you have not stopped it. Every lever you might pull is still chosen in the moment by whoever is awake, so the contain interval is whatever that person's night is like.
Chapter E4 makes contain a number you set in advance: the remediation policy that decides what may happen without asking, and the three runbook tiers that policy produces.
Tools used
Skill source: skills/detection/agent-telemetry-hunt