Community寫作與編輯github.com

Varnan-Tech/opendirectory

告訴這個技能你發布的產品內容。它會將一篇精美的、帶有日期的條目寫入 docs/changelog.md,並產出一組可直接使用的內容套件:推文串、LinkedIn 貼文、Email 片段以及一句話摘要。

opendirectory 是什麼?

此技能旨在簡化產品發布公告的流程。當你告訴它「你交付了什麼」後,它會自動產生一個結構化的變更日誌條目,並將其附加到 `docs/changelog.md` 檔案中(最新的條目會放在最前面)。同時,它還會為你生成一套完整的行銷內容套件,包含一條推文串、一篇 LinkedIn 貼文、一封 Email 片段以及一句簡潔的摘要。技能支援從自由文字、本地 Git 儲存庫的提交記錄,或 GitHub PR(需提供儲存庫名稱)中讀取輸入。內部流程會依照 `references/` 目錄下的規則進行格式轉換、雜訊過濾與自我品質檢查,確保輸出的內容符合規範(例如:禁止使用浮誇詞彙、推文長度不超過 280 字元等)。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Varnan-Tech/opendirectory/tree/main/skills/product-update-logger

Installed? Explore more 寫作與編輯 skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

product-update-logger

告訴這個技能你發布的產品內容。它會將一篇精美的變更日誌條目寫入 docs/changelog.md(一個持續更新的日誌,最新條目在最前面),並同時產生一組內容套件:推文串、LinkedIn 貼文、Email 片段以及一句話摘要。

輸入來源:來自你訊息的自由文字、從本地儲存庫自動讀取的 Git 提交,或是你提供儲存庫名稱時的 GitHub PR。任何組合都適用。

參考檔案

每次執行前請先閱讀以下檔案:

cat references/changelog-format.md
cat references/content-rules.md
cat references/noise-filter.md

步驟 1:環境檢查

echo "GITHUB_TOKEN: ${GITHUB_TOKEN:-未設定 -- 無法擷取 GitHub PR}"
echo "Git:          $(git rev-parse --is-inside-work-tree 2>/dev/null && echo '偵測到儲存庫' || echo '非 Git 儲存庫')"
echo "Changelog:    $(ls docs/changelog.md 2>/dev/null && echo '已存在' || echo '將會建立')"

注意 Git 是否可用,以及變更日誌是否已存在。這會影響版本標籤的格式。


步驟 2:解析輸入

從對話中收集以下資訊:

  • items -- 你交付內容的自由文字描述(若有多項,請以管道符分隔)。如果 Git 可用,此項可選。
  • since -- 往回查看的天數。預設值:7。使用者可以說「過去兩週」(14)或「自上次發布以來」。
  • repo -- 用於擷取 PR 的 GitHub "owner/repo"。可選。
  • version_label -- 自訂標籤,例如 "v2.1.0" 或 "The Speed Update"。可選;預設為基於日期。

如果使用者未提及任何 items,且沒有 Git 儲存庫: 詢問「你交付了什麼?請逐行列舉功能、修復或改進事項。」

如果 Git 可用,且使用者未指定具體內容: 在步驟 3 中繼續進行 Git 自動讀取。將找到的內容顯示給使用者,並在轉換前請求確認。

寫入解析後的輸入:

python3 << 'PYEOF'
import json, os, re

inp = {
    "items": "",          # 填入:以管道符分隔的自由文字,若無則為 ""
    "since": 7,           # 填入:整數天數
    "repo": "",           # 填入:"owner/repo" 或 ""
    "version_label": ""   # 填入:"" 表示自動(基於日期),或自訂字串
}

with open("/tmp/pul-input.json", "w") as f:
    json.dump(inp, f, indent=2)
print(f"Since: {inp['since']} 天")
print(f"自由文字項目:{inp['items'] or '無(將使用 Git/GitHub)'}")
print(f"GitHub 儲存庫:{inp['repo'] or '無'}")
print(f"版本標籤:{inp['version_label'] or '自動(基於日期)'}")
PYEOF

步驟 3:執行收集腳本

ls scripts/gather.py 2>/dev/null && echo "腳本已找到" || echo "錯誤:找不到 scripts/gather.py"
GITHUB_TOKEN="${GITHUB_TOKEN:-}" python3 scripts/gather.py \
    --since "$(python3 -c "import json; print(json.load(open('/tmp/pul-input.json'))['since'])")" \
    --repo "$(python3 -c "import json; print(json.load(open('/tmp/pul-input.json'))['repo'])")" \
    --items "$(python3 -c "import json; print(json.load(open('/tmp/pul-input.json'))['items'])")" \
    --output /tmp/pul-raw.json

驗證輸出:

python3 -c "
import json
with open('/tmp/pul-raw.json') as f:
    d = json.load(f)
print(f'找到的項目數:      {d[\"total_items\"]}')
print(f'已過濾的雜訊:   {d[\"noise_filtered\"]}')
print(f'Git 可用:    {d[\"git_available\"]}')
print(f'GitHub 可用: {d[\"github_available\"]}')
print(f'來源:git={sum(1 for i in d[\"items\"] if i[\"source\"]==\"git_commit\")}, '
      f'prs={sum(1 for i in d[\"items\"] if i[\"source\"]==\"github_pr\")}, '
      f'text={sum(1 for i in d[\"items\"] if i[\"source\"]==\"free_text\")}')
print()
print('項目:')
for item in d['items']:
    print(f'  [{item[\"source\"]}] {item[\"subject\"]}')
"

如果 total_items == 0: 停止。告訴使用者:「找不到已交付的項目。請描述你交付的內容、指向一個有近期提交記錄的 Git 儲存庫,或使用 repo: owner/repo 加上 GITHUB_TOKEN 來添加 GitHub 儲存庫。」

將項目列表顯示給使用者,並詢問:「這些是我找到的項目。在我寫入變更日誌之前,有任何要添加或刪除的嗎?」

等待確認或編輯。如果使用者說「看起來很好」「請繼續」或未做任何更改,則繼續。如果使用者添加或刪除了項目,請在步驟 4 之前相應地更新 /tmp/pul-raw.json。


步驟 4:產生變更日誌條目

列印項目以供參考:

python3 -c "
import json
with open('/tmp/pul-raw.json') as f:
    d = json.load(f)
print(json.dumps(d['items'], indent=2))
print()
print(f'現有變更日誌格式:{d[\"existing_changelog\"][\"format\"]}')
print(f'最後標籤:{d[\"existing_changelog\"][\"last_label\"]}')
print(f'今天日期:{d[\"date\"]}')
"

AI 指示: 將每個原始項目從技術語言轉換為使用者層面的效益語言。遵循 references/changelog-format.md 中的轉換規則和範例。

規則:

  • 不要編造成果或指標。 「快 40%」必須來自來源資料。如果提交或 PR 中沒有數字,就不要添加。
  • 使用過去式:「新增」「修正」「改善」——而非「新增中」「修正中」
  • 為每個項目分配恰好一個類別: 新增、改善、修正,或底層調整
  • 底層調整: 僅在與開發者相關時包含(API 變更、中斷性變更)。省略空章節。
  • 省略 那些對應到測試變更、CI 變更、僅文件提交的內容

決定版本標籤:

  • 如果有使用者指定的標籤:直接使用
  • 如果 existing_changelog.format == "semver":根據變更進行版本遞增(僅修復則補丁版本,有任何新功能則次版本)
  • 預設值:使用今天的日期的 [月 日, 年] 該週

將條目寫入 /tmp/pul-entry.json:

{
  "label": "2026 年 4 月 23 日該週",
  "date": "2026-04-23",
  "new": [
    {"title": "深色模式", "description": "可在「設定 > 外觀」中切換。適用於所有檢視畫面。"}
  ],
  "improved": [
    {"title": "API 回應時間", "description": "平均快 40%。儀表板現在載入時間低於 1 秒。"}
  ],
  "fixed": [
    {"title": "CSV 匯出", "description": "匯出不再遺漏最後一行。"}
  ],
  "under_the_hood": []
}

驗證條目:

python3 -c "
import json
with open('/tmp/pul-entry.json') as f:
    e = json.load(f)
print(f'標籤:{e[\"label\"]}')
total = 0
for cat in ['new', 'improved', 'fixed', 'under_the_hood']:
    items = e.get(cat, [])
    if items:
        print(f'{cat.replace(\"_\", \" \").title()} ({len(items)} 項):')
        for item in items:
            print(f'  - {item[\"title\"]}:{item[\"description\"]}')
        total += len(items)
print(f'總計:{total} 個項目')
"

步驟 5:產生內容套件

使用步驟 4 的變更日誌條目,產生全部四種內容。嚴格遵循 references/content-rules.md。

一句話摘要(最多 20 字):用一句話涵蓋最重要的 1-2 個項目。用白話,不要用行話。

推文串(3-5 則推文):

  • 推文 1:鉤子——「這週我們交付了 [N] 項東西。」或從最大的功能開始
  • 推文 2-N:每則推文一個項目,最多 1-2 句話
  • 最後一則推文:「變更日誌:[連結]」或「下週更多內容。」(可選)
  • 每則推文嚴格控制在 280 個字元以內
  • 無主題標籤。無破折號。使用主動語態。

LinkedIn 貼文:

  • 無 Markdown(星號在 LinkedIn 上會顯示為文字)
  • 無主題標籤
  • 創辦人口吻:「我們交付了」,而非「我們很興奮地宣布」
  • 短段落(每段 1-2 句),段落間空行
  • 以問題或觀察結尾,而非行動呼籲
  • 總字數 150-400

Email 片段:

  • 主旨:「本週交付內容:[最大項目] + [額外 1 項]」
  • 內文:50-100 字。「以下是我們本週交付的內容:」然後是條列項目。

寫入 /tmp/pul-content.json:

{
  "one_liner": "深色模式、更快的 API,以及修復的匯出錯誤。",
  "tweet_thread": [
    "這週我們交付了 3 項東西。",
    "深色模式上線了。可在「設定 > 外觀」中切換,到處都適用。",
    "API 回應時間現在快了 40%。儀表板在一秒內載入。",
    "修正:CSV 匯出會遺漏最後一行。這個問題解決了。",
    "變更日誌:[連結]"
  ],
  "linkedin_post": "這週我們交付了 3 項更新。\n\n深色模式上線了。可在「設定 > 外觀」中切換,它在每個檢視畫面都適用。\n\nAPI 回應時間平均快了 40%。對大多數使用者來說,儀表板現在在一秒內就能載入。\n\n我們也修了一個錯誤,CSV 匯出會悄悄遺漏最後一行。如果你遇到這個問題而停止匯出,值得再試一次。\n\n你在等什麼功能?",
  "email_snippet": {
    "subject": "本週交付內容:深色模式 + 更快的 API",
    "body": "以下是我們本週交付的內容:\n\n- 深色模式:可在「設定 > 外觀」中切換\n- API 回應時間:快了 40%,儀表板低於 1 秒載入\n- 修正:CSV 匯出不再遺漏最後一行\n\n完整變更日誌如下。"
  }
}

步驟 6:自我品質檢查

python3 -c "
import json, re

with open('/tmp/pul-raw.json') as f:
    raw = json.load(f)
with open('/tmp/pul-entry.json') as f:
    entry = json.load(f)
with open('/tmp/pul-content.json') as f:
    content = json.load(f)

full_text = json.dumps(entry) + json.dumps(content)
fails = 0

# 檢查 1:無破折號
if chr(8212) in full_text:
    print('失敗:發現破折號——請替換為連字號')
    fails += 1
else:
    print('通過:無破折號')

# 檢查 2:禁用詞彙
banned = ['強大', '穩健', '無縫', '創新', '顛覆性',
          '精簡', '槓桿', '轉型', '革命', '興奮地宣布',
          '愉快地宣布', '我們很激動', '尖端', '同級最佳',
          '世界級', '解鎖', '令人愉悅']
found = [w for w in banned if w.lower() in full_text.lower()]
if found:
    print(f'失敗:發現禁用詞彙:{found}')
    fails += 1
else:
    print('通過:無禁用詞彙')

# 檢查 3:推文長度
thread = content.get('tweet_thread', [])
long_tweets = [(i+1, len(t)) for i, t in enumerate(thread) if len(t) > 280]
if long_tweets:
    print(f'失敗:推文超過 280 字元:{long_tweets}')
    fails += 1
else:
    print(f'通過:全部 {len(thread)} 則推文皆少於 280 字元')

# 檢查 4:LinkedIn 無主題標籤
li = content.get('linkedin_post', '')
if re.search(r'#[A-Za-z]', li):
    print('失敗:LinkedIn 貼文中發現主題標籤')
    fails += 1
else:
    print('通過:LinkedIn 中無主題標籤')

# 檢查 5:LinkedIn 中無 Markdown
if '**' in li or '__' in li:
    print('失敗:LinkedIn 中的 Markdown 格式(會顯示為文字星號)')
    fails += 1
else:
    print('通過:LinkedIn 中無 Markdown')

# 檢查 6:一句話摘要字數
one_liner = content.get('one_liner', '')
word_count = len(one_liner.split())
if word_count > 20:
    print(f'失敗:一句話摘要為 {word_count} 個字(最多 20 個)')
    fails += 1
else:
    print(f'通過:一句話摘要為 {word_count} 個字')

# 檢查 7:項目數量
entry_items = (len(entry.get('new', [])) + len(entry.get('improved', [])) +
               len(entry.get('fixed', [])) + len(entry.get('under_the_hood', [])))
raw_total = raw['total_items']
print(f'資訊:變更日誌中有 {entry_items} 個項目,來自 {raw_total} 個原始項目')

print()
print(f'結果:{"通過" if fails == 0 else f"失敗({fails} 個問題)"}')
"

如果有任何檢查失敗: 在繼續步驟 7 之前,修正相關暫存檔案中的問題。修正後重新執行檢查。


步驟 7:附加到變更日誌並儲存內容

python3 << 'PYEOF'
import json, os, re

with open('/tmp/pul-entry.json') as f:
    entry = json.load(f)
with open('/tmp/pul-content.json') as f:
    content = json.load(f)

# 建立新的變更日誌區段
lines = [f"## {entry['label']}", ""]

CAT_HEADERS = {
    "new": "### 新增",
    "improved": "### 改善",
    "fixed": "### 修正",
    "under_the_hood": "### 底層調整",
}

for cat, header in CAT_HEADERS.items():
    items = entry.get(cat, [])
    if items:
        lines.append(header)
        for item in items:
            lines.append(f"- **{item['title']}** -- {item['description']}")
        lines.append("")

lines.append("---")
lines.append("")
new_section = "\n".join(lines)

# 前置插入到 docs/changelog.md
os.makedirs("docs", exist_ok=True)
changelog_path = "docs/changelog.md"

if os.path.exists(changelog_path):
    existing = open(changelog_path).read()
    # 在頂層標題(如果有的話)之後插入,或直接在最頂部插入
    if existing.startswith("# "):
        end_of_heading = existing.index("\n") + 1
        updated = existing[:end_of_heading] + "\n" + new_section + existing[end_of_heading:]
    else:
        updated = new_section + existing
else:
    updated = "# 變更日誌\n\n" + new_section

with open(changelog_path, "w") as f:
    f.write(updated)

print(f"變更日誌已更新:{changelog_path}")

# 儲存內容套件
date = entry['date']
content_dir = "docs/product-updates"
os.makedirs(content_dir, exist_ok=True)
content_path = f"{content_dir}/{date}-content.md"

content_lines = [
    f"# 內容套件:{entry['label']}",
    "",
    "## 一句話摘要",
    content.get('one_liner', ''),
    "",
    "## 推文串",
    "",
]
thread = content.get('tweet_thread', [])
for i, tweet in enumerate(thread, 1):
    content_lines.append(f"[{i}/{len(thread)}] {tweet}")
    content_lines.append("")

content_lines += [
    "## LinkedIn 貼文",
    "",
    content.get('linkedin_post', ''),
    "",
    "## Email 片段",
    "",
    f"主旨:{content.get('email_snippet', {}).get('subject', '')}",
    "",
    content.get('email_snippet', {}).get('body', ''),
    "",
]

with open(content_path, "w") as f:
    f.write("\n".join(content_lines))

print(f"內容套件:{content_path}")
PYEOF

步驟 8:清理並呈現

rm -f /tmp/pul-input.json /tmp/pul-raw.json /tmp/pul-entry.json /tmp/pul-content.json
echo "完成。"

按以下順序呈現給使用者:

1. 變更日誌條目(格式化後的 Markdown,非原始 JSON):

## 2026 年 4 月 23 日該週

### 新增
- **深色模式** -- 可在「設定 > 外觀」中切換。適用於所有檢視畫面。

### 改善
- **API 回應時間** -- 平均快 40%。儀表板現在載入時間低於 1 秒。

### 修正
- **CSV 匯出** -- 匯出不再遺漏最後一行。

2. 一句話摘要(純文字) 3. 推文串(格式化為清單) 4. LinkedIn 貼文(純文字,無 Markdown) 5. Email 片段(主旨 + 內文)

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

Varnan-Tech/opendirectory

Use when the user asks to generate a blog cover image, thumbnail, or article header. Automatically uses modern typography, brand logos, and Google Search grounding to create beautiful 16:9 images with Gemini 3.1 Flash Image Preview.

Varnan-Tech/opendirectory

World-class brand strategist and naming expert. Uses an interrogation-led discovery phase to extract your brand's DNA, then applies scientific naming frameworks (Phonosemantics) and automated multi-TLD domain checking.

Varnan-Tech/opendirectory

Use when the user asks to generate or update a project's CLAUDE or AGENTS context file from a codebase scan. Writes a focused file under 100 lines containing only the non-obvious build commands, conventions, and gotchas Claude Code needs.

Varnan-Tech/opendirectory

Use when the user wants to verify cold emails, enrich a lead list, or autonomously guess email addresses from a CSV using ValidEmail.co or the open-source Reacher engine.

Varnan-Tech/opendirectory

Competitive intelligence orchestrator tracking companies across 8+ platforms (GitHub, Twitter, Reddit, HN, PH, YC Jobs) with heat scores and AI briefings.

Varnan-Tech/opendirectory

Give it your product URL or description. It finds your top 5 competitors, runs three-track PR research across all of them (editorial, podcasts, communities), identifies which channels appear most frequently, looks up the journalist or host for each, and returns a tiered outreach list with story angles and ready-to-send cold pitch drafts tailored to your product. Use when asked to find PR opportunities, discover where competitors got featured, build a media outreach list, find which journalists cover my space, or get pitch templates for press coverage.

Varnan-Tech/opendirectory

Generate high-converting, deep-dive growth case studies in MDX format. Use this skill when asked to write a case study or blog post about a company's growth, tech stack, or product-led strategy. It handles the full pipeline (researching the company via Tavily, generating a 16:9 cover image, quality checking the draft, uploading assets to cloud storage, and pushing directly to the target repository).

Varnan-Tech/opendirectory

Scans your project for outdated npm, pip, Cargo, Go, or Ruby packages. Runs a CVE security audit. Fetches changelogs, summarizes breaking changes with Gemini, and opens one PR per risk group (patch, minor, major). Includes Diagnosis Mode for install conflicts. Use when asked to update dependencies, check for outdated packages, open dependency PRs, scan for package updates, audit for CVEs, or flag breaking changes in upgrades. Trigger when a user says "check for outdated packages", "update my dependencies", "open PRs for dependency updates", "scan for CVEs", or "which packages need upgrading".

Varnan-Tech/opendirectory

Generates and updates README.md and API reference docs by reading your codebase's functions, routes, types, schemas, and architecture. Uses graphify to build a knowledge graph first, then writes accurate docs from it. Use when asked to write docs, generate a README, document an API, update stale docs, create an API reference from code, add an architecture section, or document a project in any language. Trigger when a user says their docs are missing, outdated, or wants to document their codebase without writing it manually.

Varnan-Tech/opendirectory

Evaluates expired domain candidates against a target niche, scores them by topical relevance, historical activity level, and history cleanliness, then outputs a ranked shortlist with explainable reasoning and risk flags.

Varnan-Tech/opendirectory

Brutally honest developer-experience audit for a GitHub repo. Scores 10 DX dimensions (time-to-first-success, README clarity, visual proof, install, quick-start, docs, examples, community, trust, marketing), writes a shareable roast in the requested tone (brutal/honest/kind), produces a prioritized action plan ranked by impact × effort, and sketches an ideal README. Trigger when user says "roast my repo", "audit my README", "dx audit", "developer experience review", "score my GitHub project", "before launch checklist", or "make my repo shareable".

Varnan-Tech/opendirectory

Drafts and designs a complete HTML email newsletter from a topic or content brief. Outputs paste-ready HTML for Loops, Mailchimp, Beehiiv, Resend, or any standard email platform. Includes subject line options and plain-text fallback. Trigger when a user says "write a newsletter", "draft an email newsletter", "create an HTML email", "design an email for my subscribers", or "write a newsletter about [topic]".

Varnan-Tech/opendirectory

Takes a GitHub PR URL or the current branch and writes a plain-English explanation of what it does and why, then posts it as a PR comment. Use when asked to explain a PR, summarize a pull request, write a plain-English description of a PR, add a summary comment to a PR, or understand what a PR changes. Trigger when a user says "explain this PR", "summarize this pull request", "what does this PR do", "add a comment explaining the PR", or shares a GitHub PR URL and asks what it does.

Varnan-Tech/opendirectory

Audit how often LLMs recommend your brand vs competitors and generate a GEO action plan.

Varnan-Tech/opendirectory

Takes a competitor's public GitHub repo URL, fetches their open issues via the GitHub REST API, filters noise locally, clusters issues into 6 demand categories, computes a demand score per issue and per cluster, and outputs a ranked demand gap report with a GTM messaging brief. Use when asked to scan a competitor's GitHub issues, find what their users are begging for, turn GitHub complaints into product positioning, identify competitor feature gaps, or generate messaging from real user demand. Trigger when a user says "scan competitor issues", "what are users asking for on X repo", "find demand gaps in Y", "turn GitHub issues into messaging", or "what should I build based on competitor complaints".

Varnan-Tech/opendirectory

Find recurring confusion in your repo's GitHub Discussions, rank it by urgency, and draft the actual docs fixes and content angles — with verbatim community quotes and source links as evidence.

Varnan-Tech/opendirectory

SEO keyword research workflow for blog generation using Google Trends data. Use when writing blog posts, planning content calendars, or optimizing articles for search engines. Finds breakout keywords, builds content structure, and generates SEO-optimized blog outlines targeting tech and developer audiences.

Varnan-Tech/opendirectory

Generates a professionally designed case study PDF for B2B SaaS sales and marketing. Supports 7 page layouts, 9 style presets, 1-4 page output. Trigger when user says "create a case study", "write a customer story", "make a case study PDF", "design a success story", "turn this customer win into a PDF".

Varnan-Tech/opendirectory

Generates data visualization charts (bar, line, area, pie, doughnut, scatter, radar, treemap) as PNG using Apache ECharts v6. 1080×1080px default, 5 style presets, highlight annotations. Trigger when user says "create a chart", "visualize data", "make a bar chart", "line graph", "pie chart", "data visualization", "chart this data", "plot", "graph", or "visualize these numbers".

Varnan-Tech/opendirectory

Fetches low-star App Store and Google Play reviews, clusters them into broken-promise patterns, and generates a ranked copy brief with positioning opportunities.

相關技能