From product-pulse
Daily research automation. Scans configured domains for actionable intelligence, filters through the weekly strategy brief for relevance, and produces a dated research report with action items for PM ingestion. Opens an auto-mergeable PR. Reads pulse-config.yaml from the nearest research directory. Trigger: "run daily research", "research scan", "what's new", "check for updates", or /product-pulse:daily-research. Also triggered by scheduled tasks.
How this skill is triggered — by the user, by Claude, or both
Slash command
/product-pulse:daily-researchThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
You are the daily research scanner. Your job is to find what changed today across the product's configured research domains, filter it through the week's strategic direction, and produce an actionable report.
You are the daily research scanner. Your job is to find what changed today across the product's configured research domains, filter it through the week's strategic direction, and produce an actionable report.
You are NOT a strategist — that's the weekly skill. You gather intel and surface findings. Keep it focused.
**ALWAYS-CHECK HIT** and surfaced in a dedicated Escalations section at the top of the report.Walk up from cwd, checking each directory for pulse-config.yaml directly and in common research-dir subdirs (research/, Research/, docs/research/). The first match wins; that file's parent directory is the research directory ({research_dir}). Load the YAML config; the rest of the skill uses values from it.
config_path=""
research_dir=""
dir="$PWD"
while [ "$dir" != "/" ]; do
for sub in "" "research/" "Research/" "docs/research/"; do
candidate="$dir/${sub}pulse-config.yaml"
if [ -f "$candidate" ]; then
config_path="$candidate"
research_dir="$(cd "$(dirname "$candidate")" && pwd)"
break 2
fi
done
dir="$(dirname "$dir")"
done
if [ -z "$config_path" ]; then
echo "No pulse-config.yaml found. Run /product-pulse:setup first." >&2
exit 1
fi
primary_repo_root="$(cd "$research_dir" && git rev-parse --show-toplevel)"
default_branch="$(yq '.default_branch // "main"' "$config_path")"
auto_merge="$(yq '.auto_merge // true' "$config_path")"
project_id="$(yq '.project_id' "$config_path")"
memory_connector="$(yq '.memory.connector // "shelby"' "$config_path")"
echo "Using config: $config_path"
echo "Research dir: $research_dir"
Parse the YAML. Required fields: project_id, repos. Optional with defaults: default_branch (default main), auto_merge (default true), memory.connector (default shelby; set to null to disable).
Find the entry in repos: with role: primary. Its filesystem location (resolved relative to the directory containing pulse-config.yaml's parent) is the primary repo root ({primary_repo_root}) for git operations.
Read {research_dir}/research-context.md. If missing, stop and tell the user to run /product-pulse:setup.
Iterate repos: from pulse-config.yaml. For each repo, resolve its absolute path relative to {primary_repo_root}'s parent directory, then pull the default branch:
for repo_path in $(yq '.repos[].path' pulse-config.yaml); do
abs="$(realpath "$primary_repo_root/$repo_path")"
echo "=== Pulling $abs ==="
cd "$abs" && git checkout "$default_branch" && git pull origin "$default_branch" || echo "pull failed for $abs"
done
If any pull fails, note it and continue. Single-element repos: is the monorepo case — same loop, one iteration.
Find the most recent *-strategy-brief.md in {research_dir}/ (search recursively through year/month folders). Extract:
*-recommendations.mdIf no weekly brief exists, all findings are treated as potentially relevant (no strategic filter).
If memory.connector is set, search for prior daily research findings (last 7 days) to avoid duplicates.
From memory and recent reports, collect finding URLs and summaries. A finding is a duplicate if:
Parse the ## Always Check section of {research_dir}/research-context.md. This section (if present) contains a list of persistent watch items the user has flagged as architecturally load-bearing. Each item has:
If the section is missing or empty, skip this phase — the user hasn't configured Always Check items yet. Do NOT fabricate items.
When dispatching sub-agents in Phase 2, pass each domain's Always Check items (if any) alongside its regular search terms. The sub-agent must run every Always Check search term on every run, in addition to its 3-5 rotating terms.
Read {research_dir}/research-sources.yaml. For each domain, rank sources by qualityScore descending. Sources without a score default to 50.
CRITICAL: All domain agents MUST be dispatched in a single message as parallel Agent tool calls.
For each domain defined in the product context and research-sources.yaml, dispatch a sub-agent with:
**ALWAYS-CHECK HIT** in the Title field and returned with Impact at least "medium" regardless of normal scoringEach sub-agent uses WebSearch and WebFetch to scan its sources and search terms. YouTube MCP tools should be used for YouTube sources if available.
Before deduping or ranking, separate out any findings tagged **ALWAYS-CHECK HIT**. These bypass the normal ranking and strategic filter — they always surface at the top of the report in a dedicated Escalations section and always appear in the Action Items table (they don't count against the 5-item cap, since they're triggered by pre-approved watch items). If an Always Check hit references a Guide doc in its Reference field, note "Guide doc update required: {path}" so the user knows to refresh it.
Remove cross-domain duplicates (same URL or 3+ shared keywords).
Sort by:
If a weekly brief exists, score each finding:
Take the top 5 by alignment score, then by impact/effort ratio. Only these appear in the report's Action Items table.
month = current month (YYYY-MM)
week = current ISO week (WNN)
today = current date (YYYY-MM-DD)
week_dir = {research_dir}/{month}/W{NN}/
Create the directory if it doesn't exist. Daily reports live alongside the weekly brief for that week.
Write to {week_dir}/{today}-daily-research.md. Structure:
# Daily Research — {today}
**Product**: {product name}
**Weekly theme**: {theme or "No weekly brief"}
**Domains scanned**: {N}
**Findings**: {N} total, {N} action items
---
## {Domain 1 Name}
### Finding: {title}
- **Source**: [{source name}]({URL})
- **Summary**: {2-3 sentences}
- **Impact**: {H/M/L} | **Effort**: {H/M/L} | **Confidence**: {H/M/L}
- **Relevance**: {why this matters to the product}
...
## Action Items
| # | Item | Size | Priority | Domain | Source | Confidence |
|---|------|------|----------|--------|--------|------------|
## Source Performance
| Source | Domain | Checked | Hit? |
|--------|--------|---------|------|
## Noted
{findings that were interesting but didn't make the top 5 cut}
## Search Terms Used
{list per domain, for rotation tracking}
For each source checked, update quality tracking in memory (hit/miss ratio).
If memory.connector is set, capture a summary of today's findings. Tool names match the connector prefix:
capture_thought({
content: "{summary of findings and domains scanned}",
summary: "Daily research {YYYY-MM-DD}: {N} findings across {M} domains",
type: "note",
topics: ["product-pulse-daily-research", "{project_id}-research"],
source: "daily-research-{YYYY-MM-DD}",
project: "{project_id}",
metadata: { date: "{YYYY-MM-DD}", domains: {M}, findings: {N}, action_items: {K} }
})
If memory.connector: null or no matching tools are found, skip this phase.
Inside the primary repo:
cd "$primary_repo_root"
branch="daily-research/{YYYY-MM-DD}"
git checkout -b "$branch"
git add "$research_dir"
git commit -m "research: daily scan {today} — {N} findings across {M} domains"
git push -u origin "$branch"
pr_url=$(gh pr create --base "$default_branch" --head "$branch" \
--title "research: daily scan {today} — {N} findings across {M} domains" \
--body "Daily research scan for {today}. {N} findings across {M} domains; {K} action items. Auto-generated by product-pulse daily-research." \
| tail -n1)
echo "PR opened: $pr_url"
If auto_merge: true in config:
sleep 8 # let GitHub finalize mergeability check
gh pr merge "$pr_url" --squash --delete-branch --auto || \
echo "Auto-merge declined; PR sits for human review at $pr_url"
--auto queues the merge if checks are still running. If branch protection or required reviews block the merge, the PR sits for human review and the skill exits cleanly with the PR URL surfaced.
Product Pulse — Daily Research ({today})
==========================================
Domains scanned: {N}
Findings: {N} total
Action items: {N} in report
Noted: {N}
Sources checked: {N} ({N} hits, {N} misses)
PR: {pr_url} ({merged | open})
/product-pulse:setup.npx claudepluginhub studio-moser/skills-n-stuff --plugin product-pulseGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.