tokens-for-good 0.3.5 → 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/pipeline/01-research/PROMPT.md +78 -66
- package/pipeline/02-verify/PROMPT.md +32 -76
- package/pipeline/04-peer-review/PROMPT.md +48 -28
- package/src/cli.js +0 -0
- package/src/mcp-server.js +68 -159
package/package.json
CHANGED
|
@@ -1,47 +1,29 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Research an Organization for Fierce Philanthropy
|
|
2
2
|
|
|
3
3
|
## Your Role
|
|
4
4
|
|
|
5
|
-
You are a social impact research analyst
|
|
6
|
-
|
|
7
|
-
You recognize that the best social impact organizations follow a repeated cycle of four items:
|
|
8
|
-
|
|
9
|
-
1. **Theory of Change grounded in the social problem's negative consequences**
|
|
10
|
-
- Start from negative consequences, not activities or feel-good goals
|
|
11
|
-
- Build a causal chain from activities to short-term shifts to meaningful changes in negative consequences
|
|
12
|
-
- Make assumptions and risks explicit at each link
|
|
13
|
-
|
|
14
|
-
2. **Intervention implementation that actually follows the model**
|
|
15
|
-
- Every major activity should map onto a specific link in the Theory of Change
|
|
16
|
-
- Ensure fidelity vs adaptation is thought through
|
|
17
|
-
|
|
18
|
-
3. **Measurement focused on intermediate outcomes, ultimate outcomes, negative consequences, and counterfactuals**
|
|
19
|
-
- Measure how much you are reducing negative consequences, directly or through well-chosen proxies
|
|
20
|
-
- Intermediate outcomes: changes in behavior or action from earlier gains in knowledge, skills, or attitudes
|
|
21
|
-
- Ultimate outcomes: changes in condition or life status (reduced homelessness, improved health, economic stability)
|
|
22
|
-
- Counterfactual thinking: compare to what would have happened otherwise
|
|
23
|
-
|
|
24
|
-
4. **Feedback loop: learning that actually changes the organization's efforts**
|
|
5
|
+
You are a social impact research analyst for Fierce Philanthropy. You evaluate nonprofit organizations using Todd Manwaring's Social Impact Evaluation Framework. You are thorough, evidence-driven, and honest about what the data does and does not show.
|
|
25
6
|
|
|
26
7
|
## Instructions
|
|
27
8
|
|
|
28
9
|
### 1. Research the Organization
|
|
29
10
|
|
|
30
|
-
Using
|
|
11
|
+
Using web search and web fetch, thoroughly research:
|
|
31
12
|
|
|
32
|
-
1. The
|
|
33
|
-
2.
|
|
34
|
-
3. Independent evaluations —
|
|
35
|
-
4. Third-party reviews — GiveWell, Charity Navigator, GuideStar/Candid, news coverage
|
|
36
|
-
5. Financial data — ProPublica Nonprofit Explorer (search by EIN or
|
|
13
|
+
1. **The org's website** — homepage, about page, impact/results pages, annual reports
|
|
14
|
+
2. **Impact evidence** — published data, metrics, program evaluations
|
|
15
|
+
3. **Independent evaluations** — RCTs, quasi-experimental studies (search J-PAL, 3ie, Campbell Collaboration)
|
|
16
|
+
4. **Third-party reviews** — GiveWell, Charity Navigator, GuideStar/Candid, news coverage
|
|
17
|
+
5. **Financial data** — ProPublica Nonprofit Explorer (search by EIN or name), Form 990
|
|
37
18
|
|
|
38
19
|
**Research rules:**
|
|
39
|
-
- Only
|
|
40
|
-
- Only measured results with citations
|
|
20
|
+
- Only include DIRECT results from this organization or independent measurements of it
|
|
21
|
+
- Only include measured results with citations. No anecdotes, no modeling, no evidence from other organizations.
|
|
22
|
+
- Every factual claim must trace to a specific source URL you actually visited
|
|
41
23
|
|
|
42
24
|
### 2. Generate the Report
|
|
43
25
|
|
|
44
|
-
|
|
26
|
+
Follow this exact structure:
|
|
45
27
|
|
|
46
28
|
---
|
|
47
29
|
|
|
@@ -57,49 +39,50 @@ Generate the COMPLETE report following this exact format and section order:
|
|
|
57
39
|
|
|
58
40
|
#### PROMPT 1 — Organization and Social Problem Summary
|
|
59
41
|
|
|
60
|
-
Identify:
|
|
61
42
|
1. **Social Problem:** (less than 5 words)
|
|
62
43
|
2. **Population:** (who is affected)
|
|
63
44
|
3. **Location:** (where)
|
|
64
45
|
|
|
65
46
|
#### PROMPT 2 — Top 20 Negative Consequences
|
|
66
47
|
|
|
67
|
-
Create a table of the top 20 negative consequences of that social problem with that population in that location.
|
|
68
|
-
|
|
69
48
|
| # | Negative Consequence |
|
|
70
49
|
|---|----------------------|
|
|
71
50
|
|
|
51
|
+
List the top 20 negative consequences of that social problem for that population in that location.
|
|
52
|
+
|
|
72
53
|
#### PROMPT 3 — Intermediary vs Ultimate Outcome Classification
|
|
73
54
|
|
|
74
|
-
Keep
|
|
75
|
-
- **Intermediary:** changes in behavior
|
|
76
|
-
- **Ultimate:** changes in condition or life status (reduced
|
|
55
|
+
Keep all 20 items. Add a column classifying each as Intermediary or Ultimate Outcome.
|
|
56
|
+
- **Intermediary:** changes in behavior or action from gains in knowledge, skills, or attitudes
|
|
57
|
+
- **Ultimate:** changes in condition or life status (reduced poverty, improved health, economic stability)
|
|
77
58
|
|
|
78
59
|
Sort by Intermediary first, then Ultimate.
|
|
79
60
|
|
|
80
61
|
#### PROMPT 4 — Positive Results Shared by Organization
|
|
81
62
|
|
|
82
|
-
Keep the table with all columns. For each of the 20 negative consequences, does the organization share positive results?
|
|
63
|
+
Keep the table with all columns. For each of the 20 negative consequences, add a column: does the organization share positive results?
|
|
64
|
+
|
|
83
65
|
- Start each cell with "Yes.", "Partial.", or "No direct results shared."
|
|
84
|
-
- When Yes or Partial
|
|
85
|
-
-
|
|
86
|
-
- Every data point
|
|
66
|
+
- When Yes or Partial: include SPECIFIC data (percentages, sample sizes, time periods, study names)
|
|
67
|
+
- Only direct results from this organization, not from other orgs or modeling
|
|
68
|
+
- **CITATION RULES (critical):** Every data point MUST have its own inline citation `[Source Name](URL)`. If one cell contains two facts from different sources, include two separate citations. Never cite a general overview page for a specific statistic — cite the exact page where you found the number.
|
|
87
69
|
|
|
88
70
|
#### PROMPT 5 — Counterfactual Results
|
|
89
71
|
|
|
90
|
-
Keep the table with ALL previous columns
|
|
72
|
+
Keep the table with ALL previous columns. For each of the 20 negative consequences, add a column: does the organization share COUNTERFACTUAL results?
|
|
73
|
+
|
|
91
74
|
- Start each cell with "Yes.", "Partial.", or "No counterfactual results."
|
|
92
|
-
-
|
|
93
|
-
- Counterfactual = comparison to what would have happened without the intervention
|
|
94
|
-
-
|
|
75
|
+
- Describe study design (RCT, quasi-experimental, matched comparison), sample sizes, what the control/comparison group showed
|
|
76
|
+
- Counterfactual = comparison to what would have happened without the intervention. Before/after alone does not count.
|
|
77
|
+
- **Same citation rules as Prompt 4:** every data point gets its own inline citation to the specific page.
|
|
95
78
|
|
|
96
79
|
#### SUMMARY REPORT
|
|
97
80
|
|
|
98
81
|
**Section 1 — Our Recommendation**
|
|
99
82
|
|
|
100
|
-
Write a recommendation
|
|
83
|
+
Write a recommendation (2-4 sentences): lead with stance, state strongest evidence, note caveats if any.
|
|
101
84
|
|
|
102
|
-
|
|
85
|
+
Then include this scored checklist. Base score is out of 100. Counterfactuals are extra credit (max 120).
|
|
103
86
|
|
|
104
87
|
Base score (out of 100):
|
|
105
88
|
- [x] or [ ] a. Has Ultimate Outcome Goals (50 pts)
|
|
@@ -111,47 +94,76 @@ Extra credit:
|
|
|
111
94
|
- [x] or [ ] e. Measures Intermediate Counterfactual (10 pts)
|
|
112
95
|
- [x] or [ ] f. Measures Ultimate Counterfactual (10 pts)
|
|
113
96
|
|
|
114
|
-
**Score: [X]/100** (
|
|
97
|
+
**Score: [X]/100** (can exceed 100 with extra credit, max 120)
|
|
115
98
|
|
|
116
99
|
**Section 2 — The Social Problem**
|
|
117
|
-
|
|
100
|
+
Frame with specificity ("chronic malnutrition among children under 5 in rural sub-Saharan Africa", not just "poverty"). Include scale and cite prevalence data.
|
|
118
101
|
|
|
119
102
|
**Section 3 — The Solution**
|
|
120
|
-
|
|
103
|
+
What the organization actually does (not their mission statement). Explain the theory of change: how does activity X lead to outcome Y? Be specific about the intervention.
|
|
121
104
|
|
|
122
105
|
**Section 4 — Key Outputs**
|
|
123
|
-
|
|
106
|
+
Measured activities and direct products with specific numbers. Distinguish outputs (things produced) from outcomes (changes caused).
|
|
124
107
|
|
|
125
108
|
**Section 5 — Key Intermediate Outcomes**
|
|
126
|
-
|
|
109
|
+
Measurable short-to-medium term changes. Note whether data is self-reported or independently verified. Include any counterfactual data found.
|
|
127
110
|
|
|
128
111
|
**Section 6 — Key Ultimate Outcomes**
|
|
129
|
-
|
|
112
|
+
Long-term impact evidence only. This section may be thin. Do not pad it. If no ultimate outcome data exists, say so in one sentence.
|
|
130
113
|
|
|
131
114
|
**Section 7 — Continual Learning & Adaptation**
|
|
132
|
-
|
|
115
|
+
Documented program changes based on evidence. "They adapted" needs specifics: what changed, based on what data, when?
|
|
133
116
|
|
|
134
117
|
#### SOURCES
|
|
135
118
|
|
|
136
119
|
List all cited sources with full URLs:
|
|
137
120
|
1. [Source Name](Full URL) - Brief description of what was cited
|
|
138
|
-
2.
|
|
121
|
+
2. ...
|
|
122
|
+
|
|
123
|
+
End with: *Report prepared using Todd Manwaring's Social Impact Evaluation Framework for Fierce Philanthropy.*
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
### 3. Citation Rules (Read Carefully)
|
|
128
|
+
|
|
129
|
+
These rules are critical for report quality. Poorly attributed citations are the #1 reason reports fail review.
|
|
130
|
+
|
|
131
|
+
1. **One citation per fact.** If a sentence contains two claims from different sources, it needs two citations. Never bundle multiple facts under one link.
|
|
132
|
+
|
|
133
|
+
2. **Cite the specific page, not a general overview.** If you found "27% reduction" on the org's 2024 Annual Report page, cite that URL — not their homepage or about page.
|
|
134
|
+
|
|
135
|
+
3. **If you can't find a URL for a claim, don't include the claim.** No unsourced facts. If you read something during research but can't trace it to a specific page, leave it out.
|
|
139
136
|
|
|
140
|
-
|
|
141
|
-
*Report prepared using Todd Manwaring's Social Impact Evaluation Framework for Fierce Philanthropy.*
|
|
137
|
+
4. **Verify before citing.** After writing a claim with a citation, confirm the cited page actually contains that information. If it doesn't, find the correct source or remove the claim.
|
|
142
138
|
|
|
143
|
-
|
|
139
|
+
5. **Attribution matters.** Say "X reports that" when citing an org's own claims. Say "independent evaluation found" when citing third-party evidence. The distinction is load-bearing.
|
|
144
140
|
|
|
145
|
-
|
|
141
|
+
6. **Format:** `[Source Name](URL)` inline. The SOURCES section at the end must list every URL cited in the report.
|
|
146
142
|
|
|
147
|
-
###
|
|
143
|
+
### 4. Before-Submission Quality Checks
|
|
148
144
|
|
|
149
|
-
|
|
145
|
+
Run these checks before submitting. They are not optional.
|
|
150
146
|
|
|
151
|
-
|
|
147
|
+
**Structure:**
|
|
152
148
|
- [ ] All 5 prompt tables present and complete (20 rows each)
|
|
153
|
-
- [ ] All 7 summary sections present
|
|
154
|
-
- [ ]
|
|
155
|
-
- [ ]
|
|
156
|
-
|
|
157
|
-
|
|
149
|
+
- [ ] All 7 summary sections present with substantive content
|
|
150
|
+
- [ ] SOURCES section lists every URL cited inline
|
|
151
|
+
- [ ] Scored checklist adds up correctly
|
|
152
|
+
|
|
153
|
+
**Citations:**
|
|
154
|
+
- [ ] Every factual claim has its own inline citation
|
|
155
|
+
- [ ] Spot-check at least 5 citations: visit the URL and confirm the page says what you claim
|
|
156
|
+
- [ ] For any citation where the page doesn't support your claim, find the correct source or remove the claim
|
|
157
|
+
- [ ] No claims are cited to general overview pages when a specific report or data page exists
|
|
158
|
+
|
|
159
|
+
**Writing style:**
|
|
160
|
+
- [ ] No em dashes (—). Replace with periods, commas, or parentheses.
|
|
161
|
+
- [ ] No filler adjectives: seamless, robust, comprehensive, innovative, cutting-edge, holistic, game-changing
|
|
162
|
+
- [ ] No AI transitions: "It's worth noting", "Here's the thing", "Let's dive in", "Simply put"
|
|
163
|
+
- [ ] Replace "leverage" with "use", "utilize" with "use"
|
|
164
|
+
- [ ] Paragraphs under 4 sentences
|
|
165
|
+
- [ ] No superlatives unless backed by comparative data
|
|
166
|
+
|
|
167
|
+
### 5. Submit
|
|
168
|
+
|
|
169
|
+
Submit using `submit_report` with the full markdown as `report_markdown`. Include `estimated_tokens` (count web searches at ~1K tokens each, web fetches at ~2-5K each, your output at ~4 tokens/word, plus ~10K overhead).
|
|
@@ -1,113 +1,69 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Verify Citations (Standalone Re-verification)
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
- **Org name:** `{{ORG_NAME}}`
|
|
6
|
-
- **Research report:** The report from Step 1 (kept in memory from the previous step)
|
|
7
|
-
- **Research guidance:** The same methodology from Step 1
|
|
8
|
-
|
|
9
|
-
## Purpose
|
|
10
|
-
|
|
11
|
-
Step 1 generated the research report. This step verifies it. You are a fact-checker, not a rewriter. Your job is to test every citation, flag hallucinations, and correct factual errors. Do not change tone, structure, or style.
|
|
3
|
+
Use this methodology when re-verifying an existing report. During normal research, citation verification is built into the research prompt (Section 4, quality checks). This standalone step is for when a report needs a second verification pass.
|
|
12
4
|
|
|
13
5
|
## Instructions
|
|
14
6
|
|
|
15
7
|
### 1. Read the Report
|
|
16
8
|
|
|
17
|
-
Read the full research report. Note every inline citation `[Source Name](URL)` and every factual claim
|
|
9
|
+
Read the full research report. Note every inline citation `[Source Name](URL)` and every factual claim.
|
|
18
10
|
|
|
19
11
|
### 2. Test Every Citation
|
|
20
12
|
|
|
21
|
-
For each citation
|
|
13
|
+
For each citation, visit the URL using web fetch and verify:
|
|
22
14
|
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
15
|
+
- **URL loads** — Is it a real page (not 404, not a redirect to a homepage)?
|
|
16
|
+
- **Content matches** — Does the page actually say what the report claims? Quote the relevant passage.
|
|
17
|
+
- **Data is accurate** — Do the numbers match?
|
|
26
18
|
|
|
27
|
-
Record each
|
|
19
|
+
Record each check:
|
|
28
20
|
|
|
29
21
|
| # | Citation | URL Status | Content Match | Notes |
|
|
30
22
|
|---|----------|-----------|---------------|-------|
|
|
31
23
|
|
|
32
24
|
Status values:
|
|
33
25
|
- **VALID** — URL loads and content matches
|
|
34
|
-
- **BROKEN** — 404
|
|
35
|
-
- **MISMATCH** — URL loads but doesn't support the claim
|
|
36
|
-
- **PARTIAL** —
|
|
37
|
-
- **UNVERIFIABLE** — Paywalled
|
|
26
|
+
- **BROKEN** — 404 or page doesn't load
|
|
27
|
+
- **MISMATCH** — URL loads but doesn't support the claim
|
|
28
|
+
- **PARTIAL** — Some claims match, some don't
|
|
29
|
+
- **UNVERIFIABLE** — Paywalled or content not accessible
|
|
38
30
|
|
|
39
|
-
### 3.
|
|
31
|
+
### 3. Re-attribute Mismatches
|
|
40
32
|
|
|
41
|
-
|
|
33
|
+
For each MISMATCH or PARTIAL citation:
|
|
34
|
+
1. Use web search to find the correct source for the claim
|
|
35
|
+
2. If found: replace the citation URL with the correct one
|
|
36
|
+
3. If not found anywhere: remove the claim from the report or add a caveat ("This claim could not be independently verified")
|
|
42
37
|
|
|
43
|
-
|
|
44
|
-
- Named studies, RCTs, or evaluations that can't be found
|
|
45
|
-
- Program details (founding dates, staff names, locations) that contradict other sources
|
|
46
|
-
- Claims about independent evaluations when none exist
|
|
38
|
+
Do not leave misattributed citations in place.
|
|
47
39
|
|
|
48
|
-
### 4.
|
|
40
|
+
### 4. Check for Hallucinations
|
|
49
41
|
|
|
50
|
-
|
|
42
|
+
Search the web for claims that seem unusually specific:
|
|
43
|
+
- Statistics that don't appear in any source
|
|
44
|
+
- Named studies or RCTs that can't be found
|
|
45
|
+
- Program details that contradict other sources
|
|
51
46
|
|
|
52
|
-
|
|
53
|
-
- **[SEVERITY: MEDIUM]** — Misleading framing, outdated data, partially supported claims
|
|
54
|
-
- **[SEVERITY: LOW]** — Minor inaccuracies, rounding differences, ambiguous wording
|
|
47
|
+
### 5. Apply Corrections
|
|
55
48
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
For each HIGH or MEDIUM issue, write the exact correction:
|
|
49
|
+
For each issue:
|
|
59
50
|
|
|
60
51
|
```
|
|
61
52
|
### Correction [N]
|
|
62
53
|
**Location:** [First ~10 words of the problematic passage]
|
|
63
54
|
**Problem:** [What's wrong]
|
|
64
|
-
**
|
|
65
|
-
**Corrected:** [Fixed text]
|
|
55
|
+
**Fix:** [What was changed]
|
|
66
56
|
```
|
|
67
57
|
|
|
68
|
-
### 6.
|
|
69
|
-
|
|
70
|
-
Apply all corrections to produce a verified version of the report. Keep the result in memory for the next pipeline step (Humanize).
|
|
58
|
+
### 6. Output
|
|
71
59
|
|
|
72
|
-
|
|
60
|
+
Write the corrected report with a verification summary at the top:
|
|
73
61
|
|
|
74
62
|
```markdown
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
# Verification Log
|
|
78
|
-
|
|
79
|
-
## Citation Check Results
|
|
80
|
-
|
|
81
|
-
| # | Citation | URL Status | Content Match | Notes |
|
|
82
|
-
|---|----------|-----------|---------------|-------|
|
|
83
|
-
|
|
84
|
-
## Factual Issues Found
|
|
85
|
-
|
|
86
|
-
- [List each issue with severity]
|
|
87
|
-
|
|
88
|
-
## Corrections Applied
|
|
89
|
-
|
|
90
|
-
- [List each correction made]
|
|
91
|
-
|
|
92
|
-
## Summary
|
|
93
|
-
|
|
94
|
-
- Total citations checked: X
|
|
63
|
+
## Verification Summary
|
|
64
|
+
- Citations checked: X
|
|
95
65
|
- Valid: X | Broken: X | Mismatch: X | Partial: X
|
|
96
|
-
-
|
|
66
|
+
- Claims removed (unsourced): X
|
|
67
|
+
- Citations re-attributed: X
|
|
97
68
|
- Corrections applied: X
|
|
98
|
-
- Overall accuracy: HIGH / MEDIUM / LOW
|
|
99
|
-
|
|
100
|
-
---
|
|
101
|
-
|
|
102
|
-
[Full verified report below]
|
|
103
69
|
```
|
|
104
|
-
|
|
105
|
-
## Quality Checks
|
|
106
|
-
|
|
107
|
-
Before writing the output:
|
|
108
|
-
- [ ] Every citation URL was actually visited and checked
|
|
109
|
-
- [ ] The citation table is complete (no citations skipped)
|
|
110
|
-
- [ ] All HIGH and MEDIUM issues have written corrections
|
|
111
|
-
- [ ] Corrections were applied to the report text
|
|
112
|
-
- [ ] No new content was added (only corrections to existing content)
|
|
113
|
-
- [ ] The verification log accurately reflects all checks performed
|
|
@@ -1,67 +1,86 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
## Inputs
|
|
4
|
-
|
|
5
|
-
- **Report to review:** Provided by the `get_peer_review` MCP tool
|
|
6
|
-
- **Research guidance:** The same methodology from step 1
|
|
7
|
-
- **Writing style guide:** The same decontamination rules from step 3
|
|
1
|
+
# Peer Review — Instructions
|
|
8
2
|
|
|
9
3
|
## Purpose
|
|
10
4
|
|
|
11
|
-
You are reviewing another contributor's research report. Your job is to verify quality and catch problems before a human reviewer sees it. You are NOT the original researcher
|
|
5
|
+
You are reviewing another contributor's research report. Your job is to verify quality and catch problems before a human reviewer sees it. You are NOT the original researcher — you are a second pair of eyes.
|
|
12
6
|
|
|
13
7
|
## Instructions
|
|
14
8
|
|
|
15
|
-
### 1.
|
|
9
|
+
### 1. Check the Automated Fact-Check Results First
|
|
10
|
+
|
|
11
|
+
If automated fact-check results are included above the report, read them before diving into the report itself. Focus on:
|
|
12
|
+
- **Red flags** — these are specific problems the automated system detected (unsupported claims, dead links, self-reported data issues)
|
|
13
|
+
- **Fact support rate** — below 70% means many claims aren't backed by their cited sources
|
|
14
|
+
- **Avg trust score** — below 50% means citations are low-quality (self-reported, blog posts, dead links)
|
|
15
|
+
|
|
16
|
+
Use these results to target your spot-checks. If the automated system flagged specific unsupported claims, verify those first.
|
|
17
|
+
|
|
18
|
+
### 2. Read the Full Report
|
|
16
19
|
|
|
17
|
-
Read the entire report
|
|
20
|
+
Read the entire report. Note the org name, the scored checklist, and the overall recommendation.
|
|
18
21
|
|
|
19
|
-
###
|
|
22
|
+
### 3. Spot-Check Citations (3-5)
|
|
20
23
|
|
|
21
|
-
Pick 3-5 citation URLs from the report. For each:
|
|
24
|
+
Pick 3-5 citation URLs from the report (prioritize any flagged by the automated fact-check). For each:
|
|
22
25
|
- Visit the URL using web fetch
|
|
23
26
|
- Verify the page exists (not 404)
|
|
24
27
|
- Check that the source says what the report claims
|
|
28
|
+
- If a citation is wrong, search for the correct source. If the claim can't be sourced anywhere, remove it.
|
|
25
29
|
|
|
26
|
-
###
|
|
30
|
+
### 4. Check Report Structure
|
|
27
31
|
|
|
28
32
|
Verify:
|
|
29
|
-
- [ ] All 5 prompt sections present (PROMPT 1-5)
|
|
33
|
+
- [ ] All 5 prompt sections present (PROMPT 1-5) with 20 rows each
|
|
30
34
|
- [ ] All 7 summary sections present (Sections 1-7)
|
|
31
35
|
- [ ] SOURCES section exists with citations
|
|
32
|
-
- [ ]
|
|
33
|
-
- [ ]
|
|
36
|
+
- [ ] Every factual claim has its own inline citation `[Source Name](URL)`
|
|
37
|
+
- [ ] No claims cited to general overview pages when a specific report or data page exists
|
|
38
|
+
|
|
39
|
+
### 5. Evaluate Scoring
|
|
40
|
+
|
|
41
|
+
The scored checklist uses these weights. Verify the math and the evidence:
|
|
42
|
+
|
|
43
|
+
Base score (out of 100):
|
|
44
|
+
- a. Has Ultimate Outcome Goals (50 pts)
|
|
45
|
+
- b. Measures Intermediate Outcomes (10 pts)
|
|
46
|
+
- c. Measures Ultimate Outcomes (15 pts)
|
|
47
|
+
- d. Shows Continual Learning & Adaptation (25 pts)
|
|
48
|
+
|
|
49
|
+
Extra credit:
|
|
50
|
+
- e. Measures Intermediate Counterfactual (10 pts)
|
|
51
|
+
- f. Measures Ultimate Counterfactual (10 pts)
|
|
34
52
|
|
|
35
|
-
|
|
53
|
+
**Score: X/100** (can exceed 100 with extra credit, max 120)
|
|
36
54
|
|
|
37
|
-
|
|
55
|
+
Check:
|
|
38
56
|
- Are checked items supported by evidence in the report?
|
|
39
57
|
- Are unchecked items correctly unchecked (no evidence was found)?
|
|
40
|
-
- Does the score math add up
|
|
58
|
+
- Does the score math add up?
|
|
41
59
|
|
|
42
|
-
###
|
|
60
|
+
### 6. Look for Red Flags
|
|
43
61
|
|
|
44
62
|
- Suspiciously specific numbers with no citation
|
|
45
63
|
- Studies or evaluations that seem fabricated
|
|
46
64
|
- Copy-pasted content or generic filler
|
|
47
65
|
- Sections that are empty or trivially short
|
|
48
66
|
- Claims that contradict other parts of the report
|
|
67
|
+
- Em dashes, filler adjectives (robust, comprehensive, innovative), AI transitions
|
|
49
68
|
|
|
50
|
-
###
|
|
69
|
+
### 7. Assign a Score
|
|
51
70
|
|
|
52
71
|
| Score | When to use |
|
|
53
72
|
|-------|------------|
|
|
54
|
-
| **4
|
|
55
|
-
| **3
|
|
56
|
-
| **2
|
|
57
|
-
| **1
|
|
73
|
+
| **4 — Great** | Report is thorough, citations check out, scoring is correct. No changes needed. |
|
|
74
|
+
| **3 — Good with fixes** | Minor issues you can fix: broken citation, wrong score math, awkward phrasing, a checklist item that should be toggled, misattributed citation. **Fix the issues yourself** and submit the corrected report. |
|
|
75
|
+
| **2 — Needs redo** | Major problems: thin evidence across multiple sections, significant hallucinations, missing sections, fundamentally wrong scoring. Not fixable with minor edits. |
|
|
76
|
+
| **1 — Bad actor** | Garbage: copy-pasted nonsense, completely fabricated data, obvious gaming attempt. This flags the original author. Use sparingly and only when clearly warranted. |
|
|
58
77
|
|
|
59
|
-
###
|
|
78
|
+
### 8. Submit Your Review
|
|
60
79
|
|
|
61
80
|
Use `submit_peer_review` with:
|
|
62
|
-
- `claim_id`: The claim ID
|
|
81
|
+
- `claim_id`: The claim ID shown above
|
|
63
82
|
- `score`: Your score (1-4)
|
|
64
|
-
- `notes`: Brief explanation of your score
|
|
83
|
+
- `notes`: Brief explanation of your score. Mention which citations you checked and what you found.
|
|
65
84
|
- `updated_report`: If score is 3, include the full fixed report
|
|
66
85
|
|
|
67
86
|
## Important Rules
|
|
@@ -71,3 +90,4 @@ Use `submit_peer_review` with:
|
|
|
71
90
|
- Score 1 is for abuse. If you're unsure, use 2 instead.
|
|
72
91
|
- If you spot-check a citation and it's broken, that alone is a 3 (fix it), not a 2.
|
|
73
92
|
- Don't rewrite the report to match your style. Fix factual errors, not opinions.
|
|
93
|
+
- If the automated fact-check flagged issues, verify them. If the flags are correct, fix the citations (score 3) or flag the report (score 2) depending on severity.
|
package/src/cli.js
CHANGED
|
File without changes
|
package/src/mcp-server.js
CHANGED
|
@@ -4,7 +4,7 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { ApiClient } from './api-client.js';
|
|
6
6
|
import { detectPlatform, isSchedulable, getAutomationInstructions } from './platform.js';
|
|
7
|
-
import { loadState, updateState, isSnoozed, hasContributedToday, markContributed
|
|
7
|
+
import { loadState, updateState, isSnoozed, snoozeDays, hasContributedToday, markContributed } from './state.js';
|
|
8
8
|
import { readFileSync } from 'fs';
|
|
9
9
|
import { join, dirname } from 'path';
|
|
10
10
|
import { fileURLToPath } from 'url';
|
|
@@ -26,7 +26,7 @@ updateState({ platform });
|
|
|
26
26
|
|
|
27
27
|
const server = new McpServer({
|
|
28
28
|
name: 'tokens-for-good',
|
|
29
|
-
version: '0.
|
|
29
|
+
version: '0.1.0',
|
|
30
30
|
});
|
|
31
31
|
|
|
32
32
|
// --- No-key onboarding message ---
|
|
@@ -41,9 +41,7 @@ Walk them through setup:
|
|
|
41
41
|
|
|
42
42
|
3. **Add the key to their MCP config:** Update their tokens-for-good MCP configuration to include the key as an environment variable:
|
|
43
43
|
|
|
44
|
-
For Claude Code (
|
|
45
|
-
|
|
46
|
-
Mac/Linux:
|
|
44
|
+
For Claude Code (.mcp.json or settings.json):
|
|
47
45
|
\`\`\`json
|
|
48
46
|
{
|
|
49
47
|
"mcpServers": {
|
|
@@ -56,19 +54,6 @@ Mac/Linux:
|
|
|
56
54
|
}
|
|
57
55
|
\`\`\`
|
|
58
56
|
|
|
59
|
-
Windows:
|
|
60
|
-
\`\`\`json
|
|
61
|
-
{
|
|
62
|
-
"mcpServers": {
|
|
63
|
-
"tokens-for-good": {
|
|
64
|
-
"command": "cmd",
|
|
65
|
-
"args": ["/c", "npx", "-y", "tokens-for-good", "--mcp"],
|
|
66
|
-
"env": { "TFG_API_KEY": "tfg_live_their_key_here" }
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
\`\`\`
|
|
71
|
-
|
|
72
57
|
For Opencode (opencode.json):
|
|
73
58
|
\`\`\`json
|
|
74
59
|
{
|
|
@@ -82,7 +67,7 @@ For Opencode (opencode.json):
|
|
|
82
67
|
}
|
|
83
68
|
\`\`\`
|
|
84
69
|
|
|
85
|
-
For Cursor (
|
|
70
|
+
For Cursor (.cursor/mcp.json):
|
|
86
71
|
\`\`\`json
|
|
87
72
|
{
|
|
88
73
|
"mcpServers": {
|
|
@@ -95,13 +80,9 @@ For Cursor (\`.cursor/mcp.json\` in your project root):
|
|
|
95
80
|
}
|
|
96
81
|
\`\`\`
|
|
97
82
|
|
|
98
|
-
**
|
|
83
|
+
4. **Restart the session** after updating the config so the MCP server picks up the new key.
|
|
99
84
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
5. **Verify it loaded** by running \`/mcp\` — you should see \`tokens-for-good\` in the server list.
|
|
103
|
-
|
|
104
|
-
6. **Set up permissions for hands-free research:** After restarting, use the \`check_permissions\` tool to verify WebFetch and WebSearch are in the allowlist, and offer to add them if not. Without these permissions, every web request will pause for approval and the research won't complete unattended.
|
|
85
|
+
5. **For hands-free operation**, also add WebFetch and WebSearch to their tool allowlist so research runs without prompts.
|
|
105
86
|
|
|
106
87
|
Once set up, they can say "Research an org for Fierce Philanthropy" and the AI does the rest. Each org takes ~5 minutes and costs ~$0.20 in tokens.
|
|
107
88
|
|
|
@@ -125,10 +106,11 @@ How it works:
|
|
|
125
106
|
5. Another contributor's AI peer-reviews your report
|
|
126
107
|
6. A human reviewer finalizes it for the directory
|
|
127
108
|
|
|
128
|
-
Research pipeline (
|
|
129
|
-
-
|
|
130
|
-
-
|
|
131
|
-
-
|
|
109
|
+
Research pipeline (per org, all done by your AI):
|
|
110
|
+
- Research the org using web search + web fetch, following the 6-prompt methodology
|
|
111
|
+
- Score using a weighted checklist (100 pts base, 120 max with extra credit)
|
|
112
|
+
- Verify citations by visiting each URL before submitting
|
|
113
|
+
- Clean up writing style (no AI tells, no filler adjectives, no em dashes)
|
|
132
114
|
|
|
133
115
|
Contributor tiers:
|
|
134
116
|
- New: first 5 orgs, easy orgs only
|
|
@@ -144,21 +126,7 @@ Cost: ~$0.15-0.25 per org in tokens. Scale: 750K+ US nonprofits to research.`,
|
|
|
144
126
|
|
|
145
127
|
// --- Tools ---
|
|
146
128
|
|
|
147
|
-
server.tool('
|
|
148
|
-
if (!client) return { content: [{ type: 'text', text: 'Error: TFG_API_KEY not set.' }] };
|
|
149
|
-
|
|
150
|
-
try {
|
|
151
|
-
const result = await client.getNextAction();
|
|
152
|
-
if (result.action === 'review') {
|
|
153
|
-
return { content: [{ type: 'text', text: `Action: REVIEW\n\nYou have ${result.research_count} research submissions and ${result.review_count} peer reviews. Target ratio is 1:2 (research:review). Use get_peer_review to pick up a draft to review.` }] };
|
|
154
|
-
}
|
|
155
|
-
return { content: [{ type: 'text', text: `Action: RESEARCH\n\nYou have ${result.research_count} research submissions and ${result.review_count} peer reviews. You're clear to claim a new org. Use claim_org to get started.` }] };
|
|
156
|
-
} catch (err) {
|
|
157
|
-
return { content: [{ type: 'text', text: `Error: ${err.message}` }] };
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
server.tool('claim_org', 'Claim the next available nonprofit org to research. Call next_action first to check if you should review instead.', {
|
|
129
|
+
server.tool('claim_org', 'Claim the next available nonprofit org to research. Blocked if you have a pending peer review.', {
|
|
162
130
|
platform: z.string().optional().describe('Your platform (claude-code, opencode, cursor, windsurf, devin)'),
|
|
163
131
|
}, async ({ platform: plat }) => {
|
|
164
132
|
if (!client) return { content: [{ type: 'text', text: 'Error: TFG_API_KEY not set. Get your key at https://fierce-philanthropy-directory.laravel.cloud/contribute' }] };
|
|
@@ -166,7 +134,7 @@ server.tool('claim_org', 'Claim the next available nonprofit org to research. Ca
|
|
|
166
134
|
try {
|
|
167
135
|
const result = await client.claimOrg(plat || platform);
|
|
168
136
|
return {
|
|
169
|
-
content: [{ type: 'text', text: `Claimed: ${result.org.name}\nURL: ${result.org.url}\nDescription: ${result.org.description || 'N/A'}\nSource: ${result.org.source || 'N/A'}\nClaim ID: ${result.claim_id}\nExpires: ${result.expires_at}\n\
|
|
137
|
+
content: [{ type: 'text', text: `Claimed: ${result.org.name}\nURL: ${result.org.url}\nDescription: ${result.org.description || 'N/A'}\nSource: ${result.org.source || 'N/A'}\nClaim ID: ${result.claim_id}\nExpires: ${result.expires_at}\n\nNext steps:\n1. Call get_methodology with step="research" to get the full research instructions\n2. Follow the methodology to research this org using WebSearch and WebFetch\n3. The methodology includes citation verification and writing quality checks — complete them before submitting\n4. Submit with submit_report when done` }],
|
|
170
138
|
};
|
|
171
139
|
} catch (err) {
|
|
172
140
|
return { content: [{ type: 'text', text: `Error: ${err.message}` }] };
|
|
@@ -191,33 +159,20 @@ server.tool('get_methodology', 'Get the full research methodology, verification
|
|
|
191
159
|
}
|
|
192
160
|
});
|
|
193
161
|
|
|
194
|
-
server.tool('submit_report', 'Submit a completed research report for an org you claimed. You MUST include estimated_tokens
|
|
162
|
+
server.tool('submit_report', 'Submit a completed research report for an org you claimed. You MUST include estimated_tokens.', {
|
|
195
163
|
claim_id: z.string().describe('The claim ID from claim_org'),
|
|
196
164
|
report_markdown: z.string().describe('The full research report in markdown'),
|
|
165
|
+
estimated_tokens: z.number().describe('Estimated total tokens used: count web searches (~1K each), web fetches (~2-5K each), report output (~4 tokens/word), plus ~10K overhead'),
|
|
197
166
|
model_used: z.string().optional().describe('The model that generated this report'),
|
|
198
|
-
|
|
199
|
-
}, async ({ claim_id, report_markdown, model_used, estimated_tokens }) => {
|
|
167
|
+
}, async ({ claim_id, report_markdown, estimated_tokens, model_used }) => {
|
|
200
168
|
if (!client) return { content: [{ type: 'text', text: 'Error: TFG_API_KEY not set.' }] };
|
|
201
169
|
|
|
202
|
-
const tokenUsage = estimated_tokens ? { total_tokens: estimated_tokens } : null;
|
|
203
170
|
try {
|
|
204
|
-
const result = await client.submitReport(claim_id, report_markdown,
|
|
171
|
+
const result = await client.submitReport(claim_id, report_markdown, null, null, model_used);
|
|
205
172
|
markContributed();
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
let message = `Report submitted for ${result.org_name}!\n\nYour stats:\n- Total orgs: ${stats.total_orgs}\n- Tier: ${stats.tier}\n- Orgs remaining: ${result.orgs_remaining}\n\nYour report will now go through peer review. Thank you for contributing!`;
|
|
210
|
-
|
|
211
|
-
// Nudge to set up automation if they haven't already
|
|
212
|
-
if (!state.auto_schedule) {
|
|
213
|
-
if (isSchedulable(platform)) {
|
|
214
|
-
message += `\n\n---\n\nWant to make this automatic? You can schedule daily contributions so your spare tokens research nonprofits while you're away. Use the \`setup_automation\` tool or say "Set up automatic daily contributions" to get started.`;
|
|
215
|
-
} else {
|
|
216
|
-
message += `\n\n---\n\nWant to contribute regularly? You can set up a system cron to research an org automatically each day. Use the \`setup_automation\` tool to get instructions for your platform.`;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
return { content: [{ type: 'text', text: message }] };
|
|
173
|
+
return {
|
|
174
|
+
content: [{ type: 'text', text: `Report submitted for ${result.org_name}!\n\nYour stats:\n- Total orgs: ${result.contributor_stats.total_orgs}\n- Tier: ${result.contributor_stats.tier}\n- Orgs remaining: ${result.orgs_remaining}\n\nYour report will now go through peer review. Thank you for contributing!` }],
|
|
175
|
+
};
|
|
221
176
|
} catch (err) {
|
|
222
177
|
return { content: [{ type: 'text', text: `Submit error: ${err.message}${err.data?.validation_errors ? '\n' + err.data.validation_errors.join('\n') : ''}` }] };
|
|
223
178
|
}
|
|
@@ -228,8 +183,33 @@ server.tool('get_peer_review', 'Get a draft report assigned to you for peer revi
|
|
|
228
183
|
|
|
229
184
|
try {
|
|
230
185
|
const result = await client.getNextPeerReview();
|
|
186
|
+
let peerMethodology = '';
|
|
187
|
+
try {
|
|
188
|
+
peerMethodology = readFileSync(join(PIPELINE_DIR, '04-peer-review/PROMPT.md'), 'utf-8');
|
|
189
|
+
} catch {
|
|
190
|
+
peerMethodology = 'Score 1-4: 4=Great, 3=Good with fixes (submit corrected version), 2=Needs redo, 1=Bad actor.';
|
|
191
|
+
}
|
|
192
|
+
let factCheckNote = '';
|
|
193
|
+
if (result.automated_review?.summary) {
|
|
194
|
+
const s = result.automated_review.summary;
|
|
195
|
+
const lines = [
|
|
196
|
+
`\n\n## Automated Fact-Check Results`,
|
|
197
|
+
`Quality: ${s.overall_quality} | Fact support: ${Math.round(s.fact_support_rate * 100)}% | Avg trust: ${Math.round(s.avg_trust_score * 100)}%`,
|
|
198
|
+
`Facts checked: ${result.automated_review.facts_checked}/${result.automated_review.facts_extracted} | Citations rated: ${result.automated_review.citations_rated}`,
|
|
199
|
+
];
|
|
200
|
+
if (s.red_flags?.length > 0) {
|
|
201
|
+
lines.push(`\nRed flags:\n${s.red_flags.map(f => ` - ${f}`).join('\n')}`);
|
|
202
|
+
}
|
|
203
|
+
if (s.strengths?.length > 0) {
|
|
204
|
+
lines.push(`\nStrengths:\n${s.strengths.map(f => ` - ${f}`).join('\n')}`);
|
|
205
|
+
}
|
|
206
|
+
lines.push(`\nUse these results to focus your spot-checks on flagged areas.`);
|
|
207
|
+
factCheckNote = lines.join('\n');
|
|
208
|
+
} else if (result.automated_review) {
|
|
209
|
+
factCheckNote = `\n\nAutomated Fact-Check: ${result.automated_review.status} (no summary available yet)`;
|
|
210
|
+
}
|
|
231
211
|
return {
|
|
232
|
-
content: [{ type: 'text', text: `Peer review assigned:\nOrg: ${result.org.name}\nAuthor:
|
|
212
|
+
content: [{ type: 'text', text: `Peer review assigned:\nOrg: ${result.org.name}\nAuthor: ${result.author}\nClaim ID: ${result.claim_id}${factCheckNote}\n\n---\n\n${peerMethodology}\n\n---\n\n${result.report_markdown}\n\n---\n\nUse submit_peer_review with your score and notes.` }],
|
|
233
213
|
};
|
|
234
214
|
} catch (err) {
|
|
235
215
|
if (err.status === 404) {
|
|
@@ -279,33 +259,10 @@ server.tool('my_impact', 'See your personal contribution stats, tier, and histor
|
|
|
279
259
|
try {
|
|
280
260
|
const result = await client.getImpact();
|
|
281
261
|
const c = result.contributor;
|
|
282
|
-
const
|
|
262
|
+
const estimatedCost = (c.total_tokens / 1_000_000 * 3).toFixed(2);
|
|
283
263
|
|
|
284
264
|
return {
|
|
285
|
-
content: [{ type: 'text', text: `Your Impact (@${c.github_handle}):\n\nTier: ${c.tier}\nOrgs researched: ${c.total_orgs}\
|
|
286
|
-
};
|
|
287
|
-
} catch (err) {
|
|
288
|
-
return { content: [{ type: 'text', text: `Error: ${err.message}` }] };
|
|
289
|
-
}
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
server.tool('get_badge', 'Get a markdown badge for your GitHub README showing your Tokens for Good contribution stats.', {}, async () => {
|
|
293
|
-
if (!client) return { content: [{ type: 'text', text: 'Error: TFG_API_KEY not set.' }] };
|
|
294
|
-
|
|
295
|
-
try {
|
|
296
|
-
const result = await client.getImpact();
|
|
297
|
-
const c = result.contributor;
|
|
298
|
-
const tier = c.tier || 'new';
|
|
299
|
-
const orgCount = c.total_orgs || 0;
|
|
300
|
-
const label = `Tokens_for_Good`;
|
|
301
|
-
const message = `${orgCount}_org${orgCount !== 1 ? 's' : ''}_researched`;
|
|
302
|
-
const color = tier === 'gold' ? 'FFD700' : tier === 'silver' ? 'C0C0C0' : tier === 'bronze' ? 'CD7F32' : '54BC4B';
|
|
303
|
-
const badgeUrl = `https://img.shields.io/badge/${label}-${message}-${color}?style=flat`;
|
|
304
|
-
const linkUrl = `https://fierce-philanthropy-directory.laravel.cloud/contribute`;
|
|
305
|
-
const markdown = `[](${linkUrl})`;
|
|
306
|
-
|
|
307
|
-
return {
|
|
308
|
-
content: [{ type: 'text', text: `Add this badge to your GitHub README:\n\n\`\`\`markdown\n${markdown}\n\`\`\`\n\nPreview: ${markdown}\n\nTier: ${tier} | Orgs: ${orgCount}` }],
|
|
265
|
+
content: [{ type: 'text', text: `Your Impact (@${c.github_handle}):\n\nTier: ${c.tier}\nOrgs researched: ${c.total_orgs}\nEstimated donation: ~$${estimatedCost}\nAcceptance rate: ${c.acceptance_rate}%\nAutomation: ${c.has_schedule ? 'Active' : 'Not set up'}\n\nRecent:\n${result.claims?.slice(0, 5).map(cl => ` ${cl.organization?.name || 'Unknown'} - ${cl.status}`).join('\n') || 'None'}` }],
|
|
309
266
|
};
|
|
310
267
|
} catch (err) {
|
|
311
268
|
return { content: [{ type: 'text', text: `Error: ${err.message}` }] };
|
|
@@ -316,71 +273,13 @@ server.tool('setup_guide', 'Get setup instructions for Tokens for Good. Use this
|
|
|
316
273
|
return { content: [{ type: 'text', text: NO_KEY_INSTRUCTIONS }] };
|
|
317
274
|
});
|
|
318
275
|
|
|
319
|
-
server.tool('
|
|
320
|
-
return {
|
|
321
|
-
content: [{ type: 'text', text: `Set up Tokens for Good permissions and session hook. Read ~/.claude/settings.json and ensure it has:
|
|
322
|
-
|
|
323
|
-
1. **Permissions** — these entries in "permissions.allow" (merge with existing, keep other entries):
|
|
324
|
-
- "WebFetch"
|
|
325
|
-
- "WebSearch"
|
|
326
|
-
- "mcp__tokens-for-good__*"
|
|
327
|
-
|
|
328
|
-
2. **SessionStart hook** — add this to "hooks.SessionStart" (merge with existing hooks). It checks if the user has set up scheduled contributions and nudges them if not:
|
|
329
|
-
|
|
330
|
-
{
|
|
331
|
-
"hooks": {
|
|
332
|
-
"SessionStart": [
|
|
333
|
-
{
|
|
334
|
-
"matcher": "",
|
|
335
|
-
"hooks": [
|
|
336
|
-
{
|
|
337
|
-
"type": "command",
|
|
338
|
-
"command": "result=$(curl -sf -H \\"X-TFG-Api-Key: $TFG_API_KEY\\" \\"https://fierce-philanthropy-directory.laravel.cloud/api/research/schedule-status\\" 2>/dev/null) && echo \\"$result\\" | grep -q '\\"scheduled\\":false' && echo 'Tokens for Good: You have not set up scheduled daily research yet. Say \\"set up automation\\" to enable perpetual daily contributions via /schedule.' || true"
|
|
339
|
-
}
|
|
340
|
-
]
|
|
341
|
-
}
|
|
342
|
-
]
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
The hook reads TFG_API_KEY from the environment (set in .mcp.json env), curls the schedule-status endpoint, and only outputs a nudge if they haven't scheduled yet. Once they schedule, the hook goes silent.
|
|
347
|
-
|
|
348
|
-
3. **Skill** — create the file ~/.claude/skills/tfg/SKILL.md with this content:
|
|
349
|
-
|
|
350
|
-
---
|
|
351
|
-
name: tfg
|
|
352
|
-
description: Do charitable research for Fierce Philanthropy via Tokens for Good
|
|
353
|
-
---
|
|
354
|
-
|
|
355
|
-
Do charitable research for Fierce Philanthropy via Tokens for Good. Call next_action to check whether to research or review. Then follow its guidance: either claim_org + get_methodology + submit_report, or get_peer_review + submit_peer_review.
|
|
356
|
-
|
|
357
|
-
---
|
|
358
|
-
|
|
359
|
-
This lets the user type /tfg to start a research session.
|
|
360
|
-
|
|
361
|
-
After setting up everything, tell the user: "Done! Permissions, schedule reminder, and /tfg command are configured."` }],
|
|
362
|
-
};
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
server.tool('setup_automation', 'Get instructions for setting up automated daily contributions on your platform. For Claude Code, generates a /schedule prompt that calls the API directly (no MCP connector needed).', {
|
|
276
|
+
server.tool('setup_automation', 'Get instructions for setting up automated daily contributions on your platform.', {
|
|
366
277
|
frequency: z.enum(['hourly', 'daily', 'weekly']).optional().describe('How often to contribute'),
|
|
367
278
|
}, async ({ frequency }) => {
|
|
368
|
-
|
|
369
|
-
updateState({ auto_schedule: true });
|
|
370
|
-
if (client) {
|
|
371
|
-
try { await client.enableSchedule(); } catch { /* best effort */ }
|
|
372
|
-
}
|
|
373
|
-
const instructions = getAutomationInstructions(platform, frequency || 'daily', apiKey);
|
|
279
|
+
const instructions = getAutomationInstructions(platform, frequency || 'daily');
|
|
374
280
|
return { content: [{ type: 'text', text: instructions }] };
|
|
375
281
|
});
|
|
376
282
|
|
|
377
|
-
server.tool('snooze', 'Snooze the Tokens for Good session start prompt for a number of days.', {
|
|
378
|
-
days: z.number().min(1).max(30).describe('Number of days to snooze (1 = ask tomorrow, 7 = ask in a week)'),
|
|
379
|
-
}, async ({ days }) => {
|
|
380
|
-
snoozeDays(days);
|
|
381
|
-
return { content: [{ type: 'text', text: `Got it! Tokens for Good will stay quiet for ${days} day${days !== 1 ? 's' : ''}.` }] };
|
|
382
|
-
});
|
|
383
|
-
|
|
384
283
|
// --- Prompts (session start) ---
|
|
385
284
|
|
|
386
285
|
server.prompt('session_start', 'Check if you should research an org or complete a peer review', {}, async () => {
|
|
@@ -396,13 +295,28 @@ server.prompt('session_start', 'Check if you should research an org or complete
|
|
|
396
295
|
|
|
397
296
|
const state = loadState();
|
|
398
297
|
|
|
298
|
+
// Check for pending peer review first
|
|
299
|
+
if (client) {
|
|
300
|
+
try {
|
|
301
|
+
const review = await client.getNextPeerReview();
|
|
302
|
+
return {
|
|
303
|
+
messages: [{
|
|
304
|
+
role: 'user',
|
|
305
|
+
content: { type: 'text', text: `You have a pending peer review to complete before you can claim a new org. Use get_peer_review to see the report, then submit_peer_review with your score.` },
|
|
306
|
+
}],
|
|
307
|
+
};
|
|
308
|
+
} catch {
|
|
309
|
+
// No pending review, continue
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
399
313
|
if (isSnoozed()) {
|
|
400
314
|
return { messages: [{ role: 'user', content: { type: 'text', text: 'Tokens for Good is snoozed. No action needed.' } }] };
|
|
401
315
|
}
|
|
402
316
|
|
|
403
317
|
if (state.auto_schedule) {
|
|
404
318
|
try {
|
|
405
|
-
const impact = await client
|
|
319
|
+
const impact = await client?.getImpact();
|
|
406
320
|
const c = impact?.contributor;
|
|
407
321
|
return {
|
|
408
322
|
messages: [{
|
|
@@ -419,24 +333,19 @@ server.prompt('session_start', 'Check if you should research an org or complete
|
|
|
419
333
|
return { messages: [{ role: 'user', content: { type: 'text', text: 'Tokens for Good: You already contributed today. Nice work!' } }] };
|
|
420
334
|
}
|
|
421
335
|
|
|
422
|
-
// Check permissions before first research
|
|
423
|
-
const permNote = state.total_session_contributions === 0
|
|
424
|
-
? `\n\n**First time?** Before researching, use the \`check_permissions\` tool to make sure WebFetch and WebSearch are allowed — otherwise you'll get prompted for every web request.`
|
|
425
|
-
: '';
|
|
426
|
-
|
|
427
336
|
// Show the session start prompt
|
|
428
337
|
if (isSchedulable(platform)) {
|
|
429
338
|
return {
|
|
430
339
|
messages: [{
|
|
431
340
|
role: 'user',
|
|
432
|
-
content: { type: 'text', text: `Tokens for Good: Would you like to donate your spare tokens to research a nonprofit today?\n\n1. Set up automatic daily contributions (recommended)\n2. Just run one now\n3. Ask me tomorrow\n4. Ask me in a week\n\nUse setup_automation for option 1, claim_org for option 2
|
|
341
|
+
content: { type: 'text', text: `Tokens for Good: Would you like to donate your spare tokens to research a nonprofit today?\n\n1. Set up automatic daily contributions (recommended)\n2. Just run one now\n3. Ask me tomorrow\n4. Ask me in a week\n\nUse setup_automation for option 1, claim_org for option 2.` },
|
|
433
342
|
}],
|
|
434
343
|
};
|
|
435
344
|
} else {
|
|
436
345
|
return {
|
|
437
346
|
messages: [{
|
|
438
347
|
role: 'user',
|
|
439
|
-
content: { type: 'text', text: `Tokens for Good: Would you like to research a nonprofit org today? It takes about 5 minutes.\n\n1. Research an org now\n2. Ask me tomorrow\n3. Ask me in a week\n\nUse claim_org for option 1
|
|
348
|
+
content: { type: 'text', text: `Tokens for Good: Would you like to research a nonprofit org today? It takes about 5 minutes and costs ~$0.20 in tokens.\n\n1. Research an org now\n2. Ask me tomorrow\n3. Ask me in a week\n\nUse claim_org for option 1.` },
|
|
440
349
|
}],
|
|
441
350
|
};
|
|
442
351
|
}
|