Engineering · July 2026

Garmr: building a one-person SOC in Rust, with an AI analyst in the loop

By Henrik · Vetra

Garmr is the hound that guards the gates of Hel. Ours is a self-hosted Security Operations Center for a single operator, written entirely in Rust, where an agentic AI analyst is the core of the pipeline rather than a bolt-on. Logs come in, detections fire, and an LLM agent investigates each one with a set of read-only tools: it queries log history, checks the source IP, compares against the host's baseline, and searches past cases. Then it posts a triaged verdict to us in Matrix. One binary. No Grafana, no Loki, no Wazuh.

It has been watching our own infrastructure around the clock since spring 2026. This post is about why it exists and what we learned building it.

The gap nobody was standing in

When we surveyed the landscape in 2026, it split cleanly in two. On one side: agentic SOC platforms, impressive AI layers written in Python or TypeScript that sit on top of someone else's SIEM. They rent their storage and detection from Splunk, ELK or Wazuh, and inherit all of that weight. On the other side: excellent Rust security infrastructure (OpenObserve, Quickwit, Kunai, Pulsar). Fast, self-contained building blocks with no brain attached.

The agentic projects are glue over someone else's SIEM. The Rust projects are infrastructure without an analyst. Nothing bridged the gap: a vertically integrated, self-hosted, agent-native SOC sized for one person and their homelab or small fleet. So we built it.

The pipeline

The whole system is one Rust binary with an embedded storage engine. The stages:

  • Ingest. A native, vendor-neutral HTTP endpoint that accepts canonical JSON or NDJSON from anything that can POST: Vector, Fluent Bit, a cron job, curl. Syslog too, and a Loki-compatible push endpoint as an opt-in compatibility feature for setups still fanning in through Grafana Alloy.
  • Store. An embedded Apache Iceberg lakehouse for the columnar event history, queried with DataFusion SQL, plus an embedded key-value store for agent state. No external database of any kind.
  • Detect. Sigma rules evaluated per event, with a burst of matches collapsing into a single case instead of a pager storm.
  • Correlate. Windowed, stateful multi-event rules for what a single event can't express: a brute-force burst followed by a successful login from the same address is a different animal than either alone.
  • Triage. The agent. More on that below.
  • Notify. Verdicts fan out to Matrix, webhooks and mail.

On the endpoint side, eBPF telemetry from Kunai gives us process-level visibility on Linux hosts, feeding the same pipeline as the network and auth logs. On top of the raw detections sit risk-based alerting, where scores accumulate per host so that ten small oddities on one machine surface even when no single one would page, and a MITRE ATT&CK coverage view that shows plainly which techniques the current ruleset would and wouldn't catch.

The analyst costs half a cent

The part that makes it a SOC rather than a log pipeline is the triage agent. When a detection fires, the agent gets the case and a toolbox of strictly read-only tools: SQL over the event history, semantic search over past cases, IP intelligence, the host's behavioral baseline. It investigates the way a junior analyst would. Has this host ever talked to this address before? Is this login pattern normal for this user? Did we see this last month, and what was the verdict then? Then it writes up a conclusion with its reasoning attached.

Two design decisions matter here. First, the tools are read-only by construction: the agent can investigate anything and change nothing, which is what lets us sleep while it works. Second, cost is capped in hard numbers: a typical investigation costs about $0.005, and the agent has a hard daily budget of $5. If it's ever wrong about something expensive, the blast radius is the price of a coffee.

A one-person operation cannot staff a night shift. An agent that triages every alert for half a cent, every night, without fatigue, is the only realistic way a single operator gets 24/7 triage at all.

A war story: the zero-byte manifests

Building your own storage engine means owning your own durability bugs. Ours arrived when a machine restarted mid-compaction and we came back to zero-byte metadata files: the table pointer said one thing, the files on disk said nothing at all. The heal routine we had at the time checked that the manifest list existed, but never opened the manifests themselves. Green checkmarks, torn table.

The fix was two-fold: fsync discipline through the whole commit path, and a self-healing routine that walks the metadata chain and rolls back to the last fully intact snapshot instead of trusting file existence. We verified it by deliberately tearing the pointer on the live system and watching it roll back with zero data loss. If your recovery path has never run in anger, you don't have a recovery path; you have a wish.

Where it stands

Garmr runs in production on a small NUC in our lab, ingesting logs and eBPF telemetry from our real infrastructure, triaging real alerts every day. It is deliberately sized for one person: one binary, embedded storage, no cluster to babysit. The codebase is private today while the architecture settles; we're still deciding what to open up.

If a self-hosted, agent-native SOC in Rust is relevant to you, as an operator, a pilot user, or someone building in the same space, we'd like to hear from you: [email protected].