Announcing Framework Releases
After a governance framework cuts a formal version release (a new version tag, pushed and verified), post a
version-update card to the team chat: which framework, old→new version, a change-class summary pulled from its
CHANGELOG, a one-line consumer-impact verdict, the repo / CHANGELOG links + maintainer, and — when the instance
opts in — an optional 🏆 cumulative contribution leaderboard. This is a governance-meta skill — it operates on
the framework ecosystem, alongside syncing-frameworks / announcing-skills / publishing-skills.
Boundary vs announcing-skills: announcing-skills celebrates skill-hub 上新 (新 skill); this skill
announces a framework version update (framework / version / change-class / consumer-impact). Different trigger,
data, and core payload. Both carry the same optional 🏆 leaderboard — a per-user ruling (2026-06-11): a
contribution shows up wherever it is announced, so the leaderboard rides both cards, computed from the one hub
ledger (contributors.yaml) and gated by the instance toggle. PR-sourced contributions count only once their PR is
merged (user ruling 2026-06-11); unmerged PRs are excluded from the ledger and the leaderboard. (This reverses the skill's original "no leaderboard"
design; see the CHANGELOG.) The leaderboard block is identical in shape to announcing-skills' — see
references/card-format.md.
Triggers
- Prompt / keyword, run post-release (after the framework's release tag is cut and push-verified):
"公告框架版本更新" / "announce framework release" / "发框架升级公告" / "框架版本公告".
- Inputs from the caller: which framework released + its old→new version. Not automatic — it is a step run in
the version-gate flow after a verified release.
Model (read first)
- Render, don't author. The change summary is extracted from the released framework's CHANGELOG top entry
(
## [X.Y.Z] … its ### Added/Changed/Fixed/BREAKING sections) — the CHANGELOG is the single source of the
change text. This skill classifies + links; it never rewrites the change prose.
- Framework-agnostic (decoupling — skill_spec §9). No framework name is hardcoded. Which framework released
comes from the caller's input; its repo / CHANGELOG URL is resolved at runtime from the pinned submodule's
remote (
git -C <submodule> remote get-url origin) — the same pattern syncing-frameworks uses. (Note the
divergence from announcing-skills, which reads an instance repo_url for the single hub; a framework announce
targets many frameworks, so URL resolution is runtime, not instance.)
- Two homes for identity. The group chat id and the maintainer→open_id map are org-instance facts
(
project_profile.yaml -> framework_announce, with the group reused from skill_hub.announce.group_chat_id —
single source, same group). Nothing identity-bearing is hardcoded in this skill.
- Leaderboard reuses the hub's single ledger + maps (no second ledger). The optional leaderboard is computed from
the same hub
contributors.yaml as announcing-skills, and resolves @-mentions via the same instance maps
skill_hub.announce.contributor_open_id + pr_account_map — not redeclared under framework_announce (single
source, the same way framework_announce reuses group_chat_id). A per-user ruling (2026-06-11): the leaderboard is
"contributions made visible", not a taxonomy — so both cards read one ledger and may show the same ranking. Gated by
framework_announce.include_leaderboard.
- Card surface, not post. The change-class summary is a real table, so the message is a Lark interactive card
(
--msg-type interactive). The send mechanism (lark-cli, send_as, idempotency) is shared with announcing-skills
/ publishing-deliverables; only the payload differs — see references/card-format.md (this skill's own card
reference; the change-class table is this card's distinctive part, plus the same optional leaderboard block as
announcing-skills).
Inputs (all instance-read / runtime-resolved; zero hardcode)
- From the caller: the released framework (its code, e.g. the submodule id) + old→new version.
- From
project_profile.yaml -> framework_announce: send_as (user|bot) · maintainer_open_id (framework code →
open_id) · include_leaderboard (bool — render the 🏆 leaderboard section or skip it). Group chat id: read at
runtime from skill_hub.announce.group_chat_id (same group, single source — not redeclared in framework_announce).
- For the leaderboard (only if
include_leaderboard): the hub contributors.yaml ledger (same one
announcing-skills reads) + the instance skill_hub.announce.contributor_open_id and pr_account_map maps (reused,
not redeclared under framework_announce — single source).
- Resolved at runtime: the framework's repo URL and CHANGELOG URL via
git -C <submodule> remote get-url origin (build the CHANGELOG link from the remote + the repo's CHANGELOG path).
- From the framework: its CHANGELOG.md top
[X.Y.Z] entry (the released version's change text).
Procedure
- Read the released framework's CHANGELOG top entry (
## [<NEW_VER>]): collect its ### Added / ### Changed /
### Fixed / ### BREAKING (or ⚠️ BREAKING) sections. This is the authoritative change text — extract, don't rewrite.
- Classify the changes into the change-class table rows (one row per present class; ⚠️ BREAKING row first if present).
- Derive the consumer-impact verdict (deterministic rule — see below).
- Resolve repo + CHANGELOG URLs at runtime from the submodule remote.
- Resolve the maintainer:
maintainer_open_id[<framework-code>] → ou_xxx for the card <at>. Missing
(e.g. an external maintainer not in the group) → render the maintainer as plain text, skip the @ (do not fail).
- Compute the leaderboard (only if
include_leaderboard is true and the contributor_open_id map is
non-empty — either condition unmet → skip this step and the leaderboard block in step 7; no error). Read (do
not write) the hub contributors.yaml: per contributor, count = len(contributions); sort by count desc;
assign 🥇🥈🥉 to the top three (then 4., 5., …); collect each person's item list. Resolve each label's <at>
via the reused skill_hub.announce.contributor_open_id (and pr_account_map for PR-sourced rows). This is the
same ledger and same maps announcing-skills uses — a single source, so the two cards' leaderboards may match.
(Adding framework-contribution entries to the ledger is a separate ledger-maintenance step, not done by this skill.)
- Build the card per
references/card-format.md (fill {FRAMEWORK}/{CODE}/{OLD_VER}/{NEW_VER}/{REPO_URL}/
{CHANGELOG_URL}/{IMPACT}/{CHANGE_ROWS}/{MAINTAINER_AT}/{DATE}; if the leaderboard is on, also fill
{RANKING} and include the hr + ranking-heading + Table ② block; else omit that block; honor the field-tested
hard constraints).
- Confirm, then send (outward-facing — sending to a group publishes).
lark-cli im +messages-send --as <send_as> --chat-id <group_chat_id> --msg-type interactive --content '<card-json>' --idempotency-key <framework>-<NEW_VER>.
--content does not accept @file — inline the JSON.
- Record. Write the announcement (framework + old→new version + group) into the consuming project's
flow_log.md.
Consumer-impact verdict (deterministic rule — checkable, not free prose)
Do not key "breaking" solely on a textual ⚠️ BREAKING marker — external frameworks' CHANGELOGs may not use it
(e.g. one that only has ### Added/Changed). Use a framework-agnostic fallback signal: a semver major bump.
IF CHANGELOG top entry contains "⚠️ BREAKING" / "### BREAKING" OR major-version bump (X increases, e.g. 1.x → 2.0)
→ IMPACT = "⚠️ 破坏性更新:sync 前请评估对本项目的影响,可能需要适配。"
ELIF only recognized non-breaking sections (Added / Changed / Fixed) AND not a major bump
→ IMPACT = "✅ 向后兼容:可在下一个版本门照常 sync 升级。"
ELSE (no recognized sections / unparseable)
→ IMPACT = "ℹ️ 变更类型待确认:请查阅 CHANGELOG 评估影响。" # do not guess
- Semver-major is the universal signal; the textual marker is a supplement, not the sole trigger.
Rules
- Decoupling red line (skill_spec §9): zero hardcoded framework name / repo / identity. Group + maintainer map are
instance-owned (
framework_announce, group reused from skill_hub.announce); the leaderboard ledger + contributor
maps are reused from the hub / skill_hub.announce (single source, not redeclared); repo/CHANGELOG URL resolved at
runtime from the submodule remote. The CHANGELOG is the single source of change text.
- Leaderboard is instance-gated, single-ledger — render the 🏆 section only when
include_leaderboard is true
and the contributor_open_id map is non-empty; either unmet → omit silently (no error). It reads the one hub
ledger (contributors.yaml) — it never writes a second one. The same block appears on announcing-skills' card.
- Card, not post — the change-class table needs the interactive surface;
<at> syntax is card-specific
(references/card-format.md), distinct from a post's {"tag":"at"}.
- Announce-after-push — run only after the release tag is cut and push-verified; never pre-announce.
- Outward-facing — sending to a group publishes; confirm with the user before sending.
Never touched
- The framework's repo / tags / CHANGELOG — read-only; this skill announces a release, it does not cut one.
- The
maintainer_open_id / contributor_open_id / pr_account_map / group_chat_id — instance values, read not written.
- The hub
contributors.yaml ledger — read-only here (this skill ranks from it; adding framework-contribution
entries is a separate ledger-maintenance step, not this skill's job).
References
references/card-format.md — this skill's own Lark interactive-card reference (the version-update card: a
change-class table + impact line + maintainer, plus the same optional 🏆 leaderboard block as announcing-skills,
instance-gated).
1---2name: announcing-framework-releases3description: Announce a governance framework's formal version release to the team chat as a Feishu (Lark) interactive card — framework name + code, old→new version, change-class summary (Added / Changed / ⚠️ BREAKING) extracted from its CHANGELOG, a one-line consumer-impact verdict (sync now? breaking?), repo + CHANGELOG links, maintainer, plus an optional 🏆 cumulative contribution leaderboard (instance-gated by include_leaderboard, computed from the same hub ledger as announcing-skills). Use after a framework release is tagged and push-verified. Identity-decoupled — group and the maintainer/contributor open_id maps are instance values; repo URL is resolved at runtime from the submodule remote.4---56# Announcing Framework Releases78After a governance framework cuts a **formal version release** (a new version tag, pushed and verified), post a9**version-update card** to the team chat: which framework, old→new version, a change-class summary pulled from its10CHANGELOG, a one-line **consumer-impact verdict**, the repo / CHANGELOG links + maintainer, and — when the instance11opts in — an **optional 🏆 cumulative contribution leaderboard**. This is a **governance-meta** skill — it operates on12the framework ecosystem, alongside `syncing-frameworks` / `announcing-skills` / `publishing-skills`.1314**Boundary vs `announcing-skills`**: `announcing-skills` celebrates **skill-hub 上新** (新 skill); **this** skill15announces a **framework version update** (framework / version / change-class / consumer-impact). Different trigger,16data, and core payload. **Both** carry the **same optional 🏆 leaderboard** — a per-user ruling (2026-06-11): a17contribution shows up wherever it is announced, so the leaderboard rides **both** cards, computed from the **one** hub18ledger (`contributors.yaml`) and gated by the instance toggle. **PR-sourced contributions count only once their PR is19merged** (user ruling 2026-06-11); unmerged PRs are excluded from the ledger and the leaderboard. (This reverses the skill's original "no leaderboard"20design; see the CHANGELOG.) The leaderboard block is **identical in shape** to `announcing-skills`' — see21`references/card-format.md`.2223## Triggers24- **Prompt / keyword**, run **post-release** (after the framework's release tag is cut **and push-verified**):25 "公告框架版本更新" / "announce framework release" / "发框架升级公告" / "框架版本公告".26- Inputs from the caller: **which framework** released + its **old→new version**. Not automatic — it is a step run in27 the version-gate flow after a verified release.2829## Model (read first)30- **Render, don't author.** The change summary is **extracted** from the released framework's CHANGELOG top entry31 (`## [X.Y.Z]` … its `### Added/Changed/Fixed/BREAKING` sections) — the CHANGELOG is the **single source** of the32 change text. This skill classifies + links; it never rewrites the change prose.33- **Framework-agnostic (decoupling — skill_spec §9).** No framework name is hardcoded. *Which* framework released34 comes from the caller's input; its repo / CHANGELOG URL is **resolved at runtime** from the pinned submodule's35 remote (`git -C <submodule> remote get-url origin`) — the same pattern `syncing-frameworks` uses. (Note the36 divergence from `announcing-skills`, which reads an instance `repo_url` for the single hub; a framework announce37 targets many frameworks, so URL resolution is runtime, not instance.)38- **Two homes for identity.** The **group chat id** and the **maintainer→open_id map** are **org-instance facts**39 (`project_profile.yaml -> framework_announce`, with the group reused from `skill_hub.announce.group_chat_id` —40 single source, same group). Nothing identity-bearing is hardcoded in this skill.41- **Leaderboard reuses the hub's single ledger + maps (no second ledger).** The optional leaderboard is computed from42 the **same** hub `contributors.yaml` as `announcing-skills`, and resolves @-mentions via the **same** instance maps43 `skill_hub.announce.contributor_open_id` + `pr_account_map` — **not** redeclared under `framework_announce` (single44 source, the same way `framework_announce` reuses `group_chat_id`). A per-user ruling (2026-06-11): the leaderboard is45 "contributions made visible", not a taxonomy — so both cards read one ledger and may show the same ranking. Gated by46 `framework_announce.include_leaderboard`.47- **Card surface, not post.** The change-class summary is a real table, so the message is a Lark **interactive card**48 (`--msg-type interactive`). The send mechanism (lark-cli, `send_as`, idempotency) is shared with `announcing-skills`49 / `publishing-deliverables`; only the payload differs — see `references/card-format.md` (this skill's **own** card50 reference; the change-class table is this card's distinctive part, plus the **same optional leaderboard block** as51 `announcing-skills`).5253## Inputs (all instance-read / runtime-resolved; zero hardcode)54- From the caller: the **released framework** (its code, e.g. the submodule id) + **old→new version**.55- From `project_profile.yaml -> framework_announce`: `send_as` (user|bot) · `maintainer_open_id` (framework code →56 open_id) · `include_leaderboard` (bool — render the 🏆 leaderboard section or skip it). **Group chat id**: read at57 runtime from `skill_hub.announce.group_chat_id` (same group, single source — not redeclared in `framework_announce`).58- **For the leaderboard** (only if `include_leaderboard`): the hub `contributors.yaml` ledger (same one59 `announcing-skills` reads) + the instance `skill_hub.announce.contributor_open_id` and `pr_account_map` maps (reused,60 **not** redeclared under `framework_announce` — single source).61- Resolved at runtime: the framework's **repo URL** and **CHANGELOG URL** via `git -C <submodule> remote get-url62 origin` (build the CHANGELOG link from the remote + the repo's CHANGELOG path).63- From the framework: its **CHANGELOG.md** top `[X.Y.Z]` entry (the released version's change text).6465## Procedure661. **Read the released framework's CHANGELOG top entry** (`## [<NEW_VER>]`): collect its `### Added` / `### Changed` /67 `### Fixed` / `### BREAKING` (or `⚠️ BREAKING`) sections. This is the authoritative change text — extract, don't rewrite.682. **Classify the changes** into the change-class table rows (one row per present class; ⚠️ BREAKING row first if present).693. **Derive the consumer-impact verdict** (deterministic rule — see below).704. **Resolve repo + CHANGELOG URLs** at runtime from the submodule remote.715. **Resolve the maintainer**: `maintainer_open_id[<framework-code>]` → `ou_xxx` for the card `<at>`. **Missing**72 (e.g. an external maintainer not in the group) → render the maintainer as **plain text**, skip the `@` (do not fail).736. **Compute the leaderboard** *(only if `include_leaderboard` is true **and** the `contributor_open_id` map is74 non-empty — either condition unmet → skip this step and the leaderboard block in step 7; no error)*. **Read** (do75 **not** write) the hub `contributors.yaml`: per contributor, `count = len(contributions)`; sort by count desc;76 assign 🥇🥈🥉 to the top three (then `4.`, `5.`, …); collect each person's item list. Resolve each label's `<at>`77 via the reused `skill_hub.announce.contributor_open_id` (and `pr_account_map` for PR-sourced rows). This is the78 **same ledger and same maps** `announcing-skills` uses — a single source, so the two cards' leaderboards may match.79 *(Adding framework-contribution entries to the ledger is a separate ledger-maintenance step, not done by this skill.)*807. **Build the card** per `references/card-format.md` (fill `{FRAMEWORK}`/`{CODE}`/`{OLD_VER}`/`{NEW_VER}`/`{REPO_URL}`/81 `{CHANGELOG_URL}`/`{IMPACT}`/`{CHANGE_ROWS}`/`{MAINTAINER_AT}`/`{DATE}`; **if the leaderboard is on**, also fill82 `{RANKING}` and include the `hr` + ranking-heading + Table ② block; **else omit that block**; honor the field-tested83 hard constraints).848. **Confirm, then send** (outward-facing — sending to a group publishes). `lark-cli im +messages-send --as <send_as>85 --chat-id <group_chat_id> --msg-type interactive --content '<card-json>' --idempotency-key <framework>-<NEW_VER>`.86 `--content` does not accept `@file` — inline the JSON.879. **Record.** Write the announcement (framework + old→new version + group) into the consuming project's `flow_log.md`.8889## Consumer-impact verdict (deterministic rule — checkable, not free prose)90> Do **not** key "breaking" solely on a textual `⚠️ BREAKING` marker — **external frameworks' CHANGELOGs may not use it**91> (e.g. one that only has `### Added/Changed`). Use a **framework-agnostic** fallback signal: a **semver major bump**.92```93IF CHANGELOG top entry contains "⚠️ BREAKING" / "### BREAKING" OR major-version bump (X increases, e.g. 1.x → 2.0)94 → IMPACT = "⚠️ 破坏性更新:sync 前请评估对本项目的影响,可能需要适配。"95ELIF only recognized non-breaking sections (Added / Changed / Fixed) AND not a major bump96 → IMPACT = "✅ 向后兼容:可在下一个版本门照常 sync 升级。"97ELSE (no recognized sections / unparseable)98 → IMPACT = "ℹ️ 变更类型待确认:请查阅 CHANGELOG 评估影响。" # do not guess99```100- Semver-major is the universal signal; the textual marker is a **supplement**, not the sole trigger.101102## Rules103- **Decoupling red line (skill_spec §9)**: zero hardcoded framework name / repo / identity. Group + maintainer map are104 instance-owned (`framework_announce`, group reused from `skill_hub.announce`); the leaderboard ledger + contributor105 maps are reused from the hub / `skill_hub.announce` (single source, not redeclared); repo/CHANGELOG URL resolved at106 runtime from the submodule remote. The CHANGELOG is the single source of change text.107- **Leaderboard is instance-gated, single-ledger** — render the 🏆 section only when `include_leaderboard` is true108 **and** the `contributor_open_id` map is non-empty; either unmet → omit silently (no error). It reads the **one** hub109 ledger (`contributors.yaml`) — it never writes a second one. The same block appears on `announcing-skills`' card.110- **Card, not post** — the change-class table needs the interactive surface; `<at>` syntax is card-specific111 (`references/card-format.md`), distinct from a post's `{"tag":"at"}`.112- **Announce-after-push** — run **only after the release tag is cut and push-verified**; never pre-announce.113- **Outward-facing** — sending to a group publishes; **confirm with the user before sending**.114115## Never touched116- The framework's repo / tags / CHANGELOG — read-only; this skill announces a release, it does not cut one.117- The `maintainer_open_id` / `contributor_open_id` / `pr_account_map` / `group_chat_id` — instance values, read not written.118- The hub `contributors.yaml` ledger — **read-only** here (this skill ranks from it; adding framework-contribution119 entries is a separate ledger-maintenance step, not this skill's job).120121## References122- `references/card-format.md` — this skill's **own** Lark interactive-card reference (the version-update card: a123 change-class table + impact line + maintainer, plus the **same optional 🏆 leaderboard block** as `announcing-skills`,124 instance-gated).