Fusebox is a Rust data plane, a ClickHouse store, a Sigma detection engine and a Mastra agent runtime, built as one system by the team that runs it. This is what happens to a single event from the moment it arrives.
Rust · data plane
ClickHouse · event store
OCSF 1.4 · schema
Sigma v2 · detections
Mastra · agent runtime
Convex · control plane
Temporal · durable jobs
Vector · transport
S3 · evidence
01 / Ingest
Every byte arrives with a receipt.
Syslog lands on a dedicated mTLS listener and passes through Vector's disk buffer. Microsoft 365, Entra, Defender, CrowdStrike and CloudTrail arrive through connector workers that lease their work from Convex. Both paths end at the same Rust endpoint on loopback, where each event is normalised to OCSF 1.4 into typed columns with the original bytes kept alongside. Vector is transport and nothing more. It may add a reception id and a receipt time. Anything else is rejected.
stage 01 · ingestlive
02 / Store
One table. One tenant at a time.
Events live in ClickHouse with the tenant first in the ordering key, and the original evidence lives in S3 behind a writer that can create but never delete. Every query in Rust or TypeScript passes through a single tenant boundary that fails closed, and ClickHouse enforces it a second time with row policies. Retention is 30, 90, 180 or 365 days per tenant, decided in Convex and applied to ClickHouse and S3 by a separate workload with its own identity.
stage 02 · store
session tenant
live
03 / Detect
Sigma in. ClickHouse SQL out.
Detections are written as standard Sigma v2 rules and compiled to ClickHouse SQL. Values are bound as typed parameters, never interpolated, so a rule cannot become an injection. A micro-batch scheduler runs every rule against newly admitted events every one to five minutes on a bounded pool of 32 workers, and never lets two runs of the same rule overlap. Every generated query dedupes by event identity, enforces retention inline and caps its own memory.
SELECT event_identity, event_id, processed_at_msFROM ( SELECT event_identity, argMax(fields, processed_at_ms) AS latest FROM detection_events_admission LEFT JOIN active_retention_policy_cutovers USING (tenant_id) PREWHERE tenant_id = ? AND admitted_at_ms > ? AND admitted_at_ms <= ? WHERE retention_deadline_ms > now64() GROUP BY event_identity)WHERE class_uid = ? AND activity_id = ? AND action_id = ? AND status_id = ?ORDER BY processed_at_ms, event_identityLIMIT 10001SETTINGS max_memory_usage = 536870912
bindings [4001, 6, 2, 2] typed, never interpolatedmicro-batch every 1 to 5 minworkers 32 with an overlap fencededupe by event_identity
04 / Investigate
The model is a component. Everything around it is the product.
A Sigma match or a Defender alert opens a case. The Mastra agent works the loop: plan, call a tenant-scoped tool, record the evidence, repeat. Its tools are Defender device context, Entra sign-ins, Fusebox search and threat intelligence, and every call is scoped to the tenant before it runs. The verdict must cite an evidence chain, then passes the policy gate. Allowed actions run. Everything else waits for approval in Teams or email. One provider interface routes Claude, OpenAI and Gemini per task and per tenant, so reasoning goes to the strongest model and classification to the cheapest model that passes our evals.
stage 04 · investigatelive
05 / Control
Tenant authority is a certificate, not a claim.
Each syslog connector gets its own mTLS listener with its own port and its own client CA. The tenant is fixed by which listener accepted the connection, before a single byte is parsed. A certificate issued for one tenant is cryptographically invalid on another tenant's listener, so a sender cannot cross tenants even by pointing at the wrong port. Source IP and message content are never tenant authority. The emergency stop halts the agent per tenant or across the whole organisation.
stage 05 · controllive
// decisions we would make again
Built to be argued with.
No message bus.
Vector's disk buffers give the data plane its durability. The interfaces are seamed so Redpanda drops in the day a second real-time consumer of the raw stream exists, and not a day before.
ClickHouse, not a search index.
Columnar storage over typed OCSF fields turns detection into a SQL problem, keeps a year of retention affordable, and gives every tenant one boundary to reason about.
Two languages, enforced.
Rust owns the data plane. TypeScript owns the control plane and the console. Nothing else gets in, so every engineer can read every line.
Convex is the single policy authority.
Every tenant, role, connector, policy and retention decision has exactly one home. ClickHouse and S3 follow it, never the other way round.
Temporal for anything long-running.
Scans, enrichment, onboarding and durable agent jobs get retries and history for free instead of a hand-rolled job table that fails on a Sunday.
Proof, not slides.
Every release has to pass the same test: a genuine alert in a real tenant, investigated, actioned by policy and closed by the agent, while a second tenant cannot see or influence any of it.
// founding partners
Put Fusebox to work.
Get founding-partner terms and a direct line to the team building Fusebox. Tell us about your environment.