Recipes
Release Notes
Weekly release notes auto-generated from GitHub commits.
Every Monday at 09:00 UTC, scan the last 7 days of merged PRs in your repo,
group them by label, summarise each group with orbit.ai, write the
result as a workspace artifact, and post a link to Slack.
The Function
defineJob({
name: "weekly-release-notes",
description: "Generate weekly release notes from merged PRs.",
handler: async (ctx) => {
const since = new Date(Date.now() - 7 * 86_400_000).toISOString();
const prs = await ctx.plugins.githubMcp.searchIssues({
q: `repo:acme/api is:pr is:merged merged:>=${since.slice(0, 10)}`,
sort: "updated",
});
const groups: Record<string, typeof prs> = {};
for (const pr of prs) {
for (const label of (pr.labels ?? []).map((l) => l.name)) {
(groups[label] ??= []).push(pr);
}
}
const sections = await Promise.all(
Object.entries(groups).map(async ([label, items]) => {
const summary = await ctx.orbit.ai.run({
model: "anthropic/claude-3.7-sonnet",
prompt: `Summarise these merged PRs as 3-5 user-facing bullet points:\n\n${items
.map((p) => `- ${p.title} (#${p.number})`).join("\n")}`,
maxTokens: 300,
});
return `## ${label}\n\n${summary}\n`;
}),
);
const body = [`# Release notes (${since.slice(0, 10)} → today)`, ...sections].join("\n\n");
const path = `release-notes-${new Date().toISOString().slice(0, 10)}.md`;
await ctx.orbit.storage.put(path, body, { contentType: "text/markdown" });
const url = await ctx.orbit.storage.url(path, { expiresIn: "30d" });
await ctx.plugins.slackMcp.postMessage({
channel: "#releases",
text: `Weekly release notes: ${url}`,
});
return { artifact: path, url };
},
});hrbr inspect -f ./release-notes.job.ts
hrbr inspect 'return await hrbr.triggers.list({ limit: 20 })'What you get
The artifact lives in workspace storage for 30 days. A signed URL means anyone with the link can read it — no Harbor login required (useful for contractors / public stakeholders).
Variations
- Per-team feed: filter
searchIssuesby team label, write multiple artifacts. - HTML output: import
/sdk/orbitto render a styled report instead of plain markdown. - Cross-repo: loop over a configured list of repos before grouping.