watcher
Your logs already know what broke.
A self-hosted daemon that reads your application logs, notices crashes on its own, and explains them in plain English using a small local model. No cloud calls, no API keys.
Watcher runs in the background reading your application logs. When something crashes, it works out the root cause and tells you in plain English, using a small model on the machine you already have.
curl -fsSL https://github.com/shaheeranser/watcher/releases/latest/download/install.sh | sudo shwatcher onboard
watcher run --model qwen2.5:1.5b --file /var/log/app.logNew incident · Critical
Application startup failure due to missing RELAYBOX_API_TOKEN.
- Likely cause
- The application is attempting to load configuration without the required RELAYBOX_API_TOKEN environment variable.
- Suggested fix
- Ensure the RELAYBOX_API_TOKEN environment variable is set before attempting to load configuration.
From a real test run. I broke a live service on purpose, with no crash switch wired into it. It even tells you when it is unsure: this run flagged that some cited evidence was not in the excerpt, and lowered its own confidence to 0.30.
It comes to you, so you never invoke it against an incident
Push, not pull. Watcher watches continuously and only speaks up when something actually breaks.
Read
A file, stdin, or several labelled sources. Inside Docker Compose it attaches to its own sibling containers over the Docker socket, with no configuration.
Detect
Go panics, Python tracebacks, and generic fatal or exception lines. Deliberately heuristic: logs have no universal format, and requiring one would make Watcher undeployable anywhere unusual.
Fingerprint
Addresses, timestamps, UUIDs and request ids are normalised away, so the same failure keeps the same identity. This is what stops a crash loop from becoming fifty alerts.
Curate
A bounded excerpt of the crash block and its surrounding context is extracted within a token budget, so a small model still gets a clean, affordable prompt.
Explain
A local Ollama model returns a summary, a likely cause, the evidence it used, a suggested fix, a confidence, and a severity.
Report
Readable text in a terminal, JSON Lines when piped, and lifecycle notifications to Slack, Discord or a generic webhook. One message when it breaks, one when it recovers.
A crash loop is one incident, not fifty
Deduplication is decided by the fingerprint, so a service failing in a loop produces a single incident with a rising count.
- A raw log gives you twenty-four identical stack traces and no idea which one matters.
- Watcher sends one incident, announced once, then an update when it recovers — the notifications follow the incident, not the log line. One incident, count 24, moving new → ongoing → resolved.
Where this actually is
Watcher is pre-1.0 and currently published as a release candidate. It is tested against real services rather than declared finished, so here is the real position rather than a pitch.
- The engine, its production runtime, and crash deduplication.
- watcher attach — a live dashboard over SQLite incident history and a read API on a unix socket.
- watcher eval — scoring explanations against a ground-truth file.
- watcher onboard, the TOML config file, the checksum-verified installer, and a systemd unit.
- Webhook delivery with retry, a fallback spool, and a heartbeat.
Known gaps, stated plainly
- The live Docker Compose checks and the evaluation-harness checks have not been run end to end yet. The behaviour behind them is covered by unit tests; the integration is unverified.
- No default model is bundled. --model is required, so you choose.
- The webhook spool is never replayed automatically. It captures undeliverable notifications so nothing is lost, but draining it is manual.
- Notification state is process-local: after a restart, a still-failing crash is announced as new rather than ongoing.
Pick something small and real
These are scoped, have a definition of done, and can be tested offline. Every one of them is a genuine gap in the code or the docs, not busywork. Go is 1.26 or newer; read CONTRIBUTING.md first, and AGENTS.md if you are working with an agent.
- #1watcher --version prints nothing, and the bug template asks for itsmall
- #3Add an ntfy webhook payload formatsmall
- #2Detect JavaScript / Node.js stack tracessmall
- #4Document the development loop, from a clean clone to a rendered explanationdocs
- #5Add an examples/ directory with one worked end-to-end recipedocs