refactor: Reorganize skill numbering and update documentation
Skill Numbering Changes: - 01-03: OurDigital core (was 30-32) - 31-32: Notion tools (was 01-02) - 99_archive: Renamed from _archive for sorting New Files: - AGENTS.md: Claude Code agent routing guide - requirements.txt for 00-claude-code-setting, 32-notion-writer, 43-jamie-youtube-manager Documentation Updates: - CLAUDE.md: Updated skill inventory (23 skills) - AUDIT_REPORT.md: Current completion status (91%) - Archived REFACTORING_PLAN.md (most tasks complete) Removed: - ga-agent-skills/ (moved to separate repo ~/Project/dintel-ga4-agent) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
64
custom-skills/01-ourdigital-research/code/CLAUDE.md
Normal file
64
custom-skills/01-ourdigital-research/code/CLAUDE.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# CLAUDE.md
|
||||
|
||||
## Overview
|
||||
|
||||
Research-to-publication workflow toolkit. Exports research to Ulysses for OurDigital blog publishing.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Export research to Ulysses
|
||||
python scripts/export_to_ulysses.py --input research.md --group "Blog Drafts"
|
||||
```
|
||||
|
||||
## Scripts
|
||||
|
||||
| Script | Purpose |
|
||||
|--------|---------|
|
||||
| `export_to_ulysses.py` | Export markdown to Ulysses app for editing/publishing |
|
||||
|
||||
## Ulysses Export
|
||||
|
||||
```bash
|
||||
# Basic export
|
||||
python scripts/export_to_ulysses.py --input research.md
|
||||
|
||||
# With target group
|
||||
python scripts/export_to_ulysses.py \
|
||||
--input research.md \
|
||||
--group "Blog Drafts" \
|
||||
--tags "research,draft"
|
||||
|
||||
# From Notion export
|
||||
python scripts/export_to_ulysses.py \
|
||||
--notion-export notion_export.zip \
|
||||
--group "From Notion"
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Complete research in Claude/Notion
|
||||
2. Export to markdown format
|
||||
3. Run export script to Ulysses
|
||||
4. Edit and polish in Ulysses
|
||||
5. Publish to Ghost/OurDigital
|
||||
|
||||
## Output Targets
|
||||
|
||||
- **blog.ourdigital.org** - Main blog
|
||||
- **journal.ourdigital.org** - Long-form essays
|
||||
- **ourstory.day** - Personal narratives
|
||||
|
||||
## Ulysses Integration
|
||||
|
||||
Requires:
|
||||
- Ulysses app installed
|
||||
- x-callback-url scheme enabled
|
||||
- Target group created in Ulysses
|
||||
|
||||
## References
|
||||
|
||||
See `references/` for:
|
||||
- `blog-style-guide.md` - OurDigital writing style
|
||||
- `publishing-checklist.md` - Pre-publish checklist
|
||||
- `ghost-api-config.md` - Ghost CMS integration
|
||||
@@ -0,0 +1,87 @@
|
||||
# {제목 / Title}
|
||||
|
||||
> **요약**: {1-2문장 핵심 요약}
|
||||
>
|
||||
> **Summary**: {1-2 sentence key takeaway}
|
||||
|
||||
---
|
||||
|
||||
## 들어가며 / Introduction
|
||||
|
||||
{독자의 관심을 끄는 도입부. 문제 제기, 질문, 또는 흥미로운 사실로 시작.}
|
||||
|
||||
{Opening hook that captures reader attention. Start with a problem, question, or interesting fact.}
|
||||
|
||||
---
|
||||
|
||||
## 배경 / Background
|
||||
|
||||
{주제에 대한 맥락 설명. 왜 이것이 중요한지, 현재 상황은 어떤지.}
|
||||
|
||||
{Context for the topic. Why this matters, current state of things.}
|
||||
|
||||
---
|
||||
|
||||
## 핵심 내용 / Key Points
|
||||
|
||||
### 첫 번째 포인트 / First Point
|
||||
|
||||
{상세 설명과 근거}
|
||||
|
||||
{Detailed explanation with evidence}
|
||||
|
||||
### 두 번째 포인트 / Second Point
|
||||
|
||||
{상세 설명과 근거}
|
||||
|
||||
{Detailed explanation with evidence}
|
||||
|
||||
### 세 번째 포인트 / Third Point
|
||||
|
||||
{상세 설명과 근거}
|
||||
|
||||
{Detailed explanation with evidence}
|
||||
|
||||
---
|
||||
|
||||
## 실무 적용 / Practical Application
|
||||
|
||||
{독자가 바로 적용할 수 있는 액션 아이템}
|
||||
|
||||
{Actionable items readers can implement immediately}
|
||||
|
||||
1. **첫 번째 단계**: {설명}
|
||||
2. **두 번째 단계**: {설명}
|
||||
3. **세 번째 단계**: {설명}
|
||||
|
||||
---
|
||||
|
||||
## 마치며 / Conclusion
|
||||
|
||||
{핵심 메시지 재강조, 독자에게 남기는 생각거리 또는 다음 단계}
|
||||
|
||||
{Reinforce key message, leave reader with thought or next step}
|
||||
|
||||
---
|
||||
|
||||
## 참고 자료 / References
|
||||
|
||||
- [출처 1](URL)
|
||||
- [출처 2](URL)
|
||||
- [출처 3](URL)
|
||||
|
||||
---
|
||||
|
||||
**태그 / Tags**: #{tag1} #{tag2} #{tag3}
|
||||
|
||||
**카테고리 / Category**: {category}
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
SEO Meta (Ghost/CMS용):
|
||||
- Meta Title: {60자 이내}
|
||||
- Meta Description: {150-160자}
|
||||
- URL Slug: {짧고-명확한-슬러그}
|
||||
- Featured Image Alt: {이미지 설명}
|
||||
-->
|
||||
@@ -0,0 +1,114 @@
|
||||
# OurDigital Blog Style Guide
|
||||
|
||||
## Channel-Specific Voice & Tone
|
||||
|
||||
### blog.ourdigital.org (Korean)
|
||||
**Voice**: 전문적이면서 친근한 선배 마케터
|
||||
**Tone**: 실용적, 데이터 기반, 인사이트 중심
|
||||
|
||||
Writing patterns:
|
||||
- 제목: 핵심 키워드 포함, 30자 이내
|
||||
- 도입부: 독자의 고민/질문으로 시작
|
||||
- 본문: 번호 매기기보다 소제목 활용
|
||||
- 전문용어: 한글(영문) 형식 - 예: 검색엔진최적화(SEO)
|
||||
- 문장: ~입니다/~습니다 경어체
|
||||
- 단락: 3-4문장, 모바일 가독성 고려
|
||||
|
||||
Example opening:
|
||||
```
|
||||
"구글 상위 노출, 왜 이렇게 어려울까요?
|
||||
많은 마케터들이 SEO에 시간을 투자하지만
|
||||
결과가 보이지 않아 좌절합니다.
|
||||
오늘은 실제로 효과를 본 전략 3가지를 공유합니다."
|
||||
```
|
||||
|
||||
### journal.ourdigital.org (English)
|
||||
**Voice**: Thoughtful industry analyst
|
||||
**Tone**: Insightful, evidence-based, forward-looking
|
||||
|
||||
Writing patterns:
|
||||
- Headlines: Clear value proposition, under 60 chars
|
||||
- Opening: Hook with industry trend or data point
|
||||
- Body: Structured arguments with supporting evidence
|
||||
- Terminology: Define jargon on first use
|
||||
- Style: Active voice, varied sentence length
|
||||
- Paragraphs: 2-4 sentences for scannability
|
||||
|
||||
Example opening:
|
||||
```
|
||||
"The digital marketing landscape shifted dramatically in 2024.
|
||||
With AI reshaping search behavior, traditional SEO metrics
|
||||
no longer tell the full story. Here's what the data reveals—
|
||||
and what it means for your strategy."
|
||||
```
|
||||
|
||||
### ourstory.day (Korean)
|
||||
**Voice**: 성찰하는 동료, 이야기꾼
|
||||
**Tone**: 개인적, 진솔한, 영감을 주는
|
||||
|
||||
Writing patterns:
|
||||
- 제목: 감성적, 질문형 또는 은유적
|
||||
- 도입부: 개인 경험이나 장면 묘사로 시작
|
||||
- 본문: 이야기 흐름, 대화체 허용
|
||||
- 문장: ~해요/~네요 부드러운 경어체 가능
|
||||
- 단락: 자유로운 길이, 호흡에 따라
|
||||
- 마무리: 열린 질문 또는 여운
|
||||
|
||||
Example opening:
|
||||
```
|
||||
"새벽 5시, 아이를 깨우지 않으려 살금살금 책상에 앉았다.
|
||||
화면에는 어제 작성한 리포트가 그대로 남아있었다.
|
||||
'이게 정말 내가 하고 싶은 일인가?'
|
||||
문득 그런 생각이 스쳤다."
|
||||
```
|
||||
|
||||
### Medium (English)
|
||||
**Voice**: Knowledgeable peer sharing discoveries
|
||||
**Tone**: Conversational, practical, slightly informal
|
||||
|
||||
Writing patterns:
|
||||
- Headlines: Curiosity-driven, specific numbers work well
|
||||
- Opening: Personal anecdote or surprising fact
|
||||
- Body: Mix of storytelling and practical advice
|
||||
- Style: First person allowed, contractions okay
|
||||
- Subheadings: Every 300-400 words
|
||||
- Closing: Clear takeaway or call-to-action
|
||||
|
||||
Example opening:
|
||||
```
|
||||
"I've spent 15 years in digital marketing, and nothing
|
||||
prepared me for what happened when AI entered the chat.
|
||||
Last month, I ran an experiment that changed how I think
|
||||
about content strategy entirely. Let me walk you through it."
|
||||
```
|
||||
|
||||
## Universal Guidelines
|
||||
|
||||
### SEO Considerations
|
||||
- Primary keyword in title and first 100 words
|
||||
- Secondary keywords naturally distributed
|
||||
- Meta description: 150-160 chars, action-oriented
|
||||
- URL slug: Short, keyword-rich, no dates
|
||||
- Alt text for all images
|
||||
|
||||
### Formatting Rules
|
||||
- Use `##` for main sections, `###` for subsections
|
||||
- Code blocks with language specification
|
||||
- Blockquotes for key insights or quotes
|
||||
- Bold for emphasis (sparingly)
|
||||
- Lists only when truly listing items
|
||||
|
||||
### Citation Style
|
||||
- Inline links preferred over footnotes
|
||||
- Source attribution: "According to [Source Name](URL)..."
|
||||
- Data citations: Include date of data
|
||||
- Internal links: Reference related OurDigital posts
|
||||
|
||||
## Word Count Guidelines
|
||||
|
||||
| Channel | Target | Min | Max |
|
||||
|---------|--------|-----|-----|
|
||||
| blog.ourdigital.org | 1,500 | 1,000 | 2,500 |
|
||||
| journal.ourdigital.org | 1,800 | 1,200 | 3,000 |
|
||||
| ourstory.day | 1,000 | 500 | 2,000 |
|
||||
| Medium | 1,500 | 800 | 2,500 |
|
||||
@@ -0,0 +1,74 @@
|
||||
# Ghost Admin API Configuration
|
||||
|
||||
## Configured Channels
|
||||
|
||||
| Channel | Domain | API Status |
|
||||
|---------|--------|------------|
|
||||
| blog.ourdigital.org | Korean main blog | ✅ Configured |
|
||||
| journal.ourdigital.org | English journal | ✅ Configured |
|
||||
| ourstory.day | Personal essays | ✅ Configured |
|
||||
|
||||
## API Endpoints
|
||||
|
||||
Base URL pattern: `https://{domain}/ghost/api/admin/`
|
||||
|
||||
### Authentication
|
||||
Ghost Admin API uses JWT tokens generated from Admin API keys.
|
||||
|
||||
```
|
||||
Admin API Key Format: {id}:{secret}
|
||||
- id: 24 hex characters
|
||||
- secret: 64 hex characters
|
||||
```
|
||||
|
||||
### Key Endpoints
|
||||
|
||||
| Endpoint | Method | Purpose |
|
||||
|----------|--------|---------|
|
||||
| `/posts/` | POST | Create new post |
|
||||
| `/posts/{id}/` | PUT | Update existing post |
|
||||
| `/images/upload/` | POST | Upload image |
|
||||
| `/tags/` | GET/POST | Manage tags |
|
||||
|
||||
### Post Creation Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"posts": [{
|
||||
"title": "Post Title",
|
||||
"html": "<p>Content in HTML</p>",
|
||||
"status": "draft",
|
||||
"tags": [{"name": "tag1"}, {"name": "tag2"}],
|
||||
"feature_image": "https://...",
|
||||
"meta_title": "SEO Title",
|
||||
"meta_description": "SEO Description",
|
||||
"og_title": "Social Title",
|
||||
"og_description": "Social Description",
|
||||
"published_at": "2024-01-15T09:00:00.000Z"
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
### Status Options
|
||||
- `draft`: Save without publishing
|
||||
- `published`: Publish immediately
|
||||
- `scheduled`: Schedule for future (requires `published_at`)
|
||||
|
||||
## Future Automation Opportunities
|
||||
|
||||
### Zapier Integration Points
|
||||
1. **Trigger**: New Notion page in "Working with AI" → Create Ghost draft
|
||||
2. **Trigger**: Ghost post published → Share to social channels
|
||||
3. **Trigger**: New MD file in iCloud folder → Create Ghost draft
|
||||
|
||||
### n8n Workflow Ideas
|
||||
1. Research complete → Auto-create drafts across all relevant channels
|
||||
2. Scheduled publishing queue management
|
||||
3. Cross-posting between Ghost instances
|
||||
|
||||
## Security Notes
|
||||
|
||||
- API keys stored in environment variables
|
||||
- Never expose keys in code or logs
|
||||
- Rotate keys if compromised
|
||||
- Use separate keys for different integrations
|
||||
@@ -0,0 +1,118 @@
|
||||
# Pre-Publishing Checklist
|
||||
|
||||
## Content Quality
|
||||
|
||||
### Writing
|
||||
- [ ] Title is compelling and SEO-optimized
|
||||
- [ ] Opening hook captures attention within first 3 sentences
|
||||
- [ ] Clear thesis/value proposition stated early
|
||||
- [ ] Logical flow between sections
|
||||
- [ ] Strong conclusion with takeaway or CTA
|
||||
- [ ] Proofread for typos and grammar (Ulysses phase)
|
||||
|
||||
### Accuracy
|
||||
- [ ] All facts verified with sources
|
||||
- [ ] Statistics include source and date
|
||||
- [ ] Links tested and working
|
||||
- [ ] No outdated information presented as current
|
||||
- [ ] Technical accuracy reviewed
|
||||
|
||||
### Formatting
|
||||
- [ ] Consistent heading hierarchy (H2 → H3 → H4)
|
||||
- [ ] Paragraphs appropriately sized for readability
|
||||
- [ ] Code blocks properly formatted with language tags
|
||||
- [ ] Lists used only for actual list content
|
||||
- [ ] Emphasis (bold/italic) used sparingly
|
||||
|
||||
## SEO Elements
|
||||
|
||||
### On-Page
|
||||
- [ ] Primary keyword in title
|
||||
- [ ] Primary keyword in first 100 words
|
||||
- [ ] Secondary keywords naturally distributed
|
||||
- [ ] URL slug: short, descriptive, keyword-rich
|
||||
- [ ] Meta description: 150-160 chars, includes CTA
|
||||
|
||||
### Technical
|
||||
- [ ] Internal links to related posts (2-3 minimum)
|
||||
- [ ] External links to authoritative sources
|
||||
- [ ] Alt text for all images
|
||||
- [ ] Heading structure is semantic (one H1 only)
|
||||
|
||||
## Visual Elements (Web UI Phase)
|
||||
|
||||
### Featured Image
|
||||
- [ ] High quality, relevant to content
|
||||
- [ ] Proper dimensions for channel
|
||||
- Ghost: 1200 x 630px recommended
|
||||
- Medium: 1500 x 750px recommended
|
||||
- [ ] Alt text added
|
||||
- [ ] Copyright/license verified
|
||||
|
||||
### In-Post Images
|
||||
- [ ] Compressed for web (< 200KB ideal)
|
||||
- [ ] Descriptive filenames (not IMG_001.jpg)
|
||||
- [ ] Captions added where helpful
|
||||
- [ ] Alt text for accessibility
|
||||
|
||||
## Channel-Specific
|
||||
|
||||
### Ghost (blog.ourdigital.org, journal.ourdigital.org, ourstory.day)
|
||||
|
||||
**Before Publishing:**
|
||||
- [ ] Tags assigned (3-5 relevant tags)
|
||||
- [ ] Author profile selected
|
||||
- [ ] Excerpt/custom snippet written
|
||||
- [ ] Publication date/time set
|
||||
- [ ] Email newsletter toggle reviewed
|
||||
|
||||
**Ghost Admin Settings:**
|
||||
- [ ] Code injection (if needed): header/footer scripts
|
||||
- [ ] Facebook/Twitter card preview checked
|
||||
- [ ] Canonical URL set (if republishing)
|
||||
|
||||
### Medium
|
||||
|
||||
**Before Publishing:**
|
||||
- [ ] Tags selected (max 5)
|
||||
- [ ] Publication submitted to (if applicable)
|
||||
- [ ] Subtitle/kicker written
|
||||
- [ ] Reading time appears reasonable
|
||||
- [ ] Preview in both web and mobile
|
||||
|
||||
**Medium-Specific:**
|
||||
- [ ] No excessive self-promotion
|
||||
- [ ] Paywall setting decided (member-only?)
|
||||
- [ ] Cross-post canonical URL added (if from blog)
|
||||
|
||||
## Final Verification
|
||||
|
||||
### Preview Check
|
||||
- [ ] Desktop preview looks correct
|
||||
- [ ] Mobile preview is readable
|
||||
- [ ] Links work in preview mode
|
||||
- [ ] Images display properly
|
||||
- [ ] Social share preview correct
|
||||
|
||||
### Publication
|
||||
- [ ] Schedule vs. publish now decided
|
||||
- [ ] Social sharing plan ready
|
||||
- [ ] Newsletter inclusion decided
|
||||
- [ ] Analytics tracking confirmed
|
||||
|
||||
## Post-Publication
|
||||
|
||||
### Immediate (within 1 hour)
|
||||
- [ ] Verify live URL works
|
||||
- [ ] Share to social channels
|
||||
- [ ] Notify team/subscribers if relevant
|
||||
|
||||
### Follow-up (within 24-48 hours)
|
||||
- [ ] Check initial engagement metrics
|
||||
- [ ] Respond to comments
|
||||
- [ ] Fix any reported issues
|
||||
|
||||
### Long-term (monthly)
|
||||
- [ ] Review analytics performance
|
||||
- [ ] Update outdated information
|
||||
- [ ] Add internal links from newer posts
|
||||
@@ -0,0 +1,133 @@
|
||||
# Research Frameworks
|
||||
|
||||
## Framework Selection Guide
|
||||
|
||||
| Topic Type | Framework | Best For |
|
||||
|------------|-----------|----------|
|
||||
| Trend analysis | STEEP + Timeline | Industry shifts, emerging tech |
|
||||
| Problem-solution | Problem Tree | Pain points, how-to guides |
|
||||
| Comparison | Feature Matrix | Tool reviews, option analysis |
|
||||
| Strategy | SWOT + Action | Business recommendations |
|
||||
| Technical | Layered Deep-Dive | Implementation guides |
|
||||
|
||||
## STEEP + Timeline Framework
|
||||
|
||||
For analyzing trends and industry changes:
|
||||
|
||||
```
|
||||
S - Social: User behavior changes, demographics
|
||||
T - Technological: New tools, platforms, capabilities
|
||||
E - Economic: Market conditions, pricing trends
|
||||
E - Environmental: Sustainability, resource factors
|
||||
P - Political/Legal: Regulations, compliance
|
||||
|
||||
Timeline:
|
||||
- Past (2-3 years): What changed?
|
||||
- Present: Current state of play
|
||||
- Future (1-2 years): Projections
|
||||
```
|
||||
|
||||
## Problem Tree Framework
|
||||
|
||||
For diagnostic and solution-oriented research:
|
||||
|
||||
```
|
||||
ROOT PROBLEM
|
||||
├── Cause 1
|
||||
│ ├── Sub-cause 1.1
|
||||
│ └── Sub-cause 1.2
|
||||
├── Cause 2
|
||||
│ └── Sub-cause 2.1
|
||||
└── Cause 3
|
||||
|
||||
SOLUTIONS
|
||||
├── Solution A → addresses Cause 1
|
||||
├── Solution B → addresses Cause 2
|
||||
└── Solution C → addresses Cause 3
|
||||
```
|
||||
|
||||
## Feature Matrix Framework
|
||||
|
||||
For comparisons and evaluations:
|
||||
|
||||
```
|
||||
| Criteria | Option A | Option B | Option C | Weight |
|
||||
|----------|----------|----------|----------|--------|
|
||||
| Feature 1 | ⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ | High |
|
||||
| Feature 2 | ⭐⭐ | ⭐⭐⭐ | ⭐ | Medium |
|
||||
| Feature 3 | ⭐ | ⭐⭐ | ⭐⭐⭐ | Low |
|
||||
| Price | $$$ | $$ | $ | High |
|
||||
|
||||
Weighted Score: Calculate based on importance
|
||||
Recommendation: Based on user's priority
|
||||
```
|
||||
|
||||
## Layered Deep-Dive Framework
|
||||
|
||||
For technical and implementation topics:
|
||||
|
||||
```
|
||||
Layer 1: Concept (What is it?)
|
||||
- Definition
|
||||
- Key components
|
||||
- How it works (simplified)
|
||||
|
||||
Layer 2: Context (Why does it matter?)
|
||||
- Business value
|
||||
- Use cases
|
||||
- When to use vs. alternatives
|
||||
|
||||
Layer 3: Implementation (How to do it?)
|
||||
- Prerequisites
|
||||
- Step-by-step process
|
||||
- Code/configuration examples
|
||||
|
||||
Layer 4: Optimization (How to do it well?)
|
||||
- Best practices
|
||||
- Common pitfalls
|
||||
- Advanced techniques
|
||||
|
||||
Layer 5: Measurement (How to know it works?)
|
||||
- Success metrics
|
||||
- Monitoring approach
|
||||
- Iteration guidance
|
||||
```
|
||||
|
||||
## Research Question Templates
|
||||
|
||||
### Exploratory Questions
|
||||
- "What is the current state of [topic]?"
|
||||
- "How has [topic] evolved in the past [timeframe]?"
|
||||
- "Who are the key players/stakeholders in [topic]?"
|
||||
|
||||
### Analytical Questions
|
||||
- "What factors drive [outcome] in [context]?"
|
||||
- "How does [variable A] affect [variable B]?"
|
||||
- "What patterns emerge when comparing [X] and [Y]?"
|
||||
|
||||
### Evaluative Questions
|
||||
- "What are the strengths and limitations of [approach]?"
|
||||
- "How effective is [solution] for [problem]?"
|
||||
- "What criteria should guide [decision]?"
|
||||
|
||||
### Practical Questions
|
||||
- "How can [audience] implement [solution]?"
|
||||
- "What resources are needed for [action]?"
|
||||
- "What are the risks and mitigations for [approach]?"
|
||||
|
||||
## Source Priority
|
||||
|
||||
1. **Primary**: Official documentation, research papers, authoritative reports
|
||||
2. **Secondary**: Industry publications, expert analysis, case studies
|
||||
3. **Tertiary**: News articles, blog posts, community discussions
|
||||
|
||||
Always cross-reference claims across multiple source types.
|
||||
|
||||
## Data Quality Checklist
|
||||
|
||||
- [ ] Source credibility verified
|
||||
- [ ] Publication date recent (within context)
|
||||
- [ ] Statistics include sample size/methodology
|
||||
- [ ] Claims are falsifiable/verifiable
|
||||
- [ ] Potential biases identified
|
||||
- [ ] Conflicting viewpoints considered
|
||||
@@ -0,0 +1,113 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Ulysses Export Helper
|
||||
|
||||
Exports markdown files to iCloud folder for Ulysses sync.
|
||||
Designed for OurDigital research-to-publisher workflow.
|
||||
|
||||
Usage:
|
||||
python export_to_ulysses.py --content "# Title\n\nContent..." --filename "my-post.md"
|
||||
python export_to_ulysses.py --file /path/to/draft.md --channel blog
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
# Default iCloud paths (user should customize)
|
||||
ICLOUD_BASE = Path.home() / "Library/Mobile Documents/com~apple~CloudDocs"
|
||||
|
||||
# Channel-specific folders (customize based on Ulysses library structure)
|
||||
CHANNEL_FOLDERS = {
|
||||
"blog": "Ulysses/OurDigital/Blog Drafts",
|
||||
"journal": "Ulysses/OurDigital/Journal Drafts",
|
||||
"ourstory": "Ulysses/OurDigital/OurStory Drafts",
|
||||
"medium": "Ulysses/OurDigital/Medium Drafts",
|
||||
"default": "Ulysses/Blog Drafts"
|
||||
}
|
||||
|
||||
def get_export_path(channel: str = "default") -> Path:
|
||||
"""Get the export path for a specific channel."""
|
||||
folder = CHANNEL_FOLDERS.get(channel, CHANNEL_FOLDERS["default"])
|
||||
export_path = ICLOUD_BASE / folder
|
||||
|
||||
# Create directory if it doesn't exist
|
||||
export_path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
return export_path
|
||||
|
||||
def generate_filename(title: str = None) -> str:
|
||||
"""Generate a filename with timestamp."""
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M")
|
||||
if title:
|
||||
# Clean title for filename
|
||||
clean_title = "".join(c if c.isalnum() or c in "- " else "" for c in title)
|
||||
clean_title = clean_title.replace(" ", "-").lower()[:50]
|
||||
return f"{timestamp}_{clean_title}.md"
|
||||
return f"{timestamp}_draft.md"
|
||||
|
||||
def export_content(content: str, filename: str, channel: str = "default") -> Path:
|
||||
"""Export content to the appropriate iCloud folder."""
|
||||
export_path = get_export_path(channel)
|
||||
file_path = export_path / filename
|
||||
|
||||
# Add Ulysses-friendly frontmatter if not present
|
||||
if not content.startswith("---"):
|
||||
frontmatter = f"""---
|
||||
created: {datetime.now().isoformat()}
|
||||
channel: {channel}
|
||||
status: draft
|
||||
---
|
||||
|
||||
"""
|
||||
content = frontmatter + content
|
||||
|
||||
file_path.write_text(content, encoding="utf-8")
|
||||
return file_path
|
||||
|
||||
def export_file(source_path: str, channel: str = "default") -> Path:
|
||||
"""Copy an existing file to the iCloud folder."""
|
||||
source = Path(source_path)
|
||||
if not source.exists():
|
||||
raise FileNotFoundError(f"Source file not found: {source_path}")
|
||||
|
||||
content = source.read_text(encoding="utf-8")
|
||||
filename = source.name
|
||||
|
||||
return export_content(content, filename, channel)
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Export markdown to Ulysses via iCloud")
|
||||
parser.add_argument("--content", help="Markdown content to export")
|
||||
parser.add_argument("--file", help="Path to existing markdown file")
|
||||
parser.add_argument("--filename", help="Output filename (auto-generated if not provided)")
|
||||
parser.add_argument("--channel", choices=list(CHANNEL_FOLDERS.keys()),
|
||||
default="default", help="Target channel/folder")
|
||||
parser.add_argument("--list-paths", action="store_true",
|
||||
help="List configured export paths")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.list_paths:
|
||||
print("Configured export paths:")
|
||||
for channel, folder in CHANNEL_FOLDERS.items():
|
||||
full_path = ICLOUD_BASE / folder
|
||||
exists = "✓" if full_path.exists() else "✗"
|
||||
print(f" [{exists}] {channel}: {full_path}")
|
||||
return
|
||||
|
||||
if args.file:
|
||||
result = export_file(args.file, args.channel)
|
||||
print(f"✓ Exported to: {result}")
|
||||
elif args.content:
|
||||
filename = args.filename or generate_filename()
|
||||
result = export_content(args.content, filename, args.channel)
|
||||
print(f"✓ Exported to: {result}")
|
||||
else:
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,3 @@
|
||||
# 31-ourdigital-research dependencies
|
||||
markdown>=3.5.0
|
||||
python-dotenv>=1.0.0
|
||||
204
custom-skills/01-ourdigital-research/desktop/SKILL.md
Normal file
204
custom-skills/01-ourdigital-research/desktop/SKILL.md
Normal file
@@ -0,0 +1,204 @@
|
||||
---
|
||||
name: ourdigital-research-publisher
|
||||
description: |
|
||||
End-to-end research-to-publication workflow for OurDigital channels. Transforms questions into comprehensive research, then Korean/English blog posts. Use when user wants to: (1) Research a topic deeply, (2) Create research papers from conversations, (3) Write blog posts for OurDigital/Ghost, (4) Execute "research to publish" workflow, (5) Save research to Notion and export to Ulysses. Triggers: "research this", "write a blog about", "publish to OurDigital", "deep dive into", "연구해줘", "블로그 작성", "포스팅 초안".
|
||||
---
|
||||
|
||||
# OurDigital Research-to-Publisher Workflow
|
||||
|
||||
Transform questions into comprehensive research papers and polished blog posts for OurDigital channels.
|
||||
|
||||
## Workflow Overview
|
||||
|
||||
```
|
||||
Phase 1: Discovery → Phase 2: Research Planning → Phase 3: Deep Research
|
||||
↓
|
||||
Phase 4: Research Paper → Phase 5: Notion Save → Phase 6: Blog Draft
|
||||
↓
|
||||
Phase 7: Ulysses Export → Phase 8: Publishing Guidance
|
||||
```
|
||||
|
||||
## Phase 1: Discovery
|
||||
|
||||
**Goal**: Understand user's question and refine scope.
|
||||
|
||||
1. Acknowledge the topic/question
|
||||
2. Ask clarifying questions (max 3 per turn):
|
||||
- Target audience? (전문가/일반인/마케터)
|
||||
- Depth level? (개요/심층분석/실무가이드)
|
||||
- Specific angles or concerns?
|
||||
3. Confirm research scope before proceeding
|
||||
|
||||
**Output**: Clear research objective statement
|
||||
|
||||
## Phase 2: Research Planning
|
||||
|
||||
**Goal**: Create structured research instruction.
|
||||
|
||||
Generate research plan with:
|
||||
- Primary research questions (3-5)
|
||||
- Secondary questions for depth
|
||||
- Suggested tools/sources:
|
||||
- Web search for current info
|
||||
- Google Drive for internal docs
|
||||
- Notion for past research
|
||||
- Amplitude for analytics data (if relevant)
|
||||
- Expected deliverables
|
||||
|
||||
**Output**: Numbered research instruction list
|
||||
|
||||
## Phase 3: Deep Research
|
||||
|
||||
**Goal**: Execute comprehensive multi-source research.
|
||||
|
||||
Tools to leverage:
|
||||
- `web_search` / `web_fetch`: Current information, statistics, trends
|
||||
- `google_drive_search`: Internal documents, past reports
|
||||
- `Notion:notion-search`: Previous research, related notes
|
||||
- `Amplitude:search` / `Amplitude:query_*`: Analytics insights (if applicable)
|
||||
- `conversation_search`: Past chat context
|
||||
|
||||
Research execution pattern:
|
||||
1. Start broad (overview searches)
|
||||
2. Deep dive into key subtopics
|
||||
3. Find supporting data/statistics
|
||||
4. Identify expert opinions and case studies
|
||||
5. Cross-reference and validate
|
||||
|
||||
**Output**: Organized research findings with citations
|
||||
|
||||
## Phase 4: Research Paper (Artifact)
|
||||
|
||||
**Goal**: Synthesize findings into comprehensive document.
|
||||
|
||||
Create HTML artifact with:
|
||||
```
|
||||
Structure:
|
||||
├── Executive Summary (핵심 요약)
|
||||
├── Background & Context (배경)
|
||||
├── Key Findings (주요 발견)
|
||||
│ ├── Finding 1 with evidence
|
||||
│ ├── Finding 2 with evidence
|
||||
│ └── Finding 3 with evidence
|
||||
├── Analysis & Implications (분석 및 시사점)
|
||||
├── Recommendations (제언)
|
||||
├── References & Sources (참고자료)
|
||||
└── Appendix (부록) - if needed
|
||||
```
|
||||
|
||||
Style: Professional, data-driven, bilingual key terms
|
||||
|
||||
**Output**: Comprehensive research paper artifact
|
||||
|
||||
## Phase 5: Notion Save
|
||||
|
||||
**Goal**: Archive research to Working with AI database.
|
||||
|
||||
Auto-save to Notion with:
|
||||
- **Database**: 🤖 Working with AI (data_source_id: f8f19ede-32bd-43ac-9f60-0651f6f40afe)
|
||||
- **Properties**:
|
||||
- Name: [Research topic]
|
||||
- Type: "Research"
|
||||
- Category: Based on topic (e.g., "SEO", "AI Literacy", "Digital Marketing")
|
||||
- Topic: Relevant tags
|
||||
- AI used: ["Claude 4.5"]
|
||||
- Status: "Done"
|
||||
- AI summary: 2-3 sentence summary
|
||||
|
||||
**Output**: Notion page URL confirmation
|
||||
|
||||
## Phase 6: Blog Draft
|
||||
|
||||
**Goal**: Transform research into engaging blog post.
|
||||
|
||||
**PROMPT USER for channel selection:**
|
||||
```
|
||||
📝 블로그 채널을 선택해주세요:
|
||||
|
||||
1. blog.ourdigital.org (Korean, 디지털 마케팅/SEO/데이터)
|
||||
2. journal.ourdigital.org (English, professional insights)
|
||||
3. ourstory.day (Korean, 에세이/성찰/개인적 이야기)
|
||||
4. Medium (English, broader tech audience)
|
||||
|
||||
선택: [번호]
|
||||
```
|
||||
|
||||
Generate MD file based on channel:
|
||||
- See `references/blog-style-guide.md` for tone/voice
|
||||
- Use `assets/blog-template.md` as structure reference
|
||||
- Korean channels: 한글 작성, 전문용어는 영문 병기
|
||||
- English channels: Professional but accessible
|
||||
|
||||
**Output**: Complete .md blog draft file
|
||||
|
||||
## Phase 7: Ulysses Export
|
||||
|
||||
**Goal**: Deliver MD file for Ulysses editing.
|
||||
|
||||
Export path: iCloud Drive folder for Ulysses sync
|
||||
|
||||
**PROMPT USER (first time only):**
|
||||
```
|
||||
📁 Ulysses 동기화 폴더 경로를 알려주세요:
|
||||
|
||||
예시:
|
||||
- /Users/[username]/Library/Mobile Documents/com~apple~CloudDocs/Ulysses/Blog Drafts/
|
||||
- 또는 선호하는 iCloud 폴더 경로
|
||||
|
||||
(최초 1회 설정 후 기억됩니다)
|
||||
```
|
||||
|
||||
After receiving path:
|
||||
1. Save .md file to specified iCloud folder
|
||||
2. Confirm file location
|
||||
3. Provide Ulysses opening instructions
|
||||
|
||||
**Output**: MD file in iCloud + path confirmation
|
||||
|
||||
## Phase 8: Publishing Guidance
|
||||
|
||||
**Goal**: Guide user through final publishing steps.
|
||||
|
||||
Provide channel-specific checklist:
|
||||
|
||||
### Ghost (blog.ourdigital.org / journal.ourdigital.org)
|
||||
- [ ] Ulysses에서 최종 교정 완료
|
||||
- [ ] Ghost 관리자 페이지에서 새 포스트 생성
|
||||
- [ ] MD 콘텐츠 붙여넣기
|
||||
- [ ] Featured image 설정
|
||||
- [ ] SEO meta (title, description, URL slug)
|
||||
- [ ] Tags/Categories 설정
|
||||
- [ ] 발행 또는 예약 발행
|
||||
|
||||
### ourstory.day (Ghost)
|
||||
- Same as above, personal essay tone check
|
||||
|
||||
### Medium
|
||||
- [ ] Medium 에디터에서 새 story
|
||||
- [ ] Import from clipboard or MD
|
||||
- [ ] Add images/embeds
|
||||
- [ ] Tags (max 5)
|
||||
- [ ] Publication 선택 (if applicable)
|
||||
|
||||
**OFFER**: "Ghost API로 자동 발행을 원하시면 알려주세요."
|
||||
|
||||
---
|
||||
|
||||
## Quick Commands
|
||||
|
||||
| Command | Action |
|
||||
|---------|--------|
|
||||
| "연구 시작" / "research this" | Start Phase 1 |
|
||||
| "초안 작성" / "draft blog" | Skip to Phase 6 (if research exists) |
|
||||
| "노션 저장" | Execute Phase 5 only |
|
||||
| "발행 가이드" | Show Phase 8 checklist |
|
||||
| "handoff summary" | Generate context transfer summary |
|
||||
|
||||
## Channel Reference
|
||||
|
||||
| Channel | Language | Tone | Topics |
|
||||
|---------|----------|------|--------|
|
||||
| blog.ourdigital.org | Korean | Professional, practical | SEO, Digital Marketing, Data |
|
||||
| journal.ourdigital.org | English | Insightful, analytical | Industry trends, Best practices |
|
||||
| ourstory.day | Korean | Personal, reflective | Essays, Life lessons, Reflections |
|
||||
| Medium | English | Accessible, engaging | Tech, Marketing, AI |
|
||||
Reference in New Issue
Block a user