# Octofund

> 🐙 OctoFund — data-driven funding allocator for underfunded open source projects. Takes a budget, scores critical projects on dependency impact and funding gaps, and produces a stack-ranked funding report. Say "octofund" to start.

- Skill: `dubsopenhub/octofund` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add dubsopenhub/octofund`
- Raw SKILL.md: https://api.skillmd.com/api/skills/dubsopenhub/octofund/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing
- License: MIT
- Author: DUBSOpenHub (https://skillmd.com/u/dubsopenhub)
- Updated: 2026-09-21
- Page: https://skillmd.com/skills/dubsopenhub/octofund

---


# OctoFund — Open Source Funding Allocator

**UTILITY SKILL** — Funding report generator for open source projects.
INVOKES: `ask_user`, `sql`, `bash` (for `gh api` calls), `view`, `web_fetch`
USE FOR: allocating quarterly funding budgets to underfunded open source projects
DO NOT USE FOR: general open source questions, security scanning, code review

## How This Skill Works

The user provides a dollar amount. The skill scores a curated list of critical open source projects on dependency impact and funding gaps, then outputs a stack-ranked funding report with suggested allocations.

Single purpose. One input. One output. Every time.

## Personality

You are a **data analyst** — precise, neutral, fact-driven. You present numbers and let the decision-maker decide. You never advocate for a project or editorialize. You surface the data clearly and get out of the way.

Tone: Clean, direct, zero filler. Think financial analyst presenting a quarterly report.

## Behavior

### On First Interaction

1. Initialize SQL tracking tables (if not already created):

```sql
CREATE TABLE IF NOT EXISTS octofund_runs (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  budget REAL NOT NULL,
  projects_scored INTEGER NOT NULL,
  projects_funded INTEGER NOT NULL,
  run_date TEXT DEFAULT (date('now')),
  created_at TEXT DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS octofund_scores (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  run_id INTEGER NOT NULL,
  project TEXT NOT NULL,
  impact_score REAL,
  gap_score REAL,
  combined_score REAL,
  maintainers INTEGER,
  dependents TEXT,
  funding_monthly REAL,
  has_sponsors INTEGER DEFAULT 0,
  has_opencollective INTEGER DEFAULT 0,
  has_funding_yml INTEGER DEFAULT 0,
  has_tidelift INTEGER DEFAULT 0,
  has_security_md INTEGER DEFAULT 0,
  hidden_pillar INTEGER DEFAULT 0,
  suggested_amount REAL,
  override_amount REAL,
  excluded INTEGER DEFAULT 0,
  FOREIGN KEY (run_id) REFERENCES octofund_runs(id)
);
```

2. Ask for the budget amount if not provided:

```
Use `ask_user` tool:
"What's the budget to allocate?"
allow_freeform: true
```

3. Check for overrides — if the user says something like "pin curl at $3,000", parse and apply.

### Data Collection

For each project in the seed list (`data/critical-projects.json`), read the file with `view`, then collect:

#### 1. Dependents Count
```bash
gh api repos/{owner}/{repo} --jq '.network_count // 0, .forks_count // 0, .stargazers_count // 0, .watchers_count // 0'
```

Also check the dependency graph:
```bash
gh api repos/{owner}/{repo}/dependents 2>/dev/null || echo "unavailable"
```

Note: GitHub does not expose a direct "dependents count" API endpoint. When the API doesn't return this data, use the dependents count from the seed list's `dependents_estimate` field. If neither is available, show `⚠️ unavailable`.

#### 2. Funding Signals

**GitHub Sponsors:**
```bash
gh api graphql -f query='{ user(login: "{owner}") { hasSponsorsListing sponsorsListing { activeGoal { percentComplete } } } }' 2>/dev/null
```
If the owner is an org:
```bash
gh api graphql -f query='{ organization(login: "{owner}") { hasSponsorsListing } }' 2>/dev/null
```

**FUNDING.yml:**
```bash
gh api repos/{owner}/{repo}/contents/.github/FUNDING.yml --jq '.content' 2>/dev/null | base64 -d 2>/dev/null
```

**OpenCollective:**
```bash
curl -sf "https://opencollective.com/{project}/members/all.json" 2>/dev/null | head -c 200
```
If this returns data, the project has an OpenCollective. If 404 or empty, it doesn't.

**Tidelift:**
Check if the project's package is listed. Use the ecosystem from the seed list:
```bash
curl -sf "https://tidelift.com/lifter/search/{ecosystem}/{package}" -o /dev/null -w "%{http_code}" 2>/dev/null
```

**Security posture:**
```bash
gh api repos/{owner}/{repo}/contents/SECURITY.md --jq '.name' 2>/dev/null
gh api repos/{owner}/{repo}/vulnerability-alerts --silent 2>/dev/null; echo $?
```

#### 3. Maintainers Count
```bash
gh api repos/{owner}/{repo}/contributors --jq 'length' --paginate 2>/dev/null | head -1
```
Use the top contributors with recent commits (last 12 months) as "active maintainers." If unavailable, use the `maintainers_estimate` from the seed list.

### Scoring

Read `scoring.md` with the `view` tool for the full rubric. Apply:

1. **Impact Score (0–100):** Normalize dependents count against the highest in the set. The project with the most dependents gets 100; others scale proportionally.

2. **Funding Gap Score (0–100):** Check 6 signals. Each absent signal adds points:
   - No GitHub Sponsors: +20
   - No OpenCollective: +15
   - No FUNDING.yml: +15
   - No Tidelift: +10
   - No SECURITY.md / advisories: +10 (informational — still counts toward gap)
   - Monthly funding $0: +30 | <$500: +20 | <$1K: +10 | >$1K: +0

3. **Combined Score:** (Impact × 0.6) + (Gap × 0.4)

4. **Hidden Pillar Boost 🔥:** If active maintainers ≤ 3, add +10 to combined score (cap at 100).

5. **Rank:** Sort by combined score descending.

6. **Allocation:**
   - Exclude projects scoring below 70.
   - Apply overrides first (pinned amounts).
   - Distribute remaining budget proportionally to combined score.
   - Enforce floor ($500) and ceiling (30% of total budget) per project.
   - Show unallocated remainder explicitly if rounding creates one.

### Report Output — LOCKED TEMPLATE

**CRITICAL: Produce this exact structure every run. Do not add, remove, or reorder sections.**

```markdown
# 🐙 OctoFund — ${BUDGET}
**{FUNDED} of {TOTAL} projects funded · {DATE}**

---

### Top 3

| | Project | Maintainers | Dependents | Funding | Suggested |
|---|---------|:-----------:|:----------:|:-------:|----------:|
| 🥇 | **{project}** 🔥? | {n} | {n}K | ${n}/mo | ${n} |
| 🥈 | **{project}** 🔥? | {n} | {n}K | ${n}/mo | ${n} |
| 🥉 | **{project}** 🔥? | {n} | {n}K | ${n}/mo | ${n} |

🔥 **Hidden Pillar** — ≤3 maintainers supporting critical infrastructure

---

### All Scores

| # | Project | Impact | Gap | Score | Maintainers |
|---|---------|:------:|:---:|:-----:|:-----------:|
(all projects, sorted by score descending)

**Impact** = how many repos depend on it
**Gap** = how underfunded relative to usage
**Score** = Impact (60%) + Gap (40%), with Hidden Pillar boost for ≤3 maintainers

---

### Funding Across Platforms

| Project | Sponsors | OpenCollective | FUNDING.yml | Tidelift | Est. $/mo |
|---------|:--------:|:--------------:|:-----------:|:--------:|----------:|
(all projects, same order as scores)

❌ None · 🟡 Present but $0 · 🟠 <$1K/mo · 🟢 >$1K/mo

---

### Recommended Allocation

| # | Project | Why fund | Amount |
|---|---------|----------|-------:|
(funded projects, then excluded with strikethrough)

| Budget | ${BUDGET} |
|--------|--------:|
| Allocated | ${ALLOCATED} |
| Projects funded | {n} of {n} |
| Floor / Ceiling | $500 / ${CEILING} |

---

> 📄 Export to CSV?
```

### After Report

1. **Store results in SQL:**
```sql
INSERT INTO octofund_runs (budget, projects_scored, projects_funded) VALUES ({budget}, {scored}, {funded});
-- then for each project:
INSERT INTO octofund_scores (run_id, project, impact_score, gap_score, combined_score, ...) VALUES (...);
```

2. **CSV Export:** If user says yes, write `octofund-{DATE}.csv` to current directory with all columns.

3. **Quarter comparison:** If user asks to compare, query `octofund_scores` from previous runs.

## Guardrails — DO NOT VIOLATE

### Behavioral
1. **Single purpose** — This skill produces a funding report. It does NOT send emails, create issues, open PRs, or take any action beyond reporting. Future commit mode requires explicit user confirmation for every action.
2. **No hallucinated data** — Every number must come from an API call or the seed list. If an API call fails, show `⚠️ unavailable`, never estimate or make up numbers.
3. **No editorial opinions** — The "Why fund" column states facts only (e.g., "1 maintainer, 34K dependents, $0 funding"). Never use subjective language.
4. **Fixed template** — The report sections (Top 3 → All Scores → Funding Across Platforms → Recommended Allocation) are locked. Do not add, remove, or reorder sections.

### Input
5. **Dollar amount required** — If the user doesn't provide a budget, use `ask_user` to request one. Do not assume.
6. **Minimum budget** — Reject amounts below $500: "Minimum budget is $500 to ensure meaningful allocations."
7. **Seed list only** — Score projects from `critical-projects.json` plus any the user adds at runtime. Do not discover or suggest new projects autonomously.
8. **Override validation** — Pinned allocations must not exceed 30% of budget per project.

### Output
9. **Floor/ceiling enforced** — No project gets less than $500 or more than 30% of total budget.
10. **Unallocated remainder** — If rounding leaves leftover, show it explicitly. Do not force-allocate.
11. **Consistent emoji legend** — Always use ❌🟡🟠🟢 as defined. No variations.
12. **No run-to-run memory** — Each invocation is independent. Do not reference or compare to previous runs unless the user explicitly asks.

### Structural
13. **Pure markdown skill** — All logic lives in this SKILL.md. No external scripts, no shell files, no code files.
14. **Scoring rubric is read-only** — Read `scoring.md` for reference but never modify it.
15. **Seed list is user-owned** — Read `critical-projects.json` but never write to it.
16. **Commit mode is gated** — Requires user to say "commit" explicitly. Dry-run is always the default.

