DEV Community

Wilson Xu
Wilson Xu

Posted on

How I Built an AI-Powered Bounty Hunting System That Finds and Solves GitHub Issues Automatically

Open source bounties are real money. Platforms like Algora, Expensify's Help Wanted program, and dozens of smaller bounty boards collectively post hundreds of issues per week with cash rewards attached — typically $250 to $5,000 per issue. The problem is not supply. The problem is that by the time you manually find an interesting bounty, read the issue, clone the repo, understand the codebase, and write a fix, someone else has already submitted a pull request.

So I built a system that automates the entire pipeline: monitoring bounty sources in real time, filtering for issues I can actually solve, analyzing the codebases, and generating candidate fixes. The monitor runs every 10 minutes on a cron job. When it finds something worth pursuing, it pings my phone. When I sit down to work, the solution is often already half-written.

This article walks through the architecture, the actual code, the real bounties I have pursued, and honest numbers on what this approach earns.

Prerequisites

To follow along, you will need:

  • Node.js 18+ (for built-in fetch support)
  • GitHub CLI (gh) installed and authenticated — run gh auth status to verify
  • A macOS, Linux, or WSL environment for cron scheduling
  • Basic familiarity with the GitHub API and JavaScript/TypeScript

The Bounty Landscape in 2026

Before diving into code, it helps to understand where the money comes from.

Algora is the largest bounty aggregator. Projects post issues with explicit dollar amounts from $200 to $5,000. On any given day, 10-15 open bounties above $200 exist in TypeScript, JavaScript, and Python alone.

Expensify runs one of the most consistent programs. Nearly every "Help Wanted" issue in Expensify/App carries a $250 bounty, paid through Upwork after merge. The catch: a Contributor+ reviewer must approve your proposal before you submit a PR.

AsyncAPI, Supabase, Cal.com, and others run formal bounty programs. $100-$500 per issue is typical for mid-complexity bugs.

GitHub Issues with label:bounty is the long tail. Individual maintainers attach bounties across thousands of repositories. Harder to find, but less competitive.

The total addressable market is meaningful side income if you can reduce time per bounty from 4-8 hours of manual work to 30-60 minutes of review and refinement.

Architecture: Monitor, Filter, Solve

The system has three stages:

┌─────────────────┐     ┌──────────────────┐     ┌──────────────────┐
│  Bounty Monitor  │────►│  Filter + Score  │────►│   Solver Agent   │
│  (cron, 10 min)  │     │  (lang, amount)  │     │  (AI + codebase) │
└─────────────────┘     └──────────────────┘     └──────────────────┘
        │                        │                        │
   Algora scraper          $200+ minimum            Clone + analyze
   GitHub API search       TS/JS/Python only        Generate patch
   Deduplication           Skip aggregates          Write tests
        │                        │                        │
        ▼                        ▼                        ▼
   bounty-log.json        macOS notification        solution/ dir
Enter fullscreen mode Exit fullscreen mode

Stage 1: The Monitor scrapes Algora's HTML and queries the GitHub Search API for issues labeled bounty created in the last 2 hours. It runs on a 10-minute cron schedule.

Stage 2: Filtering eliminates bounties below $200, bounties in languages I do not work with (Rust, Go, Scala), and duplicate entries. New bounties trigger a macOS notification with the Glass sound — impossible to miss.

Stage 3: The Solver is a semi-automated step where I point an AI coding agent at the issue. It clones the repo, reads the issue, traces the relevant code paths, and generates a patch with tests. I review, refine, and submit.

Building the Bounty Monitor

The monitor is a single Node.js file with zero external dependencies. No npm install, no build step. It uses Node's built-in fetch and child_process. This matters because you want a monitor that runs reliably on a cron job for weeks without dependency rot.

Here is the configuration that drives everything:

const MIN_BOUNTY_USD = 200;
const ALGORA_URL = "https://algora.io/bounties";
const LOG_PATH = path.join(__dirname, "bounty-log.json");
const RELEVANT_LANGUAGES = new Set([
  "typescript", "javascript", "python",
  "ts", "js", "py", "node", "nodejs",
  "react", "next", "nextjs", "vue", "nuxt",
  "svelte", "deno", "bun", "django", "flask", "fastapi",
]);
const MAX_BOUNTY_AGE_HOURS = 2;
Enter fullscreen mode Exit fullscreen mode

Scraping Algora Without a DOM Parser

Algora renders bounty cards as server-side HTML. Without jsdom or cheerio (remember, zero dependencies), I parse the HTML with regex. This sounds terrible and it mostly is, but for a monitoring script that just needs dollar amounts and links, it works.

The parser runs two strategies. Strategy 1 looks for HTML chunks that contain both an anchor tag and a dollar amount nearby:

const chunkRegex =
  /(<a[^>]*href="([^"]*)"[^>]*>[\s\S]*?<\/a>[\s\S]{0,500}?\$[\d,]+|(?:\$[\d,]+)[\s\S]{0,500}?<a[^>]*href="([^"]*)"[^>]*>)/gi;
Enter fullscreen mode Exit fullscreen mode

Strategy 2 is a broader sweep that finds any dollar amount on the page and grabs 300 characters of surrounding context:

const broadRegex = /.{0,300}\$\s?[\d,]+(?:\.\d{2})?.{0,300}/gi;
Enter fullscreen mode Exit fullscreen mode

Querying GitHub's Search API

For the GitHub source, the monitor uses the gh CLI for authenticated requests (higher rate limits) with a fallback to unauthenticated fetch:

const since = new Date(
  Date.now() - MAX_BOUNTY_AGE_HOURS * 60 * 60 * 1000
).toISOString();

const query = `label:bounty created:>=${since}`;

let result;
try {
  result = execSync(
    `gh api "search/issues?q=${encodedQuery}&sort=created&order=desc&per_page=100"`,
    { encoding: "utf-8", timeout: 30000 }
  );
} catch {
  // Fallback to unauthenticated API
  const resp = await fetch(
    `https://api.github.com/search/issues?q=${encodedQuery}&sort=created&order=desc&per_page=100`
  );
  result = await resp.text();
}
Enter fullscreen mode Exit fullscreen mode

The interesting part is bounty amount parsing. Bounty amounts hide in different places: the issue title ("[$500] Fix the parser"), the body ("This issue has a $500 bounty"), or labels (bounty-500, reward:500, $500). The parser checks all three:

for (const label of issue.labels || []) {
  const labelAmount = parseDollarAmount(label.name);
  if (labelAmount && (!amount || labelAmount > amount)) {
    amount = labelAmount;
  }
  const numMatch = label.name.match(
    /(?:bounty|reward)[\/:\-_]?\s?(\d+)/i
  );
  if (numMatch) {
    const parsed = parseInt(numMatch[1], 10);
    if (parsed >= MIN_BOUNTY_USD && (!amount || parsed > amount)) {
      amount = parsed;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Notifications and Persistence

New bounties trigger a macOS notification using osascript:

function sendNotification(title, message) {
  try {
    execSync(
      `osascript -e 'display notification "${escapedMsg}" with title "${escapedTitle}" sound name "Glass"'`
    );
  } catch {
    // Notification failure is non-fatal
  }
}
Enter fullscreen mode Exit fullscreen mode

All seen bounties are persisted to bounty-log.json so re-runs do not spam notifications for the same issue. Entries older than 7 days are automatically purged.

The Solver Loop: From Issue to Patch

When a bounty notification fires, I run a coding agent pointed at the issue. The process is:

  1. Clone the repository (or pull latest if already cloned)
  2. Read the issue thoroughly, including all comments
  3. Trace the code path mentioned in the issue
  4. Generate a minimal fix
  5. Write tests that cover the fix
  6. Package everything as a patch file

Example 1: Expensify/App #85632 ($250)

The issue: "We'd hate to see you go!" reason field is not mandatory when closing an account. Users could close their Expensify account without providing any feedback in the reason field.

The root cause took 3 minutes to find. In CloseAccountPage.tsx, the form validation function only listed phoneOrEmail as required:

const errors = getFieldRequiredErrors(values, ['phoneOrEmail'], translate);
Enter fullscreen mode Exit fullscreen mode

The fix was one line:

const errors = getFieldRequiredErrors(values, ['reasonForLeaving', 'phoneOrEmail'], translate);
Enter fullscreen mode Exit fullscreen mode

This is the sweet spot for automated bounty hunting: issues where the bug is straightforward validation logic, the fix is small, but you need to navigate a large codebase to find the right file.

Example 2: AsyncAPI/CLI #2027

The issue: CLI hangs indefinitely when --registry-url points to an unreachable host. The fix added an AbortController with a 5-second timeout, switched from GET to HEAD for lightweight validation, and provided specific error messages for different failure modes:

const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), REGISTRY_TIMEOUT_MS);

try {
  const response = await fetch(registryUrl, {
    method: 'HEAD',
    signal: controller.signal,
  });
  // ... auth checking
} catch (err: unknown) {
  if (err instanceof Error && err.name === 'AbortError') {
    throw new Error(
      `Registry URL '${registryUrl}' is unreachable (timed out after ${REGISTRY_TIMEOUT_MS / 1000}s).`
    );
  }
  throw new Error(`Can't reach registry at '${registryUrl}'.`);
} finally {
  clearTimeout(timeoutId);
}
Enter fullscreen mode Exit fullscreen mode

Running on a Schedule

The monitor runs as a cron job every 10 minutes:

*/10 * * * * /usr/local/bin/node /path/to/bounty-monitor.js >> /path/to/bounty-monitor.log 2>&1
Enter fullscreen mode Exit fullscreen mode

A typical run takes 2-3 seconds. Both sources are fetched in parallel using Promise.all, so total runtime is bounded by the slower source (usually Algora at ~2 seconds).

Results and Lessons Learned

Speed is everything. On competitive programs like Expensify, bounties get proposals within hours of posting. Having a 10-minute monitoring loop means I see issues before most people browsing GitHub.

One-line fixes pay the same as hundred-line fixes. The Expensify validation fix was literally one line of code for $250. The value is in finding the right file in a massive codebase.

Most bounties are not worth pursuing. Of the 11 bounties my monitor found in a single scan, only 2-3 were realistic targets. The $5,000 ZIO bounty is Scala. The $4,000 Archestra bounty requires deep domain knowledge.

Tests are your competitive advantage. Most bounty hunters submit minimal fixes. Including comprehensive tests dramatically increases your chances of getting merged.

The Economics: Honest Numbers

  • Time to build: ~10 hours
  • Time per bounty: 30-60 minutes for straightforward issues
  • Hit rate: ~25% of submissions get merged
  • Realistic monthly earnings: $500-$1,500 at 5-10 hours/week
  • Effective hourly rate: $25-$50

The value proposition is not the hourly rate — it is that the monitoring runs while you sleep and every merged PR builds your open source profile.

Quick Start

# 1. Create the project directory
mkdir bounty-monitor && cd bounty-monitor

# 2. Create bounty-monitor.js with the code from this article

# 3. Test it manually
node bounty-monitor.js

# 4. Add to cron (runs every 10 minutes)
crontab -e
# */10 * * * * /usr/local/bin/node /path/to/bounty-monitor.js >> /path/to/bounty-monitor.log 2>&1
Enter fullscreen mode Exit fullscreen mode

Conclusion

The bounty monitor is under 500 lines of zero-dependency Node.js. No infrastructure, no servers, no databases. It runs on a laptop cron job and pings you when money appears.

The combination of automated monitoring and AI-assisted solving compresses a 4-8 hour manual workflow into 30-60 minutes. At $500-$1,500 per month of side income while building your open source profile, the return on a 10-hour setup investment is hard to beat.


If you found this useful, check out some of my other developer tools:

  • websnap-reader — Convert any webpage to clean Markdown, perfect for LLM/AI pipelines
  • gitpulse — GitHub activity analytics from the command line
  • depcheck-ai — AI-powered dependency vulnerability scanner
  • ghbounty — Find and track GitHub bounties from your terminal
  • repo-readme-gen — Auto-generate professional README files for any repo

Find me on GitHub: @chengyixu

Top comments (0)