Unleashing AutoFix: A Dev's Deep Dive into AI-Driven Security & Bug Remediation
Join us on a technical deep dive into the AutoFix Pipeline, our latest venture into AI-powered security and bug remediation, from issue detection to automated pull request generation.
The relentless pursuit of clean, secure, and performant code is a developer's eternal struggle. We've all been there: a security vulnerability surfaces, a subtle bug is reported, or a performance bottleneck rears its ugly head. The process of identifying, diagnosing, and fixing these issues can be a significant drain on resources.
What if we could automate a significant chunk of that process? What if AI could not only pinpoint the problem but also suggest and even generate a fix, ready for review? This was the driving vision behind our latest project: the AutoFix Pipeline.
This post is a behind-the-scenes look at a recent development sprint where we brought the AutoFix Pipeline to feature completeness. It's less a polished product announcement and more a raw, honest account of the technical journey, the architectural decisions, and the inevitable bumps along the way.
The Vision: Automated Remediation, From Scan to PR
Our goal with the AutoFix Pipeline was ambitious: a comprehensive system for automated security and bug discovery, complete with AI-powered remediation, unified diff patching, optional GitHub Pull Request creation, and even an external resolution webhook for third-party tools. Think of it as a proactive guardian for your codebase, constantly scanning, detecting, and suggesting fixes.
As of our last session, the core pipeline is feature complete and committed. Typechecks pass, and the build compiles (ignoring a couple of pre-existing, unrelated issues). Let's dive into how we built it.
Under the Hood: The AutoFix Architecture
Building an AI-driven remediation system touches many parts of the stack. Here's a breakdown of the key components we developed:
1. Data Models: The Foundation
We started by laying down the data structure with Prisma, defining two new models:
AutoFixRun: Represents an entire scan-and-fix operation for a repository.AutoFixIssue: Details a single detected issue within anAutoFixRun, including its severity, category, status, and related code snippets. These models establish crucial relations to existingUser,Tenant, andRepositoryentities, ensuring proper ownership and context.
2. Shared Types: Clarity and Consistency
To maintain consistency across our frontend and backend, we introduced src/types/auto-fix.ts. This file centralizes key enums and interfaces like AutoFixEvent (for streaming updates), IssueSeverity, IssueCategory, and IssueStatus.
3. GitHub Connector: The Bridge to Your Code
Automating fixes means interacting directly with source control. We significantly extended src/server/services/github-connector.ts to handle write operations:
createBranch: For creating feature branches for proposed fixes.createOrUpdateFile: To apply changes to specific files.getFileSha: Essential for optimistic updates in GitHub's API.createPullRequest: The ultimate goal – proposing the AI-generated fix for review.
4. The Brains of the Operation: AI-Powered Services
This is where the magic happens. We developed two core AI services:
-
src/server/services/auto-fix/issue-detector.ts: This service leverages Large Language Models (LLMs) for prescriptive issue detection. It's trained to identify common vulnerabilities (OWASP Top 10), performance bottlenecks, error-handling deficiencies, and general code smells. We adopted a batch processing pattern from our existingpattern-detectorand support a "Bring Your Own Key" (BYOK) model for LLM providers. -
src/server/services/auto-fix/fix-generator.ts: Once an issue is detected, this service takes over. It's responsible for generating a unified diff – a standard patch format – that proposes a fix for the identified problem. The LLM here is prompted to produce precise, context-aware code changes.
5. Patch Application: Making Diffs a Reality
An AI-generated diff is useless if you can't apply it. src/server/services/auto-fix/patch-utils.ts handles this critical step. It parses the unified diff format and applies the changes to the relevant files, ensuring the proposed fix integrates cleanly with the existing codebase.
6. The Orchestrator: pipeline.ts
The heart of the AutoFix system is src/server/services/auto-fix/pipeline.ts. This asynchronous generator orchestrates the entire workflow:
- Scan Phase: Initiates the code analysis.
- Detect Phase: Feeds the code to the
issue-detector. - Fix Phase: For each detected issue, calls the
fix-generatorand thenpatch-utilsto apply the changes locally. - PR Phase: If configured, uses the
github-connectorto create a new branch, commit the changes, and open a Pull Request.
Using an AsyncGenerator here was a deliberate choice, allowing us to stream updates to the UI in real-time as each phase completes and issues are processed.
7. API & UI: Bringing it to Life
- tRPC Router (
src/server/trpc/routers/auto-fix.ts): We exposed 7 procedures for managing AutoFix runs and issues:list,get,start,cancel,resolveIssue,skipIssue, andresolutionStats. - SSE Streaming Endpoint (
src/app/api/v1/events/auto-fix/[id]/route.ts): Following a pattern established in ourcode-analysisfeature, this endpoint provides live updates to the frontend using Server-Sent Events, reflecting the progress of thepipeline.tsgenerator. - External Resolution Webhook (
src/app/api/v1/webhooks/auto-fix/resolve/route.ts): This allows external tools (like Claude Code, GitHub Copilot, or Cursor) to mark an issue as resolved, integrating with our pipeline. - UI Components & Pages: We built dedicated UI components (
patch-viewer.tsx,issue-card.tsx,run-progress.tsx,run-stats.tsx) and integrated them into new dashboard pages (/dashboard/auto-fixfor a run list and/dashboard/auto-fix/[id]for detailed run views with live updates and filtering). - Knowledge Hub Integration: Finally, we updated
src/server/services/knowledge-hub.tsandknowledge-stats.tsxto blend AutoFix resolution data with existing insight pairing data, providing a holistic view of code quality improvements.
Navigating the Treacherous Waters: Lessons Learned
Our journey wasn't without its bumps. Here are a few critical lessons from the trenches:
1. Prisma and PostgreSQL Vector Columns: A Clash of Abstractions
- The Problem: We use a
vector(1536)column for embeddings in ourworkflow_insightstable, which is created using raw SQL. Prisma, however, represents this asUnsupported("tsvector")in its schema. Everynpm run db:pushcommand would warn about dropping this column. - The Workaround: Our standard (and somewhat painful) workflow became: run
npm run db:push --accept-data-loss(because Prisma can't understand thevectortype and wants to drop it), then manually re-add the column usingALTER TABLE workflow_insights ADD COLUMN IF NOT EXISTS embedding vector(1536);. - Lesson Learned: When working with ORMs and custom database types (especially those not natively supported or understood), be prepared for friction. Either accept a manual step in your migration workflow, or explore raw SQL migrations entirely for such columns. Understanding the ORM's limitations is key to preventing data loss.
2. ESLint Configuration Woes: The Silent Killer of Productivity
- The Problem: During a
npm run buildwith linting enabled, ESLint would fail, complaining that the@typescript-eslint/no-unused-varsrule wasn't found across all files. This was a pre-existing, project-wide configuration issue. - The Workaround: We resorted to
npx next build --no-lintto bypass the linting step, per an existing team agreement. - Lesson Learned: A broken ESLint config can severely hinder developer productivity and code quality. Invest time in a robust, shared linting setup early, and ensure
@typescript-eslintplugins are correctly installed and configured in the monorepo root or relevant packages. Don't let linting issues fester; they often indicate deeper configuration problems.
3. Relative Path Hell: Mind Your Directories
- The Problem: While setting up the SSE endpoint, I initially used
../../../../middlewarefor an import path. TypeScript couldn't resolve it. - The Workaround: A quick count revealed it should have been
../../../middleware– three levels up, matching ourcode-analysisSSE endpoint. - Lesson Learned: Relative paths can be tricky, especially in deeply nested directories or when copying patterns. Double-check your directory structure. For larger projects, consider implementing path aliases (e.g., in
tsconfig.json) to avoid "dot-dot-slash" soup and improve readability and maintainability.
State of Play & What's Next
The AutoFix Pipeline is now feature complete, committed as 0fa60cc on main. The database has new auto_fix_runs and auto_fix_issues tables, and our Prisma client is regenerated. GitHub write operations for this feature will require the repo scope on user-provided PATs.
Our immediate next steps involve:
- Adding the sidebar navigation link for AutoFix (
/dashboard/auto-fix). - Performing end-to-end testing: starting a run on a test repo and verifying SSE streaming.
- Testing the external resolution webhook.
- Considering Row-Level Security (RLS) policies for the new tables in
prisma/rls.sql. - Finally tackling those pre-existing ESLint and
useSearchParams()Suspense issues!
Building the AutoFix Pipeline has been an exciting challenge, pushing the boundaries of what's possible with AI in developer tooling. We're eager to see how this system will empower developers to maintain healthier, more secure codebases with less manual effort.
Stay tuned for more updates as we refine and deploy this powerful new capability!
{
"thingsDone": [
"Implemented AutoFixRun and AutoFixIssue Prisma models",
"Created shared TypeScript types for AutoFix events, severities, categories, and statuses",
"Extended GitHub connector for branch creation, file updates, and PR generation",
"Developed LLM-based issue detection service (OWASP, bugs, perf, code smells)",
"Developed LLM-based unified diff generation service for fixes",
"Implemented unified diff parser and applier utility",
"Built an AsyncGenerator-based pipeline orchestrator (scan → detect → fix → PR)",
"Created tRPC router with 7 procedures for AutoFix management",
"Registered autoFix router in main tRPC setup",
"Developed SSE streaming endpoint for live AutoFix run updates",
"Created external resolution webhook for AI code assistants",
"Built 4 new UI components (patch-viewer, issue-card, run-progress, run-stats)",
"Created AutoFix run list and detail pages in the dashboard",
"Integrated AutoFix resolution stats into Knowledge Hub and dashboard cards"
],
"pains": [
"Prisma's incompatibility with PostgreSQL 'vector' column, requiring manual ALTER TABLE after db:push --accept-data-loss",
"Pre-existing ESLint configuration issue preventing full build without '--no-lint' flag",
"Incorrect relative path resolution for an SSE endpoint import"
],
"successes": [
"Achieved feature completeness for the core AutoFix Pipeline",
"Successful integration of LLMs for both issue detection and diff generation",
"Robust pipeline orchestration using AsyncGenerators for real-time feedback",
"Comprehensive API and UI for managing and monitoring auto-fix runs",
"Seamless integration with GitHub for automated PR creation"
],
"techStack": [
"TypeScript",
"Next.js",
"Prisma",
"PostgreSQL",
"LLMs (Large Language Models)",
"GitHub API",
"tRPC",
"Server-Sent Events (SSE)",
"React (UI components)",
"ESLint",
"npm"
]
}