Chore: Update release-notes skill and add security skill#7271
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the existing draft-release Claude skill to be safer and more accurate when selecting a diff baseline and when creating draft releases, and it adds a new rewrite-security-advisory skill to standardize Obot GHSA writeups into a concise user-facing format.
Changes:
- Added a new skill for rewriting GitHub security advisories into Obot’s standard short format.
- Improved
draft-releaseguidance around selecting a diff baseline that is actually reachable fromHEAD. - Added an explicit “full draft approval” checkpoint before any GitHub write operation in
draft-release.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| .claude/skills/rewrite-security-advisory/SKILL.md | New skill for fetching and rewriting GHSA advisories into a consistent, deployer-focused markdown format. |
| .claude/skills/draft-release/SKILL.md | Tightens release-drafting procedure (baseline selection + explicit approval gate + local draft file workflow). |
Comments suppressed due to low confidence (3)
.claude/skills/rewrite-security-advisory/SKILL.md:77
- The credits boilerplate links to
...?tab=security-ov-file, which is a GitHub UI query parameter and not a stable/security-policy-specific URL. Link to the repo's actual security policy instead (either the policy page orSECURITY.md).
The Obot team would like to thank [@<reporter>](https://github.com/<reporter>) for responsibly disclosing this issue in accordance with our [security policy](https://github.com/obot-platform/obot/?tab=security-ov-file).
.claude/skills/rewrite-security-advisory/SKILL.md:92
- This section references example GHSA markdown files in the repo root, but there are currently no
GHSA-*.mdfiles in the repository root. This makes the guidance misleading; either point to a real location/source for examples or ask the user to provide one.
## Reference: a finished example
See the advisory writeups already in the repo root (e.g. `GHSA-jgh3-fggc-mcpm.md`,
`GHSA-pr6h-vr44-xq8j.md`, `GHSA-xwmw-prc4-v3cr.md`) for the exact tone and length
to match.
.claude/skills/draft-release/SKILL.md:223
- Step 8 instructs writing the scratch file to
<REPO_ROOT>/release-notes-<VERSION>.md, but step 9 uses a relative path (release-notes-<VERSION>.md). If the working directory is not the repo root when runninggh release create, this will fail to find the file. Use the same<REPO_ROOT>/...path in the command for consistency.
gh release create <VERSION> \
--repo obot-platform/obot \
--draft \
--title "<VERSION>" \
--target main \
--notes-file release-notes-<VERSION>.md
</details>
---
💡 <a href="/obot-platform/obot/new/main?filename=.github/instructions/*.instructions.md" class="Link--inTextBlock" target="_blank" rel="noopener noreferrer">Add Copilot custom instructions</a> for smarter, more guided reviews. <a href="https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot" class="Link--inTextBlock" target="_blank" rel="noopener noreferrer">Learn how to get started</a>.
24944c7 to
f018c30
Compare
| ### 8. Show the full assembled draft and wait for approval (required, do not skip) | ||
|
|
||
| First write the assembled notes to `/tmp/release-notes-<VERSION>.md` so there's a local copy the user can re-use if they want to recreate the draft. Then create the draft release on GitHub with that file as the body: | ||
| Write the fully assembled notes (opener, Big Updates, Improvements, Upgrade Notes, What's Changed, Full Changelog line) to `<REPO_ROOT>/release-notes-<VERSION>.md` — in the project working directory itself (not `/tmp`), so the user can open it directly in their IDE for review/editing. Make sure `release-notes-*.md` is in the repo's `.gitignore` (add it if it's missing) so this scratch file can't be accidentally committed or included in a PR diff. |
f018c30 to
c05b87a
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (3)
.claude/skills/rewrite-security-advisory/SKILL.md:23
- The
--jqexpression uses.credits_detailed[].user.loginand.cwes[].cwe_idwithout null-safe operators; if either array is missing/null in an advisory response,jqwill error and the fetch step will fail. Using[]?makes this robust while preserving the same output shape.
gh api repos/obot-platform/obot/security-advisories/<GHSA-id> --jq '{summary, description, severity, cvss: .cvss.vector_string, score: .cvss.score, vuln_range: .vulnerabilities[0].vulnerable_version_range, patched: .vulnerabilities[0].patched_versions, credits: [.credits_detailed[].user.login], cwes: [.cwes[].cwe_id]}'
.claude/skills/rewrite-security-advisory/SKILL.md:77
- The credits boilerplate links to
...?tab=security-ov-file, which is not the canonical security policy URL for this repo (the policy is inSECURITY.mdand is published at/security/policy). This link is likely to break for readers; use the stable policy URL instead.
The Obot team would like to thank [@<reporter>](https://github.com/<reporter>) for responsibly disclosing this issue in accordance with our [security policy](https://github.com/obot-platform/obot/?tab=security-ov-file).
.claude/skills/draft-release/SKILL.md:206
- This step instructs the skill to modify the repo’s committed
.gitignoreifrelease-notes-*.mdisn’t present. In the current repo,.gitignoredoes not include this pattern, so running the skill will leave an unrelated working-tree change that could be accidentally committed. Consider using.git/info/excludefor a local-only ignore (or explicitly include the.gitignorechange as part of this PR).
Write the fully assembled notes (opener, Big Updates, Improvements, Upgrade Notes, What's Changed, Full Changelog line) to `<REPO_ROOT>/release-notes-<VERSION>.md` — in the project working directory itself (not `/tmp`), so the user can open it directly in their IDE for review/editing. Make sure `release-notes-*.md` is in the repo's `.gitignore` (add it if it's missing) so this scratch file can't be accidentally committed or included in a PR diff.
| --title "<VERSION>" \ | ||
| --target main \ | ||
| --notes-file /tmp/release-notes-<VERSION>.md | ||
| --notes-file release-notes-<VERSION>.md |
| Immediately before conversion, re-read the markdown from disk and confirm it contains the user's latest requested revisions. Record its SHA-256 hash so the exact source state being uploaded is explicit. | ||
|
|
||
| ```bash | ||
| shasum -a 256 "$CLAUDE_PROJECT_DIR/release-blog-<VERSION>.md" |
| ``` | ||
| mcp__obot-wordpress__list_categories(search_query="Blog") # → expect id 6 | ||
| mcp__obot-wordpress__list_users() # → find Craig Jellick, expect id 9 | ||
| mcp__obot-wordpress__list_users(context="view") # → find Craig Jellick, expect id 9 |
Some tweaks to the release-notes skills based on my most recent use of it. Also I previously wrote a skill to help me rewrite security advisories to prepare them for publishing. Committing that as well. Signed-off-by: Craig Jellick <craig@obot.ai>
c05b87a to
a616996
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (3)
.claude/skills/rewrite-security-advisory/SKILL.md:77
- The credits boilerplate links to the security policy using a non-canonical
?tab=security-ov-fileURL. Prefer the stable repo security page URL (also referenced in SECURITY.md) so the link works consistently.
The Obot team would like to thank [@<reporter>](https://github.com/<reporter>) for responsibly disclosing this issue in accordance with our [security policy](https://github.com/obot-platform/obot/?tab=security-ov-file).
.claude/skills/draft-release/SKILL.md:24
- This new hard-constraint bullet includes an em dash ("Full Changelog line — ...") while the skill also says "No em dashes". Consider using a plain hyphen here to avoid the model echoing em dashes into the generated release notes.
- Never run `gh release create` (or any other command that writes to GitHub) until the user has seen the fully assembled draft (opener, Big Updates, Improvements, Upgrade Notes, What's Changed, Full Changelog line — the whole document, not just the feature list from step 5) and explicitly approved it. Step 5's feature-list confirmation is necessary but not sufficient; the user must sign off on the actual prose before anything is pushed to GitHub.
.claude/skills/draft-release-blog/SKILL.md:180
- This uses
shasum -a 256, but the repo already usessha256sum(e.g. .github/workflows/release.yml:40). Usingsha256sumis also more standard on Linux runners.
shasum -a 256 "$CLAUDE_PROJECT_DIR/release-blog-<VERSION>.md"
| ## Reference: a finished example | ||
|
|
||
| See the advisory writeups already in the repo root (e.g. `GHSA-jgh3-fggc-mcpm.md`, | ||
| `GHSA-pr6h-vr44-xq8j.md`, `GHSA-xwmw-prc4-v3cr.md`) for the exact tone and length | ||
| to match. |
|
|
||
| - **Target version** (e.g. `v0.22.0`): ask the user if not provided. If recent pre-release tags exist (e.g. `v0.22.0-rc3`), suggest the corresponding minor (`v0.22.0`) and confirm. | ||
| - **Diff baseline** (e.g. `v0.21.3`): auto-detect as the highest non-pre-release tag, regardless of whether it is a minor or patch. This is the range used to find changes (`<DIFF_BASELINE>..HEAD`) and the left side of the "Full Changelog" compare link. Use `git tag --sort=-v:refname | grep -v -- '-' | head -1`. | ||
| - **Diff baseline** (e.g. `v0.21.3`): auto-detect as the highest non-pre-release tag, regardless of whether it is a minor or patch, **that is also an ancestor of `HEAD`**. This is the range used to find changes (`<DIFF_BASELINE>..HEAD`) and the left side of the "Full Changelog" compare link. Use `git tag --sort=-v:refname | grep -v -- '-' | head -1`, then verify with `git merge-base --is-ancestor <candidate> HEAD`. Patch releases are sometimes cut from a separate release branch that never merges back into `main` — if the highest-sorted tag fails the ancestor check, walk down to the next-highest tag and check again until one passes. Do not silently trust version-sort order alone. |
| Drafts a blog post announcing an obot release. Sources the feature spine from the draft GitHub release (the output of the `draft-release` skill or an existing draft on GitHub), then does additional research to add the kind of detail, context, and rationale that release notes deliberately omit but a blog post needs. | ||
|
|
||
| The blog is for obot.ai's hosted Wordpress CMS. The default output is a markdown file at `/tmp/release-blog-<VERSION>.md` that the user can paste into the CMS themselves. If the user explicitly asks to post it (e.g. "post it up there", "create the draft in Wordpress"), the skill can also create the post as a Wordpress **draft** via the `obot-wordpress` MCP server (see step 8). The skill never publishes a live post without explicit user confirmation of the `publish` status. | ||
| The blog is for obot.ai's hosted Wordpress CMS. The default output is a markdown file at `<repo root>/release-blog-<VERSION>.md` (i.e. the current project directory) that the user can paste into the CMS themselves. Writing it into the repo makes it easy to review in the IDE; it is an intentionally untracked file — do not commit it and do not add it to `.gitignore`. If the user explicitly asks to post it (e.g. "post it up there", "create the draft in Wordpress"), the skill can also create the post as a Wordpress **draft** via the `obot-wordpress` MCP server (see step 8). The skill never publishes a live post without explicit user confirmation of the `publish` status. |
| - https://obot.ai/blog/announcing-obot-platform-v0-22-0-centrally-managed-skills-fleet-scanning-and-enterprise-controls-for-mcp/ — ~2,100 words, one `## <Feature Name>` section per feature, closes with a multi-CTA "Get started". Note: this post opens with a "client zoo" problem-first hook. Use it as a reference for body voice and structure only. Do NOT copy its opener; the required opener pattern is in step 6. | ||
| - https://obot.ai/blog/announcing-obot-platform-v0-23-0/ — ~1,800 words, opens with the mandated pattern ("The Obot Platform v0.23.0 release is out."), same per-feature section structure and multi-CTA close. This is the opener to model. | ||
|
|
||
| Author byline is **Craig Jellick** (`craig@obot.ai`). The personal voice in the deep-dive shape is his — when the post uses "I", that's him. Don't use "I" in the roundup shape; use "we". | ||
| Author byline is **Craig Jellick** (`craig@obot.ai`). Write in the first-person plural ("we") throughout — these are company announcements, not personal essays. Reserve first-person singular for a specific personal-stake line only if the user supplies one. |
Some tweaks to the release-notes skill based on my most recent use of
it. Also I previously wrote a skill to help me rewrite security
advisories to prepare them for publishing. Committing that as well.
Signed-off-by: Craig Jellick craig@obot.ai