- 9 mm* skills (orchestrator, article, social, publish, analytics) - 6 dependency skills (content-writer, geo-optimizer, etc.) - 3 analytics scripts (GSC, Google Ads, Meta Ads) - Config template + setup guide - SOUL-MM.md persona extension - OrbitOS integration reference
311 lines
9.6 KiB
Markdown
311 lines
9.6 KiB
Markdown
---
|
|
name: mm-article-from-research
|
|
description: >
|
|
Data Stage A: Convert a vault research note into an article brief.
|
|
Scans 30_Research/ for resources not yet used for articles, lets user pick one,
|
|
reads the content, summarizes key points, asks user which angles to focus on,
|
|
then creates a brief.md for the content-writer-mm skill.
|
|
Use when: "เขียนบทความจาก research", "article from research", "ใช้ research เขียนบทความ".
|
|
---
|
|
|
|
# Article From Research
|
|
|
|
Converts existing vault research notes into structured article briefs.
|
|
|
|
## When This Must Trigger
|
|
|
|
- "เขียนบทความจาก research", "article from research"
|
|
- "ใช้ research เขียนบทความ", "make article from research"
|
|
- "เลือก research มาเขียน"
|
|
- "ทั้งหมด", "ทุก research", "batch" (batch mode — see Step 1b)
|
|
|
|
## Process
|
|
|
|
### Step 1: Determine mode — Single or Batch
|
|
|
|
Ask the user if they want to work on ONE research or ALL at once:
|
|
|
|
```python
|
|
# Detect batch intent
|
|
batch_keywords = ['ทั้งหมด', 'ทุก', 'all', 'batch', 'ทุกไฟล์', '14', '13', '12',
|
|
'ทุก research', '14 บทความ', 'ทั้งหมดเลย']
|
|
user_msg = user_message.lower()
|
|
is_batch = any(kw in user_msg for kw in batch_keywords)
|
|
```
|
|
|
|
- **Single mode** (default): user picks one research → interactive focus questions
|
|
- **Batch mode**: process ALL unused research at once → skip interactivity
|
|
|
|
Trigger batch immediately if user says "ทั้งหมด" or "ทุก research" or "ทุกไฟล์"
|
|
|
|
### Step 0: Determine client
|
|
|
|
Ask which client this article is for:
|
|
|
|
```
|
|
บทความนี้สำหรับลูกค้าไหน?
|
|
|
|
1. [client-1] — [display_name]
|
|
2. [client-2] — [display_name]
|
|
```
|
|
|
|
If no clients configured, suggest running `mm-article-idea-extract` to add one first.
|
|
|
|
### Step 1: Scan 30_Research/<client-id>/ for available resources
|
|
|
|
```bash
|
|
VAULT_PATH="$HOME/vault"
|
|
```
|
|
|
|
Search for research notes in both client-specific and general folders that have
|
|
NOT been marked as used for articles:
|
|
|
|
```python
|
|
# Search 30_Research/<client-id>/ AND 30_Research/general/
|
|
# Exclude Archive/ subfolders and notes with article_created: true
|
|
import os, re
|
|
|
|
vault = os.path.expanduser("~/vault/30_Research")
|
|
results = []
|
|
search_dirs = [
|
|
os.path.join(vault, client_id), # client-specific
|
|
os.path.join(vault, "general"), # general research
|
|
]
|
|
|
|
for search_dir in search_dirs:
|
|
if not os.path.exists(search_dir):
|
|
continue
|
|
for root, dirs, files in os.walk(search_dir):
|
|
# Skip Archive folders
|
|
if 'Archive' in root.split(os.sep):
|
|
continue
|
|
for f in files:
|
|
if not f.endswith('.md'):
|
|
continue
|
|
path = os.path.join(root, f)
|
|
try:
|
|
content = open(path).read()
|
|
if 'article_created: true' in content[:500]:
|
|
continue
|
|
title_match = re.search(r'^#\s+(.+)$', content, re.MULTILINE)
|
|
title = title_match.group(1) if title_match else f.replace('.md', '')
|
|
type_match = re.search(r'^type:\s*(.+)$', content, re.MULTILINE)
|
|
note_type = type_match.group(1).strip() if type_match else 'unknown'
|
|
results.append({
|
|
'path': path,
|
|
'title': title,
|
|
'type': note_type,
|
|
'relative': os.path.relpath(path, os.path.expanduser("~/vault"))
|
|
})
|
|
except:
|
|
continue
|
|
```
|
|
|
|
Present results to user as a numbered list:
|
|
|
|
```
|
|
พบ research notes ที่ยังไม่ได้ใช้เขียนบทความ:
|
|
|
|
1. [Title] — type: reference — 30_Research/Area/Topic/Topic.md
|
|
2. [Title] — type: reference — 30_Research/Area/Topic2/Topic2.md
|
|
...
|
|
|
|
เลือกหมายเลขที่ต้องการเขียนบทความ (หรือพิมพ์ชื่อหัวข้อเพื่อค้นหา):
|
|
```
|
|
|
|
If no research notes found, suggest running `article-idea-extract` instead.
|
|
|
|
### Step 1b: Batch mode — Process ALL research at once
|
|
|
|
Skip interactive selection. Read ALL research notes from 30_Research/ that don't have `article_created: true`.
|
|
|
|
Classify into two buckets:
|
|
|
|
| Status | Action |
|
|
|--------|--------|
|
|
| `reference`, `candidate`, `draft` | Ready — create brief from existing content |
|
|
| `seed` | **Research first** — search the web for current info, stats, examples, and sources. Compile into a supplementary data block for the brief |
|
|
|
|
For seed-status notes, search internet for:
|
|
- Latest articles/tutorials on the topic
|
|
- Official documentation or product pages
|
|
- Statistics, benchmarks, or case studies
|
|
- Competitor or comparison info
|
|
|
|
### Step 1c: Apply date convention (ALL modes)
|
|
|
|
**Article date = source research date.** Extract `date:` from research frontmatter:
|
|
|
|
```python
|
|
date_m = re.search(r'^date:\s*(.+)$', content, re.MULTILINE)
|
|
article_date = date_m.group(1).strip() if date_m else today
|
|
```
|
|
|
|
Use this date for:
|
|
- Article folder name: `~/vault/60_Articles/<article_date>-<slug>/`
|
|
- Article frontmatter `date:` field
|
|
- DO NOT use today's date unless the research has no date field at all
|
|
|
|
### Step 2: Read the selected research note (Single mode)
|
|
|
|
Read the full content of the selected research note using `read_file`.
|
|
|
|
Extract:
|
|
- **Title** — from H1
|
|
- **Key concepts** — from H2/H3 headings
|
|
- **Main points** — from body content
|
|
- **Related notes** — from wikilinks `[[...]]`
|
|
- **Area** — from frontmatter `area:` field
|
|
- **Tags** — from frontmatter `tags:` field
|
|
|
|
### Step 3: Summarize and ask for focus
|
|
|
|
Present a summary of the research:
|
|
|
|
```
|
|
📄 Research: [Title]
|
|
📂 Area: [Area]
|
|
🏷️ Tags: [tags]
|
|
|
|
สรุปประเด็นหลัก:
|
|
1. [Key point 1]
|
|
2. [Key point 2]
|
|
3. [Key point 3]
|
|
...
|
|
|
|
บทความนี้ควรเน้นประเด็นไหนบ้าง?
|
|
(เลือกหมายเลข หรือพิมพ์ประเด็นเพิ่มเติม)
|
|
```
|
|
|
|
### Step 4: Iterate on details
|
|
|
|
After user selects focus areas, ask follow-up questions:
|
|
|
|
- มีมุมมองเฉพาะที่อยากเพิ่มไหม?
|
|
- กลุ่มเป้าหมายของบทความคือใคร?
|
|
- โทนบทความ: ทางการ / casual / technical?
|
|
- ความยาวที่ต้องการ: สั้น (800 words) / กลาง (1500) / ยาว (2000+)?
|
|
- ต้องการ SEO keyword ไหม? ถ้ามี คืออะไร?
|
|
|
|
### Step 5: Additional research (optional)
|
|
|
|
If the research note is thin or user wants more depth:
|
|
|
|
1. Search internet for current information on the topic
|
|
2. Look for statistics, examples, case studies
|
|
3. Find expert quotes or references
|
|
4. Check what competitors have written (SERP analysis)
|
|
|
|
### Step 6: Create brief.md
|
|
|
|
Create the article brief at:
|
|
|
|
```
|
|
~/vault/60_Articles/<client-id>/YYYY-MM-DD-<slug>/brief.md
|
|
```
|
|
|
|
Where `<slug>` is derived from the topic (kebab-case, English).
|
|
|
|
```markdown
|
|
---
|
|
type: brief
|
|
status: ready
|
|
created: YYYY-MM-DD
|
|
source_research: "[[Original Research Title]]"
|
|
source_path: "30_Research/Area/Topic/Topic.md"
|
|
---
|
|
|
|
# Article Brief: [Topic]
|
|
|
|
## Source
|
|
- Research: [[Original Research Title]]
|
|
- Path: 30_Research/Area/Topic/Topic.md
|
|
|
|
## Target
|
|
- Audience: [who]
|
|
- Tone: [formal/casual/technical]
|
|
- Length: [target word count]
|
|
- SEO Keyword: [if provided]
|
|
|
|
## Key Angles
|
|
1. [Angle 1]
|
|
2. [Angle 2]
|
|
3. [Angle 3]
|
|
|
|
## Outline
|
|
### H1: [Proposed title]
|
|
### H2: [Section 1]
|
|
- [Key point]
|
|
### H2: [Section 2]
|
|
- [Key point]
|
|
### H2: [Section 3]
|
|
- [Key point]
|
|
|
|
## Research Data
|
|
[Key statistics, quotes, facts from the research note + internet research]
|
|
|
|
## Related Content
|
|
- [[Related Note 1]]
|
|
- [[Related Note 2]]
|
|
|
|
## Content Requirements
|
|
- Featured image: [description]
|
|
- Inline images: [list with descriptions]
|
|
- FAQ section: [yes/no, topics if yes]
|
|
- Schema markup: [Article/BlogPosting]
|
|
```
|
|
|
|
### Step 7: Mark research note as used AND move to Archive
|
|
|
|
Update the original research note's frontmatter:
|
|
|
|
```yaml
|
|
---
|
|
...existing frontmatter...
|
|
article_created: true
|
|
article_link: "[[YYYY-MM-DD-slug]]"
|
|
---
|
|
```
|
|
|
|
Use `patch` to add the two fields to the frontmatter.
|
|
|
|
Then move the research note to the client's Archive folder:
|
|
|
|
```bash
|
|
# Determine source location
|
|
SOURCE_DIR=$(dirname "$RESEARCH_PATH")
|
|
ARCHIVE_DIR="$SOURCE_DIR/Archive"
|
|
|
|
# Create Archive if it doesn't exist
|
|
mkdir -p "$ARCHIVE_DIR"
|
|
|
|
# Move the file
|
|
mv "$RESEARCH_PATH" "$ARCHIVE_DIR/$(basename $RESEARCH_PATH)"
|
|
```
|
|
|
|
**Important**: Only move if the research is in a client-specific folder.
|
|
If the research is in `30_Research/general/`, mark as used but DON'T move
|
|
(general research can be reused for other clients).
|
|
|
|
### Step 8: Confirm
|
|
|
|
```
|
|
✅ Brief created: ~/vault/60_Articles/<client-id>/YYYY-MM-DD-slug/brief.md
|
|
✅ Research marked: article_created: true
|
|
✅ Research archived: moved to 30_Research/<client-id>/Archive/
|
|
|
|
ถัดไป: โหลด mm-content-writer skill เพื่อเริ่มเขียนบทความ
|
|
```
|
|
|
|
## Output
|
|
|
|
- `~/vault/60_Articles/<client-id>/<date>-<slug>/brief.md` — Article brief ready for mm-content-writer
|
|
- Updated frontmatter in `30_Research/<client-id>/` source note
|
|
- Source note moved to `30_Research/<client-id>/Archive/` (if client-specific)
|
|
|
|
## Notes
|
|
|
|
- If user can't find what they want in 30_Research/, suggest `article-idea-extract` skill
|
|
- The brief is the contract between Data Stage and Content Stage — be thorough
|
|
- Always preserve the wikilink to the source research
|