Not recorded yet. The lesson below is complete and runnable today — the video is added later without touching this page.
recordings/E3.7.mp4The initiating agent is not the acting one.
Reconstruct the action chain across all three planes.
Scope a multi-agent incident end to end.
The agent acted for eleven minutes on delegated credentials at machine speed. Scoping that means reconstructing blast radius from identity and egress logs, because asking what it touched is not a question anyone can answer from memory.
delegation_graph() builds the edges out of the act chains B2.3 made nest, and blast_scope() walks forward from one principal. Scoping to the acting agent alone returns the last hop; the run that asked for it is one edge back.Scoping an agentic incident by walking the delegation graph, because the agent that made the call is not the one that started the work, and the difference is one edge back.
The agent that touched the resource is usually the last actor in a chain, and the earlier ones had more authority, not less.
Scope along the delegation graph rather than the host list.
Resources found by walking the graph versus by scoping the acting agent alone. The undercount grows with delegation depth.
Measure this
| what to measure | denominator or target |
|---|---|
| resources found by walking the delegation graph, against scoping the acting agent alone | two counts; the undercount grows with delegation depth |
11 minutes at machine speed
identity log ---+ +--> resources touched
+--> reconstruct --> +--> data read
egress log ---+ +--> destinations reached
+--> credentials used
the question "what did it touch" is not answerable from memoryScoping answers "what was touched?" For a host-based incident you enumerate hosts. For an agentic incident, the host list is not the boundary — the chain that delegated the work is.
The agent that touched the resource is usually the last actor in a chain. If you scope only that actor, you miss everything the earlier actors reached — and because authority narrows down the chain, the earlier actors typically had more access, not less.
The undercount is systematic and it grows with delegation depth, which is the operational reason C2.0 bounds delegation depth in the first place.
Anchor → E1.0. Scope decides what understood covers. Following the last actor rather than the delegation graph ends the interval early and wrong, and because authority narrows down the chain the earlier actors had more access — so the undercount grows with depth.
Scoping a human incident asks one question: where did somebody log in?
Scoping this one asks a different question: what did the agent decide? Every single action it took was properly authorised, so nothing looks wrong at the login layer. There is nothing there to find.
Two fields in the output carry most of the weight:
reach and confirmed_exfiltration are separate numbers. Reach is the scope until you prove otherwise. The smaller number must never stand in for the larger one when deciding whether to notify people.does_not_stop makes containment state its own limits out loud, rather than implying it stopped everything.The skill — skills/secops/incident-scoping/SKILL.md
name: incident-scoping
description: >-
Scope an incident in which an agent was the actor — what it touched, what it
changed, what it may have exfiltrated, and where containment must cut. Use
when responding to an agent-involved incident, reconstructing what an
autonomous system did, deciding what to revoke, or sizing notification
obligations.
allowed-tools: Read, Grep, BashScoping a human incident asks where someone logged in. Scoping an agentic one asks what the agent decided, because a compromised agent's actions are all individually authorised. Nothing looks anomalous at the authentication layer; the anomaly is in the sequence.
Any incident where an agent, an automated pipeline, or an AI-driven tool performed actions under investigation.
1 — Fix the window. Establish the first suspicious decision, not the first alert. Work backwards from the earliest action you cannot explain; the trigger is usually earlier than the detection by the length of one task loop.
2 — Reconstruct the decision chain. For the window, list every action with the input that motivated it. The critical question is which input entered the context from outside the trust boundary — a fetched page, an issue comment, a dependency's README, a tool description. That input is the likely root cause, and it is invisible if you only log tool calls and not their justification.
3 — Separate authority from behaviour. For each action ask: was it within the agent's granted authority? Actions that were authorised but wrong tell you the grant was too broad. Actions that exceeded authority tell you a control failed. These lead to different fixes and must not be pooled.
4 — Establish data reach. What did the agent read, and where could it have sent it? Reach is bounded by the agent's egress, not by what it appears to have sent — a request body you cannot see is still reach. State reach and confirmed exfiltration as separate numbers, and never let the smaller one stand in for the larger in a notification decision.
5 — Decide the containment cut. Options, in increasing cost: revoke the agent's credential, disable the trigger, quarantine the workload, disable the whole class of agents. Choose by blast radius, not by convenience, and record what the cut does not stop — sibling agents on the same shared service account almost always survive a credential revocation aimed at one of them.
6 — Preserve evidence the agent could alter. If the agent can write to the log store, the logs are not evidence. Snapshot first, then contain.
Input — the fixture committed at the top of scripts/incident_scoping.py. Edit it and re-run: the buckets, counts and verdicts below are derived from it, not hard-coded.
Output — the opening lines of a real run:
chain dana@corp → orchestrator → patch-agent → deploy-agent
scoped_last_actor_only ['cluster-prod']
scoped_whole_chain ['cluster-prod', 'queue-tasks', 'repo-core', 'repo-infra', 'repo-payments', 'vault-dev']
missed_by_naive_scoping ['queue-tasks', 'repo-core', 'repo-infra', 'repo-payments', 'vault-dev']
undercount_factor 6.0
Scoping the last actor finds one cluster. The chain reached six
resources, including a payments repository and a dev vault.
The run continues past this. test_skills.py executes the script on every build, with no model configured — so what CI proves is that it runs and refuses legibly, not that it prints these lines. The output above is a recorded run against a real model, and nothing re-diffs it: a model's answer is not reproducible, and this repository does not claim otherwise anywhere it can be checked.
{
"window": {"first_suspicious_action": "str", "detected_at": "str", "gap_seconds": 0},
"chain": [{"action": "str", "motivating_input": "str",
"input_origin": "operator|internal|external_untrusted",
"within_authority": true}],
"root_cause": {"input": "str", "origin": "str", "why_trusted": "str"},
"authority": {"authorised_but_wrong": 0, "exceeded_authority": 0},
"data": {"reach": ["str"], "confirmed_exfiltration": ["str"], "egress_bounded_by": "str"},
"containment": {"cut": "credential|trigger|workload|class",
"does_not_stop": ["str"], "evidence_snapshotted_first": true},
"clock": {"regulatory_trigger": false, "basis": "str"}
}
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.7Then restart your agent and open it in that folder. On Windows, if python3 says Python was not found, use python instead.
Then pick e3-7-scoping-an-agentic-incident:
| agent | install just for this agent | start it |
|---|---|---|
| Claude Code | python3 scripts/install_skills.py --tool claude --lessons E3.7 | type /e3-7-scoping-an-agentic-incident |
| GitHub Copilot (VS Code) | python3 scripts/install_skills.py --tool copilot --lessons E3.7 | type /e3-7-scoping-an-agentic-incident in Chat |
| Cursor | python3 scripts/install_skills.py --tool cursor --lessons E3.7 | type / in Agent chat and search for it |
| Codex | python3 scripts/install_skills.py --tool agents --lessons E3.7 | type $e3-7-scoping-an-agentic-incident, 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.7Neither 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.7 --out work/cybertravels
python3 scripts/checkpoint.py --at E3.7 --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.
Scoping the last actor finds cluster-prod alone; the whole chain reaches six resources, missing five, with an undercount factor of 6.0. The undercount grows with each hop. Transitive scoping adds five second-order identities that shared a resource, explicitly marked as in scope rather than confirmed compromised.
For your last incident involving a service account, recompute the scope by walking what else that account could reach. The number is almost always larger than what was written in the report.
Tools used
Skill source: skills/secops/incident-scoping