Skip to content

HakkanShah/commit-habit

Repository files navigation

Commit Habit

Build Your GitHub Activity Streak β€” Securely & Ethically

A free, open-source GitHub App that helps developers maintain daily GitHub habits without Personal Access Tokens.

MIT License Next.js TypeScript Prisma Vercel


Live Demo Β· Report Bug Β· Request Feature


⚠️ Ethics Disclaimer: Automated commits do NOT represent real development work. This tool is designed for learning and habit-building purposes only. Always be transparent about your contributions.


πŸ“– Table of Contents


✨ Features

Feature Description
πŸ”’ Secure Authentication GitHub App OAuth β€” no PATs or passwords required
πŸ” Google OAuth Support Alternative sign-in with Google account
πŸ“ Non-destructive Changes Only modifies README formatting (whitespace)
⏰ Smart Scheduling Automatically skips days when you have real commits
🎯 Daily Limits Maximum 5 automated commits per day per repository
πŸ”„ Full Control Pause, resume, or uninstall anytime
πŸ“Š Activity Dashboard Track automation history with beautiful UI
πŸ“§ Email Notifications Get notified about important events
πŸ“ˆ Analytics Discord webhook integration for visitor analytics
🌱 Beginner-Friendly Learn GitHub automation safely

πŸ› οΈ Tech Stack

Frontend Backend Database Infrastructure
  • Next.js 16 (App Router)
  • React 19
  • TypeScript 5
  • Tailwind CSS 4
  • Framer Motion
  • Next.js API Routes
  • GitHub App SDK (Octokit)
  • JWT Authentication
  • Webhook Handlers
  • PostgreSQL
  • Prisma ORM
  • Supabase
  • Vercel (Hosting)
  • Vercel Cron Jobs
  • GitHub Actions (CI/CD)

πŸš€ Quick Start (For Users)

Getting started with Commit Habit takes less than 2 minutes:

Step 1: Visit the App

Go to commithabit.vercel.app

Step 2: Sign In

Click "Get Started" and authenticate with your GitHub or Google account.

Step 3: Install the GitHub App

Click "Add Repository" and install the Commit Habit app on your selected repositories.

Step 4: Enable Automation

Toggle automation ON for any connected repository. That's it! πŸŽ‰


πŸ’» Installation (For Developers)

Prerequisites

  • Node.js 18.0 or higher
  • npm or yarn or pnpm
  • PostgreSQL database (Supabase recommended)
  • GitHub Account for creating a GitHub App

1. Clone the Repository

git clone https://github.com/HakkanShah/commit-habit.git
cd commit-habit

2. Install Dependencies

npm install
# or
yarn install
# or
pnpm install

3. Create a GitHub App

  1. Navigate to GitHub Settings β†’ Developer settings β†’ GitHub Apps
  2. Click "New GitHub App"
  3. Configure the following:
Field Value
App Name commit-habit (must be unique)
Homepage URL https://your-app.vercel.app
Callback URL https://your-app.vercel.app/api/auth/callback
Setup URL https://your-app.vercel.app/api/auth/callback
Webhook URL https://your-app.vercel.app/api/github/webhook
Webhook Secret Generate with openssl rand -hex 32
  1. Set Permissions:

    Permission Access Level
    Repository contents Read & Write
    Metadata Read
  2. Subscribe to Events:

    • βœ… Installation
    • βœ… Installation repositories
  3. Click "Create GitHub App"

  4. Generate and download a Private Key (.pem file)

  5. Note your App ID, Client ID, and Client Secret

4. Configure Environment Variables

cp .env.example .env.local

Fill in your values (see Environment Variables section).

5. Set Up Database

# Initialize Prisma and run migrations
npx prisma migrate dev --name init

# Generate Prisma Client
npx prisma generate

6. Run Development Server

npm run dev

Open http://localhost:3000 in your browser.


πŸ”‘ Environment Variables

Create a .env.local file in the root directory with the following variables:

Required Variables

Variable Description Example
DATABASE_URL PostgreSQL connection string postgresql://user:pass@host:5432/db
GITHUB_APP_ID Your GitHub App ID 123456
GITHUB_APP_CLIENT_ID OAuth Client ID Iv1.xxxxxxxxxx
GITHUB_APP_CLIENT_SECRET OAuth Client Secret xxxxxxxxxxxxxxxx
GITHUB_WEBHOOK_SECRET Webhook signature secret openssl rand -hex 32
GITHUB_APP_PRIVATE_KEY RSA Private Key content -----BEGIN RSA...
NEXT_PUBLIC_APP_URL Application base URL http://localhost:3000
NEXT_PUBLIC_GITHUB_APP_NAME GitHub App name commit-habit
CRON_SECRET Secret for cron endpoint openssl rand -hex 32
SESSION_SECRET Session encryption secret openssl rand -hex 32

Optional Variables

Variable Description Example
SMTP_HOST Email SMTP host smtp.gmail.com
SMTP_PORT Email SMTP port 587
SMTP_USER Email username your-email@gmail.com
SMTP_PASS Email app password Gmail App Password
SMTP_FROM From email address CommitHabit <noreply@example.com>
DISCORD_WEBHOOK_URL Discord webhook for analytics Webhook URL
ADMIN_EMAIL Admin notification email admin@example.com

Private Key Formatting

The private key must be converted to a single-line format:

# Linux/macOS
cat private-key.pem | tr '\n' '~' | sed 's/~/\\n/g'

# Or copy directly with newlines in the .env file (inside quotes)

πŸ— Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                           User's Browser                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Landing Page  │──▢│  OAuth Install  │──▢│      Dashboard         β”‚  β”‚
β”‚  β”‚                β”‚   β”‚  (GitHub/Google)β”‚   β”‚  (Manage Repos)        β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                 β”‚
                                 β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        Next.js Application (Vercel)                      β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚                          API Routes                                β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”‚
β”‚  β”‚  β”‚ /api/auth/*   β”‚  β”‚ /api/github/*    β”‚  β”‚ /api/cron/daily    β”‚  β”‚  β”‚
β”‚  β”‚  β”‚ OAuth Flows   β”‚  β”‚ Webhook Handler  β”‚  β”‚ Scheduled Jobs     β”‚  β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”‚
β”‚  β”‚  β”‚ /api/install* β”‚  β”‚ /api/analytics   β”‚  β”‚ /api/health        β”‚  β”‚  β”‚
β”‚  β”‚  β”‚ Manage Repos  β”‚  β”‚ Visitor Tracking β”‚  β”‚ Health Check       β”‚  β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                      β”‚
                  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                  β–Ό                                       β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚     Supabase PostgreSQL        β”‚     β”‚         GitHub API             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚     β”‚  β€’ Check user commits          β”‚
β”‚  β”‚ Users                    β”‚  β”‚     β”‚  β€’ Read README content         β”‚
β”‚  β”‚ Accounts (Multi-Provider)β”‚  β”‚     β”‚  β€’ Create automated commit     β”‚
β”‚  β”‚ Installations            β”‚  β”‚     β”‚  β€’ Manage app installations    β”‚
β”‚  β”‚ ActivityLogs             β”‚  β”‚     β”‚                                β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“ Project Structure

commit-habit/
β”œβ”€β”€ πŸ“‚ prisma/
β”‚   └── schema.prisma               # Database schema (User, Account, Installation, ActivityLog)
β”‚
β”œβ”€β”€ πŸ“‚ public/
β”‚   β”œβ”€β”€ icon.png                    # App favicon
β”‚   β”œβ”€β”€ logo.png                    # App logo
β”‚   β”œβ”€β”€ manifest.json               # PWA manifest
β”‚   β”œβ”€β”€ robots.txt                  # SEO robots file
β”‚   └── sitemap.xml                 # SEO sitemap
β”‚
β”œβ”€β”€ πŸ“‚ src/
β”‚   β”œβ”€β”€ πŸ“‚ app/
β”‚   β”‚   β”œβ”€β”€ πŸ“‚ api/
β”‚   β”‚   β”‚   β”œβ”€β”€ πŸ“‚ auth/
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ callback/       # OAuth callback handler
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ logout/         # Logout handler
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ me/             # Current user endpoint
β”‚   β”‚   β”‚   β”‚   └── google/         # Google OAuth
β”‚   β”‚   β”‚   β”œβ”€β”€ πŸ“‚ cron/
β”‚   β”‚   β”‚   β”‚   └── daily/          # Daily automation cron job
β”‚   β”‚   β”‚   β”œβ”€β”€ πŸ“‚ github/
β”‚   β”‚   β”‚   β”‚   └── webhook/        # GitHub webhook handler
β”‚   β”‚   β”‚   β”œβ”€β”€ πŸ“‚ installations/   # Repository management
β”‚   β”‚   β”‚   β”œβ”€β”€ πŸ“‚ analytics/       # Visitor analytics
β”‚   β”‚   β”‚   └── πŸ“‚ health/          # Health check endpoint
β”‚   β”‚   β”‚
β”‚   β”‚   β”œβ”€β”€ πŸ“‚ dashboard/
β”‚   β”‚   β”‚   β”œβ”€β”€ page.tsx            # Dashboard page
β”‚   β”‚   β”‚   β”œβ”€β”€ dashboard-client.tsx
β”‚   β”‚   β”‚   └── installation-card.tsx
β”‚   β”‚   β”‚
β”‚   β”‚   β”œβ”€β”€ favicon.ico
β”‚   β”‚   β”œβ”€β”€ globals.css             # Global styles & Tailwind
β”‚   β”‚   β”œβ”€β”€ layout.tsx              # Root layout with SEO
β”‚   β”‚   β”œβ”€β”€ page.tsx                # Landing page
β”‚   β”‚   └── providers.tsx           # React providers
β”‚   β”‚
β”‚   β”œβ”€β”€ πŸ“‚ components/
β”‚   β”‚   β”œβ”€β”€ animated-terminal.tsx   # Terminal animation
β”‚   β”‚   β”œβ”€β”€ contribution-demo.tsx   # Contribution graph demo
β”‚   β”‚   β”œβ”€β”€ contribution-graph.tsx  # GitHub contribution graph
β”‚   β”‚   β”œβ”€β”€ hero-comparison.tsx     # Before/after comparison
β”‚   β”‚   β”œβ”€β”€ hero-sequence.tsx       # Hero animation sequence
β”‚   β”‚   β”œβ”€β”€ skeleton.tsx            # Loading skeletons
β”‚   β”‚   β”œβ”€β”€ toast.tsx               # Toast notifications
β”‚   β”‚   β”œβ”€β”€ workflow-animation.tsx  # Workflow demo
β”‚   β”‚   └── ...                     # Other UI components
β”‚   β”‚
β”‚   └── πŸ“‚ lib/
β”‚       β”œβ”€β”€ analytics.ts            # Analytics & Discord webhook
β”‚       β”œβ”€β”€ api-client.ts           # Frontend API client
β”‚       β”œβ”€β”€ auth.ts                 # Session management
β”‚       β”œβ”€β”€ email.ts                # Email service
β”‚       β”œβ”€β”€ errors.ts               # Error handling utilities
β”‚       β”œβ”€β”€ github.ts               # GitHub API utilities
β”‚       β”œβ”€β”€ prisma.ts               # Database client
β”‚       β”œβ”€β”€ sounds.ts               # Sound effects
β”‚       └── utils.ts                # Helper functions
β”‚
β”œβ”€β”€ .env.example                    # Environment variables template
β”œβ”€β”€ next.config.ts                  # Next.js configuration
β”œβ”€β”€ package.json                    # Dependencies
β”œβ”€β”€ tailwind.config.ts              # Tailwind configuration
β”œβ”€β”€ tsconfig.json                   # TypeScript configuration
└── vercel.json                     # Vercel cron configuration

πŸ“‘ API Reference

Authentication Endpoints

Endpoint Method Description
/api/auth/callback GET GitHub OAuth callback handler
/api/auth/google GET Google OAuth initiation
/api/auth/google/callback GET Google OAuth callback
/api/auth/logout POST Logout and clear session
/api/auth/me GET Get current authenticated user

Installation Endpoints

Endpoint Method Description
/api/installations GET List user's connected repositories
/api/installations/[id] PATCH Toggle automation for a repository
/api/installations/[id] DELETE Remove a repository

System Endpoints

Endpoint Method Description
/api/github/webhook POST GitHub webhook receiver
/api/cron/daily GET Daily automation job (protected)
/api/health GET Health check endpoint
/api/analytics POST Visitor analytics

πŸ” Security

Commit Habit implements enterprise-grade security practices:

Aspect Implementation
Authentication GitHub App OAuth (no PAT exposure)
Token Storage Access tokens are never stored β€” generated on-demand via JWT
Private Keys Stored only as environment variables, never in code
Webhooks HMAC-SHA256 signature verification
Sessions HTTP-only secure cookies with encryption
Cron Protection Secret header validation for scheduled jobs
Revocation Users can uninstall anytime from GitHub settings
Data Privacy Minimal data collection, GDPR-friendly

πŸš€ Deployment

Deploy to Vercel (Recommended)

  1. Push your repository to GitHub
  2. Import the project at vercel.com/new
  3. Add all environment variables from .env.example
  4. Deploy β€” Vercel handles the rest!

Configure Cron Job

The vercel.json includes a cron job running daily at 6 AM UTC:

{
  "crons": [
    {
      "path": "/api/cron/daily",
      "schedule": "0 6 * * *"
    }
  ]
}

Post-Deployment Checklist

  • Update GitHub App URLs to your Vercel domain
  • Run database migrations: npx prisma migrate deploy
  • Verify webhook delivery in GitHub App settings
  • Test the OAuth flow end-to-end

❓ FAQ

Why use a GitHub App instead of Personal Access Tokens?
  • More Secure: No long-lived tokens stored in the database
  • User Control: Can be uninstalled anytime from GitHub settings
  • Transparent: Clear permissions displayed during installation
  • Learning Opportunity: Teaches real-world authentication patterns
What exactly does the automation do?

It toggles trailing whitespace in your README.md file. This creates a minimal, non-destructive commit that maintains your activity streak without modifying actual code.

How do I uninstall Commit Habit?
  1. Go to GitHub Settings β†’ Applications
  2. Find "Commit Habit"
  3. Click "Configure" β†’ "Uninstall"

Your data will be automatically cleaned up.

Can I self-host this?

Absolutely! Follow the Installation guide to deploy your own instance. You'll need to create your own GitHub App and database.


🀝 Contributing

Contributions are welcome! Here's how you can help:

Development Workflow

  1. Fork the repository
  2. Clone your fork: git clone https://github.com/YOUR_USERNAME/commit-habit.git
  3. Create a feature branch: git checkout -b feature/amazing-feature
  4. Commit your changes: git commit -m 'Add amazing feature'
  5. Push to the branch: git push origin feature/amazing-feature
  6. Open a Pull Request

Guidelines

  • Follow the existing code style
  • Write meaningful commit messages
  • Add tests for new features
  • Update documentation as needed

πŸ“œ License

This project is licensed under the MIT License β€” see the LICENSE file for details.


⬆ Back to Top


Crafted by Hakkan for lazy devs who want green squares without the grind 🟩


GitHub

About

A free tool that keeps your GitHub graph green on autopilot.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors