/run
Run the daily Reddit pain-post surface. Fetch new posts from configured subs, score by intent/keyword/freshness, optionally classify via Claude Haiku, dedup against history, hold in cooling queue, and emit inline markdown (plus optional Notion sync). Triggers on "run subscope",
$ npx -y skills add dancolta/subscope --skill run --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/run
Context preview
The summary Claude sees to decide when to auto-load this skill.
Run the daily Reddit pain-post surface. Fetch new posts from configured subs, score by intent/keyword/freshness, optionally classify via Claude Haiku, dedup against history, hold in cooling queue, and emit inline markdown (plus optional Notion sync). Triggers on "run subscope",
SKILL.md
run.SKILL.mdname: subscope-run
description: Run the daily Reddit pain-post surface. Fetch new posts from configured subs, score by intent/keyword/freshness, optionally classify via Claude Haiku, dedup against history, hold in cooling queue, and emit inline markdown (plus optional Notion sync). Triggers on "run subscope", "/subscope run", "daily reddit", "scan reddit", "show today's reddit posts", or the default `/subscope-run` invocation.
allowed-tools: Bash, Read, Write
/subscope-run
Daily Reddit surfacing orchestrator. Python (under `engine/`) does fetch + gate + score + SQLite + JSON output. This skill is the Claude-side wrapper: it invokes the engine, optionally syncs to Notion (if configured), and prints the inline list to chat.
Preflight
1. Check whether user has personalized targeting at `~/.config/subscope/subreddits.yml`. If missing, the engine still runs using bundled generic defaults, but results will be off-target. Recommend `/subscope-onboard` (one conversation, ~5 min, includes the first scan) with a one-line nudge: `(no personal targeting found, scanning with generic defaults. /subscope-onboard for sharper results.)` Proceed with the run unless user explicitly cancels.
Daily run procedure
Step 1: Fetch + candidates (Python engine)
cd "$CLAUDE_PLUGIN_ROOT" && PYTHONPATH=engine python3 -m subscope.cli fetch-score --candidates
Engine output: a single JSON document on stdout with `run_id`, `status`, `fetched`, `surfaced`, `buyer_count`, `authority_count`, `subs_skipped_rate_limit`, `fetch_stats`, `dropped_counts`, `surfaces[]`, `inline_table`, `inline_markdown`, and (with `--candidates`) a `candidates[]` array plus `candidate_count` / `candidate_total`.
`candidates[]` is the recall pre-filter: every fetched post that cleared the absolute rejects (NSFW, removed/locked, vendor-spam, off-topic-sub, tier-3), each with deterministic features: `title`, `body`, `url`, `sub`, `tier`, `age_h`, `kw_hits`, `matched_kw`, `names_brand` (matched against the user's `brand_anchor`), `question_intent`, `pain_intent`, `engagement_available`, `soft_reason`. The engine deliberately does NOT decide relevance for these. **You do, in Step 3.5.** The engine's own `surfaces[]`/`inline_table` are the older lexical-gate output; under judge-first they are a secondary signal, not the chat output.
The `status` field tells you why a run produced few or no surfaces, so you never show the wrong message:
- `status: "ok"` and `surfaced > 0` -> normal run, render the table (Step 4).
- `status: "ok"` and `surfaced == 0` -> Reddit was reachable, today was just quiet. Show the EMPTY-DAY copy below.
- `status: "rate_limited"` -> Reddit rate-limited this run (HTTP 429). Some subreddits may have been skipped (`subs_skipped_rate_limit` says how many), so the list can be partial or empty. This is transient. Render any surfaces you DID get, then show the RATE-LIMITED copy below. Do NOT call this "blocked".
- `status: "blocked"` -> every Reddit feed request failed for a non-rate-limit reason (Reddit's edge returned 403, or the network was down). The scan could not read anything. Show the BLOCKED copy below.
**Dual-track surfaces.** Results are split into two tracks. `surfaced` is the combined total; `buyer_count` and `authority_count` break it down. Every entry in `surfaces[]` carries a `track` field:
- `track: "buyer"` = Buyer signals. The post names a specific tool or brand AND shows buying intent. A reply here moves a deal.
- `track: "authority"` = Authority plays. On-topic, answerable question with no buyer present yet. A reply here builds presence and credibility, it does not close a sale.
The `inline_markdown` and `inline_table` fields already render both tracks as two labeled sections (BUYER SIGNALS first, then AUTHORITY PLAYS). When the authority track is empty, only the buyer section renders. The authority track can be toggled in `weights.yml` under `authority_track.enabled`. When disabled, the run reverts to buyer-only output exactly.
Step 2: Optional Notion sync
Read `~/.config/subscope/notion.yml`. Branch on the `mode` field:
**Branch A: `mode: mcp` (recommended path, auth via Notion MCP)**
1. Probe for any `mcp__*notion*` tool. If absent, print one line: `(Notion MCP not connected, skipping sync. Install with: claude mcp add --transport http notion https://mcp.notion.com/mcp)` and skip to Step 4. 2. Resolve the database ID by calling the MCP `notion-search` tool with `query=<database_name from notion.yml>`. If multiple matches, prefer one with `object: database`. If no match, print `(Notion DB "<name>" not found, skipping sync)` and skip to Step 4. 3. For each surface in the engine output, call the MCP `notion-create-pages` tool with `parent={"database_id": <resolved_id>}` and the property map below. 4. Sync failure is **non-fatal**. Capture the reason and proceed.
**Branch B: `api_key` + `database_id` (legacy SDK path)**
1. For each surface, create a row in the configured Notion database via the Notion REST API using the api_key + database_id from notion.yml. 2. Sync failure is **non-fatal**.
**Property map (both branches):**
- `Title`, `Tier`, `Subreddit`, `Score`, `Upvotes`, `Comments`, `Posted` (ISO date), `Pain`, `Fit`, `URL` (verbatim from engine output, **never hand-compose Reddit URLs**), `Surfaced on` (today, ISO)
- `Pattern` = the mode that produced the surface (default: `run`)
- `Track` ← read from `surface.track` (`buyer` or `authority`). Buyer = a reply moves a deal; authority = a reply builds presence, no buyer yet. Skip this property if the Notion DB has no `Track` column (it is optional, added with dual-track surfaces).
- `State` = `Drafting` if cooling queue active, else `Hot`
- `OP score` ← read from `surface.op_score` (string like `"2y old · 4.2k karma · 12% wrong-audience"`)
If `notion.yml` is missing, skip silently.
Step 3: Optional Slack push (handled by Python automatically)
If `~/.config/subscope/slack.json` exists OR `SLACK_W
Read more
name: subscope-run description: Run the daily Reddit pain-post surface. Fetch new posts from configured subs, score by intent/keyword/freshness, optionally classify via Claude Haiku, dedup against history, hold in cooling queue, and emit inline markdown (plus optional Notion sync). Triggers on "run subscope", "/subscope run", "daily reddit", "scan reddit", "show today's reddit posts", or the default `/subscope-run` invocation. allowed-tools: Bash, Read, Write
/subscope-run
Daily Reddit surfacing orchestrator. Python (under `engine/`) does fetch + gate + score + SQLite + JSON output. This skill is the Claude-side wrapper: it invokes the engine, optionally syncs to Notion (if configured), and prints the inline list to chat.
Preflight
1. Check whether user has personalized targeting at `~/.config/subscope/subreddits.yml`. If missing, the engine still runs using bundled generic defaults, but results will be off-target. Recommend `/subscope-onboard` (one conversation, ~5 min, includes the first scan) with a one-line nudge: `(no personal targeting found, scanning with generic defaults. /subscope-onboard for sharper results.)` Proceed with the run unless user explicitly cancels.
Daily run procedure
Step 1: Fetch + candidates (Python engine)
cd "$CLAUDE_PLUGIN_ROOT" && PYTHONPATH=engine python3 -m subscope.cli fetch-score --candidates
Engine output: a single JSON document on stdout with `run_id`, `status`, `fetched`, `surfaced`, `buyer_count`, `authority_count`, `subs_skipped_rate_limit`, `fetch_stats`, `dropped_counts`, `surfaces[]`, `inline_table`, `inline_markdown`, and (with `--candidates`) a `candidates[]` array plus `candidate_count` / `candidate_total`.
`candidates[]` is the recall pre-filter: every fetched post that cleared the absolute rejects (NSFW, removed/locked, vendor-spam, off-topic-sub, tier-3), each with deterministic features: `title`, `body`, `url`, `sub`, `tier`, `age_h`, `kw_hits`, `matched_kw`, `names_brand` (matched against the user's `brand_anchor`), `question_intent`, `pain_intent`, `engagement_available`, `soft_reason`. The engine deliberately does NOT decide relevance for these. **You do, in Step 3.5.** The engine's own `surfaces[]`/`inline_table` are the older lexical-gate output; under judge-first they are a secondary signal, not the chat output.
The `status` field tells you why a run produced few or no surfaces, so you never show the wrong message:
- `status: "ok"` and `surfaced > 0` -> normal run, render the table (Step 4).
- `status: "ok"` and `surfaced == 0` -> Reddit was reachable, today was just quiet. Show the EMPTY-DAY copy below.
- `status: "rate_limited"` -> Reddit rate-limited this run (HTTP 429). Some subreddits may have been skipped (`subs_skipped_rate_limit` says how many), so the list can be partial or empty. This is transient. Render any surfaces you DID get, then show the RATE-LIMITED copy below. Do NOT call this "blocked".
- `status: "blocked"` -> every Reddit feed request failed for a non-rate-limit reason (Reddit's edge returned 403, or the network was down). The scan could not read anything. Show the BLOCKED copy below.
**Dual-track surfaces.** Results are split into two tracks. `surfaced` is the combined total; `buyer_count` and `authority_count` break it down. Every entry in `surfaces[]` carries a `track` field:
- `track: "buyer"` = Buyer signals. The post names a specific tool or brand AND shows buying intent. A reply here moves a deal.
- `track: "authority"` = Authority plays. On-topic, answerable question with no buyer present yet. A reply here builds presence and credibility, it does not close a sale.
The `inline_markdown` and `inline_table` fields already render both tracks as two labeled sections (BUYER SIGNALS first, then AUTHORITY PLAYS). When the authority track is empty, only the buyer section renders. The authority track can be toggled in `weights.yml` under `authority_track.enabled`. When disabled, the run reverts to buyer-only output exactly.
Step 2: Optional Notion sync
Read `~/.config/subscope/notion.yml`. Branch on the `mode` field:
**Branch A: `mode: mcp` (recommended path, auth via Notion MCP)**
1. Probe for any `mcp__*notion*` tool. If absent, print one line: `(Notion MCP not connected, skipping sync. Install with: claude mcp add --transport http notion https://mcp.notion.com/mcp)` and skip to Step 4. 2. Resolve the database ID by calling the MCP `notion-search` tool with `query=<database_name from notion.yml>`. If multiple matches, prefer one with `object: database`. If no match, print `(Notion DB "<name>" not found, skipping sync)` and skip to Step 4. 3. For each surface in the engine output, call the MCP `notion-create-pages` tool with `parent={"database_id": <resolved_id>}` and the property map below. 4. Sync failure is **non-fatal**. Capture the reason and proceed.
**Branch B: `api_key` + `database_id` (legacy SDK path)**
1. For each surface, create a row in the configured Notion database via the Notion REST API using the api_key + database_id from notion.yml. 2. Sync failure is **non-fatal**.
**Property map (both branches):**
- `Title`, `Tier`, `Subreddit`, `Score`, `Upvotes`, `Comments`, `Posted` (ISO date), `Pain`, `Fit`, `URL` (verbatim from engine output, **never hand-compose Reddit URLs**), `Surfaced on` (today, ISO)
- `Pattern` = the mode that produced the surface (default: `run`)
- `Track` ← read from `surface.track` (`buyer` or `authority`). Buyer = a reply moves a deal; authority = a reply builds presence, no buyer yet. Skip this property if the Notion DB has no `Track` column (it is optional, added with dual-track surfaces).
- `State` = `Drafting` if cooling queue active, else `Hot`
- `OP score` ← read from `surface.op_score` (string like `"2y old · 4.2k karma · 12% wrong-audience"`)
If `notion.yml` is missing, skip silently.
Step 3: Optional Slack push (handled by Python automatically)
If `~/.config/subscope/slack.json` exists OR `SLACK_W
Showing the first part of this file.
subscope reads Reddit for you and hands you the threads worth replying to: the people shopping for what you sell, and the questions you can answer to build authority. Run it whenever you want.
Other skills on subscope.
- /build-vs-buy
Surface explicit build-vs-buy debate threads with numeric arguments (engineering hours, TCO, payback). OP is rationalizing the decision publicly — your worldview is the answer. Triggers on "build vs buy", "/subscope-build-vs-buy", "find build-vs-buy debates", "in-house vs SaaS",
Open skill - /churn
Surface high-intent Reddit posts where someone explicitly says they are canceling, switching from, or fed up with a named SaaS vendor. Pure buying intent. Triggers on "churn signals", "/subscope-churn", "find churn posts", "who's canceling", "switching from posts",
Open skill - /judge
Interactive classifier for a single Reddit surface. Reads one post by surface ID (or pasted URL/title/body), runs the bulk-classifier prompt against it, and returns a verdict + reply angle. Uses your Claude Code subscription, NOT a separate API key — costs nothing extra beyond
Open skill - /onboard
Mandatory first-run setup for subscope. One conversation, three plain questions, one confirmation, optional integrations, first scan. Paste URLs, answer what-you-sell / who-buys-it / what's-the-pain, confirm the targeting card, pick integrations to connect (DataForSEO,
Open skill - /op-vet
Score a Reddit user's profile before replying. Returns karma, account age, sub-activity breakdown, and a GO / HOLD / SKIP verdict. Useful when you spot a thread that looks promising but want to confirm OP is a real operator (not a throwaway, karma farmer, or hustle-bro).
Open skill - /pricing-rage
Surface Reddit price-hike rage threads (Salesforce/HubSpot/Gong cyclical Q1/Q3 spikes). Time-sensitive — cooling queue auto-disabled. Triggers on "pricing rage", "/subscope-pricing-rage", "find price hike threads", "renewal complaints", "predatory pricing posts", "tier change
Open skill

