Investigate alerts
Run a structured investigation with the investigate_alert prompt, pivot on entities, and record findings in notebooks
Investigate alerts
Once an alert is worth more than a glance, the investigate_alert prompt drives a structured workflow: read the alert, pull the detection's intent, enrich the entities, look for related activity, and land on a recommendation. This page covers that prompt, the entity pivots it uses, and where the findings go.
This page assumes you've read Triage & cases, since an investigation usually ends in a case.
The investigate_alert prompt
investigate_alert takes alert_id (required) and depth (optional: quick, standard, or deep). It runs a fixed chain:
get_alertfor the matched events andai_triage_hintsget_detectionto read the rule's intent and itsignore_when/suspicious_whenlists- Assess false-positive versus true-positive against those hints
- Enrich the entities with
get_entity_context,lookup_ip, andget_prevalence(IOC hits surface on theioc_*columns in search results) - Run one or two search queries for related activity
get_related_casesto check for prior history- Recommend: false positive, needs more investigation, or true positive
depth controls how far the chain runs. quick stops after step 3 (the hint-based assessment). standard and deep run the enrichment and search steps. Regardless of depth, the prompt will not go more than two levels deep down a pivot without checking in with you first, so you stay in control of scope.
> investigate alert 456
Running investigate_alert (alert_id=456, depth=standard)...
get_alert(456): rule "DNS tunneling — high entropy subdomains",
severity high, entity ip 10.5.2.40, 47 matched DNS events.
get_detection: ai_triage_hints.suspicious_when =
["query volume to a single domain > 200/hr",
"subdomain entropy > 4.0"]. ignore_when =
["domain is a known CDN or telemetry endpoint"].
Assessment: matched events show 612 queries/hr to
*.dataxfil-c2.example.com, entropy 4.7. Not a known CDN.
Leaning true positive.
Enriching 10.5.2.40 (get_entity_context):
GeoIP: internal RFC1918, asset = VPN-issued laptop (jdoe)
IOC: no threat-intel hits on the IP itself
Risk timeline: score climbed 22 → 74 over 6 hours
search dataxfil-c2.example.com | where ioc_matched=true:
ThreatFox match, ioc_threat_type "generic_exfil", ioc_confidence 75.
get_prevalence(domain, dataxfil-c2.example.com):
seen on 1 host, first seen 6h ago, is_rare = true.
Related activity search returned 2 hits on the same host.
get_related_cases: 1 similar case (DNS exfil, different host,
closed true_positive 3 weeks ago).
Recommendation: TRUE POSITIVE. Rare C2-like domain, threat-intel
match, single host, risk climbing. Suggest a case and a host
isolation action. Want me to open one?Resuming an investigation
When you come back to a case that already has an investigation in it, start with review_case rather than re-reading the pieces by hand. It is a composite read: it returns the case, its wall, and every linked notebook with entries and references, batched so you get the whole context in one call. Treat it as the resume-an-investigation entry point.
> pick up case C-204
Calling review_case (id=C-204)...
Case C-204 — Credential dumping on WIN-FS01 (critical, in_progress)
Wall (4 entries): last status "confirmed lateral move to WIN-FS02"
Notebooks (1): "WIN-FS01 credential dumping" — 9 entries
(timeline, 2 ioc_markers, 3 search_executed, ai_summary)
You left off pivoting from WIN-FS01 to WIN-FS02. Continue there?Pivoting on entities
The investigation widens by pivoting from one entity to its context:
get_entity_contextis a composite pivot. Givenentity_type(ip/user/host/domain/hash) andvalue, it runs GeoIP (for IPs) and the risk timeline in parallel and returns them together. This is the usual first pivot.lookup_ipreturns GeoIP and ASN for oneip.- IOC matches are applied at ingest into the
ioc_matched/ioc_threat_type/ioc_confidencecolumns — surface them by filtering search results (e.g.... | where ioc_matched=true), not a dedicated lookup. get_prevalenceanswers how common an artifact is (host count, occurrences, first and last seen,is_rare). It acceptstypeofhashordomainonly. Passing an IP errors; use the rare/new artifact tools for IPs instead.
> what do we know about the domain dataxfil-c2.example.com?
Calling get_entity_context (entity_type=domain,
value=dataxfil-c2.example.com)...
IOC: ThreatFox hit, family generic_exfil
Risk: associated with 1 entity (10.5.2.40), trending up
Calling get_prevalence (type=domain,
value=dataxfil-c2.example.com)...
host_count=1, occurrences=47, first_seen=6h ago, is_rare=trueRecording findings: the case wall vs notebooks
Two surfaces hold investigation output, and they have different jobs.
The case wall holds short status. Use add_case_wall_entry for a one-or-two-line update an analyst can scan: "confirmed C2 beacon, isolating host." Keep the wall readable.
Notebooks hold the detailed analysis: the queries you ran, the entities you touched, the timeline you built. Create one per investigation with create_notebook (param: title; optional visibility of private/shared/public), then append structured entries.
add_notebook_entry takes notebook_id, entry_type, and content (an object). The entry_type is one of a fixed set, each expecting its own JSON content shape:
manual_notesearch_executedai_suggestionai_summaryentity_referenceioc_markertimeline_markerinvestigation_timeline
add_notebook_reference links a notebook to an alert, detection, saved_search, or case so the two stay connected.
The split is the point: put the short, scannable status on the case wall and the full reasoning in a notebook. A reviewer reads the wall to get the state of the case in seconds, then opens the notebook when they need the detail.
> log this investigation. case C-204, build me a notebook.
Calling create_notebook (title="DNS exfil from 10.5.2.40",
visibility="shared")... → notebook NB-77
Calling add_notebook_entry (NB-77, entry_type="ioc_marker",
content={value:"dataxfil-c2.example.com", type:"domain",
source:"ThreatFox", family:"generic_exfil"})...
Calling add_notebook_entry (NB-77, entry_type="search_executed",
content={query:"...", hits:47, window:"-24h"})...
Calling add_notebook_entry (NB-77, entry_type="ai_summary",
content={text:"Rare C2-like domain, single host, risk 74..."})...
Calling add_notebook_reference (NB-77, reference_type="case",
reference_id="C-204")...
Calling add_notebook_reference (NB-77, reference_type="alert",
reference_id="456")...
Calling add_case_wall_entry (C-204, entry_type="ai_analysis",
content="DNS exfil confirmed to dataxfil-c2.example.com
(ThreatFox, rare). Detail in notebook NB-77.")...
Notebook NB-77 created and linked. Wall updated with a short
status pointing at it.Finding related work
get_related_cases (param: id) returns cases that share entities, rules, or MITRE techniques with the current one. Use it to find out whether the same host, user, or domain has been investigated before, which often changes the disposition.
find_notebooks_by_reference goes the other direction: given a reference_type (alert/detection/saved_search/case) and reference_id, it finds notebooks that already reference that object, so you do not redo analysis someone else already wrote up.
What's next
- Hunt: go looking before an alert fires, with
search_sql, prevalence, and MITRE coverage - Triage & cases: the case model and the start-of-shift briefing
- Detection-as-Code: turn a confirmed pattern into a scheduled detection