---
name: chatter-scout
description: Sweep the web for new chatter on a topic, skip what earlier runs already saw, verify what is left, and write one ranked, cited findings file to feed a blog post or a digest email.
disable-model-invocation: true
argument-hint: "A topic or profile slug (omitted: the repo's only profile)"
allowed-tools: "WebSearch WebFetch"
compatibility: "Needs jq on PATH"
model: sonnet
effort: medium
---

# Chatter Scout

Run one scouting pass on a topic, then stop. Output is one findings file; nothing is drafted, sent, or published. Safe to re-run: the seen-ledger keeps every run from resurfacing what an earlier one reported.

Cost is the design constraint. The lead (this skill) does no bulk searching or page reading; it writes briefs, runs the ledger script, ranks, and writes the file. Searching fans out to cheap sweepers; page reading goes only to candidates that survive the ledger.

## Files (in the target repo)

- **Profile** `docs/chatter/<topic-slug>/profile.md`: the lens, sources, and watchlist. Format and bootstrap rules: [PROFILE-FORMAT.md](PROFILE-FORMAT.md).
- **Ledger** `docs/chatter/<topic-slug>/seen.json`: JSON array of normalized URLs already judged. Only [scripts/filter-seen.sh](scripts/filter-seen.sh) reads or writes it; it never removes an entry.
- **Findings** `.scratch/chatter/<topic-slug>/<YYYY-MM-DD>.md`: this run's output. A second run on the same day appends `-2`, `-3`.

## Steps

1. **Resolve the topic.** `$ARGUMENTS` is a profile slug or free text. Slugify free text and match it against `docs/chatter/*/profile.md`. No argument: use the only profile; if there are zero or several, list them and stop. No profile for the topic: bootstrap one per PROFILE-FORMAT.md. *Done when* one profile is loaded and today's date is known from the environment.
2. **Load what is already covered.** If the profile has `covered:` globs, collect the title (and tags, if any) from each file's frontmatter, one line each. Do not read bodies. *Done when* you hold a covered-titles list (possibly empty).
3. **Sweep.** Dispatch one sweeper per profile source group (watchlist included), at most 5, **in parallel** (in Claude Code with this plugin installed, `subagent_type=leek-skills:chatter-sweeper`; in plain Claude Code, `general-purpose` with `model: haiku`; elsewhere, any sub-agent on the cheapest model the harness offers, or run the groups inline one after another). Each brief carries: today's date, `window_days`, the Lens, Buckets, and Ignore sections verbatim, that one group's sources, queries, and notes, and the **Sweeper** section of [BRIEFS.md](BRIEFS.md). Nothing else. *Done when* every sweeper has returned its JSON array.
4. **Drop what the ledger has seen.** Concatenate the arrays and pipe them through `bash <skill-dir>/scripts/filter-seen.sh filter docs/chatter/<slug>/seen.json`. Then drop, by title, anything a covered title already covers: a genuinely new development in a covered story (new ruling, new data, new state) stays. Drop any item dated before the window (non-evergreen buckets). If more than 15 survive, keep the 15 that best fit the Lens, taking day-dated items before undated ones: an undated item takes a slot only when no dated item fits. *Done when* at most 15 new candidates remain; if none remain, skip to step 6.
5. **Verify.** Split the survivors into batches of about 5 and dispatch one verifier per batch **in parallel** (in Claude Code, `subagent_type=leek-skills:chatter-verifier`; in plain Claude Code, `general-purpose` with `model: sonnet`; elsewhere, a sub-agent on a mid-tier model, or inline). Each brief carries: today's date, `window_days`, the Lens, Buckets, and Ignore sections, the batch, the profile's fetch notes, and the **Verifier** section of BRIEFS.md. *Done when* every candidate has a verdict.
6. **Rank and write.** Keep verdict `keep` and `community`. Rank by fit to the Lens first, then freshness (for non-evergreen buckets), then how many concrete facts the item carries. Take the top `max_items`; the rest go under **Also seen**. Write the findings file in the format below. *Done when* the file exists.
7. **Update the ledger.** Pipe a JSON array of every URL with verdict `keep`, `community`, `off-topic`, `stale`, or `thin` to `filter-seen.sh add`. Leave `unreachable` out so a later run retries it. *Done when* the script reports its `added` count.
8. **Recap** in 3–6 lines: groups swept, candidates found, new after the ledger, kept; the single strongest item; the findings path; and, if the profile was bootstrapped, that it needs review.

Never write to the profile after it exists, and never edit an earlier findings file.

## Findings format

```markdown
# Chatter: <topic>, <YYYY-MM-DD>

Swept <n> groups · <n> candidates · <n> new · <n> kept. Purpose: <blog | digest | both>.

## 1. <title>
- **Bucket:** <bucket> · **Date:** <YYYY-MM-DD, or "undated"> · **New this week:** yes | no
- **Source:** <publication> <URL>
- **Summary:** 1–2 lines.
- **Facts:** the specific numbers, dates, names, and citations the item hangs on.
- **Why it matters:** 1–2 lines against the Lens.
- **Angle:** for blog, the search query or headline it could win; for digest, the one line a reader acts on.
- **Action:** watch | respond | build | share | write
- **Confidence:** verified | community (unverified sentiment, not fact)

## Also seen
- <title>, <URL>: one line.

## Rejected
<n> off-topic · <n> stale · <n> thin · <n> unreachable (retried next run)
```

With no kept items, write only the header line and `No new relevant chatter.`
