Version: 0.2.0 Aligned with: eventmill_v1_1.md (v0.2.0-draft)
The router decides which subset of the tool catalog is visible for a user request. It is a control plane component, not an investigative tool. Its job is to reduce LLM prompt size, improve tool relevance, and make a growing plugin ecosystem manageable.
Routing occurs in four phases. Each phase narrows the candidate set.
The router determines the most relevant investigation pillar.
Supported pillars:
| Pillar | Scope |
|---|---|
network_forensics |
PCAP triage, firewall log analysis, network artifact investigation |
cloud_investigation |
Cloud audit log analysis, cloud resource investigation |
log_analysis |
New event source triage, threat intel ingestion, image analysis, event enrichment |
risk_assessment |
Risk scoring, control effectiveness, compliance gap analysis |
threat_modeling |
Shostack 4-question framework, attack path generation and visualization |
Pillar selection inputs (in precedence order per section below):
After pillar selection, the router derives candidate capabilities from the request.
Example request:
Ingest this PDF threat report and extract IOCs.
Derived capabilities:
artifact:pdf_reportoperation:parseoperation:extractentity:iocCapability derivation MUST begin with deterministic rules. Semantic enrichment is deferred to a future release.
The plugin registry is filtered to tools where:
also_useful_inartifacts_consumed includes the active artifact type (if one exists)Matching tools are ranked per the scoring model below.
After primary tool selection, the router evaluates potential downstream tools by matching:
artifacts_produced against other tools’ artifacts_consumedchains_to advisory fieldChain recommendations are informational. They appear in the routing output but do not automatically invoke. The analyst or LLM decides whether to follow a chain.
Recommended order for pillar selection:
use <pillar> CLI commandSemantic classification and LLM-assisted routing are not in MVP scope.
| Artifact Type | Implied Pillar | Strength |
|---|---|---|
pcap |
network_forensics |
strong |
cloud_audit_log |
cloud_investigation |
strong |
risk_model |
risk_assessment |
strong |
json_events |
log_analysis |
moderate |
log_stream |
log_analysis |
moderate |
pdf_report |
log_analysis |
moderate (likely threat intel) |
html_report |
log_analysis |
moderate (likely threat intel) |
image |
log_analysis |
weak (could be physical intrusion or unrelated) |
text |
ambiguous | none — requires keyword or session context |
| Keywords | Boosted Pillar |
|---|---|
pcap, packet, flow, dns query, tcp, udp, tls, wireshark |
network_forensics |
firewall, palo alto, fortinet, iptables, blocked, allowed |
network_forensics |
azure, aws, gcp, blob, s3, cloudtrail, audit log, iam |
cloud_investigation |
log, event, syslog, session, alert, parse, field, grok |
log_analysis |
threat intel, ioc, indicator, stix, cve, advisory, report |
log_analysis |
image, photo, camera, physical, badge, serial number |
log_analysis |
risk, impact, likelihood, control, residual, compliance |
risk_assessment |
mitre, attack path, technique, lateral movement, exfiltration |
threat_modeling |
threat model, four questions, shostack, what can go wrong |
threat_modeling |
If the current session already selected a pillar and the new request is ambiguous, prefer the current session pillar unless there is strong conflicting evidence from artifact type or keywords.
Candidates are the selected pillar’s tools, plus any tool whose manifest names that
pillar in also_useful_in. There is no expansion mode: one pillar at a time is the
routing model, and a tool reaches another pillar only by declaring it.
Pillar-level adjacency was specified (strict / adjacent / broad modes over an
adjacency map) and removed on 2026-09-07. It never narrowed anything useful - every
pillar was adjacent to most others, so adjacent mode admitted nearly the whole
catalogue and defeated the 3-5 tool target. also_useful_in covers the same need one
declaration at a time, which is auditable in the manifest and reviewable per plugin.
broad was never implemented.
A declaration widens where a tool is offered, never which pillar Phase 1 selects.
After filtering, tools are ranked using a weighted score:
score =
pillar_match * 50 +
artifact_consumed_match * 30 +
capability_overlap_count * 10 +
stability_weight +
auto_invoke_weight -
timeout_penalty -
cost_penalty +
chain_bonus
Weights:
| Factor | Weight | Notes |
|---|---|---|
pillar_match |
50 | 1 if pillar matches, 0.75 if the tool declares the pillar in also_useful_in, 0 otherwise |
artifact_consumed_match |
30 | 1 if tool consumes the active artifact type |
capability_overlap_count |
10 per match | Number of derived capabilities matching tool capabilities |
stability_weight |
core=10, verified=5, experimental=0, deprecated=-10 | |
auto_invoke_weight |
5 if safe_for_auto_invoke=true | |
timeout_penalty |
fast=0, medium=-5, slow=-10 | |
cost_penalty |
low=0, moderate=-5, high=-10 | |
chain_bonus |
10 | If a previously executed tool’s output feeds this tool |
This scoring is intentionally simple and explainable. A future version may introduce learned weights.
The router returns a structured decision object:
{
"selected_pillar": "log_analysis",
"requested_capabilities": [
"artifact:pdf_report",
"operation:parse",
"operation:extract",
"entity:ioc"
],
"candidate_tools": [
{
"tool_name": "threat_intel_ingester",
"score": 130,
"match_reasons": [
"pillar_match",
"artifact_consumed_match:pdf_report",
"capability:operation:parse",
"capability:entity:ioc"
]
}
],
"chain_recommendations": [
{
"tool_name": "context_enriched_analyzer",
"reason": "threat_intel_ingester produces json_events, context_enriched_analyzer consumes json_events",
"pillar": "log_analysis"
}
],
"excluded_tools": [
{
"tool_name": "pcap_ip_search",
"reason": "pillar_mismatch"
}
],
"explanation": [
"Detected pdf_report artifact",
"Keyword match: threat intel, ioc",
"Matched log_analysis pillar",
"Chain recommendation: threat_intel_ingester -> context_enriched_analyzer"
]
}
| Mode | Description |
|---|---|
manual |
Analyst explicitly selected pillar via CLI |
deterministic |
Artifact and rules selected pillar |
assisted |
Deterministic result with optional semantic recommendation (future) |
learning |
Telemetry-informed ranking (future) |
If the router cannot determine a strong match:
The router MUST emit logs at the following levels:
| Level | Content |
|---|---|
INFO |
Selected pillar, expansion mode, candidate tool count |
DEBUG |
Artifact hints, keyword hits, derived capabilities, per-tool scores, excluded tools with reasons |
WARNING |
Low-confidence decisions, fallback selections |
Logger namespace: eventmill.framework.router
The router SHOULD be config-driven. Suggested config areas:
use <pillar> CLI command)also_useful_inSemantic recommendation and learning mode are post-MVP.