All projects
Case Study

RepoSentry

A full-stack AI coding agent for GitHub. Sign in, ask about your code in plain English, and let the agent read, search, review and fix it, then open a pull request for you to approve.

Role
Solo full-stack developer
Type
Product, built end to end
Focus
Agentic AI · Developer tooling
Stack
React · TypeScript · Node.js · PostgreSQL · Gemini API
8Agent tools
4Database models
1Branch and PR per repo
0Direct writes to main
RepoSentry chat interface showing an agent fixing a bug and opening a pull request

Overview

RepoSentry turns a GitHub account into a conversation. After signing in with GitHub OAuth, a developer can ask questions like "show me the full structure of my repo", "review auth.ts for bugs" or "fix this and open a PR". Behind the chat, a Gemini-powered agent decides which GitHub tools to call, reads real code instead of guessing, and reports back. When asked to fix something, it commits the change to a dedicated branch and opens a pull request so a human always reviews before merging.

The challenge

AI assistants usually answer from memory, which is risky for code. The goal was an agent that works on the real repository and can be trusted with write access. The hard problems were grounding answers in actual files, keeping the agent from damaging a repo, and keeping responses fast on large codebases while running on free-tier model quotas.

How it works

  1. 1

    Sign in

    GitHub OAuth, then a signed JWT session. The agent uses that user's own GitHub token.

  2. 2

    Ask

    The user types a request in plain English, optionally with Think mode or voice input.

  3. 3

    Plan

    Gemini picks the right tool through function calling instead of guessing.

  4. 4

    Act

    The server runs the tool against the GitHub API and returns real data to the model.

  5. 5

    Answer

    The reply is rendered as markdown with code blocks, trees and tables.

  6. 6

    Ship

    For fixes: branch, commit, pull request. The user reviews and merges.

The agent's toolbox

list_repos

Lists every repository the signed-in user can access.

list_repo_files

Lists one folder level of a repository.

get_full_repo_tree

Fetches the complete nested structure through the Git Trees API.

read_file

Reads a file's real content, with a size cap for speed.

search_code

Searches a repository with GitHub code search instead of opening files one by one.

create_branch

Creates the single shared fix branch for a repository.

update_file

Commits the corrected file to the fix branch with a clear message.

create_pull_request

Opens the pull request, or reuses the open one, so the user can review.

What I built

  • GitHub OAuth login with JWT sessions and multi-user support, so every user works with their own repositories and token
  • A Gemini agent loop with function calling, bounded to a maximum number of tool rounds plus a forced final answer so it can never run away
  • Persistent chat history in PostgreSQL through Prisma: multiple chats per user with new, pin, rename and delete
  • Per-user usage tracking: requests, prompt tokens, completion tokens and the model used, shown against a daily cap in a Settings panel
  • A custom dark React and TypeScript interface with markdown rendering, a repository sidebar, voice input, a Think toggle and a mobile layout where the sidebar collapses
  • A layered Express backend split into routes, controllers, services and middleware, deployed with the frontend on Vercel and the API on Render

Safety by design

  • Never writes to the default branch. The check lives on the server, so even a prompt that asks the model to push to main is refused.
  • One shared fix branch per repository, enforced in code. Fixing five bugs produces five commits on one pull request, not five branches.
  • Pull requests are reused. If one is already open from the fix branch, new commits simply join it.
  • Tool failures never crash a request. Errors such as a wrong path are returned to the model so it can recover and try again.
  • The system prompt requires the model to analyze real code, cite lines, and say so honestly when the code looks fine.

Problems I solved

Runaway branches and pull requests

Problem. Left alone, the model invented a new branch name for every bug.

Solution. The branch name is fixed on the server and the model's choice is ignored, with pull request reuse on top.

Slow answers on big repositories

Problem. A huge file or tree can turn one question into minutes of model input.

Solution. Files are capped at 30,000 characters, history is trimmed to recent messages, and the last file or tree is carried forward so it is not fetched twice.

Mangled folder trees

Problem. Models retype indentation badly and burn output tokens doing it.

Solution. The server builds the ASCII tree itself. Plain tree requests skip the model and return it directly, saving two model calls.

Free-tier quotas and overloads

Problem. Models return 503s and run out of daily requests.

Solution. A fast model handles normal chat and a deeper model handles Think mode, each acting as the other's fallback, with retries on overload.

No quota API from Google

Problem. There is no endpoint that reports remaining requests.

Solution. Every call is logged with its token counts and compared with a configurable daily cap, so users see honest, self-tracked usage.

Architecture

Frontend

React · TypeScript · Vite. Components for sidebar, chat window, input panel, login and settings.

API

Node.js · Express · TypeScript with routes, controllers, services and JWT middleware.

AI layer

Google Gemini with function calling, a tool executor and context carry-over.

Data

PostgreSQL through Prisma: users, chats, messages and usage logs with cascading deletes.

Integrations

GitHub OAuth, REST API, Git Trees API and code search API.

Hosting

Vercel for the client and Render for the server, configured through render.yaml.

MethodEndpoints
GET/auth/github · /auth/github/callback · /auth/me
POST/api/chat
GET POST PATCH DELETE/api/chats
GET/api/github/repos · files · file · tree
GET/api/usage

Outcome

RepoSentry is live and open source. It shows how to give an AI model real access to a codebase without giving up control: the agent reads, reasons and writes, but a human always makes the final call. Building it end to end covered OAuth, a typed REST API, a relational schema, agent design, prompt engineering and deployment.

What I learned

  • Enforce safety rules in code, never only in the prompt
  • Do deterministic work in code and keep the model for reasoning
  • Bound every loop, size and retry in an agent
  • Track usage from the first version, not after the bill arrives

What is next

  • Syntax highlighting for file results
  • Rate limiting and abuse protection on public endpoints