/tune
Sharpen the subscope ranker with targeted feedback. Shows your recent surfaces; you mark ONLY the ones that are off (and any standouts) and skip the rest. The engine nudges per-sub weights from your marks. Faster than re-running /profile when the daily list feels a little off.
$ npx -y skills add dancolta/subscope --skill tune --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
/tune
Context preview
The summary Claude sees to decide when to auto-load this skill.
Sharpen the subscope ranker with targeted feedback. Shows your recent surfaces; you mark ONLY the ones that are off (and any standouts) and skip the rest. The engine nudges per-sub weights from your marks. Faster than re-running /profile when the daily list feels a little off.
SKILL.md
tune.SKILL.mdname: subscope-tune
description: Sharpen the subscope ranker with targeted feedback. Shows your recent surfaces; you mark ONLY the ones that are off (and any standouts) and skip the rest. The engine nudges per-sub weights from your marks. Faster than re-running /profile when the daily list feels a little off. Triggers on "tune subscope", "/subscope-tune", "fix the rankings", "list is mediocre", "feedback on surfaces", "tune the ranker".
allowed-tools: Bash, Read, Write, Edit
/subscope-tune
Targeted feedback. You mark only the surfaces that stand out (wrong or great), the engine nudges per-sub weights, and your config gets sharper without re-running the full `/profile` interview. Anything you skip is left untouched.
When to use
The daily list (`/subscope-run`) is mostly fine but a few surfaces are off. Instead of editing YAML by hand: tune. Flag the wrong ones, optionally the great ones, ignore the rest.
Procedure
Step 1: Pull recent surfaces
cd "$CLAUDE_PLUGIN_ROOT" && PYTHONPATH=engine python3 -c "
import json
from subscope.lib import store
with store.connect() as conn:
rows = store.hot_surfaces(conn)[:15]
print(json.dumps([{
'id': r['post_id'],
'subreddit': r['subreddit'],
'title': r['title'],
'url': r['url'],
} for r in rows], indent=2))
"If the pool is empty, tell the user: *"No surfaces in the recent pool yet. Run /subscope-run first, then come back."*
Step 2: Present in chat (mark only what stands out)
Render the recent surfaces as a clean numbered list. Make clear that marking is OPTIONAL and partial: the user flags only what is off (and any standouts), and skipping changes nothing.
Your recent surfaces. Mark only the ones that are off, or great. Skip the rest, they stay as-is.
b = surface less of this g = surface more (skip = leave alone)
1. r/RevOps "Anyone else drowning in HubSpot ops debt?"
2. r/SaaS "Looking for a fractional RevOps person"
3. r/Entrepreneur "How to find first 10 customers?"
4. r/RevOps "Mass-update HubSpot deals via API?"
5. r/sales "Apollo just hiked us 40 percent"
Reply with just the ones worth flagging, e.g. 3b or 3b 5g (spaces or commas).
Reply "done" to finish without changes.
Rules:
- Lead with the one-line instruction. State plainly that partial feedback is fine and skipping is the default.
- Do NOT render a `[ ? ]` placeholder on every row. That implies the user must rate all of them, which is exactly the friction we are removing. Plain numbered list only.
- Do not force a fixed count or rounds. Show what is in the pool (up to ~15).
- If a row was flagged in an earlier pass this session, you may show its mark in brackets (e.g. `[b]`), but never require the user to re-confirm it.
Step 3: Parse the reply
Parse via `tune_engine.parse_marks(user_reply)`. It tolerates whitespace, commas, and missing indices. Unmarked rows carry NO signal and never change a weight, so the user only needs to type the few they care about. If the user replies "done" with no marks, skip to "no changes".
Step 4: Apply marks, nudge weights
cd "$CLAUDE_PLUGIN_ROOT" && PYTHONPATH=engine python3 -c "
import json, sys
from subscope.lib import store, tune_engine
payload = json.loads(sys.stdin.read())
surfaces = payload['surfaces']
marks = payload['marks'] # {1: 'g', 3: 'b', ...} for ONLY the flagged rows
subs_path = store.xdg_config_dir() / 'subreddits.yml'
result = tune_engine.apply_marks_to_subs(surfaces, marks, subs_path)
print(tune_engine.format_deltas_readout(result['changes'], round_num=1, total_rounds=1))
tune_engine.record_session(marks, result['changes'], surfaces, round_num=1)
"Pass surfaces + the flagged marks as one JSON object to stdin (Claude composes this). Only include the rows the user actually marked.
Step 5: Show the readout
The engine returns a deltas block listing ONLY the subs that actually changed:
Updated weights:
r/RevOps 1.20 -> 1.45 (+0.25) [2 flagged good]
r/Entrepreneur 1.00 -> 0.80 (-0.20) [1 flagged bad]
Tuning complete. Saved to ~/.config/subscope/subreddits.yml.
Show it verbatim. If nothing was flagged (or the user said "done"), print one line: *"No changes, nothing flagged. Your config is unchanged."* and stop.
Step 6: Offer another pass (optional)
If the user wants to keep refining, pull the next batch of surfaces and repeat. Never force multiple rounds; one targeted pass is a complete, valid session.
Step 7: What to do next
Next /subscope-run reflects these weights. If a sub keeps surfacing posts you
flag as bad, consider quarantining it (edit subreddits.yml: tier: 3, weight: 0.0).
Tuning history: ~/.local/share/subscope/tune-sessions.jsonl
Anti-patterns
- **Don't require feedback on every surface.** Targeted, partial feedback is the whole point. The user types only the few that stand out.
- **Don't penalize skipped surfaces.** Skipped means no signal means no change. The engine enforces this (meh nudge is zero); the presentation must match it.
- **Don't silently delete subs.** Even after repeated bad flags, the worst case is the 0.1 weight floor. Quarantine is a user decision, not a tune action.
- **Don't generate new keywords from the marks.** This skill sharpens EXISTING config. New entries come from `/subscope-profile`.
- **Don't suggest re-running /profile after /tune** unless several passes did not move the ranker.
Resumability
`/tune` is stateless within a session. Each pass persists to `subreddits.yml` immediately, so an interruption just means fewer surfaces got marked. Nothing to resume.
Read more
name: subscope-tune description: Sharpen the subscope ranker with targeted feedback. Shows your recent surfaces; you mark ONLY the ones that are off (and any standouts) and skip the rest. The engine nudges per-sub weights from your marks. Faster than re-running /profile when the daily list feels a little off. Triggers on "tune subscope", "/subscope-tune", "fix the rankings", "list is mediocre", "feedback on surfaces", "tune the ranker". allowed-tools: Bash, Read, Write, Edit
/subscope-tune
Targeted feedback. You mark only the surfaces that stand out (wrong or great), the engine nudges per-sub weights, and your config gets sharper without re-running the full `/profile` interview. Anything you skip is left untouched.
When to use
The daily list (`/subscope-run`) is mostly fine but a few surfaces are off. Instead of editing YAML by hand: tune. Flag the wrong ones, optionally the great ones, ignore the rest.
Procedure
Step 1: Pull recent surfaces
cd "$CLAUDE_PLUGIN_ROOT" && PYTHONPATH=engine python3 -c "
import json
from subscope.lib import store
with store.connect() as conn:
rows = store.hot_surfaces(conn)[:15]
print(json.dumps([{
'id': r['post_id'],
'subreddit': r['subreddit'],
'title': r['title'],
'url': r['url'],
} for r in rows], indent=2))
"If the pool is empty, tell the user: *"No surfaces in the recent pool yet. Run /subscope-run first, then come back."*
Step 2: Present in chat (mark only what stands out)
Render the recent surfaces as a clean numbered list. Make clear that marking is OPTIONAL and partial: the user flags only what is off (and any standouts), and skipping changes nothing.
Your recent surfaces. Mark only the ones that are off, or great. Skip the rest, they stay as-is. b = surface less of this g = surface more (skip = leave alone) 1. r/RevOps "Anyone else drowning in HubSpot ops debt?" 2. r/SaaS "Looking for a fractional RevOps person" 3. r/Entrepreneur "How to find first 10 customers?" 4. r/RevOps "Mass-update HubSpot deals via API?" 5. r/sales "Apollo just hiked us 40 percent" Reply with just the ones worth flagging, e.g. 3b or 3b 5g (spaces or commas). Reply "done" to finish without changes.
Rules:
- Lead with the one-line instruction. State plainly that partial feedback is fine and skipping is the default.
- Do NOT render a `[ ? ]` placeholder on every row. That implies the user must rate all of them, which is exactly the friction we are removing. Plain numbered list only.
- Do not force a fixed count or rounds. Show what is in the pool (up to ~15).
- If a row was flagged in an earlier pass this session, you may show its mark in brackets (e.g. `[b]`), but never require the user to re-confirm it.
Step 3: Parse the reply
Parse via `tune_engine.parse_marks(user_reply)`. It tolerates whitespace, commas, and missing indices. Unmarked rows carry NO signal and never change a weight, so the user only needs to type the few they care about. If the user replies "done" with no marks, skip to "no changes".
Step 4: Apply marks, nudge weights
cd "$CLAUDE_PLUGIN_ROOT" && PYTHONPATH=engine python3 -c "
import json, sys
from subscope.lib import store, tune_engine
payload = json.loads(sys.stdin.read())
surfaces = payload['surfaces']
marks = payload['marks'] # {1: 'g', 3: 'b', ...} for ONLY the flagged rows
subs_path = store.xdg_config_dir() / 'subreddits.yml'
result = tune_engine.apply_marks_to_subs(surfaces, marks, subs_path)
print(tune_engine.format_deltas_readout(result['changes'], round_num=1, total_rounds=1))
tune_engine.record_session(marks, result['changes'], surfaces, round_num=1)
"Pass surfaces + the flagged marks as one JSON object to stdin (Claude composes this). Only include the rows the user actually marked.
Step 5: Show the readout
The engine returns a deltas block listing ONLY the subs that actually changed:
Updated weights: r/RevOps 1.20 -> 1.45 (+0.25) [2 flagged good] r/Entrepreneur 1.00 -> 0.80 (-0.20) [1 flagged bad] Tuning complete. Saved to ~/.config/subscope/subreddits.yml.
Show it verbatim. If nothing was flagged (or the user said "done"), print one line: *"No changes, nothing flagged. Your config is unchanged."* and stop.
Step 6: Offer another pass (optional)
If the user wants to keep refining, pull the next batch of surfaces and repeat. Never force multiple rounds; one targeted pass is a complete, valid session.
Step 7: What to do next
Next /subscope-run reflects these weights. If a sub keeps surfacing posts you flag as bad, consider quarantining it (edit subreddits.yml: tier: 3, weight: 0.0). Tuning history: ~/.local/share/subscope/tune-sessions.jsonl
Anti-patterns
- **Don't require feedback on every surface.** Targeted, partial feedback is the whole point. The user types only the few that stand out.
- **Don't penalize skipped surfaces.** Skipped means no signal means no change. The engine enforces this (meh nudge is zero); the presentation must match it.
- **Don't silently delete subs.** Even after repeated bad flags, the worst case is the 0.1 weight floor. Quarantine is a user decision, not a tune action.
- **Don't generate new keywords from the marks.** This skill sharpens EXISTING config. New entries come from `/subscope-profile`.
- **Don't suggest re-running /profile after /tune** unless several passes did not move the ranker.
Resumability
`/tune` is stateless within a session. Each pass persists to `subreddits.yml` immediately, so an interruption just means fewer surfaces got marked. Nothing to resume.
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

