$npx -y skills add Varnan-Tech/opendirectory --skill reddit-icp-monitorWatches subreddits for people describing the exact problem you solve, scores their relevance to your ICP, and drafts a helpful non-spammy reply for each high-signal post. Use when asked to monitor Reddit for ICP signals, find prospects on Reddit, surface pain point posts, draft h
| 1 | # Reddit ICP Monitor |
| 2 | |
| 3 | Watch subreddits for people describing the problem you solve. Score their relevance. Draft a helpful reply for each match. |
| 4 | |
| 5 | --- |
| 6 | |
| 7 | **Critical rule:** Never invent post URLs, titles, or content. Every post in the output must come from a Reddit search result. Mark any section with no results as "No matches found." Never draft a reply to a post that was not returned by the search. |
| 8 | |
| 9 | **Anti-spam rule:** Drafted replies must never mention your product or company name unless the post explicitly asks for tool recommendations. Sound like a practitioner, not a marketer. |
| 10 | |
| 11 | --- |
| 12 | |
| 13 | ## Step 1: Setup Check |
| 14 | |
| 15 | ```bash |
| 16 | echo "GEMINI_API_KEY: ${GEMINI_API_KEY:+set}" |
| 17 | echo "REDDIT_CLIENT_ID: ${REDDIT_CLIENT_ID:-not set, using public endpoints (10 RPM)}" |
| 18 | ``` |
| 19 | |
| 20 | **If GEMINI_API_KEY is missing:** |
| 21 | Stop. Tell the user: "GEMINI_API_KEY is required. Get it at aistudio.google.com. Add it to your .env file." |
| 22 | |
| 23 | **If Reddit credentials are missing:** |
| 24 | Continue. Use Reddit's public JSON endpoints (no auth required, 10 RPM limit). For most monitoring sessions of 3-6 subreddit searches, this is sufficient. |
| 25 | |
| 26 | **If REDDIT_CLIENT_ID is set:** |
| 27 | Use OAuth for 60 RPM. Fetch a token first: |
| 28 | ```bash |
| 29 | TOKEN=$(curl -s -X POST \ |
| 30 | -d "grant_type=password&username=$REDDIT_USERNAME&password=$REDDIT_PASSWORD" \ |
| 31 | --user "$REDDIT_CLIENT_ID:$REDDIT_CLIENT_SECRET" \ |
| 32 | -H "User-Agent: varnan-skills/1.0" \ |
| 33 | https://www.reddit.com/api/v1/access_token \ |
| 34 | | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])") |
| 35 | ``` |
| 36 | Use `Authorization: Bearer $TOKEN` and `https://oauth.reddit.com` base URL for all subsequent requests. |
| 37 | |
| 38 | --- |
| 39 | |
| 40 | ## Step 2: Load ICP |
| 41 | |
| 42 | Check for an existing ICP file: |
| 43 | ```bash |
| 44 | ls docs/icp.md 2>/dev/null && echo "icp found" || echo "icp missing" |
| 45 | ``` |
| 46 | |
| 47 | **If docs/icp.md exists:** Read it. Extract: |
| 48 | - `product`: one-sentence product description |
| 49 | - `pain_points`: list of pain point phrases (exact buyer language) |
| 50 | - `anti_keywords`: phrases that disqualify a post |
| 51 | - `subreddits`: list of subreddits to search |
| 52 | |
| 53 | **If docs/icp.md does not exist:** Ask these 3 questions. Do not proceed until all 3 are answered: |
| 54 | 1. What does your product do? (one sentence) |
| 55 | 2. What subreddits does your ICP post in? (comma-separated, e.g. devops, startups, SaaS) |
| 56 | 3. What pain point phrases should trigger a match? (3-5 phrases in your buyer's own words, e.g. "onboarding takes forever", "can't see why users churn") |
| 57 | |
| 58 | After answers are collected, save to docs/icp.md in the canonical format from `references/icp-format.md`. Confirm: "ICP saved to docs/icp.md. It will be used automatically in future runs." |
| 59 | |
| 60 | Read `references/icp-format.md` for the canonical format and examples of good vs bad pain point phrases. |
| 61 | |
| 62 | --- |
| 63 | |
| 64 | ## Step 3: Search Reddit |
| 65 | |
| 66 | For each combination of subreddit and pain point phrase, run one search. Use public endpoints unless OAuth credentials are set. |
| 67 | |
| 68 | **Without OAuth (public endpoint):** |
| 69 | ```bash |
| 70 | curl -s \ |
| 71 | -H "User-Agent: varnan-skills/1.0" \ |
| 72 | "https://www.reddit.com/r/{SUBREDDIT}/search.json?q={PHRASE}&sort=new&t=week&limit=25&restrict_sr=true" \ |
| 73 | | python3 -c " |
| 74 | import sys, json |
| 75 | d = json.load(sys.stdin) |
| 76 | posts = d.get('data', {}).get('children', []) |
| 77 | for p in posts: |
| 78 | data = p['data'] |
| 79 | print(json.dumps({ |
| 80 | 'id': data['id'], |
| 81 | 'title': data['title'], |
| 82 | 'body': data.get('selftext', '')[:600], |
| 83 | 'url': 'https://reddit.com' + data['permalink'], |
| 84 | 'score': data['score'], |
| 85 | 'comments': data['num_comments'], |
| 86 | 'subreddit': data['subreddit'], |
| 87 | 'created_utc': data['created_utc'] |
| 88 | })) |
| 89 | " |
| 90 | ``` |
| 91 | |
| 92 | **With OAuth:** |
| 93 | Replace `https://www.reddit.com` with `https://oauth.reddit.com` and add `-H "Authorization: Bearer $TOKEN"`. |
| 94 | |
| 95 | **URL-encode the phrase** before inserting into the query string: |
| 96 | ```bash |
| 97 | ENCODED=$(python3 -c "import urllib.parse, sys; print(urllib.parse.quote(sys.argv[1]))" "{PHRASE}") |
| 98 | ``` |
| 99 | |
| 100 | **Time window defaults:** |
| 101 | - Default: `t=week` (last 7 days) |
| 102 | - User says "today" or "last 24 hours": `t=day` |
| 103 | - User says "this month": `t=month` |
| 104 | |
| 105 | **After all searches:** |
| 106 | - Collect all posts into one list |
| 107 | - Deduplicate by post ID. If the same post matches multiple phrases, keep it once and note all matching phrases. |
| 108 | - If a search returns 0 posts: note it and continue. Do not stop. |
| 109 | |
| 110 | State the total candidate count before scoring: "Found X cand |