open source · Apache 2.0 · self-hostable

The data layer for
your security agents

Calseta ingests security alerts, enriches indicators, and delivers normalized, context-rich payloads — so agents focus on reasoning and response, not plumbing.

Without CalsetaElastic Security · ECS
// Raw Elastic Security alert (ECS format)
{
  "@timestamp": "2025-01-15T03:42:18.441Z",
  "event": {
    "kind": "signal",
    "module": "siem",
    "category": ["authentication"],
    "type": ["indicator"],
    "severity": 73,
    "dataset": "kibana.siem_signals"
  },
  "kibana.alert.rule": {
    "name": "Impossible Travel",
    "description": "Detects user authentication events from two geographically distant locations...",
    "uuid": "a3f2c8e1-4b9d-4e7f-b2a1-8c3d5e9f1a2b",
    "rule_id": "impossible-travel-v1",
    "type": "query",
    "severity": "high",
    "risk_score": 73,
    "tags": ["Elastic", "Authentication", "Identity"]
  },
  "kibana.alert.status": "open",
  "kibana.alert.severity": "high",
  "kibana.alert.risk_score": 73,
  "kibana.alert.reason": "authentication event with high risk score 73 created high alert Impossible Travel.",
  "user": {
    "name": "nick.hathaway",
    "email": "nick.hathaway@calseta.com",
    "domain": "calseta.com",
    "id": "U0K4X8J2"
  },
  "source": {
    "ip": "185.220.101.47",
    "geo": {
      "country_name": "Germany",
      "city_name": "Frankfurt am Main",
      "country_iso_code": "DE"
    }
  },
  "related": {
    "ip": ["185.220.101.47", "67.180.201.3"],
    "user": ["nick.hathaway"]
  },
  "user_agent": {
    "original": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    "name": "Chrome",
    "version": "120.0.6099.130",
    "os": { "name": "Windows", "version": "10" }
  },
  "kibana.alert.original_event": {
    "action": "user-login",
    "outcome": "success",
    "provider": "okta"
  },
  "signal.original_event": {
    "previous_login": {
      "@timestamp": "2025-01-15T01:10:42.000Z",
      "source.ip": "67.180.201.3",
      "source.geo.country_name": "United States"
    },
    "distance_km": 9349,
    "time_delta_minutes": 148
  },
  "okta": {
    "actor": {
      "id": "00u3abc123XYZ789",
      "type": "User",
      "display_name": "Nick Hathaway",
      "alternate_id": "nick.hathaway@calseta.com"
    },
    "client": {
      "device": "Computer",
      "ip_address": "185.220.101.47",
      "user_agent": {
        "raw_user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
        "os": "Windows",
        "browser": "Chrome"
      },
      "zone": "null",
      "geographic_context": {
        "city": "Frankfurt am Main",
        "country": "Germany",
        "geolocation": { "lat": 50.1109, "lon": 8.6821 },
        "postal_code": "60325",
        "state": "Hessen"
      }
    },
    "authentication_context": {
      "authentication_provider": "FACTOR_PROVIDER",
      "credential_provider": "OKTA_CREDENTIAL_PROVIDER",
      "authentication_step": 0,
      "external_session_id": "trs7xRk4lGm9pQ2wVnCdE1oYA"
    },
    "security_context": {
      "as": { "number": 4224, "organization": { "name": "Tor Project, Inc." } },
      "isp": "Tor Project",
      "domain": "torproject.org",
      "is_proxy": true
    },
    "outcome": { "result": "SUCCESS" },
    "event_type": "user.authentication.auth_via_mfa",
    "uuid": "fpuc9o26-a2e8-4c57-bedf-8bcf36e5e8f9",
    "published": "2025-01-15T03:42:18.441Z",
    "transaction": { "id": "Wf7DEobdNHxq2IQfkSjX5wAABmo", "type": "WEB" }
  }
}
With CalsetaNormalized · Enriched · Context-ready
// Calseta enriched alert payload (normalized + enriched + context)
{
  "event": "alert.enriched",

  "alert": {
    "uuid": "9f2a-b3c1-...",
    "title": "Impossible Travel Detected",
    "severity": "High",
    "source": "elastic",
    "status": "New",
    "created_at": "2025-01-15T03:42:18.441Z"
  },

  "indicators": [
    {
      "type": "ip",
      "value": "185.220.101.47",
      "first_seen": "2024-08-12T00:00:00.000Z",
      "last_seen": "2025-01-15T03:42:18.441Z",
      "geo": { "country": "Germany", "city": "Frankfurt am Main" },
      "virustotal": { "malicious": 14, "suspicious": 2, "score": "47/94" },
      "abuseipdb": { "score": 97, "categories": ["hacking", "vpn"] },
      "greynoise": { "noise": true, "riot": false, "classification": "malicious", "name": "TOR Exit Node", "last_seen": "2025-01-15" }
    },
    {
      "type": "ip",
      "value": "67.180.201.3",
      "first_seen": "2022-03-05T00:00:00.000Z",
      "last_seen": "2025-01-15T01:10:42.000Z",
      "geo": { "country": "United States", "city": "San Francisco" },
      "virustotal": { "malicious": 0, "suspicious": 0, "score": "0/94" },
      "abuseipdb": { "score": 4, "categories": [] }
    },
    {
      "type": "account",
      "value": "nick.hathaway@calseta.com",
      "okta": {
        "status": "ACTIVE",
        "profile": {
          "full_name": "Nick Hathaway",
          "title": "Senior Software Engineer",
          "department": "Engineering",
          "employee_type": "employee",
          "location": "San Francisco, CA, US",
          "manager": "Emily Rhodes",
          "manager_email": "emily.rhodes@calseta.com"
        },
        "account_created": "2022-03-14T09:00:00.000Z",
        "last_login": "2025-01-14T22:31:05.000Z",
        "last_password_change": "2024-10-01T11:23:44.000Z",
        "mfa_factors": [
          { "type": "push", "provider": "OKTA", "status": "ACTIVE" },
          { "type": "totp", "provider": "GOOGLE", "status": "ACTIVE" }
        ],
        "group_membership": ["Engineering", "VPN-Users", "github-org-members"]
      }
    }
  ],

  "detection_rule": {
    "name": "Impossible Travel",
    "rule_id": "impossible-travel-v1",
    "enabled": true,
    "schedule": "every 10m",
    "severity": "High",
    "priority": "High — likely credential compromise or session hijacking",
    "mitre_tactics": ["TA0001 - Initial Access", "TA0005 - Defense Evasion", "TA0006 - Credential Access"],
    "mitre_techniques": ["T1078 - Valid Accounts"],
    "mitre_sub_techniques": ["T1078.004 - Cloud Accounts"],
    "data_sources": ["Entra ID Sign-In Logs", "Okta", "VPN Logs"],
    "threshold": { "field": "user.name", "condition": "multiple countries within 120m" },
    "suppression": { "field": "user.name", "duration": "1h" },
    "false_positive_tags": ["vpn", "corporate_proxy", "executive_travel"],
    "blind_spots": ["same-region cross-state travel", "VPN or proxy exit nodes", "inaccurate IP geolocation data"],
    "goal": "Detect credential compromise or session hijacking via geo-velocity analysis.",
    "documentation": "## Overview\nCorrelates sign-in timestamps and geolocation to flag logins from two countries within a short window — physically impossible without credential theft or session hijacking.\n\n## Blind Spots\n- VPN/proxy exit nodes in foreign countries\n- Same-region cross-state travel\n- Inaccurate IP-to-geo mapping\n\n## Responses\n1. Confirm travel or VPN activity with user\n2. Force sign-out and reset credentials\n3. Review concurrent risky sign-in alerts\n4. Notify SOC team of potential compromise"
  },

  "past_alerts": [
    {
      "uuid": "3c1d-a2f4-...",
      "title": "Impossible Travel Detected",
      "status": "closed",
      "classification": "true_positive_suspicious_activity",
      "closed_at": "2024-11-03T14:22:00.000Z",
      "indicators": ["91.108.56.130", "nick.hathaway@calseta.com"],
      "analyst_notes": "Confirmed malicious. Sessions revoked. Password reset. INC-2847."
    },
    {
      "uuid": "7e8b-c9d2-...",
      "title": "Impossible Travel Detected",
      "status": "closed",
      "classification": "benign_positive_suspicious_but_expected",
      "closed_at": "2024-09-17T09:14:00.000Z",
      "indicators": ["185.220.101.47", "nick.hathaway@calseta.com"],
      "analyst_notes": "VPN exit node. User confirmed travel. No action taken. INC-2601."
    }
  ],

  "context_documents": [
    {
      "title": "Company Incident Response Plan",
      "type": "ir_plan",
      "content": "## Incident Response Plan\n1. Detect & triage\n2. Contain affected accounts\n3. Notify security lead\n4. Preserve evidence\n5. Remediate & recover..."
    },
    {
      "title": "Account Compromise Runbook",
      "type": "runbook",
      "content": "## Account Compromise Response\n1. Isolate account\n2. Revoke active sessions\n3. Force password reset\n4. Re-enroll MFA..."
    }
  ],

  "workflows": [
    { "name": "Revoke User Sessions", "description": "Terminate all active sessions for the affected account across all providers." },
    { "name": "Force Password Reset", "description": "Expire current credentials and require the user to set a new password on next login." },
    { "name": "Request User Attestation", "description": "Send the user a confirmation request to verify whether the activity was theirs." },
    { "name": "Challenge User with MFA", "description": "Require step-up authentication before restoring account access." },
    { "name": "Notify Security Team", "description": "Page the on-call analyst and open a P1 incident ticket for human review." },
    { "name": "Escalate to Incident", "description": "Promote alert to a tracked incident, assign severity, and notify the incident commander." }
  ]
}
threat intel enrichment — automaticidentity & account context — automaticorg knowledge & history — surfaced+bring your own providers
The problem

Raw data. Missing context.

Security agents consistently hit the same three walls. Most engineering time goes to orchestrating tools, not reasoning.

1
Context gap
Your agent gets the alert but not the context around it — no runbook, no team history, no org-specific guidance. It falls back to generic analysis.
no org context
2
Integration burden
One alert investigation means 5+ API calls — SIEM, threat intel, identity, ticketing. Each one is custom code you have to write, auth, and maintain.
n × integration cost
3
Token waste
Raw API responses are verbose JSON dumps. Your agent spends most of its context window on noise. Expensive. Slow. Degrades reasoning quality.
~80% wasted tokens
The solution

Clean data. Actionable payloads.

Security agents need a shared data foundation. Calseta handles the deterministic work — enrichment, normalization, context — so your agent focuses on what only an agent can do.

Enriched
Every indicator — IPs, domains, hashes, accounts — enriched by all configured providers in parallel before your agent sees it. Cached. No tokens wasted on lookups.
deterministic
Agent-ready
Every alert normalized to a consistent, agent-readable schema regardless of source. Clean field names, enrichment-first, no SIEM overhead. One format, every agent.
token-efficient
Contextualized
Runbooks, detection rule docs, IR plans, and past alert history automatically matched and attached. Your agent knows your environment, your playbooks, and how your team has responded before.
agent-ready
Integrations

Any source. Any agent.

Out-of-the-box integrations. Community-extensible. One Python class to add a new source or enrichment provider.

Microsoft Sentinel
Elastic Security
Splunk
Generic Webhook
CrowdStrike
SentinelOne
Microsoft Defender
Carbon Black
VirusTotal
AbuseIPDB
OpenCTI
Okta
Microsoft Entra
Microsoft Intune
Jamf
Qualys
Tenable
Rapid7
Snyk
Wiz
AWS Security Hub
Azure Defender
Prisma Cloud
Tines
Azure Logic Apps
Azure Functions
AWS Lambda
n8n
Jira
ServiceNow
PagerDuty
Claude API
LangChain
LangGraph
CrewAI
Slack SOC Bot
Microsoft Sentinel
Elastic Security
Splunk
Generic Webhook
CrowdStrike
SentinelOne
Microsoft Defender
Carbon Black
VirusTotal
AbuseIPDB
OpenCTI
Okta
Microsoft Entra
Microsoft Intune
Jamf
Qualys
Tenable
Rapid7
Snyk
Wiz
AWS Security Hub
Azure Defender
Prisma Cloud
Tines
Azure Logic Apps
Azure Functions
AWS Lambda
n8n
Jira
ServiceNow
PagerDuty
Claude API
LangChain
LangGraph
CrewAI
Slack SOC Bot
Open source

Apache 2.0.
Your data stays yours.

Security engineers trust what they can read. Calseta is fully open-source — every integration, every enrichment provider, every API endpoint. Self-host in your environment in under an hour. Contribute integrations back to the community.

// The name “Calseta” is inspired by the Spanish word “calceta” for “sock”
How it works

Alert in. Agent payload out.

Calseta runs five deterministic steps before your agent sees a single byte. No tokens wasted. No custom integration code.

Alert Sources
Sentinel
Microsoft
Elastic
Security
Splunk
Enterprise
Webhook
Any
Calseta
Ingest
Webhook receiver
POST /v1/ingest
Normalize
Schema mapping
agent-native
Enrich
Threat intel
async · cached
Pulls from
VirusTotal
AbuseIPDB
Okta
Entra ID
Contextualize
Runbooks & rules
org context
Pulls from
Runbooks
Det. rules
Past alerts
Org docs
Dispatch
Agent delivery
webhook · MCP
Your Agents
HTTP
Any consumer
Slack Bot
SOC channel
Agent #1
Your agent
Agent #2
Your agent
Features

Everything your agent needs.
Nothing it doesn't.

📡
Alert ingestion
Plugin-based source system. Elastic, Sentinel, Splunk ship out of the box. Add any source with a single Python class. Community integrations welcome.
push webhookany sourceextensible
🔬
Enrichment engine
Async, parallel enrichment for every indicator. Cached per provider TTL. On-demand enrichment API for Slack bots and ad-hoc queries. Add providers with one file.
async · cachedextensible
📖
Detection rule library
Auto-created when alerts arrive. Add markdown documentation: query, MITRE mappings, false positives, response steps. Surfaced to agents in every alert payload.
MITRE ATT&CKmarkdown docs
📚
Context documents
Upload runbooks, IR plans, SOPs. Target them to specific alert types, severities, or detection rules. Agents receive the right docs for every alert automatically.
targeting rulesorg context
📋
Executable workflows
HTTP automation scripts that call external APIs on behalf of your SOC. AST sandboxing, code versioning, and test mode built in. Agents trigger actions — and a human-in-the-loop approval gate ensures high-risk responses require analyst sign-off via Slack or Teams.
sandboxedapproval gateversioned
🔌
MCP server
Native Model Context Protocol server. Any MCP-compatible agent can query alerts, read docs, and execute workflows. Zero custom client code.
framework-agnosticzero config
📊
Metrics API
Alert volume, false positive rates, MTTD, workflow execution stats, time saved estimates. AI-readable via MCP so agents can reason about SOC health.
REST + MCPSOC KPIs
🔐
Auth-ready architecture
API key auth in v1. BetterAuth-ready architecture means username/password and SSO/OIDC extend cleanly without touching route code.
API keysSSO ready
See it in action

Built for security teams.

A clean, purpose-built interface for managing alerts, enrichment, workflows, and context — designed to be read by both humans and agents.

Calseta alert list view showing normalized alerts with enrichment status
Alert list
Quickstart

One command.
Fully running.

Single Docker Compose command. Point your SIEM at the ingest endpoint. Register your first agent webhook. Done.

Your security agent receives a fully enriched, agent-ready alert payload with detection rule documentation, applicable runbooks, and available workflows — in under 60 seconds from alert trigger.

SHELL
calseta — quickstart
# Clone and start
git clone github.com/calseta/calseta
cd calseta && cp .env.example .env
docker compose up
✓ PostgreSQL ready
✓ Migrations applied
✓ FastAPI running on :8000
✓ MCP server running on :8001

# Create your first API key (admin bootstrap)
curl -X POST localhost:8000/v1/api-keys \
  -d '{"name": "my-agent"}'
cai_a3f8x... (save this)

# Register your agent webhook
curl -X POST localhost:8000/v1/agents \
  -H "Authorization: Bearer cai_a3f8x..." \
  -d '{
    "name": "My Investigation Agent",
    "endpoint_url": "https://my-agent/webhook",
    "trigger_on_severities": ["High","Critical"]
  }'
agent registered ✓
Measured results

92% fewer tokens. Comparable quality. Safer outcomes.

We ran the same 5 alert scenarios through GPT-4o and Claude Sonnet — with and without Calseta. The difference is measurable.

92%
avg input token reduction
Up to
93%
cost reduction per alert
Zero
tool calls with Calseta
Without Calseta
20K–106K input tokens
4–5 tool calls per alert
Custom integration per API
With Calseta
~2,700–3,000 tokens
Single LLM invocation
One API call to Calseta
5 scenarios2 modelsblind quality evalopen sourcereproducible
Estimate Your Savings
$/hr
LLM Cost (Monthly)
Baseline$141.41
Calseta$22.47
Savings
$118.9484%
Engineering Cost (One-Time)
Baseline$5,250.00
Calseta$150.00
Savings
$5,100.0097%
Year 1 Total Cost
Baseline$6,946.86
Calseta$419.64
Savings
$6,527.2294%

Assumptions: engineering cost based on configurable hourly rate above (default $150/hr), 17.5 hrs per provider for custom integration vs 0.5 hrs with Calseta. Token estimates derived from observed benchmark data. See full methodology in the case study.

One alert. Zero tokens wasted.

That's what your agents deserve.

From raw webhook to closed investigation. Calseta handles the deterministic infrastructure. Your agents handle the reasoning.

Open source · Self-hostable · Apache 2.0