Communityライティング&編集github.com

Varnan-Tech/opendirectory

スキルに出荷したプロダクトを伝えると、`docs/changelog.md`に日付入りの洗練されたエントリを追加し、ツイートスレッド、LinkedIn投稿、メールスニペット、一言キャッチコピーを含むコンテンツパッケージを生成します。

opendirectory とは?

このスキル(product-update-logger)は、開発者がプロダクトのアップデートを簡単に文書化し、複数のチャネル向けコンテンツを一度に作成できるようにします。ユーザーが自由記述テキストで機能を入力するか、ローカルGitリポジトリからコミットを自動取得するか、またはGitHubのPR番号を指定することで、変更内容を収集します。収集した情報はノイズフィルターを通して整理され、`docs/changelog.md`に日付付きの変更ログエントリとして追記されます(最新のエントリが先頭に追加)。さらに、同じデータからツイートスレッド(1ツイート280文字以内)、LinkedIn投稿(マークダウンやハッシュタグ禁止)、メールスニペット(件名と本文)、そして最大20語の一言キャッチコピーを自動生成します。このスキルはClaude CodeやCursorなどのAIエージェント環境で動作し、事前に定義された参照ファイル(フォーマットルールやコンテンツルール)に従って出力を整形します。特に、成果や指標を作り込まず、ソースデータに基づいた正確な内容のみを出力し、禁止語句や絵文字ダッシュのチェックを自ら行う品質保証ステップを内蔵しています。

対応~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に質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

product-update-logger

このスキルに出荷したプロダクトを伝えてください。docs/changelog.md(最新のエントリが先頭に追加される生きたログ)に洗練された変更ログエントリを書き込み、同時にコンテンツパッケージ(ツイートスレッド、LinkedIn投稿、メールスニペット、一言キャッチコピー)を生成します。

入力ソース:メッセージ内の自由記述テキスト、ローカルリポジトリから自動取得したGitコミット、指定されたリポジトリのGitHub PR。任意の組み合わせが可能です。

参照ファイル

毎回の実行前に以下のファイルを読み込んでください:

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

ステップ1:セットアップ確認

echo "GITHUB_TOKEN: ${GITHUB_TOKEN:-not set -- GitHub PR fetching disabled}"
echo "Git:          $(git rev-parse --is-inside-work-tree 2>/dev/null && echo 'repo detected' || echo 'not a git repo')"
echo "Changelog:    $(ls docs/changelog.md 2>/dev/null && echo 'exists' || echo 'will be created')"

Gitが利用可能かどうか、既に変更ログが存在するかどうかを確認してください。これによりバージョンラベルのフォーマットが決まります。


ステップ2:入力の解析

会話から以下を収集します:

  • items -- 出荷した内容の自由記述テキスト(複数ある場合はパイプ区切り)。Gitが利用可能な場合は省略可能。
  • since -- 何日前まで遡るか。デフォルト:7。ユーザーが「先週」や「前回のリリース以降」と言った場合に設定。
  • repo -- PR取得用のGitHub "owner/repo"。省略可能。
  • version_label -- "v2.1.0" や "The Speed Update" などのカスタムラベル。省略可能。デフォルトは日付ベース。

ユーザーがitemsについて何も言わず、かつgitリポジトリがない場合: 「何を出荷しましたか?機能、修正、改善点を1行に1つずつリストしてください。」と尋ねてください。

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"対象日数: {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 "script found" || echo "ERROR: scripts/gather.py not found"
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に数値がなければ、追加しないでください。
  • 過去形を使用: 「追加」「修正」「改善」 -- 「追加します」「修正します」ではない
  • 各アイテムにカテゴリを1つ割り当て: New(新機能)、Improved(改善)、Fixed(修正)、Under the hood(内部変更)
  • Under the hood: 開発者に関連する場合のみ含めてください(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の変更ログエントリを使用して、4つのコンテンツすべてを生成します。references/content-rules.md に厳密に従ってください。

一言キャッチコピー(最大20語):最大の1~2アイテムをカバーする一文。平易な言葉で、専門用語なし。

ツイートスレッド(3~5ツイート):

  • ツイート1:フック -- 「今週[N]個のものを出荷しました。」または最大の機能でリード
  • ツイート2~N:ツイートごとに1アイテム、最大1~2文
  • 最後のツイート:「変更ログ:[リンク]」または「また来週。」(任意)
  • 各ツイートは厳密に280文字未満
  • ハッシュタグなし。ダッシュなし。能動態。

LinkedIn投稿:

  • マークダウンなし(アスタリスクはLinkedIn上でそのまま表示されるため)
  • ハッシュタグなし
  • 創業者の声:「We are excited to announce」ではなく「We shipped」
  • 短い段落(各1~2文)、段落間は空行
  • CTAではなく、質問や観察で締めくくる
  • 合計150~400語

メールスニペット:

  • 件名:「今週の出荷:[最大のアイテム] + [あと1つ]」
  • 本文:50~100語。「今週出荷したものはこちらです:」の後に箇条書き。

/tmp/pul-content.json に書き込みます:

{
  "one_liner": "ダークモード、API高速化、エクスポートバグ修正。",
  "tweet_thread": [
    "今週3つのものを出荷しました。",
    "ダークモードが利用可能に。設定 > 表示で切り替えられます。全画面で動作します。",
    "API応答時間が平均40%高速化。ダッシュボードが1秒未満で読み込まれます。",
    "修正:CSVエクスポートで最終行が欠落していました。現在は修正済みです。",
    "変更ログ:[リンク]"
  ],
  "linkedin_post": "今週3つのアップデートを出荷しました。\n\nダークモードが利用可能になりました。設定の表示から切り替えられます。すべてのビューで動作します。\n\nAPI応答時間が平均40%高速化しました。ほとんどのユーザーでダッシュボードが1秒未満で読み込まれるようになりました。\n\nまた、CSVエクスポートが最終行を静かに欠落させるバグを修正しました。これに遭遇してエクスポートを中止していた方は、再試行する価値があります。\n\nどのような機能を待っていましたか?",
  "email_snippet": {
    "subject": "今週の出荷:ダークモード + API高速化",
    "body": "今週出荷したものはこちらです:\n\n- ダークモード:設定 > 表示で切り替え\n- API応答時間:平均40%高速化、ダッシュボードが1秒未満で読み込み\n- 修正:CSVエクスポートで最終行が欠落しなくなりました\n\n以下に完全な変更ログがあります。"
  }
}

ステップ6:自己QA

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('FAIL: ダッシュが見つかりました -- ハイフンに置き換えてください')
    fails += 1
else:
    print('PASS: ダッシュなし')

# チェック2:禁止語句
banned = ['powerful', 'robust', 'seamless', 'innovative', 'game-changing',
          'streamline', 'leverage', 'transform', 'revolutionize', 'excited to announce',
          'pleased to announce', 'we are thrilled', 'cutting-edge', 'best-in-class',
          'world-class', 'unlock', 'delightful']
found = [w for w in banned if w.lower() in full_text.lower()]
if found:
    print(f'FAIL: 禁止語句が見つかりました: {found}')
    fails += 1
else:
    print('PASS: 禁止語句なし')

# チェック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'FAIL: 280文字を超えるツイート: {long_tweets}')
    fails += 1
else:
    print(f'PASS: 全{len(thread)}ツイートが280文字未満')

# チェック4:LinkedInにハッシュタグなし
li = content.get('linkedin_post', '')
if re.search(r'#[A-Za-z]', li):
    print('FAIL: LinkedIn投稿にハッシュタグがあります')
    fails += 1
else:
    print('PASS: LinkedInにハッシュタグなし')

# チェック5:LinkedInにマークダウンなし
if '**' in li or '__' in li:
    print('FAIL: LinkedInにマークダウン書式があります(アスタリスクがそのまま表示されます)')
    fails += 1
else:
    print('PASS: LinkedInにマークダウンなし')

# チェック6:一言キャッチコピーの語数
one_liner = content.get('one_liner', '')
word_count = len(one_liner.split())
if word_count > 20:
    print(f'FAIL: 一言キャッチコピーが{word_count}語(最大20語)')
    fails += 1
else:
    print(f'PASS: 一言キャッチコピーは{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'INFO: {raw_total}個の生アイテムから{entry_items}個の変更ログアイテム')

print()
print(f'結果: {"PASS" if fails == 0 else f"FAIL ({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": "### New",
    "improved": "### Improved",
    "fixed": "### Fixed",
    "under_the_hood": "### 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 = "# Changelog\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', ''),
    "",
    "## メールスニペット",
    "",
    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. 変更ログエントリ(整形済みマークダウン、生JSONではない):

## 2026年4月23日の週

### New
- **ダークモード** -- 設定 > 表示で切り替え。全ビューで動作します。

### Improved
- **API応答時間** -- 平均40%高速化。ダッシュボードが1秒未満で読み込まれます。

...

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.

関連スキル