Template · Engineering

Release notes from a tag

Your CI posts the new tag to a webhook. Jimothy lists every commit since the previous tag, Claude groups them into features, fixes and breaking changes in language users understand (dropping refactors and CI noise), and once you approve, the notes are published to the GitHub release.

Download .json

Webhookv2.8.0Tag pushed by CIrelease
Pipeline
  1. Commits since last tag Shell
  2. Write release notes Claude API · Sonnet 5
  3. Approve notes You
  4. Publish to GitHub Shell
GitHub releasev2.8.04 features, 9 fixes, 1 breaking changePublished
The pipeline

What each step does

  1. Commits since last tag

    Shell

    Fetches tags and lists the commits between the previous tag and this one.

  2. Write release notes

    Claude API · Sonnet 5

    Groups the changes for users and leaves out internal work.

  3. Approve notes

    You

    Shows you the notes. Reject with a comment and they are rewritten.

  4. Publish to GitHub

    Shell

    Updates the GitHub release for the tag, or creates it.

Set it up

From copy to first run

  1. Copy the pipeline JSON with the button above.
  2. In Jimothy, open Pipelines → New pipeline, paste it under “Or import a pipeline JSON” and click Import.
  3. Under Workspace, choose your clone of the repository.
  4. Fill in the variables below under Pipeline settings → Variables.
  5. Triggers → Add trigger → Webhook. Add a CI step on tag push that posts {"title": "<tag>", "key": "<tag>"} to the URL.
Variables

What to fill in

The prompts and commands read these as {{vars.<name>}}. The examples are placeholders: replace them with your own.

VariableWhat to put in itExample
productYour product and who reads its release notes.Acme, a reporting tool for finance teams. Readers are admins at customer companies.
Show the pipeline JSON
{
  "jimothyPipeline": 1,
  "name": "Release notes from a tag",
  "description": "Writes release notes from the commits since the previous tag and publishes them to the GitHub release.",
  "icon": "rocket",
  "color": "#f97316",
  "repo": {
    "mode": "inplace",
    "localPath": "",
    "baseBranch": "main"
  },
  "concurrency": 1,
  "variables": {
    "product": "Acme, a reporting tool for finance teams. Readers are admins at customer companies."
  },
  "steps": [
    {
      "id": "log",
      "name": "Commits since last tag",
      "type": "shell",
      "description": "Fetches tags and lists the commits between the previous tag and this one.",
      "timeoutMinutes": 3,
      "command": "git fetch -q --tags origin && tag={{issue.title}} && if prev=$(git describe --tags --abbrev=0 \"$tag^\" 2>/dev/null); then echo \"Changes from $prev to $tag\"; git log --no-merges --pretty='- %s (%h)' \"$prev..$tag\"; else echo \"First release: $tag\"; git log --no-merges --pretty='- %s (%h)' \"$tag\" | head -300; fi"
    },
    {
      "id": "draft",
      "name": "Write release notes",
      "type": "agent",
      "description": "Groups the changes for users and leaves out internal work.",
      "harnessId": "anthropic-api",
      "model": "claude-sonnet-5",
      "dependsOn": [
        "log"
      ],
      "timeoutMinutes": 5,
      "systemPrompt": "You write release notes for {{vars.product}} Plain, specific, no hype.",
      "prompt": "{{steps.log.output | truncate:30000}}\n\nWrite the release notes for {{issue.title}} in Markdown with these sections, leaving out any that are empty: ## Breaking changes (with what to do), ## New, ## Improved, ## Fixed. Describe each change by what users can now do or what no longer goes wrong, with the commit hash in brackets. Leave out refactors, tests, CI, dependency bumps and internal tooling.{{#if steps.approve.output}}\n\nYour previous draft was rejected with this feedback. Rewrite it:\n{{steps.approve.output}}{{/if}}"
    },
    {
      "id": "approve",
      "name": "Approve notes",
      "type": "approval",
      "description": "Shows you the notes. Reject with a comment and they are rewritten.",
      "dependsOn": [
        "draft"
      ],
      "loopBackTo": "draft",
      "maxLoops": 3,
      "approvalMessage": "Publish these notes to the {{issue.title}} release?\n\n---\n\n{{steps.draft.output}}"
    },
    {
      "id": "publish",
      "name": "Publish to GitHub",
      "type": "shell",
      "description": "Updates the GitHub release for the tag, or creates it.",
      "dependsOn": [
        "approve"
      ],
      "timeoutMinutes": 3,
      "command": "if gh release view {{issue.title}} >/dev/null 2>&1; then gh release edit {{issue.title}} --notes {{steps.draft.output}}; else gh release create {{issue.title}} --title {{issue.title}} --notes {{steps.draft.output}}; fi && gh release view {{issue.title}} --json url --jq .url"
    }
  ]
}