Filter notes suitable for publishing from an Obsidian Note vault, assess suitability, batch topic selection, dual-channel processing (fast conversion / deep research), parallel Agent dispatch.
Prerequisites
| Tool | Type | Required | Installation method |
|---|---|---|---|
| Python 3 | CLI | Yes | Preinstalled on macOS |
| PyYAML | CLI | Yes | pip install pyyaml |
| writing-assistant | skill | No | Provided by personal plugin |
Do not proactively check these tools when loading the skill. When a command fails due to a missing tool, guide the user step by step through installation and configuration.
When not applicable
- When the vault has fewer than 5 notes, manual topic selection is faster
- You only want to convert a single already-determined note — just run
<skill-dir>/scripts/note-to-blog.py convert "<path>" - A blog draft already exists and only needs proofreading — use
writing-assistant
Script location
All deterministic operations are handled by Python scripts:
<skill-dir>/scripts/note-to-blog.py (collect / convert / state subcommands)
Path configuration is located in user-config.md. In the following Bash examples,
<PLACEHOLDER> must be replaced with the values from that configuration file.
Workflow overview
步骤 1 步骤 2 步骤 3 步骤 4 步骤 5
收集 ──▶ 选择深度 ──▶ 按深度处理 ──▶ 执行 ──▶ 汇总
(script) (user) ├─ L1 浏览 (Agent Teams) (report)
├─ L2 推荐
└─ L3 深探
│
交互 ──▶ 分配处理通道 ──▶ 确认
Step 1: Collect candidate notes
Use the paths in user-config.md to run collect:
python3 <skill-dir>/scripts/note-to-blog.py collect \
--note-repo "<NOTE_REPO>" \
--blog-content "<BLOG_CONTENT>" \
--project-paths <PROJECT_PATHS> \
--history-file "<HISTORY_FILE>"
The script writes a JSON object to standard output, containing:
candidates: all eligible notes, containing title, summary, char_count, and outgoing_linksclusters: wikilink hub nodes with more than 3 inbound links and related notespublished_posts: title, tags, and collection of existing blog postssession_keywords: activity signals from recent Claude Code sessionsstats: total_scanned, filtered_out, and candidates_count
After reading the JSON, proceed to Step 2.
Step 2: Choose processing depth
Show the data scale and provide Level options:
collect 完成:
候选笔记: {candidates_count} 篇 (总扫描 {total_scanned}, 过滤 {filtered_out})
主题簇: {clusters_count} 个 (3+ 引用 hub)
可选深度:
Level 1 浏览 直接展示候选列表,手动选择 0 额外 token
Level 2 推荐 LLM 评估 + 主题簇分析 ~2k token ← 推荐
Level 3 深探 Level 2 + 读取 hub 笔记全文 ~5k+ token
选择 Level (1-3)?
Depth quick reference
| Level | Name | Evaluation method | Subsequent flow |
|---|---|---|---|
| 1 | Browse | No LLM, candidates sorted by character count descending | User selects directly → all fast track |
| 2 | Recommended | LLM evaluates summaries + topic clusters → 5-8 recommendations | fast/deep track assignment |
| 3 | Deep dive | Level 2 + read the full text of hub notes | fast/deep track, cluster recommendations are more accurate |
Recommendation logic
| Number of candidates | clusters | Recommendation |
|---|---|---|
| ≤ 10 | any | Level 1 |
| > 10 | 0 | Level 2 |
| > 10 | 1+ | Level 2 |
When the user explicitly says "I want to discover topics" or "what can be integrated" → recommend Level 3.
Step 3: Process by depth
Level 1: Browse
Skip LLM evaluation and display candidates in descending order of char_count:
# 标题 字数 链接数
1 关于后LLM时代的代码Review 3200 5
2 SSH私钥加密 1200 2
3 Feed内容阅读姿势 1800 3
...
The user selects by number. All options in Level 1 only enter Fast track; Deep track is not provided.
After selection, proceed directly to "Confirm and Execute."
Level 2: Recommend
Use scoring-criteria.md Executes one LLM evaluation using the prompt template in .
Input: Use collect The candidates, clusters, published_posts, and
session_keywords in the JSON generate the evaluation prompt.
Output: The LLM must return a JSON array containing 5 to 8 recommendations. For the full format, see scoring-criteria.md。
When the response is not valid JSON, add explicit formatting requirements and retry once.
After evaluation is complete, proceed to "Interactive Selection".
Level 3: Deep Exploration
The handling is the same as Level 2, but before calling the LLM, read the full text of the center note of each topic cluster and append it to the evaluation prompt.
For collect In the JSON, hub_path For each cluster that is not empty:
- Read the full text of the center note from the Note repository.
- Append the full text to the LLM prompt's
## Hub 笔记全文section. For the Level 3 input format, see scoring-criteria.md。
This allows the LLM to recommend topic clusters based on actual content rather than relying only on metadata.
After evaluation is complete, proceed to "Interactive Selection".
Interactive Selection (Level 2/3)
Display Recommendations
Display the recommendation list using a hybrid table:
# 类型 标题 适配分 目标 工作量 活跃 重复风险
1 单篇 后LLM时代代码Review 92 blog 小 ★★★ 无
2 主题簇 优雅的哲学 (9篇关联) 88 blog 大 ★ 无
3 单篇 SSH私钥加密 85 til 小 ─ 无
...
User Operations
| Operation | Example | Result |
|---|---|---|
| Select and assign tracks | "1 and 3 fast track, 2 deep" | Add to the queue by the specified tracks |
| Override collection | "Put 1 in til" | Modify the target collection |
| Batch skip | "Skip 4~6, reason: private" | Via state skip Mark as skipped |
| View more | "Anything else" | Request more recommendations |
| Check status | "status" | Run state status |
When skippingRun immediately:
python3 <skill-dir>/scripts/note-to-blog.py state skip "<path>" --reason "<reason>" \
--note-repo "<NOTE_REPO>"
Handle track assignment
| Track | When to use | Handling method |
|---|---|---|
| Fast(fast) | Independent and basically complete notes | Script conversion → Agent review → draft |
| Deep(deep) | Topic clusters or rough notes that require research | Agent reads all related notes → research report |
Default rule:effort: "小" Goes to Fast;type: "cluster" or effort: "大" Goes to
Deep. The final decision is made by the user.
Confirm and execute
All Levels require displaying a confirmation summary:
确认选择:
Fast track:
1. 后LLM时代代码Review → blog/
3. SSH私钥加密 → til/
Deep track:
2. 优雅的哲学 (9篇关联) → blog/
开始处理?
Wait for user confirmation before dispatching tasks.
Parallel dispatch
Use the Task tool to dispatch N Agents in parallel, with one task corresponding to each selected item.
Other Agent environments: The following Fast/Deep track tasks are independent of each other and can be executed sequentially in order.
总编 (Main Agent)
├── Task Agent 1: 文章 A (fast track)
├── Task Agent 2: 文章 B (fast track)
└── Task Agent 3: 主题簇 C (deep track)
Launch all Agents in one message. Each Agent uses the general-purpose type, and the prompt provides all information needed to complete the task.
For the complete Agent prompt templates for Fast Track and Deep Track, see agent-instructions.md。
Status update
Each Agent does not directly update .note-to-blog.json. After all tasks are complete, the main Agent updates the status sequentially:
python3 <skill-dir>/scripts/note-to-blog.py state draft "<note_path>" \
--target "<collection>/<slug>.md" \
--note-repo "<NOTE_REPO>"
Deep track projects are not marked as drafted, waiting for the user to decide further.
Summary results
After all Agents are complete, display a unified summary:
Fast Track 完成:
✓ 后LLM时代代码Review → repos/bokushi/src/content/blog/llm-code-review.md
- 转换正常,无问题
✓ SSH私钥加密 → repos/bokushi/src/content/til/ssh-key-encryption.md
- 发现 1 个 TODO 标记需要手动处理
Deep Track 完成:
📋 优雅的哲学 (9篇关联)
- 研究报告已生成
- 下一步? a) 按大纲写作 b) 修改大纲 c) 暂不处理
状态更新:
drafted: N 篇
草稿均为 hidden: true,需要手动 review 后改为 false 发布。
建议使用 `writing-assistant` 进行审校。
发布后运行:
python3 <skill-dir>/scripts/note-to-blog.py state publish "<note_path>" --note-repo "<NOTE_REPO>"
Detailed reference
- Path configuration:user-config.md
- LLM evaluation prompts and scoring rules:scoring-criteria.md
- Agent prompt templates:agent-instructions.md