MCPcopy Index your code
hub / github.com/VersusControl/versus-incident

github.com/VersusControl/versus-incident @v1.4.8

Chat with this repo
repository ↗ · DeepWiki ↗ · release v1.4.8 ↗ · + Follow
3,004 symbols 10,819 edges 406 files 1,463 documented · 49% updated 1d agov1.4.8 · 2026-07-06★ 636
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Versus

Go Report Card License: MIT Sponsor

Versus Incident is the self-hosted AI SRE agent. It learns what your systems normally look like and escalates only what is new or unexpected issues — routing to your chat channels and on-call platform.

Free with MIT license · Enterprise Pricing

Versus

How Versus Creates Incidents

Incidents reach Versus two ways, and both are handled by the same notification, templating, and on-call logic:

  • AI SRE Agent (auto-detect) — point the agent at your logs and it learns your normal patterns, then automatically raises an incident when a brand-new error or anomaly appears. No alert rules to maintain.
  • Webhook alerts (you define) — any tool that can POST a webhook (Alertmanager, Grafana, Sentry, CloudWatch SNS, FluentBit, or your own scripts) sends incidents straight to Versus, formatted with your own templates.

Whichever source raises it, an incident is templated, fanned out to every channel you enable, and escalated to on-call if it isn't acknowledged in time.

Features

  • 🤖 AI SRE Agent (Beta): An AI agent that reads your logs, learns what normal looks like, and automatically opens an incident only when something new and unexpected appears.
  • 🌐 Webhook Alerts: Receive incidents from any tool that can POST a webhook — Alertmanager, Grafana, Sentry, CloudWatch SNS, FluentBit, and more.
  • 🚨 Multi-channel Notifications: Fan out every incident to Slack, Microsoft Teams, Telegram, Viber, Email, and Lark (more channels coming!)
  • 📝 Custom Templates: Define your own alert messages using Go templates
  • 🔧 Easy Configuration: YAML-based configuration with environment variables support
  • 📡 REST API: Simple HTTP interface to receive alerts
  • 📞 On-Call: On-Call integrations (PagerDuty, Opsgenie, incident.io, ServiceNow)

Versus

Table of Contents

Get Started

Auto-detect incidents with the AI SRE Agent

Let the agent learn your logs and surface what's new. The AI SRE Agent has three modes:

  • training — just watch and learn. No alerts.
  • shadow — watch and learn, plus write a "would have alerted" log entry every time a line would have triggered an alert. Still no real alerts. Good for checking the agent's judgement before going live.
  • detect — actually create incidents for lines the agent has never seen before. An AI SRE triages each one and writes the summary, severity, and suggested next steps before the incident is sent through every configured channel.

Start it in training mode — it only watches and learns, and never sends an alert until you're ready.

# Redis is used to remember where the agent left off in each log source.
docker run -d --name versus-redis -p 6379:6379 redis:7

docker run -p 3000:3000 \
  -e GATEWAY_SECRET=change-me \
  -e AGENT_ENABLE=true \
  -e AGENT_MODE=training \
  -e REDIS_HOST=host.docker.internal \
  -e REDIS_PORT=6379 \
  -v $(pwd)/config:/app/config \
  -v $(pwd)/data:/app/data \
  ghcr.io/versuscontrol/versus-incident

The agent needs a config.yaml and an agent_sources.yaml that point it at your logs. Once it's running, review the patterns it learns on the admin dashboard at http://localhost:3000/, then switch AGENT_MODE from trainingshadowdetect when you trust it.

Full walkthrough (with ready-to-copy config and a sample log generator): AI Agent — Getting Started.

Forward alerts from your existing tools

Already have monitoring? Run Versus and POST your alerts to its webhook endpoint.

docker run -p 3000:3000 \
  -e GATEWAY_SECRET=change-me \
  -e SLACK_ENABLE=true \
  -e SLACK_TOKEN=your_token \
  -e SLACK_CHANNEL_ID=your_channel \
  ghcr.io/versuscontrol/versus-incident

Versus listens on port 3000 by default and exposes:

  • POST /api/incidents — webhook endpoint for monitoring tools.
  • GET / — the embedded admin dashboard, open http://localhost:3000/ in your browser. For the full UI walkthrough and the build/watch scripts, see Admin Dashboard.

You can use both. The AI agent and webhook alerts are not mutually exclusive — run them together and every incident, whether auto-detected or forwarded from your tools, flows through the same channels, templates, and on-call logic.

AI Agent

The AI SRE agent is what makes Versus different: point it at your logs and it learns what normal looks like, then automatically opens an incident the moment a brand-new error or anomaly appears — no alert rules to maintain.

Configuration example with agent features:

name: versus
host: 0.0.0.0
port: 3000

# ... existing alert configurations ...

# Shared secret required for ALL admin endpoints (`/api/admin/*` and
# `/api/agent/*`). Sent by clients in the `X-Gateway-Secret` header.
gateway_secret: ${GATEWAY_SECRET}

# Storage backend for the pattern catalog, shadow log, and incident
# history. Only `file` is implemented today; `redis` and `database`
# are config stubs.
storage:
  type: file              # file | redis | database (env: STORAGE_TYPE)
  file:
    max_incidents: 1000   # rolling cap on persisted incidents

agent:
  enable: false # Use this to enable or disable the agent for all sources
  mode: training # Valid values: "training", "shadow", or "detect"
  poll_interval: 30s

  # Sources are kept in a separate file so they can be managed independently
  # (e.g. swap fixtures, per-environment lists). Path is resolved relative to
  # this config file. Override via env: AGENT_SOURCES_PATH.
  sources_path: ./agent_sources.yaml

  catalog:
    persist_interval: 30s
    auto_promote_after: 100 # In detect mode, this many sightings = "known"

  redaction:
    enable: true
    redact_ips: false
    extra_patterns: # Optional: extra regex rules to scrub before clustering
      - "(?i)password=\\S+"
      - "Authorization:\\s*Bearer\\s+\\S+"

  miner:
    similarity_threshold: 0.4
    tree_depth: 4
    max_children: 100

  regex:
    # Optional: tag any signal whose message matches this pattern
    # if none of the named rules below hit. Leave empty to disable.
    default_pattern: "(?i)error|exception|fatal|panic"
    # Named rules are tried first, in order. The first match wins.
    rules:
      - name: oom
        pattern: "(?i)out of memory|OOMKilled|java\\.lang\\.OutOfMemoryError"
      - name: db-timeout
        pattern: "(?i)(connection|query) timeout|deadlock detected"
      - name: auth-failure
        pattern: "(?i)401 unauthorized|invalid credentials|permission denied"

redis: # Required for the agent to persist source cursors across restarts
  host: ${REDIS_HOST}
  port: ${REDIS_PORT}
  password: ${REDIS_PASSWORD}
  db: 0

Explanation:

The agent section includes: 1. enable: Turn the agent on or off (default: false). When disabled, nothing extra runs — no background processes, no extra files written. 2. mode: How the agent behaves after it has learned your log patterns: - training: observation only — the agent learns patterns and saves them, but sends no alerts. - shadow: same as training, but also logs a note every time it would have sent an alert. Good for reviewing before going live. - detect: the agent actively sends alerts for any pattern it has never seen before. 3. poll_interval: How often the agent checks your log sources for new entries. 4. catalog: Where the agent stores the list of known patterns and how often to write updates. mode selects the storage backend — only file is supported today, which writes to data/patterns.json (the filename and directory are fixed).

Admin secret. All admin endpoints (/api/admin/* and /api/agent/*) are protected by the root-level gateway_secret (env GATEWAY_SECRET). Set it to any value you choose; clients send the same value in the X-Gateway-Secret header. When no secret is configured the admin endpoints are not registered and the agent refuses to start.

Storage. The agent's catalog and the incident history shown in the UI are persisted via the root-level storage: block (default: type: file). The file backend writes to the fixed ./data directory (/app/data in the container image). 5. redaction: Rules for automatically removing sensitive information (passwords, tokens, emails, etc.) from logs before the agent processes them. 6. miner: Controls how aggressively the agent groups similar log lines together. The defaults work well for most setups. 7. regex: Acts as a pre-filter for the agent. Only signals whose message matches at least one rule (a named entry under rules or default_pattern) are forwarded to the pattern miner and stored in the catalog. Anything that doesn't match is dropped before clustering, so boring noise (200-OK requests, debug lines, etc.) never bloats patterns.json.

  • Named rules are tried in order; the first match wins and tags the signal with that name (stored as rule_name on the pattern).
  • If no named rule hits, default_pattern is tried. Matches there are tagged with name=default.
  • To learn from every line, set default_pattern: ".*". This is useful in early training when you don't yet know what's interesting.
  • To filter aggressively, set default_pattern: "" (empty) and rely on your named rules — anything that doesn't match an explicit rule is dropped.
  • sources_path: Path to a separate YAML file that lists the log sources the agent should read from. Keeping sources in their own file makes it easier to manage per-environment source lists or swap fixtures without touching the rest of the config. The path is resolved relative to the main config file. Override via the AGENT_SOURCES_PATH env var.

The sources file (default ./agent_sources.yaml) has a single top-level sources: list. Each entry needs name, type (file or elasticsearch), enable, plus a matching file: or elasticsearch: block. Example:

sources:
  - name: prod-app
    type: elasticsearch
    enable: true
    elasticsearch:
      addresses:
        - https://es.example.internal:9200
      username: ${ES_USERNAME}
      password: ${ES_PASSWORD}
      index: "logs-app-*"
      time_field: "@timestamp"
      query: 'log.level:(error OR warn)'
      message_field: message
      page_size: 500

  - name: sample-app
    type: file
    enable: true
    file:
      path: ./local/resource/sample-app.log
      format: text
      from_beginning: true

The redis section is required when agent.enable is true. Redis is used to remember where the agent left off in each log source, so it picks up from the right place after a restart.

For detailed information on integration, please refer to the document here: Enable AI Agent.

Webhook Alerts

Already using other monitoring tools? Versus also accepts incidents from anything that can POST JSON to /api/incidents, so you can route existing alerts through the same channels, templates, and on-call.

Universal Alert Template Support

Our default template (Slack, Telegram) automatically handles alerts from multiple sources, including: - Alertmanager (Prometheus) - Grafana Alerts - Sentry - CloudWatch SNS - FluentBit

Example JSON Payload Sent by Alertmanager

```bash curl -X POST "http://localhost:3000/api/incidents" \ -H "Content-Type: application/json" \ -d '{ "receiver": "webhook-incident", "status": "firing", "alerts": [ {
"status": "firing",
"labels": {
"alertname": "PostgresqlDown", "instance": "postgresql-prod-01", "severity": "critical" },
"annotations": {
"summary": "Postgresql down (instance postgresql-prod-01)", "description": "Postgresql instance is down." },
"startsAt": "2023-10-01T12:34:56.789Z",
"endsAt": "2023-10-01T12:44:56.789Z",
"generatorURL": "" }
],
"groupLabels": {
"alertname": "PostgresqlDown"
},
"commonLabels": {
"alertname": "PostgresqlDown",
"severity": "critical", "instance": "postgresql-prod-01"

Extension points exported contracts — how you extend this code

SignalSource (Interface)
SignalSource is a puller for one external observability backend (Elasticsearch, Loki, CloudWatch, ...). [15 implementers]
pkg/core/agent_signal.go
Index (Interface)
Index is the read-only search seam the find_runbook tool depends on (via a local interface in the tools package). Implem [5 …
pkg/runbook/vectorindex/vectorindex.go
RunbookSearcher (Interface)
RunbookSearcher is the read-only vector-search seam the find_runbook tool depends on. Declared as a local interface (not [5 …
pkg/agent/ai/analyze/tools/find_runbook.go
Provider (Interface)
Provider is the storage interface used by the agent and incident service. [3 implementers]
pkg/storage/storage.go
AlertConfigResolver (Interface)
alertresolver.go — the single-slot runtime notification-channel config resolver seam. It lets a consumer (the enterpris [2 …
pkg/config/alertresolver.go
AdminAuditHook (FuncType)
AdminAuditHook records one admin mutation. It receives the request ctx so an implementation can derive the actor, org an
pkg/middleware/admin_audit.go
Factory (FuncType)
----------------------------------------------------------------------------- Signal-source registration hook. The OSS
pkg/signalsources/registry.go
ServiceOverride (Interface)
(no doc) [2 implementers]
ui/src/lib/api.ts

Core symbols most depended-on inside this repo

Add
called by 199
pkg/runbook/vectorindex/vectorindex.go
Get
called by 198
pkg/agent/mode.go
Close
called by 186
pkg/storage/storage.go
NewMemory
called by 131
pkg/storage/memory.go
Set
called by 129
pkg/agent/cursors.go
Run
called by 91
pkg/core/ai_task.go
Len
called by 74
pkg/agent/catalog.go
LoadCatalog
called by 68
pkg/agent/catalog.go

Shape

Function 1,791
Method 690
Struct 360
Interface 139
Class 11
FuncType 7
TypeAlias 6

Languages

Go77%
TypeScript17%
Python5%

Modules by API surface

scripts/generate_noisy_logs.py139 symbols
ui/src/lib/api.ts87 symbols
pkg/controllers/agent.go45 symbols
pkg/config/config.go37 symbols
pkg/agent/ai/analyze/agent_test.go36 symbols
pkg/storage/storage.go33 symbols
pkg/services/report_test.go32 symbols
pkg/storage/postgres.go29 symbols
pkg/services/report.go28 symbols
pkg/agent/worker.go28 symbols
pkg/config/clone_config.go27 symbols
pkg/agent/catalog.go27 symbols

Datastores touched

versusDatabase · 1 repos
testdbDatabase · 1 repos
(mongodb)Database · 1 repos
graylogDatabase · 1 repos
appDatabase · 1 repos
dbDatabase · 1 repos
noneDatabase · 1 repos

For agents

$ claude mcp add versus-incident \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact