Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 64 additions & 53 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,75 +1,86 @@
# 🦅 Grepbase
# Grepbase

**Grepbase** is an AI-powered code exploration and visualization platform that helps developers understand the evolution of a codebase. It transforms complex git histories into an interactive, readable timeline enhanced with AI-generated explanations.
An AI-powered git history explorer. Paste a GitHub repository, walk every commit, and understand what changed and why — with AI.

## Features
## Features

- 🕰️ **Interactive Timeline**: Visualize the progression of any GitHub repository through its commit history.
- 🤖 **Multi-Provider AI**: Support for the latest models from **OpenAI (GPT-5.3)**, **Google (Gemini 3.1)**, **Anthropic (Claude 4.6)**, **GLM**, and **Kimi**.
- 📝 **AI Code Explanations**: Get deep technical insights into what changed in a commit and why it matters.
- 📂 **File Exploration**: Dive into specific files and have AI explain their purpose and patterns.
- 🔐 **Secure BYOK**: API keys are entered by users, then stored server-side in encrypted, session-scoped storage (never persisted in browser local/session storage).
- **Commit Timeline** — Navigate any public GitHub repository commit-by-commit with keyboard shortcuts (← →)
- **Code View** — Browse the file tree and read source at any point in history
- **Diff View** — Inspect what changed in a commit (unified or split) or compare any two commits
- **Story Mode** — AI narrates the arc of a commit in plain English
- **AI Chat** — Ask questions about any commit with full file context
- **Multi-Provider AI** — Works with OpenAI, Anthropic, Gemini, Ollama, LM Studio, GLM, and Kimi
- **BYOK** — API keys are encrypted server-side per session; never stored in the browser

## 🚀 Getting Started
## Getting Started

### Prerequisites

- [Bun](https://bun.sh) (Recommended runtime)
- Node.js & NPM
- [Bun](https://bun.sh) (recommended) or Node.js 20+

### Setup

1. **Clone the repository**:
```bash
git clone https://github.com/Khrees2412/grepbase.git
cd grepbase
```
1. Clone the repository:
```bash
git clone https://github.com/Khrees2412/grepbase.git
cd grepbase
```

2. **Install dependencies**:
```bash
bun install
```
2. Install dependencies:
```bash
bun install
```

3. **Environment Variables**:
Create a `.env` file in the root directory:
```env
GITHUB_TOKEN=your_github_personal_access_token
AI_CREDENTIALS_ENCRYPTION_KEY=generate_a_long_random_secret
AI_CREDENTIALS_SIGNING_KEY=generate_a_second_long_random_secret
ADMIN_API_KEY=generate_an_admin_secret_for_retry_endpoints
CLOUDFLARE_KV_NAMESPACE_ID=your_kv_namespace_id
3. Create a `.env.local` file:
```env
# Required
GITHUB_TOKEN=your_github_personal_access_token

# Optional provider defaults (used when no user key is stored for a session)
OPENAI_API_KEY=
ANTHROPIC_API_KEY=
GEMINI_API_KEY=
GLM_API_KEY=
KIMI_API_KEY=
# Required — must be stable across restarts (session credentials become unreadable if changed)
AI_CREDENTIALS_ENCRYPTION_KEY=generate_a_long_random_secret
AI_CREDENTIALS_SIGNING_KEY=generate_a_second_long_random_secret

NEXT_PUBLIC_APP_URL=http://localhost:3000
```
`AI_CREDENTIALS_ENCRYPTION_KEY` and `AI_CREDENTIALS_SIGNING_KEY` must be stable across deploys/restarts, otherwise encrypted session credentials become unreadable.
# Optional — used as fallback when no user key is configured for a session
OPENAI_API_KEY=
ANTHROPIC_API_KEY=
GEMINI_API_KEY=
GLM_API_KEY=
KIMI_API_KEY=

4. **Run Development Server**:
```bash
bun run dev
```
# Optional
ADMIN_API_KEY=generate_an_admin_secret_for_retry_endpoints
NEXT_PUBLIC_APP_URL=http://localhost:3000
```

5. **Open Grepbase**:
Navigate to [http://localhost:3000](http://localhost:3000) and enter a GitHub repository URL to start exploring.
4. Start the development server:
```bash
bun run dev
```

## 🛠️ Tech Stack
5. Open [http://localhost:3000](http://localhost:3000) and paste a GitHub repository URL to start exploring.

- **Framework**: [Next.js](https://nextjs.org) (App Router)
- **AI Integration**: [Vercel AI SDK](https://sdk.vercel.ai)
- **Styling**: Vanilla CSS & [Framer Motion](https://www.framer.com/motion/)
- **Database**: Drizzle ORM
- **Runtime**: [Bun](https://bun.sh)
## Tech Stack

## 🤝 Contributing
| Layer | Technology |
|---|---|
| Framework | Next.js (App Router) |
| Runtime | Bun |
| Database | SQLite via Drizzle ORM |
| Styling | Vanilla CSS Modules |
| Animation | Framer Motion |
| AI | Vercel AI SDK (multi-provider) |

Contributions are welcome! Please feel free to submit a Pull Request.
## Usage

## 📄 License
1. On the home page, enter any public GitHub repository URL (e.g. `sindresorhus/is`)
2. Grepbase ingests the commit history into a local SQLite database
3. On the Explore page, use ← → to walk commits, or click in the timeline
4. Open Settings (⚙) to add your AI provider key and unlock explanations

MIT License
## Contributing

Pull requests are welcome. For significant changes, open an issue first to discuss the approach.

## License

MIT
Binary file modified bun.lockb
Binary file not shown.
Binary file added dev.db
Binary file not shown.
76 changes: 76 additions & 0 deletions drizzle/0000_nappy_catseye.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
CREATE TABLE `analyses` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`commit_id` integer NOT NULL,
`provider` text NOT NULL,
`explanation` text NOT NULL,
`created_at` integer NOT NULL,
FOREIGN KEY (`commit_id`) REFERENCES `commits`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE INDEX `idx_analyses_commit_id` ON `analyses` (`commit_id`);--> statement-breakpoint
CREATE TABLE `commits` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`repo_id` text NOT NULL,
`sha` text NOT NULL,
`message` text NOT NULL,
`author_name` text,
`author_email` text,
`date` integer NOT NULL,
`order` integer NOT NULL,
FOREIGN KEY (`repo_id`) REFERENCES `repositories`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE UNIQUE INDEX `commits_repo_sha_unique` ON `commits` (`repo_id`,`sha`);--> statement-breakpoint
CREATE INDEX `idx_commits_repo_id` ON `commits` (`repo_id`);--> statement-breakpoint
CREATE INDEX `idx_commits_sha` ON `commits` (`sha`);--> statement-breakpoint
CREATE TABLE `files` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`commit_id` integer NOT NULL,
`path` text NOT NULL,
`content` text,
`size` integer DEFAULT 0,
`language` text,
FOREIGN KEY (`commit_id`) REFERENCES `commits`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE UNIQUE INDEX `idx_files_commit_path` ON `files` (`commit_id`,`path`);--> statement-breakpoint
CREATE INDEX `idx_files_commit_id` ON `files` (`commit_id`);--> statement-breakpoint
CREATE TABLE `ingest_jobs` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`job_id` text NOT NULL,
`url` text NOT NULL,
`status` text NOT NULL,
`repo_id` text,
`progress` integer DEFAULT 0,
`total_commits` integer DEFAULT 0,
`processed_commits` integer DEFAULT 0,
`error` text,
`created_at` integer NOT NULL,
`updated_at` integer NOT NULL,
`retry_count` integer DEFAULT 0,
`max_retries` integer DEFAULT 3,
`last_error` text,
`last_retry_at` integer,
`resume_from_commit` integer DEFAULT 0,
FOREIGN KEY (`repo_id`) REFERENCES `repositories`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE UNIQUE INDEX `ingest_jobs_job_id_unique` ON `ingest_jobs` (`job_id`);--> statement-breakpoint
CREATE INDEX `idx_jobs_job_id` ON `ingest_jobs` (`job_id`);--> statement-breakpoint
CREATE INDEX `idx_jobs_status` ON `ingest_jobs` (`status`);--> statement-breakpoint
CREATE INDEX `idx_jobs_retry` ON `ingest_jobs` (`status`,`last_retry_at`,`retry_count`);--> statement-breakpoint
CREATE TABLE `repositories` (
`id` text PRIMARY KEY NOT NULL,
`url` text NOT NULL,
`owner` text NOT NULL,
`name` text NOT NULL,
`description` text,
`stars` integer DEFAULT 0,
`default_branch` text DEFAULT 'main',
`readme` text,
`last_fetched` integer NOT NULL,
`created_at` integer NOT NULL
);
--> statement-breakpoint
CREATE UNIQUE INDEX `repositories_url_unique` ON `repositories` (`url`);--> statement-breakpoint
CREATE INDEX `idx_repos_owner_name` ON `repositories` (`owner`,`name`);
23 changes: 16 additions & 7 deletions drizzle/meta/0000_snapshot.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"version": "6",
"dialect": "sqlite",
"id": "dfd2901e-6aa0-453d-a46e-3bc554e8278b",
"id": "cefce261-ebfa-4f47-aed9-acf959d37836",
"prevId": "00000000-0000-0000-0000-000000000000",
"tables": {
"analyses": {
Expand Down Expand Up @@ -83,7 +83,7 @@
},
"repo_id": {
"name": "repo_id",
"type": "integer",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
Expand Down Expand Up @@ -132,9 +132,10 @@
}
},
"indexes": {
"commits_sha_unique": {
"name": "commits_sha_unique",
"commits_repo_sha_unique": {
"name": "commits_repo_sha_unique",
"columns": [
"repo_id",
"sha"
],
"isUnique": true
Expand Down Expand Up @@ -221,6 +222,14 @@
}
},
"indexes": {
"idx_files_commit_path": {
"name": "idx_files_commit_path",
"columns": [
"commit_id",
"path"
],
"isUnique": true
},
"idx_files_commit_id": {
"name": "idx_files_commit_id",
"columns": [
Expand Down Expand Up @@ -281,7 +290,7 @@
},
"repo_id": {
"name": "repo_id",
"type": "integer",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
Expand Down Expand Up @@ -426,10 +435,10 @@
"columns": {
"id": {
"name": "id",
"type": "integer",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": true
"autoincrement": false
},
"url": {
"name": "url",
Expand Down
18 changes: 2 additions & 16 deletions drizzle/meta/_journal.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,8 @@
{
"idx": 0,
"version": "6",
"when": 1771757966096,
"tag": "0000_green_mandarin",
"breakpoints": true
},
{
"idx": 1,
"version": "6",
"when": 1771880517123,
"tag": "0001_busy_falcon",
"breakpoints": true
},
{
"idx": 2,
"version": "6",
"when": 1772025771427,
"tag": "0002_large_fabian_cortez",
"when": 1774997048038,
"tag": "0000_nappy_catseye",
"breakpoints": true
}
]
Expand Down
File renamed without changes.
Loading
Loading