Claude-skill-reddit reddit-cultivate
Reddit account cultivation for indie developers. Uses AppleScript to control real Chrome — undetectable by anti-bot systems. Checks karma, finds rising posts, drafts comments, and posts directly. Triggers on "/reddit-cultivate", "check my reddit", "reddit maintenance", "find reddit opportunities", "build reddit karma".
git clone https://github.com/PHY041/claude-skill-reddit
T=$(mktemp -d) && git clone --depth=1 https://github.com/PHY041/claude-skill-reddit "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.claude/skills/reddit-cultivate" ~/.claude/skills/phy041-claude-skill-reddit-reddit-cultivate && rm -rf "$T"
.claude/skills/reddit-cultivate/SKILL.mdReddit Cultivation Skill (AppleScript Chrome Control)
Build and maintain Reddit presence by controlling the user's real Chrome browser via AppleScript. No Playwright, no Selenium, no API tokens.
How It Works
Claude Code → osascript → Chrome (real browser, logged in) → Reddit
- AppleScript executes JavaScript in Chrome's active tab
- Chrome is already logged into Reddit → cookies sent automatically
- Same-origin fetch → no CORS, no detection, no IP blocks
- Reddit cannot distinguish this from human browsing
Prerequisites
- macOS only (AppleScript is a macOS technology)
- Chrome: View → Developer → Allow JavaScript from Apple Events ✓ (restart Chrome after enabling)
- User logged into Reddit in Chrome
Method Detection (Run First)
Chrome multi-profile can cause AppleScript to not see windows. Always detect first:
WINDOWS=$(osascript -e 'tell application "Google Chrome" to return count of windows' 2>/dev/null) if [ "$WINDOWS" = "0" ] || [ -z "$WINDOWS" ]; then echo "Use Method 2 (System Events + Console)" else echo "Use Method 1 (execute javascript)" fi
Method 1: AppleScript Execute JavaScript (Preferred)
Works when
count of windows > 0.
Navigate
osascript -e 'tell application "Google Chrome" to tell active tab of first window to set URL to "https://www.reddit.com/r/SideProject/rising/"'
Execute JS & Read Result (document.title trick)
# Run JS that writes result to document.title osascript -e 'tell application "Google Chrome" to tell active tab of first window to execute javascript "fetch(\"/api/me.json\",{credentials:\"include\"}).then(r=>r.json()).then(d=>{document.title=\"R:\"+JSON.stringify({name:d.data.name,karma:d.data.total_karma})})"' # Wait, then read title sleep 2 osascript -e 'tell application "Google Chrome" to return title of active tab of first window'
JXA for Complex JS (avoids escaping hell)
osascript -l JavaScript -e ' var chrome = Application("Google Chrome"); var tab = chrome.windows[0].activeTab; tab.execute({javascript: "(" + function() { // Complex JS here — no escaping needed fetch("/r/SideProject/rising.json?limit=10", {credentials: "include"}) .then(r => r.json()) .then(d => { var posts = d.data.children.map(p => ({ title: p.data.title.substring(0, 60), score: p.data.score, comments: p.data.num_comments, id: p.data.name, url: "https://reddit.com" + p.data.permalink })); document.title = "POSTS:" + JSON.stringify(posts); }); } + ")();"}); '
Method 2: System Events + Console (Multi-Profile Fallback)
When AppleScript can't see Chrome windows (multi-profile bug), use keyboard automation.
Step 1: Copy JS to Clipboard
python3 -c " import subprocess js = '''(async()=>{ let resp = await fetch('/api/me.json', {credentials: 'include'}); let data = await resp.json(); document.title = 'R:' + JSON.stringify({name: data.data.name, karma: data.data.total_karma}); })()''' subprocess.run(['pbcopy'], input=js.encode(), check=True) "
Step 2: Execute via Chrome Console Keyboard Shortcuts
osascript -e ' tell application "System Events" tell process "Google Chrome" set frontmost to true delay 0.3 -- Cmd+Option+J = open/close Console key code 38 using {command down, option down} delay 1 -- Select all + Paste + Enter keystroke "a" using {command down} delay 0.2 keystroke "v" using {command down} delay 0.5 key code 36 delay 0.3 -- Close Console key code 38 using {command down, option down} end tell end tell'
Step 3: Read Title via System Events
sleep 3 osascript -e ' tell application "System Events" tell process "Google Chrome" return name of window 1 end tell end tell'
Workflow
Step 1: Check Account Status
Get username, karma, verify login using
/api/me.json.
Step 2: Scan Rising Posts
For each target subreddit, fetch rising posts:
/r/{subreddit}/rising.json?limit=10
Look for:
- Rising posts with < 15 comments (early = more visibility)
- Score > 2 (some traction)
- Questions you can answer or discussions with genuine insight
Step 3: Draft Comments
Rules:
- 2-4 sentences, natural tone
- Add genuine value (insights, experience, helpful info)
- No self-promotion, no links, no emojis
- Match the subreddit's culture
- Each comment must be unique
Step 4: Post All Comments
Get modhash, then post each comment with 4s delay between posts.
// Get modhash first let me = await fetch("/api/me.json", {credentials: "include"}).then(r=>r.json()); let uh = me.data.modhash; // Post comment let body = new URLSearchParams({ thing_id: "t3_xxxxx", // post fullname text: "Your comment here", uh: uh, api_type: "json" }); let resp = await fetch("/api/comment", { method: "POST", credentials: "include", headers: {"Content-Type": "application/x-www-form-urlencoded"}, body: body.toString() }); let result = await resp.json(); document.title = "POSTED:" + JSON.stringify(result);
Extract the comment ID from the response HTML: look for
id-t1_XXXXXXX in the result.
Step 5: Session Summary with Links
ALWAYS end with a summary table containing direct links to every comment posted.
The comment link format is:
https://www.reddit.com/r/{subreddit}/comments/{post_id}/comment/{comment_id}/
Where:
= the subreddit name{subreddit}
= the post ID (from{post_id}
minus thething_id
prefix)t3_
= extracted from the POST response (the{comment_id}
value, minust1_XXXXXXX
prefix)t1_
Example summary table:
| # | Sub | Post | Comment Link |
|---|---|---|---|
| 1 | r/SideProject | "Post title" | https://www.reddit.com/r/SideProject/comments/abc123/comment/xyz789/ |
| 2 | r/ClaudeAI | "Post title" | https://www.reddit.com/r/ClaudeAI/comments/def456/comment/uvw012/ |
This lets the user bookmark, follow up on replies, and track which comments got traction.
Recommended Target Subreddits
| Priority | Subreddit | Why |
|---|---|---|
| High | r/SideProject | Project launches, very welcoming |
| High | r/indiehackers | Revenue/growth discussions |
| Medium | r/ClaudeAI | AI tooling audience |
| Medium | r/coolgithubprojects | Open source visibility |
| Medium | r/startups | Startup discussions |
| Medium | r/entrepreneur | Business insights |
| Medium | r/opensource | Technical audience |
Comment Guidelines
- Add genuine value (insights, experience, helpful info)
- No self-promotion in comments
- Match the subreddit's tone
- Be specific, not generic
- 2-4 sentences, natural voice
Rate Limiting
| Action | Limit |
|---|---|
| Between API calls | 2+ seconds |
| Between posts | 4+ seconds |
| Per session | Max 5 comments |
| Daily | 10-15 comments max |
Karma Milestones
| Karma | Unlocks |
|---|---|
| 100+ | Can post in most subreddits |
| 500+ | Reduced spam filter triggers |
| 1000+ | Trusted contributor status |
| 5000+ | Community recognition |
Algorithm Insights
- First 30 minutes determine if post reaches Hot page
- Early upvotes weighted 10x more than later ones
- 2 early comments > 20 passive upvotes
- Best posting time: Sunday 6-8 AM ET
- Upvote ratio matters: 100↑/10↓ (90%) beats 150↑/50↓ (75%)
Troubleshooting
| Problem | Solution |
|---|---|
= 0 | Chrome multi-profile bug → use Method 2 |
| "Allow JavaScript" not working | Restart Chrome after enabling |
| Modhash expired | Re-fetch from |
| 403 response | Rate limited, wait 5+ minutes |
| Comment not appearing | Check for shadowban: visit profile in incognito |
Why AppleScript (Not Playwright/Selenium)
| Tool | Problem |
|---|---|
| Playwright | Sets , detected instantly |
| Selenium | Same detection issue |
| Puppeteer | Same detection issue |
| curl + API | IP blocked by Reddit after few requests |
| AppleScript | Controls real Chrome, undetectable, cookies included |