How to Write a CONTRIBUTING.md: A Guide Humans and Coding Agents Actually Follow
Most CONTRIBUTING.md files are either a code of conduct with a link to the issue tracker or a wall of process nobody reads. A practical guide to writing one that gets a first pull request merged: what goes in it, what to leave out, how it fits next to AGENTS.md, and how to keep it true.
- documentation
- developer-experience
- ai-agents
Every repository has contribution rules. The question is whether they're written down or whether a new contributor discovers them one review comment at a time. The second version is how most teams actually work: a first pull request comes in, and it bounces three times — wrong branch name, missing changeset, tests run with the wrong command — and none of those rules appear anywhere a newcomer could have found them.
A CONTRIBUTING.md is the file that's supposed to prevent that, and GitHub gives it unusual reach. According to GitHub's documentation on contributor guidelines, the file can live in the repository root, docs/, or .github/, and anyone opening an issue or pull request sees a link to it. It also gets a Contributing tab on the repository overview. Few documents get placed in front of a contributor at the exact moment they need it. Most teams waste that slot.
This guide covers what a good CONTRIBUTING.md contains, the order to put it in, a copyable template, how it divides labor with AGENTS.md now that a growing share of pull requests are written by agents, and how to stop it from quietly going stale.
What CONTRIBUTING.md is actually for#
A CONTRIBUTING.md has one job: get a correct first pull request merged with as few review round-trips as possible. Everything in it should serve that outcome. Everything that doesn't belongs somewhere else.
That rules out a surprising amount of what ends up in these files. Project history belongs in the README. The code of conduct belongs in its own CODE_OF_CONDUCT.md, which GitHub also recognizes. Architecture belongs in architecture docs. Governance and maintainer elections belong in GOVERNANCE.md, if you need them at all. When those get stuffed into CONTRIBUTING.md, the part a contributor needs — how do I run the tests? — ends up on screen four.
Here's how the contributor-facing files in a typical repository divide up:
| File | Audience | Answers |
|---|---|---|
README.md | Anyone landing on the repo | What is this, and how do I use it? |
CONTRIBUTING.md | People about to change it | How do I get a change accepted? |
AGENTS.md / CLAUDE.md | Coding agents | What commands, conventions, and boundaries apply? |
CODE_OF_CONDUCT.md | Everyone participating | How are we expected to behave? |
SECURITY.md | Someone who found a vulnerability | Where do I report it privately? |
| PR template | The author of one specific PR | What does a reviewer need to know about this change? |
The split matters because each file is read at a different moment. A contributor reads the README once, CONTRIBUTING.md before their first change, and the pull request description template every time. Put the information where the reader is when they need it.
The sections that earn their place#
A useful CONTRIBUTING.md follows the path a contributor actually walks, in order. Write it as a sequence, not a reference manual.
1. Where to start. One short paragraph: what kinds of contributions you want, and where to find work. Link the "good first issue" label if you use it. If you don't want certain contributions — large unsolicited refactors, new dependencies without discussion — say so here, before someone spends a weekend on one.
2. Discuss before you build. State the threshold for opening an issue first. A typo fix needs no discussion; a new public API does. Without this line, you get 1,500-line pull requests for features the maintainers already decided against.
3. Local setup. The exact commands, in a fenced block, that take a fresh clone to a passing test run. Version requirements, package manager, any services that need to be running. This is the section most likely to be wrong, so keep it executable and short.
4. Making the change. Branch naming, where tests go, the conventions a reviewer will actually enforce. Only the ones they'll enforce — a list of twenty style preferences becomes a list nobody reads.
5. Before you open the PR. The checks to run locally, with commands. If CI will fail on formatting, tell people the formatting command.
6. Opening the pull request. What the description must include, commit message style, whether you squash, whether changelog entries or changesets are required.
7. What happens next. Who reviews, roughly how long it takes, and what "changes requested" means in your project. Contributors abandon PRs mostly because of silence, not rejection. Setting an expectation costs one sentence.
The flow a contributor follows should look like this, and your document should mirror it:
flowchart TD
A["Find an issue or idea"] --> B{"Needs discussion first?"}
B -->|"Yes"| C["Open an issue and agree on approach"]
B -->|"No"| D["Clone and run local setup"]
C --> D
D --> E["Make the change on a branch"]
E --> F["Run the local checks"]
F -->|"Fails"| E
F --> G["Open PR using the template"]
G --> H["Review"]
H -->|"Changes requested"| E
H --> I["Merged"]If a step in that diagram has no corresponding section in your file, that's the step where your first-time contributors are getting stuck.
A template you can copy#
Start from this and delete what doesn't apply. Every command in it should be one you've run on a clean machine this month.
# Contributing
Thanks for helping. This guide gets you from a fresh clone to a merged pull request.
## Where to start
Bug fixes, docs improvements, and issues labeled `good first issue` are always welcome.
For new features or anything that changes a public API, open an issue first so we can
agree on the approach before you write code.
## Local setup
Requires Node 22 and npm 10.
```bash
git clone https://github.com/<org>/<repo>.git
cd <repo>
npm install
npm test
```
If `npm test` passes, you're ready.
## Making a change
- Branch from `main` using `fix/<short-name>` or `feat/<short-name>`.
- Put unit tests next to the file they test, as `<name>.test.ts`.
- Don't add a dependency without mentioning it in the issue first.
## Before you open a PR
```bash
npm run format
npm run lint
npm run typecheck
npm test
```
CI runs the same commands. If they pass locally, they'll pass there.
## Opening the pull request
- Fill in the PR template: what changed, why, and how you tested it.
- Keep one concern per PR. Unrelated cleanups go in their own PR.
- We squash on merge, so your individual commit messages don't need to be perfect.
## What happens next
A maintainer will respond within a few working days. If we ask for changes, push to the
same branch — no need to open a new PR. If you hear nothing after a week, comment on
the PR to nudge us.
Notice what's missing: no project history, no philosophy, no list of every lint rule. The linter knows the lint rules. If a tool enforces it, the document only needs the command that runs the tool.
Where CONTRIBUTING.md and AGENTS.md overlap#
A growing share of the contributors following your instructions aren't people. Coding agents open pull requests against your repository, and they need many of the same facts: setup commands, test commands, conventions, what not to touch.
The AGENTS.md project draws the line explicitly: README files are for humans — "quick starts, project descriptions, and contribution guidelines" — while AGENTS.md holds "the extra, sometimes detailed context coding agents need." That's a sensible split of purpose. The trap is a split of facts. When the test command lives in both files, written independently, you now have two sources of truth and a guarantee that one of them will eventually be wrong.
Divide them like this:
| Content | CONTRIBUTING.md | AGENTS.md |
|---|---|---|
| Why we want contributions, where to start | Yes | No |
| Discuss-first threshold | Yes | Short version as a boundary |
| Setup and test commands | Yes, canonical | Yes, same commands |
| Enforced conventions | Summary | Precise, with file paths |
| Review process and timelines | Yes | No |
| Boundaries ("never edit generated files") | Briefly | Yes, explicitly |
For the facts that must appear in both — mostly commands — pick one file as canonical and make the other one either reference it or match it exactly, and check that they match. Our guide to writing an AGENTS.md covers the agent side in detail, and if you have more than one package, instruction files in a monorepo explains which file wins where.
The payoff for keeping these aligned is bigger than it looks. An agent that follows correct contribution rules opens a pull request that's already the right shape, which is most of what makes reviewing AI-generated pull requests tractable.
Common mistakes#
A few patterns show up in almost every CONTRIBUTING.md that isn't working:
- The aspirational process. The file describes how the team intended to work two years ago: a
developbranch nobody uses, a release process that changed, a sign-off requirement that was dropped. Contributors follow it faithfully and get corrected. - Setup that only works on the author's laptop. It's missing the environment variable everyone already has, or the service that has to be running. Test it on a fresh clone or in a container.
- Rules without commands. "Make sure your code is formatted" with no formatting command. Every rule a contributor must satisfy should come with the command that checks it.
- Burying the commands. Setup on screen four, below the history and the values statement. The commands are the most-read part; put them near the top.
- Silence about review. No word on who reviews or how long it takes, so contributors assume the worst and walk away.
- No owner. Nobody is responsible for the file, so nobody notices when it goes wrong.
The first two are by far the most expensive, and they share a cause.
The real failure: the file stops matching the repo#
Almost no CONTRIBUTING.md is wrong on the day it's written. It becomes wrong later, one unrelated pull request at a time. Someone migrates from Yarn to npm and updates CI but not the docs. Someone renames the test:unit script. Someone adds a required changeset step and tells the team in Slack. Each change is reasonable; none of them touches CONTRIBUTING.md, because nobody thinks of it as part of the change.
This is documentation drift, and contribution guides are especially exposed to it because the people who maintain the repo are the people who never read the file. Maintainers already know how to run the tests. The only readers are newcomers and agents — exactly the readers least able to tell that an instruction is stale. A newcomer follows the wrong command, hits an error, and assumes they did something wrong. An agent follows the wrong command and either fails or, worse, finds a workaround that encodes the stale assumption into its pull request.
Reading the file more carefully won't fix this, because nothing in the file looks wrong. The fix is to treat contributor docs like code: change them in the same pull request as the behavior they describe. That's the core idea behind a docs-as-code workflow, and it works when the reviewer knows to ask "did the contribution guide just become false?" It works better when something asks that automatically.
Keeping it true with Moxie Docs#
Moxie Docs indexes your GitHub repository into living, source-cited documentation and checks docs against the code as it changes, so a renamed script or a changed setup step shows up as a gap instead of a newcomer's bad afternoon. It serves the same conventions and verified commands to coding agents over MCP, so the agent and the human contributor work from one source rather than two files drifting apart. When docs fall behind, it opens a reviewable Cleanup PR. It proposes the fix; you decide whether to merge it.
You can see what it finds in your own repository on the free plan — one repository, no card required. If you're starting from nothing, the free README generator and AGENTS.md generator give you a first draft of the neighboring files.
Measuring whether it's working#
A contribution guide is working if first-time contributors need less help. A few cheap signals:
- Review round-trips on first PRs. Count the "please also…" comments on the last ten first-time contributions. Each repeated one is a missing line in the file.
- Setup questions in issues or chat. If people keep asking how to run something, the setup section is wrong or missing.
- Time from first PR to merge. Long tails usually mean unclear review expectations or a PR that needed discussion first.
- Agent PRs that fail CI on the first push. Agents follow written instructions literally, so a failing first push often points straight at a stale command.
- Last real edit to the file. If the build changed this quarter and
CONTRIBUTING.mddidn't, check it today. Stale contributor docs are a quiet form of documentation debt.
None of these need a dashboard. Reading your last ten first-time pull requests will tell you most of it.
Frequently asked questions#
Where should CONTRIBUTING.md go in a GitHub repository?#
GitHub recognizes it in the repository root, the docs/ folder, or the .github/ folder, and links it when someone opens an issue or pull request. The root is the most discoverable for people browsing the code. You can also set default contribution guidelines for an organization or personal account, which apply to repositories that don't have their own.
What should a CONTRIBUTING.md include?#
Where to start, when to open an issue before writing code, exact local setup commands, the conventions reviewers enforce, the checks to run before opening a pull request, what the PR must include, and what happens during review. Leave out project history, governance, and the code of conduct, which belong in their own files.
Is CONTRIBUTING.md only for open source projects?#
No. Internal repositories benefit just as much, arguably more, because new hires and engineers from other teams are contributors too, and they don't have a maintainer to ask on a public issue. The same structure works; the "where to start" section just points at your internal tracker instead.
Do I still need CONTRIBUTING.md if I have AGENTS.md?#
Yes. They serve different readers. CONTRIBUTING.md explains to a person how to get a change accepted, including review expectations and when to discuss first. AGENTS.md gives a coding agent precise commands, conventions, and boundaries. Shared facts like test commands should match exactly across both, ideally with one file as the canonical source.
How long should a CONTRIBUTING.md be?#
Short enough that a newcomer reads all of it before their first change — usually one or two screens. If it's growing past that, move reference material such as detailed style rules or architecture notes into separate docs and link them.
The short version#
A CONTRIBUTING.md exists to get a correct first pull request merged with the fewest round-trips. Write it in the order a contributor works, pair every rule with the command that checks it, leave out everything that belongs in another file, and keep shared facts identical to what your AGENTS.md tells coding agents. The hard part isn't writing it. It's keeping it true, because the only people who read it are the ones who can't tell when it's wrong.
Republish or cite this article
You're welcome to republish this piece in full or in part. We just ask that you credit the original with a link back. See our republishing guidelines.
Attribution snippet
<p>This article was originally published on <a href="https://moxiedocs.com/blog/how-to-write-a-contributing-md">Moxie Docs</a>.</p>Cite this article
The Moxie Docs team. "How to Write a CONTRIBUTING.md: A Guide Humans and Coding Agents Actually Follow." Moxie Docs, October 6, 2026, https://moxiedocs.com/blog/how-to-write-a-contributing-md.
Read next
8 Top AI Documentation Tools for Engineering Teams in 2026
Discover the top 8 AI documentation tools for engineering teams in 2026. Compare features, pricing, and ease of use for managers evaluating platforms.
Answer Engine Optimization for Developer Docs: How to Get Cited by AI Assistants
Developers now ask AI assistants before they read your docs. Learn how answer engine optimization (AEO) works for documentation: llms.txt, answer-first writing, stable URLs, and why accuracy is the real ranking factor.