Files
paperclip/CONTRIBUTING.md
T
Devin Foley d5889919a9 feat(commitperclip): widen linked-issue gate, add dedup-search check (#7632)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Contributor onboarding leans on a small set of CI gates
("commitperclip") that read PR metadata and enforce the rules in
CONTRIBUTING.md
> - We recently landed two new contributor rules: every PR must either
link an existing issue or inline an issue-template-shaped description,
and the author must affirm they searched for duplicate PRs first
> - The existing `check-pr-linked-issue` gate only accepted
`Fixes/Closes/Resolves #N`, and there was no gate at all for the
dedup-search affirmation, so the new rules were unenforced
> - This pull request widens the linked-issue gate (accept `Refs #N`,
accept inline template-shaped descriptions) and adds a new dedup-search
gate wired into `run-quality-gates`
> - The benefit is that the rules we ask contributors to follow are now
mechanically enforced, lowering review noise without raising contributor
friction

## Linked Issues or Issue Description

Refs #4260 — the PR cited in the original rule discussion, whose body is
the canonical example of the inline-issue-description shape this gate
now accepts.

**Problem or motivation**

The repo recently adopted two contributor rules: (1) link the issue your
PR fixes or inline a description in the issue-template shape, and (2)
confirm you searched for duplicate PRs before opening one. Neither rule
was enforced — the existing linked-issue check only matched
`Fixes/Closes/Resolves #N`, and nothing looked for the dedup-search
affirmation. Reviewers had to remember and re-state the rules by hand on
every PR.

**Proposed solution**

Widen `check-pr-linked-issue.mjs` and add a new
`check-pr-dedup-search.mjs` so commitperclip enforces the rules already
documented in CONTRIBUTING.md and the PR template:

- Accept `Refs #N` as a valid link verb alongside `Fixes`, `Closes`,
`Resolves`.
- Accept a PR body with an inline issue-template-shaped description (≥3
fields matched against the bug, feature, or adapter templates) as a
valid alternative to a linked issue.
- New `check-pr-dedup-search.mjs` looks for a checked checkbox affirming
the author searched for similar/duplicate/prior PRs, wired into
`run-quality-gates.mjs` with the same skip/override semantics as the
other gates.

**Alternatives considered**

- A single regex over the whole PR body looking for issue-template field
names — rejected, too brittle and gave no useful error message when it
failed. The per-field counter lets us tell the author exactly how many
template fields we matched and which template they're closest to.
- Making the dedup-search check live inside `check-pr-linked-issue` —
rejected, the two rules are orthogonal and a separate gate gives a
cleaner error message and respects `[skip-quality-gates]` independently.

**Roadmap alignment**

This is contributor-workflow plumbing for rules that already landed on
`master`. It is not a roadmap feature and does not overlap with planned
core work.

## What Changed

- `check-pr-linked-issue.mjs`: accept `Refs #N`; add
`hasInlineIssueDescription` (per-template field counter, ≥3 fields) so a
fully inlined description satisfies the gate.
- `check-pr-dedup-search.mjs`: new gate, looks for a checked
dedup-search checkbox in the PR body, with clear failure guidance.
- `run-quality-gates.mjs`: wire the new gate in alongside the existing
checks.
- `CONTRIBUTING.md`: "Before You Start: Search First" callout pointing
at the PR-template checkbox the gate enforces.
- Tests: unit tests for `Refs #N`, the inline-description threshold
(bolded labels, plain labels, headings), and the dedup-search gate
across checked/unchecked/missing/skip-prefix paths.

## Verification

- `node --test .github/scripts/tests/check-pr-linked-issue.test.mjs` →
all pass
- `node --test .github/scripts/tests/check-pr-dedup-search.test.mjs` →
all pass
- Full repo test matrix: 116/116 pass locally

For the gate itself, this PR exercises both new code paths: the body
inlines a feature-template-shaped description with ≥3 matched fields,
and the dedup-search checkbox below is checked.

## Risks

Low risk. The change is contributor-CI plumbing — no runtime or
migration impact. The widened linked-issue gate is strictly more
permissive (it can only flip prior FAILs to PASS), and the new
dedup-search gate honors the existing `[skip-quality-gates]` prefix, so
an author can always bypass it the same way as the other gates if
needed.

## Model Used

Claude Opus 4.7 (`claude-opus-4-7`), extended-thinking enabled, tool use
for filesystem + shell.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [ ] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-06-05 22:10:52 -07:00

8.9 KiB

Contributing Guide

Thanks for wanting to contribute!

We really appreciate both small fixes and thoughtful larger changes.

Before You Start: Search First

Before you start work, search GitHub for existing PRs and issues that touch the same area:

  • Look for duplicate or in-flight PRs. If something close already exists, prefer helping that PR over the line (see Helping Other Contributors) instead of opening a parallel one.
  • Look for related open issues. Link them in your PR body.
  • If an older PR is effectively dead (stale, unmaintained, would be painful to rebase/merge), a fresh PR is fine — just call out the prior PR in your description so the reviewer has context.

Duplicate PRs create extra work for reviewers and make merging harder. A 60-second search saves hours later.

Affirm that you did this search by checking the dedup-search box in the PR template (I have searched GitHub for duplicate or related PRs and linked them above). Commitperclip checks for this checkbox on non-trivial PRs.

Two Paths to Get Your Pull Request Accepted

Path 1: Small, Focused Changes (Fastest way to get merged)

  • Pick one clear thing to fix/improve
  • Touch the smallest possible number of files
  • Make sure the change is very targeted and easy to review
  • All tests pass and CI is green
  • Greptile score is 5/5 with all comments addressed
  • Use the PR template

These almost always get merged quickly when they're clean.

Path 2: Bigger or Impactful Changes

  • First talk about it in Discord → #dev channel
    → Describe what you're trying to solve
    → Share rough ideas / approach
  • Once there's rough agreement, build it
  • In your PR include:
    • Before / After screenshots (or short video if UI/behavior change)
    • Clear description of what & why
    • Proof it works (manual testing notes)
    • All tests passing and CI green
    • Greptile score 5/5 with all comments addressed
    • PR template fully filled out

PRs that follow this path are much more likely to be accepted, even when they're large.

PR Requirements (all PRs)

Use the PR Template

Every pull request must follow the PR template at .github/PULL_REQUEST_TEMPLATE.md. If you create a PR via the GitHub API or other tooling that bypasses the template, copy its contents into your PR description manually. The template includes required sections: Thinking Path, What Changed, Verification, Risks, Model Used, and a Checklist.

We do not gate PRs on a pre-existing issue. Two acceptable paths:

  1. Issue exists — search the Issues database for anything this PR addresses and tag each one with Fixes: #123 / Closes #123 / Refs #123 so GitHub auto-links them. If there are duplicate or closely related issues, link all of them, not just the one you picked. If there are related PRs (prior attempts, dependent work, follow-ups, abandoned predecessors), link those too.
  2. No issue exists — describe the problem directly in your PR body, following one of our issue templates so a reviewer has the same fields they'd get from a filed issue:
    • Bug fix: what happened, expected behavior, steps to reproduce, Paperclip version/commit, deployment mode. See bug_report.yml.
    • Feature: problem/motivation, proposed solution, alternatives considered, roadmap alignment. See feature_request.yml.
    • New adapter: agent or provider, why it's useful, how it's invoked. See adapter_request.yml.

Either way, a reviewer should be able to understand the underlying issue without leaving the PR. Commitperclip may check that one of these two paths is satisfied.

Model Used (Required)

Every PR must include a Model Used section specifying which AI model produced or assisted with the change. Include the provider, exact model ID/version, context window size, and any relevant capability details (e.g., reasoning mode, tool use). If no AI was used, write "None — human-authored". This applies to all contributors — human and AI alike.

Tests Must Pass

All tests must pass before a PR can be merged. Run them locally first and verify CI is green after pushing.

Paperclip Gates Must Pass

All Paperclip CI gates (lint, typecheck, tests, build, and any other required checks) must be satisfied before a PR can be merged. Don't ask for a merge while gates are red — fix them first.

Greptile Review

We use Greptile for automated code review. Your PR must achieve a 5/5 Greptile score before it can be merged, with:

  • No open P2 (or higher) comments
  • No open recommendations
  • No open follow-ups

We hold the bar high here on purpose — we want code quality to be as high as possible. If Greptile leaves comments, fix them (or, if a comment is wrong, reply explaining why) and request a re-review.

Helping Other Contributors

Fixing up someone else's stalled or almost-there PR is strongly encouraged. If a contributor has done most of the work but ran out of time or got stuck, picking up their branch, polishing it, and getting it over the line is one of the most valuable things you can do here.

When you do:

  • Give credit. Mention the original author in the PR description and thank them.
  • Preserve their commits where reasonable — don't squash them out of existence.
  • Be kind in comments and reviews. People put real effort into their PRs, even the ones that didn't quite land.

A culture where contributors help each other ship is worth more than any single PR. Be generous with thanks.

Feature Contributions

We actively manage the core Paperclip feature roadmap.

Uncoordinated feature PRs against the core product may be closed, even when the implementation is thoughtful and high quality. That is about roadmap ownership, product coherence, and long-term maintenance commitment, not a judgment about the effort.

If you want to contribute a feature:

  • Check ROADMAP.md first
  • Start the discussion in Discord -> #dev before writing code
  • If the idea fits as an extension, prefer building it with the plugin system
  • If you want to show a possible direction, reference implementations are welcome as feedback, but they generally will not be merged directly into core

Bugs, docs improvements, and small targeted improvements are still the easiest path to getting merged, and we really do appreciate them.

General Rules (both paths)

  • Write clear commit messages
  • Keep PR title + description meaningful
  • One PR = one logical change (unless it's a small related group)
  • Run tests locally first
  • Be kind in discussions 😄

Writing a Good PR message

Your PR description must follow the PR template. All sections are required. The "thinking path" at the top explains from the top of the project down to what you fixed. E.g.:

Thinking Path Example 1:

  • Paperclip is the open source app people use to manage AI agents for work
  • There are many types of adapters for each LLM model provider
  • But LLM's have a context limit and not all agents can automatically compact their context
  • So we need to have an adapter-specific configuration for which adapters can and cannot automatically compact their context
  • This pull request adds per-adapter configuration of compaction, either auto or paperclip managed
  • That way we can get optimal performance from any adapter/provider in Paperclip

Thinking Path Example 2:

  • Paperclip is the open source app people use to manage AI agents for work
  • But humans want to watch the agents and oversee their work
  • Human users also operate in teams and so they need their own logins, profiles, views etc.
  • So we have a multi-user system for humans
  • But humans want to be able to update their own profile picture and avatar
  • But the avatar upload form wasn't saving the avatar to the file storage system
  • So this PR fixes the avatar upload form to use the file storage service
  • The benefit is we don't have a one-off file storage for just one aspect of the system, which would cause confusion and extra configuration

Then have the rest of your normal PR message after the Thinking Path.

This should include details about what you did, why you did it, why it matters & the benefits, how we can verify it works, and any risks.

Please include screenshots if possible if you have a visible change. (use something like the agent-browser skill or similar to take screenshots). Ideally, you include before and after screenshots.

Questions? Just ask in #dev — we're happy to help.

Happy hacking!