Skip to content

Open-source AI log monitoring that finishes the job

It finds the bug. Then it writes the fix.

Your monitoring already tells you something broke. guiltyspark is a self-hosted AI agent that does the next part: it reads your logs, works out what's actually wrong, writes the patch and the regression tests in an isolated clone, runs your test suite, and opens a pull request explaining what it found.

You wake up to a code review instead of an alert.

See what it opens View on GitHub

Apache-2.0  ·  Self-hosted  ·  Reads Grafana Loki  ·  Runs on a Raspberry Pi

The work product

nobody was awake for this

This is what's waiting in the morning.

Not a dashboard to go read. Not an alert to go triage. A pull request, with the evidence that motivated it, the reasoning behind the change, the diff, and tests that fail without the fix and pass with it. It writes to you as the Monitor — that's the personality — but the contents are ordinary, checkable engineering.

● Open guiltyspark wants to merge 1 commit into main from guiltyspark/null-safe-inventory
fix: handle missing inventory items without throwing
guiltyspark opened this at 02:19 · 4 minutes after the first error
Containment Record

Greetings, Reclaimer. inventory-api logged 612 failed product requests between 02:14 and 02:18. Each attempted to read an item that no longer existed, producing the same nil-reference malfunction. The anomaly is recurrent and, I am pleased to report, entirely correctable.

Evidence Archive
02:14:07 ERROR NoMethodError: undefined method `name' for nil
02:14:07 ERROR app/services/inventory_service.rb:47:in `get_product'
… 610 further occurrences, clustered to one issue
Causal Assessment

The repository returns nil when an item is absent, but the service dereferences it before checking. Every trace terminates at the same line after requests for deleted product IDs. A missing item should produce a controlled 404, not an internal server error.

Corrective Protocol 2 files changed · within allowed paths · under change limit
app/services/inventory_service.rb
   product = repository.find(id)
+  raise NotFound, id unless product
   ProductResponse.from(product)
Verification Sequence
✓ returns 404 for a missing product — fails without patch
✓ bundle exec rspec — 128 passed in 6.4s
✓ bundle exec rubocop — clean

Final authorization remains yours, Reclaimer.

It shows its work

Every claim in the PR traces back to log lines it actually saw. If the diagnosis is wrong, the evidence is right there to catch it — you're reviewing an argument, not trusting a black box.

The tests come with it

A fix ships with a regression test that fails without the patch. That's the difference between a plausible-looking change and a demonstrated one.

You never see the bad ones

Patches that break the suite, wander outside allowed paths, or exceed the change limit die in the clone. Only work that passed gets as far as your review queue.

How it got there

five minutes, unattended

Detect. Diagnose. Fix. Verify.

The loop is deliberately boring, because boring is auditable. Here's the whole thing, timestamped against the pull request above.

  1. 02:14  ·  DETECT

    Polls Loki on an interval and collapses 612 near-identical lines into a single coherent incident. Noise it has ruled on before never surfaces again.

  2. 02:15  ·  DIAGNOSE

    Hands the evidence to Codex along with the source repo and your notes on which warnings are expected, so benign chatter isn't mistaken for a fault.

  3. 02:17  ·  FIX

    Clones the repository somewhere disposable and writes the smallest change that addresses the cause, plus a test that proves it.

  4. 02:18  ·  VERIFY

    Checks the patch against your policy — allowed paths, file count — then runs your real test suite. A failure here ends the attempt quietly.

  5. 02:19  ·  HAND OFF

    Opens the pull request and stops. It will not reopen this issue while your PR is still sitting there, and it stays quiet for a cooldown after you merge.

Progressive autonomy

An agent that writes code should have to earn it.

So it starts with nothing. Every repository begins in observe, where it can look and reason but not touch. Watch its diagnoses for a while; promote it only once you believe them. It cannot push code unless you have explicitly moved that target to draft-pr or pr, one repo at a time.

  • Default

    observe

    Detect and diagnose only. Nothing is cloned, nothing is written. Read the findings and judge them.

  • Then

    fix

    It writes the patch and validates it in an isolated clone — but nothing leaves that clone. Fixes without consequences.

  • Then

    draft-pr

    Same checks, then it pushes a branch and opens a draft. Visible to your team, mergeable by nobody until you say so.

  • Once you trust it

    pr

    A review-ready pull request, like the one above. It still ends at your approval — that line never moves.

Built for trust

The fences that make this safe.

Letting an AI agent write to your repositories is only reasonable if it's boxed in properly. Here's the box.

  • The AI never holds the keys

    Install a GitHub App scoped to only your target repos. guiltyspark mints short-lived tokens for its own Git operations — Codex never receives credentials, so a bad model day can't become a bad security day.

  • Patches stay in their lane

    Per-target allowed paths, a cap on files changed, and required test commands. All of it enforced in a short-lived clone that's thrown away either way.

  • Rehearse before you commit

    guiltyspark replay re-runs a captured incident against a local checkout, so you can watch it work a real bug before granting it push access to anything.

  • One issue, one PR

    It dedups on the underlying problem, not the exact log line. An issue with an open PR is never re-filed, and a configurable cooldown keeps it quiet after merge. It won't bury you.

  • No API key required

    Runs on a ChatGPT-authenticated Codex session, so your existing plan covers it rather than a separately billed OpenAI key. Known problems short-circuit from the local store — a model call is spent only on something genuinely new.

  • Yours to run and audit

    Apache-2.0, self-hosted, no vendor telemetry. A native arm64 image means the whole loop can live on a Raspberry Pi in your house, on infrastructure you control.

The console

for when you do want to look

Teach it what to ignore.

Most of what a log monitor sees isn't worth a pull request, and you're the one who decides which. The dashboard is where you draw that line: silence a noisy pattern, point a new repository at the agent, or check what it's seeing right now. Changes reach the running daemon within one poll cycle — no restart.

343 Guilty Spark
Monitor · Installation Log Surveillance
Uplink nominal

I have grouped the remaining anomalies for your review. None of them warrant a corrective measure yet.

grouped TLS handshake retries from the health checker 4 variants · ×612 events Silence group
Proposed silence pattern would suppress 612 current events · your call
edge-proxy: ^TLS handshake retry \(attempt [0-9]+\)
unassigned legacy-cron ×38 · no repository configured for this one Silence Add target

Silence that sticks

Mute one fingerprint, a whole group, or commit a service-scoped regex that catches future variants too. Every entry keeps a note explaining why, and anything can be restored.

It suggests, you decide

Codex clusters loose anomalies and proposes silence patterns, showing exactly how many live events each would swallow before you commit. Nothing is ever auto-applied.

Nothing falls off the map

Errors that match no configured repository still surface, flagged as unassigned — so a service you forgot to wire up doesn't quietly rot.

The dashboard is unauthenticated and can modify configuration. Keep it on a trusted LAN — never expose it to the public internet.

Reasonable questions

The ones you should be asking.

Does it change production code on its own?

No. Every target starts in observe, where nothing is cloned or written. It pushes only from repos you deliberately promoted to draft-pr or pr — and even then it opens a pull request. Merging is a human action, always.

What if the fix is wrong?

Then you close the PR — that's the whole point of ending at review. Wrong patches also have to survive your test suite and patch policy first, so the common failure isn't a bad merge, it's an attempt that dies in the clone and you never hear about.

How is this different from an AI log summarizer?

A summarizer explains text you paste in and stops. This runs on its own, remembers what it has already ruled on, knows which repo each service comes from, writes and validates real code, and finishes with a pull request. The summary was never the hard part.

What do I need to run it?

Docker, a Loki instance to read from, and a Codex session signed in with your ChatGPT account. It's happy on any always-on box you already own — the arm64 image exists because it was built to live on a Raspberry Pi.

Will it flood me with pull requests?

It dedups on the underlying issue rather than the log line, remediates one representative per run, won't re-file while a PR is open, and waits out a cooldown after merge. Noise you silence stays silenced.

Why does it talk like that?

343 Guilty Spark is the endlessly polite AI caretaker from Halo, left alone for millennia to monitor an installation and quite certain he's being helpful. It seemed like the right voice for something that watches your logs while you sleep. You can ignore the reference entirely — the pull requests still make sense.

Quick start

Four commands, then leave it alone.

It comes up in observe mode, so this is a safe thing to point at a real repository on a Tuesday afternoon.

# configure targets, then:
cp .env.example .env
docker compose pull
docker compose run --rm \
  guiltyspark codex login --device-auth
docker compose up
guiltyspark once
Poll Loki once and analyze what's there right now.
guiltyspark daemon
Run forever, polling on an interval. The normal mode.
guiltyspark doctor
Check your configuration and connectivity before trusting any of it.
guiltyspark dashboard
Serve the console on port 8343.
guiltyspark replay
Re-run a captured incident against a local checkout.

Greetings, Reclaimer

Point it at your logs. See what it fixes.

It starts in observe mode and can't touch anything. The worst case is you learn something about your own logs.

Clone on GitHub Read the docs