tokens-for-good 0.2.6 → 0.3.0
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/02-verify/PROMPT.md +5 -6
- package/pipeline/03-humanize/PROMPT.md +6 -6
- package/src/mcp-server.js +12 -5
- package/src/platform.js +10 -105
- package/src/state.js +4 -4
package/package.json
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
## Inputs
|
|
4
4
|
|
|
5
5
|
- **Org name:** `{{ORG_NAME}}`
|
|
6
|
-
- **Research report:**
|
|
7
|
-
- **Research guidance:**
|
|
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
8
|
|
|
9
9
|
## Purpose
|
|
10
10
|
|
|
@@ -65,12 +65,11 @@ For each HIGH or MEDIUM issue, write the exact correction:
|
|
|
65
65
|
**Corrected:** [Fixed text]
|
|
66
66
|
```
|
|
67
67
|
|
|
68
|
-
### 6. Apply Corrections and
|
|
68
|
+
### 6. Apply Corrections and Produce Output
|
|
69
69
|
|
|
70
|
-
Apply all corrections to produce a verified version of the report.
|
|
71
|
-
`{{ORG_SLUG}}_02_Verified.md`
|
|
70
|
+
Apply all corrections to produce a verified version of the report. Keep the result in memory for the next pipeline step (Humanize).
|
|
72
71
|
|
|
73
|
-
Start the
|
|
72
|
+
Start the output with a verification log:
|
|
74
73
|
|
|
75
74
|
```markdown
|
|
76
75
|
<!-- Verified: {{ORG_NAME}} | Date: [date] -->
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
## Inputs
|
|
4
4
|
|
|
5
5
|
- **Org name:** `{{ORG_NAME}}`
|
|
6
|
-
- **Verified report:**
|
|
7
|
-
- **Writing style guide:**
|
|
6
|
+
- **Verified report:** The verified report from Step 2 (kept in memory from the previous step)
|
|
7
|
+
- **Writing style guide:** The AI decontamination rules below
|
|
8
8
|
|
|
9
9
|
## Purpose
|
|
10
10
|
|
|
@@ -16,7 +16,7 @@ Step 2 verified the facts. This step makes the report sound human. You are an ed
|
|
|
16
16
|
|
|
17
17
|
Read the verified report (skip the verification log header, work on the content below the `---`).
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
The AI decontamination passes below are your checklist.
|
|
20
20
|
|
|
21
21
|
### 2. Run Each Pass
|
|
22
22
|
|
|
@@ -97,11 +97,11 @@ After all passes, verify you did NOT change:
|
|
|
97
97
|
- [ ] The SOURCES section
|
|
98
98
|
- [ ] Section separators (`---`)
|
|
99
99
|
|
|
100
|
-
### 4.
|
|
100
|
+
### 4. Produce Output
|
|
101
101
|
|
|
102
|
-
|
|
102
|
+
Keep the humanized report in memory. This is the final version that will be submitted via the `submit_report` tool.
|
|
103
103
|
|
|
104
|
-
Start with a change log:
|
|
104
|
+
Start the output with a change log:
|
|
105
105
|
|
|
106
106
|
```markdown
|
|
107
107
|
<!-- Humanized: {{ORG_NAME}} | Date: [date] -->
|
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 } from './state.js';
|
|
7
|
+
import { loadState, updateState, isSnoozed, hasContributedToday, markContributed, snoozeDays } 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.3.0',
|
|
30
30
|
});
|
|
31
31
|
|
|
32
32
|
// --- No-key onboarding message ---
|
|
@@ -359,6 +359,13 @@ server.tool('setup_automation', 'Get instructions for setting up automated daily
|
|
|
359
359
|
return { content: [{ type: 'text', text: instructions }] };
|
|
360
360
|
});
|
|
361
361
|
|
|
362
|
+
server.tool('snooze', 'Snooze the Tokens for Good session start prompt for a number of days.', {
|
|
363
|
+
days: z.number().min(1).max(30).describe('Number of days to snooze (1 = ask tomorrow, 7 = ask in a week)'),
|
|
364
|
+
}, async ({ days }) => {
|
|
365
|
+
snoozeDays(days);
|
|
366
|
+
return { content: [{ type: 'text', text: `Got it! Tokens for Good will stay quiet for ${days} day${days !== 1 ? 's' : ''}.` }] };
|
|
367
|
+
});
|
|
368
|
+
|
|
362
369
|
// --- Prompts (session start) ---
|
|
363
370
|
|
|
364
371
|
server.prompt('session_start', 'Check if you should research an org or complete a peer review', {}, async () => {
|
|
@@ -393,7 +400,7 @@ server.prompt('session_start', 'Check if you should research an org or complete
|
|
|
393
400
|
|
|
394
401
|
if (state.auto_schedule) {
|
|
395
402
|
try {
|
|
396
|
-
const impact = await client
|
|
403
|
+
const impact = await client.getImpact();
|
|
397
404
|
const c = impact?.contributor;
|
|
398
405
|
return {
|
|
399
406
|
messages: [{
|
|
@@ -420,14 +427,14 @@ server.prompt('session_start', 'Check if you should research an org or complete
|
|
|
420
427
|
return {
|
|
421
428
|
messages: [{
|
|
422
429
|
role: 'user',
|
|
423
|
-
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.${permNote}` },
|
|
430
|
+
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, snooze with days=1 for option 3, snooze with days=7 for option 4.${permNote}` },
|
|
424
431
|
}],
|
|
425
432
|
};
|
|
426
433
|
} else {
|
|
427
434
|
return {
|
|
428
435
|
messages: [{
|
|
429
436
|
role: 'user',
|
|
430
|
-
content: { type: 'text', text: `Tokens for Good: Would you like to research a nonprofit org today? It takes about 5 minutes
|
|
437
|
+
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, snooze with days=1 for option 2, snooze with days=7 for option 3.${permNote}` },
|
|
431
438
|
}],
|
|
432
439
|
};
|
|
433
440
|
}
|
package/src/platform.js
CHANGED
|
@@ -22,114 +22,19 @@ export function isSchedulable(platform) {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export function getSchedulePrompt(apiKey) {
|
|
25
|
-
|
|
25
|
+
const base = 'https://fierce-philanthropy-directory.laravel.cloud/api';
|
|
26
|
+
return `You are a research agent for Fierce Philanthropy's Tokens for Good program.
|
|
26
27
|
|
|
27
|
-
##
|
|
28
|
+
## Setup
|
|
29
|
+
API Base: ${base}
|
|
30
|
+
Auth header for all requests: X-TFG-Api-Key: ${apiKey}
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
## Instructions
|
|
33
|
+
1. Fetch the batch flow: WebFetch GET ${base}/research/schedule-instructions
|
|
34
|
+
2. Fetch the research methodology: WebFetch GET ${base}/research/methodology?step=research
|
|
35
|
+
3. Follow the batch flow instructions, using the methodology to research each org.
|
|
31
36
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
### 1. Claim an org
|
|
35
|
-
Use WebFetch to POST to /api/research/claim:
|
|
36
|
-
|
|
37
|
-
WebFetch URL: https://fierce-philanthropy-directory.laravel.cloud/api/research/claim
|
|
38
|
-
Method: POST
|
|
39
|
-
Headers: X-TFG-Api-Key: ${apiKey}, Content-Type: application/json
|
|
40
|
-
Body: {"platform": "claude-code-scheduled"}
|
|
41
|
-
|
|
42
|
-
This returns the org name, URL, description, and a claim_id. You have 30 minutes.
|
|
43
|
-
|
|
44
|
-
### 2. Research the org
|
|
45
|
-
Use WebSearch and WebFetch to thoroughly research the organization:
|
|
46
|
-
- The org's website, impact pages, annual reports
|
|
47
|
-
- Independent evaluations (RCTs, J-PAL, 3ie)
|
|
48
|
-
- Third-party reviews (GiveWell, Charity Navigator)
|
|
49
|
-
- Financial data (ProPublica Nonprofit Explorer)
|
|
50
|
-
|
|
51
|
-
### 3. Write the report
|
|
52
|
-
Follow the Fierce Philanthropy research methodology:
|
|
53
|
-
|
|
54
|
-
**PROMPT 1** - Org and Social Problem Summary (problem, population, location)
|
|
55
|
-
**PROMPT 2** - Top 20 Negative Consequences table
|
|
56
|
-
**PROMPT 3** - Classify each as Intermediary or Ultimate Outcome
|
|
57
|
-
**PROMPT 4** - Positive Results shared by the org (with citations)
|
|
58
|
-
**PROMPT 5** - Counterfactual Results (with citations)
|
|
59
|
-
|
|
60
|
-
**SUMMARY REPORT** with 7 sections:
|
|
61
|
-
1. Our Recommendation (with scored checklist)
|
|
62
|
-
2. The Social Problem
|
|
63
|
-
3. The Solution
|
|
64
|
-
4. Key Outputs
|
|
65
|
-
5. Key Intermediate Outcomes
|
|
66
|
-
6. Key Ultimate Outcomes
|
|
67
|
-
7. Continual Learning & Adaptation
|
|
68
|
-
|
|
69
|
-
**SOURCES** - All cited sources with full URLs
|
|
70
|
-
|
|
71
|
-
#### Scoring Checklist (use EXACTLY these criteria):
|
|
72
|
-
|
|
73
|
-
Base score (out of 100):
|
|
74
|
-
- [x] or [ ] a. Has Ultimate Outcome Goals (50 pts)
|
|
75
|
-
- [x] or [ ] b. Measures Intermediate Outcomes (10 pts)
|
|
76
|
-
- [x] or [ ] c. Measures Ultimate Outcomes (15 pts)
|
|
77
|
-
- [x] or [ ] d. Shows Continual Learning & Adaptation (25 pts)
|
|
78
|
-
|
|
79
|
-
Extra credit:
|
|
80
|
-
- [x] or [ ] e. Measures Intermediate Counterfactual (10 pts)
|
|
81
|
-
- [x] or [ ] f. Measures Ultimate Counterfactual (10 pts)
|
|
82
|
-
|
|
83
|
-
**Score: [X]/100** (can exceed 100 with extra credit, max 120)
|
|
84
|
-
|
|
85
|
-
### 4. Submit the report
|
|
86
|
-
Use WebFetch to POST to /api/research/submit:
|
|
87
|
-
|
|
88
|
-
WebFetch URL: https://fierce-philanthropy-directory.laravel.cloud/api/research/submit
|
|
89
|
-
Method: POST
|
|
90
|
-
Headers: X-TFG-Api-Key: ${apiKey}, Content-Type: application/json
|
|
91
|
-
Body: {"claim_id": <claim_id from step 1>, "report_markdown": "<full report>", "model_used": "claude-code-scheduled"}
|
|
92
|
-
|
|
93
|
-
### 5. Check next-action
|
|
94
|
-
After submitting, check if you need to do a peer review before continuing:
|
|
95
|
-
|
|
96
|
-
WebFetch URL: https://fierce-philanthropy-directory.laravel.cloud/api/research/next-action
|
|
97
|
-
Method: GET
|
|
98
|
-
Headers: X-TFG-Api-Key: ${apiKey}, Accept: application/json
|
|
99
|
-
|
|
100
|
-
If the response says action is "review", do the review:
|
|
101
|
-
|
|
102
|
-
**5a. Get the review:**
|
|
103
|
-
WebFetch URL: https://fierce-philanthropy-directory.laravel.cloud/api/research/review/next
|
|
104
|
-
Method: GET
|
|
105
|
-
Headers: X-TFG-Api-Key: ${apiKey}, Accept: application/json
|
|
106
|
-
|
|
107
|
-
**5b. Review the report** — score it 1-4 (4=great, 3=good with minor fixes, 2=needs redo, 1=bad actor)
|
|
108
|
-
|
|
109
|
-
**5c. Submit the review:**
|
|
110
|
-
WebFetch URL: https://fierce-philanthropy-directory.laravel.cloud/api/research/review/submit
|
|
111
|
-
Method: POST
|
|
112
|
-
Headers: X-TFG-Api-Key: ${apiKey}, Content-Type: application/json
|
|
113
|
-
Body: {"claim_id": <claim_id>, "score": <1-4>, "notes": "<review notes>", "updated_report": "<fixed report if score is 3>"}
|
|
114
|
-
|
|
115
|
-
### 6. Repeat (up to 3 orgs per session)
|
|
116
|
-
After completing each org (and any peer review), loop back to Step 1 and claim the next org.
|
|
117
|
-
Research up to 3 orgs total per session. After 3 orgs (or if no more are available), stop.
|
|
118
|
-
|
|
119
|
-
## Batch Flow Summary
|
|
120
|
-
\`\`\`
|
|
121
|
-
for i in 1..3:
|
|
122
|
-
claim org → research → submit report
|
|
123
|
-
check next-action → if review needed, do review
|
|
124
|
-
repeat
|
|
125
|
-
\`\`\`
|
|
126
|
-
|
|
127
|
-
### Rules
|
|
128
|
-
- Every factual claim needs an inline citation [Source Name](URL)
|
|
129
|
-
- Only use direct results from the org, not from similar orgs
|
|
130
|
-
- No anecdotes, only measured results
|
|
131
|
-
- Paragraphs under 4 sentences
|
|
132
|
-
- No em dashes, no filler adjectives, no AI tells`;
|
|
37
|
+
All endpoints, scoring criteria, and submission format are in the fetched instructions.`;
|
|
133
38
|
}
|
|
134
39
|
|
|
135
40
|
export function getAutomationInstructions(platform, frequency = 'daily', apiKey = null) {
|
package/src/state.js
CHANGED
|
@@ -64,8 +64,8 @@ export function hasContributedToday() {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
export function markContributed() {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
const state = loadState();
|
|
68
|
+
state.last_contributed = new Date().toISOString();
|
|
69
|
+
state.total_session_contributions = (state.total_session_contributions || 0) + 1;
|
|
70
|
+
saveState(state);
|
|
71
71
|
}
|