Contribute Upstream

by @zzstoatzz.io · created Oct 27, 2026

Install this skill

npx @skillz.supply/cli install did:plc:xbtmt2zjwlrfegqvch7fboei/skills.contribute-upstream

Writes SKILL.md into your agent's skills folder under this skill's name. No CLI? Download the file, or view it.

name: "contribute-upstream"

description: "Learn a repository's contribution norms from its docs and its history before changing it, then shape and open the change to match. Use before any patch, issue, or pull request to a repository the user does not own."

createdAt: "2026-10-27T20:43:50.176951+00:00"

repoUrl: "https://skillz.supply/skills/did:plc:xbtmt2zjwlrfegqvch7fboei/skills.contribute-upstream/SKILL.md"

# contribute upstream

A contribution is judged by the project's norms, not the user's. Most of those
norms are unwritten: they live in the last fifty commits and the last ten merged
pull requests. Learn both before writing code, and keep the evidence, because a
norm asserted without its source is a guess.

## 1. get the code

Look for a local checkout first (`~/{forge}/{org}/{repo}` on this machine,
sibling repos beside it). Otherwise use the `librarian` skill for a cached
checkout. Fetch the default branch before reading anything; a stale base hides
norms that changed last week and poisons the patch later.

## 2. read the written norms

Read these in full where they exist, newest first:

- `CONTRIBUTING*`, `AGENTS.md`, `CLAUDE.md`, `agents.md`, `docs/contributing*`
- pull request and issue templates (`.github/`, `.tangled/`, repository root)
- repo-local agent skills (`.agents/skills/`, `.claude/skills/`) — a repository
  that ships a `writing-tests` or `tg` skill has told you exactly what it wants
- CI workflows: what runs on a pull request, and what only runs on main
- `CODEOWNERS`, `LICENSE`, a DCO or CLA note, commit hooks (`.pre-commit-config*`, `lefthook*`)

Written norms win over everything below, including the user's habits.

## 3. read the practiced norms

The written norms omit most of what reviewers react to. Read the history for
each of these and write down the number you saw:

- **commit subjects**: prefix style (`area: change`), tense, length, how often a body appears, `Signed-off-by` share
- **pull requests**: body length of the last few merged ones, whether a punchline-only body is normal, whether one commit per PR is the shape, whether PRs are stacked, who merges, and what reviewers asked for before merging
- **tests**: where a test for this kind of change lives, what its header or docstring says, and what the repo deletes (its own words, if it has a tests skill)
- **comments**: density and form in the files you will touch (`/** */` per export, or none), what they say (why, never what), whether a client file may name a server detail
- **types and idiom**: the nearest function doing the same job is the template; copy its shape, including what it annotates and what it leaves inferred
- **docs**: whether a behaviour change updates a doc in the same commit
- **entry point**: issue first, discussion first, or straight to a PR; patches by mail; a bot that labels or closes

Commands that answer most of it:

```bash
git log origin/main -50 --format='%s'                      # subjects
git log origin/main -30 --format=%b | grep -c Signed-off-by  # signoff share
git log origin/main -20 --format='%an' | sort | uniq -c     # who commits
tg pr list --state merged --json   # or: gh pr list --state merged --limit 10 --json title,body
grep -c '^/\*\*' <file>; grep -c '^ *//' <file>             # comment form in a file
```

## 4. write the brief

Before any edit, state the norms you will follow in a few lines, each with its
evidence (the file, or "N of the last M commits"). Keep it in the session; tell
the user only what changes their decision, such as "this repo wants an issue
first" or "PR bodies here are one sentence". A norm you could not find is
"unknown", not "none".

## 5. shape the contribution

- the smallest self-contained change that fixes one thing; one commit per pull request unless the repository stacks
- match the nearest existing code, test, and comment rather than the user's house style
- update the doc the repository would update, in the same commit
- run the repository's own gate (its `test.sh`, `just check`, `pre-commit`), not a subset you chose
- review the diff adversarially against the brief: every comment, every test, every annotation must have a reason the repository would give. Delete a test that restates the implementation. Delete a comment that names what the code shows, or a detail that belongs to another layer.

## 6. open it

Open nothing without the user's go. Then:

- prose by the `pr-body` skill, sized to the change: a two-line change gets a two-line body
- the base is the upstream remote-tracking ref (`origin/main`), never a local or fork `main`; run `git log --oneline <base>..<head>` and confirm the count is exactly the intended commits before creating the PR
- after creating, read the PR's own patch back (`tg pr diff`, `gh pr diff`) and confirm the commit count and files again before telling the user it is open. A fork whose `main` has drifted ships upstream's commits as yours.
- commit trailers and attribution as the repository and user require, and never a model identifier in anything pushed

## 7. after

Watch the CI run the PR starts and treat a failure as yours. Answer review in
the repository's voice, and address a review by revising the commit the
repository way (a new round, a fixup, or a force-push, whichever its history
shows).