Install
$ agentstack add skill-elastic-agent-skills-kibana-anomaly-detection ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Elastic ML Anomaly Detection
Single skill covering all anomaly detection work against Kibana Agent Builder MCP at {KIBANA_URL}/api/agent_builder/mcp. Use the Mode Selector below to pick the right approach for the user's question — modes share the same tool surface and concepts.
Platform
- Read path: ES|QL against
.ml-anomalies-*,.ml-config,.ml-notifications-*,.ml-annotations-* - Always-available:
platform.core.execute_esql(plus additional platform tools for search, index mapping, and
documentation — see scripts/agent_builder_constants.json)
- ML API spec (if available):
.kibana_ai_openapi_spec_elasticsearch— see
[references/anomaly-detection-openapi-spec-discover.md](references/anomaly-detection-openapi-spec-discover.md) for discovery pattern.
- Run
ad_validate_ml_tool_permissionsfirst when tools return empty/misleading results — missing privileges are
the most common cause of false negatives. Full permissions matrix: [references/permissions-matrix.md](references/permissions-matrix.md).
Mode Selector
| User intent | Mode | | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | | "What broke?" / RCA / cross-job / blast radius / influencers / log categories | Investigate | | "Why score high/low?" / renormalization / model bounds / forecasts | Explain | | Missing docs / memory limit / datafeed stopped / CCS / lifecycle / calendars | Troubleshoot | | Create a job / configure a datafeed / start analysis / retrieve results | Manage | | Security framing (attack chains, MITRE, exfil) | Investigate + [references/security-anomaly-expert.md](references/security-anomaly-expert.md) | | Observability/SRE framing (degradation, capacity, deployment regression) | Investigate + [references/observability-anomaly-expert.md](references/observability-anomaly-expert.md) |
When a question spans modes: Investigate → Explain → Troubleshoot. Don't blend mode logic — finish one before moving on.
Score Quick Reference
record_scorebands: >75 critical · 50–75 warning · 25–50 minor · **> record_score` → renormalization (model saw worse anomalies later)- `actual one high score — composite cross-job signal often beats single-detector severity
> Full score definitions, renormalization mechanics, and anomaly_score_explanation components: > [references/score-reference.md](references/score-reference.md).
Core concepts
Treat .ml-anomalies-* as three layers, accessed via result_type:
bucket— bucket-level unusualness perbucket_span.anomaly_scoreis the aggregate across all detectors.record— finest-grained rows withactualvstypical,probability,record_score,
anomaly_score_explanation.
influencer— entity contributions ranked within a bucket (influencer_score).
Read scores this way:
anomaly_score/record_score= current normalized values (move as the model sees new extremes).initial_anomaly_score/initial_record_score= immutable snapshots from detection time.- Compare
actualtotypical; useprobabilityfor raw likelihood. - Map entities via
partition_field_value/by_field_value/over_field_value. - Read
multi_bucket_impact(-5 to +5) to separate single-bucket spikes from sustained trends.
Mode: Investigate — RCA
When: "what broke?", "which entity caused this?", cross-job correlation, blast radius, attack/cascade chains.
Tool chain
| Phase | Tools | | --------------------- | -------------------------------------------------------------------------------------------------------------- | | Discovery | ad_get_available_metadata, ad_get_jobs, ad_discover_related_jobs, ad_discover_jobs_by_datafeed_index | | Timeline / scope | ad_query_anomaly_timeline | | Cross-job / entities | ad_rca_cross_job_entity_match, ad_rca_multi_job_entities, ad_rca_entity_profile | | Records / influencers | ad_query_anomaly_records, ad_query_influencers | | RCA depth | ad_rca_detector_fingerprint, ad_rca_correlation, ad_rca_blast_radius, ad_rca_score_reassessment | | Evidence / categories | ad_get_job_datafeed_config, ad_rca_source_evidence, ad_get_categories, ad_search_log_category_examples |
Protocol
Follow the 14-step sequence in [references/protocols/investigation.md](references/protocols/investigation.md). High level: ad_get_available_metadata → pair ad_discover_jobs_by_datafeed_index with ad_discover_related_jobs → ad_query_anomaly_timeline → rank with ad_rca_multi_job_entities (min_job_count=2) → ad_rca_detector_fingerprint → drill with ad_query_anomaly_records + ad_query_influencers (low min_score=25) → profile with ad_rca_entity_profile → order with ad_rca_correlation → confirm with ad_rca_source_evidence. When by_field_name == "mlcategory", compare with ad_get_categories + paired ad_search_log_category_examples (baseline vs. anomaly window).
Finish with a written RCA: root cause entity · affected jobs · temporal progression · fault class (resource/network/application) · severity · recommended actions. Worked example: [references/worked-example.md](references/worked-example.md). Full ES|QL templates and parameters: [references/investigate-anomaly-esql-tools.md](references/investigate-anomaly-esql-tools.md).
Rules
- Multi-job entities are prime suspects; single-job entities are usually victims. Use
min_job_count=2. - Earliest anomaly timestamp wins — sort
ad_rca_correlationby timestamp; first-appearing entity = origin. multi_bucket_impact ≥ 3= sustained behavioral shift, weight higher than transient spikes.- Never close an RCA without
ad_rca_source_evidence— raw source documents are ground truth. - Use low
min_score(25 or lower) for influencer queries — high thresholds miss correlated entities.
Mode: Explain — Score / model behavior
When: "why is my score 30/90?", "score dropped overnight", "what is renormalization?", "why wasn't this detected?".
Score types
| Field | Scope | Meaning | | ---------------------- | --------------- | ----------------------------------------------------------------------- | | record_score | Single record | Normalized severity after renormalization. | | initial_record_score | Single record | Score at detection time. Gap vs record_score = renormalization drift. | | anomaly_score | Bucket | Aggregate severity across all detectors in a bucket. | | influencer_score | Entity × bucket | How anomalous a specific entity is in that bucket. |
anomaly_score_explanation components
| Component | Effect | What it means | | -------------------------------- | ------- | ------------------------------------------------------------ | | anomaly_length | ↑ score | More consecutive anomalous buckets | | single_bucket_impact | ↑ score | Lower probability → higher impact | | multi_bucket_impact | ↑ score | Sustained pattern contribution | | anomaly_characteristics_impact | ↑ score | Mean shift vs. variance change | | high_variance_penalty | ↓ score | Noisy data → wide bounds → anomaly less surprising | | incomplete_bucket_penalty | ↓ score | Bucket has less data than expected (ingest lag, sparse data) |
Why a score looks wrong
- Unexpectedly low:
high_variance_penalty, renormalization,hard_limitcorrupts model state and causes downstream missing-doc false alarms (categorizer silently skips events
> for unknown categories). Fix memory before fixing query_delay.
Memory concepts
| Field | Meaning | | ----------------------------------- | ------------------------------------------------------- | | model_bytes | Current memory used | | peak_model_bytes | High-water mark since job opened | | model_bytes_memory_limit | Configured model_memory_limit | | memory_status | ok / soft_limit (pruning) / hard_limit (critical) | | total_by_field_count > 100k | by_field cardinality too high — dominant driver | | total_partition_field_count > 10k | Partition explosion | | total_category_count > 10k | Too many distinct log patterns |
Prefer ad_estimate_memory_requirement (samples cardinality from source, calls Estimate Model Memory API) over heuristics like peak_model_bytes * 1.3 — the heuristic ignores pure influencer and categorization memory.
Datafeed & timing concepts
query_delay— how far behind real time the datafeed queries. Too small → missing docs; too large → slower
alerts. Set to P95 ingest latency + buffer (default 60s–120s).
delayed_data_check_config— how aggressively the datafeed checks for late data.bucket_span— analysis interval. Align with data granularity and detection window.frequency— defaults tomin(query_delay, bucket_span / 2).
Lifecycle for config changes (memory limit, query_delay)
- Stop datafeed:
ad_manage_datafeed(action=_stop) - Close job
- Update config:
ad_update_model_memory_limit,ad_update_datafeed_query_delay,
ad_update_delayed_data_check_config
- Open job:
ad_open_job - Start datafeed:
ad_manage_datafeed(action=_start)
Recover a corrupted period without resetting the whole model: ad_revert_model_snapshot.
Tool surface
| Category | Tools | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Permissions / metadata | ad_validate_ml_tool_permissions, ad_get_available_metadata, ad_get_jobs | | Job + datafeed state | ad_get_job_datafeed_config, ad_get_job_messages, ad_manage_datafeed, ad_preview_datafeed_with_latency | | Timing / missing docs | ad_ts_delayed_data_annotations, ad_ts_bucket_event_gaps, ad_ts_ingest_latency_estimate, ad_update_datafeed_query_delay, ad_update_delayed_data_check_config, ad_wf_troubleshoot_query_delay | | Memory | ad_ts_model_memory_health, ad_wf_ts_field_cardinality, ad_estimate_memory_requirement, ad_update_model_memory_limit, ad_wf_troubleshoot_memory_limit | | Model / lifecycle | ad_get_model_snapshots, ad_revert_model_snapshot, ad_open_job, ad_create_job | | CCS | ad_ts_ccs_diagnostics | | Calendars | ad_get_calendar_events, ad_create_calendar_event |
Full parameter tables, ES|QL templates, and REST step lists: [references/troubleshoot-anomaly-tool-reference.md](references/troubleshoot-anomaly-tool-reference.md).
Rules
ad_validate_ml_tool_permissionsfirst — missing privileges produce misleading empty results.- Fix memory before
query_delay—hard_limitcorrupts state;query_delayfixes on a memory-limited job are
wasted.
- Stop the datafeed before updating it. Updating a running datafeed is rejected.
- Close the job before updating memory limit. Sequence above.
- Prefer workflow tools (
ad_wf_*) over manually chaining diagnostics for complex decisions. ad_preview_datafeed_with_latencybefore starting — confirm the datafeed returns data after config changes.
Mode: Manage — Create / configure jobs
When: "set up a job", "create an ML detector", "monitor X over time", "detect rare/unusual/anomalous values".
4-step workflow
PUT _ml/anomaly_detectors/ # 1. Define job (ad_create_job)
PUT _ml/datafeeds/datafeed- # 2. Define datafeed (ad_create_datafeed)
POST _ml/anomaly_detectors//_open # 3a. Open job (ad_open_job)
POST _ml/datafeeds/datafeed-/_start # 3b. Start datafeed (ad_manage_datafeed action=_start)
GET _ml/anomaly_detectors//results/records # 4. Read results
Process
- Build configs. Parse the user request into job + datafeed JSON with no null fields.
- Apply smart defaults:
| Field | Default | Override when | | ---------------- | --------------------------------------- | ------------------------------------------------- | | bucket_span | "15m" | User specifies a different span | | time_field | "@timestamp" | User names a different timestamp field | | index | "logs-*" | User specifies an index or pattern | | datafeed_query | {"match_all": {}} | User mentions filters, processes, or time windows | | influencers | by/over/partition fields from detectors | User adds extra influencer fields | | job_id | Generated from user description | User provides an explicit ID | | query_delay | "60s" | P95 ingest latency is higher |
- Choose detector function from user intent — full table in
[references/anomaly-detection-functions.md](references/anomaly-detection-functions.md):
- "high CPU" / "unusually large" →
high_meanorhigh_sum - "rare logins" / "unusual values" →
rare(variants b
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: elastic
- Source: elastic/agent-skills
- License: Apache-2.0
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.