OpenClaw skill for market demand research - collect, filter, dedupe market signals and prepare analysis artifacts
Violation = Invalid Output - Must Redo
| # | Rule | Check |
|---|---|---|
| 1 | Read sources from config/sources.json only |
No hardcoded paths |
| 2 | Every evidence: full_text + source_url + source_type + published_at |
4 fields required |
| 3 | Output analysis-result.json with valid JSON |
Schema compliant |
| 4 | Present full Markdown report to user | No "see file" shortcuts |
| 5 | No truncated evidence text | Complete quotes |
| 6 | No placeholder text | No "TBD" or "..." |
CHARTER → SOURCES → COLLECT → ANALYZE → MD_REPORT → NOTION → ACTION
(opt) [BLOCKER] auto AI core [BLOCKER] from MD track
Core Principle: Markdown report is the "Single Source of Truth" (SSOT). Notion sync MUST read from MD file.
Read workspace/projects/{project}/config/research-charter.json if exists.
Run pipeline to collect data:
python3 scripts/run_pipeline.py \
--project-name "my-research" \
--sources "hacker_news,woshipm,pmcaff" \
--query "product pain points"
Key Options:
| Option | Description | Default |
|---|---|---|
--project-name |
Unique project identifier | Required |
--sources |
Comma-separated sources | All enabled |
--query |
Search query | From charter |
--lookback-hours |
Time window | 720 (30 days) |
--max-items-per-source |
Items per source | 50 |
--include-keyword |
Filter: must contain | None |
--exclude-keyword |
Filter: must not contain | None |
Output: workspace/projects/{project}/data/candidate_items.jsonl
Collectors output to workspace/projects/{project}/data/:
raw.jsonl - Raw datacandidate_items.jsonl - Filtered itemsRead from data/:
analysis_input.jsoncandidate_items.jsonlresearch-charter.json (if exists)AI Performs:
Must generate Markdown file first as the single source for Notion sync.
workspace/projects/{project}/data/analysis-result.jsonworkspace/projects/{project}/reports/analysis-report-{YYYY-MM-DD}.mdMarkdown File Path:
workspace/projects/{project}/reports/analysis-report-{date}.md
⚠️ Important: This MD file is the ONLY data source for Notion sync. Must contain complete content.
Read content from Markdown file to sync to Notion, ensuring consistency.
┌─────────────────────────────────────────────────────────┐
│ analysis-report-{date}.md ──────► Notion Page │
│ (Single Source of Truth) (Read from MD file) │
└─────────────────────────────────────────────────────────┘
Sync Process:
reports/analysis-report-{date}.md⚠️ Prohibited:
Notion Sync Status:
## Notion Sync Status
- [x] Synced: https://notion.so/page-id
- [ ] SYNC_SKIPPED: [reason - e.g., "Notion MCP not configured"]
Manage action items:
# List pending actions
python3 scripts/manage_actions.py --project "my-research" --list-pending
# Add new action
python3 scripts/manage_actions.py --project "my-research" \
--add "Interview 5 target users" \
--due "2026-04-15" \
--insight "High-volume sellers show strongest pain"
# Complete action
python3 scripts/manage_actions.py --project "my-research" \
--complete "ACTION-001" \
--note "Completed 5 interviews, 3 confirmed willingness to pay"
analysis-result.json){
"generated_at": "UTC timestamp",
"project_name": "string",
"top_pain_points": [{ "label", "summary", "evidence_count", "example_urls" }],
"candidate_clusters": [{ "name", "summary", "evidence_count", "payment_signal" }],
"payment_signals": [{ "label", "summary" }],
"bayesian_scores": {
"success_probability": {
"posterior": 0.35,
"prior": { "value": 0.12, "reasoning": "string" },
"confidence": "high|medium|low",
"signal_assessments": [{ "dimension", "strength", "reasoning", "evidence_quotes", "contribution" }],
"calculation_summary": "string",
"key_uncertainties": ["string"]
},
"payment_probability": { /* same structure */ }
},
"hypothesis_validation": [{ "hypothesis_id", "status", "supporting_evidence", "missing_evidence" }],
"strategic_analysis": {
"swot": { "strengths", "weaknesses", "opportunities", "threats" },
"competitor_landscape": [{ "name", "gap", "our_advantage" }],
"user_journey_stages": [{ "stage", "pain_level", "evidence_count" }]
},
"actionable_insights": [{ "insight", "evidence_basis", "recommended_action", "priority" }],
"action_items": [{ "id", "action", "owner", "status" }],
"strongest_examples": [{ "title", "url", "reason" }],
"risks_or_gaps": ["string"]
}
# [Project] Market Research Report
**Generated**: YYYY-MM-DD | **Confidence**: high/medium/low
## Executive Summary
**Conclusion**: [One sentence]
**Actions**: 1. [P0] ... 2. [P1] ... 3. [P2] ...
**Risks**: [Top 2 risks]
## Bayesian Scores
| Probability | Prior | Posterior | Key Signals |
|-------------|-------|-----------|-------------|
| Success | 12% | 35% | pain_intensity +10% |
| Payment | 6% | 18% | economic_impact +8% |
## Top Pain Points
### Pain 1: [Title] (X evidence)
> **Original**: "[Full quote]"
> **Source**: [Name](URL) | **Type**: community_discussion | **Date**: YYYY-MM-DD
## Strategic Analysis
**SWOT**: Strengths: [evidence] | Weaknesses: [gap] | Opportunities: [trend] | Threats: [risk]
**Competitors**: [Competitor] - Gap: [gap] - Our Advantage: [ours]
## Action Items
- [ ] ACTION-001: [Task] (Due: YYYY-MM-DD)
## Notion Sync
[ ] Synced: [URL] OR [ ] SYNC_SKIPPED: [reason]
Posterior = Prior + Σ(Signal_Strength × Contribution)
| Type | Dimensions |
|---|---|
| Success | pain_intensity, market_evidence, solution_gap, timing_signal, execution_fit |
| Payment | economic_impact, purchase_intent, budget_access, urgency, trust_signals |
Every evidence quote MUST include:
> **Original**: "[Complete original text]"
> **Source**: [Source Name](URL)
> **Type**: community_discussion
> **Published**: YYYY-MM-DD
Source Types: community_discussion | blog_article | industry_survey | competitor_review | documentation | interview | social_post
analysis-result.json exists with valid JSONreports/analysis-report-{date}.md exists with full Markdown reportworkspace/projects/{project}/
├── config/research-charter.json
├── data/
│ ├── raw.jsonl
│ ├── candidate_items.jsonl
│ ├── analysis_input.json
│ └── analysis-result.json
└── reports/
├── analysis-report-{date}.md # ⭐ Single Source of Truth (SSOT)
├── {date}.md # Auto-generated brief report
└── weekly-{year}-{week}.md # Weekly report
config/
├── sources.json # [BLOCKER] Data sources
└── keys.json # API keys (gitignored)
scripts/
├── run_pipeline.py # Main pipeline script
├── manage_actions.py # Action tracker
└── collectors/ # Data collectors
references/
├── analysis-result-schema.md # Detailed JSON schema
└── notion-page-template.md # Report template
┌──────────────────────────────────┐
│ Stage 5: MD Report Generation │
└───────────────┬──────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ reports/analysis-report-{date}.md │
│ ───────────────────────────────── │
│ • Executive Summary │
│ • Bayesian Scores (tables) │
│ • Pain Points (full evidence quotes) │
│ • Strategic Analysis (SWOT, competitors) │
│ • Action Items │
└───────────────────┬─────────────────────────────┘
│
│ READ (Only data source)
│
▼
┌─────────────────────────────────────────────────┐
│ Stage 6: Notion Sync │
│ ───────────────────── │
│ • Parse MD file structure │
│ • Convert to Notion block format │
│ • Preserve content integrity (no simplification)│
└───────────────────┬─────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ Notion Page │
│ ────────── │
│ Content == MD File Content ✓ │
└─────────────────────────────────────────────────┘
⚠️ Consistency Guarantee: