AI-powered bug fix generator. Paste a bug ticket, get a code patch — and optionally push it as a GitHub Pull Request.
Bug Ticket → GitHub OAuth → Index Repo → Context Search → LLM Prompt → Patch (diff) → GitHub PR
- Authenticate via GitHub OAuth 2.0 (scopes:
read:user,user:email,repo) - Index a GitHub repository — clones it, chunks the code, and stores embeddings in ChromaDB
- Input a bug report (title + description) via the React frontend
- Context fetch runs hybrid search (keyword + semantic) over indexed code
- Prompt builder constructs a structured prompt with the bug + relevant code context
- LLM analyzes the bug and returns fixed code — two modes:
- Gemini (Cloud) — backend calls the Google Gemini API
- Local (Ollama) — backend prepares the prompt, your browser calls your local Ollama instance directly, then sends the result back for patch generation. No LLM data leaves your machine.
- Diff generator produces a unified diff showing exactly what changed
- Create PR — one click to push the fix as a GitHub Pull Request via the GitHub API
| Layer | Technology | Deployment |
|---|---|---|
| Frontend | React 19, TypeScript, Vite 8 | Railway (single container) |
| Backend | FastAPI, Python 3.13, Uvicorn | Railway (single container) |
| Database | PostgreSQL (SQLAlchemy ORM) | Neon Console (serverless) |
| Vector DB | ChromaDB (semantic search) | Chroma Cloud |
| Auth | GitHub OAuth 2.0, JWT, Fernet | — |
| LLM | Google Gemini API (cloud) / Ollama (browser-local) | Cloud / User's machine |
| VCS | GitHub REST API v3 | — |
| Container | Multi-stage Docker build | Railway |
- Single-page application with dark/light theme
- Diff viewer for patch visualization
- GitHub OAuth login flow
- Repository indexing modal
- One-click PR creation from generated patches
- Auth Service — GitHub OAuth callback, JWT session cookies, Fernet-encrypted token storage
- Context Service — Hybrid search with fallback chain (semantic → keyword)
- Indexer Service — Clones GitHub repos, chunks code into overlapping segments, stores in ChromaDB
- LLM Service — Gemini with thinking + search (cloud), or browser-local Ollama via prompt handoff
- Prompt Builder — Structured prompt construction with bug context and relevant code
- GitHub PR Service — Branch creation, atomic commits via Git Trees API, pull request creation
- Diff Generator — Unified diff output with fuzzy patch application
- Middleware — Rate limiting, CORS, security headers (XSS, clickjacking), API key scrubbing
- PostgreSQL (Neon Console) — Users, encrypted GitHub tokens, repo metadata, sessions
- ChromaDB (Chroma Cloud) — Per-user vector collections for code embeddings and semantic search
- GitHub OAuth 2.0 — Authentication and authorization
- GitHub REST API v3 — Repository operations, branch/tree/commit/PR management
- Google Gemini API — Cloud LLM inference (gemini-2.5-flash, gemini-3-flash-preview)
- Ollama (optional) — Local LLM running on the user's machine, called directly from the browser
- Python 3.13+
- Node.js 22+
- A GitHub OAuth App (create one)
- A Gemini API key (get one)
# 1. Clone the repository
git clone https://github.com/your-username/AutoPatch-AI.git
cd AutoPatch-AI
# 2. Create and activate virtual environment
python3 -m venv venv
source venv/bin/activate
# 3. Install backend dependencies
pip install -r Backend/requirements.txt
# 4. Configure environment
cp Backend/.env.example Backend/.env
# Edit Backend/.env with your API keys and database URL
# 5. Start the backend
cd Backend
uvicorn main:app --reload
# 6. Start the frontend (separate terminal)
cd Frontend
npm install
npm run devThe frontend runs at http://localhost:5173 and proxies API calls to the backend at http://localhost:8000.
# Build the multi-stage image
docker build -t autopatch-ai .
# Run the container
docker run -d --name autopatch -p 8000:8000 \
--env-file Backend/.env \
autopatch-aiThe app is available at http://localhost:8000 (backend serves the built frontend).
The project is configured for Railway with a single-container deployment:
- Connect your GitHub repository to Railway
- Set environment variables in the Railway dashboard (see Configuration below)
- Railway auto-builds using the
Dockerfile(multi-stage: Node build → Python runtime) - The backend serves the built frontend static files from
/Frontend/dist
AutoPatch AI supports a hybrid architecture where the deployed backend handles context retrieval and prompt building, while the LLM runs entirely on your local machine via Ollama. Your code and prompts never leave your machine.
Browser → Backend (prepare prompt) → Browser → Local Ollama (generate) → Backend (parse into patches)
The backend is the "brain" (context, search, prompt construction, patch parsing). Your machine is the "compute" (LLM inference).
-
Install Ollama from ollama.com
-
Pull a model:
ollama pull llama3
-
Start Ollama with CORS enabled (required for browser access):
By default, browsers block requests from a website (like your deployed app) to
localhost:11434. Ollama needs to be told to allow these cross-origin requests.macOS:
OLLAMA_ORIGINS=* ollama serveIf Ollama is already running (e.g. the menu bar app), quit it first, then run the command above in a terminal.
To make it permanent so you don't have to type it every time:
launchctl setenv OLLAMA_ORIGINS "*"Then restart the Ollama app normally.
Linux:
If running directly:
OLLAMA_ORIGINS=* ollama serveIf using systemd:
sudo systemctl edit ollama
Add this in the editor:
[Service] Environment="OLLAMA_ORIGINS=*"Then:
sudo systemctl daemon-reload sudo systemctl restart ollama
Windows (PowerShell):
$env:OLLAMA_ORIGINS="*" ollama serve
To make it permanent, add
OLLAMA_ORIGINSas a system environment variable with value*via Settings > System > Environment Variables, then restart Ollama.Quick test — after starting with CORS enabled, open your browser console and run:
fetch("http://localhost:11434").then(r => console.log("Ollama OK:", r.status))
If you see
Ollama OK: 200, your deployed app will be able to connect. -
Select "Local (Ollama)" in the LLM Provider toggle on the app
-
Pick a model from the auto-detected dropdown and generate fixes as usual
| Model | Size | Best for |
|---|---|---|
llama3 |
8B | General-purpose, fast |
qwen2.5-coder:32b |
32B | High-quality code fixes (needs 20GB+ RAM) |
deepseek-coder:6.7b |
6.7B | Lightweight code-focused |
codellama:13b |
13B | Good balance of quality and speed |
Copy Backend/.env.example to Backend/.env and configure:
| Variable | Default | Description |
|---|---|---|
LLM_PROVIDER |
browser |
browser (local Ollama via user's browser) or gemini (cloud) |
LLM_MODEL |
— | Model name (e.g. gemini-2.5-flash, llama3) |
GEMINI_API_KEY |
— | Google Gemini API key (required for Gemini mode) |
| Variable | Default | Description |
|---|---|---|
GITHUB_CLIENT_ID |
— | OAuth App client ID |
GITHUB_CLIENT_SECRET |
— | OAuth App client secret |
SECRET_KEY |
— | Fernet key for encrypting tokens (generate below) |
FRONTEND_URL |
http://localhost:5173 |
Redirect URL after OAuth callback |
Generate a Fernet key:
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"| Variable | Default | Description |
|---|---|---|
DATABASE_URL |
postgresql://localhost/autopatch |
PostgreSQL connection string (Neon Console) |
| Variable | Default | Description |
|---|---|---|
CHROMA_MODE |
local |
local, cloud (Chroma Cloud), or server (self-hosted) |
CHROMA_API_KEY |
— | API key for Chroma Cloud |
CHROMA_TENANT |
— | Chroma Cloud tenant ID |
CHROMA_DATABASE |
— | Chroma Cloud database name |
CHROMA_HOST |
localhost |
Self-hosted ChromaDB host |
CHROMA_PORT |
8000 |
Self-hosted ChromaDB port |
CHROMA_PERSIST_DIR |
./.chroma_index |
Local ChromaDB storage path |
| Variable | Default | Description |
|---|---|---|
ALLOWED_ORIGINS |
* |
Comma-separated CORS origins |
RATE_LIMIT_GLOBAL |
60 |
Global requests/min per IP |
RATE_LIMIT_LLM |
10 |
LLM endpoint requests/min per IP |
| Variable | Default | Description |
|---|---|---|
MAX_CONTEXT_FILES |
3 |
Number of context files sent to LLM |
CLONE_DIR |
System temp dir | Temp directory for cloned repos |
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/auth/github |
Redirect to GitHub OAuth |
GET |
/api/auth/callback |
OAuth callback (exchanges code for token) |
GET |
/api/auth/me |
Get current user profile |
POST |
/api/auth/logout |
Clear session cookie |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/generate-fix |
Generate a patch from a bug ticket (cloud LLM) |
POST |
/api/refine-fix |
Refine a patch with feedback (cloud LLM) |
POST |
/api/generate-prompt |
Get the LLM prompt for browser-local mode |
POST |
/api/refine-prompt |
Get a refinement prompt for browser-local mode |
POST |
/api/build-patches |
Submit raw LLM output to build patches |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/index |
Index a repository for code search |
GET |
/api/index/status |
Check indexing status |
GET |
/api/index/files |
List indexed files |
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/create-pr |
Create a GitHub PR from patches |
| Method | Endpoint | Description |
|---|---|---|
GET |
/health |
Health check |
GET |
/api/settings |
Get current settings |
PUT |
/api/settings |
Update LLM settings |
curl -X POST http://localhost:8000/api/generate-fix \
-H "Content-Type: application/json" \
-b "autopatch_session=<your-jwt>" \
-d '{
"title": "Export fails for pending users",
"description": "export_user_data returns None when user status is pending instead of raising an error",
"file_hint": "user_service.py"
}'Response:
{
"ticket_title": "Export fails for pending users",
"patches": [
{
"file_path": "user_service.py",
"original_code": "...",
"fixed_code": "...",
"diff": "--- a/user_service.py\n+++ b/user_service.py\n...",
"warning": ""
}
],
"explanation": "The export_user_data function only handled active users..."
}AutoPatch-AI/
├── Backend/
│ ├── main.py # FastAPI entry, lifespan, static file serving
│ ├── requirements.txt # Python dependencies
│ ├── .env.example # Environment variable template
│ └── app/
│ ├── config.py # Environment config loader
│ ├── models.py # Pydantic request/response schemas
│ ├── models_db.py # SQLAlchemy ORM models (User)
│ ├── db.py # Database engine, session factory
│ ├── middleware.py # Rate limiter, security headers, key scrubber
│ ├── constants.py # Supported extensions, skip dirs
│ ├── routes/
│ │ ├── auth.py # GitHub OAuth + session management
│ │ ├── fix.py # /generate-fix, /refine-fix, /generate-prompt, /build-patches
│ │ ├── index.py # /index, /index/status, /index/files
│ │ ├── pr.py # /create-pr (GitHub PR creation)
│ │ └── settings.py # /settings (LLM provider config)
│ ├── services/
│ │ ├── context.py # Hybrid search orchestrator with fallbacks
│ │ ├── indexer.py # ChromaDB indexing + semantic search
│ │ ├── search_keyword.py # Keyword-based code search
│ │ ├── search_semantic.py # Semantic search via ChromaDB
│ │ ├── prompt.py # LLM prompt construction
│ │ ├── llm.py # LLM provider calls (Gemini) + response parsing
│ │ └── github.py # GitHub API (branches, commits, PRs)
│ └── utils/
│ ├── diff.py # Unified diff generator
│ └── patch.py # Fuzzy code patch application
├── Frontend/
│ ├── package.json # React 19, Vite 8, TypeScript 6
│ ├── vite.config.ts # Dev server proxy config
│ └── src/
│ ├── App.tsx # Root component
│ ├── App.css # Global styles
│ ├── api/
│ │ ├── client.ts # API client (fetch wrapper)
│ │ ├── patches.ts # Patch generation + browser-local API calls
│ │ ├── localLLM.ts # Direct Ollama communication (health check, chat, model list)
│ │ ├── settings.ts # Settings API
│ │ └── indexing.ts # Indexing API
│ ├── types.ts # TypeScript type definitions
│ ├── hooks/ # Custom React hooks
│ │ ├── useAuth.ts # GitHub OAuth state
│ │ ├── useIndex.ts # Index status management
│ │ ├── useSettings.ts # LLM settings state
│ │ ├── usePatchGeneration.ts # Patch generation flow
│ │ └── useTheme.ts # Dark/light theme toggle
│ └── components/
│ ├── TopBar/ # Navigation, auth status, theme toggle
│ ├── InputPanel/ # Bug ticket form
│ ├── OutputPanel/ # Patch results, diff viewer, PR button
│ ├── PatchCard/ # Individual patch with diff display
│ ├── ErrorCard/ # Error display component
│ ├── FileTree/ # Indexed file explorer
│ └── IndexModal/ # Repository indexing dialog
├── Dockerfile # Multi-stage build (Node + Python)
├── system-design.png # System architecture diagram
└── README.md
- Fernet encryption for GitHub access tokens at rest in PostgreSQL
- JWT session cookies (
httpOnly,sameSite=lax, 7-day expiry) - Rate limiting per IP (60 req/min global, 10 req/min LLM endpoints)
- API key scrubbing in error responses (defense-in-depth middleware)
- Security headers —
X-Content-Type-Options,X-Frame-Options,X-XSS-Protection,Referrer-Policy,Permissions-Policy,Content-Security-Policy - Per-user data isolation — separate ChromaDB collections and DB records per user
MIT
