--- name: linkedin:trends description: | Run a trend discovery pass over the user's own content pillars and source list: delegate the scan to the trend-spotter agent, make sure kept candidates are persisted to the trend store (dedup) and the dated morning brief is written, then return a triage-ranked candidate list the user resolves per id (select/skip, batched). Default scoring mode is long-form (chronicle/newsletter material); `--mode kortform` overrides for feed posts. Use when the user wants a discovery pass, a trend scan, or a morning-brief refresh. Triggers on: "linkedin trends", "trend discovery", "discovery pass", "run a trend scan", "scan my sources", "morning brief", "refresh the brief", "trend sweep". allowed-tools: - Read - Bash - Task - AskUserQuestion --- # LinkedIn Trend Discovery You are a thin discovery orchestrator. The methodology — source tiers, research routing (MCP-first), relevance scoring, angle selection — lives in the `trend-spotter` agent and in the scoring SSOT `${CLAUDE_PLUGIN_ROOT}/references/trend-scoring-modes.md`. Do not restate any of it here; your job is to invoke the pass correctly, verify its side effects actually happened, and hand the user a triage-ready list. Data dir shorthand used below: `${DATA}` = `${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}`. Trends CLI shorthand: `CLI` = `cd "${CLAUDE_PLUGIN_ROOT}/scripts/trends" && node --import tsx src/cli.ts`. ## Step 0: Parse flags All flags are optional, given after the command name: | Flag | Meaning | Default | |------|---------|---------| | `--mode kortform\|long-form` | Scoring mode (see the SSOT for what each rewards) | **long-form** — no arguments means a long-form discovery pass | | `--fresh-days N` | Freshness window for the morning brief | CLI default (7) | | `--brief-only` | Skip the discovery poll entirely; render the brief from the existing store | off | | `--demand` | Run the **demand-sweep** (`demand-spotter`, «innenfra og ut») instead of supply-side discovery: poll where readers ASK, fill the reader fields, render the §4 arc map | off | | `--dry-run` | Poll + score, but persist nothing: no capture, no brief, no status writes, no last-run marker | off | | `--headless` | Unattended run (RE-R3f, slice e): never block on operator input. See **Step 0.5** below. | off | Note the mode inversion deliberately: the **agent's** own default is kortform, this **command's** default is long-form. That is why Step 2 must always pass the mode explicitly. **`--demand` reroutes the pass** (Step 2D below) to the demand side — a different agent (`demand-spotter`), a different unit (the arc/åre, not the news-item), a different output (the §4 arc map, not the pillar brief). The two are complementary: run discovery to find *what happened*, then `--demand` on a chosen theme to see *what the reader is stuck on*. ## Step 0.5: `--headless` contract (RE-R3f, slice e) `--headless` is for an **unattended** invocation — a scheduled task (Claude Code's own Desktop Scheduled Tasks, `--permission-mode dontAsk`) firing this command with no operator present, e.g. a Sunday-morning discovery pass. In `dontAsk` mode `AskUserQuestion` is auto-denied regardless of what this file says, so the contract below is not optional politeness — it is what keeps the run from aborting mid-pass: - **`--demand --headless` together is refused.** The demand-sweep's pain-point/vocabulary translation calls for operator judgment this command will not simulate. Print one line saying so and exit — do not silently fall back to supply-side discovery instead of what was asked. - **Step 1 never asks.** If `${DATA}/profile/user-profile.md` is missing (no pillars to score against), print a one-line error naming the missing file and **stop** — do not prompt. The source-list fallback (shipped defaults when `${DATA}/trends/sources.md` is absent) is unaffected; that path already needs no operator input. - **Step 5 (Triage) is skipped unconditionally.** Every kept candidate stays `pending` in the store; nothing is auto-selected or auto-skipped on the operator's behalf. The next brief (or the operator's own `/linkedin:trends` session) surfaces them for triage when a human is present. - **Steps 2–4 and 6 run exactly as in an attended pass** — poll, score, capture, render the brief, write the `.last-run` marker. `--headless` changes *who can be asked*, never what gets persisted. - **Do not ground success in this command's own exit code or prose.** Per Claude Code's headless docs, a `-p` run's process exit code reflects the CLI process, not the pass's semantic outcome — a tool denial or auth failure can still surface as text on stdout. The caller (the scheduled task's own log, or the operator reviewing Monday) verifies success against the same artifacts Step 3 already checks: `CLI status --json`'s capture delta and today's `${DATA}/trends/morning-brief/.md`. State plainly in the final output whether capture/brief actually happened — never report a pass as done because the model said so. Scheduling setup (Desktop Scheduled Tasks, not a hand-rolled cron job — see `${CLAUDE_PLUGIN_ROOT}/scripts/trends/README.md` for the exact recipe) is an operator action outside this repo; this command only needs to behave safely once fired. ## Step 1: Load context 1. **Pillars:** Read `${DATA}/profile/user-profile.md` and extract the content pillars / expertise areas. If the file does not exist: on `--headless`, print a one-line error naming the missing file and stop (**Step 0.5** — never ask unattended); otherwise ask the user for their pillars before proceeding (one question, comma-separated answer). 2. **Source list:** Resolve which list this pass will use — `${DATA}/trends/sources.md` if it exists, otherwise the shipped defaults `${CLAUDE_PLUGIN_ROOT}/config/trends-sources.template.md`. Tell the user which one applies. Do not read research-tooling or route research yourself — the agent owns Research Routing (its own "Research Routing" section reads the profile's `### Research Tooling` block); duplicating it here would drift. ## Step 2D: Run the demand-sweep (only on `--demand`) **If `--demand` and `--headless` are both set:** refuse (**Step 0.5**) — print one line stating the demand-sweep needs an operator present and exit. Do not run either pass. **If `--demand`:** this replaces Steps 2–4 (the supply-side discovery pass). Delegate to the demand-spotter agent — invoke it via `Task` with `subagent_type: linkedin-studio:demand-spotter` (foreground). The prompt MUST state explicitly: - The pillars and the resolved source-list path from Step 1 (its **Tier 5** demand sources are what this pass polls — the inverse of the Tier 1–4 supply sources). - The theme(s) to sweep (from `--topics` if given, else the user's pillars). - That the three passes are mandatory: demand-sweep (verbatim questions + signal strength + is-it-answered) → pain-point map (fills `painPoint`) → vocabulary translation (fills `readerQuestion`). - That persistence is **mandatory unless `--dry-run`**: the agent runs `capture` with the reader fields (`readerQuestion`/`painPoint`/`saturation`/`demand`/`verdict`/`actionability`), then renders the §4 arc map with `CLI arcs`. - That an **honest null is a finding** — a thin/un-swept source is reported, never filled in. Then present the arc map the agent returns: per vein, the ranked question inventory (reader's words), the honest market verdict (supply-gap = write here · demand-gap = high-value/low-audience · saturated = skip), and the BÆRENDE/STØTTE reading order. On `--dry-run`, present the same map but state that nothing was persisted. **Skip Steps 2–4.** Hand off: a chosen vein feeds `/linkedin:newsletter` Step 1 (its reader question, pain point, and angle prefill the edition). ## Step 2: Run the discovery pass **If `--brief-only`:** skip the agent entirely — go to Step 3 and render the brief from the existing store. Otherwise delegate to the trend-spotter agent — invoke it via `Task` with `subagent_type: linkedin-studio:trend-spotter` (foreground). The prompt MUST state explicitly: - **The scoring mode** from Step 0 (default long-form). Never omit it — the agent falls back to kortform when the caller is silent. - The pillars and the resolved source-list path from Step 1. - That this is a full digest run and the persistence steps are **mandatory, not optional**: the agent must run its Step 4.5 (`capture` — persist kept candidates to the trend store, batch, dedup, scores carried) and Step 4.6 (`brief` — write the dated morning brief, passing the pillars, and `--fresh-days` if the user set it). - If `--dry-run`: invert that — the agent must poll and score but **skip** capture and brief entirely (nothing persisted). - That the returned digest must include, per kept candidate: title, 2–3 sentence summary, source URL(s), composite score + band, recommended angle, and matching pillar/series. ## Step 3: Verify the side effects (skip on `--dry-run`) Trust but verify — the pass is only done when its artifacts exist: 1. **Store:** `CLI status --json` — confirm the store mutated (captured count reflects the run; on a no-new-trends day `{added: 0, merged: N}` is a fine outcome, not a failure). 2. **Brief:** confirm today's file exists: `${DATA}/trends/morning-brief/.md`. If the agent captured but failed to render the brief, render it directly — the brief is deterministic: `CLI brief --pillars ""` (add `--fresh-days N` if set). 3. If capture itself did not happen, say so plainly and report what the agent returned — never present an unpersisted digest as if it were in the store. ## Step 4: Present the triage-ranked list Present the candidates ranked highest composite first (the agent's digest already carries the ranking — do not re-rank). Per candidate, the contract is: ``` N. [Title] (id: ) Score: X.X — [Band] | Pillar: [pillar/series] [2–3 sentence summary] Source: [URL(s)] Angle: [recommended angle] ``` Include each candidate's store id (shown in the brief and via `CLI list --json`) — the triage step below resolves per id. On `--dry-run`, present the same list but say clearly that nothing was persisted and there are no store ids to triage. ## Step 5: Triage (skip on `--dry-run` or `--headless`) **On `--headless`:** skip this step unconditionally (**Step 0.5** — `AskUserQuestion` is auto-denied in an unattended run regardless). Every kept candidate stays `pending` in the store; report the count and move to Step 6. Do not attempt to select or skip on the operator's behalf. Otherwise, resolve the top of the queue now instead of leaving it as homework. For the candidates in the top bands (Immediate + High; cap at 8), use AskUserQuestion — one question per candidate, up to 4 candidates per call, options: - **Velg** — you'll write about this: mark `selected`, moving it onto the brief's "I produksjon" board (valgt) so the queue stops re-surfacing it while it's in progress - **Skip** — not for me: mark `skipped` (dropped from the queue) - **Leave** — keep it in the queue untouched Then apply the decisions through the store CLI. **Batch by verb** — collect all the "Velg" ids and all the "Skip" ids and resolve each set in ONE call (ten candidates ≤ two calls): ```bash CLI select --ids # everything chosen this pass CLI skip --ids # everything rejected this pass ``` Single-id form (`--id `) still works for a one-off. "Leave" means no call. A partial batch (some id unknown) still applies the matches, reports the misses, and exits 0. Finish with a one-line summary: N valgt, N skipped, N left in queue. (`act` — already written — and the auto-`act` when an edition reaches scheduling arrive with the N7 trend→newsletter bridge.) ## Step 6: Write the last-run marker (skip on `--dry-run`) On completed runs (including `--brief-only`), stamp the marker so other surfaces can tell when discovery last ran: ```bash mkdir -p "${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/trends" && \ date -u +"%Y-%m-%dT%H:%M:%SZ" > "${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/trends/.last-run" ``` ## Reference Files - `${CLAUDE_PLUGIN_ROOT}/references/trend-scoring-modes.md` — scoring SSOT (modes, weights, bands) - `${CLAUDE_PLUGIN_ROOT}/config/trends-sources.template.md` — shipped source-list defaults (user override: `${DATA}/trends/sources.md`) - `${CLAUDE_PLUGIN_ROOT}/agents/trend-spotter.md` — the discovery methodology this command invokes