Turns Reddit complaints into a ranked shortlist of business opportunities.
Founder forums are full of people describing, in detail, a problem they already pay to work around — the price they hate, the tool that almost works, the manual step they repeat every week. That is the raw material of a product. But it is buried in thousands of threads a day, it is written as venting rather than as a spec, and by the time you scroll far enough to notice a pattern you have lost the afternoon.
Reading it by hand does not scale. Keyword alerts do not either: “expensive” and “I wish there was” match noise as readily as signal, and neither tells you whether anyone else in the thread agreed.
comments × 0.6 + score × 0.4 so discussion weighs more than upvotes.notifier.py appends to ~/idea-radar-output/alerts.log, plays a system sound, shows a Windows toast (with a MessageBox fallback), and POSTs a JSON summary to WEBHOOK_URL if one is set. Every channel fails silently; the scan never crashes because a notification did.COST, TIME, FRICTION, MISSING), direct quotes as pain evidence, the existing solutions named in the thread and why commenters say they fail, a differentiation angle, the target profile, the users worth contacting, a monetization model, and next actions.--local, which shells out to the Claude Code CLI and consumes no API credits.~/idea-radar-output/: TIER1_<date>.json, TIER2_<date>.json, ALL_<date>.json and RADAR_<date>.md. Output paths are resolved and checked against the output directory to block path traversal.http.server app bound to 127.0.0.1:8421 that lists and renders past runs. No build step, no framework. HOST, PORT and OUTPUT_DIR are read from the environment so the same file runs in a container.Dockerfile, a Procfile and a railway.json are included for running the dashboard as a long-lived service.flowchart LR
A["Collect<br/><small>PRAW or public JSON<br/>16 subreddits · 48 h</small>"] --> P["Pre-filter<br/><small>keyword pre-score 0–100<br/>cross-subreddit boost</small>"]
P --> B["Detect pain points<br/><small>Claude: API or local CLI<br/>strict JSON schema</small>"]
B --> C["Score<br/><small>signal · differentiation<br/>executability · timing</small>"]
C --> D["Shortlist<br/><small>Tier 1 ≥ 8 · Tier 2 6–7.9<br/>validate + dedupe 30 d</small>"]
D --> E["JSON + Markdown<br/><small>~/idea-radar-output</small>"]
E --> F["Dashboard<br/><small>localhost:8421</small>"]
--hours, with at least --min-comments comments, from each subreddit’s hot and new listings; the top comments of each surviving thread are fetched and attached.pre_score × signal_strength.[] when nothing is viable.| Layer | Choice |
|---|---|
| Language | Python 3.10+ (uses X \| None type syntax) |
| Reddit collection | urllib against Reddit’s public JSON endpoints; PRAW if installed and credentials are set |
| Analysis | Anthropic SDK (claude-sonnet-4-6 by default) or the Claude Code CLI via --local |
| Config | python-dotenv |
| Dashboard | Python standard library http.server, single-file HTML |
| Tests | unittest, run under pytest — stdlib only, no network, no credentials |
| CI | GitHub Actions, Ubuntu + Python 3.12 |
| Deployment | Dockerfile, Procfile, railway.json |
| Runners | run_radar.ps1 (full free-mode scan), open-radar.bat (dashboard) |
praw and anthropic are both optional imports. Only python-dotenv is installed by default; uncomment the others in requirements.txt if you want authenticated collection or API-based analysis.
git clone https://github.com/martinbouvet2000-tech/business-idea-radar.git
cd business-idea-radar
pip install -r requirements.txt
cp .env.example .env # optional — see below
Everything in .env is optional. With no Reddit credentials the scanner uses the public JSON endpoints; with no ANTHROPIC_API_KEY it auto-switches to --local if the Claude Code CLI is on your PATH.
| Variable | Required | Purpose |
|---|---|---|
REDDIT_CLIENT_ID |
No | Enables PRAW collection (faster, higher rate limits) |
REDDIT_CLIENT_SECRET |
No | Same |
REDDIT_USER_AGENT |
No | Defaults to RedditIdeaRadar/2.0 |
ANTHROPIC_API_KEY |
No | Required unless you use --local, --dry-run or --scrape-only |
WEBHOOK_URL |
No | If set, each Tier 1 idea is POSTed there as JSON |
HOST |
No | Dashboard bind address, defaults to 127.0.0.1 |
PORT |
No | Dashboard port, defaults to 8421 |
OUTPUT_DIR |
No | Where reports are read from, defaults to ~/idea-radar-output |
Scan and analyse:
# See what would be collected, analyse nothing
python reddit_idea_radar.py --dry-run
# Full run, analysis through the Anthropic API
python reddit_idea_radar.py
# Full run, analysis through the Claude Code CLI (no API credits)
python reddit_idea_radar.py --local
# Narrow the scan
python reddit_idea_radar.py --hours 24 --min-comments 30 --subreddits SaaS IndieHackers
Two-step free run (collect now, analyse later) — this is what run_radar.ps1 automates:
python reddit_idea_radar.py --scrape-only --hours 48
python reddit_idea_radar.py --from-file ~/idea-radar-output/THREADS_2026-01-31.json --local
Browse past runs:
python dashboard.py # http://localhost:8421
python dashboard.py 9000 # a different port
On Windows, run_radar.ps1 runs the full free-mode scan and open-radar.bat starts the dashboard and opens a browser.
All flags: --hours, --min-comments, --subreddits, --model, --dry-run, --scrape-only, --local, --from-file, --output.
pip install pytest
python -m pytest test_radar.py -v # or: python test_radar.py
60 tests covering the pure logic: thread pre-scoring, cross-subreddit signal detection, idea validation, tier classification, the JSON-extraction pattern used on model output, and the dedup filter. They use only the standard library — no network, no API key, no Reddit credentials — and run in CI on every push.
The parts that need the network or a model (scraping, Claude analysis, report rendering) are not covered.
docker build -t idea-radar .
docker run -p 8421:8421 -v "$HOME/idea-radar-output:/app/data" idea-radar
The image runs dashboard.py with HOST=0.0.0.0, PORT=8421 and OUTPUT_DIR=/app/data. Procfile and railway.json are there for platforms that expect them. The dashboard still has no authentication — put it behind something that does before exposing it.
This is a working prototype and a personal tool, not a product. Read it that way:
127.0.0.1 deliberately and reads files from your home directory. The container sets HOST=0.0.0.0 because it has to — do not expose that port publicly without putting auth in front of it.--from-file only accepts .json paths under your home directory, by design.pyproject.toml, no entry point, no published artifact — clone and run.MIT © Martin Bouvet