Open source · MIT · read-only

The loudest error is rarely the first one.

firstsignal reads your logs during an incident and tells you what went wrong, in what order, and which safe checks to run next. It remembers past incidents, so a repeat comes with what fixed it last time.

pip install git+https://github.com/AutoShiftOps/firstsignal
  • systemd
  • Docker
  • Kubernetes
  • files & stdin
  • no account
  • no agent
examples/checkout-incident.log Overall: critical
  1. Slow operations latencymedium
  2. Connection limit reached saturationhigh
  3. Timeouts latencyhigh
  4. HTTP 5xx responses errors · 5×high
  5. Rate limiting trafficmedium
  6. Out of memory saturationcritical
  7. Restart loop errorshigh
  8. Connection refused errorshigh
Real output from the bundled example. The out-of-memory kill is the most severe finding, but slow queries and a full connection pool came 24 seconds earlier.

One command per source

Each collector only reads. External tools run with a fixed argument list and no shell, and anything that looks like an injected option is rejected.

Plain text, JSON lines, logfmt and kubectl prefixes are all parsed. Health-check lines are dropped unless they report an error.

# a workload, a pod, or a label selector
firstsignal k8s --pod deploy/api -n prod --since 30m

# the container that just crashed
firstsignal k8s -l app=api -n prod --previous

It remembers what fixed it last time

Every run with findings is kept as a fingerprint: which patterns fired, in what order, on which target. When something similar happens again, firstsignal says so, with the fix you noted.

  • Local and private. One file in your home directory, readable only by you.
  • No log text stored. Pattern names, counts, target, time and your note.
  • Deterministic. The same two incidents always score the same. No model involved.
$ firstsignal k8s --pod deploy/api -n prod
…
Seen before
  3f9a1c2e  12 days ago on prod/deploy/api  (100% similar, critical)
      Fix noted: raised DB pool size from 10 to 30,
      added index on orders.customer_id

Remembered as 8b21d0aa. When it is fixed:
$ firstsignal history note 8b21d0aa "what fixed it"
$ firstsignal history list      # what is remembered
$ firstsignal history forget 8b21d0aa

Watch it live

watch re-reads a sliding window of logs and prints only what changed: a new finding, a severity change, a finding that cleared, or a match with a past incident.

When you stop it, it writes the usual reports for the worst moment it saw and keeps one history record for the whole session. Run it as a systemd service or a sidecar to keep it going.

$ firstsignal watch k8s --pod deploy/api -n prod
Watching prod/deploy/api: last 5 min, checked every 15s. Ctrl+C to stop.
09:41:12  NEW          high     Connection limit reached x2
09:41:12  SEVERITY     none -> high
09:41:31  NEW          critical Out of memory x1
09:41:31  SEVERITY     high -> critical
09:41:31  SEEN BEFORE  3f9a1c2e, 12 days ago (80% similar)
                       Fix noted: raised DB pool size
09:52:40  CLEARED      Connection limit reached
$ firstsignal watch file --path /var/log/app.log --window 10
$ firstsignal watch docker --container my-api --json | jq .

What the report gives you

The terminal shows the essentials. Every run also writes report.md to paste into the incident channel and report.json for pipelines. Add --html for a self-contained dashboard; see an example.

Four Golden Signals
Every finding is mapped to latency, traffic, errors or saturation, so you can see which kind of trouble you are in.
Order of first appearance
Which pattern showed up first. Earlier ones are likelier causes; later ones are often knock-on effects.
Severity you can gate on
--fail-on high exits 3, so a post-deploy check or a timer can act on the result.
Checks filled in for you
Read-only commands with your unit, container or pod already in place. Printed, never run.
Secrets masked by default
Passwords, tokens, keys, URL credentials and emails are redacted before anything is written.
Ten pattern packs
nginx, PostgreSQL, MySQL, Redis, Kafka, HAProxy, Node.js, Kubernetes and the JVM, plus your own rules in firstsignal.toml.
Works offline
No account, no agent, and no network calls unless you pass --ai. One runtime dependency, Python 3.10 to 3.13.
Fits in CI
JSON output and exit codes make it a post-deploy smoke check: fail the job when a deploy starts throwing errors.

AI is optional, and it only explains

Everything above works offline. Pass --ai with your own Anthropic or OpenAI-compatible key, or point it at a local Ollama model, and the report gains up to three ranked hypotheses.

The answer is labeled unverified. Nothing a model returns is ever executed.

Sent with --ai
  • Finding counts and severities
  • Order of first appearance
  • Up to two redacted example lines per finding
  • Top repeating lines, redacted
Never sent
  • The raw log
  • Lines that matched nothing
  • Anything at all with --no-redact
  • Anything at all without --ai
export ANTHROPIC_API_KEY=...
firstsignal k8s --pod deploy/api -n prod --ai

# fully local, no key
firstsignal file --path app.log --ai \
  --ai-provider ollama --ai-model llama3.1

What it does not do

Correlate and explain, never auto-act. That is a design rule, and a test enforces it.

  • It never restarts, deletes, scales or edits anything.
  • Detection is rule-based. It recognizes known failure signatures; it does not understand your application.
  • Order of appearance is a lead to check, not proof of cause.
  • It reads logs only: no metrics, traces or deploy history.
  • Redaction is pattern-based and cannot promise to catch every secret.