agentsclimarketplace

Charity grantor skill

Skill johnfitzy/charity-grantor-skill

Find NZ charities likely to make grants to Outward Bound NZ. Use this skill whenever the user wants to evaluate a list of NZ charities as potential funders or grant-makers for Outward Bound NZ — even if they just say "run the charity finder", "check these charities", "which of these would donate to Outward Bound", or hand you a CSV of charity names. The skill queries the NZ Charities Register and evaluates grant-making alignment.From its SKILL.md

Install
npx -y skills add johnfitzy/charity-grantor-skill

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

5.3 KB, ~1.2k tokens by cl100k_base, as published. Nobody here has run it

What this skill does

For each charity name in an input CSV, it:

  1. Queries the NZ Charities Register OData API via a helper script
  2. Evaluates alignment with Outward Bound NZ (grant-making likelihood)
  3. Appends results to an output CSV

No extra API keys or Python packages beyond httpx are needed — you do the evaluation reasoning directly.


Outward Bound NZ profile

Outward Bound NZ runs outdoor adventure and personal development courses for young New Zealanders. They build resilience, leadership, teamwork and life skills through wilderness experiences. They seek philanthropic grants from foundations and charitable trusts to fund youth participation.

Strong indicators a charity is a likely donor:

  • Activities includes "Makes grants to organisations"
  • Sectors/beneficiaries focus on: youth, education, sports/recreation, personal development, community, health
  • Operates within NZ (not exclusively overseas)
  • Has meaningful financial capacity (TotalGrossIncome, TotalAssets)

Negative signals:

  • Solely a service-delivery charity (no grant-making activities)
  • Activities exclusively overseas
  • Tightly restricted purpose incompatible with youth outdoor development

Step-by-step workflow

1. Identify inputs

Ask the user for:

  • Input CSV path — must have a Name column (or clarify which column holds charity names). prospects.csv in this project is a valid example.
  • Output CSV path — default to output.csv if not specified.

If the user already provided paths in their message, use those directly.

2. Read the input CSV

Read the CSV and identify the name column: prefer a column literally named name (case-insensitive), otherwise use the first column.

Announce how many charities you're about to process.

3. For each charity name — query the register

Run the helper script:

python charity-grantor-skill/scripts/search_charity.py "CHARITY NAME"

This prints a JSON array of up to 5 matching registered charities to stdout. Capture and parse it.

Edge cases:

  • Empty result array → mark as "not found", skip evaluation
  • Script error / network timeout → mark as "error", record the message
  • Charity name contains quotes or parentheses → they are already sanitised by the script, but avoid double-quoting when passing to the shell

4. Evaluate each result

Given the JSON results, determine:

  1. Which result (if any) matches the searched name. Use fuzzy judgement — "Rotary Club of Wellington" likely matches "Rotary Wellington". If uncertain, mark match_found as "uncertain".

  2. Whether that charity is likely to grant to Outward Bound NZ, using the criteria above. Be honest — most charities will be "no" or "uncertain". Reserve "yes" for clear grant-makers with aligned purpose.

Produce this evaluation object:

{
  "match_found": "yes" | "no" | "uncertain",
  "charity_name_in_register": "<matched name or empty>",
  "registration_number": "<CC-XXXX or empty>",
  "activities": "<Activities field value>",
  "sectors": "<Sectors field value>",
  "beneficiaries": "<Beneficiaries field value>",
  "charitable_purpose": "<CharitablePurpose field value>",
  "likely_donor": "yes" | "no" | "uncertain",
  "confidence": "high" | "medium" | "low",
  "reasoning": "<1-2 sentence explanation>"
}

5. Write the output CSV

  • Preserve all original columns from the input CSV
  • Append the evaluation columns: match_found, charity_name_in_register, registration_number, activities, sectors, beneficiaries, charitable_purpose, likely_donor, confidence, reasoning
  • Write a header row, then one row per input charity
  • Write incrementally if processing many charities (don't buffer everything in memory before writing)

6. Summarise results

After processing all rows, print a short summary:

Processed 42 charities → 8 likely donors, 12 uncertain, 22 no match / unlikely
Output written to output.csv

Handling large input files

If the input CSV has more than ~50 rows, consider asking the user whether they want to process in batches or run the full file. Processing is sequential and each row involves a network call, so large files take time. The OData endpoint has no rate limiting documented, but a short time.sleep(0.5) between requests is courteous — you can skip it if the user wants speed.


Helper script location

charity-grantor-skill/scripts/search_charity.py

Only dependency: httpx (already in requirements.txt).

To install if needed: pip install httpx


Notes on the OData API

  • Base URL: https://www.odata.charities.govt.nz/GrpOrgLatestReturns
  • Filter syntax: substringof('name',Name) — case-insensitive substring match
  • No authentication required
  • Results are under the d key in the JSON response
  • $format=json is required to get JSON (default is Atom/XML)

What ships with it: 4 files

3.6 KB alongside SKILL.md, 1 of them executable

scripts/

Keep looking

Skills are one crate of 326,512. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.