Plutopus is an air-gap-ready Network Operations Intelligence Platform that combines telemetry ingestion, topology awareness, predictive analytics, incident correlation, and an AI copilot to help network teams detect, understand, and respond to issues before they impact operations.
- Vision
- Platform Overview
- Key Capabilities
- System Architecture
- Technology Stack
- Repository Structure
- Core Components
- Database Design
- API Reference
- AI Copilot
- Predictive Analytics
- Air-Gap Readiness
- Security
- Observability
- Deployment
- Development Setup
- Testing
- Performance
- Production Readiness
- Roadmap
- Contributing
- License
Most network operations tools are reactive. Alerts fire after outages begin. Operators diagnose in isolation with no topological context. Root cause analysis is manual, slow, and often wrong. Dashboards show raw metrics with no intelligence layered on top. Air-gapped deployments require expensive licensed platforms with no offline model support.
Plutopus was built to address these gaps:
| Problem | How Plutopus Addresses It |
|---|---|
| Alert fatigue | Anomalies are correlated by topology into prioritized incidents, not raw alerts |
| No topology context | A NetworkX graph model maps sites → devices → interfaces → tunnels in real-time |
| Reactive troubleshooting | Linear regression forecasting predicts degradation 15m, 30m, and 60m ahead |
| Poor root cause analysis | Correlation engine groups anomalies by shared hub/underlay relationships |
| Operational toil | AI Copilot grounded in live platform data reduces manual investigation |
| Air-gap challenges | Fully offline-capable: bundled images, local Ollama models, no external calls |
Plutopus is a multi-service platform organized into a clear layered architecture:
[Operator / NOC Engineer]
│
▼
┌───────────────────────────────────────────────┐
│ Next.js Dashboard · CLI │ ← Presentation Layer
└───────────────┬───────────────────────────────┘
│ HTTP REST
┌───────▼────────────────────┐
│ FastAPI Gateway │ ← API Layer (RBAC + JWT + Audit)
└──┬──────┬──────┬───────┬──┘
│ │ │ │
┌──────▼──┐ ┌─▼───┐ ┌▼────┐ ┌▼──────────────┐
│Topology │ │Pred.│ │Corr.│ │ AI Copilot │ ← Intelligence Layer
│ Engine │ │Eng. │ │Eng. │ │ (Ollama/RAG) │
└──────┬──┘ └─┬───┘ └┬────┘ └┬──────────────┘
│ │ │ │
┌──────▼──────▼──────▼───────▼──────────────┐
│ TimescaleDB (PostgreSQL 16) │ ← Storage Layer
└────────────────────────────────────────────┘
│
┌──────▼─────────────────────────────────────┐
│ Redpanda (Kafka-compatible broker) │ ← Streaming Layer
│ Topics: metrics_raw, events_raw │
└─────────────────────────────────────────────┘
│
┌──────▼─────────────────────────────────────┐
│ Telemetry Worker (Consumer) │ ← Ingestion Layer
└─────────────────────────────────────────────┘
graph TB
subgraph Clients["Client Layer"]
DASH["Next.js Dashboard\n:3000"]
CLI["Python CLI\n(Typer)"]
end
subgraph API["API Gateway — FastAPI :8000"]
direction LR
AUTH["JWT + RBAC\nMiddleware"]
METRICS_MW["Prometheus\nMiddleware"]
ROUTES["REST Endpoints\n/api/v1/*"]
end
subgraph Intelligence["Intelligence Services"]
TOPO["Topology Engine\n(NetworkX Graph)"]
PRED["Prediction Worker\n(Forecasting + Anomaly)"]
CORR["Correlation Engine\n(Incident Grouping)"]
COP["Copilot Worker\n(Context + LLM)"]
end
subgraph Storage["Storage Layer"]
PG[("TimescaleDB\nPostgreSQL 16")]
QDRANT[("Qdrant\nVector Store")]
OLLAMA["Ollama\nLocal LLM Runtime"]
end
subgraph Stream["Streaming Layer"]
RP["Redpanda Broker\n:9092 Kafka-compat"]
TW["Telemetry Worker\n(Consumer)"]
end
subgraph Observability["Observability"]
PROM["Prometheus\n:9090"]
GRAF["Grafana\n:3001"]
end
DASH --> API
CLI --> API
API --> TOPO
API --> CORR
API --> COP
TOPO --> PG
PRED --> PG
CORR --> PG
COP --> PG
COP --> OLLAMA
COP --> QDRANT
TW --> RP
TW --> PG
API --> METRICS_MW
METRICS_MW --> PROM
PROM --> GRAF
| Capability | Status | Details |
|---|---|---|
| Telemetry Ingestion | ✅ Implemented | Redpanda consumer normalizing raw metrics and events into TimescaleDB |
| Topology Intelligence | ✅ Implemented | NetworkX digraph of sites, devices, interfaces, and tunnels |
| Network Inventory | ✅ Implemented | Full CRUD-queryable inventory: sites, devices, interfaces, tunnels |
| Linear Forecasting | ✅ Implemented | 15m / 30m / 60m look-ahead per interface/tunnel with confidence scores |
| Anomaly Detection | ✅ Implemented | Z-score detection per metric with severity classification |
| Risk Scoring | ✅ Implemented | 0–100 risk index per site and tunnel with signal attribution |
| Event Correlation | ✅ Implemented | Topology-aware grouping of anomalies into root-cause incident candidates |
| Incident Management | ✅ Implemented | Priority-ranked incidents with status lifecycle and export |
| Runbook Engine | ✅ Implemented | 6 structured markdown runbooks (congestion, latency, flapping, etc.) |
| AI Copilot | ✅ Implemented | Context-grounded Q&A via local Ollama with deterministic fallback |
| Air-Gap Deployment | ✅ Implemented | Full offline bundle: images, models, charts, runbooks, checksums |
| RBAC | ✅ Implemented | Three roles: admin, operator, viewer enforced via JWT claims |
| Audit Logging | ✅ Implemented | Immutable audit_logs table: user, action, resource, IP, result |
| Prometheus Metrics | ✅ Implemented | /metrics endpoint: request rate, latency, incidents, webhooks |
| Grafana Dashboard | ✅ Implemented | Versioned JSON dashboard configuration |
| Helm Deployment | ✅ Implemented | Helm chart v0.1.0 with Deployment, Service, and Ingress templates |
| Outbound Webhooks | ✅ Implemented | Incident export with retry/backoff to external NOC systems |
| Backup & Recovery | ✅ Implemented | pg_dump-based backup, restore scripts, and validation reporter |
| Offline Model Packaging | ✅ Implemented | SHA256-verified model export/import scripts for Ollama |
graph LR
subgraph Presentation
A["Next.js\nDashboard"]
B["Typer CLI"]
end
subgraph API["API Gateway (FastAPI)"]
C["Authentication\nJWT + RBAC"]
D["Audit Logger"]
E["Prometheus\nExporter"]
end
subgraph Logic["Business Logic Services"]
F["Topology\nEngine"]
G["Prediction\nWorker"]
H["Correlation\nEngine"]
I["Copilot\nService"]
J["Webhook\nIntegration"]
end
subgraph Persistence
K[("TimescaleDB")]
L[("Qdrant")]
end
A --> C
B --> C
C --> D
C --> E
C --> F
C --> H
C --> I
C --> J
G --> K
F --> K
H --> K
I --> K
I --> L
sequenceDiagram
participant SRC as Network Source
participant RP as Redpanda Broker
participant TW as Telemetry Worker
participant PG as TimescaleDB
participant PW as Prediction Worker
SRC->>RP: Publish raw metric/event (metrics_raw topic)
TW->>RP: Subscribe & consume message
TW->>TW: Normalize, validate, type-check
TW->>PG: INSERT into metrics / events tables
PW->>PG: SELECT recent metrics (15 samples)
PW->>PW: fit_linear_trend() → forecast_metric()
PW->>PW: detect_anomaly() Z-score check
PW->>PW: calculate_tunnel_risk() / calculate_site_risk()
PW->>PG: INSERT forecasts, anomalies, risk_scores
sequenceDiagram
participant User as NOC Operator
participant API as FastAPI /copilot/query
participant CTX as Context Engine
participant RTV as Retrieval Layer
participant LLM as Ollama Runtime
participant FB as Fallback Engine
User->>API: POST /api/v1/copilot/query {question, site_id}
API->>CTX: get_site_context(site_id)
CTX->>CTX: Query: sites, devices, interfaces, tunnels
CTX->>CTX: Query: active anomalies, risk_scores, forecasts
CTX-->>API: Structured context dict
API->>RTV: retrieve_runbooks(question)
RTV->>RTV: Keyword match against 6 runbook files
RTV-->>API: Matching runbook markdown
API->>LLM: POST /api/generate {prompt, system, context}
alt Ollama reachable (4s timeout)
LLM-->>API: Generated response text
else Timeout or error
API->>FB: generate_fallback_response()
FB-->>API: Deterministic structured diagnostic
end
API-->>User: {answer, sources, runbooks, context_used}
flowchart TD
A[Prediction Worker Starts\nSLEEP_INTERVAL=300s] --> B[Query all Interfaces]
B --> C[For each Interface]
C --> D[SELECT last 15 utilization metrics]
D --> E{Enough data?}
E -- No --> C
E -- Yes --> F[fit_linear_trend\nalpha + beta × t]
F --> G[forecast_metric\n+15m, +30m, +60m]
G --> H[detect_anomaly\nZ-score vs historical]
H --> I{Z-score > threshold?}
I -- Yes --> J[INSERT Anomaly\nseverity + score]
I -- No --> K[INSERT Forecast]
J --> K
K --> L[Repeat for Tunnels\nlatency + packet_loss]
L --> M[calculate_tunnel_risk\n0-100 risk index]
M --> N[calculate_site_risk\naggregate + weights]
N --> O[INSERT RiskScore]
O --> P[Sleep SLEEP_INTERVAL]
P --> A
flowchart TD
A[POST /api/v1/incidents/correlated] --> B[EventCorrelationEngine.run_correlation]
B --> C[SELECT latest 50 anomalies]
C --> D[Separate: hub_anoms vs spoke_anoms]
D --> E{Hub anomalies exist?}
E -- Yes --> F[For each hub anomaly\nfind matching spoke anomalies\nsame metric + branch ID]
F --> G{≥2 affected spokes?}
G -- Yes --> H[Create Incident:\nCorrelated Hub Congestion\nroot_cause = hub tunnel ID\nconfidence = 0.92]
G -- No --> I[Skip]
D --> J[Group spoke anomalies by site_id]
J --> K{≥2 anomalies per site?}
K -- Yes --> L[Create Incident:\nLocal Site Degradation\nroot_cause = site_id\nconfidence = 0.85]
K -- No --> M[Skip]
H --> N[AlertPrioritizationEngine.calculate_priority\nrisk + criticality + time + scope]
L --> N
N --> O[Score 0-100\nLevel: low/medium/high/critical]
O --> P[UPDATE Incident.priority + severity]
P --> Q[Return active incidents list]
flowchart TD
A[pack-offline-bundle.sh] --> B[distribution/\ndocker-images/\nmodels/\nrunbooks/\ndeployment/helm/\nchecksums/]
B --> C[plutopus-offline-bundle.tar.gz\n+ SHA256 checksum]
C --> D[Transfer to Air-Gapped Host\nUSB / Secure File Transfer]
D --> E[Target: Isolated Network\nNo internet, No DNS resolution\nNo external model downloads]
E --> F[docker load images]
F --> G[import-model.sh\nLoad Ollama model layers]
G --> H[docker compose up]
H --> I[AIRGAP_MODE=true]
I --> J[All services operational\nTimescaleDB ✓\nRedpanda ✓\nOllama ✓\nAPI ✓\nDashboard ✓]
I --> K[scripts/airgap/verify.sh\nairgap-report.md generated]
| Layer | Technology | Version | Purpose |
|---|---|---|---|
| API Gateway | FastAPI | 0.100+ | REST API framework with auto-generated OpenAPI docs |
| Language | Python | 3.9+ | Backend service implementation language |
| Frontend | Next.js | 15 | React-based dashboard with server-side rendering |
| Styling | TailwindCSS | 3 | Utility-first styling for the dashboard UI |
| Primary Database | PostgreSQL + TimescaleDB | PG 16 | Relational storage with time-series optimizations |
| Vector Database | Qdrant | Latest | Semantic similarity storage for copilot context retrieval |
| Message Broker | Redpanda | Latest | Kafka-compatible streaming broker for telemetry |
| LLM Runtime | Ollama | Latest | Local, self-hosted language model inference |
| Graph Engine | NetworkX | 3.x | In-memory directed graph for topology relationships |
| ORM | SQLAlchemy | 2.x | Database session management and model mapping |
| Data Validation | Pydantic | 2.x | Request/response schema validation |
| Authentication | PyJWT | 2.13 | HS256 JWT signing and verification |
| Metrics | prometheus-client | 0.25 | Prometheus exposition format exporter |
| Visualization | Grafana | Latest | Metrics dashboards and alerting |
| Metrics Scraper | Prometheus | Latest | Time-series metrics collection |
| Container Runtime | Docker + Compose | v3.8 | Multi-service containerized deployment |
| Kubernetes | Helm | v2 (Chart 0.1.0) | Kubernetes packaging and deployment |
| CLI | Typer | Latest | Terminal interface for operators |
plutopus/
│
├── apps/ # User-facing application layer
│ ├── api/ # FastAPI backend gateway
│ │ └── src/
│ │ ├── api/v1/endpoints/ # Route handlers (12 modules)
│ │ ├── core/ # Auth, audit, config, metrics
│ │ ├── schemas/ # API request/response models
│ │ └── main.py # ASGI application entrypoint
│ │
│ ├── dashboard/ # Next.js frontend
│ │ └── src/app/
│ │ ├── dashboard/ # Dashboard pages
│ │ │ ├── incidents/ # Incident management UI
│ │ │ ├── predictions/ # Forecasting & anomaly UI
│ │ │ └── copilot/ # AI Copilot chat interface
│ │ └── topology/ # Interactive topology graph
│ │
│ └── cli/ # Typer-based operator CLI
│
├── services/ # Backend intelligence services
│ ├── telemetry/ # Redpanda consumer & normalizer
│ ├── prediction/ # Forecasting, anomaly, risk engine
│ │ ├── forecasting/ # Linear regression forecaster
│ │ ├── anomaly/ # Z-score anomaly detector
│ │ ├── risk/ # 0-100 risk index calculator
│ │ ├── correlation/ # RiskCorrelationEngine
│ │ └── src/worker.py # Scheduled prediction loop
│ │
│ ├── topology/ # Network graph engine
│ │ ├── graph/ # NetworkX topology builder
│ │ ├── health/ # Site health scoring
│ │ ├── intelligence/ # Path analysis and correlation
│ │ ├── repository/ # Database query layer
│ │ └── topology.yaml # Lab topology definition
│ │
│ ├── copilot/ # AI Copilot service
│ │ ├── context/ # Context Engine & Summarizer
│ │ ├── llm/ # Ollama client with fallback
│ │ ├── memory/ # Per-user memory cache
│ │ ├── prompts/ # System prompt templates
│ │ ├── retrieval/ # Runbook retrieval layer
│ │ └── runbooks/ # 6 structured markdown runbooks
│ │
│ ├── correlation/ # Event Correlation Engine
│ │ ├── engine.py # Topology-aware anomaly grouper
│ │ └── prioritization.py # 0-100 priority index calculator
│ │
│ └── integrations/ # External integration adapters
│ └── webhooks.py # Outbound webhook with retry/backoff
│
├── packages/ # Shared internal libraries
│ ├── shared/ # ORM models, DB session, shared logic
│ │ └── src/plutopus_shared/
│ │ ├── models.py # All 11 SQLAlchemy table definitions
│ │ ├── db.py # Database engine + session factory
│ │ └── correlation.py # Shared metric query helpers
│ │
│ ├── schemas/ # Shared Pydantic API schemas
│ └── utils/ # Common utility helpers
│
├── infrastructure/ # Deployment & operations tooling
│ ├── helm/ # Helm chart (Chart.yaml, values.yaml)
│ │ └── templates/ # K8s Deployment, Service manifests
│ ├── k8s/network-policies/ # Default-deny + allow-internal policies
│ ├── monitoring/
│ │ ├── prometheus.yml # Prometheus scrape configuration
│ │ └── grafana/dashboards/ # Versioned Grafana dashboard JSON
│ └── database/ # Migration and init scripts
│
├── distribution/ # Air-gap deployment bundle
│ ├── pack-offline-bundle.sh # Bundle packager script
│ ├── models/ # Ollama model export/import scripts
│ ├── docker-images/ # Docker image tarballs
│ ├── runbooks/ # Offline runbook copies
│ ├── deployment/helm/ # Bundled Helm chart copy
│ └── checksums/ # SHA256 integrity manifests
│
├── docs/ # Technical documentation
│ ├── architecture/ # System design documents
│ ├── roadmap/ # Phase planning
│ ├── adr/ # Architecture Decision Records
│ ├── capacity-planning.md # Resource sizing guide
│ ├── compliance/ # Compliance readiness guide
│ ├── operations/ # Operations & upgrade guide
│ ├── runbooks/ # Disaster recovery runbooks
│ └── production-certification.md # Platform certification report
│
├── scripts/ # Operational scripts
│ ├── backup.sh # pg_dump-based backup
│ ├── restore.sh # Database restore
│ ├── init-redpanda.sh # Topic initialization
│ ├── generate-demo-telemetry.py # Demo data injector
│ ├── airgap/verify.sh # Air-gap compliance check
│ ├── backup-validation/ # Automated restore validator
│ ├── security-audit/audit.sh # Static security scanner
│ └── upgrade/ # Schema migration + rollback
│
├── tests/ # Test suite (45 tests, 90% coverage)
│ ├── test_api.py # API endpoint integration tests
│ ├── test_phase2.py # Topology engine tests
│ ├── test_phase3.py # Prediction pipeline tests
│ ├── test_phase4.py # Copilot tests
│ ├── test_phase5.py # Incident management tests
│ └── test_phase6.py # Audit, air-gap, security tests
│
├── docker-compose.yml # Full-stack local deployment (13 services)
├── .env.example # Environment variable template
├── Makefile # Developer task runner
└── documentation.md # Living project documentation
Located in services/telemetry/. A Kafka-protocol consumer running against the Redpanda broker.
- Subscribes to
metrics_rawandevents_rawtopics - Normalizes and type-checks incoming payloads
- Inserts validated records into the
metricsandeventsTimescaleDB tables - Runs as an always-on background Docker service
Located in services/prediction/. A scheduled worker (src/worker.py) running every PREDICTION_INTERVAL seconds (default: 300s).
Forecasting (forecasting/): Implements ordinary least squares linear regression (fit_linear_trend) over the last 15 metric samples per entity. Generates forecasts at +15m, +30m, and +60m horizons with a confidence coefficient.
Anomaly Detection (anomaly/): Computes a Z-score of the latest observation against recent history. Classifies severity (info, warning, critical) by Z-score magnitude.
Risk Scoring (risk/): Aggregates anomaly signals, utilization trends, and tunnel states into a 0–100 composite risk index per site and tunnel. Includes signal attribution for explainability.
Risk Correlation (correlation/): Cross-entity correlation that checks if multiple interfaces on the same site are simultaneously degraded.
Located in services/correlation/. The EventCorrelationEngine scans the latest 50 anomalies and groups them into incidents by applying topology knowledge:
- Hub Congestion Scenario: If a hub tunnel is anomalous and ≥2 branch sites show the same metric deviation, a correlated incident is created with the hub as root cause (confidence: 0.92).
- Local Site Isolation Scenario: If ≥2 anomalies appear on the same site, a site-level incident is created (confidence: 0.85).
The AlertPrioritizationEngine then scores each incident 0–100 using weighted factors:
| Factor | Weight | Scoring Range |
|---|---|---|
| Risk Score | 30% | 0–100 from risk engine |
| Business Criticality | 35% | mission_critical=90, high=60, medium=30, low=10 |
| Time to Impact | 20% | ≤15m=95, ≤30m=75, ≤60m=50, >60m=25 |
| Scope (node count) | 15% | Scales with number of affected sites |
Located in services/copilot/. A context-grounded diagnostic assistant with deterministic fallback.
Context Engine (context/engine.py): For a given site, retrieves the full topology subgraph (devices, interfaces, tunnels), active anomalies, latest risk scores, and recent forecasts into a single structured context dictionary.
Retrieval Layer (retrieval/): Keyword-matches the user's question against 6 bundled runbooks: congestion, high_latency, interface_flapping, packet_loss, route_instability, tunnel_failure.
LLM Client (llm/): Calls the local Ollama /api/generate endpoint with the context-injected prompt. Enforces a 4-second timeout. On failure, delegates to generate_fallback_response() which builds a structured diagnostic from the raw context data without LLM involvement — ensuring responses are always grounded and never hallucinated.
Memory (memory/): Per-session memory cache for conversation continuity.
Located in apps/api/src/api/v1/endpoints/incidents.py.
GET /api/v1/incidents— Paginated incident list with status/severity filtering (requiresviewer+)GET /api/v1/incidents/correlated— Triggers a live correlation run (requiresoperator+)GET /api/v1/incidents/{id}— Single incident detail viewPOST /api/v1/incidents/export— Export incident to external webhook endpointPOST /api/v1/incidents/integrations/webhook— Inbound alert receiver from external systems
- Prometheus: Scrapes the
/metricsendpoint on the API. Tracksapi_requests_total,api_request_latency_seconds,incidents_generated_total,copilot_queries_total,webhook_delivery_total. - Grafana: Pre-configured dashboard at
infrastructure/monitoring/grafana/dashboards/system_health.jsonwith panels for API request rate and incident severity distribution.
- Docker Compose:
docker-compose.ymldefines 13 services including API, Dashboard, Telemetry Worker, Prediction Worker, Copilot Worker, TimescaleDB, Qdrant, Redpanda, Ollama, Prometheus, and Grafana. - Helm Chart:
infrastructure/helm/(Chart v0.1.0) provides Kubernetes Deployment, Service, and Ingress templates parameterized viavalues.yaml. - Network Policies:
infrastructure/k8s/network-policies/implements default-deny-all and allow-internal-db policies for namespace isolation.
Eleven tables across the SQLAlchemy ORM, all mapped from packages/shared/src/plutopus_shared/models.py.
erDiagram
sites {
string id PK
string name
string role
string business_criticality
}
devices {
string id PK
string site_id FK
string name
string role
string ip
string business_criticality
}
interfaces {
string id PK
string device_id FK
string name
string type
string status
}
tunnels {
string id PK
string src_interface_id FK
string dst_interface_id FK
string status
}
metrics {
int id PK
string target_id
string name
float value
datetime timestamp
}
events {
int id PK
string device_id FK
string severity
string message
datetime timestamp
}
anomalies {
int id PK
string entity_id
string entity_type
string metric
string severity
float score
string description
datetime timestamp
}
forecasts {
int id PK
string target_id
string metric
float current_val
float forecast_15m
float forecast_30m
float forecast_60m
float confidence
datetime timestamp
}
risk_scores {
int id PK
string entity_id
string entity_type
int risk_score
string risk_level
string signals
datetime timestamp
}
incidents {
string id PK
string title
string severity
int priority
string status
string root_cause
float confidence
string affected_entities
string source_anomalies
datetime created_at
}
audit_logs {
int id PK
datetime timestamp
string username
string action
string resource
string resource_id
string result
string source_ip
}
sites ||--o{ devices : "contains"
devices ||--o{ interfaces : "has"
devices ||--o{ events : "generates"
interfaces ||--o{ tunnels : "src_interface"
interfaces ||--o{ tunnels : "dst_interface"
All routes are served under the /api/v1 prefix. Interactive documentation available at http://localhost:8000/docs.
| Route Group | Prefix | Auth Required | Roles |
|---|---|---|---|
| Health | /health |
No | — |
| Sites | /api/v1/sites |
Yes | viewer+ |
| Devices | /api/v1/devices |
Yes | viewer+ |
| Tunnels | /api/v1/tunnels |
Yes | viewer+ |
| Metrics | /api/v1/metrics |
Yes | viewer+ |
| Events | /api/v1/events |
Yes | viewer+ |
| Topology | /api/v1/topology |
Yes | viewer+ |
| Predictions | /api/v1/predictions/* |
Yes | viewer+ |
| Copilot | /api/v1/copilot/* |
Yes | operator+ |
| Incidents | /api/v1/incidents |
Yes | viewer+ |
| Incident Correlation | /api/v1/incidents/correlated |
Yes | operator+ |
| Incident Export | /api/v1/incidents/export |
Yes | operator+ |
| Audit Logs | /api/v1/audit/logs |
Yes | admin only |
| Prometheus Metrics | /metrics |
No | — |
Prediction Endpoints
| Endpoint | Method | Description |
|---|---|---|
/api/v1/predictions/forecasts |
GET | Latest forecasts per interface |
/api/v1/predictions/anomalies |
GET | Active anomalies with severity |
/api/v1/predictions/risk |
GET | Current risk scores per entity |
Topology Endpoints
| Endpoint | Method | Description |
|---|---|---|
/api/v1/topology/graph |
GET | Full NetworkX graph as adjacency JSON |
/api/v1/topology/sites/{id}/health |
GET | Site health score and signals |
/api/v1/topology/paths |
GET | Shortest paths between two sites |
Copilot Endpoints
| Endpoint | Method | Description |
|---|---|---|
/api/v1/copilot/query |
POST | Submit a diagnostic question |
/api/v1/copilot/context/{site_id} |
GET | Retrieve the context payload for a site |
/api/v1/copilot/runbooks |
GET | List all available runbooks |
The Copilot is a retrieval-augmented diagnostic assistant that runs entirely on local infrastructure. It never sends data to external APIs.
- Context Assembly:
CopilotContextEnginequeries TimescaleDB for the site's full inventory, active anomalies, latest risk scores, and forecast horizon. - Runbook Retrieval: Keyword matching against 6 structured markdown runbooks selects the most relevant procedures.
- Prompt Construction: Context and runbooks are serialized and injected into a system prompt with explicit grounding instructions.
- LLM Call: The Ollama
/api/generateAPI is called with a 4-second timeout. Default model:qwen:0.5b. - Fallback: If Ollama is unavailable or times out,
generate_fallback_response()constructs a deterministic diagnostic from the raw context data. No response is ever hallucinated. - Source Attribution: Every response includes
context_usedandrunbooksfields listing exactly what data sourced the answer.
| Runbook | Trigger Keywords |
|---|---|
congestion.md |
congestion, utilization, bandwidth, saturation |
high_latency.md |
latency, delay, RTT, slow |
interface_flapping.md |
flapping, cycling, instability, up/down |
packet_loss.md |
loss, drops, reachability |
route_instability.md |
BGP, route, prefix, instability |
tunnel_failure.md |
tunnel, VPN, down, failed |
The prediction engine runs as a scheduled background worker with these stages:
- Algorithm: Ordinary least squares linear trend fitting
- Input: Last 15 metric samples per interface/tunnel
- Output:
forecast_15m,forecast_30m,forecast_60m+confidencecoefficient - Metrics covered:
utilization,latency,packet_loss
- Algorithm: Z-score deviation from historical mean
- Thresholds: Configurable by severity level
- Output:
severity(info/warning/critical),score,description
- Output: Integer 0–100 per site and tunnel
- Levels:
low(0–25),moderate(26–50),elevated(51–75),high(76–100) - Signal attribution: JSON list of contributing factors stored per score record
Incidents are created by the EventCorrelationEngine, not the prediction worker directly. The prediction worker feeds the anomaly table which the correlation engine then processes on demand.
Plutopus is designed to operate in fully isolated, offline environments.
The distribution/pack-offline-bundle.sh script assembles a self-contained deployment archive:
./distribution/pack-offline-bundle.sh
# Produces: plutopus-offline-bundle.tar.gz
# Checksum: distribution/checksums/plutopus-offline-bundle.tar.gz.sha256Bundle contents:
distribution/docker-images/— Docker image tarballsdistribution/models/— Ollama model export/import scriptsdistribution/runbooks/— Offline copies of all runbooksdistribution/deployment/helm/— Bundled Helm chart
# Export a locally-pulled Ollama model
./distribution/models/export-model.sh qwen:0.5b ./models
# Produces: ollama_model_qwen_0.5b.tar + .sha256
# Import on target host
./distribution/models/import-model.sh ./models/ollama_model_qwen_0.5b.tarSetting AIRGAP_MODE=true signals the platform to enforce offline constraints. Verification:
AIRGAP_MODE=true ./scripts/airgap/verify.sh
# Produces: airgap-report.mdThe verification script checks:
AIRGAP_MODEenvironment variable is set- Outbound HTTP is not reachable
- All model storage is local
tar -xzf plutopus-offline-bundle.tar.gz
docker load -i distribution/docker-images/plutopus_images.tar
AIRGAP_MODE=true docker compose up -d- Standard: HS256 JWT tokens issued by
create_access_token()with 60-minute expiry - Key Rotation: Multiple signing keys supported via
JWT_ROTATION_SECRETSenv var (comma-separated). Decoding is attempted against each key in order. - Minimum Key Length: Keys shorter than 32 characters raise a
ValueErrorat startup — the API will not start with a weak secret.
Three roles enforced at the route level via RoleChecker FastAPI dependencies:
| Role | Capabilities |
|---|---|
viewer |
Read-only access to inventory, metrics, incidents, forecasts |
operator |
viewer + incident correlation triggers, copilot queries, webhook exports |
admin |
operator + audit log access, all management operations |
Every authentication event, resource access, and export action is recorded to the immutable audit_logs table via log_audit_event(). Fields: timestamp, username, action, resource, resource_id, result, source_ip.
Kubernetes NetworkPolicy resources in infrastructure/k8s/network-policies/:
default-deny-all.yaml— Denies all ingress and egress by default in theplutopusnamespaceallow-internal.yaml— Permits API pods to communicate with the database pods only
All API inputs are validated through Pydantic model schemas before handler execution. SQLAlchemy parameterized queries prevent SQL injection.
The /metrics endpoint (no authentication required) exposes:
| Metric | Type | Description |
|---|---|---|
api_requests_total |
Counter | Total API requests by method, endpoint, status |
api_request_latency_seconds |
Histogram | Request processing duration by method, endpoint |
prediction_jobs_total |
Counter | Prediction worker job completions by status |
copilot_queries_total |
Counter | Copilot request count by status |
incidents_generated_total |
Counter | Incidents created by severity |
webhook_delivery_total |
Counter | Outbound webhook deliveries by status |
Prometheus is configured to scrape the API every 15 seconds (infrastructure/monitoring/prometheus.yml).
Pre-configured dashboard (infrastructure/monitoring/grafana/dashboards/system_health.json) with panels for:
- API request rate (by endpoint and status code)
- Correlated incident severity distribution
Grafana is available at http://localhost:3001 (admin/admin).
curl http://localhost:8000/health
# {"status": "healthy"}- Docker Engine 24+ and Docker Compose v2
- Node.js 20+ (dashboard development only)
- Python 3.9+ (development/testing only)
# Clone the repository
git clone https://github.com/ayushkumar2601/Plutopus.git
cd Plutopus
# Configure environment
cp .env.example .env
# Start all 13 services
docker compose up -d
# Verify services are healthy
docker compose ps
curl http://localhost:8000/healthService ports after startup:
| Service | Port | URL |
|---|---|---|
| FastAPI | 8000 | http://localhost:8000 |
| Dashboard | 3000 | http://localhost:3000 |
| Grafana | 3001 | http://localhost:3001 |
| Prometheus | 9090 | http://localhost:9090 |
| TimescaleDB | 5432 | — |
| Redpanda (Kafka) | 19092 | — |
| Ollama | 11434 | http://localhost:11434 |
| Qdrant | 6333 | http://localhost:6333 |
# Seed the lab topology (sites, devices, interfaces, tunnels)
docker compose exec api python services/topology/seed.py
# Inject synthetic telemetry
python scripts/generate-demo-telemetry.py# Deploy to a Kubernetes cluster
helm install plutopus ./infrastructure/helm/ \
--namespace plutopus \
--create-namespace \
--set image.tag=latest
# Apply network isolation policies
kubectl apply -f infrastructure/k8s/network-policies/# On internet-connected machine:
./distribution/pack-offline-bundle.sh
# Transfer plutopus-offline-bundle.tar.gz to isolated host
# On isolated host:
tar -xzf plutopus-offline-bundle.tar.gz
docker load -i distribution/docker-images/plutopus_images.tar
./distribution/models/import-model.sh ./distribution/models/ollama_model_qwen_0.5b.tar
AIRGAP_MODE=true docker compose up -d- Python 3.9+
- Node.js 20+
- Docker + Docker Compose
# Create virtual environment
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# Install shared packages (editable)
pip install -e packages/shared
pip install -e packages/schemas
# Install API dependencies
pip install -e apps/api
# Install prediction service
pip install -e services/prediction
# Install copilot service
pip install -e services/copilot
# Start infrastructure services only
docker compose up postgres redpanda qdrant ollama -d
# Run the API locally
cd apps/api/src && uvicorn main:app --reload --port 8000cd apps/dashboard
npm install
npm run dev
# Dashboard available at http://localhost:3000| Variable | Default | Description |
|---|---|---|
DATABASE_URL |
postgresql://postgres:postgres@localhost:5432/plutopus |
TimescaleDB connection string |
REDPANDA_BROKERS |
localhost:19092 |
Kafka-compatible broker address |
OLLAMA_BASE_URL |
http://localhost:11434 |
Ollama inference server URL |
OLLAMA_MODEL |
qwen:0.5b |
Model name for copilot queries |
JWT_SECRET |
— | JWT signing key (min. 32 characters) |
JWT_ROTATION_SECRETS |
— | Comma-separated rotation key list |
PREDICTION_INTERVAL |
300 |
Prediction worker sleep interval (seconds) |
AIRGAP_MODE |
false |
Enables offline-only enforcement |
NEXT_PUBLIC_API_URL |
http://localhost:8000 |
API URL for dashboard |
# Activate virtual environment
source .venv/bin/activate
# Run all tests
pytest tests/
# Run with coverage report
pytest --cov=apps/api --cov=services/ --cov-report=term-missing tests/
# Run a specific phase suite
pytest tests/test_phase5.py -v| Module Group | Tests | Coverage |
|---|---|---|
| API Gateway (endpoints, auth, metrics) | 15 | ~91% |
| Topology Engine (graph, health, intelligence) | 7 | ~93% |
| Prediction Engine (forecasting, anomaly, risk) | 7 | ~88% |
| Copilot Service (context, LLM, retrieval) | 7 | ~93% |
| Incident Management + Correlation Engine | 9 | ~92% |
| Audit Logging + Air-Gap (Phase 6) | 4 | ~87% |
| Total | 45 | 90% |
| File | Scope |
|---|---|
test_api.py |
Core API endpoint integration tests |
test_normalization.py |
Telemetry normalization logic |
test_phase2.py |
Topology graph, health scoring, path analysis |
test_phase3.py |
Forecasting, anomaly detection, risk scoring |
test_phase4.py |
Copilot context, LLM fallback, retrieval |
test_phase5.py |
Incident correlation, RBAC, webhooks |
test_phase6.py |
Audit logs, JWT rotation, air-gap mode |
test_seeding.py |
Lab topology seeder |
test_topology.py |
NetworkX graph construction |
Benchmarks measured on local development hardware (Apple M-series, 16 GiB RAM) during integration testing:
| Operation | Measured Latency | Target |
|---|---|---|
API health check (/health) |
< 1ms | < 10ms |
| JWT token validation | ~0.8ms | < 100ms |
| Incident correlation run | ~22ms | < 2000ms |
| Incident priority scoring | ~15ms | < 1000ms |
| Outbound webhook dispatch | ~10ms (mock) | < 3000ms |
| Copilot context assembly | ~45ms | < 500ms |
| Ollama inference (qwen:0.5b) | ~800ms–2000ms | < 4000ms |
| Copilot fallback response | < 5ms | < 100ms |
| Forecast generation (per entity) | ~3ms | < 50ms |
| Air-gap verification script | ~3s | < 60s |
| Full test suite (45 tests) | ~1.3s | — |
| Area | Status | Notes |
|---|---|---|
| Air-Gap Deployment | ✅ Ready | Full offline bundle with model packaging and checksum verification |
| Security | ✅ Hardened | JWT with rotation, RBAC, 32-char key enforcement, audit logs |
| Backup Strategy | ✅ Implemented | pg_dump automation, restore scripts, validation reporter |
| Recovery Procedures | ✅ Documented | Runbooks in docs/runbooks/disaster-recovery.md |
| Monitoring | ✅ Operational | Prometheus scraping + Grafana dashboards |
| Compliance | ✅ Documented | docs/compliance/compliance-readiness.md (AU-2, SC-7, MP-6) |
| Horizontal Scaling | ✅ Documented | docs/capacity-planning.md (100–5000 devices) |
| Database Upgrade | ✅ Scripted | scripts/upgrade/ with pre-upgrade backup + rollback |
| Kubernetes Deploy | ✅ Ready | Helm chart v0.1.0 with NetworkPolicies |
| Phase | Objective | Key Deliverables | Status |
|---|---|---|---|
| Phase 1 | Telemetry Foundation | Redpanda pipeline, TimescaleDB, FastAPI scaffold, Demo generator | ✅ Complete |
| Phase 2 | Topology Intelligence | NetworkX graph, site health scoring, path analysis, topology dashboard | ✅ Complete |
| Phase 3 | Predictive Analytics | Linear forecasting, Z-score anomaly, 0-100 risk scores, explainability | ✅ Complete |
| Phase 4 | AI Copilot | Context engine, Ollama integration, runbook retrieval, chat dashboard | ✅ Complete |
| Phase 5 | Workflow Automation | Event correlation, incident management, RBAC, Prometheus, Helm, webhooks | ✅ Complete |
| Phase 6 | Air-Gap & Hardening | Offline bundle, model packaging, audit logs, K8s policies, capacity planning | ✅ Complete |
The following capabilities are not yet implemented and represent realistic next steps:
- Multi-tenancy: Organization-scoped data isolation within a shared database
- OAuth 2.0 / SSO: OIDC integration to replace local JWT issuance
- High-Availability Deployments: Multi-replica services with shared session state
- Distributed LLM Inference: vLLM or Triton backends for larger model support
- Automated Topology Discovery: SNMP/gRPC-based device discovery to replace YAML seeding
- Multi-Cluster Support: Federation of multiple Plutopus instances across regions
Contributions are welcome. Please follow this workflow:
- Fork the repository and create a feature branch from
main - Read the architecture documents in
docs/architecture/before implementing - Check existing ADRs in
docs/adr/to understand prior decisions - Write tests for any new module. Coverage regression below 85% will block merge
- Update documentation:
documentation.mdmust reflect any state change - Commit convention: Use
type(scope): description— e.g.,feat(copilot): add memory persistence
- Python type annotations are required on all function signatures
- All API responses must use defined Pydantic schemas
- No external HTTP calls from within the API process (copilot Ollama calls are via
services/copilot/llm/) - Database queries must go through the
packages/sharedORM layer
./scripts/security-audit/audit.sh
# Produces: security-audit-report.mdMIT License
Copyright (c) 2025 Ayush Kumar
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Built for NOC teams operating real SD-WAN and MPLS networks.