Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions .agents/skills/release-note/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
---
name: release-note
description:
Write a user-facing Discord release announcement for the mittwald CLI (command
`mw`) from a git commit log and code diff. Trigger when asked to generate,
summarize, or write a release note/announcement for a release tag.
---

# Release note

Write a short, friendly release announcement for the **mittwald CLI** (the `mw`
command), suitable for posting in a Discord channel aimed at users of the CLI.

## Determining what changed

You are given a release **tag** (e.g. `v1.20.0`). You run inside a full checkout
of the repository, so all tags and history are available. Collect the commit log
and the code diff for everything since the previous stable minor/major release
by running this in the repository root:

```bash
TAG="<the release tag you were given>"

# All stable minor/major tags (patch == 0), sorted ascending by version.
MINORS=$(git tag --list 'v*' | grep -E '^v[0-9]+\.[0-9]+\.0$' | sort -V)

# The stable minor tag immediately preceding TAG (empty if TAG is the first one).
PREV=$(echo "$MINORS" | grep -B1 -x "$TAG" | grep -v -x "$TAG" | tail -1)

# Range to diff: previous minor..current, or just TAG if there is no predecessor.
if [[ -z "$PREV" ]]; then RANGE="$TAG"; else RANGE="$PREV..$TAG"; fi

# Commit log — for orientation only.
git log --no-merges --pretty=format:'- %s (%h)' $RANGE > changes.txt

# The actual code diff. Exclude generated docs and lockfiles (they are noise),
# and cap the size so it stays within the model's context window.
git diff --stat $RANGE -- \
':(exclude)docs/**' ':(exclude)**/*.lock' \
':(exclude)yarn.lock' ':(exclude)package-lock.json' > diff.txt
echo "" >> diff.txt
git diff $RANGE -- \
':(exclude)docs/**' ':(exclude)**/*.lock' \
':(exclude)yarn.lock' ':(exclude)package-lock.json' >> diff.txt
head -c 200000 diff.txt > diff.trimmed.txt && mv diff.trimmed.txt diff.txt
```

Then read `changes.txt` and `diff.txt`. **Base the release note on what the diff
actually changes**, not merely on what the commit subjects claim; use the commit
log only for orientation / grouping.

## Rules for the note

- Use GitHub-flavored Markdown and a few tasteful emoji.
- Group related changes into a handful of bullet points; focus on user-facing
highlights.
- Mention affected command names in the form `mw <group> <command>` explicitly,
wherever the diff makes them clear.
- Skip pure dependency bumps, chores and internal refactors unless notable.
- No preamble and no heading with the version number (a heading is added
separately by the publishing step).
- Keep it under ~1200 characters.

## Output

Write **only** the finished release note to a file named `note.md` in the
current working directory, using your file-writing tool.

The content of `note.md` is the sole deliverable. Anything you say in the chat
is discarded, and any stray text in `note.md` will be posted verbatim to
Discord.
63 changes: 20 additions & 43 deletions .github/workflows/release-announcement.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,31 +46,6 @@ jobs:
with:
node-version: "24"

- name: Determine previous minor release and collect changes
if: steps.check.outputs.should_run == 'true'
id: changes
run: |
TAG="${{ steps.check.outputs.tag }}"

# All stable minor/major tags, sorted ascending by version.
MINORS=$(git tag --list 'v*' | grep -E '^v[0-9]+\.[0-9]+\.0$' | sort -V)

# The stable minor tag immediately preceding the current one.
PREV=$(echo "$MINORS" | grep -B1 -x "$TAG" | grep -v -x "$TAG" | tail -1)

if [[ -z "$PREV" ]]; then
echo "::notice::No previous minor release found; using full history."
RANGE="$TAG"
else
RANGE="$PREV..$TAG"
fi
echo "prev=$PREV" >> "$GITHUB_OUTPUT"
echo "range=$RANGE" >> "$GITHUB_OUTPUT"

# Collect the commit log for the range into a file for the model.
git log --no-merges --pretty=format:'- %s (%h)' $RANGE > changes.txt
echo "Collected $(wc -l < changes.txt) commits for range $RANGE"

- name: Install OpenCode CLI
if: steps.check.outputs.should_run == 'true'
run: npm install -g opencode-ai
Expand All @@ -93,11 +68,18 @@ jobs:
"apiKey": "{env:MITTWALD_AI_API_KEY}"
},
"models": {
"Ministral-3-14B-Instruct-2512": {
"name": "Ministral-3-14B-Instruct-2512"
"Mistral-Medium-3.5-128B": {
"name": "mistral-medium-3.5"
}
}
}
},
"permission": {
"skill": "allow",
"read": "allow",
"write": "allow",
"edit": "allow",
"bash": "allow"
}
}
EOF
Expand All @@ -109,22 +91,17 @@ jobs:
MITTWALD_AI_API_KEY: ${{ secrets.MITTWALD_AI_API_KEY }}
run: |
TAG="${{ steps.check.outputs.tag }}"
PREV="${{ steps.changes.outputs.prev }}"

PROMPT="You are writing a release announcement for the mittwald CLI (command 'mw').
Below is the git commit log for release ${TAG}${PREV:+ (changes since ${PREV})}.
Write a short, friendly release note aimed at users, suitable for posting in Discord.
Rules:
- Use GitHub-flavored Markdown and a few tasteful emoji.
- Group related changes into a handful of bullet points; focus on user-facing highlights.
- Skip pure dependency bumps, chores and internal refactors unless notable.
- No preamble, no heading with the version (that is added separately), max ~1200 characters.

Commit log:
$(cat changes.txt)"

# 'opencode run' executes a single non-interactive prompt and prints the response.
opencode run -m mittwald/Ministral-3-14B-Instruct-2512 "$PROMPT" > note.md

# Make sure a stale note.md can't leak into the announcement.
rm -f note.md

# 'opencode run' executes a single non-interactive prompt.
opencode run -m mittwald/mistral-medium-3.5 "/release-note ${TAG}"

if [[ ! -s note.md ]]; then
echo "::error::OpenCode did not produce a note.md file."
exit 1
fi

echo "----- Generated note -----"
cat note.md
Expand Down
Loading