ワンクリックで
docs-sync
Sync recently merged product PRs into the marketing website as a changelog — opens a PR on the website repo
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Sync recently merged product PRs into the marketing website as a changelog — opens a PR on the website repo
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Price performance report for the project's token — price, volume, liquidity, and context
Report on new stars, forks, and releases for watched repos — with profile enrichment (name, location, company, bio, follower count) for every new stargazer and forker, plus a one-line growth verdict
Crypto market scanner and single-token analyst - movers scans top winners/losers/trending or on-chain runners with pump-risk flags; single-token produces a verdict-first deep report for one token.
Account-based digest of recent tweets from tracked X/Twitter accounts. Sibling to fetch-tweets (keyword) and tweet-roundup (topic).
| type | Skill |
| name | Docs Sync |
| category | dev |
| description | Sync recently merged product PRs into the marketing website as a changelog — opens a PR on the website repo |
| var | |
| tags | ["dev","content","build"] |
| mode | write |
| commits | false |
| permissions | ["contents:write","pull-requests:write"] |
| requires | ["GH_GLOBAL"] |
${var} — Optional override in
product_repo->website_repoform (e.g.aaronjmars/aeon->aaronjmars/aeon-website). If empty, read config frommemory/docs-sync.md.
Today is ${today}. Your task: take the product's recently merged PRs and publish them as a changelog on the product's marketing website, via a branch + PR on the website repo. The website is the public face — this keeps "what shipped" visible without anyone hand-writing release notes.
This skill is config-driven so the same file works in every instance (aeon → aeon-website, miroshark → miroshark-website). It reads which repos to use from memory/docs-sync.md; it never hardcodes repo names.
Read memory/docs-sync.md. It defines:
product_repo — the repo whose merged PRs become the changelog (e.g. aaronjmars/aeon).website_repo — the Next.js marketing site to update (e.g. aaronjmars/aeon-website).min_prs (optional, default 1) — minimum number of new unpublished PRs required to publish an entry.lookback_days (optional, default 7) — only consider PRs merged within this many days. Bounds each entry to one window so a run never sweeps in months of history; matches the weekly schedule.draft (optional, default true) — open the website PR as a draft.If ${var} is set, it overrides product_repo->website_repo for this run.
If neither ${var} nor memory/docs-sync.md provides both repos, exit with DOCS_SYNC_NO_CONFIG (notify + log, no PR).
Compute the window cutoff first — lookback_days ago (default 7), as an ISO timestamp:
SINCE=$(date -u -d "${LOOKBACK_DAYS:-7} days ago" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v-"${LOOKBACK_DAYS:-7}"d +%Y-%m-%dT%H:%M:%SZ)
Then fetch the last 50 closed PRs and keep only those merged within the window, newest merge first:
gh api "repos/${PRODUCT_REPO}/pulls" -X GET -f state=closed -f sort=updated -f direction=desc -f per_page=50 \
--jq "[.[] | select(.merged_at != null) | select(.merged_at > \"$SINCE\") | {number, title, url: .html_url, author: .user.login, merged_at, labels: [.labels[].name], body: (.body // \"\" | .[0:500])}] | sort_by(.merged_at) | reverse"
The window is the primary filter; the published-PR dedup in step 2 is the idempotency guard against overlap and re-runs. Sandbox: if gh api fails transiently, retry once. Never use curl for the GitHub API — gh handles auth.
Clone the website repo and read the existing changelog data:
WORK_DIR="/tmp/docs-sync-work"
rm -rf "$WORK_DIR"
gh repo clone "$WEBSITE_REPO" "$WORK_DIR" -- --depth 20
cd "$WORK_DIR"
git config user.name "aeonframework"
git config user.email "aeonframework@proton.me"
Pin the commit identity in the clone. A freshly cloned repo does NOT inherit the workflow's git identity, so without these two lines the commit author falls back to an improvised/unlinked email (past runs produced aeon@aeon.fun, which links to no GitHub account). Always set it so every changelog commit + PR is attributed to the @aeonframework account (aeonframework@proton.me) — never anything else.
If app/changelog-data.ts exists, read it and collect PUBLISHED_PR_NUMBERS (every PR number already in CHANGELOG). If it doesn't exist yet, this is a bootstrap run (see step 4) and nothing is published.
Compute the new set: from step 1's windowed PRs, keep only those whose number is NOT in PUBLISHED_PR_NUMBERS. PR number is the idempotency key — not dates — so re-running within the same window is always safe and never duplicates.
DOCS_SYNC_NOTHING_NEW (silent: log only, no PR, no notify).0 < count < min_prs → exit DOCS_SYNC_BELOW_THRESHOLD (log only, no PR). Lets PRs accumulate into a meaningful entry.Split the new PRs:
dependabot[bot] and titles starting chore(deps, chore(deps-dev), chore(actions), ci:, build:, style:. These get rolled into a single "Maintenance: N dependency/CI bumps" highlight, not listed individually.prs array so idempotency stays exact — but only the substantive ones get their own highlight bullet.Compose ONE ChangelogEntry:
date: ${today} (YYYY-MM-DD).title: 4–8 words naming the dominant theme of the batch (e.g. "i18n expansion + simulation fixes"). Derive it from the substantive PR titles, not boilerplate. Never "various improvements".summary: 1–2 plain-language sentences — what a builder following the project would care about. No hype, no "we're excited".highlights: one bullet per substantive PR (plus the single maintenance rollup if any). Each bullet ≤ 18 words, names the concrete change, ends with the PR ref (#N). Translate commit-speak into plain English.prs: every new PR as { number, title, url, author }.Banned phrases: "exciting", "robust", "leverage", "unlocks", "seamless", "we're thrilled", "stay tuned". They signal stock release-note filler.
The data file app/changelog-data.ts is the only file you mutate on a normal run. Its shape:
export type ChangelogPR = { number: number; title: string; url: string; author: string };
export type ChangelogEntry = {
date: string; // YYYY-MM-DD
title: string; // 4–8 word theme
summary: string; // 1–2 sentences
highlights: string[];
prs: ChangelogPR[];
};
export const CHANGELOG: ChangelogEntry[] = [
// newest first — PREPEND new entries here, never rewrite existing ones
];
export const PUBLISHED_PR_NUMBERS = CHANGELOG.flatMap((e) => e.prs.map((p) => p.number));
Normal run: prepend the new entry to the top of the CHANGELOG array. Touch nothing else.
Bootstrap run (no app/changelog-data.ts yet) — create the changelog surface, matching the site's existing conventions (do NOT invent a new design system):
app/changelog-data.ts with the schema above + your first entry.app/changelog/page.tsx that renders CHANGELOG. Read an existing list page first (app/blog/page.tsx is the model on these sites) and reuse its shared chrome: same SiteNav/SiteFooter, the same CSS module it imports (e.g. ../docs/page.module.css as chrome), the same hero/section structure. Wire full Next.js metadata (title, description, canonical, OpenGraph) like the other pages. Give it a JSON-LD block if the blog page has one.app/docs/page.tsx: import CHANGELOG from ../changelog-data and render the latest 3 entries inline, with a "Full changelog →" link to /changelog. Place it near the top of the docs body, after the intro. Keep edits to that file minimal and self-contained.changelog link to the primary nav in app/site-chrome.tsx (or wherever the site renders its nav — check the layout if there's no site-chrome).Match indentation, quote style, and naming of each repo exactly. After editing, if the site has a typecheck/lint/build available and the sandbox allows it, run it (npm run lint / npx tsc --noEmit / npm run build) and fix any error your change introduced. If the sandbox blocks npm, skip silently — note it in the PR body.
BRANCH="aeon/changelog-${today}"
git checkout -b "$BRANCH"
git add -A
git commit -m "docs(changelog): sync N merged PRs from ${PRODUCT_REPO}"
git push -u origin "$BRANCH"
Open the PR on the website repo (draft unless config says otherwise):
gh pr create --repo "$WEBSITE_REPO" --draft \
--title "docs(changelog): ${today} — <entry title>" \
--body "$(cat <<'EOF'
## Summary
Auto-generated changelog sync from merged PRs in `${PRODUCT_REPO}`.
## Entry
**<title>** — <summary>
## PRs included
- #N — title (@author)
- ...
---
Generated by the aeon `docs-sync` skill. Review and merge to publish.
EOF
)"
Use --draft when draft config is true (the default). Build the PR body from the real entry — never leave placeholders.
*Docs Sync — ${today}*
${PRODUCT_REPO} → ${WEBSITE_REPO}
N new PRs → changelog entry "<title>"
Append to memory/logs/${today}.md:
### docs-sync
- Status: DOCS_SYNC_OK | DOCS_SYNC_BOOTSTRAP | DOCS_SYNC_NOTHING_NEW | DOCS_SYNC_BELOW_THRESHOLD | DOCS_SYNC_NO_CONFIG
- Product: ${PRODUCT_REPO} → Website: ${WEBSITE_REPO}
- New PRs: N (numbers: ...)
- Entry: "<title>"
- PR: <url>
GitHub Actions runs Claude Code in a non-interactive sandbox.
gh api / gh pr create / gh repo clone — never curl (auth + sandbox). gh works because it handles auth internally.&&, ||, |, ;) and $(...)/$VAR expansion in skill bash blocks. Split into separate calls; the working directory persists, so cd "$WORK_DIR" as its own call then run commands. Compute literal values (repo names, branch) in your reasoning, not via shell substitution.npm run build/lint fails to reach the network or is denied, skip it and note "build not verified in sandbox" in the PR body rather than aborting.GH_GLOBAL (a token with cross-repo write to the website repo). GITHUB_TOKEN alone only covers the current repo and cannot push to the website.PUBLISHED_PR_NUMBERS. Re-running must be a no-op when nothing new merged.(#N). No invented activity.