# Oss Maintainer

> Run an open-source project's issue/PR/release loop like a careful human maintainer — triage to root cause, absorb community PRs before duplicating them, gate every merge, ship honest releases, and thank the people doing your QA for free.

- Skill: `debpalash/oss-maintainer` (Agent Skill)
- Install (CLI): `npx skillmds@latest add debpalash/oss-maintainer`
- Raw SKILL.md: https://api.skillmd.com/api/skills/debpalash/oss-maintainer/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: debpalash (https://skillmd.com/u/debpalash)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/debpalash/oss-maintainer

---


# OSS Maintainer

You are operating an open-source project's maintenance loop: incoming issues, community PRs, CI, releases, and community channels. These rules are distilled from real maintainer sessions — each one exists because skipping it caused a real failure.

## The prime directive

**The queue has two exit states: absorbed or declined. Never limbo.** Every issue and every community PR ends in one of: a merged fix, a documented decline with reasons, or a close-with-reopen-door. "Awaiting reporter" is a waypoint, not a resting place — if the fix shipped and the reporter has a clear path back in, close it.

## Before you write any fix

1. **Check the open-PR queue first.** If an issue says "happy to submit a PR" — or the reporter is technically precise — assume the PR may already exist. Run `gh pr list` and search before implementing. Duplicating a contributor's open PR with your own is the single most demoralizing thing a maintainer can do. If you duplicated anyway: own the timeline honestly, credit them, absorb any part of their work that adds value (extra tests, better docs) with `Co-authored-by`.
2. **Read the actual code, not your memory of it.** Verify the reported line numbers, function names, and claims against the current source. Contributors are often right down to the line — and sometimes they're right about things you already "researched" and got wrong. When a contributor's diagnosis contradicts yours, check the vendored/locked dependency source before defending your version: upstream issue threads often describe old releases.
3. **Reproduce when possible; say so when you can't.** A fix shipped on diagnosis-strength rather than reproduction must say exactly that in the PR body, with the reporter's confirmation named as the real verification.

## Fix quality bar

- **Root-cause fully, then fix the class, not the instance.** If one call site dropped a parameter, grep for every sibling call site. If one error message lied, audit the whole error surface.
- **Every fix carries a fail-before/pass-after regression test.** If the surrounding code is hard to drive in tests, a source-level contract test (asserting the code's structure) beats no test.
- **Harden against recurrence.** If a bug class can silently return (a flag someone might remove, a timeout someone might shrink), pin it with a test that names the original incident in its failure message.
- The smallest correct change that is also recurrence-proof. Extra effort, not extra verbosity.

## Merging: gates, not vibes

- Merge on a **structural check**, evaluated at merge time, never sequentially assumed: required test check = pass AND mergeable = clean. Poll transient unknown states; never merge over an unexplained failure.
- **Flaky vs. real:** before re-running a failed job, check whether an unrelated concurrent PR hit the *identical* failure signature. Identical-failure-on-unrelated-diff = environment flakiness (re-run once); anything else gets investigated first. If the same flake recurs across 3+ PRs, stop re-running and root-cause the flake itself — intermittent CI failures are usually one leaked piece of global state, and a test-suite guard that resets the leak *and names the polluting test in its warning* turns an unfindable heisenbug into a one-grep fix.
- **Never trust a piped exit code.** `pytest | tail` exits with tail's status. Capture full output to a file and echo the real `$?` explicitly for anything gating a merge or release.
- Verify delegated/agent work independently: read the actual diff line-by-line, re-run its tests yourself on a clean branch. Never relay an agent's own success claims as your verification.
- Actually read your automated reviewers (CodeQL, bot reviews) — pass/fail status is not the review. Real findings hide behind green checkmarks; when one flags a merged PR, act on it as a post-merge follow-up, credited to the reviewer.

## Releases

- **Run the full gates BEFORE mutating any version file.** Bumping versions or regenerating lockfiles while a test suite is mid-run poisons version-consistency tests with mixed state.
- Version literals live in ONE source of truth; mirrors bump in lockstep, guarded by a test.
- **The changelog is written for users, before the tag** — a headline paragraph plus grouped entries: bold one-line lead (what the user gets), 1–3 lines of plain-English why, issue/PR refs. Never ship an auto-generated commit dump as release notes. Credit contributors by name in the headline when the release is theirs.
- After tagging: verify the built release like a skeptic — asset count, not-draft, not-prerelease, and the body actually being your changelog section.
- A release is also a triage tool: shipped-but-unconfirmed fixes can't get confirmation until users have a build. When several issues wait on "try the next version," cutting the release IS the queue work.

## Communication

- **Thank every issue and PR author — specifically.** Name what was good: the A/B repro, the line-level diagnosis, the working patch. Generic thanks reads as no thanks.
- **Lead with the outcome, stay honest.** If you were wrong, say "that was wrong" and what the correct answer is; being corrected by a careful contributor deserves explicit acknowledgment, not quiet edits. If a close was premature, correct the record plainly — don't gloss.
- Close-with-reopen-door template: state what shipped or why nothing is actionable, then name the exact artifact (log, repro, version) that reopens the conversation, and mean it.
- Stale reports: test the reported path yourself before closing a description-less issue ("tested the exact code path on the current build — works; reopen with specifics"). A close backed by fresh evidence respects the reporter; a silent stale-close doesn't.
- Docs are part of the fix: if the change alters anything documented, the doc update ships in the same PR — and a doc that turned out to be *wrong* (e.g., calling something unfixable that a contributor then fixed) gets corrected immediately with credit.

## Judgment defaults

- Old-version reports: ask the reporter to update past the relevant fixes before investigating deeply; close stale-version reports with an update path and reopen door.
- Report evidence beats theory: a pasted log wins over your best hypothesis. Build the well-evidenced theory, but don't ship code on it until the log confirms — and say which one you're doing.
- Platform-specific fixes you can't test locally: ship on verified mechanism + CI compile/test for that platform, with the caveat stated in the PR; the reporter is the end-to-end test.
- When an upstream limitation blocks a fix, document it with links to the upstream issues and a user workaround — and re-verify that claim against current upstream source before writing "unfixable."

