Extract writing style features from multimodal input and store them in the powermem knowledge base, supporting intelligent conflict detection and manual arbitration.
Core Process
Execute the following steps to extract and store style features:
0. Environment Preparation (First Execution)
Before running any script, first prepare .venv. The following approach does not depend on a fixed absolute path:
ROOT_DIR="$(cd ../.. && pwd)"
PYTHON_BIN="$ROOT_DIR/.venv/bin/python"
test -d "$ROOT_DIR/.venv" || python3 -m venv "$ROOT_DIR/.venv"
"$PYTHON_BIN" -m pip install -U pip
"$PYTHON_BIN" -m pip install -U powermem python-dotenv
All subsequent Python scripts use $PYTHON_BIN for execution, without depending on whether the current shell has activated the virtual environment.
Configuration Management Notes:
- On first use, the script will automatically create the
../pmem-config/shared configuration directory - containing
pmem-key.env(user configuration) and.env(full template) - Configuration priority: system environment variables >
pmem-config/pmem-key.env>pmem-config/.env - The two skills (extraction and generation) share the same configuration, so configuring once is sufficient
0.1 Configuration Detection (Required Step)
Configuration detection must be executed before each run:
"$PYTHON_BIN" scripts/check_config.py
If configuration detection fails (exit code is 1):
-
Detection output description (fixed text is retained in the Skill; only missing items are dynamically output by the script):
# 运行配置检测(脚本会动态输出“当前缺失的配置项”) "$PYTHON_BIN" scripts/check_config.pyOutput structure example (the list of missing items is subject to the script's actual detection results):
⚠️ 检测到以下配置项缺失或未设置: [这里的缺失项列表由 check_config.py 动态输出] 📝 共享配置文件位置: /path/to/skills/pmem-config/pmem-key.env 请点击上面的共享配置文件路径,进入文件夹后手动编辑文件:`pmem-key.env`。 手动填写完成后,返回聊天框回复:已完成 -
The Agent should perform the following operations:
- Clearly inform the user of the shared configuration directory path:
../pmem-config/ - Clearly inform the user of the filename that needs to be edited:
pmem-key.env - Do not collect configuration values item by item in the conversation; only wait for the user to fill them in manually
- After the user replies "completed", rerun
check_config.pyto verify the configuration
- Clearly inform the user of the shared configuration directory path:
-
Configuration writing example:
# 用户手动打开并编辑:../pmem-config/pmem-key.env # 在文件中填写缺失项,例如: LLM_API_KEY=sk-xxxxx EMBEDDING_API_KEY=sk-yyyyy # 重新检测 "$PYTHON_BIN" scripts/check_config.py -
Important Notes:
- The configuration will be persistently saved in
../pmem-config/pmem-key.env - There is no need to reconfigure the next time either skill is used
- Users can also manually edit this file to modify the configuration
- The configuration will be persistently saved in
After configuration detection passes, continue to the subsequent steps.
1. Obtain Content
Choose the processing method based on the input type:
URL input: call baoyu-url-to-markdown to obtain the webpage content
SKILL_URL_DIR="$HOME/.cursor/skills/baoyu-url-to-markdown"
npx -y bun ${SKILL_URL_DIR}/scripts/main.ts <url> -o /tmp/extracted_content.md
Then read /tmp/extracted_content.md as the input for subsequent analysis.
Text/file input: directly use the provided content.
Skill file input: read the content of the SKILL.md file.
Image input: use visual capabilities to extract the text layout and visual style elements from the image.
2. Feature Extraction
Use an LLM to strip factual information from the content, retaining only the style skeleton. Use the following Prompt template:
你是一位专业的写作风格分析师。请从下面的内容中提取纯粹的风格特征,忽略所有具体的事实、观点和信息内容。
请从以下维度提取风格特征:
1. **叙事节奏 (narrative_rhythm)**:句子长度偏好、段落节奏、信息密度
2. **金句位置 (key_phrase_placement)**:强调内容的位置习惯(段首/段中/段尾)
3. **排版符号 (formatting_symbols)**:特殊引号、列表符号、分隔符使用习惯
4. **标点习惯 (punctuation_habits)**:省略号、破折号、感叹号等使用频率和场景
5. **段落结构 (paragraph_structure)**:段落组织方式(总分总、递进、并列等)
6. **情感基调 (emotional_tone)**:理性/感性、克制/热烈、严肃/幽默等
7. **修辞手法 (rhetorical_devices)**:比喻、排比、反问等惯用修辞
8. **开篇风格 (opening_style)**:如何引入话题(直入主题/铺垫/引用/提问)
9. **结尾风格 (closing_style)**:如何收束内容(总结/升华/留白/号召)
请以 JSON 格式输出,每个维度用简洁的描述性语言概括:
{
"narrative_rhythm": "描述",
"key_phrase_placement": "描述",
"formatting_symbols": "描述",
"punctuation_habits": "描述",
"paragraph_structure": "描述",
"emotional_tone": "描述",
"rhetorical_devices": "描述",
"opening_style": "描述",
"closing_style": "描述"
}
待分析内容:
---
{CONTENT}
---
Save the extracted features in JSON format (for example /tmp/extracted_features.json),Then automatically proceed to the next step of conflict detection。
3. Automatic Conflict Detection
No user action required; the system automatically uses the script to search for similar Profiles that already exist in powermem and detects whether conflicts exist:
"$PYTHON_BIN" scripts/search_profiles.py \
--features /tmp/extracted_features.json \
--threshold 0.85
The script will output:
- Whether a similar Profile is found
- Similarity score
- Whether conflicting features exist
- Conflict details (if any)
4. Manual arbitration (only when there is a conflict)
Pause only when a conflict is detected, show the comparison to the user and wait for a choice:
检测到风格特征冲突:
【已存 Profile: default】
- 叙事节奏: 短句为主,每段2-4行
- 情感基调: 理性克制
【新提取特征】
- 叙事节奏: 长句排比,情绪化段落
- 情感基调: 热烈煽情
请选择处理方式:
1. 抛弃 - 仅作参考,不写入
2. 覆盖 - 用新特征替换旧 Profile
3. 分支 - 保留旧 Profile,新建独立风格变体(需指定名称)
Wait for the user to enter a choice (1/2/3).
If there is no conflict, skip directly to step 5 to collect metadata。
5. Interactively collect metadata
Regardless of whether there is a conflict, after determining the storage mode, immediately proceed to metadata collection, asking the user one by one through dialogue:
Interaction flow(the Agent asks one by one, and after the user answers one, asks the next):
Step 1/6 - Applicable platform:
Agent: 📱 这个风格适合哪些平台?请从以下选项中选择(可多选,用逗号分隔):
1. 小红书
2. Twitter / X
3. 公众号
4. 知乎
5. LinkedIn
6. 通用(不限平台)
7. 其他(请说明)
请输入序号或平台名称(例如:2,3 或 Twitter,公众号)
After the user answers, the Agent confirms and continues.
Step 2/6 - Style tags:
Agent: 🏷️ 用几个词描述这个风格的特点,请从以下选项中选择(可多选,用逗号分隔):
1. 轻松
2. 口语化
3. 专业
4. 严谨
5. 情绪化
6. 理性
7. 幽默
8. 简洁
9. 详细
10. 煽情
11. 克制
12. 热烈
13. 其他(请说明)
请输入序号或标签(例如:1,2,7 或 轻松,口语化,幽默)
After the user answers, the Agent confirms and continues.
Step 3/6 - Overall tone:
Agent: 🎭 这个风格的总体基调是?请选择一个:
1. 轻松愉快
2. 理性克制
3. 热烈煽情
4. 专业严谨
5. 幽默风趣
6. 深沉内敛
7. 激情澎湃
8. 其他(请说明)
请输入序号或描述
After the user answers, the Agent confirms and continues.
Step 4/6 - Brief description:
Agent: 📝 请用一句话描述这个风格的适用场景(可跳过,直接回复"跳过"或留空)
例如:适合日常分享类内容,语气轻松亲切
After the user answers, the Agent confirms and continues.
Step 5/6 - Profile ID:
Agent 首先调用脚本获取智能建议:
"$PYTHON_BIN" scripts/collect_metadata.py --features /tmp/extracted_features.json --get-suggestions
{"id": "casual-style", "name": "轻松风格"}
Agent: 💡 系统建议的 Profile ID 是:casual-style
🆔 请选择:
1. 使用默认建议(casual-style)
或直接输入自定义 ID(只能使用小写字母、数字和连字符)
After the user answers, the Agent confirms and continues.
Step 6/6 - Profile name:
Agent: 💡 系统建议的显示名称是:轻松风格
📛 请选择:
1. 使用默认建议(轻松风格)
或直接输入自定义名称
After the user answers, the Agent summarizes all information and confirms.
After collection is complete, the Agent calls the script to save the metadata:
"$PYTHON_BIN" scripts/collect_metadata.py \
--features /tmp/extracted_features.json \
--platforms "Twitter,公众号" \
--tags "轻松,口语化,幽默" \
--tone "理性克制" \
--description "适合日常分享类内容,语气轻松亲切" \
--profile-id "xiaohongshu-casual" \
--profile-name "小红书轻松版" \
--output /tmp/metadata.json
6. Store the Profile
Use the collected metadata to perform storage:
No conflict - automatically create new:
"$PYTHON_BIN" scripts/store_profile.py \
--features /tmp/extracted_features.json \
--mode new \
--source "来源标题或URL" \
--profile-id $(jq -r '.profile_id' /tmp/metadata.json) \
--profile-name $(jq -r '.profile_name' /tmp/metadata.json) \
--tags $(jq -r '.tags | join(",")' /tmp/metadata.json) \
--platforms $(jq -r '.platforms | join(",")' /tmp/metadata.json) \
--tone $(jq -r '.tone' /tmp/metadata.json) \
--description $(jq -r '.description' /tmp/metadata.json)
Overwrite mode and branch mode are the same, using the same parameters.
7. Confirm the result
After storage is complete, list all current Profiles for the user to confirm:
"$PYTHON_BIN" scripts/list_profiles.py
Auxiliary tools
List all stored Profiles:
"$PYTHON_BIN" scripts/list_profiles.py
View the Profile data structure description: refer to references/profile_schema.md
Environment requirements
- Python environment: use the project's
.venvvirtual environment - Dependencies: powermem SDK (automatically loads/initializes on script startup
.envconfiguration) - baoyu-url-to-markdown skill (required when processing URL input)
Usage examples
Complete flow (recommended):
用户:"帮我分析这篇文章的写作风格并保存:[粘贴文章内容]"
Agent(自动执行,无需用户干预):
1. 提取特征 → 保存到 /tmp/extracted_features.json
2. 自动检测冲突 → 无冲突
3. 开始逐个询问元数据(用户交互):
步骤 1/6:适用平台?
→ Agent 展示选项,等待用户回答
→ 用户:"2,3"(Twitter 和公众号)
→ Agent:"✓ 已选择:Twitter, 公众号"
步骤 2/6:风格标签?
→ Agent 展示选项,等待用户回答
→ 用户:"轻松,口语化,幽默"
→ Agent:"✓ 已选择:轻松, 口语化, 幽默"
步骤 3/6:总体基调?
→ Agent 展示选项,等待用户回答
→ 用户:"2"(理性克制)
→ Agent:"✓ 已选择:理性克制"
步骤 4/6:简短说明?
→ Agent 询问
→ 用户:"适合日常分享类内容,语气轻松亲切"
→ Agent:"✓ 已填写"
步骤 5/6:Profile ID?
→ Agent 获取智能建议并展示:"系统建议:casual-style"
→ Agent:"请选择:1. 使用默认建议 或直接输入自定义 ID"
→ 用户:"1"(使用建议)或 "xiaohongshu-casual"(自定义)
→ Agent:"✓ 已设置:casual-style"(或用户输入的值)
步骤 6/6:Profile 名称?
→ Agent 展示建议:"系统建议:轻松风格"
→ Agent:"请选择:1. 使用默认建议 或直接输入自定义名称"
→ 用户:"1"(使用建议)或 "小红书轻松版"(自定义)
→ Agent:"✓ 已设置:轻松风格"(或用户输入的值)
4. Agent 汇总并调用 Python 脚本保存元数据
5. 自动存储 Profile
6. 显示确认信息
整个流程中,用户只需要在元数据收集时依次回答6个问题,其他步骤自动进行。
Learn style from a URL:
用户:"学习这篇文章的风格:https://example.com/article"
Agent(自动):
1. 调用 url-to-markdown → 获取内容
2. 提取特征 → 自动检测冲突 → 无冲突
3. 开始逐个询问元数据(用户依次回答6个问题)
4. 自动存储
Handle style conflicts:
用户:"分析这篇情绪化的文章"
Agent(自动):
1. 提取特征 → 自动检测冲突
2. 发现与 default 冲突 → **暂停,展示冲突对比**
⚠️ 检测到风格冲突...
请选择:1.抛弃 2.覆盖 3.分支
用户选择:3(分支)
3. Agent 继续:开始逐个询问元数据(系统建议 profile_id: emotion-style)
4. 自动存储为独立分支
Notes
- When extracting features, strictly exclude specific factual information and retain only the style skeleton
- Automated flow: feature extraction → conflict detection should proceed automatically, without requiring the user to wait for confirmation
- Pause only when necessary: pause and wait for the user's decision (discard/overwrite/branch) only when a conflict is detected
- Metadata collection is the main interaction point: the Agent asks the 6 questions one by one through dialogue, and after the user answers one question, asks the next
- Do not use interactive CLI tools: collect metadata through Agent dialogue, and finally call a Python script to save
- Before running the script, first ensure
$PYTHON_BINis available, and thatpowermem - The conflict detection threshold (0.85) can be adjusted according to the actual situation
- Profiles are stored in
user_id="style_owner"a fixed namespace, supporting coexistence of multiple Profiles - Each Profile is uniquely identified by
profile_id(such as default, emotion-style) - All scripts first perform environment bootstrap: automatically creating
.env(if missing) and loading the configuration - In branch mode, descriptive naming is recommended (such as "Academic Rigor Version", "Lighthearted Humor Version")
- Metadata is crucial for intelligent matching of the Generation Skill and must not be omitted