Changelog Announcer
Takes a changelog entry and generates announcements for email, Slack, and social.
aihttpemail
Source
/**
* Takes a changelog entry and generates an announcement
* for multiple channels: email, Slack, and social media.
*/
form changelog_entry {
label: "Changelog Entry"
schema: @json {
{
"type": "object",
"required": ["version", "changes"],
"properties": {
"version": { "type": "string", "title": "Version" },
"changes": { "type": "string", "title": "What Changed" },
"breaking": { "type": "boolean", "title": "Breaking Changes?" }
}
}
}
}
secret announce_config {
vars: [SLACK_WEBHOOK_URL]
}
workflow announce_release {
label: "Announce Release"
root {
type: code
label: "Extract changelog"
code: @ts { return context.nodes.root.input }
outputSchema: @json {
{
"type": "object",
"properties": {
"version": { "type": "string" },
"changes": { "type": "string" },
"breaking": { "type": "boolean" }
}
}
}
}
node generate_announcement {
type: ai
label: "Generate announcement"
kind: object
model: "google/gemini-2.5-flash"
prompt: @ts {
const entry = context.nodes.root.output
return "Generate release announcements for version " + entry.version + ".\n\nChanges:\n" + entry.changes + "\n\nBreaking changes: " + (entry.breaking ? "yes" : "no") + "\n\nGenerate: a short Slack message (2-3 lines), an email body (1 paragraph), and a tweet (under 280 chars)."
}
schema: @json {
{
"type": "object",
"required": ["slack_message", "email_body", "tweet"],
"properties": {
"slack_message": { "type": "string" },
"email_body": { "type": "string" },
"tweet": { "type": "string" }
}
}
}
temperature: 0.7
}
node post_slack {
type: http
label: "Post to Slack"
method: "POST"
url: @ts { return context.secrets.announce_config.SLACK_WEBHOOK_URL }
headers: @ts { return { "Content-Type": "application/json" } }
body: @ts {
return JSON.stringify({
text: context.nodes.generate_announcement.output.slack_message
})
}
secrets: {
announce_config: [SLACK_WEBHOOK_URL]
}
}
node send_email {
type: email
label: "Send email announcement"
from: @ts { return "[email protected]" }
to: @ts { return "[email protected]" }
subject: @ts { return "Release " + context.nodes.root.output.version }
text: @ts { return context.nodes.generate_announcement.output.email_body }
}
node result {
type: code
label: "Compile results"
code: @ts {
return {
version: context.nodes.root.output.version,
tweet_draft: context.nodes.generate_announcement.output.tweet,
tweet_length: context.nodes.generate_announcement.output.tweet.length,
slack_sent: true,
email_sent: true
}
}
}
flow {
root -> generate_announcement
generate_announcement -> post_slack
generate_announcement -> send_email
post_slack -> result
send_email -> result
}
}
trigger on_changelog {
form:changelog_entry -> announce_release
enabled: true
}
Flow
Trigger to workflow
changelog_entryform
announce_release
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.
Workflow nodes
CODE
Code Node
Extract changelog
AI
AI Node
Generate announcement
HTTP
HTTP Node
Post to Slack
EMAIL
Email Node
Send email announcement
CODE
Code Node
Compile results
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.