
Nomad • Zerops hackathon
An agentic SRE that closes the loop.

- Role
- Creator
- Timeline
- 2026
- Stack
- TypeScriptFastifyPostgres
- Status
- LiveHackathon build
Overview
Logs nobody reads are not observability.
Every team has logs. Few teams can answer, at 3am, why a service started failing. Nomad watches a live Zerops deployment, reads the logs services already forward, and closes the loop.
Nomad detects the anomaly, diagnoses the cause, and applies the fix. It treats log forwarding, the REST API, and the deployment topology as its own primitives. Zerops is not just where Nomad runs; it is what Nomad operates on.
Observe
a UDP syslog listener accepts RFC 5424 and tolerates RFC 3164.
Detect
a scanner looks for bursts of error or critical lines every 15 seconds.
Diagnose and fix
Claude reads the burst against recent logs and returns a root cause and a suggested fix.
The goal is not another dashboard. It is a system that acts and shows its work: every incident, diagnosis, and applied fix stays in a filterable timeline.
The loop
Observe, detect, diagnose, fix.
The whole product is one loop, and the bundled demo walks it end to end.
Break
POST /api/demo/break makes the target service emit error lines over UDP to the worker.
Ingest
the worker parses each line and stores it in Postgres.
Detect
five or more error or critical lines for one service in 60 seconds opens an incident.
Diagnose
Claude returns a root cause, a fix, and a confidence value as strict JSON.
Fix
POST /api/fixes/:incidentId/apply heals the service and closes the incident with a resolved timestamp.
A five-minute dedup window keeps a single failure from opening a dozen incidents. Without an ANTHROPIC_API_KEY, diagnosis falls back to heuristics and says so, rather than pretending a model was involved.
Architecture
Five services in one Zerops project.
Four Node.js 22 runtimes are declared in zerops.yaml; the database is managed Postgres 18. The schema and its indexes live in db/src/schema.ts.
frontend
Next.js landing page and dashboard, with faceted tables and a row-detail drawer.
api
Fastify REST backend: incidents, logs, chat, demo break and heal, and fix application.
worker
the syslog listener, anomaly scanner, diagnosis pipeline, and remediation.
target
a small demo service that can be broken and healed on demand.
db
Postgres with incidents, logs, and fixes tables, defined with Drizzle.
The worker is the only long-running process with real state. It holds the UDP listener, the scan timer, and the dedup window, and it is the one service that both reads logs and writes fixes.
Engineering
Syslog in, idempotent migrations out.
Two problems were more interesting than the features built on top of them: parsing logs that were not written for you, and deploying migrations that must run exactly once.
Syslog is a loose format. The worker parses RFC 5424 properly, tolerates RFC 3164, reads structured data, and drops malformed lines instead of guessing. A line that cannot be parsed is noise, and storing it would only make the timeline worse.
Migrations run on container start, gated by zsc execOnce and keyed on the app version id. That primitive is what makes an auto-migrating deploy safe: the migration runs once per app version, no matter how many replicas start or restart.
Diagnosis
Claude compares the burst with roughly fifty recent lines and returns strict JSON: root cause, fix, confidence, and reasoning.
Remediation
restart or rollback through the Zerops REST API; the bundled demo heals over the private network with no credentials.
Fallback
with no API key, Nomad returns explicit not-configured messages instead of failing silently.
The loop is only credible if the fix is real. Break the service, watch the incident open, read the diagnosis, and watch it heal: the same API call a human would make.
Source
Live demo and code.
Nomad was built for a Zerops hackathon. It is live on Zerops, and the repository includes the technical spec, the demo script, and the challenge notes.
View the live deployment