
Ce Release Notes
Pull compound-engineering-plugin GitHub releases into a stable JSON contract for changelogs, agent updates, or release comms.
Overview
Ce-release-notes is an agent skill most often used in Ship (also Build, Grow) that fetches compound-engineering-plugin GitHub releases as structured JSON for changelogs and upgrade decisions.
Install
npx skills add https://github.com/everyinc/compound-engineering-plugin --skill ce-release-notesWhat is this skill?
- Runs list-plugin-releases.py and always exits 0 with success or structured error JSON
- Uses authenticated gh when available with anonymous GitHub API fallback
- Extracts linked PR numbers from release bodies via regex
- Encodes rate_limit and network_outage failures with user_hint fields
- Supports --limit, --api-base, and CE_RELEASE_NOTES_GH_BIN for testing
- Script contract distinguishes success ok true with source gh or anon versus ok false with error codes rate_limit and net
Adoption & trust: 1.5k installs on skills.sh; 20.5k GitHub stars; 2/3 security scanners passed (skills.sh audits).
What problem does it solve?
You need trustworthy, machine-readable release history for the compound-engineering plugin without hand-scraping GitHub pages or brittle HTML parsing.
Who is it for?
Solo builders tracking EveryInc plugin drops who want gh-first fetch with anon fallback inside an agent workflow.
Skip if: Arbitrary repositories or release processes that do not match EveryInc/compound-engineering-plugin and the compound-engineering-v tag prefix.
When should I use this skill?
You need release history, changelog text, or linked PRs for EveryInc/compound-engineering-plugin.
What do I get? / Deliverables
You receive a versioned release list with bodies and linked PR ids, or a typed error object you can surface in agent or CI output.
- JSON release catalog with tags and bodies
- Linked PR id list per release
- Structured error payload on failure
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
Release notes land on the Ship phase shelf because the skill’s purpose is published version history, not day-to-day coding. Launch subphase matches distribution-facing release metadata—tags, bodies, and linked PRs—for what shipped in each plugin version.
Where it fits
Summarize the latest compound-engineering-v tag before publishing an internal upgrade note.
Pin or bump the plugin version in your agent config based on fetched release bodies.
Draft a short what's-new post from linked_prs in the latest release JSON.
How it compares
Use instead of opening GitHub Releases in a browser; this is a fixed-contract integration skill, not a general release-notes generator for any repo.
Common Questions / FAQ
Who is ce-release-notes for?
Developers using the compound-engineering plugin who want agents or scripts to read GitHub release metadata in one JSON shape.
When should I use ce-release-notes?
Use it in Ship before upgrading the plugin; in Build when pinning agent tooling versions; and in Grow when communicating what shipped to users or teammates.
Is ce-release-notes safe to install?
It calls GitHub via gh or HTTPS read-only APIs; review the Security Audits panel on this page and avoid embedding tokens in prompts when gh already handles auth locally.
SKILL.md
READMESKILL.md - Ce Release Notes
#!/usr/bin/env python3 """ list-plugin-releases.py — Fetch compound-engineering plugin releases from GitHub. Output: a single JSON object on stdout. Always exits 0; failures are encoded in the contract, never raised. Usage: python3 list-plugin-releases.py [--limit N] [--api-base URL] Environment: CE_RELEASE_NOTES_GH_BIN Override the gh binary path (default: "gh"). Used by the test harness; leave unset in production. Contract: Success: {"ok": true, "source": "gh"|"anon", "fetched_at": "ISO8601", "releases": [{tag, version, name, published_at, url, body, linked_prs}]} Failure: {"ok": false, "error": {"code": "rate_limit"|"network_outage", "message": "...", "user_hint": "..."}} """ import argparse import json import os import re import subprocess import sys import time import urllib.error import urllib.request from datetime import datetime, timezone OWNER = "EveryInc" REPO = "compound-engineering-plugin" TAG_PREFIX = "compound-engineering-v" DEFAULT_API_BASE = "https://api.github.com" GH_TIMEOUT_SECS = 10 ANON_TIMEOUT_SECS = 10 RELEASES_URL = "https://github.com/" + OWNER + "/" + REPO + "/releases" PR_REGEX = re.compile(r"\[#(\d+)\]") def _now_iso(): return datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") def _extract_linked_prs(body): if not body: return [] seen = set() out = [] for m in PR_REGEX.finditer(body): n = int(m.group(1)) if n not in seen: seen.add(n) out.append(n) return out def _version_from_tag(tag): if tag.startswith(TAG_PREFIX): return tag[len(TAG_PREFIX):] return tag def _normalize_release(raw): """Coerce a raw release dict (gh shape OR API shape) into the contract shape.""" tag = raw.get("tagName") or raw.get("tag_name") or "" if not tag: return None body = raw.get("body") or "" return { "tag": tag, "version": _version_from_tag(tag), "name": raw.get("name") or "", "published_at": raw.get("publishedAt") or raw.get("published_at") or "", "url": raw.get("html_url") or raw.get("url") or "", "body": body, "linked_prs": _extract_linked_prs(body), } def _filter_and_sort(raw_list): out = [] for raw in raw_list: if not isinstance(raw, dict): continue norm = _normalize_release(raw) if norm is None: continue if not norm["tag"].startswith(TAG_PREFIX): continue out.append(norm) out.sort(key=lambda r: r["published_at"], reverse=True) return out def attempt_gh(limit): """ Try to fetch via gh. Returns (success, releases). success=True → caller emits the result with source="gh" success=False → caller falls back to attempt_anon Falls back when: gh missing, gh exits non-zero, gh times out, gh stdout is not parseable JSON, or gh returns zero plugin tags (covers the GitHub Enterprise silent-empty case). """ gh_bin = os.environ.get("CE_RELEASE_NOTES_GH_BIN", "gh") # `gh release list --json` does NOT expose `body` or `url` (only metadata # fields). `gh api` returns the full GitHub Releases API response shape # (tag_name, html_url, body, published_at, ...) and uses gh's auth so # there is no rate limit. The normalizer already handles this shape. cmd = [ gh_bin, "api", "/repos/" + OWNER + "/" + REPO + "/releases?per_page=" + str(limit), ] try: result = subprocess.run( cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=GH_TIMEOUT_SECS, check=False, ) except (FileNotFoundError, PermissionError, subprocess.TimeoutExpired): return False, None if result.returncode != 0: return False, None try: raw_list = json.loads(result.stdout) except json.JSONDecodeError: