cd /news/developer-tools/i-built-a-github-action-that-writes-… · home topics developer-tools article
[ARTICLE · art-91103] src=dev.to ↗ pub= topic=developer-tools verified=true sentiment=↑ positive

I Built a GitHub Action That Writes Your PR Descriptions

A developer has released StandupBot, a GitHub Action that automatically writes pull request descriptions by running the diff and commit messages through any OpenAI-compatible LLM endpoint. The action generates structured Summary, Changes, and Testing sections, plus up to three labels, and is available on the GitHub Marketplace under an MIT license. The developer built it to eliminate the unrewarded work of writing PR descriptions, which often leads to vague entries like 'fixed stuff'.

read4 min views1 publishedAug 10, 2026

Yep, this does what the title says. StandupBot reads the actual PR diff and commit messages, runs them through any OpenAI-compatible LLM endpoint, and writes a structured Summary / Changes / Testing description — so you never have to write "fixed stuff" again.

I built this for my own team because I was tired of staring at empty PR boxes after every fix. Then I put it on GitHub Marketplace so anyone can use it. MIT licensed, no strings.

A GitHub Action that writes your PR descriptions for you. It runs the real diff and commits through an LLM you choose, and fills in a structured Summary / Changes / Testing description plus up to three labels — so you stop hand-writing PR bodies and standup updates.

Bring your own model: it talks to any OpenAI-compatible endpoint (OpenAI, OpenRouter, Ollama, LM Studio, …). No provider, URL, or model is hardcoded.

Generated end-to-end by StandupBot for a real PR (nodejs/node#64573) from its actual diff, using a real LLM endpoint. This is the description it produced verbatim:

Summary #

Add

lchownSync

to the VFS implementation so that symbolic link ownership can be changed without following the link, matching the behavior offs.lchownSync

.## Changes

  • doc/api/vfs.md: added lchownSync(path, uid, gid)

to the list of VFS API signatures.- lib/internal/vfs/file_system.js: added synchronous lchownSync

method toVirtualFileSystem

and updated the async…

You open a PR. Forty files changed. Two hours of focused work. The description field is empty.

So you write: fixed stuff

. Or updated code

. Or changes requested by reviewer

.

Three months later, someone (you) is running git log -p

trying to figure out why the config format changed in April. The PR description was supposed to save that investigation. Nobody wrote it.

We tried before:

Approach Why it failed
PR templates Everyone types "see title" into the template
Checklist bots Nagging doesn't scale; people ignore them
Reviewer enforcement Becomes the team's most hated job

The gap isn't discipline. It's that writing PR descriptions is unrewarded work. You get the same merge button whether you write a detailed description or "fixed stuff."

So I built StandupBot.

This is verbatim output from nodejs/node#64573, generated from the actual diff:

Summary #

Add

lchownSync

to the VFS implementation so that symbolic link ownership can be changed without following the link, matching the behavior offs.lchownSync

.## Changes

  • doc/api/vfs.md: added lchownSync(path, uid, gid)

to VFS API signatures.- lib/internal/vfs/file_system.js: added synchronous lchownSync

method and updated the async wrapper.- lib/internal/vfs/provider.js: added default lchownSync

method with JSDoc comment.- lib/internal/vfs/providers/memory.js: implemented lchownSync

that updates uid/gid of the link entry.- lib/internal/vfs/setup.js: changed handler to invoke vfs.lchownSync

instead ofvfs.chownSync

.- test/parallel/test-vfs-lchown-symlink.js: new test verifying sync, callback, and promise variants.

Testing #

The new test exercises

fs.lchownSync

,fs.lchown

(callback), andfsp.lchown

(promise) on symlinks inside a VFS mount, asserting correct uid/gid changes.

Nobody edited that. It went straight from the model into the PR body. The action also returns a normalized title

and labels

clamped to bug | feature | chore | docs | refactor

— so your label taxonomy stays clean.

Add .github/workflows/standupbot.yml

:

name: StandupBot
on:
  pull_request:
    types: [opened, synchronize]

permissions:
  pull-requests: write
  contents: read

jobs:
  describe:
    runs-on: ubuntu-latest
    steps:
      - uses: XenoCyber0/StandUpBot@v1
        with:
          llm-base-url: ${{ secrets.LLM_BASE_URL }}
          llm-api-key: ${{ secrets.LLM_API_KEY }}
          model: ${{ vars.LLM_MODEL }}

Set LLM_API_KEY

as a secret, LLM_MODEL

as a variable. That's the whole thing.

The action talks to any OpenAI-compatible chat API. Nothing is hardcoded. All of these work:

OpenAI        → https://api.openai.com/v1
OpenRouter    → https://openrouter.ai/api/v1
Ollama        → http://localhost:11434/v1
LM Studio     → http://localhost:1234/v1
LocalAI       → http://localai:8080/v1
You decide.

You pick the model. You control the data path. Switching providers later is one secret update.

If you want your code to never leave your network:

GitHub repo ──webhook──▶ self-hosted Actions runner ──HTTP──▶ Ollama
                             (on your LAN)              (your LLM box)

llm-base-url

at your Ollama/LM Studio instancellm-api-key

can be any non-empty string — Ollama ignores itYour diff never crosses the internet. The only outbound call is writing the PR body back to GitHub, which... GitHub already owns.

Model notes: In my testing, Qwen2.5-Coder 7B and similar 7–9B instruction-tuned models work well. Below ~3B params, file-name hallucinations start appearing.

The rule is simple:

Your hand-written descriptions are safe. If you ever overwrite what it generated, it takes the hint and stays out.

Three parts worth stealing:

1. Diff budget. Fetches the PR diff, applies gitignore-style exclusions from .standupbot.yml

before anything hits a prompt:

exclude:
  - package-lock.json
  - '**/*.lock'
  - '**/dist/**'

The diff is hard-capped at ~24KB — a monster PR can't blow up your LLM context window.

2. Map-reduce for big diffs. Under the budget, one call. Over it? Each file gets summarized individually (max 8 LLM calls), then merged into the final description.

3. Structured output enforcement. The prompt requires a rigid schema — title

, summary

, changes[]

, testing

, labels[]

— and the parser clamps labels to the allowed set. If the model invents urgent-pls

, it gets dropped, not shipped.

Marketplace: github.com/marketplace/actions/standupbot-pr-describer

Source: github.com/XenoCyber0/StandUpBot (MIT)

Issues/feedback: github.com/XenoCyber0/StandUpBot/issues

Written by the person who finally read "fixed stuff" one too many times and decided to do something about it.

── more in #developer-tools 4 stories · sorted by recency
── more on @standupbot 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/i-built-a-github-act…] indexed:0 read:4min 2026-08-10 ·