名称: tapestry 描述: 统一内容提取和行动规划。当用户说“tapestry <URL>”、“weave <URL>”、“help me plan <URL>”、“extract and plan <URL>”、“make this actionable <URL>”或类似短语,表示他们想要提取内容并创建行动规划时使用。自动检测内容类型(YouTube视频、文章、PDF)并进行相应处理。 允许工具:
- Bash
- Read
- Write
Tapestry: 统一内容提取 + 行动规划
这是主技能,协调整个Tapestry工作流:
- 从URL检测内容类型
- 使用适当技能提取内容
- 自动创建Ship-Learn-Next行动规划
何时使用此技能
在用户以下情况时激活:
- 说“tapestry [URL]”
- 说“weave [URL]”
- 说“help me plan [URL]”
- 说“extract and plan [URL]”
- 说“make this actionable [URL]”
- 说“turn [URL] into a plan”
- 提供URL并要求“从这学习和实施”
- 想要完整的Tapestry工作流(提取 → 规划)
关键词注意:tapestry, weave, plan, actionable, extract and plan, make a plan, turn into action
如何工作
完整工作流:
- 检测URL类型(YouTube、文章、PDF)
- 提取内容使用适当技能:
- YouTube → youtube-transcript技能
- 文章 → article-extractor技能
- PDF → 下载并提取文本
- 创建行动规划使用ship-learn-next技能
- 保存两者内容文件和规划文件
- 向用户呈现摘要
URL检测逻辑
YouTube视频
检测模式:
youtube.com/watch?v=youtu.be/youtube.com/shorts/m.youtube.com/watch?v=
操作: 使用youtube-transcript技能
网络文章/博客帖子
检测模式:
http://或https://- 非YouTube、非PDF
- 常见域名:medium.com, substack.com, dev.to等
- 任何HTML页面
操作: 使用article-extractor技能
PDF文档
检测模式:
- URL以
.pdf结尾 - URL返回
Content-Type: application/pdf
操作: 下载并提取文本
其他内容
回退:
- 尝试article-extractor(适用于大多数HTML)
- 如果失败,通知用户不支持的类型
逐步工作流
步骤1:检测内容类型
URL="$1"
# 检查YouTube
if [[ "$URL" =~ youtube\.com/watch || "$URL" =~ youtu\.be/ || "$URL" =~ youtube\.com/shorts ]]; then
CONTENT_TYPE="youtube"
# 检查PDF
elif [[ "$URL" =~ \.pdf$ ]]; then
CONTENT_TYPE="pdf"
# 检查URL是否返回PDF
elif curl -sI "$URL" | grep -i "Content-Type: application/pdf" > /dev/null; then
CONTENT_TYPE="pdf"
# 默认为文章
else
CONTENT_TYPE="article"
fi
echo "📍 检测到: $CONTENT_TYPE"
步骤2:按类型提取内容
YouTube视频
# 使用youtube-transcript技能工作流
echo "📺 提取YouTube字幕..."
# 1. 检查yt-dlp
if ! command -v yt-dlp &> /dev/null; then
echo "安装yt-dlp..."
brew install yt-dlp
fi
# 2. 获取视频标题
VIDEO_TITLE=$(yt-dlp --print "%(title)s" "$URL" | tr '/' '_' | tr ':' '-' | tr '?' '' | tr '"' '')
# 3. 下载字幕
yt-dlp --write-auto-sub --skip-download --sub-langs en --output "temp_transcript" "$URL"
# 4. 转换为干净文本(去重)
python3 -c "
import sys, re
seen = set()
vtt_file = 'temp_transcript.en.vtt'
try:
with open(vtt_file, 'r') as f:
for line in f:
line = line.strip()
if line and not line.startswith('WEBVTT') and not line.startswith('Kind:') and not line.startswith('Language:') and '-->' not in line:
clean = re.sub('<[^>]*>', '', line)
clean = clean.replace('&', '&').replace('>', '>').replace('<', '<')
if clean and clean not in seen:
print(clean)
seen.add(clean)
except FileNotFoundError:
print('错误:未找到字幕文件', file=sys.stderr)
sys.exit(1)
" > "${VIDEO_TITLE}.txt"
# 5. 清理
rm -f temp_transcript.en.vtt
CONTENT_FILE="${VIDEO_TITLE}.txt"
echo "✓ 保存字幕: $CONTENT_FILE"
文章/博客帖子
# 使用article-extractor技能工作流
echo "📄 提取文章内容..."
# 1. 检查提取工具
if command -v reader &> /dev/null; then
TOOL="reader"
elif command -v trafilatura &> /dev/null; then
TOOL="trafilatura"
else
TOOL="fallback"
fi
echo "使用: $TOOL"
# 2. 基于工具提取
case $TOOL in
reader)
reader "$URL" > temp_article.txt
ARTICLE_TITLE=$(head -n 1 temp_article.txt | sed 's/^# //')
;;
trafilatura)
METADATA=$(trafilatura --URL "$URL" --json)
ARTICLE_TITLE=$(echo "$METADATA" | python3 -c "import json, sys; print(json.load(sys.stdin).get('title', '文章'))")
trafilatura --URL "$URL" --output-format txt --no-comments > temp_article.txt
;;
fallback)
ARTICLE_TITLE=$(curl -s "$URL" | grep -oP '<title>\K[^<]+' | head -n 1)
ARTICLE_TITLE=${ARTICLE_TITLE%% - *}
curl -s "$URL" | python3 -c "
from html.parser import HTMLParser
import sys
class ArticleExtractor(HTMLParser):
def __init__(self):
super().__init__()
self.content = []
self.skip_tags = {'script', 'style', 'nav', 'header', 'footer', 'aside', 'form'}
self.in_content = False
def handle_starttag(self, tag, attrs):
if tag not in self.skip_tags and tag in {'p', 'article', 'main'}:
self.in_content = True
def handle_data(self, data):
if self.in_content and data.strip():
self.content.append(data.strip())
def get_content(self):
return '
'.join(self.content)
parser = ArticleExtractor()
parser.feed(sys.stdin.read())
print(parser.get_content())
" > temp_article.txt
;;
esac
# 3. 清理文件名
FILENAME=$(echo "$ARTICLE_TITLE" | tr '/' '-' | tr ':' '-' | tr '?' '' | tr '"' '' | cut -c 1-80 | sed 's/ *$//')
CONTENT_FILE="${FILENAME}.txt"
mv temp_article.txt "$CONTENT_FILE"
echo "✓ 保存文章: $CONTENT_FILE"
PDF文档
# 下载并提取PDF
echo "📑 下载PDF..."
# 1. 下载PDF
PDF_FILENAME=$(basename "$URL")
curl -L -o "$PDF_FILENAME" "$URL"
# 2. 使用pdftotext提取文本(如果可用)
if command -v pdftotext &> /dev/null; then
pdftotext "$PDF_FILENAME" temp_pdf.txt
CONTENT_FILE="${PDF_FILENAME%.pdf}.txt"
mv temp_pdf.txt "$CONTENT_FILE"
echo "✓ 从PDF提取文本: $CONTENT_FILE"
# 可选保留PDF
echo "保留原始PDF?(y/n)"
read -r KEEP_PDF
if [[ ! "$KEEP_PDF" =~ ^[Yy]$ ]]; then
rm "$PDF_FILENAME"
fi
else
# 无pdftotext可用
echo "⚠️ 未找到pdftotext。已下载PDF但未提取。"
echo " 安装命令:brew install poppler"
CONTENT_FILE="$PDF_FILENAME"
fi
步骤3:创建Ship-Learn-Next行动规划
重要:提取内容后总是创建行动规划。
# 读取提取的内容
CONTENT_FILE="[来自前一步]"
# 调用ship-learn-next技能逻辑:
# 1. 读取内容文件
# 2. 提取核心可操作课程
# 3. 创建5-rep渐进规划
# 4. 保存为:Ship-Learn-Next Plan - [任务标题].md
# 参见ship-learn-next/SKILL.md获取完整详情
规划创建关键点:
- 提取可操作课程(不仅仅是摘要)
- 定义具体的4-8周任务
- 创建Rep 1(本周可交付)
- 设计Reps 2-5(渐进迭代)
- 保存规划到markdown文件
- 使用格式:
Ship-Learn-Next Plan - [简短任务标题].md
步骤4:呈现结果
向用户展示:
✅ Tapestry工作流完成!
📥 内容已提取:
✓ [内容类型]:[标题]
✓ 保存到:[filename.txt]
✓ [X] 词提取
📋 行动规划已创建:
✓ 任务:[任务标题]
✓ 保存到:Ship-Learn-Next Plan - [标题].md
🎯 您的任务:[一行摘要]
📍 Rep 1(本周):[Rep 1目标]
您何时交付Rep 1?
完整Tapestry工作流脚本
#!/bin/bash
# Tapestry:提取内容 + 创建行动规划
# 用法:tapestry <URL>
URL="$1"
if [ -z "$URL" ]; then
echo "用法:tapestry <URL>"
exit 1
fi
echo "🧵 Tapestry工作流启动..."
echo "URL: $URL"
echo ""
# 步骤1:检测内容类型
if [[ "$URL" =~ youtube\.com/watch || "$URL" =~ youtu\.be/ || "$URL" =~ youtube\.com/shorts ]]; then
CONTENT_TYPE="youtube"
elif [[ "$URL" =~ \.pdf$ ]] || curl -sI "$URL" | grep -iq "Content-Type: application/pdf"; then
CONTENT_TYPE="pdf"
else
CONTENT_TYPE="article"
fi
echo "📍 检测到: $CONTENT_TYPE"
echo ""
# 步骤2:提取内容
case $CONTENT_TYPE in
youtube)
echo "📺 提取YouTube字幕..."
# [来自上面的YouTube提取代码]
;;
article)
echo "📄 提取文章..."
# [来自上面的文章提取代码]
;;
pdf)
echo "📑 下载PDF..."
# [来自上面的PDF提取代码]
;;
esac
echo ""
# 步骤3:创建行动规划
echo "🚀 创建Ship-Learn-Next行动规划..."
# [使用ship-learn-next技能的规划创建]
echo ""
echo "✅ Tapestry工作流完成!"
echo ""
echo "📥 内容: $CONTENT_FILE"
echo "📋 规划: Ship-Learn-Next Plan - [标题].md"
echo ""
echo "🎯 下一步:查看您的行动规划并交付Rep 1!"
错误处理
常见问题:
1. 不支持URL类型
- 尝试文章提取作为回退
- 如果失败:“无法从此URL类型提取内容”
2. 未提取内容
- 检查URL是否可访问
- 尝试替代提取方法
- 通知用户:“提取失败。URL可能需要认证。”
3. 工具未安装
- 可能时自动安装(yt-dlp、reader、trafilatura)
- 如果自动安装失败,提供安装说明
- 回退方法可用时使用
4. 空或无效内容
- 创建规划前验证文件有内容
- 如果提取失败,不创建规划
- 规划前向用户显示预览
最佳实践
- ✅ 总是显示检测结果(“📍 检测到: youtube”)
- ✅ 为每个步骤显示进度
- ✅ 保存内容文件和规划文件
- ✅ 显示提取内容的预览(前10行)
- ✅ 自动创建规划(不问)
- ✅ 结束时呈现清晰摘要
- ✅ 询问承诺问题:“您何时交付Rep 1?”
使用示例
示例1:YouTube视频(使用“tapestry”)
用户:tapestry https://www.youtube.com/watch?v=dQw4w9WgXcQ
Claude:
🧵 Tapestry工作流启动...
📍 检测到:youtube
📺 提取YouTube字幕...
✓ 保存字幕:Never Gonna Give You Up.txt
🚀 创建行动规划...
✓ 任务:掌握视频制作
✓ 保存规划:Ship-Learn-Next Plan - 掌握视频制作.md
✅ 完成!您何时交付Rep 1?
示例2:文章(使用“weave”)
用户:weave https://example.com/how-to-build-saas
Claude:
🧵 Tapestry工作流启动...
📍 检测到:article
📄 提取文章...
✓ 使用reader(Mozilla Readability)
✓ 保存文章:How to Build a SaaS.txt
🚀 创建行动规划...
✓ 任务:构建SaaS MVP
✓ 保存规划:Ship-Learn-Next Plan - 构建SaaS MVP.md
✅ 完成!您何时交付Rep 1?
示例3:PDF(使用“help me plan”)
用户:help me plan https://example.com/research-paper.pdf
Claude:
🧵 Tapestry工作流启动...
📍 检测到:pdf
📑 下载PDF...
✓ 下载:research-paper.pdf
✓ 提取文本:research-paper.txt
🚀 创建行动规划...
✓ 任务:应用研究成果
✓ 保存规划:Ship-Learn-Next Plan - 应用研究成果.md
✅ 完成!您何时交付Rep 1?
依赖项
此技能协调其他技能,需要:
对于YouTube:
- yt-dlp(自动安装)
- Python 3(用于去重)
对于文章:
- reader(npm)或 trafilatura(pip)
- 如果都不可用,回退到基本curl
对于PDFs:
- curl(内置)
- pdftotext(可选 - 来自poppler包)
- 安装:
brew install poppler(macOS) - 安装:
apt install poppler-utils(Linux)
- 安装:
对于规划:
- 无额外需求(使用内置工具)
哲学
Tapestry将学习内容编织成行动。
统一工作流确保您从不只是消费内容 - 您总是创建一个实施规划。这将被动学习转化为主动构建。
提取 → 规划 → 交付 → 学习 → 下一步。
这就是Tapestry的方式。