Expert system that maximizes Expected Profit per Human Hour (EPHH) from freelance technical work — using Claude Code as the execution engine.
EPHH = P(win) × P(deliver) × net_payout / hours_predicted
BountyBrain scouts GitHub bounties and Freelancer.com, scores every opportunity against this formula, and returns a ranked table. You work on the task with the highest expected return — not the loudest one.
Freelance developer platforms have a structural problem: automated bots bid within minutes of posting, saturating most opportunities before a human can evaluate them. BountyBrain solves this in two ways:
- Speed: collect, score, and rank 100+ opportunities in under 2 minutes
- Signal: hard-filter saturated bounties (too many open PRs,
/attemptbot comments, already-merged solutions) before they waste your time
The score command lets you paste any job description from any platform and get an instant EPHH analysis.
git clone https://github.com/giagnacovoluca-ctrl/bountybrain
cd bountybrain
pip install -e .
cp .env.example .env # add GITHUB_TOKEN + GROQ_API_KEY (free)
python -m bountybrain.main runRequirements: Python 3.11+, a GitHub token (read:public_repo), optionally a Groq key (free tier).
# Collect + rank all opportunities
python -m bountybrain.main run
# Score any job by pasting its description
python -m bountybrain.main score "Fix race condition in FastAPI webhook..." --budget 200
# Set up Claude Code workspace for a specific bounty
python -m bountybrain.main setup github_4735571260
# Log outcome — feeds the learning engine
python -m bountybrain.main log-outcome github_4735571260 \
--status merged --payout 150 --hours 2.0
# Live dashboard
python -m bountybrain.main dashboard # http://localhost:8080BountyCollector
├── GitHubAdapter GitHub Search API — bounties (fresh + stale abandoned)
└── FreelancerAdapter Freelancer.com public API — fixed-price jobs < 6h old
FeatureExtractor GitHub API only, zero LLM calls
├── repo quality stars, CI, Docker, tests, contributor count
├── issue clarity repro steps, acceptance criteria, body length
└── competition open PRs on issue, /attempt comments, merged PRs
RankingEngine hard filters + EPHH scoring
├── Phase 0 rule-based (always active)
├── Phase 1 Ridge regression (activates at 80 outcomes)
└── Phase 2 Gradient Boosting (activates at 300 outcomes)
QualitativeAnalyzer Groq llama-3.3-70b (free) → Anthropic → skip
KnowledgeBase JSONL append-only (bounties / outcomes / patterns)
LearningEngine tracks outcomes, triggers phase upgrades automatically
ContextBuilder generates CLAUDE.md + TASK.md + FIRST_STEPS.md
EnvironmentBuilder git clone + Python/Node/Rust/Go/Docker setup
The system runs without LLM calls until the top 10 candidates are identified — keeping costs near zero for the scouting phase.
| Signal | Threshold | Meaning |
|---|---|---|
has_merged_pr |
any | bounty already solved |
n_attempt_comments |
> 5 | bot farm detected |
n_issue_prs_open |
> 2 | competitors already working on it |
n_issue_prs_closed |
> 4 | issue blocked or re-attempted too many times |
Freelancer bid_count |
> 10 | already saturated |
| Freelancer age | > 6h | bidding window effectively closed |
Competition signals use a single GitHub Search API call per issue — batching open/closed/merged detection into one request to stay within the 30 req/min rate limit.
# GitHub bounty
P(win) = f(maintainer_response_p50, stale_PR_count, contributing_guide)
P(deliver) = f(task_type, has_tests, has_repro, has_CI, body_length)
net_payout = payout_usd
# Freelancer.com
P(win) = decays with age: < 1h → 65% < 3h → 50% < 6h → 35% > 12h → 5%
P(deliver) = f(task_type, spec_clarity, experience_level)
net_payout = payout_usd × 0.80 # platform 20% fee
EPHH = P(win) × P(deliver) × net_payout / human_hours_predictedEvery outcome logged via log-outcome is stored in outcomes.jsonl. The learning engine monitors the dataset size and upgrades the scorer automatically:
| Outcomes | Active scorer |
|---|---|
| 0 – 79 | Phase 0: rule-based |
| 80 – 299 | Phase 1: Ridge regression on 13 numerical features |
| 300+ | Phase 2: Gradient Boosting |
All three scorers share the same interface — no code changes on upgrade.
| Layer | Technology |
|---|---|
| Language | Python 3.11+ |
| Data sources | GitHub REST API, Freelancer.com public API |
| ML | scikit-learn — Ridge, GradientBoosting |
| Similarity search | TF-IDF cosine (→ sentence-transformers at Phase 2) |
| Storage | JSONL append-only, SQLite |
| API server | FastAPI + uvicorn |
| LLM | Groq free tier (primary) · Anthropic Claude Haiku (fallback) |
| CLI | Typer + Rich |
| Validation | Pydantic v2 |
| Tests | pytest-asyncio · 76/76 passing |
All parameters live in config/default.yaml — no hardcoded values in source code.
ranking:
phase: 0 # 0=rules · 1=Ridge · 2=GBM (auto-upgraded)
min_ephh_threshold: 10.0 # $/h minimum to appear in results
min_payout_usd: 50
max_issue_age_days: 180 # include stale abandoned bounties
max_attempt_comments: 5 # bot-farm detection
max_issue_prs_open: 2 # active-competition detection
upwork_max_age_hours: 48
scout:
platforms:
github:
search_queries:
- "label:bounty state:open language:python"
- "label:bounty state:open language:python created:<2026-05-26"
upwork: # actually Freelancer.com
max_bid_count: 10
max_age_hours: 6src/bountybrain/
├── core/ models.py · interfaces.py · exceptions.py
├── scout/ github_adapter.py · upwork_adapter.py · collector.py
├── extractor/ feature_extractor.py
├── analyzer/ qualitative_analyzer.py
├── ranking/ ranking_engine.py · scorers/{phase0,phase1,phase2}_scorer.py
├── knowledge/ knowledge_base.py · similarity_engine.py
├── learning/ learning_engine.py
├── environment/ environment_builder.py
├── context/ context_builder.py · templates/
├── dashboard/ app.py (FastAPI)
└── main.py CLI entrypoint (run · score · setup · log-outcome · dashboard)
tests/
├── unit/ 12 test files · 67 unit tests
└── integration/ pipeline end-to-end · dashboard smoke tests
- Phase 1 scorer training loop (feature retrieval by bounty_id)
- Sentence-transformers in SimilarityEngine (replace TF-IDF)
- GitHub Actions — daily scout run, results to Telegram
- Auto-PR submission after Claude Code solve
- Gitcoin adapter (web3 bounties)
- Per-maintainer merge rate profiling
- Multi-user SaaS mode
MIT