A solo-builder dashboard that scans Reddit and Hacker News for high-intent prospects, scores them, and drafts AI-generated replies — wired end-to-end through a Lemon Squeezy payment pipeline.
This is not a spam tool. Every reply is reviewed by a human before posting. The system exists to compress the discovery → qualification → outreach → checkout loop for a one-person digital product business.
- Discover — Scans Reddit (RSS) and Hacker News (Algolia API) on a schedule for posts mentioning configurable keywords (e.g. "need scraper", "looking for python automation", "willing to pay for").
- Qualify — Auto-scores every lead 0-100 based on recency, content depth, keyword density, high-intent phrases, and (for HN) post traction.
- Draft — Leads scoring 50+ trigger an AI reply draft via Gemini or OpenAI. Output is a natural, helpful comment — not a sales pitch.
- Convert — Reviewed replies link to a landing page hosted from the same dashboard. Checkout runs through Lemon Squeezy.
- Account — Lemon Squeezy webhooks (HMAC SHA-256 verified) update local analytics the moment an
order_createdevent lands. Daily CSV snapshots are written for backup and audit trail.
┌────────────────┐ ┌────────────────┐
│ Reddit RSS │ │ HN Algolia │
└────────┬───────┘ └────────┬───────┘
│ │
└──────────┬───────────┘
│
┌──────────▼──────────┐
│ Scraper scheduler │
│ (interval-driven) │
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ Lead pool (JSON) │
│ + dedupe + scoring │
└──────────┬──────────┘
│
score >= 50 ───┼─── score < 50
│ │
┌──────────▼─────┐ skip auto-draft
│ AI Draft Gen │
│ (Gemini/OpenAI)│
└──────────┬─────┘
│
┌──────────▼──────────┐
│ Dashboard (port │
│ 3000) — review, │
│ edit, mark sent │
└──────────┬──────────┘
│
prospect clicks
│
┌──────────▼──────────┐
│ Landing page │
│ /offer/:slug │
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ Lemon Squeezy │
│ checkout │
└──────────┬──────────┘
│ order_created
┌──────────▼──────────┐
│ Webhook handler │
│ (HMAC SHA-256) │
└──────────┬──────────┘
│
┌──────────▼──────────┐
│ Analytics + CSV │
│ snapshot │
└─────────────────────┘
I sell a few small digital products as a solo indie. The bottleneck is never "build the product" — it's qualified discovery. Manual Reddit + HN watching takes 60-90 minutes a day and most of it is filtering noise.
This system takes that 60-90 minutes down to ~10 minutes of human review per scan, with measurably better signal. The first 4 weeks of running it produced higher reply rates than my manual outreach because the AI draft removes the "blank page" friction that used to make me skip lukewarm leads.
| Feature | Detail |
|---|---|
| Multi-source scraping | Reddit RSS + HN Algolia, configurable subreddits & keywords |
| 0-100 scoring | Recency + length + keyword density + high-intent phrase + HN traction |
| Auto-draft | Threshold-gated AI reply generation (Gemini / OpenAI) |
| Dashboard UI | Live log stream, lead review, draft editor, status workflow |
| REST API | Full CRUD on leads, offers, settings, content, analytics |
| Landing pages | Server-rendered offer pages at /offer/:slug |
| Webhook receiver | Lemon Squeezy order_created with HMAC SHA-256 signature verification |
| CSV export | RFC 4180 compliant; manual download or daily snapshot to data/exports/ |
| Logs API | Last 100 events for the dashboard's terminal-style view |
| Auto-restart on boot | tmux session managed by ~/.wsl-agent-autostart.sh for unattended uptime |
Every lead gets a deterministic 0-100 score on every scan:
| Signal | Points (capped) |
|---|---|
| Posted < 24h ago | +30 |
| Posted < 72h ago | +20 |
| Posted < 7d ago | +10 |
| Body > 600 chars | +25 |
| Body > 200 chars | +15 |
| Body > 50 chars | +5 |
| Keyword match density | +5/match (cap 20) |
| High-intent phrase ("willing to pay", "$", "hire", "need a") | +5/match (cap 15) |
| HN post points > 5 | +5 |
| HN comments > 3 | +5 |
Score 50+ is the auto-draft threshold (configurable). Anything below is held for manual review, never auto-replied.
| Method | Path | Purpose |
|---|---|---|
| GET | /api/leads |
List all leads |
| POST | /api/leads/:id/status |
Update status (New / Drafted / Sent / Done) |
| POST | /api/leads/:id/draft |
Set replyDraft manually |
| POST | /api/leads/:id/ai-generate |
Generate AI draft via Gemini/OpenAI |
| POST | /api/scraper/scan |
Trigger Reddit + HN scan manually |
| GET | /api/leads/export.csv |
Download CSV (browser) |
| POST | /api/leads/export |
Snapshot CSV to data/exports/ |
| Method | Path | Purpose |
|---|---|---|
| POST | /api/webhooks/lemonsqueezy |
Receive order events, update analytics |
Signature verification: HMAC SHA-256 header X-Signature against settings.lemonsqueezyWebhookSecret.
| Method | Path | Purpose |
|---|---|---|
| GET / POST | /api/settings |
Runtime config |
| GET / POST / PUT | /api/offers[/:id] |
Manage micro-offers |
| GET / POST | /api/content |
Faceless content generation log |
| GET | /api/analytics |
Funnel + revenue counters |
| POST | /api/analytics/simulate-purchase |
Manual test purchase |
| GET | /api/logs |
Last 100 in-memory log events |
| GET | /offer/:slug |
Render offer landing page |
- Runtime: Node.js 18+
- Framework: Express 4
- Scraping: rss-parser (Reddit), Algolia public API (HN)
- AI: Gemini (default), OpenAI (alternate)
- Storage: JSON-on-disk (
data/*.json) + per-day CSV snapshots - Webhooks: HMAC SHA-256 signature verification
- Public exposure: Cloudflare Tunnel (free) for inbound webhook traffic
- Process supervision: tmux +
.bashrc-triggered autostart
The on-disk JSON store is intentional: this is a single-user system, the read/write rate is < 10 ops/sec, and the simplicity is a feature. If volume grows, the storage layer is one module (data/*.json accessors) and easy to swap for SQLite or Postgres.
git clone <repo_url>
cd stealth-ai
npm install
node server.js
# Dashboard at http://localhost:3000On first boot, all JSON databases self-seed with starter data. To run continuously:
# Detached tmux session
tmux new-session -d -s lead-discovery 'node server.js'
# Re-attach to view logs
tmux attach -t lead-discovery
# Ctrl+B then D to detach without killing it| Key | Default | Purpose |
|---|---|---|
apiProvider |
gemini |
gemini or openai |
apiKey |
(set) | LLM API key |
keywords |
(8 keywords) | Comma-separated, case-insensitive matching |
subreddits |
(8 subs) | Comma-separated subreddit list |
redditUserAgent |
(string) | UA header for Reddit RSS |
hackerNewsEnabled |
true |
Toggle HN Algolia scraper |
autoDraftEnabled |
false |
Auto-generate drafts on scan |
autoDraftMinScore |
50 |
Quality threshold for auto-draft |
lemonsqueezyWebhookSecret |
"" |
Signing secret from LS dashboard |
checkoutLink |
"" |
Lemon Squeezy URL (override per-offer) |
# 1. Tunnel local server to a public URL
cloudflared tunnel --url http://localhost:3000
# → note the https://*.trycloudflare.com URL
# 2. In Lemon Squeezy dashboard
# Settings → Webhooks → Add endpoint
# URL: https://*.trycloudflare.com/api/webhooks/lemonsqueezy
# Events: order_created (minimum)
# Copy the signing secret
# 3. Save the secret
curl -X POST http://localhost:3000/api/settings \
-H "Content-Type: application/json" \
-d '{"lemonsqueezyWebhookSecret": "ls_whsec_..."}'
# 4. Make a test purchase, then verify
tmux attach -t lead-discovery
# Look for "LS webhook: order ... confirmed."stealth-ai/
├── server.js # Express app, routes, scheduler
├── lib/
│ ├── hn-scraper.js # Hacker News Algolia client
│ ├── lead-utils.js # Dedupe + 0-100 quality scoring
│ ├── csv-export.js # RFC 4180 CSV writer
│ └── webhook.js # LS HMAC verification + order parser
├── public/ # Static dashboard (vanilla JS + CSS)
│ ├── index.html
│ ├── app.js
│ ├── style.css
│ └── offer-template.html # Server-rendered landing page
├── data/ # JSON persistence (gitignored)
│ ├── settings.json
│ ├── leads.json
│ ├── offers.json
│ ├── content.json
│ ├── analytics.json
│ └── exports/
└── package.json
# Live log tail
tmux attach -t lead-discovery
# Trigger scan now
curl -X POST http://localhost:3000/api/scraper/scan
# Export CSV
curl -X POST http://localhost:3000/api/leads/export
curl http://localhost:3000/api/leads/export.csv -o leads.csv
# Restart cleanly
tmux kill-session -t lead-discovery
cd ~/stealth-ai && tmux new-session -d -s lead-discovery 'node server.js'
# Syntax check before reboot
node -c server.js- Designing scoring heuristics that survive contact with messy real-world text
- Building webhook receivers correctly (HMAC verification, idempotency, replay safety)
- Running a long-lived Node.js service on a single laptop without losing data
- Letting AI write drafts without letting it post — keeping humans in the qualification loop
- Wiring discovery → qualification → outreach → checkout → analytics into one observable loop
- Reddit + HN multi-source scraping
- 0-100 quality scoring
- AI draft generation (Gemini + OpenAI)
- Lemon Squeezy webhook integration
- Daily CSV snapshots
- LinkedIn + IndieHackers scrapers
- Per-niche scoring profiles
- Postgres migration (when JSON file grows past ~5MB)
- Multi-user mode with auth
- Status: Active. Running on a developer laptop with daily Cloudflare Tunnel exposure for webhook reception.
- Disclaimer: This is a personal automation system, not a hosted SaaS. All AI drafts are human-reviewed before posting. The system follows each platform's API and content rules.
- Privacy: No PII is scraped beyond what is publicly posted. No emails are sent without explicit human action.
Built solo by @akwsa. Open to remote roles in Backend Engineering · Machine Learning · AI Automation. Based in Indonesia (UTC+7), full-time available.
Reach out via LinkedIn or email — see profile.