incident-wire
A live ledger of real-world AI coding-agent production incidents — data loss, fake tests, hallucinated code, fabricated screenshots, outages, breaches. Pulled every 30 minutes from public sources, classified by an LLM, and presented as a searchable, filterable, RSS-syndicated newswire.
Stories die on Hacker News in three days. incident-wire keeps them.
What it tracks
- Production incidents caused by AI coding agents (Cursor, Claude Code, Copilot, Aider, Replit Agent, Codex, Windsurf, Kiro, ChatGPT, Gemini, Devin, Amazon Q, etc.)
- Failure modes: data-loss, fake-test, hallucinated-code, fabricated-output, outage, breach, rogue-deletion, spec-drift
- Per-incident metadata: agent, model version, severity, cost estimate, victim org, incident date, lessons learned, evidence URLs
Not in scope: CVE feed (see agent-threat-feed), self-hosted postmortems (see postmortem-hub).
Data sources
| Source | URL | Freq |
|---|---|---|
| HN Algolia | hn.algolia.com/api/v1/search_by_date (rotating 16-query round-robin) | every 30 min |
| Reddit RSS | r/programming, r/AICodingAgents, r/ExperiencedDevs, r/LocalLLaMA, r/devops, r/sre, r/webdev | every 30 min |
| Lobsters RSS | lobste.rs/rss + tag feeds (ai, security) | every 60 min |
| Dev.to API | dev.to/api/articles?tag={ai,chatgpt,machinelearning,devops,security} | every 60 min |
Every fetch (success or failure) is logged into the sources_log table and exposed at /api/sources. No mock data, no seed rows — the DB boots empty and fills from real fetches.
Classification
After the prefilter (a tight regex on agent name + failure word, with negative patterns to drop tutorials/marketing), surviving candidates are POSTed to Claude Haiku 3.5 via OpenRouter with a strict JSON schema:
{
"is_incident": true,
"agent": "cursor",
"agent_model": "claude-opus-4.6",
"failure_type": "data-loss",
"severity": "critical",
"cost_usd": null,
"victim_org": "PocketOS",
"incident_date": "2026-04-25",
"summary": "...",
"lessons": ["..."],
"confidence": 0.92
}
Only items with is_incident:true and confidence ≥ 0.55 become incidents. Dedup is fingerprint-based on victim_org + incident_date + agent. Re-classifications append evidence rather than create duplicates.
If OPENROUTER_API_KEY is missing, the classifier runs in degraded mode: candidates queue forever, no fabricated classifications are written, and the health endpoint surfaces classifier_status: "degraded" (the UI shows a banner).
Endpoints
All public. No auth anywhere. POST endpoints are IP rate-limited.
GET /incident-wire/ SPA
GET /incident-wire/health health JSON
GET /incident-wire/api/incidents list, filterable
GET /incident-wire/api/incidents/:slug single + evidence
GET /incident-wire/api/stats/agents leaderboard
GET /incident-wire/api/stats/types by failure type
GET /incident-wire/api/stats/timeline last 90 days
GET /incident-wire/api/stats/summary hero stats
GET /incident-wire/api/sources fetch log
GET /incident-wire/api/candidates unclassified queue (debug)
GET /incident-wire/feed.rss RSS 2.0
POST /incident-wire/api/refetch trigger fetch (1/min)
POST /incident-wire/api/reclassify/:id re-run one candidate (5/min)
POST /incident-wire/api/classify-batch run classifier now (2/min)
Run locally
npm install
cp .env.example .env # set OPENROUTER_API_KEY (optional; classifier degrades gracefully without it)
npm start
# open http://localhost:4774/incident-wire/
Node 20+ required (uses global fetch).
Stack
- Node.js 20 + Express 4
- better-sqlite3 with WAL mode (
data/incident-wire.db) - node-cron for scheduling
- helmet + compression
- Vanilla JS SPA (no framework, no build step)
- Classifier: Claude Haiku 3.5 via OpenRouter
Project layout
server.js app entry — wires routes, helmet, static, cron kickoff
db.js sqlite open + WAL + migrations + prepared statements
fetchers/ one file per source + index orchestrator
classifier/ openrouter client, prompts, prefilter, batch runner
routes/ health, incidents, stats, sources, candidates, feed, admin
lib/ logger, slugify, rate limit, RSS parser (no xml dep)
cron/schedule.js node-cron registrations + boot kickoff
public/ index.html + app.js + style.css + favicon.svg
data/ sqlite file lives here at runtime
Tip a story
Email [email protected] with a link and a one-line summary. The wire is fed by automated polling — human tips help cover sources we don't crawl (HN comments, mailing lists, private postmortems shared on Twitter).
License
MIT