Promised automation. Kept alive by manpower.
Traditional SOARs promise to free your SOC team, but end up requiring professional consultants and a dedicated team of engineers just to keep the playbooks running.
Evolutionary SOAR driven by a team of AI agents who actually DO the work.
What's at stake.
The human-factor crisis: thin AI integration, expertise shortages, and overloaded SOC teams lead to critical errors — missed threats, mis-prioritization, and lost incidents that leave the business exposed.
Smart automation that can counter AI at equal speed — and deliver peak SOC-team efficiency — is no longer optional.
Yet the complexity of existing SOAR platforms demands heavy resources just to set up and keep running.
Sources SoSafe 2025 Cybercrime TrendsCrowdStrike Global Threat ReportGoogle Cloud Cybersecurity ForecastECSO Cybersecurity Market AnalysisarXiv:2505.23397Verizon DBIR 2023Orca Security 2022 Alert Fatigue ReportGartner ITSM Hype Cycle
The state we're in.
Traditional SOARs promise to free your SOC team, but end up requiring professional consultants and a dedicated team of engineers just to keep the playbooks running.
Instead of focusing on real threats, your team burns endless hours fixing broken integrations and building complex playbooks. AI is limited to advice you have to double-check, or trivial operations — never the high-quality work you actually need done.
Legacy SOAR isn't just software — it's a complex engineering toolkit. Companies buy it to optimize SOC operations, but end up with a massive resource drain just maintaining the platform.
See a smarter way to automateThe solution
Where AI agents orchestrate the entire workflow — from investigation to response — saving your SOC team countless working hours.
Integrate your security stack in minutes. EDR, identity, threat intel, messaging — all in one place.
Write AI-powered playbooks in code. Analyze alerts, classify threats, orchestrate response — automatically.
Isolate hosts, push IOCs, notify your team — in seconds, on the actions you choose to automate.
Examples you compose — Lunsight ships the primitives, not a fixed pipeline. The AI reads and recommends; your automation acts.
Example: classify what just fired, then route it.
// triage.ts — Detection-driven auto-triage
//
// A CrowdStrike Falcon detection fires this script. The "security/triage@v3"
// agent READS & enriches only (VirusTotal IOC reputation, CrowdStrike host
// context, M365 identity) and returns a structured verdict. The SCRIPT does
// every write: it upserts/dedups the incident on (vendor, external_id),
// attaches enriched observables, sets severity, and routes — page on-call for
// true positives, auto-close the rest.
import { defineScript, fetchPayload } from "lunex:sdk"
import { agents } from "lunex:ai"
import { incidents } from "lunex:incidents"
import { notify } from "lunex:script/lib/notify"
// The structured verdict the agent submits via its output schema. The agent
// only recommends; it performs no writes.
interface Observable {
type: string
value: string
enrichment?: unknown
}
interface Verdict {
severity: "info" | "low" | "medium" | "high" | "critical"
summary: string
isTruePositive: boolean
observables: Observable[]
}
export default defineScript(async (event) => {
// Pull the full detection record for the agent to reason over.
const detection = await fetchPayload(event)
// (1) The agent enriches (read-only tools) and returns its verdict.
const { output: verdict } = await agents.run<Verdict>("security/triage@v3", {
event,
detection,
})
// (2) The SCRIPT acts on the recommendation — find-or-create, then enrich.
const { incident, created } = await incidents.upsert("crowdstrike", event.composite_id, {
title: event.name,
severity: verdict.severity,
source: { vendor: "crowdstrike", event_type: event.event_type, ref: event.composite_id },
})
for (const obs of verdict.observables) {
await incident.addObservable(obs.type, obs.value, obs.enrichment) // idempotent
}
await incident.comment(`Auto-triage (security/triage@v3): ${verdict.summary}`)
await incident.attachRun() // link this run for the audit trail
// (3) Route: page on-call for high-severity true positives, else close benign.
if (verdict.isTruePositive && (verdict.severity === "high" || verdict.severity === "critical")) {
await notify(`🚨 ${verdict.severity.toUpperCase()} — ${event.name}\n${verdict.summary}`)
} else if (!verdict.isTruePositive) {
await incident.resolve("false_positive")
}
console.log(`Incident ${incident.id} ${created ? "created" : "updated"} (severity=${verdict.severity})`)
}) Example: an Agent System digs deeper across sources.
// investigation.ts — Agent-system deep investigation of a flagged incident
//
// A flagged incident (e.g. routed here by triage) runs this script. It calls an
// Agent System orchestrator ("soc/investigation@v2"). The orchestrator fans out
// to member agents that run in PARALLEL — IOC reputation (VirusTotal), host
// context (CrowdStrike), identity & sign-ins (M365) — aggregates their findings,
// and returns a structured assessment. The SCRIPT then records the investigation
// on the incident and pivots on shared IOCs to correlate related cases. The
// analyst works the case in the UI afterwards.
import { defineScript } from "lunex:sdk"
import { systems } from "lunex:ai"
import { incidents, observables } from "lunex:incidents"
// Aggregated output the orchestrator submits via the system's output schema.
interface EnrichedObservable {
type: string
value: string
verdict: string
findings?: unknown
}
interface Investigation {
summary: string
riskScore: number // 0–100, aggregated across member agents
observables: EnrichedObservable[]
}
export default defineScript(async (event) => {
// The flagged incident id arrives on the triggering event; load the handle.
const incident = await incidents.get(event.incident_id)
// Run the orchestrator. Member sub-agents run in parallel server-side and are
// correlated to this system run; the script only sees the aggregated output.
const { output: result, run_id } = await systems.run<Investigation>("soc/investigation@v2", {
incident: { id: incident.id, title: incident.title, severity: incident.severity },
})
// Record the investigation on the incident: attach enriched observables, drop
// a timeline comment, and link this run.
for (const obs of result.observables) {
await incident.addObservable(obs.type, obs.value, { verdict: obs.verdict, findings: obs.findings })
}
await incident.comment(`Investigation (soc/investigation@v2, run ${run_id}) — risk ${result.riskScore}/100\n${result.summary}`)
await incident.attachRun()
// Pivot on each shared IOC to surface related incidents, then note the
// correlations on the timeline for the analyst.
const related = new Set<string>()
for (const obs of result.observables) {
const hits = await observables.findIncidents(obs.type, obs.value)
for (const h of hits) if (h.id !== incident.id) related.add(h.id)
}
if (related.size > 0) {
await incident.comment(`Correlated ${related.size} related incident(s) via shared IOCs: ${[...related].join(", ")}`)
}
// Hand the enriched case to the analyst.
if (incident.status === "new") await incident.setStatus("in_progress")
console.log(`Investigation recorded on ${incident.id}; ${related.size} related, risk ${result.riskScore}`)
}) Example: the AI recommended — your automation acts.
// response.ts — Approval-gated remediation for a confirmed true positive
//
// A high-severity true-positive verdict runs this script (the AI recommended
// upstream; every action below is the SCRIPT's). It reads the response plan from
// storage, gates on an on-call approval, then remediates step by step — contain
// the host (CrowdStrike EDR isolation), disable the user + revoke sign-in
// sessions (M365 / Entra ID), and notify the team — then updates and resolves
// the incident. There is NO block-IOC step.
import { defineScript } from "lunex:sdk"
import { kv } from "lunex:storage"
import { incidents } from "lunex:incidents"
import { crowdstrike, microsoft365 } from "lunex:integrations"
import { waitForApproval } from "lunex:script/lib/approve"
import { notify } from "lunex:script/lib/notify"
interface ResponsePlan {
deviceIds: string[] // CrowdStrike device ids to isolate
userUpns: string[] // Entra ID users to disable + revoke
}
export default defineScript(async (event) => {
const incident = await incidents.get(event.incident_id)
const plan = await kv.get<ResponsePlan>(`response/plan/${incident.id}`)
if (!plan) return
// Approval gate: block until an on-call engineer approves containment.
const approved = await waitForApproval(incident.id)
if (!approved) {
await incident.comment("Containment not approved — no action taken.")
return
}
// Remediate step by step — contain hosts, disable + revoke users, notify team.
const containment = await crowdstrike.containHost(plan.deviceIds) // ActionResult[] { id, success, error }
for (const upn of plan.userUpns) {
await microsoft365.disableUser(upn)
await microsoft365.revokeSignInSessions(upn)
}
await notify(`🛡️ Remediating ${incident.id}: isolated ${plan.deviceIds.length} host(s), disabled ${plan.userUpns.length} user(s).`)
const isolated = containment.filter((r) => r.success).map((r) => r.id)
// Update + resolve the incident as a remediated true positive.
await incident.comment(`Remediated: isolated host(s) ${isolated.join(", ") || "none"}; disabled ${plan.userUpns.join(", ")}.`)
await incident.resolve("true_positive")
console.log(`Incident ${incident.id} remediated and resolved (${isolated.length} hosts isolated)`)
}) Illustration only — there's no visual mode on the platform. Every flow is written in code (see the Code tab).
Capabilities
AI isn't bolted on the side — it's the core of the platform. Luna drafts and debugs your automation, agents triage and enrich every alert, and agent teams run the deep investigations.
Every playbook is plain code — versioned, audited, reviewed like real software. No visual builder to drift out of sync, so those bugs never happen. Extend it to fit any stack.
Start from composable examples, then shape them to your processes in minutes. You're never blocked waiting on our engineers — the logic is yours to change.
You get AI speed and keep 100% control. Critical actions and generated code are cross-validated and human-approved; agents act only within the limits you set — never freelancing in critical infrastructure.
MTTR, alert volume, agent activity — in pre-built dashboards, no spreadsheets. Plus the data layer to build your own.
Cloud or on-prem — integrate with the infrastructure you already run.
Your zeroth teammate.
Your personal AI assistant, integrated into the core of the system. She holds the context, can run every function of the platform, and fully covers the technical routine 24/7/365.
Build a playbook: phishing ticket in, classify, enrich, route to L1 or L2.
Drafted. Five steps, two branches. Open phishing-triage.ts to review.
Why is step 03 returning empty?
That action calls an integration that isn't connected on this tenant. Connect it, or drop in a stub for testing?
How do I version this playbook?
Every save is a version. Open History from the editor — diff, roll back, restore.
Traditional SOAR vs. Lunsight
Integrates with
Get Early Access