feat: implement hive github repo and discord as a connected game
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
name: Integration Bounty
|
||||
description: A bounty task for the integration contribution program
|
||||
title: "[Bounty]: "
|
||||
labels: []
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
## Integration Bounty
|
||||
|
||||
This issue is part of the [Integration Bounty Program](../../docs/integration-bounty-program.md).
|
||||
**Claim this bounty** by commenting below — a maintainer will assign you within 24 hours.
|
||||
|
||||
- type: dropdown
|
||||
id: bounty-type
|
||||
attributes:
|
||||
label: Bounty Type
|
||||
options:
|
||||
- "Smoke Test (10 pts)"
|
||||
- "Agent Test Report (30 pts)"
|
||||
- "Edge Case Report (15 pts)"
|
||||
- "Write README (20 pts)"
|
||||
- "Add Health Checker (25 pts)"
|
||||
- "Add Health Check Endpoint (10 pts)"
|
||||
- "Bug Fix (40 pts)"
|
||||
- "Complete Promotion Checklist (50 pts)"
|
||||
- "New Integration (75 pts)"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: difficulty
|
||||
attributes:
|
||||
label: Difficulty
|
||||
options:
|
||||
- Easy
|
||||
- Medium
|
||||
- Hard
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: tool-name
|
||||
attributes:
|
||||
label: Tool Name
|
||||
description: The integration this bounty targets (e.g., `airtable`, `salesforce`)
|
||||
placeholder: e.g., airtable
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: What needs to be done to complete this bounty.
|
||||
placeholder: |
|
||||
Describe the specific task, including:
|
||||
- What the contributor needs to do
|
||||
- Links to relevant files in the repo
|
||||
- Any setup requirements (API keys, accounts, etc.)
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: acceptance-criteria
|
||||
attributes:
|
||||
label: Acceptance Criteria
|
||||
description: What "done" looks like. The PR or report must meet all criteria.
|
||||
placeholder: |
|
||||
- [ ] Criterion 1
|
||||
- [ ] Criterion 2
|
||||
- [ ] CI passes
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: relevant-files
|
||||
attributes:
|
||||
label: Relevant Files
|
||||
description: Links to tool directory, credential spec, health check file, etc.
|
||||
placeholder: |
|
||||
- Tool: `tools/src/aden_tools/tools/{tool_name}/`
|
||||
- Credential spec: `tools/src/aden_tools/credentials/{category}.py`
|
||||
- Health checks: `tools/src/aden_tools/credentials/health_check.py`
|
||||
|
||||
- type: textarea
|
||||
id: resources
|
||||
attributes:
|
||||
label: Resources
|
||||
description: Links to API docs, examples, or guides that will help the contributor.
|
||||
placeholder: |
|
||||
- [Building Tools Guide](../../tools/BUILDING_TOOLS.md)
|
||||
- [Tool README Template](../../docs/templates/tool-readme-template.md)
|
||||
- API docs: https://...
|
||||
@@ -0,0 +1,37 @@
|
||||
name: Bounty completed
|
||||
description: Awards points and notifies Discord when a bounty PR is merged
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [closed]
|
||||
|
||||
jobs:
|
||||
bounty-notify:
|
||||
if: >
|
||||
github.event.pull_request.merged == true &&
|
||||
contains(join(github.event.pull_request.labels.*.name, ','), 'bounty:')
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Award XP and notify Discord
|
||||
run: bun run scripts/bounty-tracker.ts notify
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }}
|
||||
GITHUB_REPOSITORY_NAME: ${{ github.event.repository.name }}
|
||||
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_BOUNTY_WEBHOOK_URL }}
|
||||
LURKR_API_KEY: ${{ secrets.LURKR_API_KEY }}
|
||||
LURKR_GUILD_ID: ${{ secrets.LURKR_GUILD_ID }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
@@ -0,0 +1,40 @@
|
||||
name: Weekly bounty leaderboard
|
||||
description: Posts the integration bounty leaderboard to Discord every Monday
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Every Monday at 9:00 UTC
|
||||
- cron: "0 9 * * 1"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
since_date:
|
||||
description: "Only count PRs merged after this date (YYYY-MM-DD). Leave empty for all-time."
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
leaderboard:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- name: Post leaderboard to Discord
|
||||
run: bun run scripts/bounty-tracker.ts leaderboard
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }}
|
||||
GITHUB_REPOSITORY_NAME: ${{ github.event.repository.name }}
|
||||
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_BOUNTY_WEBHOOK_URL }}
|
||||
LURKR_API_KEY: ${{ secrets.LURKR_API_KEY }}
|
||||
LURKR_GUILD_ID: ${{ secrets.LURKR_GUILD_ID }}
|
||||
SINCE_DATE: ${{ github.event.inputs.since_date || '' }}
|
||||
@@ -0,0 +1,24 @@
|
||||
# Identity mapping: GitHub username -> Discord ID
|
||||
#
|
||||
# This file links GitHub accounts to Discord accounts for the
|
||||
# Integration Bounty Program. When a bounty PR is merged, the
|
||||
# GitHub Action uses this file to ping the contributor on Discord.
|
||||
#
|
||||
# HOW TO ADD YOURSELF:
|
||||
# 1. Fork this repo
|
||||
# 2. Add your entry below (keep alphabetical order)
|
||||
# 3. Submit a PR with title: "docs: link @your-github to Discord"
|
||||
#
|
||||
# To find your Discord ID:
|
||||
# 1. Open Discord Settings > Advanced > Enable Developer Mode
|
||||
# 2. Right-click your name > Copy User ID
|
||||
#
|
||||
# Format:
|
||||
# - github: your-github-username
|
||||
# discord: "your-discord-id" # quotes required (it's a number)
|
||||
# name: Your Display Name # optional
|
||||
|
||||
contributors:
|
||||
# - github: example-user
|
||||
# discord: "123456789012345678"
|
||||
# name: Example User
|
||||
@@ -0,0 +1,255 @@
|
||||
# Contributor Guide — Integration Bounty Program
|
||||
|
||||
Welcome. This is a program where you earn XP, Discord roles, and eventually real money by testing and building integrations for the Aden agent framework.
|
||||
|
||||
## How It Works
|
||||
|
||||
1. You pick a bounty from the [GitHub issues board](https://github.com/adenhq/hive/issues?q=is%3Aissue+is%3Aopen+label%3A%22bounty%3A*%22)
|
||||
2. You claim it by commenting on the issue
|
||||
3. You do the work and submit a PR (or test report)
|
||||
4. A maintainer reviews and merges
|
||||
5. You automatically get XP in Discord via Lurkr, and your level goes up
|
||||
6. At certain levels, you unlock roles. At the top tier, you unlock paid bounties.
|
||||
|
||||
## Getting Started (10 min)
|
||||
|
||||
### 1. Link your GitHub and Discord
|
||||
|
||||
Fork this repo and add yourself to `contributors.yml`:
|
||||
|
||||
```yaml
|
||||
contributors:
|
||||
# ... existing entries
|
||||
- github: your-github-username
|
||||
discord: "your-discord-id"
|
||||
name: Your Name
|
||||
```
|
||||
|
||||
To find your Discord ID:
|
||||
1. Open Discord Settings > Advanced > Enable **Developer Mode**
|
||||
2. Right-click your name in any channel > **Copy User ID**
|
||||
|
||||
Submit this as a PR with title: `docs: link @your-github to Discord`
|
||||
|
||||
**Why this matters:** Without this link, you'll still get points tracked, but Lurkr can't push XP to your Discord account and you won't get role upgrades or pings.
|
||||
|
||||
### 2. Join the Discord channels
|
||||
|
||||
- `#integrations-announcements` — Bounty postings, leaderboard, promotions
|
||||
- `#integrations-testing` — Coordinate with other testers
|
||||
- `#integrations-help` — Ask questions about tools, credentials, setup
|
||||
- `#integration-showcase` — Show off what you built
|
||||
|
||||
### 3. Pick your first bounty
|
||||
|
||||
Filter GitHub issues by label:
|
||||
- [`bounty:docs`](https://github.com/adenhq/hive/issues?q=is%3Aissue+is%3Aopen+label%3A%22bounty%3Adocs%22) — Write a README for a tool (20 pts, easiest)
|
||||
- [`bounty:smoke-test`](https://github.com/adenhq/hive/issues?q=is%3Aissue+is%3Aopen+label%3A%22bounty%3Asmoke-test%22) — Test a tool with a real API key (10 pts)
|
||||
- [`difficulty:easy`](https://github.com/adenhq/hive/issues?q=is%3Aissue+is%3Aopen+label%3A%22difficulty%3Aeasy%22) — All easy bounties
|
||||
|
||||
Comment on the issue: "I'd like to work on this" and wait for a maintainer to assign you (usually within 24 hours).
|
||||
|
||||
## Tiers
|
||||
|
||||
| Tier | How to Reach | What You Get |
|
||||
|------|-------------|--------------|
|
||||
| **Agent Builder** | ~500 XP (Lurkr level 5) | Discord role, bounty board access |
|
||||
| **Open Source Contributor** | ~2,000 XP (Lurkr level 15) | Discord role, name in CONTRIBUTORS.md and tool READMEs |
|
||||
| **Core Contributor** | Maintainer nomination | Dollar values on bounties, paid per completion |
|
||||
|
||||
Lurkr auto-assigns the first two roles when you hit the level. Core Contributor requires sustained, high-quality contributions and a maintainer vouching for you.
|
||||
|
||||
### How XP Adds Up
|
||||
|
||||
You earn XP from two sources:
|
||||
|
||||
| Source | How |
|
||||
|--------|-----|
|
||||
| **GitHub bounties** | Merge a PR with a `bounty:*` label — auto-pushed to Lurkr |
|
||||
| **Discord activity** | Messages in `#integrations-*` channels, helping others, voice chat |
|
||||
|
||||
Both feed into the same Lurkr level. Helping people in Discord AND doing bounties levels you up faster than either alone.
|
||||
|
||||
## Bounty Types
|
||||
|
||||
### Smoke Test (10 pts)
|
||||
|
||||
**What:** Run an unverified tool with a real API key and report if it works.
|
||||
|
||||
**How:**
|
||||
1. Pick a tool from the bounty board
|
||||
2. Get an API key for that service (the bounty issue links to the help URL)
|
||||
3. Set the environment variable: `export TOOL_API_KEY=your-key`
|
||||
4. Run the tool functions and note what happens
|
||||
5. Comment on the bounty issue with your results: pass/fail, any errors, logs
|
||||
|
||||
**Difficulty:** Easy. You don't need to write code, just test and report.
|
||||
|
||||
### Agent Test Report (30 pts)
|
||||
|
||||
**What:** Build a real agent that uses an unverified tool and document the experience.
|
||||
|
||||
**How:**
|
||||
1. Pick a tool from the bounty board
|
||||
2. Build a simple agent that uses the tool (see [Building Agents Guide](../tools/BUILDING_TOOLS.md))
|
||||
3. Run the agent with a real task
|
||||
4. Fill out the [test report template](templates/agent-test-report-template.md)
|
||||
5. Submit the report as a comment on the bounty issue, or as a file in a PR
|
||||
|
||||
**What to include:** Environment, credential setup, which functions you tested, what worked, what broke, edge cases found, and logs or session ID.
|
||||
|
||||
**Difficulty:** Medium. Requires an API key and some familiarity with the framework.
|
||||
|
||||
### Write README (20 pts)
|
||||
|
||||
**What:** Write documentation for a tool that's missing its README.
|
||||
|
||||
**How:**
|
||||
1. Pick a tool from the bounty board
|
||||
2. Read the tool's source code in `tools/src/aden_tools/tools/{tool_name}/`
|
||||
3. Read the credential spec in `tools/src/aden_tools/credentials/`
|
||||
4. Fill in the [tool README template](templates/tool-readme-template.md)
|
||||
5. Submit a PR adding `README.md` to the tool directory
|
||||
|
||||
**Quality bar:** Function names must match the actual code. Setup instructions must be accurate. API URLs must be real.
|
||||
|
||||
**Difficulty:** Easy. Good first bounty — you learn the codebase by reading and documenting it.
|
||||
|
||||
### Add Health Checker (25 pts)
|
||||
|
||||
**What:** Implement a credential health check so the system can validate API keys at startup.
|
||||
|
||||
**How:**
|
||||
1. Pick a tool from the bounty board
|
||||
2. Find a lightweight API endpoint that validates the credential (GET, no writes, no charges)
|
||||
3. Add `health_check_endpoint` to the tool's CredentialSpec
|
||||
4. Implement a HealthChecker class in `tools/src/aden_tools/credentials/health_check.py`
|
||||
5. Register it in the `HEALTH_CHECKERS` dict
|
||||
6. Run `uv run pytest tools/tests/test_credential_registry.py` to verify wiring
|
||||
7. Submit a PR
|
||||
|
||||
**Difficulty:** Medium. Requires reading the service's API docs to find the right endpoint.
|
||||
|
||||
### Bug Fix (40 pts)
|
||||
|
||||
**What:** Find a bug during testing and fix it.
|
||||
|
||||
**How:**
|
||||
1. Find a bug while doing a smoke test or agent test
|
||||
2. File an issue describing the bug (or comment on the existing bounty issue)
|
||||
3. Fix the bug in a PR
|
||||
4. Add a test that covers the specific bug
|
||||
5. Reference the bounty issue in your PR
|
||||
|
||||
**Difficulty:** Varies. The bug itself tells you the difficulty.
|
||||
|
||||
### New Integration (75 pts)
|
||||
|
||||
**What:** Build a complete new integration from scratch.
|
||||
|
||||
**How:**
|
||||
1. Check the [Integration Request issues](https://github.com/adenhq/hive/issues?q=is%3Aissue+is%3Aopen+label%3A%22Integration%22) for requested integrations
|
||||
2. Follow the [BUILDING_TOOLS.md](../tools/BUILDING_TOOLS.md) guide
|
||||
3. Create: tool implementation + credential spec + health checker + tests + README
|
||||
4. Register in `_register_unverified()` in `tools/__init__.py`
|
||||
5. Run `make check && make test`
|
||||
6. Submit a PR
|
||||
|
||||
**Difficulty:** Hard. This is a significant contribution — expect multiple review rounds.
|
||||
|
||||
### Complete Promotion Checklist (50 pts)
|
||||
|
||||
**What:** Take an unverified tool through the full [promotion checklist](integration-promotion-checklist.md) to make it verified.
|
||||
|
||||
**How:**
|
||||
1. Pick a tool that has most checklist items already done (docs, health check, tests)
|
||||
2. Complete the remaining items
|
||||
3. Get at least 1 community test report (coordinate in `#integrations-testing`)
|
||||
4. Submit a PR that moves the tool from `_register_unverified()` to `_register_verified()`
|
||||
5. Include links to all checklist evidence in the PR description
|
||||
|
||||
**Difficulty:** Hard. Requires coordination and thoroughness.
|
||||
|
||||
## Achievement Badges
|
||||
|
||||
Permanent Discord roles earned through specific accomplishments:
|
||||
|
||||
| Badge | How to Earn |
|
||||
|-------|-------------|
|
||||
| **First Blood** | Complete your first bounty of any type |
|
||||
| **Bug Hunter** | Fix 3 bugs found during testing |
|
||||
| **Docs Champion** | Write 5 tool READMEs |
|
||||
| **Health Inspector** | Add 5 health checkers |
|
||||
| **Promoter** | Promote a tool from unverified to verified |
|
||||
| **Full Stack** | Complete at least 1 bounty of every type |
|
||||
| **Ironman** | 8 consecutive weeks with at least 1 bounty completion |
|
||||
|
||||
Badges are assigned by maintainers when you qualify. If you think you've earned one and it hasn't been assigned, ask in `#integrations-help`.
|
||||
|
||||
## Streaks
|
||||
|
||||
Consecutive weeks with at least one bounty completion earns XP multipliers:
|
||||
|
||||
| Streak | Multiplier |
|
||||
|--------|-----------|
|
||||
| 2 weeks | 1.1x |
|
||||
| 4 weeks | 1.25x |
|
||||
| 8+ weeks | 1.5x |
|
||||
|
||||
Missing a week resets the streak. A 20-point README bounty at an 8-week streak earns 30 XP instead of 20.
|
||||
|
||||
## Leaderboard
|
||||
|
||||
Posted every Monday at 9:00 UTC in `#integrations-announcements`. Top 3 get medal emojis.
|
||||
|
||||
You can also check your rank anytime in Discord:
|
||||
```
|
||||
/rank
|
||||
```
|
||||
|
||||
Or view the web leaderboard via Lurkr's dashboard.
|
||||
|
||||
## Rules
|
||||
|
||||
1. **Claim before you start** — comment on the issue, wait to be assigned
|
||||
2. **One person per bounty** — first to claim and get assigned gets it
|
||||
3. **7-day window** — if you don't submit a PR within 7 days of being assigned, the bounty is unassigned and re-opened
|
||||
4. **Maximum 3 active claims** — don't hoard bounties
|
||||
5. **Quality matters** — PRs must pass CI, follow templates, and address review feedback
|
||||
6. **No self-review** — you can't review your own PR
|
||||
7. **Honest testing** — report failures, not just successes. Finding bugs is valuable
|
||||
8. **No AI-only submissions** — AI tools are fine for assistance, but you must verify that function names, API URLs, and behavior match reality
|
||||
|
||||
## FAQ
|
||||
|
||||
**Q: Do I need an API key for every tool I test?**
|
||||
A: Yes, for smoke tests and agent tests. Most services have free tiers. The bounty issue links to where you get the key.
|
||||
|
||||
**Q: Can I work on multiple bounties at once?**
|
||||
A: Yes, up to 3 active claims at a time.
|
||||
|
||||
**Q: What if I find a bug but can't fix it?**
|
||||
A: File an issue! Someone else can pick up the `bounty:bug-fix`. Finding bugs during testing is the whole point.
|
||||
|
||||
**Q: How do I become a Core Contributor?**
|
||||
A: Keep contributing consistently across different bounty types for 4+ weeks. Maintainers will notice and nominate you when you're ready. There's no application process — just keep shipping quality work.
|
||||
|
||||
**Q: What if I haven't linked my Discord yet?**
|
||||
A: You'll still be recognized in the GitHub Action logs and Discord webhook message, but Lurkr can't push XP to your account. Link your Discord ID in `contributors.yml` to start earning XP and roles.
|
||||
|
||||
**Q: Do I earn XP from Discord messages too?**
|
||||
A: Yes. Lurkr awards XP for messages in `#integrations-*` channels (with a 60-second cooldown). Helping others in `#integrations-help` earns 2x XP. Both Discord XP and GitHub bounty XP feed into the same level.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| What | Where |
|
||||
|------|-------|
|
||||
| Bounty board | [GitHub Issues with bounty label](https://github.com/adenhq/hive/issues?q=is%3Aissue+is%3Aopen+label%3A%22bounty%3A*%22) |
|
||||
| README template | [docs/templates/tool-readme-template.md](templates/tool-readme-template.md) |
|
||||
| Test report template | [docs/templates/agent-test-report-template.md](templates/agent-test-report-template.md) |
|
||||
| Promotion checklist | [docs/integration-promotion-checklist.md](integration-promotion-checklist.md) |
|
||||
| Building tools guide | [tools/BUILDING_TOOLS.md](../tools/BUILDING_TOOLS.md) |
|
||||
| Contributing guide | [CONTRIBUTING.md](../CONTRIBUTING.md) |
|
||||
| Discord | [Join](https://discord.com/invite/MXE49hrKDk) |
|
||||
| Your rank | Type `/rank` in Discord |
|
||||
| Link your accounts | Add yourself to [contributors.yml](../contributors.yml) |
|
||||
@@ -0,0 +1,269 @@
|
||||
# Game Master Manual
|
||||
|
||||
Operations guide for maintainers running the Integration Bounty Program. This covers the day-to-day decisions: posting bounties, approving work, awarding points, managing tiers, and keeping the program healthy.
|
||||
|
||||
## Your Role
|
||||
|
||||
As a game master (maintainer), you:
|
||||
- Post bounty issues and set dollar values for Core Contributors
|
||||
- Assign claimed bounties to contributors
|
||||
- Review and merge bounty PRs (which auto-triggers point/XP awards)
|
||||
- Manually assign achievement badges and the Core Contributor role
|
||||
- Monitor for gaming and low-quality submissions
|
||||
- Keep the bounty board fresh and the community engaged
|
||||
|
||||
## Daily Operations
|
||||
|
||||
### Handling Bounty Claims
|
||||
|
||||
When someone comments "I'd like to work on this" on a bounty issue:
|
||||
|
||||
1. Check their GitHub profile — do they have relevant experience?
|
||||
2. For `difficulty:easy` bounties, assign immediately (within 24 hours)
|
||||
3. For `difficulty:medium` and `difficulty:hard`, check if they've completed easier bounties first
|
||||
4. Assign the issue to them via GitHub
|
||||
5. If they don't submit a PR within 7 days, unassign and re-open
|
||||
|
||||
### Reviewing Bounty PRs
|
||||
|
||||
When a bounty PR is submitted:
|
||||
|
||||
1. **Verify the PR matches the bounty** — does it actually complete what the issue asked for?
|
||||
2. **Check quality gates** (see below)
|
||||
3. **A different maintainer** must approve than the one who created the bounty issue
|
||||
4. **Apply the correct `bounty:*` label** to the PR before merging (if not already present)
|
||||
5. **Merge** — the GitHub Action automatically awards XP and posts to Discord
|
||||
6. **Close the linked bounty issue**
|
||||
|
||||
### Quality Gate Checks
|
||||
|
||||
#### For `bounty:docs` (READMEs):
|
||||
- [ ] Follows the [tool README template](templates/tool-readme-template.md)
|
||||
- [ ] Setup instructions are accurate (API key URL works, steps are correct)
|
||||
- [ ] Tool table lists all functions with correct names
|
||||
- [ ] At least one usage example per tool function
|
||||
- [ ] API reference link is valid
|
||||
- [ ] Not obviously AI-generated without verification (check that API URLs and function names match reality)
|
||||
|
||||
#### For `bounty:health-check`:
|
||||
- [ ] `health_check_endpoint` added to CredentialSpec
|
||||
- [ ] HealthChecker class implemented with proper 200/401/429 handling
|
||||
- [ ] Registered in `HEALTH_CHECKERS` dict
|
||||
- [ ] `uv run pytest tools/tests/test_credential_registry.py` passes
|
||||
- [ ] Endpoint is actually a lightweight validation call (no writes, no charges)
|
||||
|
||||
#### For `bounty:agent-test`:
|
||||
- [ ] Test report follows the [template](templates/agent-test-report-template.md)
|
||||
- [ ] Includes reproducible evidence (logs, session ID, or screenshots)
|
||||
- [ ] Tests were done with a real API key, not mocked
|
||||
- [ ] Reports both successes and failures honestly
|
||||
- [ ] Edge cases section is filled out (even if "none found")
|
||||
|
||||
#### For `bounty:bug-fix`:
|
||||
- [ ] Bug was found during actual integration testing (not invented)
|
||||
- [ ] Fix addresses the root cause, not just the symptom
|
||||
- [ ] Existing tests still pass
|
||||
- [ ] New test added for the specific bug
|
||||
|
||||
#### For `bounty:new-tool`:
|
||||
- [ ] Full implementation: tool + credential spec + tests + README
|
||||
- [ ] Follows [BUILDING_TOOLS.md](../tools/BUILDING_TOOLS.md) patterns
|
||||
- [ ] `make check && make test` passes
|
||||
- [ ] Registered in `_register_unverified()` (not verified — needs community testing first)
|
||||
|
||||
#### For `bounty:promote`:
|
||||
- [ ] Every item on the [promotion checklist](integration-promotion-checklist.md) is checked
|
||||
- [ ] At least 1 community agent test report exists
|
||||
- [ ] Move registration from `_register_unverified()` to `_register_verified()`
|
||||
|
||||
### Rejecting Submissions
|
||||
|
||||
When quality is insufficient:
|
||||
|
||||
1. Leave a specific, constructive review comment — explain exactly what needs to change
|
||||
2. Request changes on the PR (don't close it)
|
||||
3. Give them 7 days to address feedback
|
||||
4. If no response after 7 days, close the PR and unassign the bounty issue
|
||||
|
||||
**Never:**
|
||||
- Reject without explanation
|
||||
- Deduct points for good-faith attempts that need revision
|
||||
- Merge low-quality work just to be nice — it degrades the codebase and the program's credibility
|
||||
|
||||
## Weekly Operations
|
||||
|
||||
### Monday: Leaderboard Day
|
||||
|
||||
The `weekly-leaderboard.yml` action auto-posts at 9:00 UTC every Monday. After it posts:
|
||||
|
||||
1. Check the leaderboard in `#integrations-announcements`
|
||||
2. If anyone new entered the top 3, congratulate them in the channel
|
||||
3. Review the bounty board — are there enough open bounties? Aim for 10+ unclaimed at all times
|
||||
|
||||
### Thursday: Bounty Refresh
|
||||
|
||||
Mid-week check:
|
||||
|
||||
1. Are any bounties stale (assigned >7 days, no PR)? Unassign them
|
||||
2. Are any bounty types depleted? Post more
|
||||
3. Check `#integrations-help` — are people asking questions that suggest missing documentation? That's a signal for new `bounty:docs` issues
|
||||
|
||||
## Tier Management
|
||||
|
||||
### Promoting to Agent Builder (Automatic)
|
||||
|
||||
Lurkr handles this via role reward at level 5. No action needed.
|
||||
|
||||
### Promoting to Open Source Contributor (Automatic)
|
||||
|
||||
Lurkr handles this via role reward at level 15. No action needed.
|
||||
|
||||
### Promoting to Core Contributor (Manual)
|
||||
|
||||
This is the most important decision you make. Core Contributor unlocks monetary rewards, so the bar must be high.
|
||||
|
||||
**When to promote:**
|
||||
|
||||
1. The contributor has been active for **4+ weeks**
|
||||
2. They have contributions across **3+ bounty types** (not just one category)
|
||||
3. Their PRs are consistently clean — they don't need multiple rounds of back-and-forth
|
||||
4. They've demonstrated **technical depth** (not just documentation — they can fix bugs, add health checks, or build tools)
|
||||
5. At least one maintainer is willing to vouch for them
|
||||
|
||||
**How to promote:**
|
||||
|
||||
1. Discuss with other maintainers in your private channel
|
||||
2. If consensus, assign the Core Contributor role in Discord manually
|
||||
3. Post an announcement in `#integrations-announcements`:
|
||||
```
|
||||
Welcome @username as a Core Contributor! They've [brief summary of contributions].
|
||||
```
|
||||
4. Add them to the `#bounty-payouts` channel
|
||||
5. Brief them on how dollar-value bounties work (see below)
|
||||
|
||||
**When NOT to promote:**
|
||||
|
||||
- They only do easy bounties (all docs, no code)
|
||||
- They've been active for less than 4 weeks
|
||||
- Their PRs frequently need significant rework
|
||||
- They show signs of gaming (splitting work, low-effort submissions)
|
||||
|
||||
### Demoting / Pausing Core Contributor
|
||||
|
||||
If a Core Contributor becomes inactive or their quality drops:
|
||||
|
||||
1. Reach out privately first — "Hey, noticed you've been less active, everything okay?"
|
||||
2. If quality is the issue, provide specific feedback
|
||||
3. If they're inactive for 8+ weeks, remove the Core Contributor role (they can earn it back)
|
||||
4. Never demote publicly — handle it in DMs
|
||||
|
||||
## Monetary Bounties
|
||||
|
||||
### Setting Dollar Values
|
||||
|
||||
For each bounty issue, post the dollar value in `#bounty-payouts` (visible only to Core Contributors):
|
||||
|
||||
```
|
||||
Bounty #1234: Write README for salesforce_tool — $15
|
||||
Bounty #1235: Add health checker for jira — $25
|
||||
Bounty #1236: Full promotion of notion_tool — $75
|
||||
```
|
||||
|
||||
**Suggested dollar ranges:**
|
||||
|
||||
| Bounty Type | Dollar Range | Notes |
|
||||
|-------------|-------------|-------|
|
||||
| `bounty:docs` | $10–20 | $10 for simple tools, $20 for complex ones |
|
||||
| `bounty:health-check` | $15–30 | $15 for simple GET, $30 for complex auth |
|
||||
| `bounty:smoke-test` | $5–10 | Quick validation |
|
||||
| `bounty:agent-test` | $20–40 | Requires real API key and time |
|
||||
| `bounty:bug-fix` | $20–50 | Depends on complexity |
|
||||
| `bounty:new-tool` | $50–150 | Depends on integration complexity |
|
||||
| `bounty:promote` | $50–100 | Full checklist completion |
|
||||
|
||||
### Payout Process
|
||||
|
||||
1. Core Contributor completes bounty, PR is merged
|
||||
2. Verify the work meets quality gates
|
||||
3. Record the payout in `#bounty-payouts`:
|
||||
```
|
||||
PAID: @username — Bounty #1234 — $15 — [payment method/reference]
|
||||
```
|
||||
4. Process payment via your payment system (PayPal, Wise, crypto, etc.)
|
||||
|
||||
### Budget Management
|
||||
|
||||
- Set a monthly budget cap and communicate it
|
||||
- When budget is tight, reduce dollar values rather than stopping bounties entirely
|
||||
- Point values (XP) are always awarded regardless of budget — money is a bonus layer
|
||||
|
||||
## Achievement Badges
|
||||
|
||||
These are manually assigned when someone qualifies. Check periodically.
|
||||
|
||||
| Badge | Trigger | How to Verify |
|
||||
|-------|---------|---------------|
|
||||
| **First Blood** | First bounty completed | Check their first merged PR with `bounty:*` label |
|
||||
| **Bug Hunter** | 3 `bounty:bug-fix` PRs merged | Search: `is:pr is:merged author:USERNAME label:bounty:bug-fix` |
|
||||
| **Docs Champion** | 5 `bounty:docs` PRs merged | Search: `is:pr is:merged author:USERNAME label:bounty:docs` |
|
||||
| **Health Inspector** | 5 `bounty:health-check` PRs merged | Search: `is:pr is:merged author:USERNAME label:bounty:health-check` |
|
||||
| **Promoter** | 1 `bounty:promote` PR merged | Search: `is:pr is:merged author:USERNAME label:bounty:promote` |
|
||||
| **Full Stack** | At least 1 PR with each bounty type | Check all 7 bounty labels |
|
||||
| **Ironman** | 8 consecutive weeks with a bounty PR | Check merge dates — no gap > 7 days |
|
||||
|
||||
When assigning a badge:
|
||||
1. Assign the role in Discord
|
||||
2. Post in `#integrations-announcements`:
|
||||
```
|
||||
@username just earned the Bug Hunter badge! 3 bugs found and fixed.
|
||||
```
|
||||
|
||||
## Anti-Gaming Playbook
|
||||
|
||||
### Signs of Gaming
|
||||
|
||||
| Pattern | What It Looks Like | Response |
|
||||
|---------|-------------------|----------|
|
||||
| **Splitting** | One README split into 3 PRs | Reject extras, warn contributor |
|
||||
| **AI spam** | README with wrong function names, hallucinated APIs | Reject, explain why verification matters |
|
||||
| **Claim hoarding** | Claiming 10 bounties, completing 1 | Unassign after 7 days, limit to 3 active claims |
|
||||
| **Self-review** | Reviewing their own work under alt account | Ban both accounts |
|
||||
| **Low-effort agent tests** | Test report with no logs, no session ID | Request revision with specific feedback |
|
||||
|
||||
### Responses
|
||||
|
||||
**First offense:** Warning via PR comment or DM. Be specific about what was wrong.
|
||||
|
||||
**Second offense:** 2-week bounty cooldown (they can still contribute, but no bounty labels are applied to their PRs).
|
||||
|
||||
**Third offense:** Permanent removal from the bounty program. Core Contributor role revoked if applicable.
|
||||
|
||||
Document all actions in a private maintainer thread for transparency.
|
||||
|
||||
## Keeping the Program Alive
|
||||
|
||||
### What Makes It Stale
|
||||
|
||||
- No new bounties for 2+ weeks
|
||||
- Same 3 people on the leaderboard every week
|
||||
- Bounties claimed but never completed
|
||||
- Announcements channel goes quiet
|
||||
|
||||
### What Keeps It Fresh
|
||||
|
||||
- **New bounty types** — when the Doc Sprint is done, launch the Health Check Sprint
|
||||
- **Sprint events** — "This week: double XP on agent tests"
|
||||
- **Shoutouts** — highlight exceptional contributions in announcements
|
||||
- **Showcase pins** — pin the best demos in `#integration-showcase`
|
||||
- **Rising stars** — mention newcomers who are ramping up fast
|
||||
- **Milestones** — "We just promoted the 10th tool to verified!"
|
||||
|
||||
### Metrics to Track
|
||||
|
||||
| Metric | Healthy Range | Alarm |
|
||||
|--------|-------------|-------|
|
||||
| Open unclaimed bounties | 10–30 | < 5 (post more) or > 50 (too many, focus) |
|
||||
| Active contributors (last 30 days) | 5+ | < 3 |
|
||||
| Average days claim → PR | 3–7 | > 14 (bounties too hard or claims going stale) |
|
||||
| Tools promoted (monthly) | 2–5 | 0 (investigate blockers) |
|
||||
| Core Contributor count | 3–10 | > 15 (bar too low) or 0 (bar too high) |
|
||||
@@ -0,0 +1,223 @@
|
||||
# Integration Bounty Program — Setup Guide
|
||||
|
||||
Complete setup from zero to running. Estimated time: 30 minutes.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Admin access to the GitHub repo
|
||||
- Admin access to the Discord server
|
||||
- `gh` CLI installed and authenticated
|
||||
|
||||
## Step 1: Create GitHub Labels (2 min)
|
||||
|
||||
```bash
|
||||
./scripts/setup-bounty-labels.sh
|
||||
```
|
||||
|
||||
This creates 10 labels: 7 bounty types (`bounty:smoke-test`, `bounty:agent-test`, `bounty:docs`, `bounty:health-check`, `bounty:bug-fix`, `bounty:new-tool`, `bounty:promote`) and 3 difficulty levels (`difficulty:easy`, `difficulty:medium`, `difficulty:hard`).
|
||||
|
||||
Verify at: `https://github.com/adenhq/hive/labels`
|
||||
|
||||
## Step 2: Create Discord Channels (5 min)
|
||||
|
||||
Create these channels (or rename existing ones):
|
||||
|
||||
```
|
||||
Category: Integrations
|
||||
#integrations-announcements (read-only for non-admins)
|
||||
#integrations-testing
|
||||
#integrations-help
|
||||
#integration-showcase
|
||||
|
||||
Category: Private
|
||||
#bounty-payouts (visible only to Core Contributor role)
|
||||
```
|
||||
|
||||
**Channel permissions:**
|
||||
- `#integrations-announcements`: Everyone can read, only bots + admins can post
|
||||
- `#bounty-payouts`: Visible only to users with the Core Contributor role
|
||||
- All others: open to everyone
|
||||
|
||||
## Step 3: Create Discord Roles (3 min)
|
||||
|
||||
Create these roles if they don't exist. Order matters — higher = more prestigious:
|
||||
|
||||
| Role | Color | Hoisted | Mentionable |
|
||||
|------|-------|---------|-------------|
|
||||
| Core Contributor | Gold `#F1C40F` | Yes | Yes |
|
||||
| Open Source Contributor | Purple `#9B59B6` | Yes | No |
|
||||
| Agent Builder | Green `#2ECC71` | Yes | No |
|
||||
|
||||
Achievement badge roles (optional, create as needed):
|
||||
|
||||
| Role | Color |
|
||||
|------|-------|
|
||||
| First Blood | Default |
|
||||
| Bug Hunter | Red `#E74C3C` |
|
||||
| Docs Champion | Yellow `#F39C12` |
|
||||
| Health Inspector | Orange `#E67E22` |
|
||||
| Promoter | Gold `#F1C40F` |
|
||||
| Full Stack | Teal `#1ABC9C` |
|
||||
| Ironman | Default |
|
||||
|
||||
## Step 4: Install and Configure Lurkr (10 min)
|
||||
|
||||
### 4a. Invite Lurkr
|
||||
|
||||
Go to https://lurkr.gg/ and invite the bot to your server. Grant it the permissions it requests (Manage Roles, Send Messages, etc).
|
||||
|
||||
### 4b. Enable Leveling
|
||||
|
||||
In any channel:
|
||||
```
|
||||
/levels enable
|
||||
```
|
||||
|
||||
### 4c. Configure Message XP
|
||||
|
||||
```
|
||||
/levels set-xp min:15 max:25
|
||||
/levels set-cooldown seconds:60
|
||||
```
|
||||
|
||||
### 4d. Set Channel XP Multipliers
|
||||
|
||||
Boost XP in channels where helping others matters:
|
||||
|
||||
```
|
||||
/levels multiplier channel:#integrations-help multiplier:2
|
||||
/levels multiplier channel:#integrations-testing multiplier:1.5
|
||||
```
|
||||
|
||||
Disable XP in bot-only channels:
|
||||
|
||||
```
|
||||
/levels ignore channel:#integrations-announcements
|
||||
/levels ignore channel:#bounty-payouts
|
||||
```
|
||||
|
||||
### 4e. Configure Role Rewards
|
||||
|
||||
```
|
||||
/levels role-reward add level:5 role:@Agent Builder
|
||||
/levels role-reward add level:15 role:@Open Source Contributor
|
||||
```
|
||||
|
||||
Do NOT auto-assign Core Contributor — that's maintainer-only.
|
||||
|
||||
### 4f. Generate Lurkr API Key
|
||||
|
||||
1. Go to https://lurkr.gg/ and log in with Discord
|
||||
2. Navigate to your profile / API settings
|
||||
3. Click "Create API Key"
|
||||
4. Select **Read/Write** (not read-only)
|
||||
5. Copy the key — you'll need it in the next step
|
||||
|
||||
## Step 5: Create Discord Webhook (2 min)
|
||||
|
||||
1. Go to **Server Settings > Integrations > Webhooks**
|
||||
2. Click **New Webhook**
|
||||
3. Name it `Bounty Tracker`
|
||||
4. Set the channel to `#integrations-announcements`
|
||||
5. Copy the webhook URL
|
||||
|
||||
## Step 6: Add GitHub Repository Secrets (3 min)
|
||||
|
||||
Go to **Repo Settings > Secrets and variables > Actions > New repository secret** and add:
|
||||
|
||||
| Secret Name | Value |
|
||||
|-------------|-------|
|
||||
| `DISCORD_BOUNTY_WEBHOOK_URL` | The webhook URL from Step 5 |
|
||||
| `LURKR_API_KEY` | The Lurkr API key from Step 4f |
|
||||
| `LURKR_GUILD_ID` | Your Discord server ID* |
|
||||
|
||||
*To find server ID: Enable Developer Mode in Discord (Settings > Advanced), then right-click the server name > Copy Server ID.
|
||||
|
||||
## Step 7: Test the Pipeline (5 min)
|
||||
|
||||
### Test 1: Verify the script runs locally
|
||||
|
||||
```bash
|
||||
GITHUB_TOKEN=$(gh auth token) \
|
||||
GITHUB_REPOSITORY_OWNER=adenhq \
|
||||
GITHUB_REPOSITORY_NAME=hive \
|
||||
bun run scripts/bounty-tracker.ts leaderboard
|
||||
```
|
||||
|
||||
Expected: `Found 0 merged bounty PRs` (or more if you already have bounty PRs).
|
||||
|
||||
### Test 2: Test a webhook notification
|
||||
|
||||
Create a test PR, add the `bounty:docs` and `difficulty:easy` labels, merge it, and verify:
|
||||
- GitHub Action `Bounty completed` runs successfully
|
||||
- A message appears in `#integrations-announcements`
|
||||
- If the contributor is in `contributors.yml`, Lurkr XP is awarded
|
||||
|
||||
### Test 3: Verify Lurkr role rewards
|
||||
|
||||
Check that role rewards are configured:
|
||||
```
|
||||
/levels role-rewards
|
||||
```
|
||||
|
||||
## Step 8: Seed the First Bounty Issues (ongoing)
|
||||
|
||||
Use the bounty issue template in GitHub to create issues. Start with the easiest batch:
|
||||
|
||||
### Phase 1 (Week 1): Documentation bounties
|
||||
|
||||
For each unverified tool missing a README, create an issue:
|
||||
- Title: `[Bounty]: Write README for {tool_name}`
|
||||
- Bounty type: `Write README (20 pts)`
|
||||
- Difficulty: `Easy`
|
||||
- Labels: `bounty:docs`, `difficulty:easy`
|
||||
|
||||
### Quick list of tools missing READMEs
|
||||
|
||||
```
|
||||
azure_sql, cloudinary, confluence, databricks, docker_hub, duckduckgo,
|
||||
google_search_console, google_sheets, greenhouse, jira, kafka, lusha,
|
||||
mongodb, notion, obsidian, pagerduty, pinecone, pipedrive, plaid,
|
||||
pushover, quickbooks, redshift, sap, salesforce, shopify, snowflake,
|
||||
supabase, terraform, tines, trello, twilio, twitter, vercel,
|
||||
yahoo_finance, zoom, huggingface, langfuse, microsoft_graph, n8n,
|
||||
powerbi, redis
|
||||
```
|
||||
|
||||
## Verification Checklist
|
||||
|
||||
After setup, verify everything works:
|
||||
|
||||
- [ ] Labels exist on the repo (`bounty:*` and `difficulty:*`)
|
||||
- [ ] Discord channels created and permissions set
|
||||
- [ ] Discord roles created in correct order
|
||||
- [ ] Lurkr installed, leveling enabled, XP configured
|
||||
- [ ] Lurkr role rewards set for levels 5 and 15
|
||||
- [ ] Lurkr API key is Read/Write
|
||||
- [ ] All 3 GitHub secrets added
|
||||
- [ ] `bounty-completed.yml` workflow exists and is enabled
|
||||
- [ ] `weekly-leaderboard.yml` workflow exists and is enabled
|
||||
- [ ] Test PR + merge triggers notification in Discord
|
||||
- [ ] `contributors.yml` exists at repo root
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Action runs but no Discord message:**
|
||||
- Check the `DISCORD_BOUNTY_WEBHOOK_URL` secret is set correctly
|
||||
- Check the webhook channel still exists and the webhook hasn't been deleted
|
||||
- Check the Action logs for error messages
|
||||
|
||||
**Lurkr XP not awarded:**
|
||||
- Confirm `LURKR_API_KEY` and `LURKR_GUILD_ID` secrets are set
|
||||
- Confirm the API key is Read/Write (not read-only)
|
||||
- Confirm the contributor has linked their Discord ID in `contributors.yml`
|
||||
- Check Action logs for `Lurkr XP push failed` messages
|
||||
|
||||
**Role not assigned after level up:**
|
||||
- Verify role rewards are configured: `/levels role-rewards`
|
||||
- Lurkr assigns roles on level-up, not retroactively. The user may need to send a message or run `/rank` to trigger it
|
||||
- Verify Lurkr's role is above the roles it needs to assign in the server role hierarchy
|
||||
|
||||
**Weekly leaderboard not posting:**
|
||||
- The cron schedule is Monday 9:00 UTC. Check that the workflow is enabled
|
||||
- Manually trigger: Actions > Weekly bounty leaderboard > Run workflow
|
||||
@@ -0,0 +1,372 @@
|
||||
# Integration Bounty Program
|
||||
|
||||
Gamified contribution program for expanding and hardening Aden's integration ecosystem. Community members earn points by testing, documenting, and building integrations — with monetary rewards unlocked at the Core Contributor tier.
|
||||
|
||||
## Why Contribute?
|
||||
|
||||
### Visible Status
|
||||
|
||||
Every Discord message you send shows your tier role and badges. When someone asks a question in `#integrations-help` and you answer it with a **Core Contributor** badge, people listen. Your role is earned, not bought.
|
||||
|
||||
### Your Name in the Product
|
||||
|
||||
When you promote a tool to verified, your GitHub handle goes in the tool's README under `Contributed by`. Every agent that uses that integration carries your name. This is permanent credit in a production codebase — not a profile badge that disappears.
|
||||
|
||||
### Weekly Races
|
||||
|
||||
Every Monday the bot posts the leaderboard. The top 3 get medal emojis next to their name all week. There's a `#integration-showcase` channel where people demo agents using the tools they tested — the best demos get pinned and highlighted in announcements.
|
||||
|
||||
### The Path to Paid
|
||||
|
||||
Core Contributor unlocks real money. But you can't buy your way in — it takes sustained quality work across testing, docs, and code. The scarcity makes it matter. When you see someone with Core Contributor status, you know they've shipped real integrations.
|
||||
|
||||
### Streaks
|
||||
|
||||
Consecutive weeks with at least one bounty completion earns streak multipliers:
|
||||
|
||||
| Streak | Multiplier | Example |
|
||||
|--------|-----------|---------|
|
||||
| 2 weeks | 1.1x | 20pt README = 22 pts |
|
||||
| 4 weeks | 1.25x | 30pt agent test = 37 pts |
|
||||
| 8+ weeks | 1.5x | 75pt new tool = 112 pts |
|
||||
|
||||
Missing a week resets the streak. This rewards consistency over bursts.
|
||||
|
||||
### Achievement Badges
|
||||
|
||||
Unlocked permanently and displayed on your Discord profile via bot roles:
|
||||
|
||||
| Badge | Requirement | Role Color |
|
||||
|-------|-------------|------------|
|
||||
| **First Blood** | Complete your first bounty | — |
|
||||
| **Bug Hunter** | Find and fix 3 bugs via testing | Red |
|
||||
| **Docs Champion** | Write 5 tool READMEs | Yellow |
|
||||
| **Health Inspector** | Add 5 health checkers | Orange |
|
||||
| **Promoter** | Promote a tool from unverified to verified | Gold |
|
||||
| **Full Stack** | Complete at least 1 bounty of every type | Rainbow |
|
||||
| **Ironman** | 8-week contribution streak | — |
|
||||
|
||||
## Tiers
|
||||
|
||||
| Tier | How to Reach | What You See | Rewards |
|
||||
|------|-------------|--------------|---------|
|
||||
| **Agent Builder** | Join Discord + start testing | Bounty board with point values | Discord role, community recognition, achievement badges |
|
||||
| **Open Source Contributor** | First merged PR | Bounty board with point values | Discord role, listed in CONTRIBUTORS.md, name in tool READMEs |
|
||||
| **Core Contributor** | Maintainer-approved promotion | Bounty board with **dollar values** | Monetary payout per completed bounty, private dev channel |
|
||||
|
||||
### Core Contributor Promotion
|
||||
|
||||
Core Contributor status is **maintainer-approved** and requires:
|
||||
|
||||
1. **Sustained contribution** — consistent activity over multiple weeks, not a one-time burst
|
||||
2. **Breadth** — contributions across multiple activity types (not just 20 READMEs)
|
||||
3. **Quality** — history of clean PRs that pass CI without excessive back-and-forth
|
||||
4. **Maintainer nomination** — at least one maintainer vouches for the contributor
|
||||
|
||||
Core Contributors see dollar values on bounty issues via a private Discord channel. Payouts happen per completed bounty after the PR is merged and approved by a maintainer.
|
||||
|
||||
## Point System
|
||||
|
||||
### Testing (Highest Priority)
|
||||
|
||||
These are the most valuable contributions — testing integrations with real API keys and real agents is the bottleneck for promoting tools from unverified to verified.
|
||||
|
||||
| Activity | Points | Requirements |
|
||||
|----------|--------|-------------|
|
||||
| **Smoke Test** | 10 | Run a tool with a real API key, submit a pass/fail report with logs |
|
||||
| **Agent Test Report** | 30 | Build an agent using an unverified tool, submit a structured test report with session ID |
|
||||
| **Edge Case Report** | 15 | Document a specific edge case (rate limits, auth expiry, malformed data, etc.) |
|
||||
| **Live Demo** | 25 | Record a short video/GIF of an integration working in an agent |
|
||||
|
||||
### Code Contributions
|
||||
|
||||
| Activity | Points | Requirements |
|
||||
|----------|--------|-------------|
|
||||
| **Bug Fix PR** | 40 | Fix a bug found during testing, merged PR |
|
||||
| **Add Health Checker** | 25 | Implement health check class + register in HEALTH_CHECKERS, merged PR |
|
||||
| **Add health_check_endpoint** | 10 | Research correct endpoint, add to CredentialSpec, merged PR |
|
||||
| **Write README** | 20 | Add missing README following the [tool README template](templates/tool-readme-template.md), merged PR |
|
||||
| **Complete Promotion Checklist** | 50 | Finish all items on the [promotion checklist](integration-promotion-checklist.md) for a tool, merged PR |
|
||||
| **New Integration** | 75 | Full implementation (tool + credential spec + tests + docs), merged PR |
|
||||
|
||||
### Community
|
||||
|
||||
| Activity | Points | Requirements |
|
||||
|----------|--------|-------------|
|
||||
| **PR Review** | 15 | Substantive code review on an integration PR (not just "LGTM") |
|
||||
| **Help in Discord** | 5 | Answer an integration question (mod-verified) |
|
||||
| **Propose Integration** | 5 | File a well-structured `[Integration]:` issue per existing template |
|
||||
|
||||
## Quality Gates
|
||||
|
||||
Points are only awarded after quality verification:
|
||||
|
||||
- **PRs**: Must be merged by a maintainer (not self-merged)
|
||||
- **Test reports**: Must follow the [test report template](templates/agent-test-report-template.md) with reproducible evidence (logs, session ID, screenshots)
|
||||
- **Health checkers**: Must pass CI (`uv run pytest tools/tests/test_credential_registry.py`)
|
||||
- **READMEs**: Must follow the [tool README template](templates/tool-readme-template.md)
|
||||
- **Reviews**: Must include actionable feedback, not just approval
|
||||
- **Bounties are claimed before work starts** — comment on the issue to claim, wait for maintainer assignment
|
||||
|
||||
### Anti-Gaming Rules
|
||||
|
||||
- No self-review on PRs
|
||||
- A different maintainer must approve bounty completion than the one who created it
|
||||
- Duplicate or near-duplicate submissions are rejected
|
||||
- Low-effort submissions (copy-pasted from AI without verification) are rejected and may result in point deduction
|
||||
- Splitting a single change across multiple PRs to farm points is not allowed
|
||||
|
||||
## Bounty Issues
|
||||
|
||||
Integration bounties are tracked as GitHub Issues with specific labels.
|
||||
|
||||
### Labels
|
||||
|
||||
| Label | Color | Meaning |
|
||||
|-------|-------|---------|
|
||||
| `bounty:smoke-test` | `#0E8A16` (green) | Run tool with real API key, report results |
|
||||
| `bounty:agent-test` | `#1D76DB` (blue) | Test tool in a real agent workflow |
|
||||
| `bounty:docs` | `#FBCA04` (yellow) | Write or improve documentation |
|
||||
| `bounty:health-check` | `#D93F0B` (orange) | Add health check endpoint or checker |
|
||||
| `bounty:bug-fix` | `#B60205` (red) | Fix a discovered bug |
|
||||
| `bounty:new-tool` | `#6F42C1` (purple) | Build a new integration from scratch |
|
||||
| `bounty:promote` | `#C2A000` (gold) | Complete full promotion checklist |
|
||||
| `difficulty:easy` | `#BFD4F2` | Good first contribution |
|
||||
| `difficulty:medium` | `#D4C5F9` | Requires some familiarity |
|
||||
| `difficulty:hard` | `#F9D0C4` | Significant effort or expertise needed |
|
||||
|
||||
### Bounty Issue Structure
|
||||
|
||||
Each bounty issue includes:
|
||||
- **Activity type** (label)
|
||||
- **Difficulty** (label)
|
||||
- **Point value** (visible to all in issue body)
|
||||
- **Dollar value** (visible only to Core Contributors via private Discord channel)
|
||||
- **Acceptance criteria** (what "done" looks like)
|
||||
- **Relevant files** (links to the tool directory, credential spec, etc.)
|
||||
|
||||
See the [bounty issue template](../.github/ISSUE_TEMPLATE/integration-bounty.yml) for the standard format.
|
||||
|
||||
## Discord Structure
|
||||
|
||||
```
|
||||
#integrations-announcements — New bounties, tool promotions, leaderboard updates
|
||||
#integrations-testing — Coordinate who's testing what, share test reports
|
||||
#integrations-help — Get help with credential setup, tool development
|
||||
#integration-showcase — Demos of agents using integrations
|
||||
|
||||
# Private (Core Contributors only)
|
||||
#bounty-payouts — Dollar values, payout tracking, claims
|
||||
```
|
||||
|
||||
## Leaderboard
|
||||
|
||||
Weekly leaderboard posted to `#integrations-announcements`:
|
||||
- Top 10 contributors by points (rolling 30 days)
|
||||
- Top 10 contributors all-time
|
||||
- Recently promoted tools (unverified -> verified)
|
||||
- Number of open bounties by type
|
||||
|
||||
Tracking is done via GitHub labels on merged PRs and closed issues. Maintainers tag completed work with the appropriate `bounty:*` label and contributor handle.
|
||||
|
||||
## Launch Plan: The 55-Tool Blitz
|
||||
|
||||
The initial launch targets the 55 unverified tools that need testing, documentation, and health checks.
|
||||
|
||||
### Phase 1: Doc Sprint (Week 1-2)
|
||||
|
||||
- Post 41 `bounty:docs` issues for tools missing READMEs
|
||||
- `difficulty:easy`, 20 points each
|
||||
- Provide the [tool README template](templates/tool-readme-template.md) so contributors fill in the blanks
|
||||
|
||||
### Phase 2: Health Check Sprint (Week 2-3)
|
||||
|
||||
- Post 40 `bounty:health-check` issues for tools missing health check endpoints
|
||||
- `difficulty:medium`, 25 points each
|
||||
- Provide example health checker code in each issue
|
||||
|
||||
### Phase 3: Agent Test Sprint (Week 3-5)
|
||||
|
||||
- Post 55 `bounty:agent-test` issues — one per unverified tool
|
||||
- `difficulty:medium`, 30 points each
|
||||
- Provide a template agent that contributors can swap their tool into
|
||||
|
||||
### Phase 4: Promotion Sprint (Week 5-8)
|
||||
|
||||
- Post `bounty:promote` issues for tools that have completed docs + health checks + testing
|
||||
- `difficulty:hard`, 50 points each
|
||||
- The contributor who completes the final checklist item gets the promotion bonus
|
||||
- Each promoted tool gets an announcement in `#integrations-announcements`
|
||||
|
||||
## Automation
|
||||
|
||||
The bounty program runs on **GitHub Actions + Lurkr bot + Discord webhooks**. GitHub Actions calculate points from merged PRs, push XP to Lurkr via its API, and post notifications. Lurkr handles the Discord leveling, leaderboard display, and automatic role assignments.
|
||||
|
||||
### How It Works
|
||||
|
||||
```
|
||||
PR merged with bounty:* label
|
||||
→ GitHub Action fires bounty-tracker.ts
|
||||
→ Script calculates points from label
|
||||
→ Script resolves GitHub → Discord ID via contributors.yml
|
||||
→ Script calls Lurkr API: PATCH /levels/{guild}/users/{user} (+XP)
|
||||
→ Lurkr auto-assigns role rewards at XP thresholds
|
||||
→ Script posts Discord webhook notification to #integrations-announcements
|
||||
```
|
||||
|
||||
One system, one leaderboard, one set of roles. Discord activity XP and GitHub bounty XP flow into the same Lurkr leveling system.
|
||||
|
||||
### GitHub Actions
|
||||
|
||||
| Workflow | Trigger | What It Does |
|
||||
|----------|---------|-------------|
|
||||
| `bounty-completed.yml` | PR merged with `bounty:*` label | Calculates points, pushes XP to Lurkr, posts Discord notification |
|
||||
| `weekly-leaderboard.yml` | Every Monday 9:00 UTC (or manual) | Generates leaderboard from all merged bounty PRs, posts to Discord |
|
||||
|
||||
Both use `scripts/bounty-tracker.ts` (Bun/TypeScript) which:
|
||||
- Reads `bounty:*` labels from merged PRs to calculate points
|
||||
- Resolves GitHub username → Discord ID via `contributors.yml`
|
||||
- Calls Lurkr API to atomically increment XP: `PATCH /levels/{guildId}/users/{userId}` with `{"xp": {"increment": N}}`
|
||||
- Posts formatted messages to Discord via webhook
|
||||
|
||||
### Lurkr Bot Setup
|
||||
|
||||
[Lurkr](https://lurkr.gg/) is a free, no-paywall leveling bot with a full REST API that accepts external XP pushes — the only major leveling bot that supports this.
|
||||
|
||||
#### 1. Invite Lurkr to your Discord server
|
||||
|
||||
Go to https://lurkr.gg/ and invite the bot.
|
||||
|
||||
#### 2. Enable leveling
|
||||
|
||||
```
|
||||
/levels enable
|
||||
```
|
||||
|
||||
#### 3. Configure XP for Discord activity
|
||||
|
||||
Lurkr will also award XP for regular Discord messages. Configure this so Discord engagement and GitHub bounties both feed into the same system:
|
||||
|
||||
- Set message XP range (e.g., 15-25 XP per message)
|
||||
- Set cooldown (e.g., 60 seconds — prevents spam farming)
|
||||
- Optionally boost XP in `#integrations-help` and `#integrations-testing` channels so helping others earns more
|
||||
|
||||
```
|
||||
/levels set-xp min:15 max:25
|
||||
/levels set-cooldown seconds:60
|
||||
/levels multiplier channel:#integrations-help multiplier:2
|
||||
/levels multiplier channel:#integrations-testing multiplier:1.5
|
||||
```
|
||||
|
||||
#### 4. Configure role rewards
|
||||
|
||||
Map Lurkr levels to your existing Discord tiers. The XP thresholds should be calibrated so that a mix of Discord activity and GitHub bounties is needed to level up.
|
||||
|
||||
| Lurkr Level | XP Threshold | Discord Role | How to Reach |
|
||||
|-------------|-------------|-------------|-------------|
|
||||
| 5 | ~500 XP | **Agent Builder** | A few bounties or active Discord participation |
|
||||
| 15 | ~2,000 XP | **Open Source Contributor** | Sustained bounty contributions |
|
||||
| 30 | ~5,000 XP | Core Contributor *eligible* | Significant sustained contribution |
|
||||
|
||||
Note: **Core Contributor** role is still manually assigned by maintainers (since it involves money). Lurkr level 30 signals eligibility, not automatic promotion.
|
||||
|
||||
Add role rewards in the Lurkr dashboard or via commands:
|
||||
|
||||
```
|
||||
/levels role-reward add level:5 role:@Agent Builder
|
||||
/levels role-reward add level:15 role:@Open Source Contributor
|
||||
```
|
||||
|
||||
Achievement badge roles (First Blood, Bug Hunter, etc.) are added manually by maintainers when someone qualifies — these are not level-based.
|
||||
|
||||
#### 5. Generate a Read/Write API key
|
||||
|
||||
- Go to https://lurkr.gg/ and log in
|
||||
- Navigate to your profile / API settings
|
||||
- Create a **Read/Write** API key (not read-only — we need PATCH access)
|
||||
- Copy the key
|
||||
|
||||
#### 6. Add secrets to GitHub repository
|
||||
|
||||
Add three secrets in **Repo Settings > Secrets and variables > Actions**:
|
||||
|
||||
| Secret | Value |
|
||||
|--------|-------|
|
||||
| `DISCORD_BOUNTY_WEBHOOK_URL` | Discord webhook URL for `#integrations-announcements` |
|
||||
| `LURKR_API_KEY` | Your Lurkr Read/Write API key |
|
||||
| `LURKR_GUILD_ID` | Your Discord server ID |
|
||||
|
||||
To find your server ID: Enable Developer Mode in Discord (Settings > Advanced), then right-click the server name > Copy Server ID.
|
||||
|
||||
#### 7. Create the labels and start posting bounties
|
||||
|
||||
```bash
|
||||
./scripts/setup-bounty-labels.sh
|
||||
```
|
||||
|
||||
That's it. When a maintainer merges a PR with a `bounty:*` label, the contributor automatically gets:
|
||||
- XP added to their Lurkr level
|
||||
- A notification in `#integrations-announcements` with their new level
|
||||
- Role upgrades when they cross level thresholds
|
||||
|
||||
### Identity Linking (GitHub ↔ Discord)
|
||||
|
||||
Contributors link their accounts by adding themselves to `contributors.yml` at the repo root:
|
||||
|
||||
```yaml
|
||||
contributors:
|
||||
- github: jane-doe
|
||||
discord: "123456789012345678"
|
||||
name: Jane Doe
|
||||
```
|
||||
|
||||
This is intentionally a file-in-repo approach (not a database) because:
|
||||
- It's version-controlled and auditable
|
||||
- Adding yourself is a PR — which is itself a contribution
|
||||
- No bot infrastructure needed for identity storage
|
||||
- Maintainers can review and approve linkages
|
||||
|
||||
**To find your Discord ID:** Enable Developer Mode in Discord Settings > Advanced, then right-click your name > Copy User ID.
|
||||
|
||||
**Important:** Contributors who haven't linked their Discord ID in `contributors.yml` will still get bounty notifications on GitHub, but won't receive Lurkr XP or Discord pings. The notification will remind them to link.
|
||||
|
||||
### What Handles What
|
||||
|
||||
| Concern | Handled By | How |
|
||||
|---------|-----------|-----|
|
||||
| Bounty point calculation | GitHub Actions | `bounty-completed.yml` reads PR labels |
|
||||
| XP push to Discord | GitHub Actions → Lurkr API | `PATCH /levels/{guild}/users/{user}` with `{"xp": {"increment": N}}` |
|
||||
| Discord engagement XP | Lurkr bot | Native message XP (configurable per-channel) |
|
||||
| Leaderboard | Lurkr bot | Built-in `/levels leaderboard` + web leaderboard |
|
||||
| Weekly announcement | GitHub Actions | `weekly-leaderboard.yml` posts via webhook |
|
||||
| Agent Builder role | Lurkr bot | Auto-assigned at level 5 via role reward |
|
||||
| OSS Contributor role | Lurkr bot | Auto-assigned at level 15 via role reward |
|
||||
| Core Contributor role | Maintainer | Manual (involves money, level 30 = eligible) |
|
||||
| Achievement badges | Maintainer | Manual role assignment when criteria met |
|
||||
| Streak tracking | GitHub Actions | `bounty-tracker.ts` calculates from PR merge dates |
|
||||
| Identity linking | contributors.yml | PR-based, reviewed by maintainers |
|
||||
| Discord notifications | GitHub Actions | Webhook post to `#integrations-announcements` |
|
||||
|
||||
## Guides
|
||||
|
||||
- **[Setup Guide](bounty-setup-guide.md)** — Complete admin setup from zero to running (30 min)
|
||||
- **[Game Master Manual](bounty-game-master-manual.md)** — Maintainer operations: posting bounties, reviewing work, managing tiers, anti-gaming
|
||||
- **[Contributor Guide](bounty-contributor-guide.md)** — Everything a contributor needs to start earning XP and completing bounties
|
||||
|
||||
## Reference
|
||||
|
||||
- [Integration Promotion Checklist](integration-promotion-checklist.md) — Formal criteria for unverified -> verified
|
||||
- [Tool README Template](templates/tool-readme-template.md) — Standard format for tool documentation
|
||||
- [Agent Test Report Template](templates/agent-test-report-template.md) — Standard format for test reports
|
||||
- [Building Tools Guide](../tools/BUILDING_TOOLS.md) — How to build integrations
|
||||
- [Parent Issue #2805](https://github.com/adenhq/hive/issues/2805) — Master integration tracking issue
|
||||
- [Lurkr API Docs](https://lurkr.gg/docs/api) — API reference for XP push
|
||||
- [Lurkr Leveling Setup](https://lurkr.gg/docs/guides/setting-up-server-leveling) — Bot configuration guide
|
||||
|
||||
### Automation Files
|
||||
|
||||
- `.github/workflows/bounty-completed.yml` — PR merge → Lurkr XP push + Discord notification
|
||||
- `.github/workflows/weekly-leaderboard.yml` — Monday leaderboard post
|
||||
- `scripts/bounty-tracker.ts` — Point calculation, Lurkr API integration, Discord formatting
|
||||
- `scripts/setup-bounty-labels.sh` — One-time label setup
|
||||
- `contributors.yml` — GitHub ↔ Discord identity mapping
|
||||
@@ -0,0 +1,99 @@
|
||||
# Integration Promotion Checklist
|
||||
|
||||
Formal criteria for promoting a tool from **unverified** to **verified**. A tool must satisfy every required item before a maintainer moves it from `_register_unverified()` to `_register_verified()` in [tools/__init__.py](../tools/src/aden_tools/tools/__init__.py).
|
||||
|
||||
## Checklist
|
||||
|
||||
### Code Quality (Required)
|
||||
|
||||
- [ ] **`register_tools` function** follows the standard signature pattern from [BUILDING_TOOLS.md](../tools/BUILDING_TOOLS.md)
|
||||
- [ ] **Error handling** — all tools return `{"error": ...}` dicts instead of raising exceptions
|
||||
- [ ] **Credential handling** — graceful fallback when credentials are missing, with actionable `"help"` message
|
||||
- [ ] **Input validation** — parameters are validated before making API calls
|
||||
- [ ] **No hardcoded secrets** — API keys come from credentials adapter or environment variables only
|
||||
|
||||
### Credential Spec (Required)
|
||||
|
||||
- [ ] **CredentialSpec exists** in `tools/src/aden_tools/credentials/{category}.py`
|
||||
- [ ] **`env_var`** is set and unique (no collisions with other specs)
|
||||
- [ ] **`tools`** list includes every tool function name registered by this module
|
||||
- [ ] **`help_url`** points to the page where users get their API key
|
||||
- [ ] **`description`** is a clear one-liner
|
||||
- [ ] **`credential_id`** and **`credential_key`** are set for credential store mapping
|
||||
- [ ] **Spec is merged** into `CREDENTIAL_SPECS` in `credentials/__init__.py`
|
||||
|
||||
### Health Check (Required)
|
||||
|
||||
- [ ] **`health_check_endpoint`** is set in the CredentialSpec
|
||||
- [ ] **HealthChecker class** is implemented in `tools/src/aden_tools/credentials/health_check.py`
|
||||
- [ ] **Checker is registered** in the `HEALTH_CHECKERS` dict
|
||||
- [ ] **Handles 200** (valid), **401** (invalid/expired), and **429** (rate limited but valid) responses
|
||||
- [ ] **Registry tests pass** — `uv run pytest tools/tests/test_credential_registry.py -v`
|
||||
|
||||
### Documentation (Required)
|
||||
|
||||
- [ ] **README.md** exists in the tool directory, following the [tool README template](templates/tool-readme-template.md)
|
||||
- [ ] **Setup instructions** — how to get and configure the API key
|
||||
- [ ] **Tool table** — lists all tool functions with descriptions
|
||||
- [ ] **Usage examples** — at least one example per tool function
|
||||
- [ ] **API reference link** — link to the service's API docs
|
||||
|
||||
### Testing (Required)
|
||||
|
||||
- [ ] **Unit tests exist** in `tools/tests/tools/test_{tool_name}.py`
|
||||
- [ ] **Tests mock external APIs** — no live API calls in unit tests
|
||||
- [ ] **Tests cover happy path** for each tool function
|
||||
- [ ] **Tests cover error cases** — missing credentials, invalid input, API errors
|
||||
- [ ] **CI passes** — `make check && make test`
|
||||
|
||||
### Community Testing (Required)
|
||||
|
||||
- [ ] **At least 1 community member** has tested with a real API key
|
||||
- [ ] **Agent test report submitted** following the [test report template](templates/agent-test-report-template.md)
|
||||
- [ ] **Tool works in a real agent workflow** (not just isolated function calls)
|
||||
- [ ] **No blocking issues** reported in the test report
|
||||
|
||||
### Optional (Bonus)
|
||||
|
||||
- [ ] Multiple community test reports from different testers
|
||||
- [ ] Rate limit documentation
|
||||
- [ ] Integration tests with sandboxed API accounts
|
||||
- [ ] Pagination support for list endpoints
|
||||
- [ ] Webhook support (if applicable to the service)
|
||||
|
||||
## Promotion Process
|
||||
|
||||
1. **Contributor opens a PR** that checks off all required items above
|
||||
2. **PR description** includes links to: the tool README, the health checker, the test report(s)
|
||||
3. **Maintainer reviews** the checklist — every required item must be verified
|
||||
4. **Maintainer moves** the tool registration from `_register_unverified()` to `_register_verified()` in `tools/__init__.py`
|
||||
5. **Maintainer adds the `bounty:promote` label** to the PR — this triggers the GitHub Action to award 50 XP via Lurkr and post a Discord notification
|
||||
6. **Announcement** auto-posted in `#integrations-announcements` on Discord
|
||||
|
||||
## Current Status
|
||||
|
||||
### Tools Ready for Promotion Testing
|
||||
|
||||
The following 55 unverified tools have implementations, credential specs, and unit tests. They need documentation, health checks, and community testing to be promoted:
|
||||
|
||||
<details>
|
||||
<summary>Full list of unverified tools</summary>
|
||||
|
||||
airtable, apify, asana, attio, aws_s3, azure_sql, calendly, cloudinary, confluence,
|
||||
databricks, docker_hub, duckduckgo, gitlab, google_analytics, google_search_console,
|
||||
google_sheets, greenhouse, huggingface, jira, kafka, langfuse, linear, lusha,
|
||||
microsoft_graph, mongodb, n8n, notion, obsidian, pagerduty, pinecone, pipedrive,
|
||||
plaid, powerbi, pushover, quickbooks, reddit, redis, redshift, salesforce, sap,
|
||||
shopify, snowflake, supabase, terraform, tines, trello, twilio, twitter, vercel,
|
||||
yahoo_finance, youtube, youtube_transcript, zendesk, zoho_crm, zoom
|
||||
|
||||
</details>
|
||||
|
||||
### Gap Summary
|
||||
|
||||
| Gap | Count | Bounty Type |
|
||||
|-----|-------|-------------|
|
||||
| Missing README | ~41 | `bounty:docs` |
|
||||
| Missing health_check_endpoint | ~40 | `bounty:health-check` |
|
||||
| Missing HealthChecker class | ~40 | `bounty:health-check` |
|
||||
| No community test report | 55 | `bounty:agent-test` |
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
# Agent Test Report: {tool_name}
|
||||
|
||||
<!-- Submit this report as a comment on the bounty issue, or as a file in a PR. -->
|
||||
|
||||
## Summary
|
||||
|
||||
- **Tool tested:** `{tool_name}`
|
||||
- **Tester:** @{github_handle}
|
||||
- **Date:** {YYYY-MM-DD}
|
||||
- **Verdict:** Pass / Partial / Fail
|
||||
|
||||
## Environment
|
||||
|
||||
- **OS:** {e.g., macOS 15.2, Ubuntu 24.04}
|
||||
- **Python:** {e.g., 3.12.1}
|
||||
- **Hive version:** {commit hash or version}
|
||||
- **API tier:** {e.g., Free, Pro — relevant for rate limits}
|
||||
|
||||
## Credential Setup
|
||||
|
||||
- **Auth method:** {API key / OAuth / Bearer token}
|
||||
- **Health check result:** {Pass / Fail / No health checker available}
|
||||
- **Setup difficulty:** {Easy / Medium / Hard}
|
||||
- **Setup notes:** {Any friction, confusing docs, extra steps not documented}
|
||||
|
||||
## Agent Configuration
|
||||
|
||||
<!-- Describe the agent you built or used to test this tool. -->
|
||||
|
||||
```
|
||||
Agent name: {name}
|
||||
Tools used: {tool_name}, {any other tools}
|
||||
Goal: {What the agent was supposed to accomplish}
|
||||
```
|
||||
|
||||
## Test Results
|
||||
|
||||
### Tool Functions Tested
|
||||
|
||||
| Function | Input | Expected | Actual | Status |
|
||||
|----------|-------|----------|--------|--------|
|
||||
| `{function_name}` | {brief input description} | {expected behavior} | {what happened} | Pass/Fail |
|
||||
| `{function_name}` | {brief input description} | {expected behavior} | {what happened} | Pass/Fail |
|
||||
|
||||
### Agent Workflow Test
|
||||
|
||||
<!-- Did the agent successfully use this tool to accomplish a task? -->
|
||||
|
||||
**Goal:** {What you asked the agent to do}
|
||||
|
||||
**Result:** {What actually happened}
|
||||
|
||||
**Session ID:** `{session_id if available}`
|
||||
|
||||
### Edge Cases Found
|
||||
|
||||
<!-- Document any unexpected behavior, errors, or limitations. -->
|
||||
|
||||
| Edge Case | Behavior | Severity |
|
||||
|-----------|----------|----------|
|
||||
| {e.g., empty query} | {what happened} | Low/Medium/High |
|
||||
| {e.g., rate limit hit} | {what happened} | Low/Medium/High |
|
||||
|
||||
## Issues Found
|
||||
|
||||
<!-- List any bugs or problems. Link to new issues if you filed them. -->
|
||||
|
||||
- [ ] {Issue description} — {filed as #XXXX / not yet filed}
|
||||
- [ ] {Issue description}
|
||||
|
||||
## Recommendations
|
||||
|
||||
<!-- Suggestions for the tool maintainer. -->
|
||||
|
||||
- {e.g., "Error message for missing API key should include the help URL"}
|
||||
- {e.g., "Rate limit handling should retry with backoff"}
|
||||
- {e.g., "Ready for promotion after health checker is added"}
|
||||
|
||||
## Evidence
|
||||
|
||||
<!-- Attach or link to logs, screenshots, or recordings. At minimum, include the session ID or key log output. -->
|
||||
|
||||
<details>
|
||||
<summary>Logs</summary>
|
||||
|
||||
```
|
||||
{Paste relevant log output here}
|
||||
```
|
||||
|
||||
</details>
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
# {Tool Name} Tool
|
||||
|
||||
<!-- One-liner: what this tool does and what it enables agents to do. -->
|
||||
|
||||
{Brief description of what the tool does and its primary use case.}
|
||||
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
# Required
|
||||
export {ENV_VAR}=your-api-key
|
||||
```
|
||||
|
||||
**Get your key:**
|
||||
1. Go to {help_url}
|
||||
2. {Step to create/generate a key}
|
||||
3. {Step to copy the key}
|
||||
4. Set `{ENV_VAR}` environment variable
|
||||
|
||||
Alternatively, configure via the credential store (`CredentialStoreAdapter`).
|
||||
|
||||
<!-- If OAuth is supported, add: -->
|
||||
<!-- **OAuth:** This integration also supports OAuth2 via Aden. -->
|
||||
|
||||
## Tools ({count})
|
||||
|
||||
| Tool | Description |
|
||||
|------|-------------|
|
||||
| `{tool_function_name}` | {What it does} |
|
||||
| `{tool_function_name}` | {What it does} |
|
||||
|
||||
## Usage
|
||||
|
||||
### {Action name}
|
||||
|
||||
```python
|
||||
result = {tool_function_name}(
|
||||
param="value",
|
||||
)
|
||||
# Returns: {brief description of return value}
|
||||
```
|
||||
|
||||
### {Action name}
|
||||
|
||||
```python
|
||||
result = {tool_function_name}(
|
||||
param="value",
|
||||
)
|
||||
# Returns: {brief description of return value}
|
||||
```
|
||||
|
||||
## Scope
|
||||
|
||||
<!-- What this integration covers in its current form. -->
|
||||
|
||||
- {Capability 1}
|
||||
- {Capability 2}
|
||||
- {Capability 3}
|
||||
|
||||
## Rate Limits
|
||||
|
||||
<!-- Document known rate limits if applicable. Remove this section if not relevant. -->
|
||||
|
||||
| Tier | Limit |
|
||||
|------|-------|
|
||||
| Free | {X requests/minute} |
|
||||
| Paid | {Y requests/minute} |
|
||||
|
||||
## API Reference
|
||||
|
||||
- [{Service} API Docs]({url})
|
||||
@@ -0,0 +1,556 @@
|
||||
#!/usr/bin/env bun
|
||||
|
||||
/**
|
||||
* Bounty Tracker — calculates points from merged PRs and generates leaderboards.
|
||||
*
|
||||
* Modes:
|
||||
* notify — Post a Discord message for a single completed bounty (called by bounty-completed.yml)
|
||||
* leaderboard — Generate and post the weekly leaderboard (called by weekly-leaderboard.yml)
|
||||
*
|
||||
* Environment:
|
||||
* GITHUB_TOKEN — GitHub API token
|
||||
* GITHUB_REPOSITORY_OWNER — e.g. "adenhq"
|
||||
* GITHUB_REPOSITORY_NAME — e.g. "hive"
|
||||
* DISCORD_WEBHOOK_URL — Discord webhook for #integrations-announcements
|
||||
* LURKR_API_KEY — Lurkr Read/Write API key (for XP push)
|
||||
* LURKR_GUILD_ID — Discord server ID where Lurkr is installed
|
||||
* PR_NUMBER — (notify mode) The merged PR number
|
||||
*/
|
||||
|
||||
import { readFileSync } from "fs";
|
||||
import { join } from "path";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Types
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
interface Contributor {
|
||||
github: string;
|
||||
discord: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
interface GitHubLabel {
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface GitHubUser {
|
||||
login: string;
|
||||
}
|
||||
|
||||
interface GitHubPR {
|
||||
number: number;
|
||||
title: string;
|
||||
merged_at: string | null;
|
||||
labels: GitHubLabel[];
|
||||
user: GitHubUser;
|
||||
html_url: string;
|
||||
}
|
||||
|
||||
interface BountyResult {
|
||||
pr: GitHubPR;
|
||||
bountyType: string;
|
||||
points: number;
|
||||
difficulty: string;
|
||||
contributor: string;
|
||||
discordId: string | null;
|
||||
}
|
||||
|
||||
interface LeaderboardEntry {
|
||||
github: string;
|
||||
discordId: string | null;
|
||||
points: number;
|
||||
bounties: number;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Constants
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const POINTS: Record<string, number> = {
|
||||
"bounty:smoke-test": 10,
|
||||
"bounty:agent-test": 30,
|
||||
"bounty:docs": 20,
|
||||
"bounty:health-check": 25,
|
||||
"bounty:bug-fix": 40,
|
||||
"bounty:new-tool": 75,
|
||||
"bounty:promote": 50,
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// GitHub API
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function githubRequest<T>(
|
||||
endpoint: string,
|
||||
token: string,
|
||||
method: string = "GET",
|
||||
body?: unknown
|
||||
): Promise<T> {
|
||||
const headers: Record<string, string> = {
|
||||
Authorization: `Bearer ${token}`,
|
||||
Accept: "application/vnd.github.v3+json",
|
||||
"User-Agent": "bounty-tracker",
|
||||
};
|
||||
|
||||
if (body) {
|
||||
headers["Content-Type"] = "application/json";
|
||||
}
|
||||
|
||||
const options: RequestInit = { method, headers };
|
||||
if (body) {
|
||||
options.body = JSON.stringify(body);
|
||||
}
|
||||
|
||||
const response = await fetch(`https://api.github.com${endpoint}`, options);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`GitHub API request failed: ${response.status} ${response.statusText}`
|
||||
);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async function getPR(
|
||||
owner: string,
|
||||
repo: string,
|
||||
prNumber: number,
|
||||
token: string
|
||||
): Promise<GitHubPR> {
|
||||
return githubRequest<GitHubPR>(
|
||||
`/repos/${owner}/${repo}/pulls/${prNumber}`,
|
||||
token
|
||||
);
|
||||
}
|
||||
|
||||
async function getMergedBountyPRs(
|
||||
owner: string,
|
||||
repo: string,
|
||||
token: string,
|
||||
since?: string
|
||||
): Promise<GitHubPR[]> {
|
||||
// GitHub search API requires each label with special chars to be quoted individually.
|
||||
// Multiple label: qualifiers are OR'd together.
|
||||
const bountyLabels = Object.keys(POINTS)
|
||||
.map((l) => `label:"${l}"`)
|
||||
.join(" ");
|
||||
|
||||
const query = `repo:${owner}/${repo} is:pr is:merged ${bountyLabels}${since ? ` merged:>=${since}` : ""}`;
|
||||
|
||||
const result = await githubRequest<{ items: GitHubPR[] }>(
|
||||
`/search/issues?q=${encodeURIComponent(query)}&per_page=100&sort=updated&order=desc`,
|
||||
token
|
||||
);
|
||||
|
||||
return result.items;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Identity resolution
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Parse contributors.yml without a YAML dependency.
|
||||
// The format is simple enough to parse with regex:
|
||||
// contributors:
|
||||
// - github: jane-doe
|
||||
// discord: "123456789012345678"
|
||||
// name: Jane Doe
|
||||
function parseContributorsYaml(raw: string): Contributor[] {
|
||||
const contributors: Contributor[] = [];
|
||||
let current: Partial<Contributor> | null = null;
|
||||
|
||||
for (const line of raw.split("\n")) {
|
||||
const trimmed = line.trim();
|
||||
|
||||
if (trimmed.startsWith("- github:")) {
|
||||
if (current?.github && current?.discord) {
|
||||
contributors.push(current as Contributor);
|
||||
}
|
||||
current = { github: trimmed.replace("- github:", "").trim() };
|
||||
} else if (trimmed.startsWith("discord:") && current) {
|
||||
current.discord = trimmed.replace("discord:", "").trim().replace(/^["']|["']$/g, "");
|
||||
} else if (trimmed.startsWith("name:") && current) {
|
||||
current.name = trimmed.replace("name:", "").trim();
|
||||
}
|
||||
}
|
||||
|
||||
// Don't forget the last entry
|
||||
if (current?.github && current?.discord) {
|
||||
contributors.push(current as Contributor);
|
||||
}
|
||||
|
||||
return contributors;
|
||||
}
|
||||
|
||||
function loadContributors(): Map<string, Contributor> {
|
||||
const map = new Map<string, Contributor>();
|
||||
|
||||
try {
|
||||
// Resolve path relative to the script location (scripts/ dir → repo root)
|
||||
const scriptDir = new URL(".", import.meta.url).pathname;
|
||||
const raw = readFileSync(
|
||||
join(scriptDir, "..", "contributors.yml"),
|
||||
"utf-8"
|
||||
);
|
||||
const entries = parseContributorsYaml(raw);
|
||||
|
||||
for (const c of entries) {
|
||||
map.set(c.github.toLowerCase(), c);
|
||||
}
|
||||
} catch {
|
||||
console.warn("Warning: could not load contributors.yml");
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
function resolveDiscord(
|
||||
githubUsername: string,
|
||||
contributors: Map<string, Contributor>
|
||||
): string | null {
|
||||
const entry = contributors.get(githubUsername.toLowerCase());
|
||||
return entry?.discord ?? null;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Bounty extraction
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function extractBounty(
|
||||
pr: GitHubPR,
|
||||
contributors: Map<string, Contributor>
|
||||
): BountyResult | null {
|
||||
const labels = pr.labels.map((l) => l.name);
|
||||
|
||||
const bountyLabel = labels.find((l) => l.startsWith("bounty:"));
|
||||
if (!bountyLabel) return null;
|
||||
|
||||
const points = POINTS[bountyLabel];
|
||||
if (points === undefined) return null;
|
||||
|
||||
const difficulty =
|
||||
labels.find((l) => l.startsWith("difficulty:"))?.replace("difficulty:", "") ??
|
||||
"unknown";
|
||||
|
||||
return {
|
||||
pr,
|
||||
bountyType: bountyLabel.replace("bounty:", ""),
|
||||
points,
|
||||
difficulty,
|
||||
contributor: pr.user.login,
|
||||
discordId: resolveDiscord(pr.user.login, contributors),
|
||||
};
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Discord notifications
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function postToDiscord(
|
||||
webhookUrl: string,
|
||||
content: string,
|
||||
embeds?: unknown[]
|
||||
): Promise<void> {
|
||||
const body: Record<string, unknown> = { content };
|
||||
if (embeds) body.embeds = embeds;
|
||||
|
||||
const response = await fetch(webhookUrl, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Discord webhook failed: ${response.status} ${response.statusText}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function formatBountyNotification(bounty: BountyResult): string {
|
||||
const userMention = bounty.discordId
|
||||
? `<@${bounty.discordId}>`
|
||||
: `**${bounty.contributor}**`;
|
||||
|
||||
const typeEmoji: Record<string, string> = {
|
||||
"smoke-test": "\u{1F9EA}",
|
||||
"agent-test": "\u{1F916}",
|
||||
docs: "\u{1F4DD}",
|
||||
"health-check": "\u{1FA7A}",
|
||||
"bug-fix": "\u{1F41B}",
|
||||
"new-tool": "\u{1F527}",
|
||||
promote: "\u{2B50}",
|
||||
};
|
||||
|
||||
const emoji = typeEmoji[bounty.bountyType] ?? "\u{1F3AF}";
|
||||
|
||||
let msg = `${emoji} **Bounty Completed!**\n\n`;
|
||||
msg += `${userMention} completed a **${bounty.bountyType}** bounty (+${bounty.points} pts)\n`;
|
||||
msg += `PR: ${bounty.pr.html_url}\n`;
|
||||
|
||||
if (!bounty.discordId) {
|
||||
msg += `\n_\u{1F517} @${bounty.contributor}: link your Discord in \`contributors.yml\` to get pinged!_`;
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
function formatLeaderboard(entries: LeaderboardEntry[]): string {
|
||||
if (entries.length === 0) {
|
||||
return "No bounty completions this period.";
|
||||
}
|
||||
|
||||
const sorted = [...entries].sort((a, b) => b.points - a.points);
|
||||
const top10 = sorted.slice(0, 10);
|
||||
|
||||
const medals = ["\u{1F947}", "\u{1F948}", "\u{1F949}"];
|
||||
|
||||
let msg = "**\u{1F3C6} Integration Bounty Leaderboard**\n\n";
|
||||
|
||||
for (let i = 0; i < top10.length; i++) {
|
||||
const entry = top10[i];
|
||||
const rank = medals[i] ?? `**${i + 1}.**`;
|
||||
const name = entry.discordId
|
||||
? `<@${entry.discordId}>`
|
||||
: `**${entry.github}**`;
|
||||
msg += `${rank} ${name} — ${entry.points} pts (${entry.bounties} bounties)\n`;
|
||||
}
|
||||
|
||||
msg += `\n_${sorted.length} contributors total_`;
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Lurkr API — push XP to Discord leveling system
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const LURKR_BASE_URL = "https://api.lurkr.gg/v2";
|
||||
|
||||
interface LurkrLevelResponse {
|
||||
level: {
|
||||
level: number;
|
||||
xp: number;
|
||||
messageCount: number;
|
||||
};
|
||||
}
|
||||
|
||||
async function lurkrAddXP(
|
||||
guildId: string,
|
||||
userId: string,
|
||||
xp: number,
|
||||
apiKey: string
|
||||
): Promise<LurkrLevelResponse> {
|
||||
const response = await fetch(
|
||||
`${LURKR_BASE_URL}/levels/${guildId}/users/${userId}`,
|
||||
{
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-API-Key": apiKey,
|
||||
},
|
||||
body: JSON.stringify({ xp: { increment: xp } }),
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
const text = await response.text();
|
||||
throw new Error(`Lurkr API failed: ${response.status} ${text}`);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async function lurkrGetUser(
|
||||
guildId: string,
|
||||
userId: string,
|
||||
apiKey: string
|
||||
): Promise<LurkrLevelResponse | null> {
|
||||
const response = await fetch(
|
||||
`${LURKR_BASE_URL}/levels/${guildId}/users/${userId}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: { "X-API-Key": apiKey },
|
||||
}
|
||||
);
|
||||
|
||||
if (response.status === 404) return null;
|
||||
|
||||
if (!response.ok) {
|
||||
const text = await response.text();
|
||||
throw new Error(`Lurkr API failed: ${response.status} ${text}`);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async function awardLurkrXP(bounty: BountyResult): Promise<string | null> {
|
||||
const apiKey = process.env.LURKR_API_KEY;
|
||||
const guildId = process.env.LURKR_GUILD_ID;
|
||||
|
||||
if (!apiKey || !guildId) {
|
||||
console.log("Lurkr not configured (missing LURKR_API_KEY or LURKR_GUILD_ID), skipping XP push");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!bounty.discordId) {
|
||||
console.log(`No Discord ID for @${bounty.contributor}, cannot push Lurkr XP`);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await lurkrAddXP(guildId, bounty.discordId, bounty.points, apiKey);
|
||||
const msg = `Lurkr: +${bounty.points} XP \u2192 <@${bounty.discordId}> (now level ${result.level.level}, ${result.level.xp} XP)`;
|
||||
console.log(msg);
|
||||
return msg;
|
||||
} catch (err) {
|
||||
// Lurkr failure should not prevent the Discord notification from being sent
|
||||
console.error(`Lurkr XP push failed (non-fatal): ${err}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Leaderboard calculation
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function buildLeaderboard(
|
||||
bounties: BountyResult[]
|
||||
): LeaderboardEntry[] {
|
||||
const map = new Map<string, LeaderboardEntry>();
|
||||
|
||||
for (const b of bounties) {
|
||||
const key = b.contributor.toLowerCase();
|
||||
const existing = map.get(key);
|
||||
|
||||
if (existing) {
|
||||
existing.points += b.points;
|
||||
existing.bounties += 1;
|
||||
} else {
|
||||
map.set(key, {
|
||||
github: b.contributor,
|
||||
discordId: b.discordId,
|
||||
points: b.points,
|
||||
bounties: 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from(map.values());
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// CLI
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function main() {
|
||||
const mode = process.argv[2];
|
||||
|
||||
const token = process.env.GITHUB_TOKEN;
|
||||
const owner = process.env.GITHUB_REPOSITORY_OWNER;
|
||||
const repo = process.env.GITHUB_REPOSITORY_NAME;
|
||||
const webhookUrl = process.env.DISCORD_WEBHOOK_URL;
|
||||
|
||||
if (!token || !owner || !repo) {
|
||||
console.error(
|
||||
"Missing required env: GITHUB_TOKEN, GITHUB_REPOSITORY_OWNER, GITHUB_REPOSITORY_NAME"
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const contributors = loadContributors();
|
||||
|
||||
if (mode === "notify") {
|
||||
// Single bounty notification
|
||||
const prNumber = parseInt(process.env.PR_NUMBER ?? "", 10);
|
||||
if (!prNumber) {
|
||||
console.error("Missing PR_NUMBER env var");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const pr = await getPR(owner, repo, prNumber, token);
|
||||
if (!pr.merged_at) {
|
||||
console.log("PR not merged, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
const bounty = extractBounty(pr, contributors);
|
||||
if (!bounty) {
|
||||
console.log("No bounty label found, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`Bounty: ${bounty.bountyType} | ${bounty.points} pts | @${bounty.contributor}`
|
||||
);
|
||||
|
||||
// Push XP to Lurkr (before Discord notification so we can include level info)
|
||||
const lurkrMsg = await awardLurkrXP(bounty);
|
||||
|
||||
if (webhookUrl) {
|
||||
let msg = formatBountyNotification(bounty);
|
||||
if (lurkrMsg) {
|
||||
msg += `\n${lurkrMsg}`;
|
||||
}
|
||||
await postToDiscord(webhookUrl, msg);
|
||||
console.log("Discord notification sent");
|
||||
} else {
|
||||
console.log("No DISCORD_WEBHOOK_URL set, skipping Discord notification");
|
||||
console.log(formatBountyNotification(bounty));
|
||||
}
|
||||
} else if (mode === "leaderboard") {
|
||||
// Weekly leaderboard
|
||||
const since = process.env.SINCE_DATE;
|
||||
const prs = await getMergedBountyPRs(owner, repo, token, since);
|
||||
|
||||
console.log(`Found ${prs.length} merged bounty PRs`);
|
||||
|
||||
const bounties = prs
|
||||
.map((pr) => extractBounty(pr, contributors))
|
||||
.filter((b): b is BountyResult => b !== null);
|
||||
|
||||
const entries = buildLeaderboard(bounties);
|
||||
const msg = formatLeaderboard(entries);
|
||||
|
||||
console.log(msg);
|
||||
|
||||
if (webhookUrl) {
|
||||
await postToDiscord(webhookUrl, msg);
|
||||
console.log("Leaderboard posted to Discord");
|
||||
}
|
||||
} else {
|
||||
console.error("Usage: bounty-tracker.ts <notify|leaderboard>");
|
||||
console.error(" notify — Post Discord notification for a merged bounty PR");
|
||||
console.error(" leaderboard — Generate and post the leaderboard");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Run if invoked directly
|
||||
main().catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
// Export for testing
|
||||
export {
|
||||
extractBounty,
|
||||
buildLeaderboard,
|
||||
formatBountyNotification,
|
||||
formatLeaderboard,
|
||||
loadContributors,
|
||||
resolveDiscord,
|
||||
awardLurkrXP,
|
||||
lurkrAddXP,
|
||||
lurkrGetUser,
|
||||
POINTS,
|
||||
};
|
||||
export type {
|
||||
BountyResult,
|
||||
LeaderboardEntry,
|
||||
Contributor,
|
||||
GitHubPR,
|
||||
LurkrLevelResponse,
|
||||
};
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
# Creates GitHub labels for the Integration Bounty Program.
|
||||
# Usage: ./scripts/setup-bounty-labels.sh [owner/repo]
|
||||
# Requires: gh CLI authenticated
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
REPO="${1:-adenhq/hive}"
|
||||
|
||||
echo "Setting up bounty labels for $REPO..."
|
||||
|
||||
# Bounty type labels
|
||||
gh label create "bounty:smoke-test" --repo "$REPO" --color "0E8A16" --description "Bounty: run tool with real API key, report results (10 pts)" --force
|
||||
gh label create "bounty:agent-test" --repo "$REPO" --color "1D76DB" --description "Bounty: test tool in a real agent workflow (30 pts)" --force
|
||||
gh label create "bounty:docs" --repo "$REPO" --color "FBCA04" --description "Bounty: write or improve documentation (20 pts)" --force
|
||||
gh label create "bounty:health-check" --repo "$REPO" --color "D93F0B" --description "Bounty: add health check endpoint or checker (25 pts)" --force
|
||||
gh label create "bounty:bug-fix" --repo "$REPO" --color "B60205" --description "Bounty: fix a discovered bug (40 pts)" --force
|
||||
gh label create "bounty:new-tool" --repo "$REPO" --color "6F42C1" --description "Bounty: build a new integration from scratch (75 pts)" --force
|
||||
gh label create "bounty:promote" --repo "$REPO" --color "C2A000" --description "Bounty: complete full promotion checklist (50 pts)" --force
|
||||
|
||||
# Difficulty labels
|
||||
gh label create "difficulty:easy" --repo "$REPO" --color "BFD4F2" --description "Good first contribution" --force
|
||||
gh label create "difficulty:medium" --repo "$REPO" --color "D4C5F9" --description "Requires some familiarity" --force
|
||||
gh label create "difficulty:hard" --repo "$REPO" --color "F9D0C4" --description "Significant effort or expertise needed" --force
|
||||
|
||||
echo "Done. Labels created for $REPO."
|
||||
Reference in New Issue
Block a user