Release Notes Writer CrewAI
What it does
A collector compares the current branch against the last release tag and lists every pull request in between. An editor groups them into features, fixes, and internal changes, then writes a readable one-line entry for each, dropping pure chores. A publisher posts the draft to Slack so a human can glance at it before it ships. Classic sequential crew, one pass, no loop.
The cast · 3 agents
Group the pull requests into Features, Fixes, and Internal. Write one plain-language line per entry that says what changed for a user, not how. Drop pure chores like dependency bumps and formatting. Lead with the most user-visible changes.
Compare HEAD against the given release tag and list every merged pull request in the range: number, title, labels, and author. Return them as a list. Do not summarize yet.
Post the finished notes to the release channel as a single message, with the version heading at the top. Do not add commentary of your own.
Flow
Interface
Depends on · 2 MCP servers
io.github.github/github-mcpnot in the registry yetcode
io.github.slack/slack-mcpnot in the registry yetchat# Generated by @socketcat/compiler for target: langgraph
# blueprint: com.socketcat/release-notes v1.0.0 schema: socketcat.dev/blueprint/v0
# This code is yours. Edit it freely. The socketcat_runtime helper is optional and can be vendored.
from typing import TypedDict
from langgraph.graph import StateGraph, START, END
import socketcat_runtime as _rt
class State(TypedDict, total=False):
sinceTag: object
notes: object
changes: object
def node_AgentInvoke_0(state):
return _rt.run_agent("collector", state, {"sinceTag":"sinceTag"}, "changes")
def node_AgentInvoke_1(state):
return _rt.run_agent("editor", state, {"changes":"changes"}, "notes")
def node_AgentInvoke_2(state):
return _rt.run_agent("publisher", state, {"notes":"notes"}, "notes")
def build():
b = StateGraph(State)
b.add_node("AgentInvoke_0", node_AgentInvoke_0)
b.add_node("AgentInvoke_1", node_AgentInvoke_1)
b.add_node("AgentInvoke_2", node_AgentInvoke_2)
b.add_edge(START, "AgentInvoke_0")
b.add_edge("AgentInvoke_0", "AgentInvoke_1")
b.add_edge("AgentInvoke_1", "AgentInvoke_2")
b.add_edge("AgentInvoke_2", END)
return b.compile()
INPUTS = ["sinceTag"]
OUTPUTS = ["notes"]
if __name__ == "__main__":
_rt.main(build, INPUTS, OUTPUTS)
▸blueprint.json (the portable format)
{
"id": "com.socketcat/release-notes",
"flow": {
"type": "sequence",
"blocks": [
{
"in": {
"sinceTag": "sinceTag"
},
"out": "changes",
"use": "collector",
"type": "agent"
},
{
"in": {
"changes": "changes"
},
"out": "notes",
"use": "editor",
"type": "agent"
},
{
"in": {
"notes": "notes"
},
"out": "notes",
"use": "publisher",
"type": "agent"
}
]
},
"tags": [
"release",
"changelog",
"documentation",
"sequential"
],
"title": "Release Notes Writer",
"agents": {
"editor": {
"model": {
"hint": "reasoning"
},
"title": "Editor",
"instructions": "Group the pull requests into Features, Fixes, and Internal. Write one plain-language line per entry that says what changed for a user, not how. Drop pure chores like dependency bumps and formatting. Lead with the most user-visible changes."
},
"collector": {
"model": {
"hint": "fast"
},
"title": "Collector",
"tools": [
"code.compare",
"code.list_pulls"
],
"instructions": "Compare HEAD against the given release tag and list every merged pull request in the range: number, title, labels, and author. Return them as a list. Do not summarize yet."
},
"publisher": {
"model": {
"hint": "fast"
},
"title": "Publisher",
"tools": [
"chat.post_message"
],
"instructions": "Post the finished notes to the release channel as a single message, with the version heading at the top. Do not add commentary of your own."
}
},
"estate": {
"changes": {
"type": "array",
"description": "The pull requests merged since the tag, with titles and labels."
}
},
"$schema": "socketcat.dev/blueprint/v0",
"authors": [
{
"url": "https://socketcat.com",
"name": "SocketCat"
}
],
"license": "MIT",
"servers": [
{
"ref": "io.github.github/github-mcp",
"alias": "code"
},
{
"ref": "io.github.slack/slack-mcp",
"alias": "chat"
}
],
"summary": "Turns the pull requests merged since your last release tag into grouped, human-readable release notes.",
"targets": [
"crewai",
"langgraph",
"*"
],
"version": "1.0.0",
"interface": {
"inputs": {
"sinceTag": {
"type": "string",
"description": "The previous release tag to diff against, e.g. v1.4.0."
}
},
"outputs": {
"notes": {
"type": "string",
"description": "The finished release notes, grouped and written for a reader."
}
}
},
"extensions": {
"com.crewai": {
"process": "sequential"
}
},
"description": "A collector compares the current branch against the last release tag and lists every pull request in between. An editor groups them into features, fixes, and internal changes, then writes a readable one-line entry for each, dropping pure chores. A publisher posts the draft to Slack so a human can glance at it before it ships. Classic sequential crew, one pass, no loop."
}More in Coding & QA
Browse all →E2E Test Author
Turns a user story into browser tests: plans the scenarios, writes Playwright code, runs it against the real page, and self-heals until it passes for the right reason.