Skip to content

jezzdk/pulldog

Repository files navigation

Pulldog 🐕

The faithful watchdog for your pull requests. Live PR dashboard with sound alerts, SLA tracking, and light/dark mode — built with Vue 3, Tailwind CSS, and shadcn/ui.

License Vue TypeScript Tailwind


Features

  • Multi-repo dashboard — monitor open PRs across any number of GitHub repositories in one view
  • Live status — review state (open, approved, changes requested, draft), CI check results, assignees, and reviewers
  • SLA tracking — configurable warning and breach thresholds; rows highlight amber/red as PRs age past them
  • Comment heat — shows comment count per PR with a 🔥 when it crosses a configurable threshold
  • Granular notifications — independently toggle new PR sound, merge sound, merge confetti, and voice announcements
  • Custom per-author sounds — optionally load pr_open.mp3 / pr_merged.mp3 from each author's pulldog-sounds GitHub repo
  • Voice announcements (optional) — OpenAI-powered TTS for new PR and merge events
  • 7-day summary bar — total open PRs, PRs opened, PRs merged, average lead time, and merge rate
  • Light / dark / system theme — persisted to localStorage, respects OS preference in system mode
  • Auto-refresh — configurable poll interval (15s to 30m); detects new and merged PRs and triggers notifications
  • Flexible filtering — by status, SLA state, repo, author, staleness (7d+), free-text search, and title-regex exclusions
  • Cleaner default views — optional "Hide Drafts" and "Hide Merged" behavior when "All" is selected
  • GitHub App OAuth — one-click "Connect with GitHub" via a Cloudflare Worker; no token copy-pasting required
  • Manual PAT fallback — direct token entry remains available when OAuth is not configured

Screenshots

Dark mode Light mode
(add your own) (add your own)

Prerequisites

  • Node.js v18 or later
  • Wrangler CLI for the auth worker (npm i -g wrangler)
  • A Cloudflare account (free tier is sufficient)
  • A GitHub App (see setup below)

GitHub App setup

A single GitHub App works for both development and production — you can register multiple callback URLs.

  1. Go to github.com → Settings → Developer settings → GitHub Apps → New GitHub App
  2. Set the following:
    • Homepage URL: https://pulldog.dev (or your domain)
    • Callback URLs: https://pulldog.dev and http://localhost:5173
    • Check "Request user authorization (OAuth) during installation"
  3. Under Permissions → Repository permissions, set:
    • Metadata: Read-only (required, auto-selected)
    • Pull requests: Read-only
  4. Note the App ID and Client ID, and generate a Client secret

Cloudflare Worker setup

The worker handles the GitHub token exchange server-side so your client secret never touches the browser.

Deploy to production

# Authenticate with Cloudflare
wrangler login

# Set production secrets (uses the GitHub App credentials)
cd worker
wrangler secret put GITHUB_CLIENT_ID
wrangler secret put GITHUB_CLIENT_SECRET

# Deploy
wrangler deploy

This gives you a worker URL like https://pulldog-auth.<your-subdomain>.workers.dev.

Run locally

# Copy the example and fill in your GitHub App credentials
cp worker/.dev.vars.example worker/.dev.vars

# Start the local worker (runs at http://localhost:8787)
cd worker && wrangler dev

Getting started

# 1. Clone the repository
git clone https://github.com/YOUR_USERNAME/pulldog.git
cd pulldog

# 2. Install dependencies
npm install

# 3. Configure environment variables
cp .env.example .env
# Edit .env and fill in VITE_GITHUB_CLIENT_ID (GitHub App client ID) and VITE_GITHUB_WORKER_URL

# 4. Start the local worker in a separate terminal
cp worker/.dev.vars.example worker/.dev.vars
# Edit worker/.dev.vars with your GitHub App credentials
cd worker && wrangler dev

# 5. Start the development server
npm run dev

Open http://localhost:5173 and click Connect with GitHub.

Configuration

Frontend — .env

Copy .env.example to get started:

# GitHub App Client ID
VITE_GITHUB_CLIENT_ID=your_client_id

# URL of your deployed Cloudflare Worker
VITE_GITHUB_WORKER_URL=https://pulldog-auth.<your-subdomain>.workers.dev

# Override the OAuth redirect URI (defaults to window.location.origin)
VITE_GITHUB_REDIRECT_URI=

# Optional: bake a token directly into the bundle (skips the OAuth flow)
VITE_GITHUB_TOKEN=

# Hours until a PR row turns amber (SLA warning)
VITE_SLA_WARNING_HOURS=24

# Hours until a PR row turns red (SLA breach)
VITE_SLA_BREACH_HOURS=72

# Show 🔥 next to comment count when it reaches this number
VITE_COMMENT_FIRE_THRESHOLD=10

# Poll interval in seconds (how often to refresh PRs, default: 60)
VITE_POLL_INTERVAL_S=60

# Show sound test buttons in the top bar (true | false)
VITE_TEST_MODE=false

# Optional: OpenAI API key for voice announcements
VITE_OPENAI_API_KEY=

For local development, override VITE_GITHUB_WORKER_URL to point at the local worker:

# .env.local (git-ignored, overrides .env in dev)
VITE_GITHUB_CLIENT_ID=your_client_id
VITE_GITHUB_WORKER_URL=http://localhost:8787

Note: Vite bakes VITE_* variables into the bundle at build time. Restart npm run dev after any change.

Worker — worker/.dev.vars

Copy worker/.dev.vars.example and fill in your GitHub App credentials:

GITHUB_CLIENT_ID=your_dev_client_id
GITHUB_CLIENT_SECRET=your_dev_client_secret

Production secrets are stored in Cloudflare (via wrangler secret put) and never committed.

Custom sounds (quick guide)

Pulldog can play per-author custom sounds by loading audio files from GitHub.
When enabled, it looks for files in:

  • https://raw.githubusercontent.com/<github-username>/pulldog-sounds/main/pr_open.mp3
  • https://raw.githubusercontent.com/<github-username>/pulldog-sounds/main/pr_merged.mp3

1) Create your sound repo

For each author you want custom sounds for, create a public repo named pulldog-sounds under that same GitHub account, then add:

  • pr_open.mp3 (played on new PR)
  • pr_merged.mp3 (played on merge)

2) Enable in Pulldog

Open Settings → Notifications and turn on:

  • New PR → Custom sound
  • Merge → Custom sound

3) Test

Set VITE_TEST_MODE=true in .env, restart npm run dev, and use the top test bar to trigger sample events.

If a custom file is missing or cannot be loaded, Pulldog automatically falls back to the default built-in sound.

Project structure

pulldog/
├── worker/
│   ├── index.js             # Cloudflare Worker — GitHub token exchange
│   ├── wrangler.toml        # Worker-only Cloudflare config
│   └── .dev.vars.example    # Worker local secrets template
├── src/
│   ├── components/
│   │   ├── ui/              # shadcn-style primitive components
│   │   ├── SetupScreen.vue  # OAuth + manual token onboarding flow
│   │   ├── SettingsDialog.vue
│   │   ├── SlaLegend.vue
│   │   ├── SummaryBar.vue
│   │   └── Topbar.vue
│   ├── composables/
│   │   ├── useAudio.ts      # Web Audio API sounds
│   │   ├── useGithub.ts     # GitHub REST API calls
│   │   ├── useGithubOAuth.ts  # GitHub OAuth flow + callback handling
│   │   ├── usePersistedRepos.ts
│   │   ├── usePersistedToken.ts
│   │   ├── useSla.ts        # SLA threshold logic
│   │   └── useTheme.ts      # Light/dark/system theme
│   ├── types.ts
│   ├── App.vue
│   ├── base.css
│   ├── main.ts
│   └── vite-env.d.ts
├── .env.example             # Frontend env template
├── vite.config.ts
└── package.json

Available scripts

Command Description
npm run dev Start development server with hot-reload
npm run build Build for production (outputs to dist/)
npm run preview Preview the production build locally
npm run type-check Run TypeScript type checking via vue-tsc
cd worker && wrangler dev Run the auth worker locally on port 8787
cd worker && wrangler deploy Deploy the worker to Cloudflare

Building for production

npm run build

The dist/ directory is a fully static build. Deploy it to Cloudflare Pages, Vercel, Netlify, or any static host.

Contributing

Contributions are welcome! Here's how to get involved:

  1. Fork the repository and create a branch from main
    git checkout -b feat/your-feature-name
  2. Make your changes and ensure the project builds and type-checks cleanly
    npm run type-check && npm run build
  3. Commit using a descriptive message
    git commit -m "feat: add X"
  4. Push your branch and open a Pull Request against main

Reporting issues

Open an issue and include:

  • What you expected to happen
  • What actually happened
  • Steps to reproduce
  • Browser and Node.js version

License

Distributed under the MIT License. See LICENSE for full text.

Kiosk / TV mode

Pulldog has a built-in fullscreen toggle (⛶ button in the top-right corner) that uses the browser Fullscreen API to hide all browser chrome — address bar, tabs, bookmarks — leaving only the dashboard.

Press Esc or click the button again to exit.

For a permanent TV kiosk setup, launch Chrome or Chromium directly into kiosk mode:

# Linux / Raspberry Pi
chromium-browser --kiosk --noerrdialogs --disable-infobars https://pulldog.dev

# macOS
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
  --kiosk --noerrdialogs https://pulldog.dev

# Windows
"C:\Program Files\Google\Chrome\Application\chrome.exe" ^
  --kiosk --noerrdialogs https://pulldog.dev

Set VITE_GITHUB_TOKEN in .env before building to pre-seed a token so the dashboard connects automatically on boot without any interaction.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors