NetCortex is a simulation-first, multi-agent root cause analysis (RCA) system for network incidents. It orchestrates domain agents (metrics, logs, routing, config), performs A2A-style cross-agent collaboration, and synthesizes both machine-structured and human-readable RCA output.
- Multi-agent RCA workflow built on LangGraph.
- FastAPI-based domain agents exposing ADK-compatible A2A agent cards and task messaging.
- Deterministic confidence scoring plus Gemini LLM-based incident classification and narrative synthesis.
- Baseline-aware z-score anomaly detection in metrics and config agents (configurable thresholds, simulation and Prometheus baseline providers).
- Config agent prioritises incident-relevant config changes over raw change counts, using keyword-overlap and network-symptom heuristics.
- Simulation scenarios for reproducible local development and demos.
- Replay/eval mode to run bundled scenarios and score expected RCA keyword coverage.
- Console progress logging so users can track execution stages in real time.
- Safe A2A peer-collaboration: session cleanup after each incident, validated fallback domain literals, no dead in-memory caches.
For contributors and production-oriented extensions, use these guides:
- project_docs/agent-authoring-guide.md: how domain agents decide, score confidence, and collaborate.
- project_docs/decision-policy.md: how NetCortex turns multi-agent evidence into one RCA conclusion.
- project_docs/provider-adapter-guide.md: how to connect Prometheus, ELK, Splunk, MCP, or custom backends.
Recommended reading order for contributors:
project_docs/agent-authoring-guide.mdproject_docs/decision-policy.mdproject_docs/provider-adapter-guide.md
app/main.py: CLI entrypoint for one-shot run and server mode.core/orchestrator.py: workflow graph and stage orchestration.agents/: domain agents and RCA synthesizer.communication/: registry and A2A router.ingestion/: webhook API intake and normalization.providers/simulation/: scenario-backed provider implementations.providers/simulation/baseline_sim.py: per-entity, per-metric baseline tables used by z-score detection.providers/adapters/: stubs for real-system integrations (Prometheus, ELK, Splunk, MCP, baseline).providers/base.py: abstract provider interfaces includingBaselineProvider.providers/baseline_utils.py:compute_z_scoreandis_anomalousutilities.config/config.yaml: runtime behavior and timeouts.scripts/send_incident.py: helper for webhook injection.tests/: unit, integration, and e2e placeholders.
If you just want to prove the project works end-to-end:
- Install dependencies.
- Run one incident.
- Confirm output artifacts were created.
python -m venv .venv
.\.venv\Scripts\activate
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
python app/main.py run --scenario 1If you do not have LLM auth configured yet, run in deterministic fallback mode:
python app/main.py run --scenario 1 --no-require-llmpython -m venv .venv
.\.venv\Scripts\activate
python -m pip install --upgrade pip
python -m pip install -r requirements.txtEdit config/.env.
Supported LLM auth modes:
- API key mode:
- set
GEMINI_API_KEY=...
- set
- ADC + Vertex AI mode:
- set
GOOGLE_CLOUD_PROJECT=... - optional
GOOGLE_CLOUD_LOCATION=us-central1 - authenticate with
gcloud auth application-default login
- set
If no LLM auth is available and strict LLM mode is disabled, NetCortex falls back to deterministic synthesis.
Important:
- LLM strict mode is enabled by default.
- Without valid LLM auth, one-shot runs fail fast.
- To run in deterministic fallback mode for local experimentation, use the CLI switch
--no-require-llm.
python app/main.py run --scenario 1python -m pytest -qNetCortex now emits stage-by-stage progress logs during execution.
Examples of log events:
- Runtime startup and agent registration.
- Supervisor classification and selected active agents.
- Per-agent analysis result, timeout, or error.
- Collaboration rounds and convergence.
- Synthesizer start/finish and final confidence.
Run with default info logs:
python app/main.py run --scenario 1Run with debug logs:
python app/main.py run --scenario 1 --verboseReplay/eval all bundled scenarios (useful for reproducibility demos and CI):
python app/main.py eval --all-scenarios --fail-on-missEvaluate a single scenario:
python app/main.py eval --scenario 10LLM strict mode is optional. Enable it explicitly when you want fail-fast behavior if LLM is unavailable:
python app/main.py run --scenario 1 --require-llmDefault mode is deterministic fallback (no strict LLM requirement). The following is equivalent and explicit:
python app/main.py run --scenario 1 --no-require-llmPrint full JSON report to console (optional):
python app/main.py run --scenario 1 --print-jsonBy default, NetCortex prints a readable RCA summary and file location, not the full JSON blob.
On a successful run (python app/main.py run --scenario 1), you should see:
- Agent registration lines with skills, for example:
Registered agent=metrics endpoint=http://localhost:8001/a2a skills=analyze-metrics,respond-to-peer - Supervisor classification line, for example:
Supervisor classified incident=<id> degradation_type=network active_agents=metrics,log,routing,config - Analysis result lines from each active agent.
- Final console report block titled
NetCortex RCA Report.
A run creates artifacts under output/<incident_id>/:
rca_report.jsonagent_trace.jsonla2a_messages.jsonlsupervisor_state.json
Detailed logs are written to output/log/.
Detailed log files:
runtime.logorchestrator.logsynthesizer.logmetrics.loglog.logrouting.logconfig.log
Start service mode:
python app/main.py serveSend scenario incident from helper:
python scripts/send_incident.py send --scenario 3Send custom incident JSON:
python scripts/send_incident.py send --file sample_incident.jsonPowerShell direct POST:
$body = @{
description = "Packet loss spike and throughput drop in us-east after maintenance window"
region = "us-east"
severity = "high"
scenario_id = 1
source_system = "external-monitor"
external_incident_id = "INC-1001"
} | ConvertTo-Json
Invoke-RestMethod -Method Post -Uri http://localhost:8000/incidents -ContentType "application/json" -Body $bodyRequest fields:
description: required string.region: required string.severity: one oflow,medium,high,critical.scenario_id: optional integer.source_system: optional string.external_incident_id: optional string.
Reports are written to:
output/<incident_id>/rca_report.json
Recommended reading order:
root_causehuman_readable_summarycontributing_factorscausal_chainagent_findings[].key_eventsa2a_message_log
Key fields:
root_cause: concise primary cause statement.human_readable_summary: plain-English explanation (LLM when available).confidence_score: synthesized confidence score.corroborating_domain_count: number of anomaly-supporting domains.conflict_detected: whether signals conflict.
Conflict-focused demo scenarios:
- Scenario
10demonstrates ametricsanomaly on Switch-C with no corroborating config change (configreports no changes). - Scenario
11demonstrates mixed evidence (optic/log anomalies with limited cross-domain corroboration). - Scenario
12demonstrates explicit cross-domain conflict (log+routinganomalies with mostly cleanmetrics) to exerciseconflict_detectedbehavior.
Runtime behavior is controlled from config/config.yaml.
Important settings:
llm.model: Gemini model name.a2a.protocol_mode:adk(SDK-native A2A client) orcustom(fallback transport).a2a.analysis_timeout_seconds: per-agent analysis timeout.a2a.max_iterations: collaboration rounds cap.simulation.regionandsimulation.window_minutes.
| Key | Default | Description |
|---|---|---|
provider |
simulation |
Baseline data source. simulation or prometheus. |
metrics_z_threshold |
3.0 |
Z-score threshold above which a metric is flagged as anomalous. Must be > 0. |
config_z_threshold |
2.5 |
Z-score threshold for config change-count anomaly detection. Must be > 0. |
legacy_fallback |
true |
When true, falls back to hard-coded thresholds for entities with no baseline entry. |
All baseline keys are validated at startup. An invalid provider, a non-positive threshold, or a non-boolean legacy_fallback cause fail-fast startup.
Schema note:
The current A2A message schema (see models/schemas.py, A2AMessage) is a baseline contract used by this implementation. It is intentionally extensible and can be expanded with additional message types and payload fields as collaboration needs evolve.
Validation checks enforce compatible timeout relationships at startup.
Simulation providers are enabled by default.
Adapter extension points:
providers/adapters/prometheus_adapter.pyproviders/adapters/elk_adapter.pyproviders/adapters/splunk_adapter.pyproviders/adapters/mcp_adapter.py
To move toward production-like integrations, implement adapter methods and update provider mode in config/config.yaml.
- License: MIT (see
LICENSE). - Secrets:
config/.envis ignored by git; never commit credentials. - Development artifacts and runtime outputs are ignored in
.gitignore.
- Fork and create a feature branch.
- Run tests locally:
python -m pytest -q. - Keep changes scoped and documented.
- Open a pull request with a clear summary, test evidence, and any config impacts.
- If LLM output is missing, verify API key or ADC project settings.
- If you see GCP quota project warnings, align ADC quota project with intended billing project.
- If Typer help errors appear, ensure dependencies are installed from requirements.txt (currently click==8.3.1 and typer==0.16.1).
- Create and activate
.venv. - Install dependencies.
- Run
python -m pytest -q. - Run
python app/main.py --help. - Run
python app/main.py run --scenario 1. - Confirm logs show workflow progress.
- Inspect output report artifacts.