Stop Letting Your README Rot: Auto-Sync It on Every Push
Every developer has lived this: you clone a repo, follow the README's install instructions, and they don't work. The flags changed. The env vars changed. The quickstart references files that no longer exist. The README is lying to you, and it's nobody's fault — it's just that updating docs is the chore everyone postpones.
I got tired of it, so I built a GitHub Action that keeps the README in sync automatically. Here's how to set it up in about two minutes.
The problem
READMEs rot because they're maintained by hand. The code moves fast; the docs don't. Code review catches broken logic, but nobody reviews whether the README still describes reality after a PR merges. The result: new contributors bounce, users file "docs are wrong" issues, and maintainers sigh.
The fix isn't "write docs more diligently." That's a willpower solution, and willpower doesn't scale. The fix is making doc updates a side effect of pushing code.
The setup
Add this workflow file to your repo (.github/workflows/readme-sync.yml):
name: readme-sync
on:
push:
branches: [main]
jobs:
sync:
# Prevents the bot from triggering itself
if: "!contains(github.event.head_commit.message, '[skip readmeforge]')"
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # required — the Action diffs against the previous commit
- uses: haimhm/readmeforge-action@v1
with:
mode: pr
That's it. On every push to main, the Action:
- Computes the diff of the push (handles first pushes too, by diffing against the empty tree)
- Sends the diff plus your current README to the ReadmeForge API
- Opens a pull request with the updated README for you to review
You merge the PR, or you don't. Nothing lands in your repo without your eyes on it — that's the default pr mode. It's review-first by design.
How it actually works
The Action itself is thin on purpose. It collects the diff, ships it to a hosted API over HTTPS, and applies the returned README. The AI key lives on the server side — you never paste an OpenAI/OpenRouter key into your repo secrets, which is the part of other README-sync tools I always hated. One less secret to rotate, one less thing to leak.
The API returns the updated README plus a short changelog of what changed, so the PR body tells you exactly what the bot thinks it updated. If nothing doc-relevant changed, the Action exits quietly with updated=false and touches nothing.
Two config options worth knowing:
-
mode: pr(default) — opens a review PR.mode: commitpushes directly to the branch (Pro tier only). In commit mode, the bot's commits carry a[skip readmeforge]marker and theif:guard in the workflow above prevents infinite loops. -
readme-path— if your docs live somewhere other thanREADME.md.
The free tier
No key, no signup, no card. The free tier gives you 20 syncs a month on public repos. For most side projects that's plenty — it's roughly one sync per working day. If you need private repos, more volume (1,000 syncs/month), or direct-commit mode, there's a Pro tier at $9/month via Gumroad. You add the license key as a repo secret (READMEFORGE_LICENSE_KEY) and pass it in:
- uses: haimhm/readmeforge-action@v1
with:
mode: commit
license-key: ${{ secrets.READMEFORGE_LICENSE_KEY }}
Why this instead of a bot you prompt manually
You could paste your diff into ChatGPT and ask for a README update. That works exactly once, because you'll never do it twice. The whole point is removing the human from the loop: docs update because code moved, not because someone remembered.
Stale READMEs are a tax every new contributor pays. Two minutes of YAML removes it. Try it: https://github.com/marketplace/actions/readmeforge-readme-sync
Top comments (0)