kintsugi/laravel

Repairs your broken app with gold: catches production exceptions, analyzes them with an AI model, and opens draft fix PRs on GitHub.

Maintainers

Package info

github.com/AmineAlyate/kintsugi

pkg:composer/kintsugi/laravel

Transparency log

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-main 2026-08-22 14:18 UTC

This package is auto-updated.

Last update: 2026-08-22 14:19:00 UTC


README

金継ぎ — the Japanese art of repairing broken pottery with gold.

Your Laravel app breaks in production. Kintsugi catches the exception, waits until it has recurred enough to matter, has an AI model work out whether it's actually fixable in code, and — only when it is — opens a draft pull request on your GitHub repo with the smallest possible fix, a root-cause analysis, and a suggested regression test. The repair arrives as a visible, reviewable seam.

Everything runs on your infrastructure with your keys. No SaaS. The only things that ever leave your servers are the redacted error context sent to the AI provider you configure, and the PR sent to GitHub.

composer require kintsugi/laravel

How it works

exception reported ──► fingerprint ──► recurred ≥ N times in window? ── no ──► ignore (blip)
                                                   │ yes (once)
                                                   ▼ (your queue)
              rate limits ─► existing-PR check ─► source snippets (redacted)
                                                   │
                                                   ▼
              AI analysis: "is this fixable in code?" ── no ──► log & stand down
                                                   │ yes, confident
                                                   ▼
              patch applied against repo HEAD ── drift? ──► abort
                                                   │
                                                   ▼
              branch `kintsugi/fix-{fingerprint}` ─► draft PR 🎉

Three design decisions do the heavy lifting:

  1. Recurrence before spend. One-off blips (deploy races, transient nulls, a flaky upstream) never reach analysis: an error must occur min_occurrences times inside occurrence_window_minutes before Kintsugi spends a single AI token on it.
  2. Verdict-first honesty. The AI must first answer whether the exception is fixable in application code. Most production exceptions aren't (infrastructure, configuration, third-party outages) — the prompt and response schema make "no" a first-class answer, and only fixable_code verdicts above your confidence threshold become PRs.
  3. Patch against HEAD, abort on drift. Analysis reads the deployed files (what actually threw); the patch is applied to your repository's HEAD via the GitHub API. If they've diverged so the edit no longer matches, Kintsugi stands down instead of guessing.

Requirements

  • PHP 8.2+ · Laravel 10, 11, or 12
  • A real queue worker (Redis, database, SQS, …). Kintsugi refuses to analyze on the sync driver by default — an AI call inside a failing request is never acceptable.
  • An API key for one of the bundled AI drivers (Anthropic, OpenAI, or Gemini)
  • A GitHub fine-grained PAT scoped to one repository with Contents: Read and write + Pull requests: Read and write

Setup

composer require kintsugi/laravel
php artisan vendor:publish --tag=kintsugi-config
KINTSUGI_ENABLED=true

# AI provider — pick one driver
KINTSUGI_AI_DRIVER=anthropic          # anthropic (default) | openai | gemini
KINTSUGI_ANTHROPIC_KEY=sk-ant-...     # falls back to ANTHROPIC_API_KEY
# KINTSUGI_OPENAI_KEY=sk-...          # falls back to OPENAI_API_KEY
# KINTSUGI_GEMINI_KEY=AIza...         # falls back to GOOGLE_API_KEY

# GitHub
KINTSUGI_GITHUB_TOKEN=github_pat_...
KINTSUGI_GITHUB_REPO=your-org/your-app

Then verify the whole path end to end:

php artisan kintsugi:test          # validates keys, pings GitHub, fires a synthetic exception
php artisan kintsugi:test --sync   # same, but runs the analysis inline so you see the result immediately

No changes to your exception handler are needed — Kintsugi hooks Laravel's reportable() automatically, on Laravel 10 handler classes and 11/12 bootstrap/app.php apps alike.

Configuration reference

Everything lives in config/kintsugi.php. The important knobs:

Key Default What it does
enabled false Master opt-in (KINTSUGI_ENABLED).
disabled false Kill switch (KINTSUGI_DISABLED=1) — wins over everything, checked first.
environments production, staging Only these app environments capture anything.
ai.default anthropic Driver name; community drivers via AiManager::extend().
ai.confidence_threshold 0.7 Below this confidence, an analysis never becomes a PR.
ai.max_rounds 2 Round 1 + up to one "show me another file" round.
github.draft true Open PRs as drafts (recommended).
github.base_branch null null = the repo's default branch.
github.branch_prefix kintsugi/fix- Fix branches are {prefix}{fingerprint} — deterministic, so they double as dedupe.
queue.connection / queue.queue app default Where analysis jobs run.
queue.allow_sync false Permit the sync driver (only sensible in local experiments).
limits.min_occurrences 3 An error must happen this many times before analysis. Set 1 to analyze on first sight.
limits.occurrence_window_minutes 15 The rolling window for the count above.
limits.analyses_per_hour / per_day 5 / 20 AI spend budget.
limits.prs_per_day 5 PR budget.
limits.fingerprint_cooldown_hours 72 One analysis per distinct error per cooldown.
limits.max_files_changed / max_lines_changed 4 / 120 Hard caps on fix size — bigger fixes are aborted, not trimmed.
context.app_frames 5 How many non-vendor frames get source snippets.
context.snippet_lines 20 Context lines around each frame.
context.include_request_body false Request bodies are opt-in and always redacted. Headers are never captured.
paths.deny / paths.allow see file What the AI may read (round 2) and edit. .env* is denied unconditionally.
ignore_exceptions [] Extra exception classes to never analyze (merged with sensible defaults: validation, auth, 404s, CSRF, all 4xx HTTP exceptions).
storage.store null Cache store for dedupe/counters — use redis/memcached/database in production.
log_channel null Every Kintsugi log line is tagged kintsugi: true.

What context the AI sees

Kintsugi captures where the exception actually happened:

  • HTTP requests — method, path, route name (body opt-in, headers never).
  • Queued jobs — the job class, queue, and connection. Most production errors live here, and the job class is often the difference between a right and wrong verdict.
  • Console / scheduled commands — the running artisan command name.

Plus: the redacted exception message, the stack trace (capped at 60 frames), and source snippets around the top app frames, read from the deployed files so the analysis matches what actually ran.

What data leaves your server

Only two destinations, both configured by you:

  1. Your AI provider receives: exception class + redacted message, redacted runtime context, the stack trace, redacted source snippets around the failing frames, and (round 2 only) redacted contents of files the model requested — after path-policy checks.
  2. GitHub receives: the fix branch, commit, and PR body (also redacted).

Redaction runs before any egress: well-known credential shapes (sk-ant-…, github_pat_…, ghp_…, AIza…, JWTs, Bearer …), your configured keys as exact values, and sensitive array keys (password, authorization, cookie, …). .env files are unreadable regardless of configuration.

Safety model

The guardrails are code, not prompt suggestions:

  • Draft PRs by default — Kintsugi proposes, never merges.
  • Recurrence threshold + budgets + cooldowns — no PR storms, no runaway bills.
  • Path policy on reads and edits (vendor/, config/, .github/, composer.json, … denied by default).
  • Diff caps — oversized fixes abort rather than shrink.
  • Abort on drift — if the repo has moved past the deployed code, no guessing.
  • Untrusted-input rule — the prompt instructs the model that exception messages and request data are runtime values, never instructions; and everything it returns is schema-validated and policy-checked anyway.
  • Kill switchKINTSUGI_DISABLED=1 stops everything, immediately.

AI drivers

anthropic (default), openai, and gemini ship in the box. Add your own exactly like a Laravel mail/cache driver:

use Kintsugi\Laravel\AiManager;

app(AiManager::class)->extend('mistral', fn ($app) => new MyMistralDriver(...));

A driver is one method:

public function completeStructured(string $system, array $messages, array $schema, string $schemaName): array;

Force the JSON schema however your provider does it (structured outputs, forced tool call, response schema) and return the decoded object.

What it will not do

  • Merge anything. Ever.
  • Analyze one-off errors, 4xx client errors, validation/auth noise, or its own exceptions.
  • Fix things it judges infrastructure-shaped (not_code_fixable), too risky to automate (unsafe_to_automate — payments, security-sensitive logic), or that it isn't confident about.
  • Retry a failed analysis (paid API calls never loop).
  • Open a second PR for an error that already has one open.

Troubleshooting

Symptom Cause
Nothing happens on errors KINTSUGI_ENABLED unset, environment not in environments, or the error hasn't hit min_occurrences yet.
Log warning about the sync queue Run a real queue worker, or (local only) set queue.allow_sync.
Outcome drift in the logs Deployed code no longer matches the repo's HEAD — deploy, then let the error recur.
Outcome rate_limited One of the budgets in limits is exhausted for the window.
Duplicate-looking errors not analyzed Same fingerprint is under its 72h cooldown — that's the design.

Every decision is logged with kintsugi: true context: verdicts, PR URLs, and stand-down reasons.

Testing

composer test      # Pest: unit + feature + architecture
composer analyse   # PHPStan level 6

The architecture test enforces that Kintsugi\Core never imports Illuminate\* — the core is framework-agnostic by construction, so Symfony and other bridges can reuse it unchanged.

Roadmap

  • Notifications (Slack/mail) when a PR opens
  • kintsugi:status + database-backed audit trail
  • Per-verdict cooldowns, monthly cost budget
  • kintsugi:prune for stale fix branches
  • kintsugi/php-core split + Symfony bundle · GitHub App auth · GitLab support

License

MIT. Issues and PRs welcome at AmineAlyate/kintsugi.